ref: ad5a80bfb081dc954be03836cc65090e0f6c7e4f
dir: /appl/svc/httpd/imagemap.b/
implement imagemap;
include "sys.m";
sys : Sys;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "draw.m";
draw: Draw;
include "cache.m";
include "contents.m";
include "httpd.m";
Private_info: import Httpd;
OnlySearch, BadSearch, NotFound: import Httpd;
g : ref Private_info;
include "parser.m";
parser : Parser;
include "daytime.m";
daytime: Daytime;
include "string.m";
str : String;
imagemap : module
{
init: fn(g : ref Private_info, req: Httpd->Request);
};
Point : adt {
x,y : int;
};
me : string;
badmod(p: string)
{
sys->fprint(sys->fildes(2), "imagemap: cannot load %s: %r\n", p);
raise "fail:bad module";
}
init(k : ref Private_info, req: Httpd->Request)
{
dest, s : string;
sys = load Sys "$Sys";
draw = load Draw "$Draw";
daytime = load Daytime Daytime->PATH;
if(daytime == nil) badmod(Daytime->PATH);
parser = load Parser Parser->PATH;
if(parser == nil) badmod(Parser->PATH);
str = load String String->PATH;
if (str == nil) badmod(String->PATH);
me = "imagemap";
g=k;
bufio=g.bufio;
parser->init();
parser->httpheaders(g,req.version);
dest = translate(req.uri, req.search);
if(dest == nil){
if(req.version!= ""){
parser->okheaders(g);
g.bout.puts(sys->sprint("Date: %s\r\n", daytime->time()));
g.bout.puts("Content-type: text/html\r\n");
g.bout.puts("\r\n");
}
g.bout.puts("<head><title>Nothing Found</title></head><body>\n");
g.bout.puts("Nothing satisfying your search request could be found.\n</body>\n");
return;
}
g.bout.puts(sys->sprint("%s 301 Moved Permanently\r\n", g.version));
g.bout.puts(sys->sprint("Date: %s\r\n", daytime->time()));
g.bout.puts("Server: Charon\r\n");
g.bout.puts("MIME-version: 1.0\r\n");
g.bout.puts("Content-type: text/html\r\n");
(s,nil)=str->splitl(dest, ":");
if(s!=nil){
g.bout.puts(sys->sprint("URI: <%s>\r\n", parser->urlconv(dest)));
g.bout.puts(sys->sprint("Location: %s\r\n", parser->urlconv(dest)));
}else if(dest[0] == '/'){
g.bout.puts(sys->sprint("URI: <%s>\r\n",parser->urlconv(dest)));
g.bout.puts(sys->sprint("Location: http://%s%s\r\n", parser->urlconv(g.mydomain), parser->urlconv(dest)));
} else {
(req.uri,s) = str->splitr(req.uri, "/");
g.bout.puts(sys->sprint("URI: <%s/%s>\r\n", parser->urlconv(req.uri), parser->urlconv(dest)));
g.bout.puts(sys->sprint("Location: http://%s%s/%s\r\n", parser->urlconv(g.mydomain), parser->urlconv(req.uri), parser->urlconv(dest)));
}
g.bout.puts("\r\n");
g.bout.puts("<head><title>Object Moved</title></head>\r\n");
g.bout.puts("<body><h1>Object Moved</h1></body>\r\n");
if(dest[0] == '/')
g.bout.puts(sys->sprint("Your selection mapped to <a href=\"%s\"> here</a>.<p>\r\n", parser->urlconv(dest)));
else
g.bout.puts(sys->sprint("Your selection mapped to <a href=\"%s/%s\"> here</a>.<p>\r\n", parser->urlconv(req.uri), parser->urlconv(dest)));
}
translate(uri, search : string) : string
{
b : ref Iobuf;
p, c, q, start : Point;
close, d : real;
line, To, def, s : string;
ok, n, inside, r : int;
(pth,nil):=str->splitr(uri,"/");
# sys->print("pth is %s",pth);
if(search == nil)
parser->fail(g,OnlySearch, me);
(p, ok) = pt(search);
if(!ok)
parser->fail(g,BadSearch, me);
b = bufio->open(uri, bufio->OREAD);
if(b == nil){
sys->fprint(sys->fildes(2), "imagemap: cannot open %s: %r\n", uri);
parser->fail(g, NotFound, uri);
}
To = "";
def = "";
close = 0.;
while((line = b.gets('\n'))!=nil){
line=line[0:len line-1];
(s, line) = getfield(line);
if(s== "rect"){
(s, line) = getfield(line);
(q, ok) = pt(s);
if(!ok || q.x > p.x || q.y > p.y)
continue;
(s, line) = getfield(line);
(q, ok) = pt(s);
if(!ok || q.x < p.x || q.y < p.y)
continue;
(s, nil) = getfield(line);
return pth+s;
}else if(s== "circle"){
(s, line) = getfield(line);
(c, ok) = pt(s);
if(!ok)
continue;
(s, line) = getfield(line);
(r,nil) = str->toint(s,10);
(s, line) = getfield(line);
d = real (r * r);
if(d >= dist(p, c))
return pth+s;
}else if(s=="poly"){
(s, line) = getfield(line);
(start, ok) = pt(s);
if(!ok)
continue;
inside = 0;
c = start;
for(n = 1; ; n++){
(s, line) = getfield(line);
(q, ok) = pt(s);
if(!ok)
break;
inside = polytest(inside, p, c, q);
c = q;
}
inside = polytest(inside, p, c, start);
if(n >= 3 && inside)
return pth+s;
}else if(s== "point"){
(s, line) = getfield(line);
(q, ok) = pt(s);
if(!ok)
continue;
d = dist(p, q);
(s, line) = getfield(line);
if(d == 0.)
return pth+s;
if(close == 0. || d < close){
close = d;
To = s;
}
}else if(s == "default"){
(def, line) = getfield(line);
}
}
if(To == nil)
To = def;
return pth+To;
}
polytest(inside : int,p, b, a : Point) : int{
pa, ba : Point;
if(b.y>a.y){
pa=sub(p, a);
ba=sub(b, a);
}else{
pa=sub(p, b);
ba=sub(a, b);
}
if(0<=pa.y && pa.y<ba.y && pa.y*ba.x<=pa.x*ba.y)
inside = !inside;
return inside;
}
sub(p, q : Point) : Point {
return (Point)(p.x-q.x, p.y-q.y);
}
dist(p, q : Point) : real {
p.x -= q.x;
p.y -= q.y;
return real (p.x * p.x + p.y *p.y);
}
pt(s : string) : (Point, int) {
p : Point;
x, y : string;
if(s[0] == '(')
s=s[1:];
(s,nil)=str->splitl(s, ")");
p = Point(0, 0);
(x,y) = str->splitl(s, ",");
if(x == s)
return (p, 0);
(p.x,nil) = str->toint(x,10);
if(y==nil)
return (p, 0);
y=y[1:];
(p.y,nil) = str->toint(y, 10);
return (p, 1);
}
getfield(s : string) : (string,string) {
i:=0;
while(s[i] == '\t' || s[i] == ' ')
i++;
return str->splitl(s[i:],"\t ");
}