Form-based documents are created in three basic steps.
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.
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.
<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>.
_____________________________________________________________________________
<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:
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.
_____________________________________________________________________________
<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.
_____________________________________________________________________________
<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.
_____________________________________________________________________________
<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.
_____________________________________________________________________________
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.
_____________________________________________________________________________
<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 (CGIs) should be stored on MUSIC userids that either have no subcode or a subcode of "000".
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.
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.
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.
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").
/inc rexx /inc $tcp:rexx.forms . ... initialize name/value variables ... call load_form_variables ... your Rexx program
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".
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='').
Your program can optionally call set_form_options,
BEFORE the call to load_form_variables, to specify various
options for $TCP:rexx.forms:
** 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_".
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.)
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.
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'
_____________________________________________________________________________/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 _____________________________________________________________________________
_____________________________________________________________________________ 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? _____________________________________________________________________________
The following is a brief outline of the flow of a compiled CGI program for processing the data from an HTML form.
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.
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.
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:
STRL1=LN(STR1,STRL1) STRL2=LN(STR2,STRL2)
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:
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:
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:
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:
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:
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:
Extracts text strings from a data string delimited by CRLF's.
CALL EXLINE(RC,LINE,LINLEN,TXTSTR,MAXOUT,TXTLEN)
Arguments:
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 _____________________________________________________________________________
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:
1 The server sends back a generic "all is OK" response.
-1 The server sends back a generic "something is wrong" response.
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.
This routine is used to set the mime type of the
response. Calling sequence:
CALL SETCON (TYPE,LENGTH)
Arguments:
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.
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 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.
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) _____________________________________________________________________________
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.
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
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:
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.
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.