diff options
author | Kristaps Dzonsons <kristaps@bsd.lv> | 2011-11-09 01:24:23 +0000 |
---|---|---|
committer | Kristaps Dzonsons <kristaps@bsd.lv> | 2011-11-09 01:24:23 +0000 |
commit | 6c38eff672364431564091cddb15592a2ca4a2a0 (patch) | |
tree | 5c6a04444298122b3b219585990a64a780d8a11f /cgi.c | |
parent | 7f5351a1e9d07e9a65c22430e56ff4c50c4a9bdf (diff) | |
download | mandoc-6c38eff672364431564091cddb15592a2ca4a2a0.tar.gz |
Split apropos.c into db.c and apropos.h with simpler code (re-written, but
inspired by apropos.c and mandoc-tools' mandoc-cgi.c). This uses UTF-8
right now for its re-writing, but will soon accomodate for the regular
suspects (this is a rather simple matter).
I also introduce man.cgi (cgi.c), which is a standalone CGI that replaces
mandoc-tools' mandoc.cgi. Right now it's just a framework.
Diffstat (limited to 'cgi.c')
-rw-r--r-- | cgi.c | 303 |
1 files changed, 303 insertions, 0 deletions
@@ -0,0 +1,303 @@ +/* $Id$ */ +#include <assert.h> +#include <fcntl.h> +#include <regex.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include "apropos.h" +#include "mandoc.h" + +/* + * The page a request is trying to make. + */ +enum page { + PAGE_INDEX, + PAGE_SEARCH, + PAGE__MAX +}; + +/* + * Key-value pair. + * Both key and val are on the heap. + */ +struct kval { + char *key; + char *val; +}; + +/* + * The media type, determined by suffix, of the requesting or responding + * context. + */ +enum media { + MEDIA_HTML, + MEDIA__MAX +}; + +/* + * An HTTP request. + */ +struct req { + struct kval *fields; /* query fields */ + size_t fieldsz; + enum media media; + enum page page; +}; + +static void html_printtext(const char *); +static int kval_decode(char *); +static void kval_parse(struct kval **, size_t *, char *); +static void kval_free(struct kval *, size_t); +static void pg_index(const struct req *, char *); +static void pg_search(const struct req *, char *); +static void pg_searchres(struct rec *, size_t, void *); + +static const char * const pages[PAGE__MAX] = { + "index", /* PAGE_INDEX */ + "search", /* PAGE_SEARCH */ +}; + +static const char * const medias[MEDIA__MAX] = { + "html", /* MEDIA_HTML */ +}; + +static void +html_printtext(const char *p) +{ + char c; + + while ('\0' != *p) + switch ((c = *p++)) { + case ('"'): + printf(""e;"); + break; + case ('&'): + printf("&"); + break; + case ('>'): + printf(">"); + break; + case ('<'): + printf("<"); + break; + default: + putchar((unsigned char)c); + break; + } +} + +static void +kval_free(struct kval *p, size_t sz) +{ + int i; + + for (i = 0; i < (int)sz; i++) { + free(p[i].key); + free(p[i].val); + } + free(p); +} + +/* + * Parse out key-value pairs from an HTTP request variable. + * This can be either a cookie or a POST/GET string. + */ +static void +kval_parse(struct kval **kv, size_t *kvsz, char *p) +{ + char *key, *val; + size_t sz, cur; + + cur = 0; + + while (p && '\0' != *p) { + while (' ' == *p) + p++; + + key = p; + val = NULL; + + if (NULL != (p = strchr(p, '='))) { + *p++ = '\0'; + val = p; + + sz = strcspn(p, ";&"); + /* LINTED */ + p += sz; + + if ('\0' != *p) + *p++ = '\0'; + } else { + p = key; + sz = strcspn(p, ";&"); + /* LINTED */ + p += sz; + + if ('\0' != *p) + p++; + continue; + } + + if ('\0' == *key || '\0' == *val) + continue; + + /* Just abort handling. */ + + if ( ! kval_decode(key)) + return; + if ( ! kval_decode(val)) + return; + + if (*kvsz + 1 >= cur) { + cur++; + *kv = mandoc_realloc + (*kv, cur * sizeof(struct kval)); + } + + (*kv)[(int)*kvsz].key = mandoc_strdup(key); + (*kv)[(int)*kvsz].val = mandoc_strdup(val); + (*kvsz)++; + } +} + +/* + * In-place HTTP-decode a string. The standard explanation is that this + * turns "%4e+foo" into "n foo" in the regular way. This is done + * in-place over the allocated string. + */ +static int +kval_decode(char *p) +{ + char hex[3]; + int c; + + hex[2] = '\0'; + + for ( ; '\0' != *p; p++) { + if ('%' == *p) { + if ('\0' == (hex[0] = *(p + 1))) + return(0); + if ('\0' == (hex[1] = *(p + 2))) + return(0); + if (1 != sscanf(hex, "%x", &c)) + return(0); + if ('\0' == c) + return(0); + + *p = (char)c; + memmove(p + 1, p + 3, strlen(p + 3) + 1); + } else + *p = '+' == *p ? ' ' : *p; + } + + *p = '\0'; + return(1); +} + + +/* ARGSUSED */ +static void +pg_index(const struct req *req, char *path) +{ + +} + +static void +pg_searchres(struct rec *recs, size_t sz, void *arg) +{ + int i; + const char *pg; + + if (NULL == (pg = getenv("SCRIPT_NAME"))) + pg = ""; + + for (i = 0; i < (int)sz; i++) { + printf("<A HREF=\"%s/show/%u.html\">", + pg, recs[i].rec); + html_printtext(recs[i].title); + putchar('('); + html_printtext(recs[i].cat); + puts(")</A>"); + } +} + +static void +pg_search(const struct req *req, char *path) +{ + int i; + struct opts opt; + + for (i = 0; i < (int)req->fieldsz; i++) + if (0 == strcmp(req->fields[i].key, "key")) + break; + + if (i == (int)req->fieldsz) + return; + + memset(&opt, 0, sizeof(struct opts)); + opt.types = TYPE_NAME | TYPE_DESC; + apropos_search(&opt, req->fields[i].val, NULL, pg_searchres); +} + +int +main(void) +{ + int i; + struct req req; + char *p; + char *path, *subpath, *suffix; + + memset(&req, 0, sizeof(struct req)); + + if (NULL != (p = getenv("QUERY_STRING"))) + kval_parse(&req.fields, &req.fieldsz, p); + + suffix = subpath = path = NULL; + + req.media = MEDIA_HTML; + req.page = PAGE__MAX; + + if (NULL == (path = getenv("PATH_INFO")) || '\0' == *path) + req.page = PAGE_INDEX; + if (NULL != path && '/' == *path && '\0' == *++path) + req.page = PAGE_INDEX; + + if (NULL != path && NULL != (suffix = strrchr(path, '.'))) + if (NULL != suffix && NULL == strchr(suffix, '/')) + *suffix++ = '\0'; + + if (NULL != path && NULL != (subpath = strchr(path, '/'))) + *subpath++ = '\0'; + + if (NULL != suffix && '\0' != *suffix) + for (i = 0; i < (int)MEDIA__MAX; i++) + if (0 == strcmp(medias[i], suffix)) { + req.media = (enum media)i; + break; + } + + if (NULL != path && '\0' != *path) + for (i = 0; i < (int)PAGE__MAX; i++) + if (0 == strcmp(pages[i], path)) { + req.page = (enum page)i; + break; + } + + switch (req.page) { + case (PAGE_INDEX): + pg_index(&req, subpath); + break; + case (PAGE_SEARCH): + pg_search(&req, subpath); + break; + default: + /* Blah */ + break; + } + + kval_free(req.fields, req.fieldsz); + return(EXIT_SUCCESS); +} |