World-Wide Web Support on MUSIC/SP

HTML Forms
Sample HTML Form Document
Programs for Processing HTML Form Documents
Programming HTML Forms with REXX
Sample Rexx Program
Programming HTML Forms using Compiled Programming Languages
Subroutines for Processing HTML Forms
Notes for Compiled Programming Languages
Programming HTML Forms with Fortran
Programming Considerations
Debugging CGI Scripts and Executables
Debugging Compiled Programming Languages
Debugging Rexx
Other Considerations

HTML Forms

HTML documents can be used to either gather information or to control and guide what a user is offered next. This is done through the use of "forms" support where an application "behind" the document is used to respond to the user's interactions.

Form-based documents are created in three basic steps.

  1. Design the input form and write the corresponding html document.
  2. Write the application program that interprets the data from the input fields of the form. Do whatever processing of the data is required.
  3. Design the document(s) generated by the program as a reply to the user.

HTML form documents have the following basic features. The topic "Sample HTML Form Document" below provides working examples of these features.

_____________________________________________________________________________

<HTML>
<HEAD>...text...</HEAD>
<FORM METHOD="POST" ACTION="/userid/HTTPEXEC/prog">
last name<INPUT TYPE="TEXT" NAME="last name" SIZE=30>
<INPUT TYPE="SUBMIT" NAME="Send Form">
<SELECT NAME="Day"> <option selected>Monday <option>Tuesday </SELECT>
Comments<TEXTAREA> NAME="Comments" ROWS=5 COLS=50></TEXTAREA>
</FORM>
</HTML>
_____________________________________________________________________________

The <FORM> HTML Tag

In the above example, the METHOD attribute of the FORM tag defines the method for the data to be received by the server. The POST method is recommended. This returns a string in the form "name=value&name=value&....", where name is the name of the data-entry field and value is the associated data.

The ACTION attribute of the FORM tag defines the location of the form program. userid is a valid MUSIC userid, HTTPEXEC is the directory for storing html programs (not documents), and prog is the valid file name for the MUSIC program.

The <INPUT TYPE> HTMLTag

The form document can contain several input types of data-entry fields.

text
text entry field - this is the default.
password
text entry field - entered characters are represented as *.
checkbox
a single toggle button - on or off.
radio
similar to checkbox but takes one value from a set of alternatives.
submit
a pushbutton that causes the current form content to be sent.
Note: You must have an input field of the type "submit" so that the form can be submitted, otherwise, no action can be taken.
reset
a pushbutton to return fields to default values.
image
graphical submit button rendered by an image rather than a text string.
The form document input field "hidden" described below is a hidden field and not a data-entry field for users.
hidden
a text field not rendered on the form. It provides a means for servers to store default information with a form and have it passed back to the server when the form is submitted, using the name/value pair defined by the corresponding attributes.
The <SELECT> HTML Tag

This type of data entry allows users to select from a list of available options. Within the SELECT section use <OPTION> tags for each option and include an <OPTION SELECTED> tag for the default selection.

The <TEXTAREA> HTML Tag

This tag allows users to type in multiple lines of text in a box. The ROWS and COLS attributes are used to define the size of the input area.


Sample HTML Form Document

This is a sample HTML form document. It is a registration form for a mythical course called "WEB for Dummies". It has several fields for entering information about the user and which sessions he would like to attend. After the user has filled in the form, he can press the "SUBMIT" button. This complete document is stored on MUSIC in the public file $WWS:HTTP\REG_WEB.HTML that you could copy to your userid. See the topic "Programs for Processing HTML Form Documents" for information and sample programs in Rexx and Fortran that correspond to this form document.

$WWS:HTTP\REG_WEB.HTML:
_____________________________________________________________________________

<HTML>
<HEAD>
<TITLE>WEB for Dummies</TITLE>
</HEAD>
<h2>WEB for Dummies Seminar registration for 1997</h2>
<em>This seminar is given Monday, Wednesday, and Friday every 2nd
month starting in February.<br>
On each day two sessions are given at 10:00am-12:00pm
and at 2:00-4:00pm.</em>

<strong>Please fill in the appropriate information and someone
will verify your registration via email.</strong><br>

<FORM METHOD="POST" ACTION=
"http://musicm.mcgill.ca/$wws/httpexec/reg_web">
<table>
<td><pre> Last Name<INPUT TYPE="text" name="lastname" size=32></pre>
<td><pre> First Name<INPUT TYPE="text" name="firstname" size=32></pre>
<tr>
<td><pre> Department<INPUT TYPE="text" name="department" size=32></pre>
<td><pre> E-Mail<INPUT TYPE="text" name="email" size=30></pre>
<tr>
<td><pre> Telephone<INPUT TYPE="text" name="phone" size=12></pre>
</table>

<h3>Select Seminar Time:</h3>

Month <select name="month">
<option> February 97
<option selected> April 97
<option> June 97
<option> August 97
<option> October 97
<option> December 97
</select>
Day <select name="day">
<option selected> Monday
<option> Wednesday
<option> Friday
</select>
Session <select name="time">
<option selected> 10:00-12:00 pm
<option> 2:00-4:00 pm
</select>

<h3>Optional Info:</h3>
How would rate your computer skills?
<dl>
<dd> <input type="radio" name="experience" value="B" >Beginner
<dd> <input type="radio" name="experience" value="I" >Intermediate
<dd> <input type="radio" name="experience" value="A" >Advanced
</dl>
Check any of the following if true.
<dl>
<dd> <input type="checkbox" name="used web" value="Y">
I use a WEB browser.
<dd> <input type="checkbox" name="created web" value="Y">
I have created some documents on the WEB.
</dl>

Comments<textarea name="Comments" rows=5 cols=50></textarea>
<p>
<INPUT TYPE="submit" VALUE="Send Form"><INPUT TYPE="reset" VALUE="Clear Form">
<HR>
</FORM>
</HTML>
_____________________________________________________________________________

The following illustration shows the form document ($WWS:HTTP\REG_WEB.HTML) as displayed on the Web. Below this diagram this page is further broken down into figures displaying each component with the matching html text that produced it.



Figure 1 shows the first part of the form document. The first 4 lines include typical information that is normally found at the beginning of most html documents. The actual text that corresponds with figure 1 begins with <h2>.

_____________________________________________________________________________

Figure 1

<HTML>
<HEAD>
<TITLE>WEB for Dummies</TITLE>
</HEAD>
<h2>WEB for Dummies Seminar registration for 1997</h2>
<em>This seminar is given Monday, Wednesday, and Friday every 2nd
month starting in February.<br>
On each day two sessions are given at 10:00am-12:00pm
and at 2:00-4:00pm.<br><br></em> _____________________________________________________________________________

The text in figure 2 below corresponds with the diagram with the exception of these two lines:

<FORM METHOD="POST" ACTION=
"http://musicm.mcgill.ca/$wws/httpexec/reg_web">

These lines define the <FORM> tag that is needed before variable sections of the form document. The location of the sample Rexx program is included here (you need to include your own program name). </FORM> is used to end the section and is found in figure 6 below.

_____________________________________________________________________________

Figure 2

<strong>Please fill in the appropriate information and someone
will verify your registration via email.</strong><br>

