[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Oct 26 12:36:09 1995 
Subject:Re: Interfacing Poplog to the Web 
From:Steve Knight 
Volume-ID:951027.01 

Jocelyn asks:
> I'd be interesting in knowing of any work that's been done in
> connecting Poplog programs to World-Wide Web servers; I'm thinking of
> the Web as one method for delivering my teaching applications. At the
> moment, the methods for interaction, and the style in which results can
> be displayed, are rather limited, but things should improve as Java (or
> its competitors) become more widely available.

I'm posting this to pop-forum because I think it is of quite general
interest as far as I can tell.

Our work involves a WWW server "park".  We run a small LAN (about
10 machines) outside the corporate firewall which acts as host
for a variety of local businesses.  The interesting aspect for
Poploggers is that many of the scripts are implementing in
Pop11.

To do this efficiently, I created a compact Pop11 executable -
without X or VED - which I call poplite.  [To create one of your
own simply link with -noved and nox.]  I then "strip" the
resulting executable to create a 1Mb base.  This, although not
truly lightweight, is good enough for our purposes.

On top of this, we use a small saved image created by the script
which I enclose below.  The saved image is used to write Pop11
scripts.  So, if you wanted to implement the same functionality
as post-query, you would write a file that looks like this ...

    #/bin/csh -f
    source /usr/local/lib/poplog/preamble
    exec $popsys/poplite +script $0 $*

    pr( 'Content-type: text/html\r\n\r\n' );  ;;; MIME header + termination.

    npr( 'The following name/value pairs were submitted :-<P>' );
    npr( '<UL>' );
    lvars i;
    for i in cgi_names do
        nprintf( '<LI>%p = %p', [% i.dup.cgi_args %] );
    endfor;

Note that preamble is a trivial C-shell script for setting the
minimum of shell variable for Poplog to run.  For more details, 
read "http://www.avonibp.co.uk/office/scripts/pop/pop.html";.

People who are interested in working with me to make Poplog properly
integrated with the Internet and especially the WWW should drop me
a line.  I'm very keen on making Poplog a good alternative to Perl
for WWW hacking, for example, and making the PLUG Source Code Archive
available dynamically.

Steve Knight


#!/bin/csh -f
# Use this script to create the scripting saved image.

../poplite << 'EOT'

uses plug_archive

compile_mode :pop11 +strict;

section;

define global syntax $ ;
    sysPUSHQ( readitem() sys_>< nullstring );
    sysCALL -> pop_expr_inst;
    "systranslate" -> pop_expr_item;
enddefine;

define global incharline( r ); lvars procedure r;
    lconstant terminator = identfn(% termin %);
    procedure();
        lvars count = 0;
        repeat
            lvars c = r();
            if c == `\n` do
                consstring(count);
                quitloop
            elseif c == termin do
                if count == 0 then
                    termin
                else
                    ;;; Poplog guarantees that all end-of-files are
                    ;;; preceded by end-of-lines.  However, I do not wish
                    ;;; to rely on this undocumented fact & have put this
                    ;;; line in as protection.
                    consstring( count );
                    terminator -> r;
                endif;
                quitloop
            else
                c;
                count fi_+ 1 -> count;
            endif;
        endrepeat;
    endprocedure
enddefine;

global vars cgi_names = [];
global vars cgi_args =
    newproperty( [], 8, false, "perm" );

define lconstant cgi_escape( a, b ); lvars a, b;
    lconstant hx = '0123456789ABCDEF';
    lvars x = strmember( a, hx );
    lvars y = strmember( b, hx );
    unless x and y do
        npr( 'Invalid escape sequence sent by server' );
        nprintf( 'Found %%%c%c', [% a, b %] );
        fast_sysexit();
    endunless;
    ( x - 1 ) << 4 + ( y - 1 )
enddefine;

define lconstant cgi_oops();
    pr( 'Content-type: text/html\n\n' );
enddefine;

define lconstant bad_request();
    cgi_oops();
    npr( 'Sorry, we failed to receive your request correctly. ' );
    npr( 'If you try again you may be lucky. ' );
    fast_sysexit();
enddefine;

define lconstant readN( nbytes ); lvars nbytes;
    consstring(#|
        fast_repeat fi_check( nbytes, 0, false ) times
            lvars ch = charin();
            if ch == termin then
                bad_request()
            else
                ch
            endif
        endrepeat
    |#);
enddefine;

define lconstant cgi_parse( rptr ); lvars procedure rptr;
    {%
        lvars state = "key";
        lvars K = 0;
        repeat
            lvars ch = rptr();
        quitif( ch == termin );
            if ch == `%` then
                ;;; This is an escape sequence.
                lvars a = rptr();
                if a == termin then bad_request() endif;
                lvars b = rptr();
                if b == termin then bad_request() endif;
                cgi_escape( a, b );
                K fi_+ 1 -> K;
            elseif ch == `+` then
                K fi_+ 1 -> K;
                ` `
            elseif ch == `=` then
                consword( K );
                0 -> K;
                "value" -> state;
            elseif ch == `&` then
                consstring( K );
                0 -> K;
                "key" -> state;
            else
                K fi_+ 1 -> K;
                ch
            endif;
        endrepeat;
        if state == "value" then
            consstring( K );
        elseif state == "key" and K > 0 then
            lvars s = consstring( K );
            nprintf( 'Key (%p) without value', [ ^s ] );
            fast_sysexit();
        endif;
    %}
enddefine;

define lconstant cgi_tabulate( v ); lvars v;
    unless length( v ) mod 2 == 0 do
        npr( 'Incorrect format for arguments' );
        fast_sysexit();
    endunless;

    [%
        lvars i;
        fast_for i from 1 by 2 to length( v ) do
            lvars name = v( i );
            v(i+1) -> cgi_args( name );
            name;
        endfor;
    %] -> cgi_names;
enddefine;

define lconstant cgi_prepare();
    lvars m = $REQUEST_METHOD;
    if m = 'POST' then
        unless $CONTENT_TYPE = 'application/x-www-form-urlencoded' then
            cgi_oops();
            npr( 'This script can only be used to decode form results.' );
            fast_sysexit(1);
        endunless;
        lvars nbytes = strnumber( $CONTENT_LENGTH or nullstring );
        unless nbytes.isinteger do
            cgi_oops();
            npr( 'This server is incorrectly configured.' );
            npr( 'The $CONTENT_LENGTH environment variable is not set' );
            fast_sysexit();
        endunless;
        readN( nbytes )
    elseif m = 'GET' then
        $QUERY_STRING or nullstring
    else
        cgi_oops();
        npr( 'This script should be referenced with a METHOD of POST or GET.\n' );
        pr( 'If you don\'t understand this, see this ' );
        pr( '<A HREF="http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html";>forms overview</A>.\n' );
        fast_sysexit();
    endif.stringin.cgi_parse.cgi_tabulate
enddefine;

define lconstant cgi_compile( file ); lvars file;
    lvars chars = discin( file );
    lvars line;
    for line from_repeater incharline( chars ) do
        quitif( isstartstring( 'exec', line ) );
    endfor;
    chain( chars, pop11_compile );
enddefine;

define global cgi_startup();
    ;;; Set some global variables.
    fast_sysexit -> interrupt;
    false -> poplinewidth;
    false -> popmemlim;
    cgi_prepare();
    cgi_compile( poparglist.dest -> poparglist );
    fast_sysexit();
enddefine;


;;; Garbage collect as required.
sysgarbage();
sysgarbage();
if syssave( 'script.psv' ) then
    cgi_startup();
    fast_sysexit();
endif;

endsection;

'EOT'