FIRST_NAME DIM 30 LAST_NAME DIM 30 CITY DIM 20 STATE DIM 2 ZIP DIM 10Strings can also be defined dynamically at run time. There are some advantages to this but not many. For most purposes we prefer to define strings explicitely in the source code.
123456789.123456789.123456789.123456789. NAME INIT "Mid-Michigan Computer Consultants" ^ ^ FP LPThe FORM POINTER in this example is set to 5, the length pointer is set to 21.
"Michigan Computer"If you were to MOVE NAME TO WORKNAME only the LOGICAL string (sub-string) would be moved.
123456789.123456789.123456789.123456789. NAME INIT "Mid-Michigan Computer Consultants" ^ ^ FP LP WORKNAME DIM 30 MOVE NAME TO WORKNAME .... after the move workname will be: 123456789.123456789.123456789. "Michigan Computer" ^ ^ FP LPIt's important to note that if the RECEIVING field already contains more data than what is moved, the original data is NOT erased or removed. For example:
123456789.123456789.123456789.123456789. NAME INIT "Mid-Michigan Computer Consultants" ^ ^ FP LP WORKNAME INIT "This is the original data in workname" MOVE NAME TO WORKNAME .... after the move workname will be: 123456789.123456789.123456789. "Michigan Computer" ^ ^ FP LPIn that example, the logical string which was the middle part of NAME is moved to WORKNAME starting at the first byte. The remaining data in WORKNAME is NOT changed. But the LOGICAL STRING in workname is only the portion that was moved.
WORK_NAME DIM 10 LIVE_NAME INIT "This is the Name" KEYIN "Enter a name:",WORK_NAME MOVE WORK_NAME,LIVE_NAMEIf the user just taps ENTER the variable WORK_NAME will have no data. It will be nul. The MOVE will do nothing. That means that where you might expect LIVE_NAME to become nul after the move, in truth there is no change at all!
NAME DIM 30 MOVE "John and Mary Doe",NAME DISPLAY *HON,*LL,NAME,*PL,*HOFF RESET NAME,10 DISPLAY *LL,NAME,*PLIn this example moving the string "John and Mary Doe" fills the entire string and leaves the form pointer at the first byte (1). The DISPLAY shows the entire string.
NAME DIM 30 MOVE "John and Mary Doe",NAME //initialize DISPLAY *HON,*LL,NAME,*PL,*HOFF //show contents MOVE "JERRY",NAME //change contents DISPLAY *HON,*LL,NAME,*PL,*HOFF //show contents RESET NAME,10 //point to byte 10 DISPLAY *LL,NAME,*PL //display logical string RESET NAME //point back to byte 1 DISPLAY *LL,NAME,*PL //show logical stringMOVE "John and Mary Doe",NAME puts 17 characters into the string. The form pointer is 1 and the length pointer is 17. The physical length remains 30; that's the maximum number of bytes the string can hold.
RESET NAME to 20 ;point to position 20 LENSET NAME ;set length to current position RESET NAME ;point back to position 1Another example could be used to parse strings. Assume the string contains city and state separated by a comma and you want to just show the city. You could do this:
CITY INIT "Bay City, Michigan" DISPLAY *HON,*LL,CITY,*PL,*HOFF //show logical string (everything) SCAN ",",CITY //position form pointer to , BUMP CITY,-1 //back up 1 byte LENSET CITY //limit the length here RESET CITY //position form pointer to 1 DISPLAY *HON,*LL,CITY,*PL,*HOFF //show new logical string
STRING INIT "Bay City, Michigan" NWK_FP FORM 3 ;work variable for form pointer NWK_LP FORM 3 ;work variable for length pointer MOVEFPTR STRING TO NWK_FP ;Get the form pointer MOVELPTR STRING TO NWK_LP ;Get the length pointer DISPLAY "Sub string ": *HON,*LL,STRING,*PL,*HOFF; *N,"The sub-string starts at ",NWK_FP: " and ends at ",NWK_LP
CALL TRUNCATE USING CITY ........... #TRUNCATE_STRING DIM ^ //pointer variable #TRUNCCATE_LEN FORM 4 //truncated length of string truncate LROUTINE USING #TRUNCATE_STRING COUNT #NWK04,#TRUNCATE_STRING //get string's truncated length SETLPTR #TRUNCATE_STRING, #NWK04 //set the string's length RETURN //return to caller
SCAN "HOT" IN WORK_STRINGIf the scan succeeds and finds the desired string, the target string's FORM POINTER is set to the first byte of the string being looked for. Assume, in the example above, that WORK_STRING contains
"THE WEATHER IS HOT AND DRY" 123456789.12345679.123456789.After the SCAN for "HOT" the FORM POINTER in WORK_STRING will be set to 16, the position of the sub-string "HOT".
WORK_STRING INIT "THE DAY WAS HOT, HOT, HOT AND DRY" NWK_FP FORM 2 DISPLAY "Find all occurances of the word HOT in ": *HON,*LL,WORK_STRING,*PL,*HOFF LOOP SCAN "HOT" IN WORK_STRING //Find next HOT BREAK IF NOT EQUAL //nothing found MOVEFPTR WORK_STRING, NWK_FP //retreive form pointer DISPLAY "HOT fount at byte ",NWK_FP BUMP WORK_STRING //jump past current HOT REPEAT UNTIL EOS DISPLAY "There are no more occurances of HOT" RESET WORK_STRINGNOTE: Pay particular attention to the BUMP at the end of the loop. The SCAN starts at the current form pointed byte and works to the right. It stops on the next occurance of the desired string and leaves the form pointer at the first byte of that string. If we scan again, from that position, the SCAN will change nothing and the routine will be in an infinite loop.
CITY DIM 30 STATE DIM 2 ZIP DIM 10 PACK PRINT_CITY WITH CITY, ", ", STATE, " ",ZIP
PACK PRINT_CITY WITH: CITY: ", ": STATE: " ": ZIPPACK works on the LOGICAL string. In the above example, if the string CITY is 30 bytes and contains only the 8 byte string Bay City, that is all that will be packed.
"Bay City , MI 48706"This is a good place to use the COUNT instruction and the TRUNCATE routine to insure the string is truncated.
ISI_KEY DIM 14 COMPANY DIM 10 ACCT_ID FORM 4 PACK ISI_KEY,COMPANY,ACCT_IDSuppose that the user enters "MMCC" as the COMPANY and "25" as the ACCT_ID. The COMPANY string is only 4 bytes long. The result of the PACK would be:
"MMCC 25"When the desired string is:
"MMCC 25"In that example, the "25" works fine because it is a numeric variable. By definition it is right justified and space filled. The PACK instruction gets it right.
PACK COMPANY,COMPANY," " or PACK COMPANY,COMPANY, SPACES //assuming SPACES is definedINCREMENTAL Packing is another useful technique. You initialize a string then PACK it with some data. As more data is developed, you pack the string with itself plus the additional data. This is similar to using APPEND to build up a string, but this one is more flexible.
TITLE_LINE DIM 1500 //working string HEX_7F INIT 0x07,0xFF //new line in an EditText WORK40 DIM 40 //general work area UNPACK NUL, TITLE_LINE //empty the string GETITEM F1_ET_Name,0,WORK40 //Get name PACK TITLE_LINE,TITLE_LINE: //pack into itself WORK40 //append WORK40 GETITEM F1_ET_Addr,0,WORK40 //Get address PACK TITLE_LINE,TITLE_LINE: //pack into itself HEX_7F: //new line WORK40 //append WORK40 GETITEM F1_ET_City,0,WORK40 //Get city PACK TITLE_LINE,TITLE_LINE: //pack into itself HEX_7F: //new line WORK40 //append WORK40The above example may seen awkward. One could simply GETITEM into three fields and pack using a single instruction. The usefulness may be more obvious is we make the GETITEM and PACK into a ROUTINE:
CALL PACK_IT_UP USING TITLE_LINE, F1_ET_Name CALL PACK_IT_UP USING TITLE_LINE, F1_ET_Addr CALL PACK_IT_UP USING TITLE_LINE, F1_ET_City ............................ PASSED_ET EDITTEXT ^ PASSED_STRING DIM ^ pack_it_up ROUTINE PASSED_STRING, PASSED_ET GETITEM PASSED_ET,0,WORK40 //Get ET data PACK TITLE_LINE,TITLE_LINE: //pack into itself HEX_7F: //new line WORK40 //append WORK40 RETURN
UNPACK INPUT_STRING INTO FIELD1, FIELD2, FIELD3, etc.Unlike PACK, the UNPACK does not know the logical lengths of the elements it is dealing with. As many bytes are moved from the input field to each of the receiving fields as needed to fill each of those fields.
RAW_STRING INIT "123,456,789,MMCC" FIELD1 FORM 3 FIELD2 DIM 4 FIELD3 FORM 3 FIELD4 DIM 50 UNPACK RAW_STRING INTO FIELD1, FIELD2, FIELD3, FIELD4In the above example:
RAW_STRING INIT "123,456,789,MMCC" MY_LIST LIST FIELD1 FORM 3 FIELD2 DIM 4 FIELD3 FORM 3 FIELD4 DIM 50 LISTEND UNPACK RAW_STRING INTO MY_LIST
NUL INIT 1 FIELD INIT "This is a dummy string" UNPACK NUL,FIELD //completely clears FIELDThis technique can be used to clear strings, records, lists and most other structures.
NAME INIT "MMCC, Inc." //normal string with contents CLEAR NAME //Set form and length pointers to zero DISPLAY "name:": *HON,*LL,NAME,*PL,*HOFF //shows nothing RESET NAME,3 //point to byte 3 (extend length to match) DISPLAY "name:": *HON,*LL,NAME,*PL,*HOFF //shows "C" RESET NAME //point to byte 1 (don't change length) DISPLAY "name:": *HON,*LL,NAME,*PL,*HOFF //shows "MMC"
.................. . Remove all opening boxes [ . FOR IX3 FROM 1 TO 50 ;artificial killer SCAN "[",RAW_DATA ;find next [ IF NOT EQUAL ;none left BREAK ENDIF SPLICE "",RAW_DATA,ONE ;remove 1 byte RESET RAW_DATA ;back to front REPEAT ;see if any more
[label] WHEREIS {source}{sep}{search} [{sep2}{result}] [label] WHEREISLAST {source}{sep}{search} [{sep2}{result}]Where:
label | Optional. A Program Execution Label. |
source | Required. A previously defined Character String Variable, literal, equated character value, or a character value for which to search. |
sep | Required. A comma or one of the following prepositions: BY, TO, OF, FROM, USING, WITH, IN, or INTO. |
search | Required. A Character String Variable or Literal whose logical string is searched. |
sep2 | Optional. A comma or one of the following prepositions: BY, TO, OF, FROM, USING, WITH, IN, INTO, or GIVING. |
result | Optional. A Numeric Variable that receives the form pointer value in the {search} string where the {source} string was found. |
AND Bitwise AND two characters together. APPEND Append a string to another string. BUMP Add one to the Form Pointer. CHOP Move a variable to another while removing trailing spaces. CLEAR Set Form Pointer & Length Pointer to zero. Moves zero to numeric field. CMATCH Match a character with another character. CMOVE Move a character. COUNT Count number of characters in a list of variables. EDIT Apply a special display format to a character variable. ENDSET Set the Form Pointer equal to Length Pointer. EXTEND Append one or more blanks to a string. FILL Fill character variables with a value. FINDCHAR Search a string for a character from a list. LCMOVE Move the Length Pointer character to a variable. LENSET Set the Length Pointer equal to Form Pointer. LOAD Move one of several variables to another variable. LOWERCASE Convert a string to lower case. MATCH Match a variable with another variable. MOVEFPTR Move the Form Pointer value to a numeric variable. MOVELPTR Move the Length Pointer value to a numeric variable. MOVELS Move a variable to another variable respecting the Logical String. MOVEPLEN Move the Physical Length value to a numeric variable. MOVEPTR Move a pointer variable to another pointer variable. NOT Bitwise NOT a character and move to another variable. OR Bitwise OR a character with another character. PACK Append several variables to another variable. PACKKEY Append several variables to another variable respecting Physical Length. PARSE Select next several characters based on a mask. PARSEFNAME Retrieve a filename from within a string. REMOVE Move a variable to another variable and adjust the Form Pointer of first variable. REPLACE Change characters to other characters in a character string. RESET Set the Form Pointer of a string variable. SCAN Search a variable for a character string. SDELETE Delete several characters from a character string. SEARCH Search a set of variables for starting with a character string. SET Assigns a variable or list of variables to a value of one. SETLPTR Set the Length Pointer of a string variable. SFORMAT Change the Physical Length value of a string variable. SINSERT Inserts a string variable into another string variable. SMAKE Create a string variable. SPLICE Replace logical contents of one variable with another. SQUEEZE Move a variable to another while removing characters. STORE Move a variable to one of several variables. TEST Bitwise test one character with another character. TYPE Determine if a string variable has a valid numeric format. UNPACK Split a variable to several (usually smaller) variables. UPPERCASE Convert a string to upper case. XOR Bitwise exclusive or one character with another character.
FLD1 DIM 20 FLD2 DIM 20 MOVE "ABCDEFG",FLD1 ENDSET FLD1 LOOP UNTIL EOS CMOVE FLD1, FLD2 BUMP FLD1, -1 REPEATThis is incomplete. I would need a counter and a few other things. I was just wondering if there was an easier way of doing it.
FLD1 DIM 20 MOVE "ABCDEFG.INI",FLD1 ENDSET FLD1 BUMP FLD1,-3 MATCH ".INI",FLD1 IF EQUAL ...... do something .... ENDIF
scan ".ini",string if equal I found it else it's not there endif reset string
. For the reverse order: input dim 12 ; assume large enough for data output dim 12 xn form 2 ; array pointer aa dim 1(12) unpack input, aa ;array elements up to 12 count xn, input ;number of bytes input loop append aa(xn), output ;begins with "last" character in array decr xn repeat until (xn=0) chop outputIt's very early in the morning.... but I think this would work. Didn't test it.
input dim 12 ;assume large enough for data output dim 12 aa dim 1(12) unpack input,aa ;array elements up to 12 pack output with aa(12),aa(11),aa(10),aa(9),aa(8): aa(7), aa(6), aa(5), aa(4),aa(3): aa(2), aa(1)
MOVELPTR #strSource,#lngSourceFptr UPPERCASE #STRSOURCE WHEREISLAST ".INI" IN #STRSOURCE GIVING POSITIONNow if position is 4 less than #lngsourcefptr, it was at the end of the string.
#strSource DIM ^300