<FORM METHOD="POST" ACTION=
"http://musicm.mcgill.ca/$wws/httpexec/reg_web">
<table>
<td><pre> Last Name<INPUT TYPE="text" name="lastname" size=32></pre>
<td><pre> First Name<INPUT TYPE="text" name="firstname" size=32></pre>
<tr>
<td><pre> Department<INPUT TYPE="text" name="department" size=32></pre>
<td><pre> E-Mail<INPUT TYPE="text" name="email" size=30></pre>
<tr>
<td><pre> Telephone<INPUT TYPE="text" name="phone" size=12></pre>
</table> _____________________________________________________________________________

Figure 3 below shows three <SELECT> tags that produce pull-down options. _____________________________________________________________________________

Figure 3

<h3>Select Seminar Time:</h3>

Month <select name="month">
<option> February 97
<option selected> April 97
<option> June 97
<option> August 97
<option> October 97
<option> December 97
</select>
Day <select name="day">
<option selected> Monday
<option> Wednesday
<option> Friday
</select>
Session <select name="time">
<option selected> 10:00-12:00 pm
<option> 2:00-4:00 pm
</select>
_____________________________________________________________________________

Figure 4 shows radio and checkbox input types. The user is required to click on these options to indicate choices.

_____________________________________________________________________________

Figure 4

<h3>Optional Info:</h3>
How would rate your computer skills?
<dl>
<dd> <input type="radio" name="experience" value="B" >Beginner
<dd> <input type="radio" name="experience" value="I" >Intermediate
<dd> <input type="radio" name="experience" value="A" >Advanced
</dl>
Check any of the following if true.
<dl>
<dd> <input type="checkbox" name="used web" value="Y">
I use a WEB browser.
<dd> <input type="checkbox" name="created web" value="Y">
I have created some documents on the WEB.
</dl>
_____________________________________________________________________________

Figure 5 uses the <TEXTAREA> tag for entering comments. Attributes of this tag include the number of rows and columns for the users input area.

_____________________________________________________________________________

Figure 5

Comments<textarea name="Comments" rows=5 cols=50></textarea>
<p>
_____________________________________________________________________________

Figure 6 includes <INPUT TYPE> tags for submit and reset buttons. The user points and clicks on one of the buttons to activate. The <HR> displays a line across the page as a divider. </FORM> and </HTML> close both tags that were introduced in figures 1 and 2 respectively.
_____________________________________________________________________________

Figure 6

<INPUT TYPE="submit" VALUE="Send Form"><INPUT TYPE="reset" VALUE="Clear Form">
<HR>
</FORM>
</HTML>
_____________________________________________________________________________

The next section shows programs written in Rexx and Fortran that will process the sample HTML Form document described above.


Programs for Processing HTML Form Documents

HTML forms can be processed on MUSIC with REXX or more standard compiled programming languages such as Fortran. Both methods are described below. REXX is a simpler, more forgiving, yet powerful programming language and is often preferred.

Programs (CGIs) should be stored on MUSIC userids that either have no subcode or a subcode of "000".

Testing HTML Forms

The ECHOER program can be used to test any HTML document form. Simply place /echoer as the parameter for the ACTION key word. For example <FORM METHOD="POST" ACTION="/echoer">

The complete source of the echoer program is stored in the public file $WWS:\HTTPEXEC\ECHOER. It is a sample HTML document forms processor written in Fortran.

Using Data with CGIs

Not all CGIs process form data. You can have links in a web document that are actually plain executable files. It is often necessary to provide data with the link that customizes the application. When you provide data in the link, it is returned for the CGI to process. In this way you can have a generalized program to perform various tasks but a specific task is defined by the data portion of the link.

The example below illustrates how a link can be constructed referring to the CGI with data to be passed back for processing.

<A HREF="/userid/cgi-bin/equ ip?query =modems&part=&cat=fast">modems</A>

The entire string after "?" will be stored in the CGI environment variable called CGI_QUERY_STRING.

Rexx

The "&" in the CGI_QUERY_STRING separates each "name=value" pair. In the above example, the "name=value" pairs are "query=modems", "part=", and "cat=fast". In Rexx, if you call load_form_variables even though this is not a form, the CGI_QUERY_STRING has been interpreted and your named variables have been loaded with their respective values. Note that the CGI_QUERY_STRING named variables are given the prefix "qs_" just like named form variables. So, from the example above, "qs_query=modems", "qs_part=", and "qs_cat=fast".

If, however, the format is not parsable as name/value pairs described above, you can parse or otherwise process the Rexx variable CGI_QUERY_STRING yourself.

Other Languages (Using Fortran to Illustrate)

Unfortunately, for other languages, we don't load variables automatically. Instead you ask, through a subroutine call, for the text associated with a variable name. This is discussed in later sections.

The considerations are similar to Rexx. If the string is in a parsable format, you will be able to get the "HTTPFORMS" routines to parse it for you. You can then get the matching values for the respective variable names. Otherwise, the entire string is returned and accessed with the CGI environment variable CGI_QUERY_STRING. The example program called ECHOER illustrates how this is done (see the topic "The ECHOER Fortran Source as a CGI Example").

CGI Environment Variables

In order to pass data about the information request from the server to the script, the server uses environment variables. These environment variables are set when the server executes the program or script.
CGI_SERVER_SOFTWARE
The name and version of the information server software answering the request (and running the gateway). Format: name/version

CGI_SERVER_NAME
The server's hostname, DNS alias, or IP address as it would appear in self-referencing URLs.

CGI_GATEWAY_INTERFACE
The revision of the CGI specification to which this server complies. Format: CGI/revision

CGI_SERVER_PROTOCOL
The name and revision of the information protocol this request came in with. Format: protocol/revision

CGI_SERVER_PORT
The port number to which the request was sent.

CGI_REQUEST_METHOD
The method with which the request was made. For HTTP, this is "GET", "HEAD", "POST", etc.

CGI_PATH_INFO
The extra path information, as given by the client. In other words, scripts can be accessed by their virtual pathname, followed by extra information at the end of this path. The extra information is sent as PATH_INFO. This information should be decoded by the server if it comes from a URL before it is passed to the CGI script.

CGI_PATH_TRANSLATED
The server provides a translated version of PATH_INFO, which takes the path and does any virtual-to-physical mapping to it.

CGI_SCRIPT_NAME
A virtual path to the script being executed, used for self-referencing URLs.

CGI_QUERY_STRING
The information which follows the ? in the URL which referenced this script. This is the query information. It should not be decoded in any fashion. This variable should always be set when there is query information, regardless of command line decoding.

CGI_REMOTE_HOST
The hostname making the request. If the server does not have this information, it should set REMOTE_ADDR and leave this unset.

CGI_REMOTE_ADDR
The IP address of the remote host making the request.

CGI_AUTH_TYPE
If the server supports user authentication, and the script is protected, this is the protocol-specific authentication method used to validate the user.

CGI_REMOTE_USER
If the server supports user authentication, and the script is protected, this is the username they have authenticated as.

CGI_REMOTE_IDENT
If the HTTP server supports RFC 931 identification, then this variable will be set to the remote user name retrieved from the server. Usage of this variable should be limited to logging only.

CGI_CONTENT_TYPE
For queries which have attached information, such as HTTP POST and PUT, this is the content type of the data.

CGI_CONTENT_LENGTH
The length of the said content as given by the client.

CGI_HTTP_USER_AGENT
The browser the client is using to send the request. General format: software/version library/version.

CGI_HTTP_ACCEPT
The MIME content types accepted by the client.

CGI_HTTP_REFERER
Info from the Referer: header sent by the client. Normally this is the URL of the Web page that invoked the CGI or form.


Programming HTML Forms with REXX

Writing CGI programs and Scripts Using REXX

