In this post I expand on using records. This time creating a record array that contains a character string, or more specifically two character strings. Action! won’t allow you to add a CHAR ARRAY as part of a record (TYPE) definition. You can get around this limitation by using BYTE POINTERS. You place the string as the last variable in the TYPE definition, but as a BYTE declaration.
To include multiple string variables, a series of bytes must be added to “reserve” space for the first string. For the tContact TYPE below, bFNm is first name, bLNm is last name, and bR1 through bR10 are the “reserve” bytes. None of these will be referenced via the record.field syntax, though you could for types other than CHAR ARRAY.
TYPE tContact=[BYTE bFNm, bR1,bR2,bR3,bR4,bR5,bR6,bR7,bR8,bR9,bR10, bLNm]
Pointer Calculation
Suppose you have a BYTE ARRAY name bArray for storage space, a BYTE POINTER named bpFirst for first name, and bpLast for last name. The first name is 10 bytes (11 with size), and last name is 15 bytes (16 with size). The last name offset into the record is therefore 11. The size of the entire record (first name and last name) is 27 bytes. First Name Record 1 will be stored at 0 offset into the storage array. Record 2 will be stored at 0+(1*RecordSize) into the storage array. Record 3 will be stored at 0+(2*RecordSize) into the storage array, etc. Last Name Record 1 will be stored at 0+FirstNameSize offset into the storage array (11 bytes). Record 2 will be stored at 0+(1*RecordSize)+FirstNameSize offset into the storage array. Record 3 will be stored at 0+(2*RecordSize)+FirstNameSize into the storage array, etc.
Program Source
The source is fairly well documented and I’ve given a good explanation of how it works so I won’t break it down line by line:
; Program: RECARRAY.ACT ; Date...: 2015.08 ; Inc Action Toolkit parts INCLUDE "D5:PRINTF.ACT" ; Start program globals MODULE ; Size of a field record DEFINE SZREC = "27" ; Offset of last name into record DEFINE OFFLN = "11" ; Max number records DEFINE MAXREC = "50" ; Size of storage pool (SZ's * MAXREC) DEFINE SZMEM = "1350" ; Contact definition type ; bFN = First byte of first name ; bR1..10 = First name bytes ; bLn = First byte of last name TYPE tContact=[BYTE bFNm, bR1,bR2,bR3,bR4,bR5,bR6,bR7,bR8,bR9,bR10, bLNm] ; Enough storage for MAXREC contacts BYTE ARRAY baFlds(SZMEM) ; Main routine PROC Main() ; Record counter and loop var BYTE bEn,bLp ; Pointer to contact record tContact POINTER pRec ; Pointers to name fields BYTE POINTER pFNm,pLNm ; Name input vars CHAR ARRAY cFNm(11),cLNm(16) ; Clear memory Zero(baFlds,SZMEM) ; Setup screen Poke(82,0) Put($7D) Position(0,0) PrintE("-[Record Arrays]------------------------") Position(0,1) ; Set entry # bEn=0 DO ; 0 based counter computes. ; Set record pointer to storage loc pRec=baFlds+(bEn*SZREC) ; Set Name pointers to offsets pFNm=pRec pLNm=pRec+OFFLN ; Inc counter (start at 1) bEn==+1 PrintF("%EEntry #%D (RETURN=Done)%E",bEn) ; Get first name Print("First Name (10 char)? ") InputS(cFNm) ; If first name len > 0 if cFNm(0) > 0 then SCopy(pFNm,cFNm) ; Get last name Print(" Last Name (15 char)? ") InputS(cLNm) ; If last name len > 0 if cLNm(0) > 0 then SCopy(pLNm,cLNm) fi fi PutE() ; Repeat until empty input, max record UNTIL cFNm(0)=0 OR cLNm(0)=0 OR bEn=MAXREC OD ; Regress counter by 1 bEn==-1 ; Printe header for output validation PutE() PrintE("First----- Last-----------") ; Process each input field for bLp=1 to bEn DO ; Compute from 1 offset (-1) ; Set Fld pointer to storage loc pRec=baFlds+((bLp-1)*SZREC) ; Set Name pointers to offsets pFNm=pRec pLNm=pRec+OFFLN PrintF("%10S %15S%E",pFNm,pLNm) OD RETURN
Results
Here I input one control first and last name, then a data point first and last name, then another control first and last name:
Here the program displays the array contents, validating they are stored on the proper byte boundaries within the allocated memory space for storage: