GNU Info

Info Node: (gawkinet.info)Simple Server

(gawkinet.info)Simple Server


Next: Caveats Prev: Interacting Service Up: Using Networking
Enter node , (file) or (file)node

A Simple Web Server
===================

   In the preceding node, we built the core logic for event driven GUIs.
In this node, we finally extend the core to a real application.  No one
would actually write a commercial web server in `gawk', but it is
instructive to see that it is feasible in principle.

   The application is ELIZA, the famous program by Joseph Weizenbaum
that mimics the behavior of a professional psychotherapist when talking
to you.  Weizenbaum would certainly object to this description, but
this is part of the legend around ELIZA.  Take the site-independent
core logic and append the following code:

     function SetUpServer() {
       SetUpEliza()
       TopHeader = \
         "<HTML><title>An HTTP-based System with GAWK</title>\
         <HEAD><META HTTP-EQUIV=\"Content-Type\"\
         CONTENT=\"text/html; charset=iso-8859-1\"></HEAD>\
         <BODY BGCOLOR=\"#ffffff\" TEXT=\"#000000\"\
         LINK=\"#0000ff\" VLINK=\"#0000ff\"\
         ALINK=\"#0000ff\"> <A NAME=\"top\">"
       TopDoc    = "\
        <h2>Please choose one of the following actions:</h2>\
        <UL>\
        <LI>\
        <A HREF=" MyPrefix "/AboutServer>About this server</A>\
        </LI><LI>\
        <A HREF=" MyPrefix "/AboutELIZA>About Eliza</A></LI>\
        <LI>\
        <A HREF=" MyPrefix \
           "/StartELIZA>Start talking to Eliza</A></LI></UL>"
       TopFooter = "</BODY></HTML>"
     }

   `SetUpServer' is similar to the previous example, except for calling
another function, `SetUpEliza'.  This approach can be used to implement
other kinds of servers.  The only changes needed to do so are hidden in
the functions `SetUpServer' and `HandleGET'. Perhaps it might be
necessary to implement other HTTP methods.  The `igawk' program that
comes with `gawk' may be useful for this process.

   When extending this example to a complete application, the first
thing to do is to implement the function `SetUpServer' to initialize
the HTML pages and some variables. These initializations determine the
way your HTML pages look (colors, titles, menu items, etc.).

   The function `HandleGET' is a nested case selection that decides
which page the user wants to see next.  Each nesting level refers to a
menu level of the GUI. Each case implements a certain action of the
menu. On the deepest level of case selection, the handler essentially
knows what the user wants and stores the answer into the variable that
holds the HTML page contents:

     function HandleGET() {
       # A real HTTP server would treat some parts of the URI as a file name.
       # We take parts of the URI as menu choices and go on accordingly.
       if(MENU[2] == "AboutServer") {
         Document    = "This is not a CGI script.\
           This is an httpd, an HTML file, and a CGI script all \
           in one GAWK script. It needs no separate www-server, \
           no installation, and no root privileges.\
           <p>To run it, do this:</p><ul>\
           <li> start this script with \"gawk -f httpserver.awk\",</li>\
           <li> and on the same host let your www browser open location\
                \"http://localhost:8080\"</li>\
           </ul>\<p>\ Details of HTTP come from:</p><ul>\
                 <li>Hethmon:  Illustrated Guide to HTTP</p>\
                 <li>RFC 2068</li></ul><p>JK 14.9.1997</p>"
       } else if (MENU[2] == "AboutELIZA") {
         Document    = "This is an implementation of the famous ELIZA\
             program by Joseph Weizenbaum. It is written in GAWK and\
     /bin/sh: expad: command not found
       } else if (MENU[2] == "StartELIZA") {
         gsub(/\+/, " ", GETARG["YouSay"])
         # Here we also have to substitute coded special characters
         Document    = "<form method=GET>" \
           "<h3>" ElizaSays(GETARG["YouSay"]) "</h3>\
           <p><input type=text name=YouSay value=\"\" size=60>\
           <br><input type=submit value=\"Tell her about it\"></p></form>"
       }
     }

   Now we are down to the heart of ELIZA, so you can see how it works.
Initially the user does not say anything; then ELIZA resets its money
counter and asks the user to tell what comes to mind open heartedly.
The subsequent answers are converted to uppercase and stored for later
comparison. ELIZA presents the bill when being confronted with a
sentence that contains the phrase "shut up." Otherwise, it looks for
keywords in the sentence, conjugates the rest of the sentence, remembers
the keyword for later use, and finally selects an answer from the set of
possible answers:

     function ElizaSays(YouSay) {
       if (YouSay == "") {
         cost = 0
         answer = "HI, IM ELIZA, TELL ME YOUR PROBLEM"
       } else {
         q = toupper(YouSay)
         gsub("'", "", q)
         if(q == qold) {
           answer = "PLEASE DONT REPEAT YOURSELF !"
         } else {
           if (index(q, "SHUT UP") > 0) {
             answer = "WELL, PLEASE PAY YOUR BILL. ITS EXACTLY ... $"\
                      int(100*rand()+30+cost/100)
           } else {
             qold = q
             w = "-"                 # no keyword recognized yet
             for (i in k) {          # search for keywords
               if (index(q, i) > 0) {
                 w = i
                 break
               }
             }
             if (w == "-") {         # no keyword, take old subject
               w    = wold
               subj = subjold
             } else {                # find subject
               subj = substr(q, index(q, w) + length(w)+1)
               wold = w
               subjold = subj        #  remember keyword and subject
             }
             for (i in conj)
                gsub(i, conj[i], q)   # conjugation
             # from all answers to this keyword, select one randomly
             answer = r[indices[int(split(k[w], indices) * rand()) + 1]]
             # insert subject into answer
             gsub("_", subj, answer)
           }
         }
       }
       cost += length(answer) # for later payment : 1 cent per character
       return answer
     }

   In the long but simple function `SetUpEliza', you can see tables for
conjugation, keywords, and answers.(1) The associative array `k'
contains indices into the array of answers `r'. To choose an answer,
ELIZA just picks an index randomly:

     function SetUpEliza() {
       srand()
       wold = "-"
       subjold = " "
     
       # table for conjugation
       conj[" ARE "     ] = " AM "
       conj["WERE "     ] = "WAS "
       conj[" YOU "     ] = " I "
       conj["YOUR "     ] = "MY "
       conj[" IVE "     ] =\
       conj[" I HAVE "  ] = " YOU HAVE "
       conj[" YOUVE "   ] =\
       conj[" YOU HAVE "] = " I HAVE "
       conj[" IM "      ] =\
       conj[" I AM "    ] = " YOU ARE "
       conj[" YOURE "   ] =\
       conj[" YOU ARE " ] = " I AM "
     
       # table of all answers
       r[1]   = "DONT YOU BELIEVE THAT I CAN  _"
       r[2]   = "PERHAPS YOU WOULD LIKE TO BE ABLE TO _ ?"
       ...

       # table for looking up answers that
       # fit to a certain keyword
       k["CAN YOU"]      = "1 2 3"
       k["CAN I"]        = "4 5"
       k["YOU ARE"]      =\
       k["YOURE"]        = "6 7 8 9"
       ...

     }

   Some interesting remarks and details (including the original source
code of ELIZA) are found on Mark Humphrys' home page.  Yahoo!  also has
a page with a collection of ELIZA-like programs. Many of them are
written in Java, some of them disclosing the Java source code, and a
few even explain how to modify the Java source code.

   ---------- Footnotes ----------

   (1) The version shown here is abbreviated.  The full version comes
with the `gawk' distribution.


automatically generated by info2www version 1.2.2.9