Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include "httpd.h"
#include "httpsrv.h"

typedef struct Point    Point;
typedef struct OkPoint  OkPoint;
typedef struct Strings  Strings;

struct Point 
{
        int     x;
        int     y;
};

struct OkPoint 
{
        Point   p;
        int     ok;
};

struct Strings
{
        char    *s1;
        char    *s2;
};

static  char *me;

int             polytest(int, Point, Point, Point);
Strings         getfield(char*);
OkPoint         pt(char*);
char*           translate(HConnect*, char*, char*);
Point           sub(Point, Point);
float           dist(Point, Point);

void
main(int argc, char **argv)
{
        HConnect *c;
        Hio *hout;
        char *dest;

        me = "imagemap";
        c = init(argc, argv);
        hout = &c->hout;
        if(hparseheaders(c, HSTIMEOUT) < 0)
                exits("failed");
        anonymous(c);

        if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0){
                hunallowed(c, "GET, HEAD");
                exits("unallowed");
        }
        if(c->head.expectother || c->head.expectcont){
                hfail(c, HExpectFail, nil);
                exits("failed");
        }
        dest = translate(c, c->req.uri, c->req.search);

        if(dest == nil){
                if(c->req.vermaj){
                        hokheaders(c);
                        hprint(hout, "Content-type: text/html\r\n");
                        hprint(hout, "\r\n");
                }
                hprint(hout, "<head><title>Nothing Found</title></head><body>\n");
                hprint(hout, "Nothing satisfying your search request could be found.\n</body>\n");
                hflush(hout);
                writelog(c, "Reply: 200 imagemap %ld %ld\n", hout->seek, hout->seek);
                exits(nil);
        }

        if(http11(c) && strcmp(c->req.meth, "POST") == 0)
                hredirected(c, "303 See Other", dest);
        else
                hredirected(c, "302 Found", dest);
        exits(nil);
}

char*
translate(HConnect *c, char *uri, char *search)
{
        Biobuf *b;
        Strings ss;
        OkPoint okp;
        Point p, cen, q, start;
        float close, d;
        char *line, *to, *def, *s, *dst;
        int n, inside, r, ncsa;

        if(search == nil){
                hfail(c, HNoData, me);
                exits("failed");
        }
        okp = pt(search);
        if(!okp.ok){
                hfail(c, HBadSearch, me);
                exits("failed");
        }
        p = okp.p;

        b = Bopen(uri, OREAD);
        if(b == nil){
                hfail(c, HNotFound, uri);
                exits("failed");
        }

        to = nil;
        def = nil;
        dst = nil;
        close = 0.;
        ncsa = 1;
        while(line = Brdline(b, '\n')){
                line[Blinelen(b)-1] = 0;

                ss = getfield(line);
                s = ss.s1;
                line = ss.s2;
                if(ncsa){
                        ss = getfield(line);
                        dst = ss.s1;
                        line = ss.s2;
                }
                if(strcmp(s, "#cern") == 0){
                        ncsa = 0;
                        continue;
                }
                if(strcmp(s, "rect") == 0){
                        ss = getfield(line);
                        s = ss.s1;
                        line = ss.s2;
                        okp = pt(s);
                        q = okp.p;
                        if(!okp.ok || q.x > p.x || q.y > p.y)
                                continue;
                        ss = getfield(line);
                        s = ss.s1;
                        line = ss.s2;
                        okp = pt(s);
                        q = okp.p;
                        if(!okp.ok || q.x < p.x || q.y < p.y)
                                continue;
                        if(!ncsa){
                                ss = getfield(line);
                                dst = ss.s1;
                        }
                        return dst;
                }else if(strcmp(s, "circle") == 0){
                        ss = getfield(line);
                        s = ss.s1;
                        line = ss.s2;
                        okp = pt(s);
                        cen = okp.p;
                        if(!okp.ok)
                                continue;
                        ss = getfield(line);
                        s = ss.s1;
                        line = ss.s2;
                        if(ncsa){
                                okp = pt(s);
                                if(!okp.ok)
                                        continue;
                                if(dist(okp.p, cen) >= dist(p, cen))
                                        return dst;
                        }else{
                                r = strtol(s, nil, 10);
                                ss = getfield(line);
                                dst = ss.s1;
                                d = (float)r * r;
                                if(d >= dist(p, cen))
                                        return dst;
                        }
                }else if(strcmp(s, "poly") == 0){
                        ss = getfield(line);
                        s = ss.s1;
                        line = ss.s2;
                        okp = pt(s);
                        start = okp.p;
                        if(!okp.ok)
                                continue;
                        inside = 0;
                        cen = start;
                        for(n = 1; ; n++){
                                ss = getfield(line);
                                s = ss.s1;
                                line = ss.s2;
                                okp = pt(s);
                                q = okp.p;
                                if(!okp.ok)
                                        break;
                                inside = polytest(inside, p, cen, q);
                                cen = q;
                        }
                        inside = polytest(inside, p, cen, start);
                        if(!ncsa)
                                dst = s;
                        if(n >= 3 && inside)
                                return dst;
                }else if(strcmp(s, "point") == 0){
                        ss = getfield(line);
                        s = ss.s1;
                        line = ss.s2;
                        okp = pt(s);
                        q = okp.p;
                        if(!okp.ok)
                                continue;
                        d = dist(p, q);
                        if(!ncsa){
                                ss = getfield(line);
                                dst = ss.s1;
                        }
                        if(d == 0.)
                                return dst;
                        if(close == 0. || d < close){
                                close = d;
                                to = dst;
                        }
                }else if(strcmp(s, "default") == 0){
                        if(!ncsa){
                                ss = getfield(line);
                                dst = ss.s1;
                        }
                        def = dst;
                }
        }
        if(to == nil)
                to = def;
        return to;
}

int
polytest(int inside, Point p, Point b, Point a)
{
        Point pa, ba;

        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;
}

Point
sub(Point p, Point q)
{
        p.x -= q.x;
        p.y -= q.y;
        return p;
}

float
dist(Point p, Point q)
{
        p.x -= q.x;
        p.y -= q.y;
        return (float)p.x * p.x + (float)p.y * p.y;
}

OkPoint
pt(char *s)
{
        OkPoint okp;
        Point p;
        char *t, *e;

        if(*s == '(')
                s++;
        t = strchr(s, ')');
        if(t != nil)
                *t = 0;
        p.x = 0;
        p.y = 0;
        t = strchr(s, ',');
        if(t == nil){
                okp.p = p;
                okp.ok = 0;
                return okp;
        }
        e = nil;
        p.x = strtol(s, &e, 10);
        if(e != t){
                okp.p = p;
                okp.ok = 0;
                return okp;
        }
        p.y = strtol(t+1, &e, 10);
        if(e == nil || *e != 0){
                okp.p = p;
                okp.ok = 0;
                return okp;
        }
        okp.p = p;
        okp.ok = 1;
        return okp;
}

Strings
getfield(char *s)
{
        Strings ss;
        char *f;

        while(*s == '\t' || *s == ' ')
                s++;
        f = s;
        while(*s && *s != '\t' && *s != ' ')
                s++;
        if(*s)
                *s++ = 0;
        ss.s1 = f;
        ss.s2 = s;
        return ss;
}