All Rexx CGIs must have the following elements:

/inc rexx
/inc $tcp:rexx.forms
        .
  ... initialize name/value variables
  ... call load_form_variables
  ... your Rexx program
/inc rexx
is required to indicate to the system that the contents of the file is a Rexx program.

/inc $tcp:rexx.forms
is used to include Rexx functions that are used to process the form data.
You need to initialize the variables from the form. Below is a full discussion on form variables and the many conventions.

A call to load_form_variables perform processing and parsing to generate Rexx variables that map to your form variables. At this point the CGI environment variables are generated and when available the Query string is passed and loaded into respective Rexx variables. The query string is the string that follows a question mark (?) at the end of a link that defines a CGI. This is discussed in an earlier section called "Using Data with CGIs".

Note: You should make every effort to call load_form_variables as soon as possible in the Rexx program. The execution of other programs before this will kill your CGI.

The html page that defines the form and its input and text areas also includes the names of these input fields. All such fields have an associated name. For example, the following statement defines an input text field called "lastname".

Last Name<INPUT TYPE="text" name="lastname" size=32>
The Rexx program must reference the returned value by that name, with a caller-specified prefix added. The prefix defaults to "ff_" (ff stands for Form Field), or can be specified as the argument in the call to set_form_options. So the variable in Rexx that contains the user's input will be "ff_lastname".

If the name defined in the html document were "last name" then the Rexx variable name will be "ff_last_name&quo t;. Valid Rexx variable names can contain any of the following: a-z, A-Z, 0-9, _ @ # $ . All other characters are translated to underscore (_). Periods have a special meaning in Rexx so they too will be translated to underscores. (Rexx also allows cent sign, period, ! and ?, but we do not allow them here - they are changed to underscores.) Also, since a Rexx variable name cannot start with a digit, we add an underscore on the front if the final name starts with a digit. NOTE: Case is not significant in Rexx variable names.

To load the variables with the corresponding values you call load_form_variables. This will automatically produce variable names and load them with the correct value from the returned form data. Form fields not filled in by the user are not returned and are therefore not detected and automatically loaded with a value. If you do not initialize the variables before calling load_form_variables , variables remain undefined. Before referencing or processing a non-initialized variable you should use the Rexx function SYMBOL to determine whether a variable has been defined or pre-assign the value null (eg ff_abc='').

Changing the Prefix for REXX Form Variables

Your program can optionally call set_form_options, BEFORE the call to load_form_variables, to specify various options for $TCP:rexx.forms:

call set_form_options name_prefix
Arguments:

name_prefix
Specifies the prefix that is to be added to the front of the field names, in order to make the Rexx variable names. The default is "ff_", if the argument is omitted or set_form_options is not called. The prefix should not start with a digit, and should not be null (see the following warning). In fact, the minimum length is 2 characters; if less, f's are added on the front to make it length 2.

** WARNING ** To ensure the integrity and security of the Rexx program, choose a prefix that clearly distinguishes the form field variables from all other Rexx variables in your program and in $TCP:rexx..forms. Otherwise, any user could make his own form with any field name, invoke your Rexx program, and thereby modify your variables as the program executes. We strongly recommend that you not use a null prefix, that the prefix end with an underscore, that it not start with X or x, and that it not be "cgi_", "CGI_", "qs_", or "QS_".

Return Values for other Forms Fields

Of all of the possible forms fields, the checkbox input element passes back to the server a value different from the standard name/value pair defined by the corresponding attributes when the form is submitted. For a checkbox, if the box was checked, name='on' is returned where name is the field name. Otherwise, name=' ' (null string) is returned.

Multi-line Fields

If a form field is defined as a multi-line "textarea", the returned text may have character strings delimited by CRLF (end of line markers). When this occurs, the Rexx load_form_variables call automatically detect such data. If you have defined such fields in your form you will have to process such fields differently. While fields can be referenced by the name you assigned to the field in the html document, multi-line fields are returned in either the field name or the field name with a numeric suffix. For example, ff_comment or ff_comment.1, ff_comment.2, etc.

The variable ff_comment.num contains the total number of lines returned. If the field is returned with one line, then ff_comment.num remains undefined by load_form_variables. The easiest way to test if ff_comment returned multiple lines is to check if the variable ff_comment.num is greater than zero. If it is not greater than zero then only one line was returned. If the field name is comment and one line of text is entered and returned, the Rexx variable ff_comment will hold that one line. If, however, more than one line is returned, the text would be in ff_comment.1, ff_comment.2, etc.

Note: If the "textarea" field is not filled in by the user, ff_comment, ff_comment.num and all ff_comment.i (where i=1 to ff_comment.num) will be undefined. It is your responsibility to pre-initialize some or all of the variables that you expect to use or you should test that they are not undefined. (See the sample Rexx program below.)

Assembling a Response File

While processing or after processing the data from the form, you can assemble a response for the user. This is done by the use of successive calls of the function "send_line".

Usage: call send_line '... text ...'

To return an html document you must ensure that the html you compose has the proper syntax. The minimum should look as follows:

call send_line '<html>'
call send_line '<head>'
call send_line '<title> some title </title>'
call send_line '</head>'
call send_line '<body>'

call send_line ' ... text of your choice ...'

call send_line '</body>'
call send_line '</html>'

The content of the response can be any of the supported mime types. See the section "Storing Documents on MUSIC" for a list of mime types. If you assemble a response with contents other than an HTML document, you must set the desired mime type using the send_close routine. See below.

Terminating Rexx CGIs and Sending the Response

The send_line function will have built a response for the browser. To send the response you must call the "send_close" function. This will terminate your Rexx program so that your response can be handed to the web server for delivery to the browser. This should be the last Rexx statement you issue.

Usage: call send_close n [, mime_type]

Where n is one of:

 0   to pass the contents accumulated via the send_line function.
>0   send to the browser a generic "Everything is ok" file,
     provided by the system.
<0   send to the browser a generic "Something is wrong" file
     provided by the system.
Mime_type is a mime suffix such as gif, txt, etc. For example: call send_close 0, 'txt'

Sample Rexx Program

This sample program corresponds to the "Sample HTML Form Document" described earlier. This complete program is stored in the public file $WWS:HTTPEXEC\REG_WEB.
_____________________________________________________________________________

/inc rexx /inc $TCP:rexx.forms /* initialize variables */ FF_lastname =''; FF_firstname =''; FF_department =''; FF_email =''; FF_phone =''; FF_month =''; FF_day =''; FF_time =''; FF_experience =''; FF_used_web =''; FF_created_web =''; FF_comments ='' /* generate rexx variables */ call load_form_variables call mail_it call answer exit /**********************************************************************/ mail_it: /* send mail to seminar organizer */ /* we are going to insist that a last name be present */ error=0 if ff_lastname='' then do error=1 return end queue 'lastname ='ff_lastname queue 'firstname ='ff_firstname queue 'department ='ff_department queue 'email ='ff_email queue 'phone ='ff_phone queue 'month ='ff_month queue 'day ='ff_day queue 'time ='ff_time queue 'experience ='ff_experience queue 'used_web ='ff_used_web queue 'created_web ='ff_created_web if ff_comments.num>0 then do /* multi-line comment? */ k=ff_comments.num /* yes, get each line */ do i = 1 to k queue 'comments ='ff_comments.i end end else do /* no just one line was returned */ queue 'comments ='ff_comments end /* use musio to write the queue content to a file */ 'MUSIO WRITE @TEMP ALL' /* use sendmail (sm) to send the file to the seminar coordinator */ 'SM TO($WWS) SUBJECT(WEB Seminar Registration) file(@temp)' 'purge @temp' return /*********************************************************************/ answer: /* respond to the request */ call send_line '<html>' call send_line '<head>' call send_line '<title> Registration for WEB Seminar </title>' call send_line '</head>' call send_line '<body>' call send_line '<h1>WEB for Dummies Seminar</h1>' if error=1 then do /* error was set to 1 if no last name given */ call send_line, 'You must fill in the name and email portion of the form. ' call send_line, 'Otherwise we will not be able to accept your registration' call send_line '<p>' call send_line 'Please re-submit.' end else do call send_line 'Thank you for your interest.' call send_line 'You will be contacted via email to confirm.' end /* write out the body of text and the html document */ call send_line '</body>' call send_line '</html>' /* now pass the info to the httpd server to be given to the client */ call send_close 0 exit _____________________________________________________________________________

