gawkinet: Simple Server
1
1 2.10 A Simple Web Server
1 ========================
1
1 In the preceding node, we built the core logic for event-driven GUIs.
1 In this node, we finally extend the core to a real application. No one
1 would actually write a commercial web server in 'gawk', but it is
1 instructive to see that it is feasible in principle.
1
1 The application is ELIZA, the famous program by Joseph Weizenbaum
1 that mimics the behavior of a professional psychotherapist when talking
1 to you. Weizenbaum would certainly object to this description, but this
1 is part of the legend around ELIZA. Take the site-independent core logic
1 and append the following code:
1
1 function SetUpServer() {
1 SetUpEliza()
1 TopHeader = \
1 "<HTML><title>An HTTP-based System with GAWK</title>\
1 <HEAD><META HTTP-EQUIV=\"Content-Type\"\
1 CONTENT=\"text/html; charset=iso-8859-1\"></HEAD>\
1 <BODY BGCOLOR=\"#ffffff\" TEXT=\"#000000\"\
1 LINK=\"#0000ff\" VLINK=\"#0000ff\"\
1 ALINK=\"#0000ff\"> <A NAME=\"top\">"
1 TopDoc = "\
1 <h2>Please choose one of the following actions:</h2>\
1 <UL>\
1 <LI>\
1 <A HREF=" MyPrefix "/AboutServer>About this server</A>\
1 </LI><LI>\
1 <A HREF=" MyPrefix "/AboutELIZA>About Eliza</A></LI>\
1 <LI>\
1 <A HREF=" MyPrefix \
1 "/StartELIZA>Start talking to Eliza</A></LI></UL>"
1 TopFooter = "</BODY></HTML>"
1 }
1
1 'SetUpServer()' is similar to the previous example, except for
1 calling another function, 'SetUpEliza()'. This approach can be used to
1 implement other kinds of servers. The only changes needed to do so are
1 hidden in the functions 'SetUpServer()' and 'HandleGET()'. Perhaps it
1 might be necessary to implement other HTTP methods. The 'igawk' program
1 that comes with 'gawk' may be useful for this process.
1
1 When extending this example to a complete application, the first
1 thing to do is to implement the function 'SetUpServer()' to initialize
1 the HTML pages and some variables. These initializations determine the
1 way your HTML pages look (colors, titles, menu items, etc.).
1
1 The function 'HandleGET()' is a nested case selection that decides
1 which page the user wants to see next. Each nesting level refers to a
1 menu level of the GUI. Each case implements a certain action of the
1 menu. On the deepest level of case selection, the handler essentially
1 knows what the user wants and stores the answer into the variable that
1 holds the HTML page contents:
1
1 function HandleGET() {
1 # A real HTTP server would treat some parts of the URI as a file name.
1 # We take parts of the URI as menu choices and go on accordingly.
1 if(MENU[2] == "AboutServer") {
1 Document = "This is not a CGI script.\
1 This is an httpd, an HTML file, and a CGI script all \
1 in one GAWK script. It needs no separate www-server, \
1 no installation, and no root privileges.\
1 <p>To run it, do this:</p><ul>\
1 <li> start this script with \"gawk -f httpserver.awk\",</li>\
1 <li> and on the same host let your www browser open location\
1 \"http://localhost:8080\"</li>\
1 </ul>\<p>\ Details of HTTP come from:</p><ul>\
1 <li>Hethmon: Illustrated Guide to HTTP</p>\
1 <li>RFC 2068</li></ul><p>JK 14.9.1997</p>"
1 } else if (MENU[2] == "AboutELIZA") {
1 Document = "This is an implementation of the famous ELIZA\
1 program by Joseph Weizenbaum. It is written in GAWK and\
1 uses an HTML GUI."
1 } else if (MENU[2] == "StartELIZA") {
1 gsub(/\+/, " ", GETARG["YouSay"])
1 # Here we also have to substitute coded special characters
1 Document = "<form method=GET>" \
1 "<h3>" ElizaSays(GETARG["YouSay"]) "</h3>\
1 <p><input type=text name=YouSay value=\"\" size=60>\
1 <br><input type=submit value=\"Tell her about it\"></p></form>"
1 }
1 }
1
1 Now we are down to the heart of ELIZA, so you can see how it works.
1 Initially the user does not say anything; then ELIZA resets its money
1 counter and asks the user to tell what comes to mind open heartedly.
1 The subsequent answers are converted to uppercase characters and stored
1 for later comparison. ELIZA presents the bill when being confronted
1 with a sentence that contains the phrase "shut up." Otherwise, it looks
1 for keywords in the sentence, conjugates the rest of the sentence,
1 remembers the keyword for later use, and finally selects an answer from
1 the set of possible answers:
1
1 function ElizaSays(YouSay) {
1 if (YouSay == "") {
1 cost = 0
1 answer = "HI, IM ELIZA, TELL ME YOUR PROBLEM"
1 } else {
1 q = toupper(YouSay)
1 gsub("'", "", q)
1 if(q == qold) {
1 answer = "PLEASE DONT REPEAT YOURSELF !"
1 } else {
1 if (index(q, "SHUT UP") > 0) {
1 answer = "WELL, PLEASE PAY YOUR BILL. ITS EXACTLY ... $"\
1 int(100*rand()+30+cost/100)
1 } else {
1 qold = q
1 w = "-" # no keyword recognized yet
1 for (i in k) { # search for keywords
1 if (index(q, i) > 0) {
1 w = i
1 break
1 }
1 }
1 if (w == "-") { # no keyword, take old subject
1 w = wold
1 subj = subjold
1 } else { # find subject
1 subj = substr(q, index(q, w) + length(w)+1)
1 wold = w
1 subjold = subj # remember keyword and subject
1 }
1 for (i in conj)
1 gsub(i, conj[i], q) # conjugation
1 # from all answers to this keyword, select one randomly
1 answer = r[indices[int(split(k[w], indices) * rand()) + 1]]
1 # insert subject into answer
1 gsub("_", subj, answer)
1 }
1 }
1 }
1 cost += length(answer) # for later payment : 1 cent per character
1 return answer
1 }
1
1 In the long but simple function 'SetUpEliza()', you can see tables
1 for conjugation, keywords, and answers.(1) The associative array 'k'
1 contains indices into the array of answers 'r'. To choose an answer,
1 ELIZA just picks an index randomly:
1
1 function SetUpEliza() {
1 srand()
1 wold = "-"
1 subjold = " "
1
1 # table for conjugation
1 conj[" ARE " ] = " AM "
1 conj["WERE " ] = "WAS "
1 conj[" YOU " ] = " I "
1 conj["YOUR " ] = "MY "
1 conj[" IVE " ] =\
1 conj[" I HAVE " ] = " YOU HAVE "
1 conj[" YOUVE " ] =\
1 conj[" YOU HAVE "] = " I HAVE "
1 conj[" IM " ] =\
1 conj[" I AM " ] = " YOU ARE "
1 conj[" YOURE " ] =\
1 conj[" YOU ARE " ] = " I AM "
1
1 # table of all answers
1 r[1] = "DONT YOU BELIEVE THAT I CAN _"
1 r[2] = "PERHAPS YOU WOULD LIKE TO BE ABLE TO _ ?"
1 ...
1
1 # table for looking up answers that
1 # fit to a certain keyword
1 k["CAN YOU"] = "1 2 3"
1 k["CAN I"] = "4 5"
1 k["YOU ARE"] =\
1 k["YOURE"] = "6 7 8 9"
1 ...
1 }
1
1 Some interesting remarks and details (including the original source
1 code of ELIZA) are found on Mark Humphrys' home page. Yahoo! also has
1 a page with a collection of ELIZA-like programs. Many of them are
1 written in Java, some of them disclosing the Java source code, and a few
1 even explain how to modify the Java source code.
1
1 ---------- Footnotes ----------
1
1 (1) The version shown here is abbreviated. The full version comes
1 with the 'gawk' distribution.
1