
Joachim Neuber jneuber@foni.net, December 2001
(Translated from the original German article "CGI-Programmierung mit COMAL" with the kind permission of the author. Program code extracts have been left in their original form, with translations of the variable names etc. provided after the code. Our thanks, once again, to Anita of Translations A. Millar for the translation.)
Literature: I consider that the best introduction to CGI programming in the German language can be found in SELFHTML at selfhtml.teamone.de.
The programs in this article use a small COMAL module called STDOUT.EXE. You can download it, together with comments.exe, comments.lst and cgicomal.htm as a ZIP file(59 KB)by clicking here: cgicomal.zip.
The browser (client) requests a document (e.g. info.htm) from the web server that is often quite distant. The web server searches for the requested document in its web directory and delivers it to the browser. The rules of this operation are defined in the HTTP (Hypertext Transfer Protocol).
In addition, it is possible to send data to the web server via the browser, to make the web server start a program to process these data on the server computer, and return the HTML-coded answer via the web server. The most common example for this kind of application must be a search that is entered on a search engine form. The rules, according to which browser, web server and the program, which the browser calls up from the web server, interact, are set out in the CGI interface definition. Theoretically, all programs can be executed through CGI, as long as they can be run on the server computer's operating system (the configuration of the web server regulates the details). A program in C, however, that has been compiled for UNIX will not run on a web server in a Windows environment.
In order to write so-called CGI programs we still use the programming language PERL from the UNIX world. It has several advantages: it is freely available (at no cost!) even for Windows platforms; is very powerful and has especially powerful string processing routines; but it is also a little unfamiliar. So why not stick to COMAL?
COMAL too, offers very powerful string processing and should therefore be well suited for CGI programming (in Windows systems only, of course). So the question arises what additional features a programming language ought to 'offer' in order to be suitable as a CGI programming language. CGI programs must be able to read the data passed from the browser, either through the environment variables set by the web server, or through the standard input (STDIN). The COMAL programmer has direct access to both. The selection of environment variables is done using the environment$ function of the SYSTEM module, e.g. dat$=environment$("QUERY_STRING"). The standard input can, for example, be read in through the command sequence:
| anzahl#:=environment$("CONTENT_LENGTH") OPEN FILE 1, "CON:", READ dat$:= GET$(1, anzahl#) CLOSE FILE 1 |
(anzahl# = number# - the number of items)
The only problem a CGI programmer encounters when using COMAL is the data output. CGI programs must return their own HTML-coded answer to the browser via the web server. For this, the program must write to the standard output STDOUT, which the web server redirects to itself. At the time, COMAL programmers decided, for extra speed, to implement the PRINT command so that it either writes directly to the screen memory or uses the BIOS functions to write to the screen, but did not use the standard output of the operating system DOS-Interrupt 21. Therefore the web server cannot divert to itself the PRINT output of a COMAL program.
There is, however, a simple solution to this problem: a small assembler module STDOUT that contains one single procedure: PROC printout(a$) that writes the string a$ via the DOS-Interrupt 21 to the standard output STDOUT. If you use the procedure printout() from the STDOUT module instead of COMAL's own PRINT command, the web server will be able to divert the output to itself and pass it to the searching browser.
This example illustrates the interaction between browser, web server and CGI program. The web server has a page called "kommentar.htm" in its "document" directory. This page contains a form into which the user can enter his/her name and a (hopefully favourable) comment on some firm's advert on the Web:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN"> <html> <head> <title>Kommentarseite</title> </head> <body bgcolor="#E0E0E0"> <h1>Ihr Kommentar</h1> <form action="/cgi-bin/comments.exe" method="post"> <p>Name:<br><input size="40" maxlength="40" name="AnwenderName"></p> <p>Text:<br><textarea rows="5" cols="50" name="Kommentartext"></textarea></p> <p><input type="submit" value="Absenden"></p> </form> </body> </html> |
(Kommentarseite = feedback page
Ihr Kommentar = your feedback
AnwenderName = user name
Kommentartext = text of feedback
Absenden = send)
In the opening <FORM> tag, the form contains the command action="/cgi-bin/comments.exe" method="post", instructing the web server to execute the compiled COMAL program "comments.exe" in the web server's directory "/cgi-bin/". The data for the program are transferred by the POST method, i.e. the program "comments.exe" must read the data from the standard input and the number of bytes are contained in the environment variable CONTENT_LENGTH.
| 0080 USE
system 0090 USE stdout 0100 0110 e$:=CHR$(13)+CHR$(10)+"$" // Endkennung fuer printout!! 0120 0130 DIM dat$ OF 1000 0190 getdata(dat$) 0200 0210 html_begin("comments.cml") 0220 eingabedaten_verarbeiten 0230 print_("<h1>Vielen Dank fr Ihren Kommentar</h1>") 0240 print_("<br>") 0250 print_("<p>Hier zur Kontrolle Ihre Eingaben:</p>") 0260 print_("<b>"+name1$+": </b>"+wert1$+"<br>") 0270 print_("<b>"+name2$+": </b>"+wert2$+"<br>") 0280 print_("<br>") 0290 print_("<i>"+DATE$+" "+TIME$+"</i><br>") 0300 print_("<i>"+environment$("SCRIPT_NAME")+"</i><br>") 0310 0320 html_end |
| 1520
PROC html_begin(title$) 1530 // printout schreibt auf STDOUT 1540 // e$ muss wg der Endkennung $ (DOS-Konvention) angehängt werden 1550 1560 print_("content-type: text/html") 1570 print_("") 1580 print_("<html>") 1590 print_("<head>") 1600 print_("<title>"+title$+"</title>") 1610 print_("</head>") 1620 print_("<body>") 1630 ENDPROC html_begin 1640 1650 PROC html_end 1660 print_("</body>") 1670 print_("</html>") 1680 ENDPROC html_end 1690 1700 PROC getdata(REF dat$) 1710 rm$:=environment$("REQUEST_METHOD") 1720 rm$:=UPPER$(rm$) 1730 CASE rm$ OF 1740 WHEN "POST" 1750 // Daten von Standardeingabe lesen 1760 ct$:=environment$("CONTENT_LENGTH") 1770 ct#:=VAL(ct$) 1780 OPEN FILE 1,"CON:",READ 1790 dat$:=GET$(1,ct#) 1800 CLOSE FILE 1 1810 WHEN "GET" 1820 dat$:=environment$("QUERY_STRING") 1830 OTHERWISE 1840 dat$:="Es wurden keine Daten Übergeben!" 1850 ENDCASE 1860 ENDPROC getdata 1870 1880 PROC print(a$) 1890 // printout schreibt per DOS-Interrupt auf STDOUT 1900 // DOS erwartet als Endkennung das $-Zeichen 1910 // alles vor dem $-Zeichen wird ausgegeben, daher 1920 // muss an den STRING a$ CHR$(13)+CHR$(10) als Endkennung 1930 // für einen COMAL-DOS-String und das $-Zeichen angefügt werden. 1940 e$:=CHR$(13)+CHR$(10)+"$" // Endkennung fuer printout!! 1950 printout(a$+e$) 1960 ENDPROC print_ |
(printout schreibt auf STDOUT = printout writes on STDOUT
e$ muss wg der Endkennung $ (DOS Konvention) angehängt werden = e$ must be added at the end
because of the DOS convention printout terminator character
Daten von Standardeingabe lesen = read data from standard input
Es wurden keine Daten übergeben = no data have been transferred
Printout schreibt per DOS_Interrupt auf STDOUT = printout writes via DOS_Interrupt on STDOUT
DOS erwartet als Endkennung das $-Zeichen = DOS expects the $ character as terminator
Alles vor dem $-Zeichen wird ausgegeben, daher muss an den STRING a$ CHR$ (13) + CHR$ (10)
das $-Zeichen angefügt werden = the output comprises everything before the $ character, therefore the $ character must be added to the STRING a$ CHR$ (13) + CHR$ (10) as terminator on a COMAL-DOS-String.)
The procedure "PROC getdata(REF dat$)" (line 1700) selects the contents of the environment variable "REQUEST_METHOD", set by the web server. This variable contains the data transfer method, set in the HTML document. All transferred data will then be located in the string "dat$", which of course has to be DIMensioned appropriately beforehand. "dat$" could for example have the following contents:
AnwenderName=Neuber&Kommentartext=Hallo+alter+Meister%0D%0AKlappt+es+nun+doch%3F%3F
(AnwenderName = user name
Kommentartext = text of comment
Hallo alter Meister = Hello, old master
Klappt es nun doch = Is it working after all?
The content of the text field entitled "AnwenderName" [user name] is "Neuber" and the content of the text field entitled Kommentartext [text of comment] is "Hallo" [hello]…. The COMAL program has to further process this data stream, i. e. it has to break it up it into its individual components and to revert the Url coding of the special characters. For this, the procedures "split" or "url_decode" are used:
1880 PROC eingabedaten_verarbeiten 1890 split(dat$,"&",links$,rechts$) 1900 split(links$,"=",name1$,wert1$) 1910 split(rechts$,"=",name2$,wert2$) 1920 url_decode(wert1$) 1930 url_decode(wert2$) 1940 ENDPROC eingabedaten_verarbeiten 0550 PROC split(a$,trenn$,REF b$,REF c$) 0560 // teilt den String a$ am Trennzeichen trenn$ auf 0570 // und speichert die beiden Teile in b$ und c$ 0580 0590 pos#:=trenn$ IN a$ 0600 IF pos# THEN 0610 b$:=a$(1:pos#-1) 0620 c$:=a$(pos#+1:) 0630 ENDIF 0640 ENDPROC split 0650 0850 PROC url_decode(REF a$) 0860 // Ersetzt URL-codierte Sonderzeichen 0870 // wie z.B. %0D=CHR$(13) und +=" " 0880 LOOP 0890 asc$:=3*" " 0900 pos#:="%" IN a$ 0910 EXIT WHEN pos#=0 0920 links$:=a$(1:pos#-1) 0930 asc$:=a$(pos#:pos#+2) 0940 rechts$:=a$(pos#+3:) 0950 asc$(:1:):="$" 0960 asc$:=CHR$(VAL(asc$)) 0970 a$:=links$+asc$+rechts$ 0980 ENDLOOP 0990 1000 LOOP 1010 pos#:="+" IN a$ 1020 EXIT WHEN pos#=0 1030 a$(:pos#:):=" " 1040 ENDLOOP 1050 ENDPROC url_decode |
(Eingabedaten verarbeiten = process input data
Links = left
Rechts = right
Teilt den String a$ am Trennzeichen trenn$ auf = separates the string a$ at the hyphenation mark trenn$
Und speichert die beiden Teile in b$ und c$ = and saves the two parts in b$ and c$
Ersetzt Url-codierte Sonderzeichen = replaces Url coded special characters
Wie z.B. = like for example
Und = and
Endkennung fuer printout = end-marker for "printout"
Vielen Dank für Ihren Kommentar = thank you for your comment
Hier zur Kontrolle Ihre Eingaben = please check your details)