[Top] [Prev] [Next] [Bottom]



5. Field Manipulation Functions



Introduction
This chapter describes all of the FML and FML VIEWS functions, with the 
exception of the run-time mapping functions described in Chapter 4, "Field 
Definition and Use." In this chapter you will learn: 
    FML parameter conventions 
    how to use various field identifier mapping functions 
    how to allocate and initialize fielded buffers 
    how to move fielded buffers 
    how to access and modify fielded buffers 
    how to update fielded buffers 
    how to map fielded buffers to C structures 
    how to perform type conversions on data transferred to or from fielded 
    buffers 
    how to use indexing functions 
    how to use input/output functions 
    how to construct boolean expressions to make program decisions based on the 
    contents of fielded buffers 
For COBOL programs, the FML functions are not directly available. A procedure 
called FINIT is available to initialize a record for receiving FML data, and 
FVSTOF and FVFTOS are available to convert from a COBOL record to an FML buffer 
and back. These are described in detail in the BEA TUXEDO COBOL Guide. The COBOL 
interface will not be described further in this chapter. 
FML/FML32 and VIEW/VIEW32
There are two variants of FML. The original FML interface is based on 16-bit 
values for the length of fields and contains information identifying fields 
(hence FML16). FML16 is limited to 8191 unique fields, individual field lengths 
of up to 64K bytes, and a total fielded buffer size of 64K. The definitions, 
types, and function prototypes for this interface are in fml.h which must be 
included in an application program using the FML16 interface; and functions live 
in -lfml. A second interface, FML32, uses 32-bit values for the field lengths 
and identifiers. It allows for about 30 million fields, and field and buffer 
lengths of about 2 billion bytes. The definitions, types, and function 
prototypes for FML32 are in fml32.h; and functions live in -lfml32. All 
definitions, types, and function names for FML32 have a "32" suffix (for 
example, MAXFBLEN32, FBFR32, FLDID32, FLDLEN32, F_OVHD32, Fchg32, and error code 
Ferror32). Also the environment variables are suffixed with "32" (for example, 
FLDTBLDIR32, FIELDTBLS32, VIEWFILES32, and VIEWDIR32). For FML32, a fielded 
buffer pointer is of type "FBFR32 *", a field length has the type FLDLEN32, and 
the number of occurrences of a field has the type FLDOCC32. Also note that the 
default required alignment for FML32 buffers is 4-byte alignment. 
Existing FML16 applications that are written correctly can easily be changed to 
use the FML32 interface. All variables used in the calls to the FML functions 
must use the proper typedefs (FLDID, FLDLEN, and FLDOCC). Any call to tpalloc 
for an FML typed buffer should use the FMLTYPE definition instead of "FML". The 
application source code can be changed to use the 32-bit functions simply by 
changing the include of fml.h to inclusion of fml32.h followed by fml1632.h. The 
fml1632.h contains macros that convert all of the 16-bit type definitions to 
32-bit type definitions, and 16-bit functions and macros to 32-bit functions and 
macros. 
Functions are also provided to convert an FML32 fielded buffer to an FML16 
fielded buffer and vice versa. 
#include "fml.h"#include "fml32.h"intF32to16(FBFR *dest, FBFR32 *src)intF16to32(FBFR32 *dest, FBFR *src)
F32to16 converts a 32-bit FML buffer to a 16-bit FML buffer. It does this by 
converting the buffer on a field-by-field basis and then creating the index for 
the fielded buffer. A field is converted by generating a FLDID from a FLDID32, 
and copying the field value (and field length for string and carray fields). 
dest and src are pointers to the destination and source fielded buffers 
respectively. The source buffer is not changed. These functions can fail for 
lack of space; they can be re-issued after allocating enough additional space to 
complete the operation. F16to32 converts a 16-bit FML buffer to a 32-bit FML 
buffer. It lives in the fml32 library or shared object and sets Ferror32 on 
error. F32to16 lives in the fml library or shared object and sets Ferror on 
error. Note that both fml.h and fml32.h must be included to use these functions; 
fml1632.h may not be included in the same file. 
For the remainder of this chapter, rather than continuing to give both the FML 
and FML32 names, and VIEW and VIEW32 names, the 16-bit functions will be 
described. 
FML Parameters
To make it easier to remember the parameters for the FML functions, a convention 
has been adopted for the sequence of function parameters. FML parameters appear 
in the following sequence: 
    For functions that require a pointer to a fielded buffer (FBFR), this 
    parameter is first. If a function takes two fielded buffer pointers (such as 
    the transfer functions), the destination buffer comes first followed by the 
    source buffer. A fielded buffer pointer must point to an area that is 
    aligned on a short boundary (or an error is returned with Ferror set to 
    FALIGNERR) and the area must be a fielded buffer (or an error is returned 
    with Ferror set to FNOTFLD). 
    For the input/output functions, a pointer to a stream follows the fielded 
    buffer pointer. 
    For functions that need one, a field identifier (type FLDID) appears next 
    (in the case of Fnext, it is a pointer to a field identifier). 
    For functions that need a field occurrence (type FLDOCC), this parameter 
    comes next (for Fnext, it is a pointer to an occurrence number). 
    In functions where a field value is passed to or from the function, a 
    pointer to the beginning of the field value is given next (defined as a 
    character pointer but may be cast from any other pointer type). 
    When a field value is passed to a function that contains a character array 
    (carray) field, you must specify its length as the next parameter (type 
    FLDLEN). For functions that retrieve a field value, a pointer to the length 
    of the retrieval buffer must be passed to the function and this length 
    parameter is set to the length of the value retrieved. 
    A few functions require special parameters and differ from the preceding 
    conventions; these special parameters appear after the above parameters and 
    will be discussed in the individual function descriptions. 
    The following NULL values are defined for the various field types: 0 for 
    short and long; 0.0 for float and double; \0 for string (1 byte in length); 
    and a zero-length string for carray. 
Field Identifier Mapping Functions
Several functions allow the programmer to query field tables or field 
identifiers for information about fields during program execution. 
Fldid
Fldid returns the field identifier for a given valid field name and loads the 
field name/fieldid mapping tables from the field table files, if they do not 
already exist: 
FLDIDFldid(char *name)
where name is a valid field name. 
The space used by the mapping tables in memory can be freed using the 
Fnmid_unload or Fnmid_unload32 function. Note that these tables are separate 
from the tables loaded and used by the Fname function. 
Fname
Fname returns the field name for a given valid field identifier and loads the 
fieldid/name mapping tables from the field table files, if they do not already 
exist: 
char *Fname(FLDID fieldid)
where fieldid is a valid field identifier. 
The space used by the mapping tables in memory can be freed using the 
Fidnm_unload or Fidnm_unload32 function. Note that these tables are separate 
from the tables loaded and used by the Fldid function. 
Fldno
Fldno extracts the field number from a given field identifier: 
FLDOCCFldno(FLDID fieldid)
where fieldid is a valid field identifier. 
Fldtype
Fldtype extracts the field type (an integer, as defined in fml.h) from a given 
field identifier. 
intFldtype(FLDID fieldid)
where fieldid is a valid field identifier. 
Table 5-1 shows the possible values returned by Fldtype and their meanings. 
Table 5-1 Field Types Returned by FldtypeReturn Value Meaning 
            0 short integer 
            1 long integer 
            2 character 
            3 single-precision float 
            4 double-precision float 
            5 null-terminated string 
            6 character array 
    
Ftype
Ftype returns a pointer to a string containing the name of the type of a field 
given a field identifier: 
char *Ftype(FLDID fieldid)
where fieldid is a valid field identifier. 
For example: 
char *typename. . .typename = Ftype(fieldid);
returns a pointer to one of the following strings: short, long, char, float, 
double, string, or carray. 
Fmkfldid
As part of an application generator, or to reconstruct a field identifier, it 
might be useful to be able to make a field identifier from a type specification 
and an available field number. Fmkfldid provides this functionality: 
FLDIDFmkfldid(int type, FLDID num)
where 
    type is a valid type (an integer; see Fldtype, above) 
    num is a field number (it should be an unused field number, to avoid 
    confusion with existing fields) 
Buffer Allocation and Initialization
Most FML functions require a pointer to a fielded buffer as an argument. The 
typedef FBFR is available for declaring such pointers, as in this example: 
FBFR *fbfr;
In this chapter, the variable fbfr will be used to mean a pointer to a fielded 
buffer. 
Never attempt to declare fielded buffers themselves, only pointers to them. The 
functions used to reserve space for fielded buffers are explained in the 
following pages, but first we will describe a function that can be used to 
determine whether a given buffer is in fact a fielded buffer. 
Fielded
Fielded (or Fielded32) is used to test whether the specified buffer is fielded. 
intFielded(FBFR *fbfr)
Fielded32 is used with 32-bit FML. 
Fielded returns true (1) if the buffer is fielded. It returns false (0) if the 
buffer is not fielded and does not set Ferror in this case. 
Fneeded
The amount of memory to allocate for a fielded buffer depends on the maximum 
number of fields it will contain and the total amount of space needed for all 
the field values. The function Fneeded can be used to determine the amount of 
space in bytes needed for a fielded buffer; it takes the number of fields and 
the space needed for all field values (in bytes) as arguments. 
longFneeded(FLDOCC F, FLDLEN V)
where 
    F is the number of fields 
    V is the space for field values, in bytes 
The space needed for field values is computed by estimating the amount of space 
that would be required by each field value if stored in standard structures 
(e.g., a long is stored as a long and needs four bytes, etc.). For variable 
length fields, you should estimate the average amount of space needed for the 
field. The space calculated by Fneeded includes a fixed overhead for each field; 
it adds that to the space needed for the field values. 
Once you obtain the estimate of space from Fneeded, you can allocate the desired 
number of bytes using malloc(3) and set up a pointer to the allocated memory 
space. For example, the following allocates space for a fielded buffer large 
enough to contain 25 fields and 300 bytes of values: 
#define NF 25#define NV 300extern char *malloc;. . .  if((fbfr = (FBFR *)malloc(Fneeded(NF, NV))) == NULL)      F_error("pgm_name");   /* no space to allocate buffer */
However, this allocated memory space is not yet a fielded buffer. Finit must be 
used to initialize it. 
Finit
The Finit function initializes an allocated memory space as a fielded buffer. 
intFinit(FBFR *fbfr, FLDLEN buflen)
where 
    fbfr is a pointer to an uninitialized fielded buffer 
    buflen is the length of the buffer, in bytes 