Sample Email message produced by Rexx program

_____________________________________________________________________________
Message-Id:  <27MAR97.09805780.0074.MUSIC @MUSICM.MCGILL.CA>
Date:        Thu, 27 Mar 1997 09:04:45 EST
From:        TEST WEB PAGES <$WWS@MUSICM.MCGILL.CA>
To:          TEST WEB PAGES <$WWS@MUSICM.MCGILL.CA>
Subject: WEB Seminar Registration
X-Mailer: MUSIC/SP V5.1.0

lastname    =Smith
firstname   =Lucy
department  =MUSIC Product Group
email       =lucy@musicm.mcgill.ca
phone       =398-xxxx
month       =June 97
day         =Wednesday
time        =2:00-4:00 pm
experience  =A
used_web    =Y
created_web =Y
comments    =Is there any charge?
_____________________________________________________________________________


Programming HTML Forms using Compiled Programming Languages

The following is a brief outline of the flow of a compiled CGI program for processing the data from an HTML form.

  1. Call to GTFORM to fetch the 2 response strings from the client. Each string has a series of name/value pairs separated by ampersands (&). The first string contains the form data; the second string contains the CGI environment variables. The following is a sample from the example presented later in this section:

    last name=&first name=&department=&email=&phone=& month=April%2095&day=Monday&time=10%3A00-12%3A00%20am

    Note that special characters are transmitted as %xx, where xx is a hexadecimal number representing an ASCII character. The RDFORM and RDNUM routines automatically convert these for you.

  2. Calls to RDINFO and either RDFORM or RDNUM will retrieve the name/value pairs. Please see the Fortran sample program to help you understand the technique.

  3. Calls to RDRSET for switching between using the returned contents of the forms fields and the CGI environment variables.

  4. Your program performs whatever processing is necessary. This could include writing the forms data to a file, sending an e-mail message to someone, etc.

  5. Calls to ADLINE are used either during or after processing to construct a response to the user.

  6. Calls SETCON used to set the mime type of the response. Default is HTML.

  7. Call to RSPOND is used to signal to the HTTPD (Web) server that processing is complete and that a response is available for transmittal to the client. RSPOND will terminate your program. It then sends the response to the Web server to complete the response to the browser. Do all your processing before calling RSPOND, since RSPOND ends the CGI program.

Subroutines for Processing HTML Forms

Programs written to handle html forms will use some or all of the following routines (details of each routine can be found below). These routines can be used in any programming language including REXX. However, Rexx has a special interface that is discussed in earlier sections. These routines are recommended for compiled programming languages only.

GTFORM
get the client's returned string of variable names/values from what the user filled in.

RDFORM
given a variable name return its value.

RDNUM
get the name/value strings of the ith pair.

RDINFO
tells you how many name/value pairs there are, as well as the maximum lengths of the name strings and value strings.

RDPOS
returns the positions and lengths of the name/value pairs.

ADLINE
add a line to the response to the client.

EXLINE
extract text strings from a data string delimited by CRLF's.

RSPOND
tells HTTPD server that the program has completed. The text passed back by ADLINE will be transmitted to the client as a response to the user.

RDRSET
resets all pointers, variables etc.

SETCON
sets the mime type of the response.


Descriptions of HTML Subroutines

The following describes each subroutine and its corresponding arguments.

GTFORM

The forms data from the client (browser) is available as 2 records in a file. The first record contains the name=value strings for each field in the form. The second record contains the CGI environment variables for this HTTP request, also as name=value strings. Each record is in the format:

name1=value1&name2=value2&name3=value3& ...

The GTFORM routine reads the two records and stores them into 2 string areas that you provide (the STR1 and STR2 arguments). Calling sequence:

CALL GTFORM(RC,STR1,STRL1,STR2,STRL2)

Arguments:

RC
(Output arg) MFIO return code in case of error. Any nonzero value indicates an error.

STR1
(Output arg) Area to receive the first string, from record 1 of the file. The string contains the HTML form variables. The area is blank-filled at the end, to the length specified by STRL1.

STRL1
(Input arg) The length of the area STR1 that the caller provides. If the actual string is longer than this, only the first STRL1 characters are returned in STR1. The maximum possible length of a string is 32760 characters. STRL1 can have a value from 1 to 32760. For efficient processing, do not specify a length that is a lot longer than is needed to hold the largest expected amount of forms data.

STR2
(Output arg) Area to receive the second string, from record 2 of the file. This string contains the CGI variables. An example of a CGI variable is CGI_REMOTE_ADDR=133.125.45.101 . The area is blank-filled at the end, to the length specified by STRL2.

STRL2
(Input arg) The length of the area STR2 that the caller provides. If the actual string is longer than this, only the first STRL2 characters are returned in STR2. The maximum possible length of a string is 32760 characters. STRL2 can have a value from 1 to 32760, but normally a value of 4096 or less is used, since that is sufficient to hold the CGI variables.
NOTE: For efficient processing, you can reduce the lengths STRL1 and STRL2 after calling GTFORM and before calling the other routines such as RDINFO, RDFORM, RDNUM, in order to exclude the trailing blanks at the end of STR1 and STR2. This can be done by the statements:

          STRL1=LN(STR1,STRL1)
          STRL2=LN(STR2,STRL2)

RDFORM

This subroutine is used to get the value of a known variable name. Given KWORD, PRMSTR is returned as the value of KWORD. Calling Sequence:

CALL RDFORM(RC,STRn,STRLn,KWORD,KLEN,PRMSTR,PRMLEN,VALUE)

Arguments:

RC
returns the length of prmstr, if KWORD is not found, -1 is returned as the value.

KWORD
A 1 to 64 character keyword to be searched for

KLEN
length of KWORD

STRn
The string from the client with the forms response.

STRLn
The length of string.

PRMSTR
The character string associated with KWORD.

PRMLEN
The maximum length of PRMSTR.

VALUE
Integer value of PRMSTR (where applicable)
Some special characters are encoded with a preceding % (per cent). For example an asterisk (*) will come to us as an encoded %2A, where 2A is the ascii hex value. We will convert "%2A" to "*".

Example:

STRING contains the following, and is of length 32000

password=secret&fromemail=me@here& title=Duh..%20title&message=Text

CALL RDFORM(RC,STRING,32000,'password',8,PRMSTR,80,VALUE)

returns: RC     6      (length of prmstr)
         PRMSTR secret (character string associated with password)
         VALUE  0      ('secret' is not an integer)
Arguments:
RC
returns the length of prmstr, if KWORD is not found, -1 is returned as the value.

