/*****************************************************************************/ /* CGIutl.c A CLI utility to assist at the DCL level with generating HTTP responses, returning content and with the handling of POSTed requests. Intended to be used within DCL procedures to manipulate the CGI environment. Assign a foreign verb, $ CGIUTL = "$HT_EXE:CGIUTL" All DCL symbols created by or supplied to this utility MUST be global symbols. It does not deal with local symbols at all. HAVING DCL PROBLEMS WITH SYMBOL SIZE? ------------------------------------- Although CLI symbols may have maximum capacities of 1023 (earlier than VMS V7.3-2) or 8191 (V7.3-2 and later) it can often be problematic accessing this full capacity from the DCL command line. If this is an issue try using the /MAXSYM= qualifier to set the maximum number of characters CGIUTL places into a single symbol. Perhaps /MAXSYM=900 (as ~980 seems to be a 'magic' number for DCL), or even /MAXSYM=255. Needless-to-say, there are also SYSGEN parameters controlling memory allocations to such purposes. CLISYMTBL is a dynamic parameter directly related to the symbol table size. CTLPAGES controls the number of pages allocated to the P1 (process') pool. See note against %LIB-F-INVARG described in main()! DECODING A REQUEST BODY TO DCL SYMBOLS -------------------------------------- The /URLDECODE qualifier results in a form-URL-encoded POSTed request body being decoded and the contents of each field being placed into DCL symbols named using that field. HTML form field names may contain characters not allowed within DCL symbol names, therefore when constructing the symbol name non-alpha-numeric characters in the field name have underscores substituted in the symbol name. Once the request body has been decoded the DCL procedure can manipulate the contents quite simply. Here's the command line: $ CGIUTL /URLDECODE [/SYMBOL|/OUTPUT] For example the following form input field would have the corresponding DCL symbol name assigned CGIUTL_TEXT_INPUT_ONE == "blah-blah-blah-blah" Field contents greater than the capacity of a single DCL symbol (255 on <=6.n and 1023 on >=7.n) have the contents distributed across multiple symbol names. Each of these fields comprises the basic name with a dollar symbol and an ascending integer. A symbol with the integer zero contains the total count of the contents of all of the symbols. For example, the following text-area field may have had 900 characters entered. Assuming a maximum symbol capacity of 255 characters the contents would be distributed across 4 symbols, with the additional count symbol, as follows: CGIUTL_TEXT_AREA_INPUT$0 == "900" CGIUTL_TEXT_AREA_INPUT$1 == "blah-blah-blah-blah...blah-blah" CGIUTL_TEXT_AREA_INPUT$2 == "blah-blah-blah-blah...blah-blah" CGIUTL_TEXT_AREA_INPUT$3 == "blah-blah-blah-blah...blah-blah" CGIUTL_TEXT_AREA_INPUT$4 == "blah-blah-blah" NOTE: There was a bug prior to version 1.5 which resulted in the $1, $2, etc. ~~~~~ symbol names being created as _1, _2, etc. This has been rectified with backward compatibility supplied via adding the /BUGSYM qualifier to scripts that require it. Apologies for any inconvenience. Where form field names are duplicated, as can be done with checkboxes, etc., CGUTL attempts to create multiple symbols representing these. For fields containing less than the maximum symbol value contents (255 or 1023 depending on the VMS version) this is quite successful, but can get complex to interpret where multiple symbols must be created to represent a single field name and should be avoided. The naming schema for such duplicate field names is as follows: For backward compatibility with pre-v1.5 CGIUTL a symbol corresponding to the field name always contains the value of the LAST such encountered field name. The symbol CGIUTL_$$0 contains the number of symbols representing a duplicate field name. If this does not exist then there is only one instance of this field name in the request body and that value can be obtained from symbol CGIUTL_. If it exists it will always have a value of at least 2 ... you need at least two for it to be duplicated!! The first instance of the field name will then be found in a symbol named CGIUTL_$$1, the second in CGIUTL_$$2, etc. This also applies to multi-symbol value representations (see above), but can get quite complex and having duplicate field names for large field values should be avoided when using CGIUTL. For example. The following form fields, 1 2 3 4 if all checked, would result in the following symbols being generated CGIUTL_EXAMPLE == "four" CGIUTL_EXAMPLE$$0 == "4" CGIUTL_EXAMPLE$$1 == "one" CGIUTL_EXAMPLE$$2 == "two" CGIUTL_EXAMPLE$$3 == "three" CGIUTL_EXAMPLE$$4 == "four" When using the /DELIMITER qualifier the first character of the supplied string is used to split the data in the form fields. The delimiter character is discarded. An example form field datum of This contains, some simple comma-separated, values. and CGIUTL usage of $ CGIUTL /URLDECODE /SYMBOL /MAXSYM=20 /DELIMITER="," would result in symbols of CGIUTL_EXAMPLE$0 == "49" CGIUTL_EXAMPLE$0$ == "2" CGIUTL_EXAMPLE$1 == "This contains" CGIUTL_EXAMPLE$1$ == "," CGIUTL_EXAMPLE$2 == " some simple comma-s" CGIUTL_EXAMPLE$3 == "eparated" CGIUTL_EXAMPLE$3$ == "," CGIUTL_EXAMPLE$4 == " values." Note the symbols with names ending in the dollar symbol. These contain the delimiter character when it terminated the value parse (i.e. the symbol exists if the symbol value was delimited). In the case of symbol value overflow this dollar-delimited symbol does not exist and indicates the symbol number (and hence name) should be incremented for the remainder of the value (up until the dollar-delimited name is encounted). Of course delimited values can be empty (and will be with trailing delimiter characters). The symbol name plus dollar plus zero plus trailing dollar contains the count of the number of times the delimiter was hit (so the number of resulting symbols should be that plus one). Avoid having duplicate field names as it becomes very complex very quickly. The /SPLIT qualifier performs the same operation on an existing symbol. $ EXAMPLE == "one and two and three" $ CGIUTL EXAMPLE /SPLIT=" " $ SHOW SYMBOL EXAMPLE* EXAMPLE == "one and two and three" EXAMPLE$0 == "17" EXAMPLE$0$ == "4" EXAMPLE$1 == "one" EXAMPLE$1$ == " " EXAMPLE$2 == "and" EXAMPLE$2$ == " " EXAMPLE$3 == "two" EXAMPLE$3$ == " " EXAMPLE$4 == "and" EXAMPLE$4$ == " " EXAMPLE$5 == "three" This facility overwrites any existing symbol(s) of the same name(s)! In addition to all field-name related symbols produced during URL-decoding the following four special-purpose symbol provide some information about those DCL symbols created. CGIUTL$FIELDS .... the number of fields in the body (and hence
) CGIUTL$FIELDS_DUPLICATE .... the number of field names having multiple instances in the request body CGIUTL$MAXSYM .... the maximum number of characters possible in each symbol CGIUTL$SYMBOLS ... the number of field symbols created by the utility (this excludes these four special-purpose symbols) if a simple comparision between this and CGIUTL$FIELDS show a different count then at least one field had to be distributed across multiple symbols due to size DECODING A REQUEST BODY TO DCL SYMBOLS *PER LINE* ------------------------------------------------- Where a request field may have multiple lines (as with Had the following text entered into it: This is an example of a line. This is the next line. This is another line. ... and this is the last line! This text would be distributed across 4 symbols, with the additional count symbol, as follows: CGIUTL_TEXT_AREA_INPUT$0 == "102" CGIUTL_TEXT_AREA_INPUT$1 == "This is an example of a line." CGIUTL_TEXT_AREA_INPUT$2 == "This is the next line." CGIUTL_TEXT_AREA_INPUT$3 == "This is another line." CGIUTL_TEXT_AREA_INPUT$4 == "... and this is the last line!" The additional keyword NOCONTROL, removes all (tabs), (vertical-tabs) and (form-feeds), leaving only space characters. $ CGIUTL /URLDECODE /SYMBOLS=(LINES,NOCONTROL) SYMBOL NAME PREFIX ------------------ By default symbols names are created prefixed with the string "CGIUTL_". That is if there is a field name FREDDO in the request body the equivalent symbol is named "CGIUTL_FREDDO". This prefix may be user-specified with the /PREFIX qualifier. As an example; to make the symbol names much the same as those created by the server for GET requests use /PREFIX=WWW_FORM, which would result in the above form field having the symbol name "WWW_FORM_FREDDO". This could be made the default for a given script by making it part of the foreign verb assignment. $ CGIUTL = "$HT_EXE:CGIUTL/PREFIX=WWW_FORM" DECODING A REQUEST BODY TO A FILE --------------------------------- The /URLDECODE used with the /OUTPUT=filename qualifier results in a form-URL-encoded POSTed request body being written to the specified file. Two formats are possible controlled using the /FORMAT=NAMES (default) and /FORMAT=HEADINGS qualifier and keywords. When NAMES are used each field name of the format is followed by a colon, space and then the field value. With HEADINGS the field name is on a line by itself, underlined with hyphens and then in a block the field values (more suited to