############################################################################
#
# File: cgi.icn
#
# Subject: Procedures for writing CGI scripts
#
# Authors: Joe Van Meter, Clinton Jeffery, Federico Balbi,
# Kostas Oikonomou, and Wade Bowmer
#
# Date: October 27, 2005
# Revised: May 2007
#
############################################################################
#
# This library makes programming cgi programs easier by automatically
# checking for title and body procedures. There are other procedures
# that do some repetitive things for the programmer.
#
############################################################################
global cgi # table of input fields
global cgi_hexen # set in cgiReadParse()
#
# cgiEcho(file,args[]) - write a file to both HTML stdout and a regular
# text file, if one is present
#
procedure cgiEcho(f, args[])
push(args, f)
if type(f) == "file" then { # if we have a file
write ! args # write to it
pop(args) # and then discard it
}
put(args, "<br>") # write HTML
write ! args
end
#
# cgiInput(type, name, values) -
#
procedure cgiInput(ty,nam,va)
every is := !va do {
writes("[<input type=\"",ty,"\" name=\"",nam,"\" value=\"",is,"\"")
if is===va[1] then
writes(" checked")
write(">", is, "]")
}
end
#
# cgiSelect(name, values)
# this program with the name and value makes a select box
#
procedure cgiSelect(nam, va)
write("<select name=\"", nam, "\">")
every is := !va do {
writes("<option" )
if is==va[1] then writes(" selected")
write(">", is)
}
write("</select>")
end
#
# cgiXYCoord()
# This procedure is used with a ISMAP to figure out what the x and y coords
# and if they are between a certain boundry. It returns the value of the
# list that was entered.
#
record HMap(value,x1,y1,x2,y2)
procedure cgiXYCoord(hlst)
title := hlst[1]
getenv("QUERY_STRING") ? {
x := tab(find(","))
move(1)
y := tab(0)
}
every q := 2 to *hlst do {
if (hlst[q].x1 < x < hlst[q].x2) & (hlst[q].y1 < y < hlst[q].y2) then {
title := hlst[q].value
}
}
return title
end
procedure cgiMyURL()
return "http://" || getenv("SERVER_NAME") || getenv("SCRIPT_NAME")
end
procedure cgiMethGet()
if getenv("REQUEST_METHOD")==="GET" then return
# else fail
end
#
# cgiReadParse()
# This procedure gets input from either QUERY_STRING or stdin puts the
# values with their variable names and returns a table with references
# from the variables to their values
#
procedure cgiReadParse()
local html, it, line, r, k, data, c1, c2
initial {
cgi_hexen := &digits ++ 'ABCDEF'
}
html := [ ]
it := ""
cgi := table()
line := ""
ct := getenv("CONTENT_TYPE")
cl := getenv("CONTENT_LENGTH")
if match("multipart/form-data;", ct) then {
ct ? {
tab(find("boundary=") + 9)
boundary := "--" || tab(0)
}
content := reads(&input, cl)
content ? {
while tab(find(boundary)) do {
tab(find("\n")+1)
while match("Content-") do {
line := tab(find("\n"))
move(1)
line ? {
s := tab(many(&letters++'-')) | stop("bogons")
case s of {
"Content-Disposition": {
move(2)
if ="form-data; " then {
if ="name=" then {
move(1)
nam := tab(find("\""))
if tab(find("filename=")+9) then {
if match("\"") then {
move(1)
cgi["filename"] := tab(find("\""))
}
}
}
}
}
"Content-Type": {
}
default: cgiEcho("eh? ", line)
}
}
}
#if it didn't match "Content-" its not header any more, skip a line
tab(find("\n")+1)
# then grab rest
value := tab(find(boundary)) | stop("incomplete value")
if value[-1] == "\n" then value[-1] := ""
if value[-1] == "\r" then value[-1] := ""
if \nam then cgi[\nam] := value
if match(boundary || "--") then {
break
}
else if match(boundary) then { # no terminating --
next
}
}
}
}
else {
if cgiMethGet() then
line := getenv("QUERY_STRING")
else line := reads(&input, getenv("CONTENT_LENGTH"))
line ? {
while put(html, tab(find("&"))) do
tab(many('&'))
put(html, tab(0))
}
every r := 1 to *html do
html[r] := map(html[r], "+", " ")
every !html ? {
# does this really loop multiple times? If so, what are we
# throwing away?
while k := tab(find("=")) do
tab(many('='))
k := cgiFixHex(\k)
data := cgiFixHex(tab(0))
if member(cgi, k) then cgi[k] ||:= "," || data
else cgi[k] := data
}
}
return cgi
end
# Replaces any hex codes in the given string by their ascii character
# equivalents and returns the fixed string.
procedure cgiFixHex(s)
while s ?:=
((tab(find("%")) ||
(move(1) &
(c1 := tab(any(cgi_hexen))) & (c2 := tab(any(cgi_hexen))) &
cgiHexchar(c1,c2)
) || tab(0)
)
)
return s
end
#
# procedure cgiPrintVariables
# prints the variables with their value
#
procedure cgiPrintVariables(in)
write("<br>")
every X := key(in) do
write("<b>",X,"</b> is <i>",in[X],"</i><p>")
end
procedure cgiError(in)
if /in then
write("Error: Script ", cgiMyURL(), " encountered fatal error")
else {
write("Content-type: text/html\n\n")
write("<html><head><title>",in[1],"</title></head>\n")
every i := 2 to *in do
write("<p>", in[i], "</p>")
write("</body></html>\n")
}
end
procedure cgiHexval(c)
if any(&digits, c) then return integer(c)
if any('ABCDEF', c) then return ord(c) - ord("A") + 10
if any('abcdef', c) then return ord(c) - ord("a") + 10
end
procedure cgiHexchar(c1,c2)
return char(cgiHexval(c1) * 16 + cgiHexval(c2))
end
#
# procedure cgiColorToHex
# if a basic color is entered into the procedure the hex values
# is returned
#
procedure cgiColorToHex(s)
static ColorTbl
initial {
ColorTbl:=table(0)
ColorTbl["black"] := "000000"
ColorTbl["gray"] := "666666"
ColorTbl["white"] := "ffffff"
ColorTbl["pink"] := "ff0099"
ColorTbl["violet"]:= "ffccff"
ColorTbl["brown"] := "996633"
ColorTbl["red"] := "ff0000"
ColorTbl["orange"]:= "ff9900"
ColorTbl["yellow"]:= "ffff33"
ColorTbl["green"] := "339933"
ColorTbl["cyan"] := "ff66cc"
ColorTbl["blue"] := "0000ff"
ColorTbl["purple"]:= "990099"
ColorTbl["magenta"]:="cc0066"
}
if rv := ColorValue(s) then {
# unfinished; convert 16-bit decimal values into 8-bits/component hex
}
return ColorTbl[s]
end
#
# Procedure cgiPrePro
# This procedure goes through a file writes out
# either anything between ALL and the value that are passed into the
# procedure.
#
procedure cgiPrePro(filename,def)
AllFlag := 0
DefFlag := 0
all := "<!-- ALL"
look := "<!-- " || def
intext := open(filename)
while here:=read(intext) do {
if match(all,here) then {
if AllFlag = 1 then
AllFlag := 0
else {
here := read(intext)
AllFlag := 1
}
}
if match(look,here) then
if DefFlag = 1 then {
DefFlag := 0
}
else {
DefFlag := 1
here := read(intext)
}
if AllFlag = 1 then writes(here)
else if DefFlag = 1 then writes(here)
}
end
#
# cgiRemoteUser(): returns the reported Web user.
#
procedure cgiRemoteUser()
return getenv("REMOTE_USER")
end
#
# Procedure cgiRndImg
#
# if a list is passed into the procedure then an img is randomized
#
procedure cgiRndImg(GifList, AltText)
writes("<img src=\"",?GifList,"\"", " alt=\"",AltText,"\"", ">")
end
procedure cgiOptwindow(opts, args[])
if not getenv("DISPLAY") then {
/opts["D"] := getenv("REMOTE_ADDR") || ":0"
}
return optwindow ! push(args, opts)
end
#
# procedure main
#
# This procedure wraps the application's cgimain() inside a standard HTML
# document, with customizable title, head, and body attributes procedures.
# It reads the input for the application, placing results in variable "cgi".
#
procedure main(args)
local BB
write("Content-type: text/html\n\n")
if \cgicookies then
every c := !cgicookies(args) do {
if type(c) == "table" then {
write("Set-cookie: ", c["name"], "=", c["value"])
every attr := ! [ "expires", "path", "domain" ] do
if \c[attr] then writes("; " || attr || c[attr])
if \c["secure"] then writes("; secure")
}
else
write("Set-cookie: ", c)
write()
}
write()
write("<html>")
write("<head>")
if \cgititle then {
write("<title>")
write(cgititle(args))
write("</title>")
}
# This can write arbitrary stuff, e.g. JavaScript.
if \cgihead then cgihead(args)
write("</head>")
writes("<body")
if \cgiBBuilder then {
BB := cgiBBuilder(args)
writes(" background=\"",BB["background"],"\"")
writes(" bgcolor=\"",BB["bgcolor"],"\"")
writes(" text=\"",BB["text"],"\"")
writes(" link=\"",BB["link"],"\"")
writes(" vlink=\"",BB["vlink"],"\"")
writes(" bgproperties=\"",BB["bgproperties"],"\"")
}
write(">")
cgiReadParse()
cgimain(args)
write("</body>")
write("</html>")
end
This page produced by UniDoc on 2021/04/15 @ 23:59:45.