STRING
The string from the client with the forms response.

PRMSTR
The character string associated with KWORD.

VALUE
Integer value of PRMSTR (where applicable)
Note that the keyword must be in the same case as was used in the HTML document form.

RDNUM

This subroutine is used to get the ith name/value pair from one of the strings returned by GTFORM. The index number i of the desired pair is specified by the VARNUM arg. The keyword (name) string is returned in the KWORD arg. The value string is returned in the PRMSTR arg. For example, if a string contains "username=Fred", then the name (keyword) string is "username" (8 chars) and its value string is "Fred" (4 chars). Calling sequence:

CALL RDNUM(RC,STRn,STRLn,KWORD,KLEN,PRMSTR,PRMLEN,VALUE,VARNUM)

Arguments:

RC
(Output arg) Returns the length of the value string (PRMSTR). If VARNUM is out of bounds, -1 is returned.

STRn
(Input arg) The string from the client with the forms response. This is either STR1 or STR2 returned by the GTFORM routine.

STRLn
(Input arg) The length of the string STRn. For efficient processing, this should not include trailing blanks in the string STRn that was returned by GTFORM. After the call to GTFORM, use the Fortran statement STRLn=LN(STRn,STRLn) to set STRLn to the length not counting trailing blanks.

KWORD
(Output arg) A 32-character area which is set to the keyword (name). It is blank-filled to length 32. NOTE: If any keyword is longer than 32 characters, a longer KWORD arg must also be used. The maximum length of a keyword can be found by the RDINFO routine (MXVARL arg).

KLEN
(Output arg) Set to the length of the keyword, not counting trailing blanks.

PRMSTR
(Output arg) An area to receive the value string associated with the keyword. The area is NOT blank-filled with trailing blanks. The caller must ensure that the length of this area is at least the maximum value length (MXVALL) returned by the RDINFO routine. The length of the value string is returned in the RC arg. RC=0 means there is no value string (null string).

PRMLEN
(Input arg) The maximum length of PRMSTR. NOTE: Currently, this argument is ignored.

VALUE
(Output arg) If the value string is a numeric value (1 or more digits only), the integer value of it is returned in this argument. Otherwise this arg is set to 0.

VARNUM
(Input arg) The index number (1 or more) of the desired keyword.

RDINFO

This subroutine is used to return the number of variable/value pairs and the length of the longest variable name and the longest value string. Calling sequence:

CALL RDINFO(RC,STRn,STRLn,TOTVAR,MXVARL,MXVALL)

You should call RDINFO before calling RDFORM or RDNUM.

Arguments:

RC
(Output arg) MFIO return code in case of error.

STRn
(Input arg) The string from the client with the forms response. This is either STR1 or STR2 returned by the GTFORM routine.

STRLn
(Input arg) The length of the string STRn. For efficient processing, this should not include trailing blanks in the string STRn that was returned by GTFORM. After the call to GTFORM, use the Fortran statement STRLn=LN(STRn,STRLn) to set STRLn to the length not counting trailing blanks.

TOTVAR
(Output arg) Total number of name/value pairs in the string.

MXVARL
(Output arg) The length of the longest variable name (keyword) in the string.

MXVALL
(Output arg) The length of the longest value string in the string.

RDPOS

This subroutine is used to return the character positions of the variable/ value pair pointed to by VARNUM. Calling sequence:

CALL RDPOS(RC,STRn,STRLn,VARNUM,VARPOS,VARLN,VALPOS,VALLN)

Arguments:

RC
mfio return code in case of error.

STRn
1-32760 text string to be retrieved from the file (line 1). this is in the form keyword1=text1&keyword2=text2

STRLn
MAXIMUM length of STR1

VARNUM
ITH variable in the form

VARPOS
position of the ith variable.

VARLN
length of the ith variable

VALPOS
position of the ith value string

VALLN
length of the ith value string

ADLINE

Adds a record to the response file. The first call to ADLINE automatically opens the file. The file is automatically closed when you call RSPOND. By default, the response file is assumed to contain HTML text, starting with <html> and ending with </html>. For a text file (HTML or plain text), the Web server automatically takes care of converting the data to Ascii and adding CR/LF at the end of each line; therefore your calls to ADLINE send only the text itself. Calling sequence:

CALL ADLINE(RC,TEXT,TXTLEN)

Arguments:

RC
(Output arg) MFIO return code in case of an input/output or file error. Any nonzero value indicates an error.

TEXT
(Input arg) 1- to 32760-character string to be written to the file as a record.

TXTLEN
(Input arg) The length of the string to be written.

EXLINE

Extracts text strings from a data string delimited by CRLF's.

CALL EXLINE(RC,LINE,LINLEN,TXTSTR,MAXOUT,TXTLEN)

Arguments:

RC
mfio return code in case of error.

LINE
data string delimited with CRLF's (x'OD25') that is to be processed.

LINELEN
the length of LINE.

TXTSTR
the extracted text string will be placed in TXTSTR.

MAXOUT
the maximum length of TXTSTR.

TXTLEN
the returned length of the extracted text string in TXTSTR.

Example:

_____________________________________________________________________________

IMPLICIT INTEGER (A-Z) CHARACTER*80 LINE, TXTSTR 100 ... get a new string for processing ... ... LINLEN is the length of LINE ... ... processed all data strings go to 999 ... C 200 CALL EXLINE(RC,LINE,LINLEN,TXTSTR,80,TXTLEN) C C-- if rc=0 or 1, a text string was returned C IF (RC.GE.0) PRINT*,TXTSTR(:TXTLEN) C C-- if rc=0 or -1, process for current string done, get a new string C IF (RC.LE.0) GO TO 100 GO TO 200 999 STOP END _____________________________________________________________________________

RSPOND

This routine is used to signal the HTTPD server that processing is complete. Your CGI program is terminated. The server then takes the text lines provided by ADLINE and sends them as response data to the client (browser). Calling sequence:

CALL RSPOND(RC,GEN)

Arguments:

RC
(output arg) This is a return code. However, your program cannot use it because RSPOND ends the CGI program and does not return to the caller.

GEN
(Input arg) If you are using the ADLINE routine to generate your own response to be sent to the client (as in normally the case), this argument should be 0. In other cases, you can set it as follows:

1     The server sends back a generic "all is OK" response.

-1     The server sends back a generic "something is wrong" response.

RDRSET

This subroutine is used to zero all counters and pointers into string. Calling sequence:

CALL RDRSET

RDRSET is used for switching between processing the forms name/value pairs and the CGI name/value pairs.

SETCON

This routine is used to set the mime type of the response. Calling sequence:

CALL SETCON (TYPE,LENGTH)

Arguments:

TYPE
is a 1-16 character string containing one of the standard mime suffixes such as txt, gif, or jpg. See the section "Storing Documents on MUSIC" for more details on mime types.

LENGTH
is the length of the text string of the TYPE argument.
Example: CALL SETCON('TXT',3)

The default assumption is that the response data for the user will be an HTML document. This, however, need not be the case. If you choose to build a TXT (plain text file) or a GIF (graphic), or any other mime type via the ADLINE routine, you must set the mime type. A call to SETCON is used to set it. It must be called before the RSPOND routine.

Notes for Compiled Programming Languages


Programming HTML Forms with Fortran

The following is a Fortran program that processes the HTML document form in a previous section called "Sample HTML Form Document". This program uses GTFORM to fetch the fields from the client (user). It stores the string in a REXX variable called STRING with an expected length of 3200. This is an arbitrary number that you choose based on the number and size of the fields. The maximum is 32000 characters.

