summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2006-08-09 13:01:38 +0000
committerDimitri Sokolyuk <demon@dim13.org>2006-08-09 13:01:38 +0000
commite7803f7520bd591c37557ffd853dd40541854357 (patch)
tree36274a7799df7ea2805dbda7e9c20beefb773612
parent4df8b4b8a702768352cc1df07d00f975a98bb0bd (diff)
Maple Worksheet repository CGI frontend
-rw-r--r--math/Makefile13
-rw-r--r--math/Makefile.inc12
-rw-r--r--math/crc.c103
-rw-r--r--math/crc.h26
-rw-r--r--math/math.c497
-rw-r--r--math/math.css161
-rw-r--r--math/math/Makefile7
-rw-r--r--math/metadb.c581
-rw-r--r--math/metadb.h68
-rw-r--r--math/mkdb.c130
-rw-r--r--math/mkdb/Makefile7
-rw-r--r--math/query.c81
-rw-r--r--math/query.h27
-rw-r--r--math/readmeta.c158
14 files changed, 1871 insertions, 0 deletions
diff --git a/math/Makefile b/math/Makefile
new file mode 100644
index 0000000..9278b34
--- /dev/null
+++ b/math/Makefile
@@ -0,0 +1,13 @@
+# $Id$
+
+.include "Makefile.inc"
+
+.include <bsd.own.mk>
+
+SUBDIR= mkdb math
+
+beforeinstall:
+ ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 \
+ math.css ${BINDIR}/..
+
+.include <bsd.subdir.mk>
diff --git a/math/Makefile.inc b/math/Makefile.inc
new file mode 100644
index 0000000..a4d6c59
--- /dev/null
+++ b/math/Makefile.inc
@@ -0,0 +1,12 @@
+# $Id$
+
+.PATH: ${.CURDIR}/..
+CFLAGS+= -I${.CURDIR}/..
+
+WARNINGS= yes
+
+CDIAGFLAGS+= -Wall -Wpointer-arith \
+ -Wstrict-prototypes -Wmissing-prototypes \
+ -ggdb
+
+BINDIR= /var/www/htdocs/cgi-bin
diff --git a/math/crc.c b/math/crc.c
new file mode 100644
index 0000000..9af785b
--- /dev/null
+++ b/math/crc.c
@@ -0,0 +1,103 @@
+/* $Id$ */
+/* $OpenBSD: crc.c,v 1.2 2004/05/10 19:48:07 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include "crc.h"
+
+/*
+ * Table-driven version of the following polynomial from POSIX 1003.2:
+ * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 +
+ * x^7 + x^5 + x^4 + x^2 + x + 1
+ */
+static const u_int32_t crc32tab[] = {
+ 0x00000000U,
+ 0x04c11db7U, 0x09823b6eU, 0x0d4326d9U, 0x130476dcU, 0x17c56b6bU,
+ 0x1a864db2U, 0x1e475005U, 0x2608edb8U, 0x22c9f00fU, 0x2f8ad6d6U,
+ 0x2b4bcb61U, 0x350c9b64U, 0x31cd86d3U, 0x3c8ea00aU, 0x384fbdbdU,
+ 0x4c11db70U, 0x48d0c6c7U, 0x4593e01eU, 0x4152fda9U, 0x5f15adacU,
+ 0x5bd4b01bU, 0x569796c2U, 0x52568b75U, 0x6a1936c8U, 0x6ed82b7fU,
+ 0x639b0da6U, 0x675a1011U, 0x791d4014U, 0x7ddc5da3U, 0x709f7b7aU,
+ 0x745e66cdU, 0x9823b6e0U, 0x9ce2ab57U, 0x91a18d8eU, 0x95609039U,
+ 0x8b27c03cU, 0x8fe6dd8bU, 0x82a5fb52U, 0x8664e6e5U, 0xbe2b5b58U,
+ 0xbaea46efU, 0xb7a96036U, 0xb3687d81U, 0xad2f2d84U, 0xa9ee3033U,
+ 0xa4ad16eaU, 0xa06c0b5dU, 0xd4326d90U, 0xd0f37027U, 0xddb056feU,
+ 0xd9714b49U, 0xc7361b4cU, 0xc3f706fbU, 0xceb42022U, 0xca753d95U,
+ 0xf23a8028U, 0xf6fb9d9fU, 0xfbb8bb46U, 0xff79a6f1U, 0xe13ef6f4U,
+ 0xe5ffeb43U, 0xe8bccd9aU, 0xec7dd02dU, 0x34867077U, 0x30476dc0U,
+ 0x3d044b19U, 0x39c556aeU, 0x278206abU, 0x23431b1cU, 0x2e003dc5U,
+ 0x2ac12072U, 0x128e9dcfU, 0x164f8078U, 0x1b0ca6a1U, 0x1fcdbb16U,
+ 0x018aeb13U, 0x054bf6a4U, 0x0808d07dU, 0x0cc9cdcaU, 0x7897ab07U,
+ 0x7c56b6b0U, 0x71159069U, 0x75d48ddeU, 0x6b93dddbU, 0x6f52c06cU,
+ 0x6211e6b5U, 0x66d0fb02U, 0x5e9f46bfU, 0x5a5e5b08U, 0x571d7dd1U,
+ 0x53dc6066U, 0x4d9b3063U, 0x495a2dd4U, 0x44190b0dU, 0x40d816baU,
+ 0xaca5c697U, 0xa864db20U, 0xa527fdf9U, 0xa1e6e04eU, 0xbfa1b04bU,
+ 0xbb60adfcU, 0xb6238b25U, 0xb2e29692U, 0x8aad2b2fU, 0x8e6c3698U,
+ 0x832f1041U, 0x87ee0df6U, 0x99a95df3U, 0x9d684044U, 0x902b669dU,
+ 0x94ea7b2aU, 0xe0b41de7U, 0xe4750050U, 0xe9362689U, 0xedf73b3eU,
+ 0xf3b06b3bU, 0xf771768cU, 0xfa325055U, 0xfef34de2U, 0xc6bcf05fU,
+ 0xc27dede8U, 0xcf3ecb31U, 0xcbffd686U, 0xd5b88683U, 0xd1799b34U,
+ 0xdc3abdedU, 0xd8fba05aU, 0x690ce0eeU, 0x6dcdfd59U, 0x608edb80U,
+ 0x644fc637U, 0x7a089632U, 0x7ec98b85U, 0x738aad5cU, 0x774bb0ebU,
+ 0x4f040d56U, 0x4bc510e1U, 0x46863638U, 0x42472b8fU, 0x5c007b8aU,
+ 0x58c1663dU, 0x558240e4U, 0x51435d53U, 0x251d3b9eU, 0x21dc2629U,
+ 0x2c9f00f0U, 0x285e1d47U, 0x36194d42U, 0x32d850f5U, 0x3f9b762cU,
+ 0x3b5a6b9bU, 0x0315d626U, 0x07d4cb91U, 0x0a97ed48U, 0x0e56f0ffU,
+ 0x1011a0faU, 0x14d0bd4dU, 0x19939b94U, 0x1d528623U, 0xf12f560eU,
+ 0xf5ee4bb9U, 0xf8ad6d60U, 0xfc6c70d7U, 0xe22b20d2U, 0xe6ea3d65U,
+ 0xeba91bbcU, 0xef68060bU, 0xd727bbb6U, 0xd3e6a601U, 0xdea580d8U,
+ 0xda649d6fU, 0xc423cd6aU, 0xc0e2d0ddU, 0xcda1f604U, 0xc960ebb3U,
+ 0xbd3e8d7eU, 0xb9ff90c9U, 0xb4bcb610U, 0xb07daba7U, 0xae3afba2U,
+ 0xaafbe615U, 0xa7b8c0ccU, 0xa379dd7bU, 0x9b3660c6U, 0x9ff77d71U,
+ 0x92b45ba8U, 0x9675461fU, 0x8832161aU, 0x8cf30badU, 0x81b02d74U,
+ 0x857130c3U, 0x5d8a9099U, 0x594b8d2eU, 0x5408abf7U, 0x50c9b640U,
+ 0x4e8ee645U, 0x4a4ffbf2U, 0x470cdd2bU, 0x43cdc09cU, 0x7b827d21U,
+ 0x7f436096U, 0x7200464fU, 0x76c15bf8U, 0x68860bfdU, 0x6c47164aU,
+ 0x61043093U, 0x65c52d24U, 0x119b4be9U, 0x155a565eU, 0x18197087U,
+ 0x1cd86d30U, 0x029f3d35U, 0x065e2082U, 0x0b1d065bU, 0x0fdc1becU,
+ 0x3793a651U, 0x3352bbe6U, 0x3e119d3fU, 0x3ad08088U, 0x2497d08dU,
+ 0x2056cd3aU, 0x2d15ebe3U, 0x29d4f654U, 0xc5a92679U, 0xc1683bceU,
+ 0xcc2b1d17U, 0xc8ea00a0U, 0xd6ad50a5U, 0xd26c4d12U, 0xdf2f6bcbU,
+ 0xdbee767cU, 0xe3a1cbc1U, 0xe760d676U, 0xea23f0afU, 0xeee2ed18U,
+ 0xf0a5bd1dU, 0xf464a0aaU, 0xf9278673U, 0xfde69bc4U, 0x89b8fd09U,
+ 0x8d79e0beU, 0x803ac667U, 0x84fbdbd0U, 0x9abc8bd5U, 0x9e7d9662U,
+ 0x933eb0bbU, 0x97ffad0cU, 0xafb010b1U, 0xab710d06U, 0xa6322bdfU,
+ 0xa2f33668U, 0xbcb4666dU, 0xb8757bdaU, 0xb5365d03U, 0xb1f740b4U
+};
+
+#define UPDATE(crc, byte) do \
+ (crc) = ((crc) << 8) ^ crc32tab[((crc) >> 24) ^ (byte)]; \
+while(0)
+
+u_int32_t
+crc32(unsigned char *buf, size_t len)
+{
+ u_int32_t crc = 0;
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ UPDATE(crc, buf[i]);
+
+ while (len != 0) {
+ UPDATE(crc, len & 0xff);
+ len >>= 8;
+ }
+
+ return ~crc;
+}
diff --git a/math/crc.h b/math/crc.h
new file mode 100644
index 0000000..9738c47
--- /dev/null
+++ b/math/crc.h
@@ -0,0 +1,26 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _CRC_H_
+#define _CRC_H_
+
+__BEGIN_DECLS
+u_int32_t crc32(unsigned char *, size_t);
+__END_DECLS
+
+#endif /* not _CRC_H_ */
diff --git a/math/math.c b/math/math.c
new file mode 100644
index 0000000..0f00140
--- /dev/null
+++ b/math/math.c
@@ -0,0 +1,497 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if 0
+#include <sys/time.h> /* gettimeofday() */
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "metadb.h"
+#include "query.h"
+
+#define SHOWNEW 5
+enum jflag { J_HTML, J_PDF, J_MWS, J_MW, J_CODE, J_EMAIL, J_IMG, J_NONE };
+char *sname;
+char *datadir = "data";
+
+void pr_head(struct meta *);
+void pr_foot(void);
+void pr_path(struct meta *, size_t);
+void pr_set(struct meta *, size_t);
+void pr_opts(struct meta *);
+char *pr_lang(char *);
+void pr_record(struct meta *, size_t, enum sorder);
+void pr_new(size_t);
+int have(struct meta *, size_t, enum mtype);
+__dead void jmp(struct meta *, size_t, enum jflag);
+__dead void mailto(unsigned int);
+
+void
+pr_head(struct meta *mp)
+{
+ puts("<html>");
+ puts("<head>");
+ printf("<title>%s</title>\n", mp->title);
+ puts("<link rel=\"stylesheet\" type=\"text/css\" href=\"/math.css\" />");
+ puts("</head>");
+ puts("<body>");
+
+ puts("<div class=\"head\">");
+#if 0
+ printf("<h1><a href=\"%s?id=%u\">%s</a></h1>\n", sname, mp->id, mp->title);
+#else
+ printf("<h1>%s</h1>\n", mp->title);
+#endif
+
+ printf("<form method=\"get\" action=\"%s\">\n", sname);
+ puts("Search: <input type=\"text\" name=\"search\" size=\"14\" maxlength=\"64\" />");
+ puts("<input class=\"submit\" type=\"submit\" value=\"Go!\" />");
+ puts("</form>");
+ puts("</div>");
+}
+
+void
+pr_foot(void)
+{
+ puts("<div class=\"foot\">");
+ puts("<p>Copyright &copy; 2006 <a href=\"http://www.vhost.dyndns.org/\">Dimitri A. Sokolyuk</a>");
+ puts("Worksheets are copyright their respective authors,");
+ puts("submission implies license to publish on this web site.");
+ puts("This size runs as CGI on <a href=\"http://www.openbsd.org/\">OpenBSD</a>,");
+ puts("the <a href=\"http://math.vhost.dyndns.org/math-src.tar.gz\">source code</a>");
+ puts("is <a href=\"http://www.opensource.org/licenses/mit-license.php\">MIT licensed</a>.</p>");
+
+#if 0
+ puts("<p>");
+#if 0
+ puts("<a href=\"http://www.catb.org/hacker-emblem/\">");
+ puts("<img src=\"http://www.catb.org/hacker-emblem/glider-small.png\" alt=\"hacker emblem\" /></a>");
+
+ puts("<a href=\"http://www.openbsd.org/\">");
+ puts("<img src=\"/images/openbsd_pb.gif\" alt=\"Powered by OpenBSD\" /></a>");
+
+ puts("<a href=\"http://www.bostic.com/vi/\">");
+ puts("<img src=\"/images/vipower.gif\" alt=\"vi powered\" /></a>");
+#endif
+ puts("<a href=\"http://jigsaw.w3.org/css-validator/check/referer\">");
+ puts("<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\"");
+ puts("alt=\"Valid CSS!\" /></a>");
+
+ puts("<a href=\"http://validator.w3.org/check?uri=referer\">");
+ puts("<img src=\"http://www.w3.org/Icons/valid-xhtml10\"");
+ puts("alt=\"Valid XHTML 1.0 Transitional\" /></a>");
+
+ puts("</p>");
+#endif
+
+ puts("</div>");
+ puts("</body>");
+ puts("</html>");
+}
+
+void
+pr_path(struct meta *mp, size_t n)
+{
+ puts("<div class=\"path\">");
+ for (; n--; ++mp) {
+ if (mp->id != 0)
+ puts(" &middot;");
+ printf("<a href=\"%s?id=%u\">%s</a>", sname, mp->id, mp->title);
+ }
+ puts("</div>");
+}
+
+void
+pr_set(struct meta *mp, size_t n)
+{
+ for (; n--; ++mp) {
+ if (mp->type == M_SET) {
+ printf("<h3><a href=\"%s?id=%u\">%s</a>\n", sname, mp->id, mp->title);
+ printf("(%zu)</h3>\n", db_nelem(mp->id));
+ if (*mp->abstract != '\0')
+ printf("<blockquote>%s</blockquote>\n", mp->abstract);
+ }
+ }
+}
+
+void
+pr_opts(struct meta *mp)
+{
+ struct {
+ char *str;
+ char *alt;
+ char *img;
+ char trg;
+ char *dsc;
+ } *op, o[] = {
+ { mp->html, "HTML", "htmlicon.gif", 'h', "View HTML version" },
+ { mp->pdf, "PDF", "pdficon.gif", 'p', "View as PDF" },
+ { mp->mws, "MWS", "mwicon.gif", 's', "Download Maple classic worksheet" },
+ { mp->mw, "MW", "mwicon.gif", 'm', "Download Maple worksheet" },
+ { mp->code, "CODE", "codeicon.gif", 'c', "Download Maple code" },
+ { mp->email, "EMAIL", "emailicon.gif", 'e', "E-mail to a colleague" },
+ { NULL, NULL, NULL, 0, NULL }
+ };
+
+ puts("<p class=\"options\">");
+ for (op = o; op->str != NULL; ++op) {
+ if (*op->str != '\0') {
+ printf("<a href=\"%s?id=%u&amp;jump=%c\">", sname, mp->id, op->trg);
+ printf("<img alt=\"%s\" src=\"/%s/%s\" /> ", op->alt, "images", op->img);
+ printf("%s</a><br />\n", op->dsc);
+ }
+ }
+ puts("</p>");
+}
+
+char *
+pr_lang(char *lang)
+{
+ char l[3];
+
+ struct {
+ char *lang;
+ char *img;
+ char *name;
+ } *lp, language[] = {
+ { "en", "uk_small.png", "English" },
+ { "de", "germany_small.png", "Deutsch" },
+ { "fr", "france_small.png", "Francaise" },
+ { "ru", "ussr_small.png", "Russian" },
+ { NULL, NULL, NULL }
+
+ };
+
+ l[0] = tolower(lang[0]);
+ l[1] = tolower(lang[1]);
+ l[2] = '\0';
+
+ for (lp = language; lp->lang != NULL; ++lp) {
+ if (strncmp(lang, lp->lang, 2) == 0)
+ break;
+ }
+
+ if (lp->lang == NULL)
+ lp = language;
+
+ printf("<img alt=\"%s\" src=\"/flags/%s\" />\n", lp->name, lp->img);
+
+ return lp->name;
+}
+
+void
+pr_record(struct meta *mp, size_t n, enum sorder curso)
+{
+ int i = 0;
+ char *uri, *p;
+
+ uri = getenv("REQUEST_URI");
+
+ /* HACK: strip all args exept the first */
+ if ((p = strchr(uri, '&')) != NULL)
+ *p = '\0';
+
+ puts("<table>");
+ puts("<tr>");
+ printf("<th><a href=\"%s&amp;%c=t\">Title</a></th>\n", uri, curso == TITLEI ? 'd' : 'a');
+ puts("<th>Language</th>");
+ puts("<th>Options</th>");
+ printf("<th><a href=\"%s&amp;%c=d\">Date Publlished</a></th>\n", uri, curso == DATEI ? 'd' : 'a');
+ printf("<th><a href=\"%s&amp;%c=a\">Author</a></th>\n", uri, curso == AUTHORI ? 'd' : 'a');
+ puts("</tr>");
+
+ for (; n--; ++mp) {
+ if (mp->type == M_RECORD) {
+ printf("<tr class=\"%s\"><td>", (i++ & 1) == 0 ? "odd" : "even");
+ printf("<h4><a href=\"%s?id=%u\">%s</a></h4>\n", sname, mp->id, mp->title);
+ if (*mp->abstract != '\0')
+ printf("<blockquote>%s</blockquote>\n", mp->abstract);
+ puts("</td><td>");
+ pr_lang(mp->language);
+ puts("</td><td>");
+ pr_opts(mp);
+ puts("</td>");
+ printf("<td>%s</td>\n", ctime(&mp->date));
+ printf("<td>%s</td></tr>\n", mp->author);
+ }
+ }
+
+ puts("</table>");
+}
+
+#if 0
+void
+pr_image(struct meta *mp, size_t n)
+{
+ puts("<div class=\"image\">");
+ printf("<img src=\"/%s/", datadir);
+ while (--n)
+ printf("%s/", (++mp)->dir);
+ printf("%s\" />", mp->img);
+ puts("</div>");
+}
+#endif
+
+void
+pr_new(size_t max)
+{
+ struct meta *mp;
+ size_t n;
+
+ mp = db_find("", &n);
+ if (mp == NULL)
+ return;
+
+ db_sort(mp, n, DATED);
+
+ for (; n-- && max; ++mp) {
+ if (mp->type == M_RECORD) {
+ puts("<p>");
+ printf("<a href=\"%s?id=%u\">%s</a><br />\n", sname, mp->id, mp->title);
+ puts(ctime(&mp->date));
+ puts("</p>");
+ --max;
+ }
+ }
+}
+
+int
+have(struct meta *mp, size_t n, enum mtype t)
+{
+ while (n--)
+ if ((mp++)->type == t)
+ return 1;
+ return 0;
+}
+
+__dead void
+jmp(struct meta *mp, size_t n, enum jflag jf)
+{
+ char *p[16];
+
+ printf("Location: http://%s/%s/", getenv("SERVER_NAME"), datadir);
+ while (--n)
+ printf("%s/", (++mp)->dir);
+
+ p[0] = mp->html;
+ p[1] = mp->pdf;
+ p[2] = mp->mws;
+ p[3] = mp->mw;
+ p[4] = mp->code;
+ p[5] = mp->email;
+ p[6] = mp->img;
+
+ printf("%s\n\n", p[jf]);
+
+ exit(0);
+}
+
+__dead void
+mailto(unsigned int id)
+{
+ struct meta m;
+
+ if (db_get(&m, id) != NULL)
+ printf("Location: mailto:%s\n\n", m.email);
+
+ exit(0);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ struct meta *curr, *chld, *path, *found;
+ size_t nchld, npath, nfound;
+ unsigned int id;
+ enum jflag jf;
+ enum sorder so;
+ char *q, *srchq, *lang;
+
+ sname = getenv("SCRIPT_NAME");
+
+ id = 0;
+ if ((q = getquery("id")) != NULL) {
+ id = atoll(q);
+ free(q);
+ }
+
+ jf = J_NONE;
+ if ((q = getquery("jump")) != NULL) {
+ switch (*q) {
+ case 'h': jf = J_HTML; break;
+ case 'p': jf = J_PDF; break;
+ case 's': jf = J_MWS; break;
+ case 'm': jf = J_MW; break;
+ case 'c': jf = J_CODE; break;
+ case 'e': jf = J_EMAIL; break;
+ case 'i': jf = J_IMG; break;
+ }
+ free(q);
+ }
+
+ so = TITLEI;
+ if ((q = getquery("a")) != NULL) {
+ switch (*q) {
+ case 'a': so = AUTHORI; break;
+ case 'd': so = DATEI; break;
+ case 't': so = TITLEI; break;
+ }
+ free(q);
+ } else if ((q = getquery("d")) != NULL) {
+ switch (*q) {
+ case 'a': so = AUTHORD; break;
+ case 't': so = TITLED; break;
+ case 'd': so = DATED; break;
+ }
+ free(q);
+ }
+
+ if (db_open(O_RDONLY) != 0)
+ exit(0);
+
+ found = NULL;
+ srchq = NULL;
+ if ((q = getquery("search")) != NULL) {
+ srchq = decode(q);
+ found = db_find(srchq, &nfound);
+ free(q);
+ }
+
+ curr = db_get(NULL, id);
+ chld = db_children(id, &nchld);
+ path = db_path(id, &npath);
+
+ if (jf != J_NONE && path != NULL)
+ jmp(path, npath, jf);
+ /* NOTREACHED */
+
+ puts("Content-type: text/html; charset=iso-8859-1;\n");
+
+ puts("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
+ puts("\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
+ puts("<!-- $Id$ -->");
+
+ if (curr == NULL) {
+
+ puts("<html>");
+#if 0
+ printf("<h1> %s has just experienced an error</h1>", getenv("SERVER_NAME"));
+ puts("<p>Our technical team has been notified of the issue.");
+ puts("Please refresh the page or use the back button to return to the site.</p>");
+#else
+ puts("<h1>oops</h1>");
+ printf("id %u doesn't exist, try another number ;-)", id);
+#endif
+ puts("</html>");
+ exit(0);
+ }
+
+ pr_head(curr);
+
+ if (id != 0 && path != NULL)
+ pr_path(path, npath);
+
+ puts("<div class=\"content\">");
+
+ if (srchq != NULL) {
+ if (found != NULL) {
+ puts("<h2>Search results for:");
+ printf("<a href=\"%s?search=%s\">%s</a></h2>\n", sname, srchq, srchq);
+ db_sort(found, nfound, so);
+ if (have(found, nfound, M_SET)) {
+ puts("<h2>Sections</h2>");
+ pr_set(found, nfound);
+ }
+ if (have(found, nfound, M_RECORD)) {
+ puts("<h2>Content</h2>");
+ pr_record(found, nfound, so);
+ }
+ free(q);
+ } else {
+ puts("<h2>Nothing found for:");
+ printf("<a href=\"%s?search=%s\">%s</a></h2>\n", sname, srchq, srchq);
+ }
+ } else {
+ if (id == 0) {
+ puts("<div class=\"right\">");
+ puts("<h3>Recent</h3>");
+ pr_new(SHOWNEW);
+ puts("</div>");
+ }
+
+ if (chld != NULL) {
+ if (*curr->abstract != '\0')
+ printf("<p>%s</p>\n", curr->abstract);
+ db_sort(chld, nchld, so);
+ if (have(chld, nchld, M_SET)) {
+ printf("<h2>%sections</h2>", (id == 0) ? "S" : "Subs");
+ pr_set(chld, nchld);
+ }
+ if (have(chld, nchld, M_RECORD)) {
+ puts("<h2>Content</h2>");
+ pr_record(chld, nchld, so);
+ }
+ } else if (curr->type == M_RECORD) {
+ if (*curr->img != '\0') {
+ puts("<div class=\"image\">");
+ printf("<img alt=\"illustration\" src=\"%s?id=%u&amp;jump=img\" />", sname, curr->id);
+ puts("</div>");
+ }
+
+ puts("<div class=\"right\">");
+ puts("<h3>Options</h3>");
+ pr_opts(curr);
+ puts("</div>");
+
+ if (*curr->abstract != '\0')
+ printf("<p>%s</p>\n", curr->abstract);
+
+ puts("<p>");
+ printf("Author: %s<br />\n", curr->author);
+ printf("Date: %s<br />\n", ctime(&curr->date));
+ printf("Language: ");
+ lang = pr_lang(curr->language);
+ printf("%s\n", lang);
+ puts("</p>");
+ } else if (curr->type == M_SET) {
+ if (*curr->abstract != '\0')
+ printf("<p>%s</p>\n", curr->abstract);
+ } else {
+ puts("oops");
+ }
+
+ }
+
+ puts("</div>");
+
+ pr_foot();
+
+ db_close();
+
+ return 0;
+}
diff --git a/math/math.css b/math/math.css
new file mode 100644
index 0000000..ad6a82c
--- /dev/null
+++ b/math/math.css
@@ -0,0 +1,161 @@
+/* $Id$ */
+
+body {
+ padding: 0px;
+ margin: 0px;
+ color: #000000;
+ background: #ffffff;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 90%;
+}
+
+.foot {
+ font-size: x-small;
+ text-align: center;
+ padding: 5px 20px;
+ clear: both;
+}
+
+.right {
+ float: right;
+ border: 2px solid #cccccc;
+ padding: 0px 10px 10px 10px;
+ margin-left: 20px;
+ margin-bottom: 20px;
+ font-size: smaller;
+}
+
+.image {
+ float: left;
+ margin-right: 20px;
+ margin-bottom: 20px;
+ font-size: smaller;
+}
+
+.image img {
+ max-width: 200px;
+}
+
+input {
+ border: 1px solid #000000;
+}
+
+
+.head {
+ position: relative;
+ background: #777777;
+ color: #ffffff;
+ border-bottom: 2px solid #cccccc;
+ margin: 0px;
+ padding: 5px 30px;
+}
+
+.head form {
+ position: absolute;
+ margin: 20px;
+ padding: 0px;
+ right: 0px;
+ top: 0px;
+}
+
+/*
+.head a {
+ color: #ffffff;
+}
+*/
+
+
+
+.path {
+ position: relative;
+ background: #eaeaea;
+ color: #000000;
+ border-bottom: 1px solid #000000;
+ margin: 0px;
+ padding: 5px 20px 5px 30px;
+}
+
+.path a {
+ color: #777777;
+}
+
+
+
+
+/* contents */
+
+.content {
+ margin: 0px;
+ margin-top: 30px;
+ padding: 0px 20px 50px 30px;
+}
+
+.content h2 {
+ margin-top: 50px;
+}
+
+.content h3 {
+ margin-top: 30px;
+}
+
+
+a {
+ color: #777777;
+}
+
+a:link, a:visited, a:active {
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+ color: #000000;
+/* color: #ffa500; */
+}
+
+th a {
+ color: #ffffff;
+}
+
+a img {
+ border: 0px;
+}
+
+table {
+/*
+ width: 100%;
+*/
+ border-collapse: collapse;
+}
+
+th {
+ background: #777777;
+ color: #eaeaea;
+ border-bottom: 2px solid #cccccc;
+ padding: 5px 10px;
+ text-align: left;
+}
+
+td {
+ vertical-align: top;
+ padding: 5px 10px;
+ border-bottom: 1px solid #cccccc;
+}
+
+.options {
+ font-size: smaller;
+ text-align: left;
+ margin: 0px;
+}
+
+tr.odd td {
+ background: #eaeaea;
+}
+
+tr.even td {
+ background: #ffffff;
+}
+
+p {
+ text-align: justify;
+}
diff --git a/math/math/Makefile b/math/math/Makefile
new file mode 100644
index 0000000..d2a56fc
--- /dev/null
+++ b/math/math/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= index.cgi
+SRCS= math.c metadb.c query.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/math/metadb.c b/math/metadb.c
new file mode 100644
index 0000000..7e50959
--- /dev/null
+++ b/math/metadb.c
@@ -0,0 +1,581 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <ctype.h>
+#include <db.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "metadb.h"
+
+/* O_RDONLY */
+#define DB_FLAGS O_CREAT|O_RDWR
+#define DB_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
+
+#define P(f1,f2) printf( #f1 " = '%s'\t" #f2 " = '%s'\n", (f1), (f2))
+
+DB *idx, *meta, *srch;
+
+struct meta *decode_meta(struct meta *, char *);
+int cmptitle_i(const void *, const void *);
+int cmptitle_d(const void *, const void *);
+int cmpdate_i(const void *, const void *);
+int cmpdate_d(const void *, const void *);
+int cmpauthor_i(const void *, const void *);
+int cmpauthor_d(const void *, const void *);
+
+int
+db_open(int flags)
+{
+ idx = dbopen(INDEXDB, flags, DB_MODE, DB_HASH, NULL);
+ meta = dbopen(METADB, flags, DB_MODE, DB_HASH, NULL);
+ srch = dbopen(SEARCHDB, flags, DB_MODE, DB_HASH, NULL);
+ if (idx == NULL || meta == NULL || srch == NULL) {
+ db_close();
+ return -1;
+ }
+ return 0;
+}
+
+void
+db_close(void)
+{
+ if (idx != NULL)
+ (idx->close)(idx);
+ if (meta != NULL)
+ (meta->close)(meta);
+ if (srch != NULL)
+ (srch->close)(srch);
+}
+
+static int
+chkid(unsigned int *p, size_t n, unsigned int id)
+{
+ while (n--)
+ if (*p++ == id)
+ return 1;
+ return 0;
+}
+
+static int
+addindex(int parent, int id)
+{
+ DBT k, d;
+ int ret, *buf;
+ size_t siz = 0;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ /* add new record, payload is parents id */
+ k.data = &id;
+ k.size = sizeof(int);
+ d.data = &parent;
+ d.size = sizeof(int);
+
+ ret = (idx->put)(idx, &k, &d, 0);
+
+ /* go further and update parent only if id isn't root */
+ if (id == 0 || ret == -1)
+ return ret;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ k.data = &parent;
+ k.size = sizeof(int);
+
+ /* try to get perent */
+ if ((ret = (idx->get)(idx, &k, &d, 0)) != 0)
+ return ret;
+
+ siz = d.size + sizeof(int);
+ buf = malloc(siz);
+ assert(buf);
+ memset(buf, 0, siz);
+
+ memcpy(buf, (int *)d.data, sizeof(int));
+ memcpy(buf + 1, &id, sizeof(int));
+ memcpy(buf + 2, (int *)d.data + 1, d.size - sizeof(int));
+
+ d.data = buf;
+ d.size = siz;
+
+ ret = (idx->put)(idx, &k, &d, 0);
+ free(buf);
+
+ return ret;
+}
+
+#define EMPTY(s) ((s) == NULL ? "" : (s))
+
+#define LENGTH(s) (strlen(EMPTY(s)) + 1)
+
+#define PUTSTR(d, s, b, l) do { \
+ (l) = LENGTH(s); \
+ memcpy((d) + (b), EMPTY(s), (l)); \
+ (b) += (l); \
+} while (0)
+
+static char *
+encode_meta(struct meta *mp, size_t *siz)
+{
+ char *buf;
+ size_t len, blen;
+
+ *siz = sizeof(mp->type);
+ *siz += sizeof(mp->date);
+ *siz += sizeof(mp->id);
+
+ *siz += LENGTH(mp->dir);
+ *siz += LENGTH(mp->title);
+ *siz += LENGTH(mp->abstract);
+ *siz += LENGTH(mp->author);
+ *siz += LENGTH(mp->email);
+ *siz += LENGTH(mp->html);
+ *siz += LENGTH(mp->mws);
+ *siz += LENGTH(mp->mw);
+ *siz += LENGTH(mp->pdf);
+ *siz += LENGTH(mp->code);
+ *siz += LENGTH(mp->img);
+ *siz += LENGTH(mp->language);
+ *siz += LENGTH(mp->tokens);
+
+ buf = malloc(*siz);
+ assert(buf);
+ memset(buf, 0, *siz);
+
+ len = sizeof(mp->type);
+ memcpy(buf, &mp->type, len);
+ blen = len;
+
+ len = sizeof(mp->date);
+ memcpy(buf + blen, &mp->date, len);
+ blen += len;
+
+ len = sizeof(mp->id);
+ memcpy(buf + blen, &mp->id, len);
+ blen += len;
+
+ PUTSTR(buf, mp->dir, blen, len);
+ PUTSTR(buf, mp->title, blen, len);
+ PUTSTR(buf, mp->abstract, blen, len);
+ PUTSTR(buf, mp->author, blen, len);
+ PUTSTR(buf, mp->email, blen, len);
+ PUTSTR(buf, mp->html, blen, len);
+ PUTSTR(buf, mp->mws, blen, len);
+ PUTSTR(buf, mp->mw, blen, len);
+ PUTSTR(buf, mp->pdf, blen, len);
+ PUTSTR(buf, mp->code, blen, len);
+ PUTSTR(buf, mp->img, blen, len);
+ PUTSTR(buf, mp->language, blen, len);
+ PUTSTR(buf, mp->tokens, blen, len);
+
+ return buf;
+}
+
+#define GETSTR(d, s, l) do { \
+ (d) = strdup((s) + (l)); \
+ (l) += strlen(d) + 1; \
+} while (0)
+
+struct meta *
+decode_meta(struct meta *mp, char *buf)
+{
+ size_t blen;
+
+ mp->type = *(unsigned int *)buf;
+ blen = sizeof(mp->type);
+ mp->date = *(time_t *)(buf + blen);
+ blen += sizeof(mp->date);
+ mp->id = *(unsigned int *)(buf + blen);
+ blen += sizeof(mp->id);
+ GETSTR(mp->dir, buf, blen);
+ GETSTR(mp->title, buf, blen);
+ GETSTR(mp->abstract, buf, blen);
+ GETSTR(mp->author, buf, blen);
+ GETSTR(mp->email, buf, blen);
+ GETSTR(mp->html, buf, blen);
+ GETSTR(mp->mws, buf, blen);
+ GETSTR(mp->mw, buf, blen);
+ GETSTR(mp->pdf, buf, blen);
+ GETSTR(mp->code, buf, blen);
+ GETSTR(mp->img, buf, blen);
+ GETSTR(mp->language, buf, blen);
+ GETSTR(mp->tokens, buf, blen);
+
+ return mp;
+}
+
+static int
+addmeta(struct meta *mp, int id)
+{
+ DBT k, d;
+ char *buf;
+ size_t siz;
+ int ret;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ mp->id = id;
+ buf = encode_meta(mp, &siz);
+
+ k.data = &id;
+ k.size = sizeof(int);
+ d.data = buf;
+ d.size = siz;
+
+ ret = (meta->put)(meta, &k, &d, 0);
+ free(buf);
+
+ return ret;
+}
+
+static int
+addsearch(char *s, int id)
+{
+ DBT k, d;
+ int ret, *buf;
+ size_t siz = 0;
+ char *t, *p;
+ char sep[] = " \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ while ((t = strsep(&s, sep)) != NULL) {
+ for (p = t; *p != '\0'; p++)
+ *p = tolower(*p);
+
+ k.data = t;
+ k.size = strlen(t) + 1;
+
+ switch (ret = (srch->get)(srch, &k, &d, 0)) {
+ case -1: /* error */
+ return -1;
+ case 0: /* found */
+ siz = d.size + sizeof(int);
+ if (chkid(d.data, d.size / sizeof(int), id) == 1)
+ return 1;
+ break;
+ case 1: /* not found */
+ siz = sizeof(int);
+ break;
+ }
+
+ buf = malloc(siz);
+ assert(buf);
+ memset(buf, 0, siz);
+
+ memcpy(buf, &id, sizeof(int));
+ if (ret == 0)
+ memcpy(buf + 1, (int *)d.data, d.size);
+
+ d.data = buf;
+ d.size = siz;
+
+ if ((srch->put)(srch, &k, &d, 0) == -1)
+ return -1;
+
+ free(buf);
+ }
+
+ return 0;
+}
+
+int
+db_add(struct meta *mp, int parent, int id)
+{
+ addindex(parent, id);
+ addmeta(mp, id);
+
+ addsearch(mp->title, id);
+ addsearch(mp->abstract, id);
+ addsearch(mp->author, id);
+ addsearch(mp->tokens, id);
+
+ /* XXX */
+ addsearch("", id);
+
+ return 0;
+}
+
+struct meta *
+db_find(char *key, size_t *n)
+{
+ DBT k, d;
+ struct meta *mp;
+ char *p;
+ size_t i;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ for (p = key; *p != '\0'; p++)
+ *p = tolower(*p);
+
+ k.data = key;
+ k.size = strlen(key) + 1;
+
+ *n = 0;
+ if ((srch->get)(srch, &k, &d, 0) != 0)
+ return NULL;
+
+ *n = d.size / sizeof(int);
+
+ mp = calloc(*n, sizeof(struct meta));
+ assert(mp);
+
+ for (i = 0; i < *n; i++)
+ db_get(&mp[i], ((unsigned int *)d.data)[i]);
+
+ return mp;
+}
+
+struct meta *
+db_get(struct meta *mp, unsigned int id)
+{
+ DBT k, d;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ k.data = &id;
+ k.size = sizeof(int);
+
+ if ((meta->get)(meta, &k, &d, 0) == 0) {
+ if (mp == NULL) {
+ mp = malloc(sizeof(struct meta));
+ assert(mp);
+ }
+
+ return decode_meta(mp, d.data);
+ }
+
+ return NULL;
+}
+
+size_t
+db_nelem(unsigned int id)
+{
+ DBT k, d;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ k.data = &id;
+ k.size = sizeof(int);
+
+ if ((idx->get)(idx, &k, &d, 0) == 0)
+ return d.size / sizeof(int) - 1;
+
+ return 0;
+}
+
+struct meta *
+db_children(unsigned int id, size_t *n)
+{
+ DBT k, d;
+ struct meta *mp;
+ size_t i;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ k.data = &id;
+ k.size = sizeof(int);
+
+ *n = 0;
+ if ((idx->get)(idx, &k, &d, 0) != 0)
+ return NULL;
+
+ if ((*n = d.size / sizeof(int) - 1) == 0)
+ return NULL;
+
+ mp = calloc(*n, sizeof(struct meta));
+ assert(mp);
+
+ for (i = 0; i < *n; i++)
+ db_get(&mp[i], ((unsigned int *)d.data)[i + 1]);
+
+ return mp;
+}
+
+struct meta *
+db_path(unsigned int id, size_t *n)
+{
+ DBT k, d;
+ struct meta *mp;
+ unsigned int path[32], *p, i;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ p = path;
+ *p = id;
+
+ k.data = &id;
+ k.size = sizeof(int);
+
+ while (*p != 0 && p - path < 32) {
+ if ((idx->get)(idx, &k, &d, 0) != 0)
+ return NULL;
+ id = *(unsigned int *)d.data;
+ *(++p) = id;
+ }
+
+ *n = p - path + 1;
+ mp = calloc(*n, sizeof(struct meta));
+ assert(mp);
+
+ for (i = 0; i < *n; i++) {
+ db_get(&mp[i], *p--);
+ };
+
+ return mp;
+}
+
+/* increasing sort order */
+int
+cmptitle_i(const void *p1, const void *p2)
+{
+ struct meta *m1, *m2;
+
+ m1 = (struct meta *)p1;
+ m2 = (struct meta *)p2;
+
+ return strcmp(m1->title, m2->title);
+}
+
+/* decreasing sort order */
+int
+cmptitle_d(const void *p1, const void *p2)
+{
+ struct meta *m1, *m2;
+
+ m1 = (struct meta *)p1;
+ m2 = (struct meta *)p2;
+
+ return strcmp(m2->title, m1->title);
+}
+
+/* increasing sort order */
+/* oldest first */
+int
+cmpdate_i(const void *p1, const void *p2)
+{
+ struct meta *m1, *m2;
+
+ m1 = (struct meta *)p1;
+ m2 = (struct meta *)p2;
+
+ if (m1->date > m2->date)
+ return 1;
+ else if (m1->date < m2->date)
+ return -1;
+ else
+ return 0;
+}
+
+/* decreasing sort order */
+/* newest first */
+int
+cmpdate_d(const void *p1, const void *p2)
+{
+ struct meta *m1, *m2;
+
+ m1 = (struct meta *)p1;
+ m2 = (struct meta *)p2;
+
+ if (m1->date > m2->date)
+ return -1;
+ else if (m1->date < m2->date)
+ return 1;
+ else
+ return 0;
+}
+
+/* increasing sort order */
+int
+cmpauthor_i(const void *p1, const void *p2)
+{
+ struct meta *m1, *m2;
+
+ m1 = (struct meta *)p1;
+ m2 = (struct meta *)p2;
+
+ return strcmp(m1->author, m2->author);
+}
+
+/* decreasing sort order */
+int
+cmpauthor_d(const void *p1, const void *p2)
+{
+ struct meta *m1, *m2;
+
+ m1 = (struct meta *)p1;
+ m2 = (struct meta *)p2;
+
+ return strcmp(m2->author, m1->author);
+}
+
+int (*cmp[])(const void *, const void *) = {
+ cmptitle_i, cmptitle_d,
+ cmpdate_i, cmpdate_d,
+ cmpauthor_i, cmpauthor_d
+};
+
+void
+db_sort(struct meta *mp, size_t n, enum sorder o)
+{
+ qsort(mp, n, sizeof(struct meta), cmp[o]);
+}
+
+#if 0
+int
+(*cmp(enum sorder o))(const void *, const void *)
+{
+ return fct[o];
+}
+#endif
+
+void
+db_wipe(void)
+{
+ DBT k, d;
+
+ memset(&k, 0, sizeof(DBT));
+ memset(&d, 0, sizeof(DBT));
+
+ while ((idx->seq)(idx, &k, &d, 0) != 0)
+ (idx->del)(idx, &k, 0);
+
+ while ((meta->seq)(meta, &k, &d, 0) != 0)
+ (meta->del)(meta, &k, 0);
+
+ while ((srch->seq)(srch, &k, &d, 0) != 0)
+ (srch->del)(srch, &k, 0);
+}
diff --git a/math/metadb.h b/math/metadb.h
new file mode 100644
index 0000000..d00f34a
--- /dev/null
+++ b/math/metadb.h
@@ -0,0 +1,68 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _METADB_H_
+#define _METADB_H_
+
+#define INDEXDB "_index.db"
+#define METADB "_meta.db"
+#define SEARCHDB "_search.db"
+
+#define METADATA "meta.txt"
+#define SECTION "section.txt"
+
+enum mtype { M_SET, M_RECORD };
+enum sorder { TITLEI, TITLED, DATEI, DATED, AUTHORI, AUTHORD };
+
+struct meta {
+ enum mtype type;
+ time_t date;
+ unsigned int id;
+ char *dir;
+ char *title;
+ char *abstract;
+ char *author;
+ char *email;
+ char *html;
+ char *mws;
+ char *mw;
+ char *pdf;
+ char *code;
+ char *img;
+ char *language;
+ char *tokens;
+};
+
+__BEGIN_DECLS
+struct meta *openmeta(char *);
+void closemeta(struct meta *);
+
+int db_open(int);
+void db_close(void);
+void db_wipe(void);
+int db_add(struct meta *, int, int);
+size_t db_nelem(unsigned int);
+
+struct meta *db_get(struct meta *, unsigned int);
+struct meta *db_children(unsigned int, size_t *);
+struct meta *db_path(unsigned int, size_t *);
+struct meta *db_find(char *, size_t *);
+void db_sort(struct meta *, size_t, enum sorder);
+__END_DECLS
+
+#endif /* not _METADB_H_ */
diff --git a/math/mkdb.c b/math/mkdb.c
new file mode 100644
index 0000000..db07eff
--- /dev/null
+++ b/math/mkdb.c
@@ -0,0 +1,130 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "crc.h"
+#include "metadb.h"
+
+void twiddle(void);
+void walk(char **);
+
+void
+twiddle(void)
+{
+ static int i;
+
+ putchar("|/-\\"[i++ & 3]);
+ putchar('\b');
+ fflush(stdout);
+}
+
+void
+walk(char **fname)
+{
+ FTS *fts;
+ FTSENT *ftp, *chld, *cp;
+ char *p, pathmeta[BUFSIZ], pathset[BUFSIZ];
+ int parent, id;
+ struct meta *mp;
+
+ fts = fts_open(fname, FTS_LOGICAL, NULL);
+ assert(fts);
+
+ printf("Scanning: ");
+
+ db_open(O_CREAT|O_RDWR);
+
+// db_wipe();
+
+ while ((ftp = fts_read(fts)) != NULL) {
+ twiddle();
+ if (ftp->fts_info == FTS_D) {
+ p = ftp->fts_parent->fts_name;
+ if (ftp->fts_parent->fts_level <= 0)
+ parent = 0;
+ else
+ parent = crc32(p, strlen(p));
+
+ p = ftp->fts_name;
+ if (ftp->fts_level <= 0)
+ id = 0;
+ else
+ id = crc32(p, strlen(p));
+
+ snprintf(pathmeta, sizeof(pathmeta), "%s/%s", ftp->fts_accpath, METADATA);
+ snprintf(pathset, sizeof(pathset), "%s/%s", ftp->fts_accpath, SECTION);
+
+ if ((mp = openmeta(pathmeta)) != NULL) {
+ mp->dir = strdup(p);
+ mp->date = ftp->fts_statp->st_ctimespec.tv_sec;
+ mp->type = M_RECORD;
+
+ chld = fts_children(fts, 0);
+ for (cp = chld; cp != NULL; cp = cp->fts_link) {
+ if (cp->fts_info == FTS_F) {
+ p = cp->fts_name;
+ if (strstr(p, ".htm") != NULL)
+ mp->html = strdup(p);
+ else if (strstr(p, ".mws") != NULL)
+ mp->mws = strdup(p);
+ else if (strstr(p, ".mw") != NULL)
+ mp->mw = strdup(p);
+ else if (strstr(p, ".pdf") != NULL)
+ mp->pdf = strdup(p);
+ else if (strstr(p, ".zip") != NULL)
+ mp->code = strdup(p);
+ }
+ }
+
+
+ db_add(mp, parent, id);
+ closemeta(mp);
+ } else if ((mp = openmeta(pathset)) != NULL) {
+ mp->dir = strdup(p);
+ mp->date = ftp->fts_statp->st_ctimespec.tv_sec;
+ mp->type = M_SET;
+ db_add(mp, parent, id);
+ }
+ }
+ }
+
+ db_close();
+ fts_close(fts);
+
+ printf("done\n");
+}
+
+int
+main(int argc, char **argv)
+{
+
+ if (argc != 2)
+ return -1;
+
+ walk(&argv[1]);
+
+ return 0;
+}
diff --git a/math/mkdb/Makefile b/math/mkdb/Makefile
new file mode 100644
index 0000000..043647a
--- /dev/null
+++ b/math/mkdb/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= mkdb
+SRCS= crc.c metadb.c mkdb.c readmeta.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/math/query.c b/math/query.c
new file mode 100644
index 0000000..c275547
--- /dev/null
+++ b/math/query.c
@@ -0,0 +1,81 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "query.h"
+
+char *
+decode(const char *s)
+{
+ char *buf, *t;
+
+ assert(s);
+ buf = malloc(sizeof(char) * strlen(s) + 1);
+ assert(buf);
+
+ for (t = buf; *s != '\0'; ++t, ++s) {
+ if (*s == '%') {
+ *t = *++s;
+ *t -= isdigit(*s) ? '0' : ((isupper(*s) ? 'A' : 'a') - 0x0a);
+ *t *= 0x10;
+ *t += *++s;
+ *t -= isdigit(*s) ? '0' : ((isupper(*s) ? 'A' : 'a') - 0x0a);
+ } else if (*s == '+')
+ *t = ' ';
+ else
+ *t = *s;
+ }
+ *t = '\0';
+
+ return buf;
+}
+
+char *
+getquery(char *var)
+{
+ const char *qstr;
+ char *buf, *s, *p;
+
+ assert(var);
+ qstr = getenv("QUERY_STRING");
+ if (!qstr)
+ return NULL;
+ buf = decode(qstr);
+
+ for (s = buf; *s != '\0'; s = p + 1) {
+ for (p = s; *p && *p != '&'; ++p)
+ ;
+ *p = '\0';
+ if (strncmp(s, var, strlen(var)) == 0) {
+ s = strchr(s, '=') + 1;
+ if (strlen(s) == 0)
+ break; /* XXX */
+ p = strdup(s);
+ free(buf);
+ return p;
+ }
+ }
+
+ free(buf);
+ return NULL;
+}
diff --git a/math/query.h b/math/query.h
new file mode 100644
index 0000000..f5fdc52
--- /dev/null
+++ b/math/query.h
@@ -0,0 +1,27 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _QUERY_H_
+#define _QUERY_H_
+
+__BEGIN_DECLS
+char *decode(const char *);
+char *getquery(char *);
+__END_DECLS
+
+#endif /* not _QUERY_H_ */
diff --git a/math/readmeta.c b/math/readmeta.c
new file mode 100644
index 0000000..33fc5f7
--- /dev/null
+++ b/math/readmeta.c
@@ -0,0 +1,158 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2006 Dimitri A. Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "metadb.h"
+
+char *freadall(char *);
+
+#define STRIPWS(p) do { \
+ while (*(p) != '\0' && isascii(*(p)) && isblank(*(p))) \
+ ++(p); \
+} while (0)
+
+#define INITTAB(k, v) do { \
+ (k)->key = k; ((k)++)->val = (v); \
+} while (0)
+
+/* TODO: rewrite it all */
+
+char *
+freadall(char *fname)
+{
+ FILE *fd;
+ char *buf;
+ size_t len;
+
+ if ((fd = fopen(fname, "r")) == NULL)
+ return NULL;
+
+ fseek(fd, 0L, SEEK_END);
+ len = ftell(fd);
+ fseek(fd, 0L, SEEK_SET);
+
+ if ((buf = calloc(len + 1, sizeof(char))) == NULL)
+ return NULL;
+
+ fread(buf, sizeof(char), len, fd);
+ fclose(fd);
+
+ buf[len + 1] = '\0';
+
+ return buf;
+}
+
+struct meta *
+openmeta(char *fname)
+{
+ char *buf, *p, *key, *eol;
+ struct meta *mp;
+ struct kwords {
+ char *key;
+ char **val;
+ } *kwp, kw[16];
+
+ if ((buf = freadall(fname)) == NULL)
+ return NULL;
+
+ mp = malloc(sizeof(struct meta));
+ assert(mp);
+ memset(mp, 0, sizeof(struct meta));
+
+ kwp = kw;
+ kwp->key = "title"; (kwp++)->val = &mp->title;
+ kwp->key = "abstract"; (kwp++)->val = &mp->abstract;
+ kwp->key = "author"; (kwp++)->val = &mp->author;
+ kwp->key = "email"; (kwp++)->val = &mp->email;
+ kwp->key = "image"; (kwp++)->val = &mp->img;
+ kwp->key = "language"; (kwp++)->val = &mp->language;
+ kwp->key = "tokens"; (kwp++)->val = &mp->tokens;
+ kwp->key = NULL;
+
+#if DEBUG
+ printf("file: %s\n", fname);
+#endif
+ for (p = buf; p != NULL; p = eol) {
+ /* join lines */
+ for (eol = p; (eol = strchr(eol, '\n')) != NULL;) {
+ ++eol;
+ if (isascii(*eol) && !isblank(*eol)) {
+ *(eol - 1) = '\0';
+ break;
+ }
+ }
+
+ /* skip commentars and empty lines */
+ if (*p == '\0' || *p == '#' || (isascii(*p) && (isspace(*p))))
+ continue;
+
+ key = p;
+ while (*p != '\0' && isascii(*p) && !isblank(*p) && *p != ':' && *p != '=')
+ ++p;
+ *p++ = '\0';
+
+ /* strip whitespace */
+ while (*p != '\0' && isascii(*p) && isblank(*p))
+ ++p;
+
+#if DEBUG
+ printf("key: %s\tval: %s\n", key, p);
+#endif
+ for (kwp = kw; kwp->key != NULL; kwp++) {
+ if (strcmp(key, kwp->key) == 0)
+ *kwp->val = strdup(p);
+ }
+ }
+
+ free(buf);
+
+ if (mp->language == NULL)
+ mp->language = "en";
+
+ return mp;
+}
+
+void
+closemeta(struct meta *mp)
+{
+ if (mp->title != NULL)
+ free(mp->title);
+ if (mp->abstract != NULL)
+ free(mp->abstract);
+ if (mp->author != NULL)
+ free(mp->author);
+ if (mp->email != NULL)
+ free(mp->email);
+ if (mp->html != NULL)
+ free(mp->html);
+ if (mp->mw != NULL)
+ free(mp->mw);
+ if (mp->pdf != NULL)
+ free(mp->pdf);
+ if (mp->code != NULL)
+ free(mp->code);
+ if (mp->tokens != NULL)
+ free(mp->tokens);
+ free(mp);
+}