A call to Finit to initialize the memory space allocated in the previous example 
above would look like the following: 
Finit(fbfr, Fneeded(NF, NV));
Now fbfr points to an initialized, empty fielded buffer. Up to Fneeded(NF, NV) 
bytes minus a small amount (F_OVHD as defined in fml.h) are available in the 
buffer to hold fields. 
Note: The numbers used in the malloc(3) (from the previous section) and Finit 
calls must be the same. 
Falloc
Calls to Fneeded, malloc(3) and Finit may be replaced by a single call to 
Falloc, which allocates the desired amount of space and initializes the buffer. 
FBFR *Falloc(FLDOCC F, FLDLEN V)
where 
    F is the number of fields 
    V is the space for field values, in bytes 
A call to Falloc that would replace the examples above would look like the 
following: 
extern FBFR *Falloc;. . . if((fbfr = Falloc(NF, NV)) == NULL)      F_error("pgm_name");   /* couldn't allocate buffer */
Storage allocated with Falloc (or Fneeded, malloc(3) and Finit) should be freed 
with Ffree. 
Remember that when using the BEA TUXEDO system, the ATMI functions tpalloc, 
tprealloc, and tpfree must be used to allocate and free message buffers, rather 
than the FML functions Falloc, Frealloc, and Free. 
Ffree
Ffree is used to free memory space allocated as a fielded buffer. 
intFfree(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
For example: 
#include  <fml.h>. . .if(Ffree(fbfr) < 0)      F_error("pgm_name");     /* not fielded buffer */
Ffree is recommended as opposed to free(3), because Ffree will invalidate a 
fielded buffer whereas free(3) will not. It is necessary to invalidate fielded 
buffers because malloc(3) re-uses memory that has been freed, without clearing 
it. Thus, if free(3) were used, it would be possible for malloc to return a 
piece of memory that looks like a valid fielded buffer, but is not. 
Space for a fielded buffer may also be reserved directly. The buffer must begin 
on a short boundary. The user must allocate at least F_OVHD bytes (defined in 
fml.h) for the buffer or an error will be returned from Finit. 
The following code is analogous to the preceding example but Fneeded cannot be 
used to size the static buffer since it is not a macro. 
/* the first line aligns the buffer */static short buffer[500/sizeof(short)];FBFR *fbfr=(FBFR *)buffer;. . .Finit(fbfr, 500);
It should be emphasized that the following code is quite wrong: 
FBFR badfbfr;. . .Finit(&badfbfr, Fneeded(NF, NV));
The structure for FBFR is not defined in the user header files so this will 
result in a compilation error. 
Fsizeof
Fsizeof returns the size of a fielded buffer in bytes: 
longFsizeof(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
For example: 
long bytes;. . .bytes = Fsizeof(fbfr);
Fsizeof returns the same number that Fneeded returned when the fielded buffer 
was originally allocated. 
Funused
Funused may be used to determine how much space is available in a fielded buffer 
for additional data: 
longFunused(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
For example: 
long unused;. . .unused = Funused(fbfr);
Note that Funused does not indicate where in the buffer the unused bytes are, 
only the number of unused bytes. 
Fused
Fused may be used to determine how much space is used in a fielded buffer for 
data and overhead: 
longFused(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
For example: 
long used;. . .used = Fused(fbfr);
Note that Fused does not indicate where in the buffer the used bytes are, only 
the number of used bytes. 
Frealloc
At some point, the buffer may run out of space, such as during the addition of a 
new field value. Frealloc can be used to increase (or decrease) the size of the 
buffer: 
FBFR *Frealloc(FBFR *fbfr, FLDOCC nf, FLDLEN nv)
where 
    fbfr is a pointer to a fielded buffer 
    nf is the new number of fields or 0 
    nv is the new space for field values, in bytes 
For example: 
FBFR *newfbfr;. . .if((newfbfr = Frealloc(fbfr, NF+5, NV+300)) == NULL)        F_error("pgm_name");      /* couldn't re-allocate space */else        fbfr = newfbfr;          /* assign new pointer to old */
In this case, the application needed to remember the number of fields and number 
of value space bytes previously allocated. Note that the arguments to Frealloc 
(as with its counterpart realloc(3)) are absolute values, not increments. This 
example will not work if space needs to be re-allocated several times. 
The following example shows a second way of incrementing the allocated space: 
/* define the increment size when buffer out of space */#define INCR    400FBFR *newfbfr;. . .if((newfbfr = Frealloc(fbfr, 0, Fsizeof(fbfr)+INCR)) == NULL)      F_error("pgm_name");       /* couldn't re-allocate space */else      fbfr = newfbfr;           /* assign new pointer to old */
Note that you do not need to know the number of fields or the value space size 
with which the buffer was last initialized. Thus, the easiest way to increase 
the size is to use the current size plus the increment as the value space. The 
above example could be executed as many times as needed without remembering past 
executions or values. The user need not call Finit after calling Frealloc. 
If the amount of additional space requested in the call to Frealloc is 
contiguous to the old buffer, newfbfr and fbfr in the examples above will be the 
same. However, defensive programming dictates that the user should declare 
newfbfr as a safeguard against the case where either a new value or NULL is 
returned. If Frealloc fails, do not use fbfr again. 
Note: The buffer size can only be decreased to the number of bytes currently 
being used in the buffer. 
Functions for Moving Fielded Buffers
The only restriction on the location of fielded buffers is that they must be 
aligned on a short boundary. Otherwise, fielded buffers are position-independent 
and may be moved freely around in memory. 
Fmove
If src points to a fielded buffer and dest points to an area of storage big 
enough to hold it, then the following might be used to move the fielded buffer: 
FBFR *src;char *dest;. . .memcpy(dest, src, Fsizeof(src));
The function memcpy, part of the C runtime memory management functions, moves 
the number of bytes indicated by its third argument from the area pointed to by 
its second argument to the area pointed to by its first argument. 
While memcpy may be used to copy a fielded buffer, the destination copy of the 
buffer looks just like the source copy. In particular, for example, the 
destination copy has the same number of unused bytes as the source buffer. 
Fmove acts like memcpy, but does not need an explicit length (it is computed): 
intFmove(char *dest, FBFR *src)
where 
    dest is a pointer to the destination buffer 
    src is a pointer to the source fielded buffer 
For example: 
FBFR *src;char *dest;. . .if(Fmove(dest,src) < 0)        F_error("pgm_name");
Fmove checks that the source buffer is indeed a fielded buffer, but does not 
modify the source buffer in any way. 
The destination buffer need not be a fielded buffer (that is, it need not have 
been allocated using Falloc), but it must be aligned on a short boundary (4-byte 
alignment for FML32). Thus, Fmove provides an alternative to Fcpy (see below) 
when it is desired to copy a fielded buffer to a non-fielded buffer, but Fmove 
does not check to make sure there is enough room in the destination buffer to 
receive the source buffer. 
Fcpy
Fcpy is used to overwrite one fielded buffer with another: 
intFcpy(FBFR *dest, FBFR *src)
where 
    dest is a pointer to the destination fielded buffer 
    src is a pointer to the source fielded buffer 
Fcpy preserves the overall buffer length of the overwritten fielded buffer; 
thus, Fcpy is useful for expanding or reducing the size of a fielded buffer. For 
example: 
FBFR *src, *dest;. . .if(Fcpy(dest, src) < 0)        F_error("pgm_name");
Unlike Fmove, where dest could point to an uninitialized area, Fcpy expects dest 
to point to an initialized fielded buffer (allocated using Falloc) and also 
checks to see that it is big enough to accommodate the data from the source 
buffer. 
Note: You cannot reduce the size of a fielded buffer below the amount of space 
needed for currently held data. 
As with Fmove, the source buffer is not modified by Fcpy. 
Field Access and Modification Functions
This section discusses how to update and access fielded buffers using the field 
types of the fields without doing any conversions. The functions that allow you 
to convert data from one type to another upon transfer to/from a fielded buffer 
are listed under "Conversion Functions" later in this chapter. 
Fadd
The Fadd function adds a new field value to the fielded buffer. 
intFadd(FBFR *fbfr, FLDID fieldid, char *value, FLDLEN len)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    value is a pointer to a new value. Its type is shown as char*, but when it 
    is used, its type must be the same type as the value to be added (see below) 
    
    len is the length of the value if its type is FLD_CARRAY 
If no occurrence of the field exists in the buffer, then the field is added. If 
one or more occurrences of the field already exist, then the value is added as a 
new occurrence of the field, and is assigned an occurrence number 1 greater than 
the current highest occurrence. (To add a specific occurrence, Fchg must be 
used.) 
Fadd, like all other functions that take or return a field value, expects a 
pointer to a field value, never the value itself. 
If the field type is such that the field length is fixed (short, long, char, 
float, or double) or can be determined (string), the field length need not be 
given (it is ignored). If the field type is a character array, the length must 
be specified; the length is defined as type FLDLEN. For example: 
FLDID fieldid, Fldid;FBFR *fbfr;. . .fieldid = Fldid("fieldname");if(Fadd(fbfr, fieldid, "new value", (FLDLEN)9) < 0)          F_error("pgm_name");
gets the field identifier for the desired field and adds the field value to the 
buffer. 
It is assumed (by default) that the native type of the field is a character 
array so that the length of the value must be passed to the function. If the 
value being added is not a character array, the type of value must reflect the 
type of the value it points to; for instance, the following example adds a long 
field value: 
long lval;. . .lval = 123456789;if(Fadd(fbfr, fieldid, &lval, (FLDLEN)0) < 0)          F_error("pgm_name");
For character array fields, null fields may be indicated by a length of 0. For 
string fields, the null string may be stored since the NULL terminating byte is 
actually stored as part of the field value: a string consisting of only the NULL 
terminating byte is considered to have a length of 1. For all other types (fixed 
length types), you may choose some special value that is interpreted by the 
application as a NULL, but the size of the value will be taken from its field 
type (e.g., length of four for a long) regardless of what value is actually 
passed. Passing a NULL value address will result in an error (FEINVAL). 
Fappend
The Fappend function appends a new field value to the fielded buffer. 
intFappend(FBFR *fbfr, FLDID fieldid, char *value, FLDLEN len)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    value is a pointer to a new value. Its type is shown as char *, but when it 
    is used, its type must be the same type as the value to be appended (see 
    below) 
    len is the length of the value if its type is FLD_CARRAY 
Fappend appends a new occurrence of the field fieldid with a value located at 
value to the fielded buffer and puts the buffer into append mode. Append mode 
provides optimized buffer construction for large buffers constructed of many 
rows of a common set of fields. A buffer that is in append mode is restricted as 
to what operations may be performed on the buffer. Only calls to the following 
FML routines are allowed in append mode: Fappend, Findex, Funindex, Ffree, 
Fused, Funused and Fsizeof. Calls to Findex or Funindex will end append mode. 
The following example shows the construction of a 500 row buffer with 5 fields 
per row using Fappend. 
for (i=0; i 500 ;i++) {   if ((Fappend(fbfr, LONGFLD1, &lval1[i], (FLDLEN)0) < 0) ||      (Fappend(fbfr, LONGFLD2, &lval2[i], (FLDLEN)0) < 0) ||      (Fappend(fbfr, STRFLD1, &str1[i], (FLDLEN)0) < 0) ||      (Fappend(fbfr, STRFLD2, &str2[i], (FLDLEN)0) < 0) ||      (Fappend(fbfr, LONGFLD3, &lval3[i], (FLDLEN)0) < 0)) {      F_error("pgm_name");     break;   }}Findex(fbfr, 0);
Fappend, like all other functions that take or return a field value, expects a 
pointer to a field value, never the value itself. 
If the field type is such that the field length is fixed (short, long, char, 
float, or double) or can be determined (string), the field length need not be 
given (it is ignored). If the field type is a character array, the length must 
be specified; the length is defined as type FLDLEN. 
It is assumed (by default) that the native type of the field is a character 
array so that the length of the value must be passed to the function. If the 
value being appended is not a character array, the type of value must reflect 
the type of the value it points to. 
For character array fields, null fields may be indicated by a length of 0. For 
string fields, the null string may be stored since the NULL terminating byte is 
actually stored as part of the field value: a string consisting of only the NULL 
terminating byte is considered to have a length of 1. For all other types (fixed 
length types), you may choose some special value that is interpreted by the 
application as a NULL, but the size of the value will be taken from its field 
type (e.g., length of four for a long) regardless of what value is actually 
passed. Passing a NULL value address will result in an error (FEINVAL). 
Fchg
Fchg changes the value of a field in the buffer. 
intFchg(FBFR *fbfr, FLDID fieldid, FLDOCC oc, char *value, FLDLEN len)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number of the field 
    value is a pointer to a new value. Its type is shown as char *, but when it 
    is used, its type must be the same type as the value to be added (see Fadd) 
    len is the length of the value if its type is FLD_CARRAY 
For example, to change a field of type carray to a new value stored in value: 
FBFR *fbfr;FLDID fieldid;FLDOCC oc;FLDLEN len;char value[50];. . .strcpy(value, "new value");flen = strlen(value);if(Fchg(fbfr, fieldid, oc, value, len) < 0)       F_error("pgm_name");
If oc is -1, then the field value is added as a new occurrence to the buffer. If 
oc is 0 or greater and the field is found, then the field value is modified to 
the new value specified. If oc is 0 or greater and the field is not found, then 
NULL occurrences are added to the buffer until the value can be added as the 
specified occurrence. For example, changing field occurrence 3 for a field that 
does not exist on a buffer will cause three NULL occurrences to be added 
(occurrences 0, 1 and 2), followed by occurrence 3 with the specified field 
value. Null values consist of the NULL string "\0" (1 byte in length) for string 
and character values, 0 for long and short fields, 0.0 for float and double 
values, and a zero-length string for a character array. 
The new or modified value is contained in value. If it is a character array, its 
length is given in len (len is ignored for other field types). If the value 
pointer is NULL and the field is found, then the field is deleted. If the field 
occurrence to be deleted is not found, it is considered an error (FNOTPRES). 
The buffer must have enough room to contain the modified or added field value, 
or an error is returned (FNOSPACE). 
Fcmp
Fcmp compares the field identifiers and field values of two fielded buffers. 
intFcmp(FBFR *fbfr1, FBFR *fbfr2)
where 
    fbfr1 and fbfr2 are pointers to fielded buffers 
The function returns a 0 if the buffers are identical; it returns a -1 on any of 
the following conditions: 
    the fieldid of a fbfr1 field is less than the field id of the corresponding 
    field of fbfr2 
    the value of a fbfr1 field is less than the value of the corresponding field 
    of fbfr2 
    fbfr1 is shorter than fbfr2 
Fcmp returns a 1 if any of the reverse set of the above conditions is true (for 
example, if the field id of a fbfr2 field is less than the field id of the 
corresponding field of fbfr1, etc.). 
Fdel
The Fdel function deletes the specified field occurrence. 
intFdel(FBFR *fbfr, FLDID fieldid, FLDOCC oc)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number 
For example, 
FLDOCC occurrence;. . .occurrence=0;if(Fdel(fbfr, fieldid, occurrence) < 0)            F_error("pgm_name");
deletes the first occurrence of the field indicated by the specified field 
identifier. If it does not exist, the function returns -1 (Ferror is set to 
FNOTPRES). 
Fdelall
Fdelall deletes all occurrences of the specified field from the buffer: 
intFdelall(FBFR *fbfr, FLDID fieldid)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
For example: 
if(Fdelall(fbfr, fieldid) < 0)     F_error("pgm_name");        /* field not present */
If the field is not found, the function returns -1 (Ferror is set to FNOTPRES). 
Fdelete
Fdelete deletes all occurrences of all fields listed in the array of field 
identifiers, fieldid[]: 
intFdelete(FBFR *fbfr, FLDID *fieldid)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a pointer to the list of field identifiers to be deleted 
The update is done directly to the fielded buffer. The array of field 
identifiers does not need to be in any specific order, but the last entry in the 
array must be field identifier 0 (BADFLDID). For example: 
#include "fldtbl.h"FBFR *dest;FLDID fieldid[20];. . .fieldid[0] = A;   /* field id for field A */fieldid[1] = D;   /* field id for field D */fieldid[2] = BADFLDID;   /* sentinel value */if(Fdelete(dest, fieldid) < 0)         F_error("pgm_name");
If the destination buffer has fields A, B, C, and D, this example will result in 
a buffer that contains only occurrences of fields B and C. 
Fdelete is a more efficient way of deleting several fields from a buffer than 
using several Fdelall calls. 
Ffind
Ffind finds the value of the specified field occurrence in the buffer: 
char *Ffind(FBFR *fbfr, FLDID fieldid, FLDOCC oc, FLDLEN *len)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number 
    len is the length of the value found 
In the declaration above the return value to Ffind is shown as a character 
pointer data type (char* in C). The actual type of the pointer returned is the 
same as the type of the value it points to. 
An example of the use of the function is: 
#include "fldtbl.h"FBFR *fbfr;FLDLEN len;char* Ffind, *value;. . .if((value=Ffind(fbfr,ZIP,0, &len)) == NULL)      F_error("pgm_name");
If the field is found, its length is returned in len (if len is NULL, the length 
is not returned), and its location is returned as the value of the function. If 
the field is not found, NULL is returned, and Ferror is set to FNOTPRES. 
Ffind is useful for gaining "read-only" access to a field. The value returned by 
Ffind should not be used to modify the buffer. Field value modification should 
only be done by the functions Fadd or Fchg. 
The value returned by Ffind is valid only so long as the buffer remains 
unmodified. The value is guaranteed to be aligned on a short boundary but may 
not be aligned on a long or double boundary, even if the field is of that type 
(see the conversion functions described later in this document for aligned 
values). On processors that require proper alignment of variables, referencing 
the value when not aligned properly will cause a system error, as in the 
following example: 
long *l1,l2;FLDLEN length;char *Ffind;. . .if((l1=(long *)Ffind(fbfr, ZIP, 0, &length)) == NULL)        F_error("pgm_name");else        l2 = *l1;
and should be re-written as: 
if((l1==(long *)Ffind(fbfr, ZIP, 0, &length)) == NULL)         F_error("pgm_name");else         memcpy(&l2,l1,sizeof(long));
Ffindlast
This function finds the last occurrence of a field in a fielded buffer and 
returns a pointer to the field, as well as the occurrence number and length of 
the field occurrence: 
char *Ffindlast(FBFR *fbfr, FLDID fieldid, FLDOCC *oc, FLDLEN *len)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is a pointer to the occurrence number of the last field occurrence found 
    len is a pointer to the length of the value found 
In the declaration above the return value to Ffindlast is shown as a character 
pointer data type (char* in C). The actual type of the pointer returned is the 
same as the type of the value it points to. 
Ffindlast acts like Ffind, except that you do not specify a field occurrence. 
Instead, both the occurrence number and the value of the last field occurrence 
are returned. However, if you specify NULL for occurrence on calling the 
function, the occurrence number will not be returned. 
The value returned by Ffindlast is valid only as long as the buffer remains 
unchanged. 
Ffindocc
Ffindocc looks at occurrences of the specified field on the buffer and returns 
the occurrence number of the first field occurrence that matches the 
user-specified field value: 
FLDOCCFfindocc(FBFR *fbfr, FLDID fieldid, char *value, FLDLEN len;)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    value is a pointer to a new value. Its type is shown as char*, but when it 
    is used, its type must be the same type as the value to be added (see Fadd) 
    len is the length of the value if type carray 
For example, 
#include "fldtbl.h"FBFR *fbfr;FLDOCC oc;long zipvalue;. . .zipvalue = 123456;if((oc=Ffindocc(fbfr,ZIP,&zipvalue, 0)) < 0)       F_error("pgm_name");
would set oc to the occurrence for the specified zip code. 
Regular expressions are supported for string fields. For example, 
#include "fldtbl.h"FBFR *fbfr;FLDOCC oc;char *name;. . .name = "J.*"if ((oc = Ffindocc(fbfr, NAME, name, 1)) < 0)        F_error("pgm_name");
would set oc to the occurrence of NAME that starts with "J". 
Note: To enable pattern matching on strings, the fourth argument to Ffindocc 
must be nonzero. If zero, simple string compare is performed. If the field value 
is not found, -1 is returned. 
For upward compatibility, a circumflex (^) and dollar sign ($) are implied to 
surround the regular expression; thus, the above example is actually interpreted 
as "^(J.*)$". This means that the regular expression must match the entire 
string value in the field. 
Fget
Fget should be used to retrieve a field from a fielded buffer when the value is 
to be modified: 
intFget(FBFR *fbfr, FLDID fieldid, FLDOCC oc, char *loc, FLDLEN *maxlen)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number 
    loc is a pointer to a buffer to copy the field value into 
    maxlen is a pointer to the length of the source buffer on calling the 
    function, and a pointer to the length of the field on return 
The caller provides Fget with a pointer to a private buffer, as well as the 
length of the buffer. If maxlen is specified as NULL, then it is assumed that 
the destination buffer is large enough to accommodate the field value, and its 
length is not returned. 
Fget returns an error if the desired field is not in the buffer (FNOTPRES), or 
if the destination buffer is too small (FNOSPACE). For example, 
FLDLEN len;char value[100];. . .len=sizeof(value);if(Fget(fbfr, ZIP, 0, value, &len) < 0)          F_error("pgm_name");
gets the zip code assuming it is stored as a character array or string. If it is 
stored as a long, then it would be retrieved by: 
FLDLEN len;long value;. . .len = sizeof(value);if(Fget(fbfr, ZIP, 0, value, &len) < 0)          F_error("pgm_name");
Fgetalloc
Like Fget, Fgetalloc finds and makes a copy of a buffer field, but it acquires 
space for the field via a call to malloc(3): 
char *Fgetalloc(FBFR *fbfr, FLDID fieldid, FLDOCC oc, FLDLEN *extralen)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number 
    extralen is a pointer to the additional length to be acquired on calling the 
    function, and a pointer to the actual length acquired on return 
In the declaration above the return value to Fgetalloc is shown as a character 
pointer data type (char* in C). The actual type of the pointer returned is the 
same as the type of the value it points to. 
On success, Fgetalloc returns a valid pointer to the copy of the properly 
aligned buffer field; on error it returns NULL. If malloc(3) fails, Fgetalloc 
returns an error (Ferror is set to FMALLOC). 
The last parameter to Fgetalloc specifies an extra amount of space to be 
acquired if, for instance, the gotten value is to be expanded before 
re-insertion into the fielded buffer. On success, the length of the allocated 
buffer is returned in extralen. For example: 
FLDLEN extralen;FBFR *fieldbfrchar *Fgetalloc;. . .extralen = 0;if (fieldbfr = (FBFR *)Fgetalloc(fbfr, ZIP, 0, &extralen) == NULL)         F_error("pgm_name");
It is the responsibility of the caller to free space acquired by Fgetalloc. 
Fgetlast
Fgetlast is used to retrieve the last occurrence of a field from a fielded 
buffer when the value is to be modified: 
intFgetlast(FBFR *fbfr, FLDID fieldid, FLDOCC *oc, char *loc, FLDLEN *maxlen)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is a pointer to the occurrence number of the last field occurrence 
    loc is a pointer to a buffer to copy the field value into 
    maxlen is a pointer to the length of the source buffer on calling the 
    function, and a pointer to the length of the field on return 
The caller provides Fgetlast with a pointer to a private buffer, as well as the 
length of the buffer. Fgetlast acts like Fget, except that you do not specify a 
field occurrence. Instead, both the occurrence number and the value of the last 
field occurrence are returned. However, if you specify NULL for occ on calling 
the function, the occurrence number will not be returned. 
Fnext
Fnext finds the next field in the buffer after the specified field occurrence: 
intFnext(FBFR *fbfr, FLDID *fieldid, FLDOCC *oc, char *value, FLDLEN *len)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a pointer to a field identifier 
    oc is a pointer to the occurrence number 
    value is a pointer of the same type as the value contained in the next field 
    
    len is a pointer to the length of *value 
A fieldid of FIRSTFLDID should be specified to get the first field in a buffer; 
the field identifier and occurrence number of the first field occurrence are 
returned in the corresponding parameters; if the field is not NULL, its value is 
copied into the memory location addressed by the value pointer; the len 
parameter is used to determine if value has enough space allocated to contain 
the field value (Ferror is set to FNOSPACE if it does not); and, the length of 
the value is returned in the len parameter. Note that if the value of the field 
is non-null, then the len parameter is also assumed to contain the length of the 
currently allocated space for value. 
If the field value is NULL, then the value and length parameters are not 
changed. 
If no more fields are found, Fnext returns 0 (end of buffer) and fieldid, 
occurrence, and value are left unchanged. 
If the value parameter is not NULL, the length parameter is also assumed to be 
non-NULL. 
The following example reads all field occurrences in the buffer: 
FLDID fieldid;FLDOCC occurrence;char *value[100];FLDLEN len;. . .for(fieldid=FIRSTFLDID,len=sizeof(value);     Fnext(fbfr,&fieldid,&occurrence,value,&len) > 0;     len=sizeof(value)) {   /* code for each field occurrence */}
Fnum
Fnum returns the number of fields contained in the specified buffer, or -1 on 
error: 
FLDOCCFnum(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
For example: 
if((cnt=Fnum(fbfr)) < 0)  F_error("pgm_name");else  fprintf(stdout,"%d fields in buffer\n",cnt);
would print the number of fields in the specified buffer. 
Foccur
Foccur returns the number of occurrences for the specified field in the buffer: 
FLDOCCFoccur(FBFR *fbfr, FLDID fieldid)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
Zero is returned if the field does not occur in the buffer and -1 is returned on 
error. For example: 
FLDOCC cnt;. . .if((cnt=Foccur(fbfr,ZIP)) < 0) F_error("pgm_name");else fprintf(stdout,"Field ZIP occurs %d times in buffer\n",cnt);
would print the number of occurrences of the field ZIP in the specified buffer. 
Fpres
Fpres returns true (1) if the specified field occurrence exists and false (0) 
otherwise: 
intFpres(FBFR *fbfr, FLDID fieldid, FLDOCC oc)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number 
For example: 
Fpres(fbfr,ZIP,0)
would return true if the field ZIP exists in the fielded buffer pointed to by 
fbfr. 
Fvals and Fvall
Fvals works like Ffind for string values but guarantees that a pointer to a 
value is returned. Fvall works like Ffind for long and short values, but returns 
the actual value of the field as a long, instead of a pointer to the value. 
char* Fvals(FBFR *fbfr,FLDID fieldid,FLDOCC oc)
char*Fvall(FBFR *fbfr,FLDID fieldid,FLDOCC oc)
where in both functions 
    fbfr is a pointer to a fielded buffer 
    fieldid is a field identifier 
    oc is the occurrence number 
For Fvals, if the specified field occurrence is not found, the NULL string, \0, 
is returned. This function is useful for passing the value of a field to another 
function without checking the return value. This function is valid only for 
fields of type string; the NULL string is automatically returned for other field 
types (i.e., no conversion is done). 
For Fvall, if the specified field occurrence is not found, then 0 is returned. 
This function is useful for passing the value of a field to another function 
without checking the return value. This function is valid only for fields of 
type long and short; 0 is automatically returned for other field types (i.e., no 
conversion is done). 
Buffer Update Functions
The functions listed in this section access and update entire fielded buffers, 
rather than individual fields in the buffers. These functions use at most three 
parameters, dest, src, and fieldid, where 
    dest is a pointer to a destination fielded buffer 
    src is a pointer to a source fielded buffer 
    fieldid is a field identifier or an array of field identifiers 
Fconcat
Fconcat adds fields from the source buffer to the fields that already exist in 
the destination buffer. 
intFconcat(FBFR *dest, FBFR *src)
Occurrences in the destination buffer are maintained (i.e., retained and not 
modified) and new occurrences from the source buffer are added with greater 
occurrence numbers than any existing occurrences for each field (the fields are 
maintained in field identifier order). 
In the following example: 
FBFR *src, *dest;. . .if(Fconcat(dest,src) < 0)       F_error("pgm_name");
if dest has fields A, B, and two occurrences of C, and src has fields A, C, and 
D, the resultant dest will have two occurrences of field A (destination field A 
and source field A), field B, three occurrences of field C (two from dest and 
the third from src), and field D. 
This operation will fail if there is not enough space to contain the new fields 
(FNOSPACE); in this case, the destination buffer remains unchanged. 
Fjoin
Fjoin is used to join two fielded buffers based on matching fieldid/occurrence. 
intFjoin(FBFR *dest, FBFR *src)
For fields that match on fieldid/occurrence, the field value is updated in the 
destination buffer with the value from the source buffer. Fields in the 
destination buffer that have no corresponding fieldid/occurrence in the source 
buffer are deleted. Fields in the source buffer that have no corresponding 
fieldid/occurrence in the destination buffer are not added to the destination 
buffer. Thus, 
if(Fjoin(dest,src) < 0)     F_error("pgm_name");
Using the input buffers in the previous example will result in a destination 
buffer that has source field value A and source field value C. This function may 
fail due to lack of space if the new values are larger than the old (FNOSPACE); 
in this case, the destination buffer will have been modified. However, if this 
happens, the destination buffer may be re-allocated using Frealloc and the Fjoin 
function repeated (even if the destination buffer has been partially updated, 
repeating the function will give the correct results). 
Fojoin
Fojoin is similar to Fjoin, but it does not delete fields from the destination 
buffer that have no corresponding fieldid/occurrence in the source buffer. 
intFojoin(FBFR *dest, FBFR *src)
Note that fields that exist in the source buffer that have no corresponding 
fieldid/occurrence in the destination buffer are not added to the destination 
buffer. For example: 
if(Fojoin(dest,src) < 0)      F_error("pgm_name");
Using the input buffers from the previous example, dest will contain the source 
field value A, the destination field value B, the source field value C, and the 
second destination field value C. As with Fjoin, this function can fail for lack 
of space (FNOSPACE) and can be re-issued again after allocating more space to 
complete the operation. 
Fproj
Fproj is used to update a buffer in place so that only the desired fields are 
kept (in other words, the result is a projection on specified fields). 
intFproj(FBFR *fbfr, FLDID *fieldid)
These fields are specified in an array of field identifiers passed to the 
function. The update is performed directly in the fielded buffer. For example: 
#include "fldtbl.h"FBFR *fbfr;FLDID fieldid[20];. . .fieldid[0] = A;   /* field id for field A */fieldid[1] = D;   /* field id for field D */fieldid[2] = BADFLDID;   /* sentinel value */if(Fproj(fbfr, fieldid) < 0)      F_error("pgm_name");
If the buffer has fields A, B, C, and D, the example results in a buffer that 
contains only occurrences of fields A and D. Note that the entries in the array 
of field identifiers do not need to be in any specific order, but the last value 
in the array of field identifiers must be field identifier 0 (BADFLDID). 
Fprojcpy
Fprojcpy is similar to Fproj but the projection is done into a destination 
buffer. 
intFprojcpy(FBFR *dest, FBFR *src, FLDID *fieldid)
Any fields in the destination buffer are first deleted and the results of the 
projection on the source buffer are copied into the destination buffer. Using 
the above example, 
if(Fprojcpy(dest, src, fieldid) < 0)       F_error("pgm_name");
will place the results of the projection in the destination buffer. The entries 
in the array of field identifiers may be re-arranged; the field identifier array 
is sorted if they are not in numeric order. 
Fupdate
Fupdate updates the destination buffer with the field values in the source 
buffer. 
intFupdate(FBFR *dest, FBFR *src)
For fields that match on fieldid/occurrence, the field value is updated in the 
destination buffer with the value in the source buffer (like Fjoin). Fields on 
the destination buffer that have no corresponding field on the source buffer are 
left untouched (like Fojoin). Fields on the source buffer that have no 
corresponding field on the destination buffer are added to the destination 
buffer (like Fconcat). For example: 
if(Fupdate(dest,src) < 0)     F_error("pgm_name");
If the src buffer has fields A, C, and D, and the dest buffer has fields A, B, 
and two occurrences of C, the updated destination buffer will contain: the 
source field value A, the destination field value B, the source field value C, 
the second destination field value C, and the source field value D. 
VIEWS Functions
Fvftos
This function transfers data from a fielded buffer to a C structure using a 
specified view description. 
intFvftos(FBFR *fbfr, char *cstruct, char *view)
where 
    fbfr is a pointer to a fielded buffer 
    cstruct is a pointer to a structure 
    view is a pointer to a view name string 
If the named view is not found, Fvftos returns -1, and Ferror is set to 
FBADVIEW. 
When transferring data from a fielded buffer to a C structure, the following 
rules apply: 
    If a field in the fielded buffer is not mapped to a C structure member, the 
    field is ignored. 
    If a field is not in the fielded buffer, but appears in the view description 
    and is mapped to a structure member, the corresponding null value is copied 
    into the member. 
    If a field in the fielded buffer contains data of type string or carray, 
    characters will be copied into the structure up to the size of the mapped 
    structure member (i.e., source values that are too long will be truncated). 
    If the source value is shorter than the mapped structure member, the 
    remainder of the member value will be padded with null (0) characters. 
    String values will always be terminated with a null character (even if this 
    means truncating the value). 
    If the number of occurrences of a field in the buffer is equal to the number 
    of mapped structure members, then the fielded data is copied into the C 
    structure. 
    If the number of occurrences of a field in the buffer is greater than the 
    number of mapped structure members, then the fielded data is ignored. 
    If the number of occurrences of a field in the buffer is less than the 
    number of mapped structure members, then the extra members are assigned the 
    corresponding null value. 
For example, 
#include <stdio.h>#include "fml.h"#include "custdb.flds.h"#include "custdb.h"struct custdb cust;FBFR *fbfr;. . .fbfr = Falloc(800,1000);Fvinit((char *)&cust,"custdb");    /* initialize cust */str = "string1";Fadd(fbfr,ACTION,str,(FLDLEN)8);str = "abc";Fadd(fbfr,BUG_CURS,str,(FLDLEN)4);Fvftos(fbfr,(char *)&cust,"custdb");. . .
would put "string1" into cust.action[0] and "abc" into cust.bug[0]. All other 
members in the cust structure should contain null values. 
View custdb is defined in "VIEWS Examples" in Chapter 6. 
Fvstof
This function transfers data from a C structure to a fielded buffer using a 
specified view description. 
intFvstof(FBFR *fbfr, char *cstruct, int mode, char *view)
where 
    fbfr is a pointer to a fielded buffer 
    cstruct is a pointer to a structure 
    mode is one of the following: FUPDATE, FJOIN, FOJOIN, FCONCAT 
    view is a pointer to a view name string 
The transfer process obeys the rules listed under the FML function corresponding 
to the mode parameter (Fupdate, Fjoin, Fojoin, and Fconcat, described in this 
chapter). 
If the named view is not found, Fvstof returns -1, and Ferror is set to 
FBADVIEW. 
Note: Null values are not transferred from a structure member to a fielded 
buffer. That is, during a structure-to-field transfer, if a structure member 
contains the (default or user-specified) null value defined for that member, the 
member is ignored. 
Fvnull
Fvnull is used to determine if an occurrence in a C structure contains the null 
value for that field. 
intFvnull(char *cstruct, char *cname, FLDOCC oc, char *view)
where 
    cstruct is a pointer to a structure 
    cname is a pointer to the name of a structure member 
    oc is the index to a particular element 
    view is a pointer to a view name string 
Fvnull returns: 
 1     if an occurrence is null 0     if an occurrence is not null-1     if an error occurred
Fvsinit
This function initializes all elements in a C structure to their appropriate 
null value. 
intFvsinit(char *cstruct, char *view)
where 
    cstruct is a pointer to a structure 
    view is a pointer to a view name string 
Fvopt
This function allows users to change flag options at run time. 
intFvopt(char *cname, int option, char *view)
where 
    cname is the name of a structure member 
    option is one of the options listed below 
    view is a pointer to a view name string 
Possible values for the option parameter are: 
    F_FTOS 
    Allows one-way mapping from fielded buffers to C structures. Similar to the 
    S option in view descriptions. 
    F_STOF 
    Allows one-way mapping from C structures to fielded buffers. Similar to the 
    F option in view descriptions. 
    F_BOTH 
    Allows two-way mapping between C structures and fielded buffers. 
    F_OFF 
    Turns off mapping of the specified member. Similar to the N option in view 
    descriptions. 
Note that changes to view descriptions are not permanent. They are guaranteed 
only until another view description is accessed. 
Fvselinit
This function initializes an individual member of a C structure to its 
appropriate null value. It sets the ACM of the element to 0, if the C flag is 
used in the view file; it sets the ALMs to the length of the associated null 
value, if the L flag is used in the view file. 
intFvselinit(char *cstruct, char *cname, char *view)
where 
    cstruct is a pointer to a structure 
    cname is a pointer to the name of a structure member 
    view is a pointer to a view name string 
Conversion Functions
FML provides a set of routines that perform data conversion upon reading or 
writing a fielded buffer. 
Generally, the functions behave like their non-conversion counterparts, except 
that they provide conversion from a user type to the native field type when 
writing to a buffer, and from the native type to a user type when reading from a 
buffer. 
The native type of a field is the type specified for it in its field table entry 
and encoded in its field identifier. (The only exception to this rule is 
CFfindocc, which, although it is a read operation, converts from the 
user-specified type to the native type before calling Ffindocc.) The function 
names are the same as their non-conversion FML counterparts except they have a 
"C" prefix. 
CFadd
The CFadd function adds a user supplied item to a buffer creating a new field 
occurrence within the buffer: 
intCFadd(FBFR *fbfr, FLDID fieldid, char *value, FLDLEN len, int type)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is the field identifier of the field to be added 
    value is a pointer to the value to be added 
    len is the length of the value, if of type carray 
    type is the type of the value 
Before the field addition, the data item is converted from a user supplied type 
to the type specified in the field table as the fielded buffer storage type of 
the field. If the source type is FLD_CARRAY (character array), the length 
argument should be set to the length of the array. For example, 
if(CFadd(fbfr,ZIP,"12345",(FLDLEN)0,FLD_STRING) < 0)      F_error("pgm_name");
If the ZIP (zip code) field were stored in a fielded buffer as a long integer, 
the function would convert "12345" to a long integer representation, before 
adding it to the fielded buffer pointed to by fbfr (note that the field value 
length is given as 0 since the function can determine it; the length is needed 
only for type FLD_CARRAY). The following code fragment: 
long zipval;. . .zipval = 12345;if(CFadd(fbfr,ZIP,&zipval,(FLDLEN)0,FLD_LONG) < 0)      F_error("pgm_name");
puts the same value into the fielded buffer, but does so by presenting it as a 
long, instead of as a string. Note that the value must first be put into a 
variable, since C does not permit the construct &12345L. CFadd returns 1 on 
success, and -1 on error, in which case Ferror is set appropriately. 
CFchg
The function CFchg acts like CFadd, except that it changes the value of a field 
(after conversion of the supplied value): 
intCFchg(FBFR *fbfr, FLDID fieldid, FLDOCC oc, char *value, FLDLEN len, int type)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is the field identifier of the field to be changed 
    oc is the occurrence number of the field to be changed 
    value is a pointer to the value to be added 
    len is the length of the value, if of type carray 
    type is the type of the value 
For example, 
FLDOCC occurrence;long zipval;. . .zipval = 12345;occurrence = 0;if(CFchg(fbfr,ZIP,occurrence,&zipval,(FLDLEN)0,FLD_LONG) < 0)       F_error("pgm_name");
would change the first occurrence (occurrence 0) of field ZIP to the specified 
value, doing any needed conversion. 
If the specified occurrence is not found, then null occurrences are added to pad 
the buffer with multiple occurrences until the value can be added as the 
specified occurrence. 
CFget
CFget is the conversion analog of Fget. The difference is that it copies a 
converted value to the user-supplied buffer: 
intCFget(FBFR *fbfr, FLDID fieldid, FLDOCC oc, char *buf, FLDLEN *len, int type)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is the field identifier of the field to be retrieved 
    oc is the occurrence number of the field 
    buf is a pointer to the post-conversion buffer 
    len is the length of the value, if of type carray 
    type is the type of the value 
Using the previous example, 
FLDLEN len;. . .len=sizeof(zipval);if(CFget(fbfr,ZIP,occurrence,&zipval,&len,FLD_LONG) < 0)        F_error("pgm_name");
would get the value that was just stored in the buffer, no matter what format, 
and convert it back to a long integer. If the length pointer is NULL, then the 
length of the value retrieved and converted is not returned. 
CFgetalloc
CFgetalloc is like Fgetalloc; you are responsible for freeing the malloc'd space 
for the returned (converted) value with free: 
char *CFgetalloc(FBFR *fbfr, FLDID fieldid, FLDOCC oc, int type, FLDLEN *extralen)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is the field identifier of the field to be converted 
    oc is the occurrence number of the field 
    type is the type to which the value is converted 
    extralen on calling the function is a pointer to the extra allocation 
    amount; on return, it is a pointer to the size of the total allocated area 
In the declaration above the return value to CFgetalloc is shown as a character 
pointer data type (char* in C). The actual type of the pointer returned is the 
same as the type of the value it points to. 
The previously stored value could be retrieved into space allocated 
automatically for you by the following code: 
char *value;FLDLEN extra;. . .extra = 25;if((value=CFgetalloc(fbfr,ZIP,0,FLD_LONG,&extra)) == NULL) F_error("pgm_name");
The value extra in the function call indicates that the function should not only 
allocate enough space for the retrieved value but an additional 25 bytes and the 
total amount of space allocated will be returned in this variable. 
CFfind
CFfind returns a pointer to a converted value of the desired field: 
char *CFfind(FBFR *fbfr, FLDID fieldid, FLDOCC oc, FLDLEN len, int type)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is the field identifier of the field to be retrieved 
    oc is the occurrence number of the field 
    len is the length of the post-conversion value 
    type is the type to which the value is converted 
In the declaration above the return value to CFfind is shown as a character 
pointer data type (char* in C). The actual type of the pointer returned is the 
same as the type of the value it points to. 
Like Ffind, this pointer should be considered read only. For example: 
char *CFfind;FLDLEN len;long *value;. . .if((value=(long *)CFfind(fbfr,ZIP,occurrence,&len,FLD_LONG))== NULL)   F_error("pgm_name");
would return a pointer to a long containing the value of the first occurrence of 
the ZIP field. If the length pointer is NULL, then the length of the value found 
is not returned. Unlike Ffind, the value returned is guaranteed to be properly 
aligned for the corresponding user-specified type. 
Note: The duration of the validity of the pointer returned by CFfind is 
guaranteed only until the next buffer operation, even if it is non-destructive, 
since the converted value is retained in a single private buffer. This differs 
from the value returned by Ffind, which is guaranteed until the next 
modification of the buffer. 
CFfindocc
CFfindocc looks at occurrences of the specified field on the buffer and returns 
the occurrence number of the first field occurrence that matches the 
user-specified field value after it has been converted (it is converted to the 
type of the field identifier). 
FLDOCCCFfindocc(FBFR *fbfr, FLDID fieldid, char *value, FLDLEN len, int type)
where 
    fbfr is a pointer to a fielded buffer 
    fieldid is the field identifier of the field to be retrieved 
    value is a pointer to the unconverted matching value 
    len is the length of the unconverted matching value 
    type is the type of the unconverted matching value 
For example, 
#include "fldtbl.h"FBFR *fbfr;FLDOCC oc;char zipvalue[20];. . .strcpy(zipvalue,"123456");if((oc=CFfindocc(fbfr,ZIP,zipvalue,0,FLD_STRING)) <  0)        F_error("pgm_name");
would convert the string to the type of fieldid ZIP (possibly a long) and set oc 
to the occurrence for the specified zip code. If the field value is not found, 
-1 is returned. 
Note: Since CFfindocc converts the user-specified value to the native field type 
before examining the field values, regular expressions will only work when the 
user-specified type and the native field type are both FLD_STRING. Thus, 
CFfindocc has no utility with regular expressions. 
Converting Strings
A set of functions (Fadds(3fml), Fchgs(3fml), Fgets(3fml), Fgetsa(3fml) and 
Ffinds(3fml) and their FML32 counterparts) has been provided to handle the case 
of conversion to/from a user type of FLD_STRING. These functions call their 
non-string-function counterparts, providing a type of FLD_STRING, and a len of 
0. Note that the duration of the validity of the pointer returned by Ffinds is 
the same as that described for CFfind. 
See Section 3fml of the BEA TUXEDO Reference Manual for descriptions of these 
functions. 
Ftypcvt
The functions CFadd, CFchg, CFget, CFgetalloc, and CFfind use the function 
Ftypcvt to perform the appropriate data conversion. The synopsis of Ftypcvt 
usage is as follows (it does not follow the parameter order conventions): 
char *Ftypcvt(FLDLEN *tolen, int totype, char *fromval, int fromtype, FLDLEN fromlen)
where 
    tolen is a pointer to the length of the converted value 
    totype is the type to which to convert 
    fromval is a pointer to the value from which to convert 
    fromtype is the type from which to convert 
    fromlen is the length of the from value if the from type is FLD_CARRAY 
Ftypcvt converts from the value *fromval, which has type fromtype, and length 
fromlen if fromtype is type FLD_CARRAY (otherwise fromlen is inferred from 
fromtype), to a value of type totype. Ftypcvt returns a pointer to the converted 
value, and sets *tolen to the converted length, upon success. Upon failure, 
Ftypcvt returns NULL. As an example of its usage, the function CFchg is 
presented: 
CFchg(fbfr,fieldid,oc,value,len,type)FBFR *fbfr;             /* fielded buffer */FLDID fieldid;          /* field to be changed */FLDOCC oc;              /* occurrence of field to be changed */char *value;            /* location of new value */FLDLEN len;             /* length of new value */int type;               /* type of new value */{ char *convloc;         /* location of post-conversion value */ FLDLEN convlen;        /* length of post-conversion value */ extern char *Ftypcvt;          /* convert value to fielded buffer type */  if((convloc = Ftypcvt(&convlen,FLDTYPE(fieldid),value,type,len)) == NULL)                return(-1);   if(Fchg(fbfr,fieldid,oc,convloc,convlen) < 0)                return(-1);  return(1);} 
The user may call Ftypcvt directly to do field value conversion without adding 
or modifying a fielded buffer. 
Conversion Rules
A description of conversion rules is now presented. In this description, oldval 
represents a pointer to the data item being converted, and newval a pointer to 
the post-conversion value: 
    When both types are identical, *newval is identical to *oldval. 
    When both types are numeric, i.e., any of long, short, float, or double, the 
    conversion is done by the C assignment operator, with proper type casting. 
    For example, converting a short to a float is done by: 
*((float *)newval) = *((short *) oldval)
    When converting from a numeric to a string, an appropriate sprintf is used. 
    For example, converting a short to a string is done by: 
sprintf(newval,"%d",*((short *)oldval))
    When converting from a string to a numeric, the appropriate function (for 
    example, atof, atol) is used, with the result assigned to a typecasted 
    receiving location, for example: 
*((float *)newval) = atof(oldval)
    When converting from type char to any numeric type, or from a numeric type 
    to a char, the char is considered to be a "shorter short." For example, 
*((float *)newval) = *((char *)oldval)
    is the method used to convert a char to a float. Similarly, 
*((char *)newval) = *((short *)oldval)
    is used to convert a short to a char. 
    A char is converted to a string by appending a NULL character. In this 
    regard, a char is not a "shorter short." If it were, assignment would be 
    done by converting it to a short, and then converting the short to a string 
    via sprintf. In the same sense, a string is converted to a char by assigning 
    the first character of the string to the character. 
    The carray type is used to store an arbitrary sequence of bytes. In this 
    sense, it can encode any user data type. Nevertheless, the following 
    conversions are specified for carray types: 
        A carray is converted to a string by appending the NULL byte to the 
        carray. In this sense, a carray could be used to store a string, less 
        the overhead of the trailing NULL (note that this does not always save 
        space, since fields are aligned on short boundaries within a fielded 
        buffer). A string is converted to a carray by removing its terminating 
        NULL byte. 
        When a carray is converted to any numeric, it is first converted to a 
        string, and the string is then converted to a numeric. Likewise, a 
        numeric is converted to a carray, by first converting it to a string, 
        and then converting the string to a carray. 
        A carray is converted to a char by assigning the first character of the 
        array to the char. Likewise, a char is converted to a carray by 
        assigning it as the first byte of the array, and setting the length of 
        the array to 1. 
    Note that a carray of length 1 and a char have the following differences: 
        A char has only the overhead of its associated fieldid, while a carray 
        contains a length code, in addition to the associated fieldid. 
        A carray is converted to numeric by first becoming a string, and then 
        undergoing an atoi call; a char becomes a numeric by typecasting. For 
        example, a char with value ASCII '1' (decimal 49) converts to a short of 
        value 49; a carray of length 1, with the single byte an ASCII '1' 
        converts to a short of value 1. Likewise a char 'a' (decimal 97) 
        converts to a short of value 97; the carray 'a' converts to a short of 
        value 0 (since atoi("a") produces a 0 result). 
    When converting to or from a dec_t type, the associated conversion function 
    as described in decimal(3) is used (_gp_deccvasc, _gp_deccvdbl, 
    _gp_deccvflt, _gp_deccvint, _gp_deccvlong, _gp_dectoasc, _gp_dectodbl, 
    _gp_dectoflt, _gp_dectoint, and _gp_dectolong). 
Table 5-2 summarizes the conversion rules presented in this section. 
Table 5-2 Summary of Conversion Rulessrc typ dest type 
            - char short long float double string carray dec_t 
            char - cast cast cast cast st[0]=c array[0]=c d 
            short cast - cast cast cast sprintf sprintf d 
            long cast cast - cast cast sprintf sprintf d 
            float cast cast cast - cast sprintf sprintf d 
            double cast cast cast cast - sprintf sprintf d 
            string c=st[0] atoi atol atof atof - drop 0 d 
            carray c=array[0] atoi atol atof atof add 0 - d 
            dec_t d d d d d d d - 
    
Table 5-3 defines the entries in Table 5-2. 
Table 5-3 Meanings of Entries in the Summary of Conversion 
            RulesEntry Meaning 
            - no conversion need be done, src and dest are same type 
            cast conversion done using C assignment with type casting 
            sprintf conversion done using sprintf function 
            atoi conversion done using atoi function 
            atof conversion done using atof function 
            atol conversion done using atol function 
            add 0 conversion done by concatenating NULL byte 
            drop 0 conversion done by dropping terminating NULL byte 
            c=array[0] character set to first byte of array 
            array[0]=c first byte of array is set to character 
            c=st[0] character set to first byte of string 
            st[0]=c first byte of string set to c 
            d decimal(3c) conversion function 
    
Indexing Functions
When a fielded buffer is initialized by Finit or Falloc, an index is 
automatically set up. This index is used to expedite fielded buffer accesses and 
is transparent to you. As fields are added to or deleted from the fielded 
buffer, the index is automatically updated. 
However, when storing a fielded buffer on a long-term storage device, or when 
transferring it between cooperating processes, it may be desirable to save space 
by eliminating its index and regenerating it upon receipt. The functions 
described in this section may be used to perform such index manipulations. 
Fidxused
This function returns the amount of space used by the index of a buffer: 
longFidxused(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
You can use this function to determine the size of the index of a buffer and 
whether significant time or space would be saved by deleting the index. 
Findex
The function Findex may be used at any time to index an unindexed fielded 
buffer: 
intFindex(FBFR *fbfr. FLDOCC intvl)
where 
    fbfr is a pointer to a fielded buffer 
    intvl is the indexing interval 
The second argument to Findex specifies the indexing interval for the buffer. If 
0 is specified, the value FSTDXINT (defined in fml.h) is used. The user may 
ensure that all fields are indexed by specifying an interval of 1. 
Note that more space may be made available in an existing buffer for user data 
by increasing the indexing interval, and re-indexing the buffer. This represents 
a space/time trade-off, however, since reducing the number of index elements (by 
increasing the index interval), means, in general, that searches for fields will 
take longer. Most operations will attempt to drop the entire index if they run 
out of space before returning a "no space" error. 
Frstrindex
This function can be used instead of Findex in cases where the fielded buffer 
has not been altered since its index was removed: 
intFrstrindex(FBFR *fbfr, FLDOCC numidx)
where 
    fbfr is a pointer to a fielded buffer 
    numidx is the value returned by the Funindex function. 
Funindex
Funindex discards the index of a fielded buffer and returns the number of index 
entries the buffer had before the index was stripped: 
FLDOCCFunindex(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
Example
To transmit a fielded buffer without its index, something similar to the 
following should be done: 
    Remove the index: 
save = Funindex(fbfr);
    Get the number of bytes to send (that is, the number of significant bytes 
    from the beginning of the buffer): 
num_to_send = Fused(fbfr);
    Send the buffer without the index: 
transmit(fbfr,num_to_send);
    Restore the index to the buffer: 
Frstrindex(fbfr,save);
On the receiving side, the index could be regenerated with the following 
statement: 
Findex(fbfr);
Note that the receiving process cannot call Frstrindex because it did not remove 
the index itself, and the index was not sent with the file. 
Note: The space used in memory by the index is not freed by calling Funindex; 
this function only saves space on disk or when sending a buffer to another 
process. Of course, you are always free to send a fielded buffer and its index 
to another process and avoid using these functions. 
Input/Output Functions
The functions described in this section provide for input and output of fielded 
buffers to standard I/O or to file streams. 
Fread and Fwrite
The I/O functions Fread and Fwrite work with the Standard I/O Library: 
int Fread(FBFR *fbfr, FILE *iop)int Fwrite(FBFR *fbfr, FILE *iop)
The stream to or from which the I/O is directed is determined by a FILE pointer 
argument. This argument must be set up using the normal Standard I/O Library 
functions. 
A fielded buffer may be written into a Standard I/O stream with the function 
Fwrite, like this: 
if (Fwrite(fbfr, iop) < 0)  F_error("pgm_name");
A buffer written with Fwrite may be read with Fread, as in: 
if(Fread(fbfr, iop) < 0) F_error("pgm_name");
Although the contents of the fielded buffer pointed to by fbfr are replaced by 
the fielded buffer read in, the capacity of the fielded buffer (size of the 
buffer) remains unchanged. 
Fwrite discards the buffer index, writing only as much of the fielded buffer as 
has been used (as returned by Fused). 
Fread restores the index of a buffer by calling Findex. The buffer is indexed 
with the same indexing interval with which it was written by Fwrite. 
Fchksum
A checksum may be calculated for verifying I/O: 
long chk;. . .chk = Fchksum(fbfr);
The user is responsible for calling Fchksum, writing the checksum value out 
along with the fielded buffer, and checking it on input. Fwrite does not write 
the checksum automatically. 
Fprint and Ffprint
The function Fprint prints a fielded buffer on the standard output in ASCII 
format: 
Fprint(FBFR *fbfr)
where 
    fbfr is a pointer to a fielded buffer 
Ffprint is similar to Fprint, except the text is printed to a specified output 
stream: 
Ffprint(FBFR *fbfr, FILE *iop)
where 
    fbfr is a pointer to a fielded buffer 
    iop is a pointer of type FILE to the output stream 
Each of these print functions prints, for each field occurrence, the field name 
and the field value, separated by a tab and followed by a new-line. Fname is 
used to determine the field name; if the field name cannot be determined, then 
the field identifier is printed. Non-printable characters in the field values 
for strings and character arrays are represented by a backslash followed by 
their two-character hexadecimal value. Backslashes occurring in the text are 
escaped with an extra backslash. A blank line is printed following the output of 
the printed buffer. 
Fextread
Fextread may be used to construct a fielded buffer from its printed format, i.e. 
from the output of Fprint (hexadecimal values output by Fprint are interpreted 
properly). 
intFextread(FBFR *fbfr, FILE *iop)
Fextread accepts an optional flag preceding the field-name/field-identifier 
specification in the output of Fprint as shown in Table 5-4. 
Table 5-4 Fextread Flagsflag indicates 
            + field should be changed in the buffer 
            - field should be deleted from the buffer 
            = one field should be assigned to another 
            # comment line - ignored 
    
If no flag is given, the default action is to Fadd the field to the buffer. 
Field values may be extended across lines by having the overflow lines begin 
with a tab (the tab is discarded). A single blank line signals end of buffer; 
successive blank lines yield a null buffer. 
If an error has occurred, -1 is returned, and Ferror is set accordingly. If end 
of file is reached before a blank line, Ferror is set to FSYNTAX. 
Boolean Expressions of Fielded Buffers
The functions in this section deal with the evaluation of boolean expressions 
where the "variables" of the expression are the values of fields in a fielded 
buffer or a VIEW. Functions described in this section allow you to: 
    compile boolean expression into a compact form suitable for evaluation 
    evaluate a boolean expression against a fielded buffer or a VIEW, returning 
    a true or false answer 
    print a compiled boolean expression 
A function is provided that compiles the expression into a compact form suitable 
for efficient evaluation. A second function evaluates the compiled form against 
a fielded buffer to produce a true or false answer. 
Boolean Expressions
This section describes, in detail, the expressions accepted by the boolean 
compilation function and how the expression is evaluated. Table 5-5 shows the 
Backus-Naur Form definitions of the accepted boolean expressions. 
Standard C language operators not supported include the shift operators (<< and 
>>), the bitwise "or" and "and" operators (|| and &&), the conditional operator 
(?), the prefix and postfix incrementation and decrementation operators (++ and 
--), the address and indirection operators (& and *), the assignment operator 
(=), and the comma operator (,). The following sections describe boolean 
expressions in greater detail. 
Table 5-5 BNF Boolean Expression DefinitionsExpression Definition 
            <boolean> <boolean> || <logical and> | <logical and> 
            <logical and> <logical and> && <xor expr> | <xor expr> 
            <xor expr> <xor expr> ^ <equality expr> | <equality expr> 
            <equality expr> <equality expr> <eq op> <relational expr> | 
            <relational expr> 
            <eq op> == | != | %% | !% 
            <relational expr> <relational expr> <rel op> <additive expr> | 
            <additive expr> 
            <rel op> < | <= | >= | > | 
            <additive expr> <additive expr> <add op> <multiplicative expr> | 
            <multiplicative expr> 
            <add op> + | - 
            <multiplicative expr> <multiplicative expr> <mult op> <unary expr> | 
            <unary expr> 
            <mult op> * | / | % 
            <unary expr> <unary op> <primary expr> | <primary expr> 
            <unary op> + | - | ~ | ! 
            <primary expr> ( <boolean> ) | <unsigned constant> | <field ref> 
            <unsigned constant> <unsigned number> | <string> 
            <unsigned number> <unsigned float> | <unsigned int> 
            <string> ' <character> {<character>. . .} ' 
            <field ref> <field name> | <field name>[<field occurrence>] 
            <field occurrence> <unsigned int> | <meta> 
            <meta> ? 
    
Field Names and Types
The only variables allowed in the boolean expressions are field references. 
There are several restrictions on field names. Names are made up of letters and 
digits; the first character must be a letter. The underscore (_) counts as a 
letter; it is useful for improving the readability of long variable names. Up to 
30 characters are significant. There are no reserved words. 
For a fielded buffer evaluation, any field that is referenced in a boolean 
expression must exist in a field table. This implies that the FLDTBLDIR and 
FIELDTBLS environment variables are set, as described in Chapter 3, "Setup," 
before using the boolean compilation function. The field types used in booleans 
are those allowed for FML fields; namely, short, long, float, double, char, 
string, and carray. Along with the field name, the field type is kept in the 
field table. Thus, the field type can always be determined. 
For a VIEW evaluation, any field that is referenced in a boolean expression must 
exist as a C structure element name, not the associated fielded buffer name, in 
the VIEW. This implies that the VIEWDIR and VIEWFILES environment variables are 
set, as described in Chapter 3, "Setup," before using the boolean compilation 
function. The field types used in booleans are those allowed for FML VIEWS; 
namely, short, long, float, double, char, string, carray, plus int and dec_t. 
Along with the field name, the field type is kept in the view definition. Thus, 
the field type can always be determined. 
Strings
A string is a group of characters within single quotes. The ASCII code for a 
character may be substituted for the character via an escape sequence. An escape 
sequence takes the form of a backslash followed by exactly two hexadecimal 
digits. NOTE THAT THIS IS NOT AS IT IS IN C where a hexadecimal escape sequence 
starts with \x. 
As an example, consider `hello' and `hell\\6f'. They are equivalent strings 
because the hexadecimal code for an `o' is 6f. 
Octal escape sequences and escape sequences such as "\n" are not supported. 
Constants
Numeric integer and floating point constants are accepted, as in C (octal and 
hexadecimal constants are not recognized). Integer constants are treated as 
longs and floating point constants are treated as doubles (decimal constants for 
the dec_t type are not supported). 
Conversion
To evaluate a boolean expression, the following conversions are performed by the 
boolean compiler: 
    short and int values are converted to longs 
    float and decimal values are converted to doubles 
    characters are converted to strings 
    when comparing a non-quoted string within a field with a numeric, the string 
    is converted to a numeric value 
    when comparing a constant (that is, quoted) string with a numeric, the 
    numeric is converted to a string, and a lexical comparison is done 
    when comparing a long and a double, the long is converted to a double 
Primary Expressions
Boolean expressions are built from primary expressions, which can be any of the 
following: 
    field name-a field name 
    field name[constant-a field name and a constant subscript 
    field name[?-a field name and the `?' subscript 
    constan -a constant 
    ( expression -an expression in parentheses 
A field name or a field name followed by a subscript is a primary expression. 
The subscript indicates which occurrence of the field is being referenced. The 
subscript may be either an integer constant, or ? indicating any occurrence; the 
subscript cannot be an expression. If the field name is not subscripted, field 
occurrence 0 is assumed. 
If a field name reference appears without an arithmetic, unary, equality, or 
relational operator, then its value is the long integer value 1 if the field 
exists and 0 if the field does not exist. This may be used to test the existence 
of a field in the fielded buffer regardless of field type (note that there is no 
* indirection operator). 
A constant is a primary expression. Its type may be long, double, or carray, as 
discussed in the conversion section. 
A parenthesized expression is a primary expression whose type and value are 
identical to those of the unadorned expression. Parentheses may be used to 
change the precedence of operators, which is discussed in the next section. 
Expression Operators
Table 5-6 lists the precedence of expression operators, with the operators 
having the highest precedence at the top of the list. 
Table 5-6 Boolean Expression OperatorsType Operators 
            unary +, -, !, ~ 
            multiplicative *, /, % 
            additive +, - 
            relational < , >, <=, >=, ==, != 
            equality and matching ==, !=, %%, !% 
            exclusive OR ^ 
            logical AND && 
            logical OR || 
    
Within each operator type, the operators have the same precedence. The following 
sections discuss each operator type in detail. As in C, you can override the 
precedence of operators by using parentheses. 
Unary Operators
The unary operators recognized are the unary plus operator (+), the unary minus 
operator (-), the one's complement operator (~), and the logical not operator 
(!). Expressions with unary operators group right-to-left: 
+ expression- expression~ expression! expression
The unary plus operator has no effect on the operand (it is recognized and 
ignored). The result of the unary minus operator is the negative of its operand. 
The usual arithmetic conversions are performed. Unsigned entities do not exist 
in FML and thus cause no problems with this operator. 
The result of the logical negation operator is 1 if the value of its operand is 
0, and 0 if the value of its operand is non-zero. The type of the result is 
long. 
The result of the one's complement operator is the one's complement of its 
operand. The type of the result is long. 
Multiplicative Operators
The multiplicative operators *, /, and % group left-to-right. The usual 
arithmetic conversions are performed. 
expression * expressionexpression / expressionexpression % expression
The binary * operator indicates multiplication. The * operator is associative 
and expressions with several multiplications at the same level may be rearranged 
by the compiler. 
The binary / operator indicates division. When positive integers are divided 
truncation is toward 0, but the form of truncation is machine-dependent if 
either operand is negative. 
The binary % operator yields the remainder from the division of the first 
expression by the second. The usual arithmetic conversions are performed. The 
operands must not be float or double. 
Additive Operators
The additive operators + and - group left-to-right. The usual arithmetic 
conversions are performed. 
expression + expressionexpression - expression
The result of the + operator is the sum of the operands. The operator + is 
associative and expressions with several additions at the same level may be 
rearranged by the compiler. The operands must not both be strings; if one is a 
string, it is converted to the arithmetic type of the other. 
The result of the - operator is the difference of the operands. The usual 
arithmetic conversions are performed. The operands must not both be strings; if 
one is a string, it is converted to the arithmetic type of the other. 
Equality and Match Operators
These operators group left-to-right. 
expression == expressionexpression != expressionexpression %% expressionexpression !% expression
The == (equal to) and the != (not equal to) operators yield 0 if the specified 
relation is false and 1 if it is true. The type of the result is long. The usual 
arithmetic conversions are performed. 
The %% operator takes, as its second expression, a regular expression against 
which it matches its first expression. The second expression (the regular 
expression) must be a quoted string. The first expression may be an FML field 
name or a quoted string. This operator yields a 1 if the first expression is 
fully matched by the second expression (the regular expression). The operator 
yields a 0 in all other cases. 
The !% operator is the not regular expression match operator. It takes exactly 
the same operands as the %% operator, but yields exactly the opposite results. 
The relationship between %% and !% is analogous to the relationship between == 
and !=. 
The regular expressions allowed are described on the recomp(3c) manual page. 
Relational Operators
These operators group left-to-right. 
expression < expressionexpression > expressionexpression <= expressionexpression >= expression
The operators < (less than), > (greater than), <= (less than or equal to) and >= 
(greater than or equal to) all yield 0 if the specified relation is false and 1 
if it is true. The type of the result is long. The usual arithmetic conversions 
are performed. 
Exclusive OR Operator
The ^ operator groups left-to-right. 
expression ^ expression
It returns the bitwise exclusive OR function of the operands. The result is 
always a long. 
Logical AND Operator
expression && expression
The && operator groups left-to-right. It returns 1 if both its operands are 
non-zero, 0 otherwise. The && operator guarantees left-to-right evaluation. 
However, it is not guaranteed that the second operand is not evaluated if the 
first operand is 0; this is different from the C language. The operands need not 
have the same type. The result is always a long. 
Logical OR Operator
The || operator groups left-to-right. 
expression || expression
It returns 1 if either of its operands is non-zero, and 0 otherwise. The || 
operator guarantees left-to-right evaluation. However, it is not guaranteed that 
the second operand is not evaluated if the first operand is non-zero; this is 
different from the C language. The operands need not have the same type, and the 
result is always a long. 
Sample Boolean Expressions
The following field table defines the fields used for the sample boolean 
expressions: 
EMPID    200    carraySEX      201    charAGE      202    shortDEPT     203    longSALARY   204    floatNAME     205    string
Recall that boolean expressions always evaluate to either true or false. The 
following example: 
"EMPID[2] %% '123.*' && AGE < 32"
would be true if field occurrence 2 of EMPID exists and begins with the 
characters "123" and the age field (occurrence 0) appears and is less than 32. 
This example uses a constant integer as a subscript to EMPID. The ? subscript is 
used in the following example: 
"PETS[?] == 'dog'"
This expression would be true if PETS exists and any occurrence of it contained 
the characters "dog". 
Boolean Functions
The following sections describe the various functions that take boolean 
expressions as arguments. 
Fboolco and Fvboolco
Fboolco compiles a boolean expression for FML and returns a pointer to an 
evaluation tree: 
char *Fboolco(char *expression)
where *expression is a pointer to an expression to be compiled. 
Fvboolco compiles a boolean expression for a VIEW and returns a pointer to an 
evaluation tree: 
char *Fvboolco(char *expression, char *viewname)
where *expression is a pointer to an expression to be compiled, and *viewname is 
a pointer to the view name for which the fields are evaluated. 
Space is allocated using malloc(3) to hold the evaluation tree. For example, 
#include "<stdio.h>"#include "fml.h"extern char *Fboolco;char *tree;. . .if((tree=Fboolco("FIRSTNAME %% 'J.*n' && SEX == 'M'")) == NULL)  F_error("pgm_name");
would compile a boolean expression that checks whether the FIRSTNAME field is in 
the buffer, begins with `J' and ends with `n' (e.g., John, Joan, etc.), and 
whether the SEX field is equal to `M'. 
The first and second characters of the tree array form the least significant 
byte and the most significant byte, respectively, of an unsigned 16 bit quantity 
that gives the length, in bytes, of the entire array. This value is useful for 
copying or otherwise manipulating the array. 
The evaluation tree produced by Fboolco is used by the other boolean functions 
listed below; this avoids having to constantly re-compile the expression. 
free(3) should be used to free the space allocated to an evaluation tree when 
the boolean expression will no longer be used. Compiling many boolean 
expressions without freeing the evaluation tree when no longer needed may cause 
a program to run out of data space. 
Fboolpr and Fvboolpr
Fboolpr prints a compiled expression to the specified file stream. The 
expression is fully parenthesized, as it was parsed (as indicated by the 
evaluation tree), 
voidFboolpr(char *tree, FILE *iop)
where 
    *tree is a pointer to a Boolean tree previously compiled by Fboolco 
    *iop is a pointer of type FILE to an output file stream 
Fvboolpr prints a compiled expression to the specified file stream. 
voidFvboolpr(char *tree, FILE *iop, char *viewname)
where 
    *tree is a pointer to a Boolean tree previously compiled by Fvboolco 
    *iop is a pointer of type FILE to an output file stream 
    *viewname is the name of the view whose fields are used. 
This function is useful for debugging. 
Executing Fboolpr on the expression compiled above would yield 
(((FIRSTNAME[0]) %% ('J.*n')) && ((SEX[0]) == ('M')))
Fboolev and Ffloatev, Fvboolev and Fvfloatev
These functions evaluate a fielded buffer against a boolean expression. 
int Fboolev(FBFR *fbfr,char *tree)
double Ffloatev(FBFR *fbfr,char *tree) 
where 
    fbfr is the fielded buffer referenced by an evaluation tree produced by 
    Fboolco 
    tree is a pointer to an evaluation tree that references the fielded buffer 
    pointed to by fbfr 
The VIEW equivalents are as follows. 
intFvboolev(FBFR *fbfr,char *tree,char *viewname)
doubleFvfloatev(FBFR *fbfr,char *tree,char *viewname)
Fboolev returns true (1) if the fielded buffer matches the boolean conditions 
specified in the evaluation tree. This function does not change either the 
fielded buffer or the evaluation tree. Using the evaluation tree compiled above: 

#include <stdio.h>#include "fml.h"#include "fldtbl.h"FBFR *fbfr;. . .Fchg(fbfr,FIRSTNAME,0,"John",0);Fchg(fbfr,SEX,0,"M",0);if(Fboolev(fbfr,tree) > 0)  fprintf(stderr,"Buffer selected\n");else  fprintf(stderr,"Buffer not selected\n");
would print "Buffer selected". 
Ffloatev or Ffloatev32 is similar to Fboolev, but returns the value of the 
expression as a double. For example, 
#include <stdio.h>#include "fml.h"FBFR *fbfr;. . .main() {  char *Fboolco;  char *tree;  double Ffloatev;  if (tree=Fboolco("3.3+3.3")) {      printf("%lf",Ffloatev(fbfr,tree));  }}
would print 6.6. If Fboolev were used in place of Ffloatev in the above example, 
a 1 would be printed. 
VIEW Conversion to and from Target Format
A VIEW can be converted to and from a target record format. The default target 
format is IBM System/370 COBOL records. 
Fvstot, Fvttos and Fcodeset
The three functions that provide target conversion are as follows. 
longFvstot(char *cstruct, char *trecord, long treclen, char *viewname)
longFvttos(char *cstruct, char *trecord, char *viewname)
int Fcodeset(char *translation_table)
The Fvstot function transfers data from a C structure to a target record type. 
The Fvttos function transfers data from a target record to a C structure. 
trecord is a pointer to the target record. cstruct is a pointer to a C 
structure. viewname is a pointer to the name of a compiled view description. The 
VIEWDIR and VIEWFILES environment variables are used to find the directory and 
file containing the compiled view description. 
To convert from an FML buffer to a target record, first call Fvftos to convert 
the FML buffer to a C structure, and call Fvstot to convert to a target record. 
To convert from a target record to an FML buffer, first call Fvttos to convert 
to a C structure and then call Fvstof to convert the structure to an FML buffer. 

The default target is IBM/370 COBOL records. The default data conversion is done 
as shown in Table 5-7. 
Table 5-7 Data Conversion from a structure to a recordStruct Record 
            float COMP-1 
            double COMP-2 
            long S9(9) COMP 
            short S9(4) COMP 
            int S9(9) COMP or S9(4) COMP 
            dec_t(m, n) S9(2*m-(n+1))V9(n)COMP-3 
            ASCII char EBCDIC char 
            ASCII string EBCDIC string 
            carray character array 
    
No filler bytes are provided between fields in the IBM/370 record. The COBOL 
SYNC clause should not be specified for any data items that are a part of the 
structure corresponding to the view. An integer field is converted to either a 
four or two-byte integer depending on the size of integers on the machine on 
which the conversion is done. A string field in the view must be terminated with 
a null when converting to/from the IBM/370 format. The data in a carray field is 
passed unchanged; no data translation is performed. 
Packed decimals exist in the IBM/370 environment as two decimal digits packed 
into one byte with the low-order half byte used to store the sign. The length of 
a packed decimal may be 1 to 16 bytes with storage available for 1 to 31 digits 
and a sign. Packed decimals are supported in C structures using the dec_t field 
type. The dec_t field has a defined size consisting of two numbers separated by 
a comma. The number to the left of the comma is the total number of bytes that 
the decimal occupies. The number to the right is the number of digits to the 
right of the decimal point. The formula for conversion is: 
dec_t(m, n) <=> S9(2*m-(n+1))V9(n)COMP-3
Decimal values may be converted to and from other data types (e.g., int, long, 
string, double, and float) using the functions described in decimal(3c). 
See the Fvstof(3fml) reference page for the default character conversion of 
ASCII to/from EBCDIC. 
An alternate character translation table can be used at run-time by calling 
Fcodeset. The translation_table must point to 512 bytes of binary data. The 
first 256 bytes of data are interpreted as the ASCII to EBCDIC translation 
table. The second 256 bytes of data are interpreted as the EBCDIC to ASCII 
table. Any data after the 512th byte is ignored. If the pointer is NULL, the 
default translation is used. 



[Top] [Prev] [Next] [Bottom]

 