The string is made up of pairs of name/value strings separated by "&". The program requires that the user types in his last name at least. So the program through the use of RDFORM verifies this. If it is not found, it will send a complaint back to the user via the ADLINE routine.

If the last name is present, it will continue to get each name/value pair.

It then constructs a mail message to be sent to the course coordinator.

If all goes well via the ADLINE routine we tell the user that he will be contacted about his registration.

After all processing is complete, the RSPOND routine is called to hand the HTTPD (WEB) server control and terminate our program.

This sample program corresponds to the "Sample HTML Form Document" described earlier. This complete program is stored in the public file $WWS:HTTPEXEC\FORTFORM.S.

_____________________________________________________________________________

/FILE 6 N(WORK2) NEW(REPL) RECFM(VC) /SYS REGION=1024 /LOAD VSFORT /OPT DECK,FLAG(E),NOSDUMP,OPT(3),CHARLEN(32000) C +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ C C--fortform C This program is a fortran version of rexform. C----------------------------------------------------------------------- BLOCK DATA COMMON/VN/ VNLEN, VNLIST CHARACTER*64 VNLIST(12) INTEGER VNLEN(12) DATA C-----------------------------|---+----1----+ * VNLIST(01), VNLEN(01)/'lastname ', 8/ * VNLIST(02), VNLEN(02)/'firstname ', 9/ * VNLIST(03), VNLEN(03)/'department ', 10/ * VNLIST(04), VNLEN(04)/'email ', 5/ * VNLIST(05), VNLEN(05)/'phone ', 5/ * VNLIST(06), VNLEN(06)/'month ', 5/ * VNLIST(07), VNLEN(07)/'day ', 3/ * VNLIST(08), VNLEN(08)/'time ', 4/ * VNLIST(09), VNLEN(09)/'experience ', 10/ * VNLIST(10), VNLEN(10)/'used web ', 8/ * VNLIST(11), VNLEN(11)/'created web ', 11/ * VNLIST(12), VNLEN(12)/'comments ', 8/ END C----------------------------------------------------------------------- C IMPLICIT INTEGER(A-Z) CHARACTER STRING*32000, CGISTR*4096, PARMX*256 CHARACTER INPUT*32000, OUTPUT*8192, TXTSTR*4096, KWORD*32 CHARACTER CRLF*2/Z0D25/, REFSTR*10/'0123456789'/ C COMMON/VN/ VNLEN, VNLIST CHARACTER*64 VNLIST(12) INTEGER VNLEN(12) C-- initialize error to 0, it will be set to zero if lastname is found ERROR=1 C C-- fetch the returned DATA C CALL GTFORM(RC,STRING,32000,CGISTR,4096) C C-- get some info about name/value pairs C CALL RDINFO(RC,STRING,32000,TOTVAR,MXVARL,MXVALL) C C-- if no name/value pairs were returned, set error=1 and answer C IF (TOTVAR.LE.0) THEN ERROR=1 CALL ANSWER(ERROR,*888) ELSE C C-- open a new mail file, mailit will close it later C CALL OPNML(RC) IF (RC.NE.0) GO TO 888 C C-- Now get each name/value pair and write them to our mail file C DO 350 I=1,12 CALL RDFORM(XC,STRING,32000,VNLIST(I),VNLEN(I), * INPUT,32000,VALUE) PRINT*,VNLIST(I),XC IF (XC.GT.0) THEN C C-- if the text has imbedded CRLF chars write it out in chunks C 360 CALL EXLINE(ERC,INPUT,XC,TXTSTR,4096,TXTLEN) PRINT*,'ERC=',ERC, TXTSTR(:TXTLEN) IF (ERC.GE.0) THEN OUTPUT=VNLIST(I)(:MXVARL)//' = '//TXTSTR(:TXTLEN) TOTAL=MXVARL+TXTLEN+3 CALL WRITML(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 ENDIF IF (ERC.EQ.1) GO TO 360 C ELSE C C- case when no value has been return for a variable C-- if lastname is not specified report an error C IF (I.EQ.1) THEN ERROR=1 CALL ANSWER(ERROR,*888) GO TO 888 ENDIF C OUTPUT=VNLIST(I)(:MXVARL)//' = ' TOTAL=MXVARL+XC+3 CALL WRITML(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 ENDIF C C-- go find next name/value pair C 350 CONTINUE ENDIF C C-- Tell SERVER that we are finished C 999 ERROR=0 CALL CLSML(RC) IF (RC.NE.0) GO TO 888 CALL MAILIT CALL ANSWER(ERROR,*888) CALL RSPOND(RC,0) C C-- Tell SERVER that we are finished, BUT something went wrong C 888 CALL RSPOND(RC,-1) STOP END C----------------------------------------------------------------------- SUBROUTINE ANSWER(ERROR,*) IMPLICIT INTEGER (A-Z) CHARACTER TXT(13)*80 C DATA *TXT(1)/'<html>'/ *TXT(2)/'<head>'/ *TXT(3)/'<title> Registration for WEB Seminar </title>'/ *TXT(4)/'</head>'/ *TXT(5)/'<body>'/ *TXT(6)/'<h1>WEB for Dummies Seminar</h1>'/ *TXT(7)/'You must fill in your name and email portion of the form.' */ *TXT(8)/'Otherwise we will not be able to accept your registration. *<p>'/ *TXT(9)/'Please re-submit.'/ *TXT(10)/'Thank you for your interest.'/ *TXT(11)/'You will be contacted via email to confirm.'/ *TXT(12)/'</body>'/ *TXT(13)/'</html>'/ C C-- write the top part of prepared header text C DO 300 I=1,6 CALL ADLINE(RC,TXT(I),80) IF (RC.NE.0) GO TO 888 300 CONTINUE C C-- if no last name, complain to the user, write correct text C IF (ERROR.GT.1) THEN START=7 END=9 ELSE C C-- everything ok, write correct text C START=10 END=11 ENDIF DO 310 I=START,END CALL ADLINE(RC,TXT(I),80) IF (RC.NE.0) GO TO 888 310 CONTINUE C C-- write last closing html line to results file C DO 320 I=12,13 CALL ADLINE(RC,TXT(I),80) IF (RC.NE.0) GO TO 888 320 CONTINUE RETURN 888 RETURN 1 END C----------------------------------------------------------------------- SUBROUTINE OPNML(RC) C IMPLICIT INTEGER (A-Z) CHARACTER*200 OUTPUT REAL*8 LIST(1) C INTEGER INFO(5)/2,0,-1,Z00C80400,Z0000C0C0/, FINFO(5) COMMON/MFINFO/ FINFO C C-- OPEN A TEMPORARY WORK FILE TO BE LATER RENAMED TO THE OUTPUT FILE. C CALL LMOVE(INFO,FINFO,20) CALL MFACT(RC,'OPEN OKNEW RDOK WROK.','&&TEMP ') PRINT*,'OPEN RC=',RC RETURN C C-- WRITE text to file C ENTRY WRITML(RC,OUTPUT,LEN) CALL MFIO(RC,'$.',0,LEN,OUTPUT) PRINT*,'WRITE RC=',RC RETURN C C-- THIS SECTION CLOSES AND RENAMES THE &&TEMP FILE TO @temp C ENTRY CLSML(RC) CALL MFACT(RC,'CLOSE REPL RLSE.','@TEMP ') PRINT*,'CLOSE RC=',RC RETURN END C----------------------------------------------------------------------- SUBROUTINE MAILIT IMPLICIT INTEGER (A-Z) CHARACTER*100 CMDSTR C C-- USE sendmail (SM) to sent the file @temp that we created and C delete it. C CMDSTR='SM TO($WWS) SUBJECT(WEB Seminar Registration) FILE(@TEMP)' CALL NXTCMD(CMDSTR,100,128,64+32) RETURN END _____________________________________________________________________________

