Apparatus and method for constructing a non-linear data object from a common gateway interface5787450Abstract A computer implemented method and apparatus for creating a data structure comprising a non-linear data object with typed data fields and field names from a common gateway interface type input string. Claims We claim: Description BACKGROUND OF THE INVENTION
TABLE 1
______________________________________
QTMH.sub.-- EXTERN void QtmhCvtDb
(void *, /* qualified DDS file name*/
char *, /* buffer containing the string of
CGI keyword parameters to be
parsed.*/
int *, /* length of the string of CGI
keyword parameters to be
parsed.*/
void *, /* output buffer into which the
parsed parameter values will be
stored.*/
int *, /* length of buffer provided for
parsed paramter values.*/
int *, /* response length.*/
int *, /* response code.*/
void *, /* error code.*/
______________________________________
Referring to FIG. 2, DDS file specification includes, in this example, record name field 142 and a series of field pairs 144, 146 setting forth a template of field names 144 (in this example, field names FIRST, SECOND and THIRD), and corresponding data type and field size definitions 146 (in this example, 21 characters of alphanumeric, 9.3 poision floating point, and 3 position binary or integer, respectively.) Referring to FIG. 3, the contents of output buffer 160 resulting from execution of the method of the invention shows a plurality of variable length records 162, 164, 166 located at offsets 168 of 1, 21 and 30, respectively, each record containing values converted to proper type from the corresponding text name/value pairs 102, 104, and 106 of the CGI input string. The advantage to the user, or CGI programmer, is that returned data can be referenced by structure member name, and the data is returned in useable types. Thus, the CGI programmer enters: CGI.sub.-- INPUT.sub.-- STRUCT.FIRST and the returned data is useable, such that 10% of the third parameter is CGI.sub.-- INPUT.sub.-- STRUCT.THIRD * 0.1 Referring to FIG. 4, a flow chart of the method of the invention for constructing a typed data structure from a text input string is set forth. In step 200, initialization routines are executed which set up variables, establish working space in memory, read in the DDS template file 140, and receive the passed parameters, including:
______________________________________
PtrDbFileName name of DB template file 140
PtrParseString the input string
StringLength length of the input string
PtrRecBuffer variable to hold response
BufferLength length of buffer
PtrRespLength length of response
PtrRespcode response code
PtrEcStruc error code structure
______________________________________
Various local variables are established, the passed pointers and variables are checked for validity, a signal handler is turned on to catch exceptions, null and zero fields are checked, user space to contain the output from the list APIs is created, and a previously created definition of fields from the db.sub.-- list›! array is found or a definition of fields is created using the appropriate APIs. In step 202, a keyword/value pair 102 is read from input string 100. In step 204, template 140 is searched for a match of the keyword word from pair 102 with a keyword 144. If, in step 206, a match is not found in step 208, a bit or field is set in the return codes indicating such, and processing passes to block 220. Otherwise, upon a successful match in block 206, the data type and size for the value in keyword/value pair 102 is determined from entry 146 in template file 140 corresponding to the keyword 144. In step 212, the value in keyword/value pair 102 is converted to the correct data type and size determined in step 210. If the conversion is not successful, such as would be the case if the input value 102 is floating point and the correct data type is day-of-week, for example, then in step 216 a bit or field in the return code is set for unsuccessful conversion, and processing passes to step 220. Otherwise, if conversion is successful, in step 218 the converted value is placed in output buffer 168 at the appropriate offset (in this case, as the first keyword, from pair 102, is also the first keyword in template file 140, then the offset is zero. In this specific embodiment, for subsequent fields 164 and 166, the offset will be related to the sum of field sizes for previous entries in template 140.) In step 220 it is determined if all keyword/value pairs have been read from input string 100 and, if not, processing passes to step 202 where the next keyword/value pair 104, for example, is read and processed through steps 218. When all keyword/value pairs have been read from input string 100, template 140 is examined to see if all template fields 144 have been used, and if not, in step 224 a bit or field is set in the return code indicating such. Processing then, in either case, passes to step 226 where buffer 168 and the return codes are returned to the calling program, and processing ends. Table 2 sets forth a source code listing of the main routine implementing the process illustrated in FIG. 2. As will be apparent to those skilled in the art, and therefore not set forth in the source code listing of Table 2, initial routines are provided for declaring and initializing local variables; turning on a SignalHandler to catch exceptions; checking all passed pointers for validity, and that they are not null or zero; handling errors and raising exceptions; assuring that error code structures are valid. Table 2 includes a description, in lines 1825 through 1847, of the process for finding or creating user space to contain output from the list APIs QUSLFLD and QUSLRCD.
TABLE 2
______________________________________
MAIN ROUTINE
______________________________________
1825 if (list.sub.-- header == NULL)
1826 create.sub.-- list.sub.-- space();
1833 db.sub.-- cvt = find.sub.-- db.sub.-- cvt((char*)PtrDbFileName);
1835 reset.sub.-- fields(db.sub.-- cvt);
1836 memcpy(parm.sub.-- data, PtrParseString,
StringLength);
1837 parm.sub.-- data›*PtrStringLength! = '.backslash.0'
1838 PtrTempReceiver =
(char*)malloc(RequiredBuffersize);
1839 RequestMethod = getenv("REQUEST.sub.-- METHOD");
1842 if (strcmp(requestMethod, "GET") |=0
1843 {
1844 ptr.sub.-- char = strcat("first?", parm.sub.-- data);
1845 strcpy(parm.sub.-- data, ptr.sub.-- char);
1846 }
1847 strtok(parm.sub.-- data, "?");
1848 while ((field.sub.-- name=strtok(NULL,"=")) |=NULL
1849 {
1850 if ((data = strtok(NULL,",&")) |=NULL
1851 {
1852 fill.sub.-- field(db.sub.-- cvt, (char*)PtrTempReceiver,
cvt.sub.-- data(field.sub.-- name) ,cvt.sub.-- data(data),
&error.sub.-- flag);
1854 }
1855 }
1856 fill.sub.-- unused.sub.-- fields(db.sub.-- cvt,(char*)
PtrTempReceiver,&error.sub.-- flag);
1858 if (BufferLength >= RequiredBuffersize)
memcpy(PtrRecBuffer, PtrTempReceiver,
RequiredBufferSize);
1861 *PtrRespLength = RequiredBufferSize;
1862 if (error.sub.-- flag > 4)
error.sub.-- flag &= 3;
1864 *PtrRespCode = -(error.sub.-- flag);
1865 signal (SIGALL, original.sub.-- handler);
1866 return;
1867 }
______________________________________
Several functions are called in the course of processing the main routine and related routines, among them the following: (1) cvt.sub.-- to.sub.-- alpha copies data from source to result and pads with blanks; (2) cvt.sub.-- to.sub.-- pd converts data to packed decimal; and (3) cvt.sub.-- to.sub.-- f converts data to floating point notation; (4) cvt.sub.-- to.sub.-- i converts data to integer. C-code routines for several other functions and structures helpful to an understanding of a preferred embodiment of the invention are set forth in the following tables. Table 3 describes the create.sub.-- list.sub.-- space function, which creates the space to be used by the list APIs QUSLFLD and QUSLRCD.
TABLE 3
______________________________________
CREATE LIST SPACE
______________________________________
void create.sub.-- list.sub.-- space(void)
char attrb›10!;
char desc›50!,
void *space.sub.-- ptr;
int error.sub.-- code = 0;
sprintf(list.sub.-- space.sub.-- name, "%-10s%", LIST.sub.-- SPACE,
LIST.sub.-- SPACE.sub.-- LIB);
memset(attrb, ' ', 10);
memset(desc, ' ', 50);
sprintf(attrb, "%- 10s", LIST.sub.-- SPACE.sub.-- ATTR);
sprintf(desc, "%-50s", LIST.sub.-- SPACE.sub.-- DESC);
QUSCRTUS(list.sub.-- space.sub.-- name, attrb, LIST.sub.-- SPACE.sub.--
SIZE,
".backslash.0", "*LIBCRTAUT", desc, "*YES",
&error.sub.-- code);
QUSPTRUS(list.sub.-- space.sub.-- name, &space.sub.-- ptr);
list.sub.-- header = (header.sub.-- struct*)space.sub.-- ptr;
}
______________________________________
Table 4 describes the create.sub.-- db.sub.-- cvt function, which reads in the DDS template file and creates the db.sub.-- cvt.sub.-- t structure; list.sub.-- header contains the address of user space. A call to the List Record Formats API generates a list of record formats available for the file named in the calling parameter list (db.sub.-- name). This code assumes there will only be one record format returned (it only looks at the first record format name returned.) The List Fields API is called to generate a list of field names and descriptions from the record format name returned by the QUSLRCD() API.
TABLE 4
______________________________________
CREATE DB CONVERT STRUCTURE
______________________________________
DB.sub.-- CVT.sub.-- t *create.sub.-- db.sub.-- cvt(char *db.sub.--
name)
Qdb.sub.-- Lrcd RCDL0100.sub.-- t *record.sub.-- list;
Qdb.sub.-- Lfld.sub.-- FLDL0100.sub.-- t *field.sub.-- list;
DB.sub.-- CVT.sub.-- t *db.sub.-- cvt;
FIELD.sub.-- CVT.sub.-- t *field.sub.-- cvt;
int field;
QUSLRCD(list.sub.-- space.sub.-- name, "RCDL0100", db.sub.-- name,
"0") ;
record.sub.-- list = (Qdb.sub.-- Lrcd.sub.-- RCDL0100 *) ((char*)
list.sub.-- header + list.sub.-- header->
list.sub.-- section.sub.-- offset);
QUSLFLD(list.sub.-- space.sub.-- name, "FLDL0100", db.sub.-- name,
record list->Format Name, "0");
field.sub.-- list = (Qdb.sub.-- Lfld.sub.-- FLDL0100 *)
((char*)list.sub.-- header +
list.sub.-- header->list section.sub.-- offset);
db.sub.-- cvt = (DB.sub.-- CVT.sub.-- t*)malloc(size of(DB.sub.--
CVT.sub.-- t) +
(list.sub.-- header->number.sub.--of.sub.-- entries - 1) *
sizeof(FIELD.sub.-- CVT.sub.-- t));
db.sub.-- cvt->field.sub.-- count = list.sub.-- header->
number.sub.-- of.sub.-- entries;
memcpy(db.sub.-- list›db.sub.-- count! .db.sub.-- name,
db.sub.-- name, 20);
db.sub.-- list›db.sub.-- count! .db.sub.-- cvt = db.sub.-- cvt;
db.sub.-- count++;
field.sub.-- cvt = db.sub.-- cvt->field.sub.-- cvt;
for (field = 0; field < db.sub.-- cvt->field.sub.-- count;
field++, field.sub.-- cvt++)
{
memcpy(field.sub.-- cvt->field.sub.-- name, field.sub.-- list->
Field Name, 10);
field.sub.-- cvt->field.sub.-- offset = field.sub.-- list->
Input.sub.-- Buffer.sub.-- Position - 1;
field.sub.-- cvt->field.sub.-- type = field list->Data.sub.-- Type;
RequiredBufferSize = field.sub.-- list->
Input.sub.-- Buffer.sub.-- Position - 1 + field list->
Field.sub.-- Length.sub.-- Bytes;
switch (field.sub.-- cvt->field.sub.-- type)
{
case 'A':
case 'S':
case 'T':
case 'L':
case 'Z': field.sub.-- cvt->field.sub.-- length =
field.sub.-- list->Field Length.sub.-- Bytes;
field.sub.-- cvt->field.sub.-- dec.sub.-- pos = 0;
field.sub.-- cvt->convert.sub.-- function =
cvt.sub.-- to.sub.-- alpha;
break;
case 'P': field.sub.-- cvt->field.sub.-- length =
field.sub.-- list->Digits;
field.sub.-- cvt->field.sub.-- dec.sub.-- pos =
field.sub.-- list->Decimal Positions;
field.sub.-- cvt->convert.sub.-- function =
cvt.sub.-- to.sub.-- pd;
break;
case "F": field.sub.-- cvt->field.sub.-- length =
field.sub.-- list->Field.sub.-- Length.sub.-- Bytes;
field.sub.-- cvt->field.sub.-- dec.sub.-- pos =
field.sub.-- list->Decimal.sub.-- Positions;
field.sub.-- cvt->convert.sub.-- function =
cvt.sub.-- to.sub.-- f;
break;
case "B": field.sub.-- cvt->field.sub.-- length =
field.sub.-- list->Field.sub.-- Length.sub.-- Bytes;
field.sub.-- cvt->field.sub.-- dec.sub.-- pos = 0;
field.sub.-- cvt->convert.sub.-- function =
cvt.sub.-- to.sub.-- i;
break;
}
field list = (Qdb.sub.-- Lfld.sub.-- FLDL0100 *)((char *)
field.sub.-- list + list.sub.-- header ->
size.sub.-- of.sub.-- entry);
}
return db.sub.-- cvt;
}
______________________________________
Table 5 describes the find.sub.-- db.sub.-- cvt function, which finds an existing db.sub.-- cvt.sub.-- t structure, if it exists, containing field definitions that have already been created.
TABLE 5
______________________________________
FIND DB CONVERT
______________________________________
DB.sub.-- CVT.sub.-- t *find.sub.-- db.sub.-- cvt(char *db.sub.-- name)
int i;
for (i = 0; i < db.sub.-- count; i++)
if (memcmp(db.sub.-- list›i! .db.sub.-- name,
db.sub.-- name, 20) == 0)
return db.sub.-- list›i! .db.sub.-- cvt;
return create.sub.-- db.sub.-- cvt(db.sub.-- name);
}
______________________________________
Table 6 describes the reset.sub.-- fields function.
TABLE 6
______________________________________
RESET FIELDS
______________________________________
void reset.sub.-- fields(DB.sub.-- CVT.sub.-- t *db.sub.-- cvt)
int i;
FIELD.sub.-- CVT.sub.-- t *field.sub.-- cvt;
field.sub.-- cvt = db.sub.-- cvt->field.sub.-- cvt;
for (i = 0; i < db.sub.-- cvt->field.sub.-- count; i++,
field.sub.-- cvt++) field.sub.-- cvt->field.sub.-- used = 0
}
______________________________________
Table 7 describes the fill.sub.-- unused.sub.-- fields function, which fills all the unused fields with appropriate filler.
TABLE 7
______________________________________
FILL UNUSED FIELDS
______________________________________
void fill.sub.-- unused.sub.-- fields(DB.sub.-- CVT.sub.-- t *db.sub.--
cvt, char
*buffer, int *error.sub.-- field)
int i;
FIELD.sub.-- CVT.sub.-- t *field.sub.-- cvt;
int error;
field.sub.-- cvt = db.sub.-- cvt->field.sub.-- cvt;
for (i = 0; i < db.sub.--cvt-> field.sub.-- count;
i++, field.sub.-- cvt++)
if (field.sub.-- cvt->field.sub.-- used == 0)
{
*error.sub.-- field = *error field .vertline. 1;
switch (field.sub.-- cvt->field.sub.-- type)
{
case 'A':
case 'S':
case 'T':
case 'L':
case 'Z':
field.sub.-- cvt->convert.sub.-- function(buffer +
field.sub.-- cvt->field.sub.-- offset, " "
field.sub.-- cvt->field.sub.-- length, 0, &error);
break;
case 'B':
case 'P':
case 'F':
field.sub.-- cvt->convert.sub.-- function(buffer +
field.sub.-- cvt->field.sub.-- offset, "0",
field.sub.-- cvt->field.sub.-- length,
field.sub.-- cvt->field.sub.-- dec.sub.-- pos, &error);
break;
}
}
}
______________________________________
Table 8 describes the cvt.sub.-- data function, which converts the data passed to upper case, converts plus signs to blanks, and converts escape sequences (identified by % sign) to a single character.
TABLE 8
______________________________________
CONVERT DATA
______________________________________
char *cvt.sub.-- data(char *s)
char *c;
c = s;
while ((c = strchr(c, '+')) |= NULL)
*c++ = ' ';
c = s;
while ((c = strchr(c, '%')) |= NULL)
{
*(c + 1) = toupper(*(c + 1));
*(c + 2) = toupper(*(c + 2));
cvtch(c, c + 1, 2);
strcpy(c + 1, c + 3);
c++;
}
return s;
}
______________________________________
Table 9 describes the fill.sub.-- field function, which fills in the buffer with the information for this field and creates padded names.
TABLE 9
______________________________________
FILL FIELD
______________________________________
void fill.sub.-- field(DB.sub.-- CVT.sub.-- t *db.sub.-- cvt, char
*buffer, char
*field.sub.-- name, char *data, int *error.sub.-- field)
FIELD.sub.-- CVT.sub.-- t *field.sub.-- cvt;
char padded.sub.-- name›11!;
int error;
int i = strlen(field.sub.-- name);
char *c = padded.sub.-- name;
sprintf(padded.sub.-- name, "%-10s", field.sub.-- name);
while (i--)
{
*c = toupper(*c);
c++;
}
field.sub.-- cvt = db.sub.-- cvt->field.sub.-- cvt;
for (i = 0; i < db.sub.-- cvt->field.sub.-- count; i++,
field.sub.-- cvt++)
{
if (memcmp(padded.sub.-- name, field.sub.-- cvt->field.sub.-- name,
10) == 0)
{
switch (field.sub.-- cvt->field.sub.-- type)
{
case 'A':
case 'B':
case 'S':
case 'T':
case 'L':
case 'Z':
case 'P':
case 'F': field.sub.-- cvt->
convert.sub.-- function(buffer +
field.sub.-- cvt->field.sub.-- offset,
data, field.sub.-- cvt->field.sub.-- length,
field.sub.-- cvt->field.sub.-- dec.sub.-- pos,
&error);
field.sub.-- cvt->field.sub.-- used = 1;
if (error |= 0)
*error.sub.-- field = *error.sub.-- field .vertline.
4;
return;
}
}
else if (i == (db.sub.-- cvt->field.sub.-- count -1))
*error.sub.-- field = *error.sub.-- field .vertline. 2;
}
}
______________________________________
Advantages over the Prior Art This invention provides a method and programming structure for creating a data structure comprising a non-linear data object with typed data fields and field names from a common gateway interface type input string. Alternative Embodiments It will be appreciated that, although specific embodiments of the invention have been described herein for purposes of illustration, various modifications may be made without departing from the spirit and scope of the invention. For example, the digital signals required to operate the computer to perform the method of the invention may be stored in or transmitted through a storage or transmission medium. Accordingly, the scope of protection of this invention is limited only by the following claims and their equivalents.
|
Same subclass Same class Consider this |
||||||||||
