Structured String Definitions

A new type of string manipulation feature has been added to PxPlus that allows for the direct manipulation of components within a string. This new feature allows the developer to treat a string much like a data structure and then reference the components within the string by name as opposed to by offset.

These structure strings are similar to composite strings in that the full string itself is comprised of multiple component values. However, unlike composite strings, the string itself is not dynamically generated when referenced. Instead, the string remains intact in memory and references to its components merely extract their value from the complete structure. All existing composite string functions and directives (VIS, VIN, VIA and XFA) will work with structured strings.

Structured String Definition:

The DIM directive is used to define a structured string in much the same way as composite strings are defined but instead of using an IOLIST, the structure is defined using a string similar to other language template definitions. The format of a structure definition statement is:

DIM Varname$ :: "<Definition>"

Where:

Varname$ Is the name of the string variable which will contain the structure
Definition Is a string containing comma separated various field names and definitions.

Example:

DIM CLIENT$::"Name:C(30),Address:C(30),City:C(15),Owing:N(10)"

This would define an 85-byte structure with four elements. The first 30 being the Name, next 30 Address, 15 for City, and 10 character numeric field containing the Owing value.

Accessing Elements in the Structure:

To access the various elements/fields within a string structure the '::' operator is used. For example, using the Client structure above:

 

N$ = Client::Name$ Returns the 'name' element from the string Client$
Client::City$ = "Markham" Changes the 'city' element in the structure Client$
Client::Owing += 3 Adds three to the Owing field in the structure Client$ converting it to/from string format

Note that the type of variable being referenced is defined on the field/element name not the name of the string structure itself. Even though the values are stored in the string CLIENT$, the $ is omitted prior the :: operator. String elements that are numeric in nature can be referenced either as a string or as a numeric. Non-numeric data can only be referenced as a string.

Field Definition:

Each field definition consists of a field name, optional array specification, and a field type/length specification. Some field types do not require a length specification since by there definition their length is pre-defined. A colon is used to separate the field name from its definition.

Field Type Length Description
C Required Character data
N Required Numeric data
I 1 to 6 Binary value from 1 to 6 bytes in length with a leading sign bit
U 1 to 6 Unsigned binary value from 1 to 6 in length
F 8 8 byte IEEE floating point number
+P * Operating system pointer
+Z * Pointer to a NULL terminated string
+L * Signed 'long'
+I * Signed 'int'
+S * Signed 'short'
+UL * Un-signed 'long'
+UI * Un-signed 'int'
+US * Un-signed 'short'
+H * HANDLE (Windows only)
+W * WORD (Windows only)
+2 * DWORD (Windows only)

If desired type C, N, I, and U can be immediately followed by a slash and byte swapping indicators. There are three byte swapping indicators supported:

B - Swap every byte with the following byte in two byte pairs.
W - Swap every two bytes with the following two bytes
L - Swap every four bytes with the following four bytes

If only a slash is given, the byte swapping is done in accordance the standard internal format on the machine you are running on.

Length Specifications:

The length of a field can be specified within parenthesis as either fixed or variable. To specify a fixed length field simply place the field length within the parenthesis following the field name.

To specify a variable length field, one that has a delimiter character, provide the maximum expected field length followed by "*=" and then optionally the CHR value for the delimiter character. For example (10*=9) would indicate a field whose max length is 10, delimited by a CHR(9) or a TAB character.

If no delimiter character is specified the system will use the default SEP character (or $0A$ if the system 'TX' parameter is set).

Special '+' Field Types:

There are a number of special '+' field definitions provided to allow for the definition of OS specific data types. The size and format of these data types will be determined by the operating system you are running on. In addition, the value contained in the fields will be properly 'byte swapped' such that the fields can be directly used by the operating system as well as accessed by your application without regard to byte ordering.

The '+P' and '+Z' field types are special as they represent true memory pointers. Accessing these types of elements as a numeric value returns the memory pointer as numeric value. Accessing these types of fields as string returns the data to which they are pointing.

For Example:

0010 DIM Struct$::"Path:+Z"
0020 DIM Filename$(256,$00$)
0030 Struct::Path$ = Filename$
0040 A = DLL(………, Struct$)
0050 PRINT Struct::Path$

The above will define a structure (Struct$) that contains a pointer to a null byte terminated string. Line 0030 assigns the address of the variable Filename$ into the pointer Path$ within Struct$. Subsequent referencing of the value in Struct::Path$ will return the string value up to and including the null byte terminator. Struct::Path will return the same value as MEM(Filename$).

Much the same logic applies to a '+P' data type however when referencing a '+P' field as a string you MUST specify a length as in Struct::path$(1,40).

A null pointer is assumed to have a value of "" and if a pointer is assigned "", its internal value is set to NULL.

Using these '+' field definitions makes it easier to create structures that are compatible with most operating system functions. For instance, the Windows system call to choose a colour is passed in a structure as follows:

The 'C' structure definition:  
typedef struct { DWORD lStructSize;
  HWND hwndOwner;
  HWND hInstance;
  COLORREF rgbResult;
  COLORREF* lpCustColors;
  DWORD Flags;
  LPARAM lCustData;
  LPCCHOOKPROC lpfnHook;
  LPCTSTR lpTemplateName;
  } CHOOSECOLOR;

Using String structures becomes:

 
DIM ChooseColor$::" lStructSize:+2,
  hwndOwner:+H,
  hInstance:+H,
  rgbResult:+2,
  lpCustColors:+P,
  Flags:+2,
  lCustData:+UL,
  lpfnHook:+P,
  lpTemplateName:+P"

Comment Information:

You can provide a comment and/or descriptive information following any field description by enclosing it in colons. These comments can be accessed via the XFA function as per the standard ProvideX documentation.