The ECHOER Fortran Source as a CGI Example

The ECHOER program has been included as a standard compiled programming example because it illustrates how the form data can be manipulated. It shows how you can sample the CGI environment variables and parse the returned query string.

Specifically, it shows how you can switch from parsing one of the three "form data", CGI environment variables and the query string.

The example also includes all Job Control Language (JCL) to create object decks and load modules. These are offered as a guide to assist you in creating load modules of your CGI. Consult the MUSIC/SP User's Reference Guide for details about the specific compiler that you are using.

Note: $TCP is a system userid (account). You must substitute your own userid in its place for your own applications.

ECHOER Example

The Source File:

The following JCL will produce an object deck to be used later in the LINKAGE step. This program is stored in the public file $WWS:HTTPEXEC\ECHOER.

_____________________________________________________________________________

/SYS REGION=1024 /FILE SYSPUNCH N($tcp:ECHOER.OBJ) NEW(REPL) DEF /LOAD VSFORT /JOB NOGO /OPT DECK,FLAG(E),NOSDUMP,OPT(3),CHARLEN(32000) C +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ C MUSIC/SP: MULTI-USER SYSTEM FOR INTERACTIVE COMPUTING/ SYSTEM PRODUCT C 5796-AAT (C) COPYRIGHT MCGILL UNIVERSITY, MONTREAL, CANADA, 1972 C 5796-AJC (C) COPYRIGHT MCGILL UNIVERSITY, MONTREAL, CANADA, 1975 C 5796-ATL (C) COPYRIGHT MCGILL UNIVERSITY, MONTREAL, CANADA, 1978 C 5796-PQA (C) COPYRIGHT MCGILL UNIVERSITY, MONTREAL, CANADA, 1981 C 5664-197 (C) COPYRIGHT MCGILL UNIVERSITY, MONTREAL, CANADA, 1985 C 5750-ACF (C) COPYRIGHT MCGILL UNIVERSITY, MONTREAL, CANADA, 1989 C +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ C C C--ECHOER C This program is used by HTTPD to ECHO back to a client the C name/value pairs that are transmitted to us. C C----------------------------------------------------------------------- C C CHANGE LOG: C C written 08may95 by Frank Pettinicchio C 17jul95 support for echoing map coordinates C----------------------------------------------------------------------- C IMPLICIT INTEGER(A-Z) CHARACTER STRING*32000, CGISTR*4096, PARMX*256 CHARACTER INPUT*32000, OUTPUT*8192, TXTSTR*4096, KWORD*32 CHARACTER TXT(10)*80, CRLF*2/Z0D25/, REFSTR*10/'0123456789'/ C DATA *TXT(1)/'<HTML> <head>'/ *TXT(2)/'<title> ECHO </title> '/ *TXT(3)/'</head>'/ *TXT(4)/'<body>'/ *TXT(5)/'<h1>Query results</h1>'/ *TXT(6)/'<p>'/ *TXT(7)/'<h2> You submitted the following name/value pairs. *</h2><PRE>'/ *TXT(8)/'</PRE> </body> </html>'/ *TXT(9)/'<HR><H3>CGI Info</H3><BR>'/ *TXT(10)/'<HR><H3>QUERY STRING PARSED</H3><BR>'/ C C-- fetch the returned DATA and CGI info from the client C CALL GTFORM(RC,STRING,32000,CGISTR,4096) C C-- write the top part of prepared header text C DO 300 I=1,7 CALL ADLINE(RC,TXT(I),80) IF (RC.NE.0) GO TO 888 300 CONTINUE C C-- get some info about name/value pairs C CALL RDINFO(RC,STRING,32000,TOTVAR,MXVARL,MXVALL) C C-- if no name/value pairs were returned, C this is either a C 1- an image map coordinate pair C 2- A generic CGI query string C IF (TOTVAR.LE.0) THEN C C-- reset and connect variables to the CGI data C CALL RDRSET CALL RDINFO(RC,CGISTR,4096,TOTVAR,MXVARL,MXVALL) C C-- the CGI_QUERY_STRING contains the data return with the CGI C program name separated by a "?" C CALL RDFORM(RC,CGISTR,4096,'CGI_QUERY_STRING',16,PARMX,256, * VALUE) PARMXL=RC IF (PARMXL.LE.0) GO TO 777 COMMA=LOCATE(PARMX,PARMXL,',',1) PART1=0 PART2=0 IF (COMMA.GT.0) THEN CALL VERIFY(PARMX,COMMA-1,REFSTR,10,PART1) CALL VERIFY(PARMX(COMMA+1:),PARMXL-COMMA,REFSTR,10,PART2) ENDIF C C-- If this is an image map request, it must be in the form #,# C where # is a valid number composed of digits 0-9 C IF (COMMA.GT.0.AND.PART1.EQ.0.AND.PART2.EQ.0) THEN OUTPUT(1:30)='X='//PARMX(1:COMMA-1) CALL ADLINE(RC,OUTPUT,30) IF (RC.NE.0) GO TO 888 OUTPUT(1:30)='Y='//PARMX(COMMA+1:PARMXL) CALL ADLINE(RC,OUTPUT,30) IF (RC.NE.0) GO TO 888 GO TO 777 ELSE C C-- Otherwise this is a CGI that isn't posting forms data for processing C simply report the query string C OUTPUT='CGI query string is: '//PARMX(:PARMXL) TOTAL=LOCATE(OUTPUT,-400,' ',-1) CALL ADLINE(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 ENDIF ELSE C C-- reset and re-establish connection to posted data string C CALL RDRSET CALL RDINFO(RC,STRING,32000,TOTVAR,MXVARL,MXVALL) C C-- Now get each name/value pairs and write them to our results file C DO 350 I=1,TOTVAR CALL RDNUM(XC,STRING,32000,KWORD,KLEN,INPUT,32000,VALUE,I) IF (XC.GT.0) THEN C C-- if the text has imbedded CRLF chars write it out in chunks C 360 CALL EXLINE(ERC,INPUT,XC,TXTSTR,4096,TXTLEN) IF (ERC.GE.0) THEN OUTPUT=KWORD(:MXVARL)//' = '//TXTSTR(:TXTLEN) TOTAL=MXVARL+TXTLEN+3 CALL ADLINE(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 ENDIF IF (ERC.EQ.1) GO TO 360 C ELSE C C- case when no value has been return for a variable C OUTPUT=KWORD(:MXVARL)//' = ' TOTAL=MXVARL+XC+3 CALL ADLINE(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 ENDIF C C-- go find next name/value pair C 350 CONTINUE ENDIF C** C C-- Now get CGI name/value pairs and write them to our results file C 777 CALL RDRSET CALL RDINFO(RC,CGISTR,4096,TOTVAR,MXVARL,MXVALL) CALL ADLINE(RC,TXT(9),80) DO 450 I=1,TOTVAR CALL RDNUM(XC,CGISTR,4096,KWORD,KLEN,INPUT,4096,VALUE,I) IF (XC.GT.0) THEN OUTPUT=KWORD(:MXVARL)//' = '//INPUT(:XC) IF (RC.NE.0) GO TO 888 ELSE C C- case when no value has been return for a variable C OUTPUT=KWORD(:MXVARL)//' = ' ENDIF TOTAL=MXVARL+XC+3 CALL ADLINE(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 C C-- go find next name/value pair C 450 CONTINUE C C-- if we have CGI_QUERY_STRING, try to parse it, it may or may not C be in the correct format, load it into PARMX C CALL RDRSET CALL RDINFO(RC,CGISTR,4096,TOTVAR,MXVARL,MXVALL) CALL RDFORM(RC,CGISTR,4096,'CGI_QUERY_STRING',16,PARMX,256, * VALUE) PARMXL=RC C C-- IF no query string was returned, leave now C IF (PARMXL.LE.0) GO TO 666 C C-- otherwise reset the form variables and plug in the query string C CALL RDRSET CALL RDINFO(RC,PARMX,256,TOTVAR,MXVARL,MXVALL) C C-- if rc=-1 there are not name/value pairs in the query string C IF (RC.LT.0) GO TO 666 CALL ADLINE(RC,TXT(10),80) DO 550 I=1,TOTVAR CALL RDNUM(XC,PARMX,PARMXL,KWORD,KLEN,INPUT,4096,VALUE,I) IF (XC.GT.0) THEN OUTPUT=KWORD(:MXVARL)//' = '//INPUT(:XC) IF (RC.NE.0) GO TO 888 ELSE C C- case when no value has been return for a variable C OUTPUT=KWORD(:MXVARL)//' = ' ENDIF TOTAL=MXVARL+XC+3 CALL ADLINE(RC,OUTPUT,TOTAL) IF (RC.NE.0) GO TO 888 C C-- go find next name/value pair C 550 CONTINUE C** C C-- write last closing html line to results file C 666 CALL ADLINE(RC,TXT(8),80) IF (RC.NE.0) GO TO 888 C C-- Tell httpd that we are finished C 999 CALL RSPOND(RC,0) C C-- Tell httpd that we are finished, BUT something went wrong C 888 CALL RSPOND(RC,-1) STOP END _____________________________________________________________________________

