There are three ways to use this server:
#! /home/setlorg/bin/setl
const max_n = 10 ** 5; -- maximum allowed n
if (m := getmap()) = om then stop; end if;
s := m.maxprime;
if (n := val s) /= om and n > 0 then
n := floor n;
n min:= max_n;
print('Content-type: text/html');
print();
print('<TITLE>The primes up to '+n+'</TITLE>');
#define cmput(x) print(#x,'=',x)
cmput({p in {2 .. n} | forall i in {2 .. floor sqrt p} | p mod i /= 0});
if n < val s then -- big number, or contains a fraction
print('<p>The SETL server extends its sincerest apologies for '+
'imposing the artificial limit of '+n+' when you asked '+
'so nicely for '+s+'.</p>');
end if;
else
print('Content-type: text/html');
print();
print('<TITLE>No can do</TITLE>');
print('Error - positive number required, but got '+pretty s+'.');
end if;
#include "web.setl"
#!/bin/sh
export PATH=~/bin:$PATH
# Limit size of created files to 1MB
ulimit -f 1024
# Limit data seg size, max memory size, and virtual memory to 10MB
ulimit -d 10240
ulimit -m 10240
ulimit -v 10240
# Limit total CPU time to 10 sec.
ulimit -t 10
# Limit max user processes to 10
ulimit -u 10
# Run the "server", a SETL program
setl -3 3<<'.' >/tmp/setl.stdout$$ 2>/tmp/setl.stderr$$
const wget_cmd = 'wget -O - ';
m := getmap();
m_source := m.setl_source ? '';
m_input := m.setl_input ? '';
m_url := m.setl_url ? '';
m_data := m.setl_data ? '';
-- Fetch source text of user program
if not blank m_url then
m_source := wget(m_url);
end if;
-- Compile it
if not blank m_source then
m_object := filter('setl -c 2>&1',m_source+'\n');
if m_object(1) /= '#' then
printa(stderr, rehigh amp m_object);
stop 1;
end if;
else
printa(stderr, 'No source (no sweat).');
stop;
end if;
-- Fetch data for the program
if not blank m_data then
m_input := wget(m_data);
end if;
-- Start example server, directing to stderr any output it may spew
system ('setl daytime-server.setl >&2 &');
-- Run the compiled user program
t := tmpnam();
putfile(t,m_object);
u := tmpnam();
m_output := filter('setl -t'+
' --restricted'+
' --maxmem=100M'+
' --allow-open=localhost:1313,socket'+
' --allow-open=setl.org:1313,socket'+
' '+t+' 2>'+u, m_input);
unlink(t);
-- Report its stdout output
print('<pre>');
print(amp m_output);
print('</pre>');
-- Report its stderr output
putc(stderr, rehigh amp getfile u);
unlink(u);
op blank(s);
return s('^ *$') = s;
end;
proc wget(url);
return filter("wget -q -O - '"+escape url+"'");
end;
op rehigh(s); -- change ANSI highlighting to HTML
[saved_magic, magic] := [magic, false];
gsub(s,'\033[1m','<b><i>');
gsub(s,'\033[0m','</i></b>');
gsub(s,'\a',''); -- get rid of BEL chars too
magic := saved_magic;
return s;
end op;
#include "web.setl"
#include "amp.setl"
.
# Report server output
echo 'Content-type: text/html'
echo ''
echo '<title>SETL Server output</title>'
if test -s /tmp/setl.stdout$$; then
echo '<h3>stdout</h3>'
# stdout output is expected to contain markup
cat /tmp/setl.stdout$$
fi
if test -s /tmp/setl.stderr$$; then
echo '<h3>stderr</h3>'
# stderr output is more likely to have been inadvertent
echo '<pre>'
cat /tmp/setl.stderr$$
echo '</pre>'
fi
# Remove scratch files
rm -f /tmp/setl.stdout$$ /tmp/setl.stderr$$
-- A one-shot server to return a line with the current time and date
-- (to the millisecond) and then return input lines in hex.
const ms = 10000; -- time limit for client to connect, else we quit
sd := open ('1313', 'server-socket'); -- listen on port 1313
if sd = om then stop 1; end if; -- exit(1) if (e.g.) port in use
[ready] := select([{sd}], ms); -- wait up to ms for client to connect
if sd notin ready then stop 2; end if; -- exit(2) on timeout
fd := accept (sd); -- accept client connection
printa (fd, fdate(tod)); -- send formatted date and time to client
while (line := getline fd) /= om loop -- get line from client
printa (fd, hex line); -- reply with line in hex form
end loop; -- exit on eof from client
-- Please #include me in SETL programs that read from forms.
proc getmap; -- decode form result into a SETL map
if getenv 'REQUEST_METHOD' notin {'GET','POST'} then
print('This script must be referenced with a METHOD of GET or POST.');
stop 1;
end if;
if getenv 'CONTENT_TYPE' /= 'application/x-www-form-urlencoded' then
print('This script can only be used to decode form results.');
stop 1;
end if;
n := val getenv 'CONTENT_LENGTH';
s := getn(stdin,n); -- raw data
[m, magic] := [magic, false]; -- suppress regexps
gsub(s,'+',' '); -- change plusses to blanks
r := {map_pair unescape x : x in split(s,'&')}; -- decode
magic := m; -- restore status of regexp use
return r; -- that's it!
end getmap;
op escape(x); -- convert certain characters to %HH (hex)
return +/[if c in '.:/#?&=,;~0123456789-_'+
'abcdefghijklmnopqrstuvwxyz'+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' then c
else '%' + hex c
end : c in x];
end escape;
op unescape(x); -- convert %HH hex escapes to normal chars
r := '';
while #x > 0 loop
if x(1) = '%' then
r +:= unhex x(2..3);
x(1..3) := '';
else
r +:= x(1);
x(1) := '';
end if;
end loop;
return r;
end unescape;
op map_pair(x); -- equiv. to split(x,'=') on just the first '='
s := break(x,'=');
return [s,x(2..1 max #x)];
end map_pair;
-- Useful transformation for text to be placed inside <pre>...</pre> op amp(s); -- expand some characters to &...; gsub(s,'&','\\&'); gsub(s,'<','\\<'); gsub(s,'>','\\>'); return s; end amp;
#!/bin/sh # Handy script to apply the "amp.setl" transformation on stdin setl ' putchar (amp getfile stdin); #include "amp.setl" '
dB bacon@cs.nyu.edu