The Linkage File:

Execution of the following file will produce a load module to be used in the EXEC file.
_____________________________________________________________________________

/FILE LMOD N($TCP:ECHOER.LMOD) NEW(REPL) SP(100) RECFM(F) LR(128) SHR
/FILE 6 N($TCP:ECHOER.MAP) NEW(REPL)
/LOAD LKED
/JOB PRINT,NOGO,STATS,NAME=ECHOER,MAP,MODE=OS
.ORG 4A00
/INC $TCP:ECHOER.OBJ
_____________________________________________________________________________
The Exec File: _____________________________________________________________________________
/SYS NOPRINT,REGION=300,TIME=MAX
/LOAD XMON
echoer N($TCP:echoer.LMOD)
_____________________________________________________________________________


Programming Considerations

Debugging CGI Scripts and Executables

It is often useful to capture output from your CGI script or program as it is executed via a request from a web browser. CGI scripts and programs run in background mode. On this system, this means that all standard output to the printer (Fortran unit 6 etc) is unavailable to you.

REXX CGIs differ significantly from other programming language CGIs as it is interpreted and not compiled. Therefore the method for debugging is different. This section describes the two methods for debugging and capturing print output from your CGIs.

Debugging Compiled Programming Languages

For all programming languages other than REXX, you can easily capture the print output by the use of a "/FILE" statement. In doing this you re-route your output to a file that you can inspect later. For example, a Fortran program would have a statement like the following:

/FILE 6 N(YOURUSERID:WEB.OUTPUT) NEW(REPL) SPACE(50) RECFM(VC)

Notes:

It is essential that you prefix the file name with your userid as is indicated in the example. This will ensure that the file generated will be accessible to you. When testing CGIs that login to the userid, you must use your own userid to gain authorization.

6
this is the Fortran unit number where the printed output is sent in the program. For other programming languages consult the User Reference Manual or contact your site support staff.

NEW(REPL)
should be specified so that each run creates a new file with your debug and other output.

SPACE
is used to allocate a reasonable amount of disk space in K bytes. You will have to decide how much is reasonable. 50 is a good number.

RECFM(VC)
makes the file variable length and ready to receive any record length of up to 32760 bytes. This is highly recommended.
It is essential to understand that while you are doing this kind of debugging, the CGI is not available for concurrent usage. The file you are using for collecting debugging information is exclusively enqueued to one user at a time. You must not leave such a file statement in place once in production. In fact this rule applies to all and any file your CGI may use. You must ensure that file access in your CGI is orderly and tends to enqueue conflicts on file usage.

You should avoid CGIs in source form. Compilation and linkage can be very inefficient. You should create load modules. Sample file listings for the Echoer program can be found in the previous section "The ECHOER Fortran Source as a CGI Example". It shows how a load module can be created. Please consult the MUSIC/SP User's Reference Guide for more details.

Debugging REXX

REXX requires a different strategy. For REXX there is an automated facility called HTDEBUG to turn on and off REXX print output. This is used in *Go mode while you are logged on to your MUSIC account.

Usage:

     HTDEBUG filename size
     HTDEBUG off
filename
is the name of the file in which debug information is to be written.

Size
an integer to be used to set the size of file name in K bytes. If size is not specified it defaults to 50 K bytes.

Off
turns REXX debugging off. It is important to turn of HTDEBUG when you are finished.

Notes:

Once you have successfully started REXX debugging through HTDEBUG all REXX programs you run (yours and system facilities) are affected. All output from any of these will accumulate in the allocated file. It is very important that once you have completed your debugging efforts that you turn this feature off.

You can clear the contents of the file by deleting it as follows:

delete filename
The debug facility automatically creates a new file for any new data.

Once you have turned off the REXX debug feature, you may want to delete the debug file. It can grow considerably.

WARNING:It is critical that you turn off Rexx debugging when you are done or suspending your debugging efforts. It can affect other MUSIC applications that you might use.

The following is a simple step-by-step procedure on how HTDEBUG could be used.

  1. Logon to your MUSIC userid. (You can not debug a form you don't own.)
  2. Modify your Rexx program to include debug statements in the form of SAY and TRACE statements. See the section Other Considerations below for more details.
  3. In *Go mode issue the HTDEBUG command as discussed above.
  4. From the Web browser, submit the form.
  5. From your MUSIC userid issue HTDEBUG OFF.
  6. View the contents of the file you specified in the HTDEBUG command.
  7. Repeat as required. You can delete the file between runs so as to discard the debug information from previous runs.

Other Considerations

For REXX only

REXX has a very useful function called "trace". It produces excellent debugging information. See the User's Reference guide or an appropriate REXX language reference text for further details on "trace". The most common form of the trace function is "trace results". You place this as a Rexx statement at the point which you want tracing to begin. This can help detect common syntax errors quite well. You can also use the "say" Rexx function to print the contents of variables or other debugging text.

For all programming languages

Another useful technique to get information back to you from a CGI executing in the background is the use of a command or subroutine called TELL. REXX scripts can use the command form: "TELL userid ...text...".

All other programming languages must call the NXTCMD routine to execute the TELL command. See the MUSIC/SP Reference Guide. The TELL subroutine or command is used to pop a message to a logged on userid's screen. For this purpose the userid would be your own. The tell command is placed with the proper text at what ever point you wish.

The TELL command must not be used before the call load_form_Variables.


Return to "Web Support"
This page last updated July 3, 1997.