source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Less misleading file names; ok kristaps@.
@ 2011-11-13 10:12 schwarze
  0 siblings, 0 replies; only message in thread
From: schwarze @ 2011-11-13 10:12 UTC (permalink / raw)
  To: source

Log Message:
-----------
Less misleading file names; ok kristaps@.

Modified Files:
--------------
    mdocml:
        Makefile
        apropos.c
        cgi.c

Added Files:
-----------
    mdocml:
        apropos_db.c
        apropos_db.h

Removed Files:
-------------
    mdocml:
        apropos.h
        db.c

Revision Data
-------------
--- /dev/null
+++ apropos_db.c
@@ -0,0 +1,541 @@
+/*	$Id: apropos_db.c,v 1.1 2011/11/13 10:12:05 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * 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 <fcntl.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __linux__
+# include <db_185.h>
+#else
+# include <db.h>
+#endif
+
+#include "apropos_db.h"
+#include "mandoc.h"
+
+enum	match {
+	MATCH_REGEX,
+	MATCH_REGEXCASE,
+	MATCH_STR,
+	MATCH_STRCASE
+};
+
+struct	expr {
+	enum match	 match;
+	int	 	 mask;
+	char		*v;
+	regex_t	 	 re;
+};
+
+struct	type {
+	int		 mask;
+	const char	*name;
+};
+
+static	const struct type types[] = {
+	{ TYPE_NAME, "name" },
+	{ TYPE_FUNCTION, "func" },
+	{ TYPE_UTILITY, "utility" },
+	{ TYPE_INCLUDES, "incl" },
+	{ TYPE_VARIABLE, "var" },
+	{ TYPE_STANDARD, "stand" },
+	{ TYPE_AUTHOR, "auth" },
+	{ TYPE_CONFIG, "conf" },
+	{ TYPE_DESC, "desc" },
+	{ TYPE_XREF, "xref" },
+	{ TYPE_PATH, "path" },
+	{ TYPE_ENV, "env" },
+	{ TYPE_ERR, "err" },
+	{ INT_MAX, "all" },
+	{ 0, NULL }
+};
+
+static	DB	*btree_open(void);
+static	int	 btree_read(const DBT *, const struct mchars *, char **);
+static	int	 exprexec(const struct expr *, char *);
+static	DB	*index_open(void);
+static	int	 index_read(const DBT *, const DBT *, 
+			const struct mchars *, struct rec *);
+static	void	 norm_string(const char *,
+			const struct mchars *, char **);
+static	size_t	 norm_utf8(unsigned int, char[7]);
+
+/*
+ * Open the keyword mandoc-db database.
+ */
+static DB *
+btree_open(void)
+{
+	BTREEINFO	 info;
+	DB		*db;
+
+	memset(&info, 0, sizeof(BTREEINFO));
+	info.flags = R_DUP;
+
+	db = dbopen("mandoc.db", O_RDONLY, 0, DB_BTREE, &info);
+	if (NULL != db) 
+		return(db);
+
+	return(NULL);
+}
+
+/*
+ * Read a keyword from the database and normalise it.
+ * Return 0 if the database is insane, else 1.
+ */
+static int
+btree_read(const DBT *v, const struct mchars *mc, char **buf)
+{
+
+	/* Sanity: are we nil-terminated? */
+
+	assert(v->size > 0);
+	if ('\0' != ((char *)v->data)[(int)v->size - 1])
+		return(0);
+
+	norm_string((char *)v->data, mc, buf);
+	return(1);
+}
+
+/*
+ * Take a Unicode codepoint and produce its UTF-8 encoding.
+ * This isn't the best way to do this, but it works.
+ * The magic numbers are from the UTF-8 packaging.  
+ * They're not as scary as they seem: read the UTF-8 spec for details.
+ */
+static size_t
+norm_utf8(unsigned int cp, char out[7])
+{
+	size_t		 rc;
+
+	rc = 0;
+
+	if (cp <= 0x0000007F) {
+		rc = 1;
+		out[0] = (char)cp;
+	} else if (cp <= 0x000007FF) {
+		rc = 2;
+		out[0] = (cp >> 6  & 31) | 192;
+		out[1] = (cp       & 63) | 128;
+	} else if (cp <= 0x0000FFFF) {
+		rc = 3;
+		out[0] = (cp >> 12 & 15) | 224;
+		out[1] = (cp >> 6  & 63) | 128;
+		out[2] = (cp       & 63) | 128;
+	} else if (cp <= 0x001FFFFF) {
+		rc = 4;
+		out[0] = (cp >> 18 & 7) | 240;
+		out[1] = (cp >> 12 & 63) | 128;
+		out[2] = (cp >> 6  & 63) | 128;
+		out[3] = (cp       & 63) | 128;
+	} else if (cp <= 0x03FFFFFF) {
+		rc = 5;
+		out[0] = (cp >> 24 & 3) | 248;
+		out[1] = (cp >> 18 & 63) | 128;
+		out[2] = (cp >> 12 & 63) | 128;
+		out[3] = (cp >> 6  & 63) | 128;
+		out[4] = (cp       & 63) | 128;
+	} else if (cp <= 0x7FFFFFFF) {
+		rc = 6;
+		out[0] = (cp >> 30 & 1) | 252;
+		out[1] = (cp >> 24 & 63) | 128;
+		out[2] = (cp >> 18 & 63) | 128;
+		out[3] = (cp >> 12 & 63) | 128;
+		out[4] = (cp >> 6  & 63) | 128;
+		out[5] = (cp       & 63) | 128;
+	} else
+		return(0);
+
+	out[rc] = '\0';
+	return(rc);
+}
+
+/*
+ * Normalise strings from the index and database.
+ * These strings are escaped as defined by mandoc_char(7) along with
+ * other goop in mandoc.h (e.g., soft hyphens).
+ * This function normalises these into a nice UTF-8 string.
+ * Returns 0 if the database is fucked.
+ */
+static void
+norm_string(const char *val, const struct mchars *mc, char **buf)
+{
+	size_t		  sz, bsz;
+	char		  utfbuf[7];
+	const char	 *seq, *cpp;
+	int		  len, u, pos;
+	enum mandoc_esc	  esc;
+	static const char res[] = { '\\', '\t', 
+				ASCII_NBRSP, ASCII_HYPH, '\0' };
+
+	/* Pre-allocate by the length of the input */
+
+	bsz = strlen(val) + 1;
+	*buf = mandoc_realloc(*buf, bsz);
+	pos = 0;
+
+	while ('\0' != *val) {
+		/*
+		 * Halt on the first escape sequence.
+		 * This also halts on the end of string, in which case
+		 * we just copy, fallthrough, and exit the loop.
+		 */
+		if ((sz = strcspn(val, res)) > 0) {
+			memcpy(&(*buf)[pos], val, sz);
+			pos += (int)sz;
+			val += (int)sz;
+		}
+
+		if (ASCII_HYPH == *val) {
+			(*buf)[pos++] = '-';
+			val++;
+			continue;
+		} else if ('\t' == *val || ASCII_NBRSP == *val) {
+			(*buf)[pos++] = ' ';
+			val++;
+			continue;
+		} else if ('\\' != *val)
+			break;
+
+		/* Read past the slash. */
+
+		val++;
+		u = 0;
+
+		/*
+		 * Parse the escape sequence and see if it's a
+		 * predefined character or special character.
+		 */
+
+		esc = mandoc_escape(&val, &seq, &len);
+		if (ESCAPE_ERROR == esc)
+			break;
+
+		/* 
+		 * XXX - this just does UTF-8, but we need to know
+		 * beforehand whether we should do text substitution.
+		 */
+
+		switch (esc) {
+		case (ESCAPE_SPECIAL):
+			if (0 != (u = mchars_spec2cp(mc, seq, len)))
+				break;
+			/* FALLTHROUGH */
+		default:
+			continue;
+		}
+
+		/*
+		 * If we have a Unicode codepoint, try to convert that
+		 * to a UTF-8 byte string.
+		 */
+
+		cpp = utfbuf;
+		if (0 == (sz = norm_utf8(u, utfbuf)))
+			continue;
+
+		/* Copy the rendered glyph into the stream. */
+
+		sz = strlen(cpp);
+		bsz += sz;
+
+		*buf = mandoc_realloc(*buf, bsz);
+
+		memcpy(&(*buf)[pos], cpp, sz);
+		pos += (int)sz;
+	}
+
+	(*buf)[pos] = '\0';
+}
+
+/*
+ * Open the filename-index mandoc-db database.
+ * Returns NULL if opening failed.
+ */
+static DB *
+index_open(void)
+{
+	DB		*db;
+
+	db = dbopen("mandoc.index", O_RDONLY, 0, DB_RECNO, NULL);
+	if (NULL != db)
+		return(db);
+
+	return(NULL);
+}
+
+/*
+ * Safely unpack from an index file record into the structure.
+ * Returns 1 if an entry was unpacked, 0 if the database is insane.
+ */
+static int
+index_read(const DBT *key, const DBT *val, 
+		const struct mchars *mc, struct rec *rec)
+{
+	size_t		 left;
+	char		*np, *cp;
+
+#define	INDEX_BREAD(_dst) \
+	do { \
+		if (NULL == (np = memchr(cp, '\0', left))) \
+			return(0); \
+		norm_string(cp, mc, &(_dst)); \
+		left -= (np - cp) + 1; \
+		cp = np + 1; \
+	} while (/* CONSTCOND */ 0)
+
+	left = val->size;
+	cp = (char *)val->data;
+
+	rec->rec = *(recno_t *)key->data;
+
+	INDEX_BREAD(rec->file);
+	INDEX_BREAD(rec->cat);
+	INDEX_BREAD(rec->title);
+	INDEX_BREAD(rec->arch);
+	INDEX_BREAD(rec->desc);
+	return(1);
+}
+
+/*
+ * Search the mandocdb database for the expression "expr".
+ * Filter out by "opts".
+ * Call "res" with the results, which may be zero.
+ */
+void
+apropos_search(const struct opts *opts, const struct expr *expr,
+		void *arg, void (*res)(struct rec *, size_t, void *))
+{
+	int		 i, len, root, leaf;
+	DBT		 key, val;
+	DB		*btree, *idx;
+	struct mchars	*mc;
+	int		 ch;
+	char		*buf;
+	recno_t		 rec;
+	struct rec	*recs;
+	struct rec	 srec;
+
+	root	= -1;
+	leaf	= -1;
+	btree	= NULL;
+	idx	= NULL;
+	mc	= NULL;
+	buf	= NULL;
+	recs	= NULL;
+	len	= 0;
+
+	memset(&srec, 0, sizeof(struct rec));
+
+	/* XXX: error out with bad regexp? */
+
+	mc = mchars_alloc();
+
+	/* XXX: return fact that we've errored? */
+
+	if (NULL == (btree = btree_open())) 
+		goto out;
+	if (NULL == (idx = index_open())) 
+		goto out;
+
+	while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
+		/* 
+		 * Low-water mark for key and value.
+		 * The key must have something in it, and the value must
+		 * have the correct tags/recno mix.
+		 */
+		if (key.size < 2 || 8 != val.size) 
+			break;
+		if ( ! btree_read(&key, mc, &buf))
+			break;
+
+		if ( ! exprexec(expr, buf))
+			continue;
+
+		memcpy(&rec, val.data + 4, sizeof(recno_t));
+
+		/*
+		 * O(log n) scan for prior records.  Since a record
+		 * number is unbounded, this has decent performance over
+		 * a complex hash function.
+		 */
+
+		for (leaf = root; leaf >= 0; )
+			if (rec > recs[leaf].rec && recs[leaf].rhs >= 0)
+				leaf = recs[leaf].rhs;
+			else if (rec < recs[leaf].rec && recs[leaf].lhs >= 0)
+				leaf = recs[leaf].lhs;
+			else 
+				break;
+
+		if (leaf >= 0 && recs[leaf].rec == rec)
+			continue;
+
+		/*
+		 * Now we actually extract the manpage's metadata from
+		 * the index database.
+		 */
+
+		key.data = &rec;
+		key.size = sizeof(recno_t);
+
+		if (0 != (*idx->get)(idx, &key, &val, 0))
+			break;
+
+		srec.lhs = srec.rhs = -1;
+		if ( ! index_read(&key, &val, mc, &srec))
+			break;
+
+		if (opts->cat && strcasecmp(opts->cat, srec.cat))
+			continue;
+		if (opts->arch && strcasecmp(opts->arch, srec.arch))
+			continue;
+
+		recs = mandoc_realloc
+			(recs, (len + 1) * sizeof(struct rec));
+
+		memcpy(&recs[len], &srec, sizeof(struct rec));
+
+		/* Append to our tree. */
+
+		if (leaf >= 0) {
+			if (rec > recs[leaf].rec)
+				recs[leaf].rhs = len;
+			else
+				recs[leaf].lhs = len;
+		} else
+			root = len;
+		
+		memset(&srec, 0, sizeof(struct rec));
+		len++;
+	}
+
+	if (1 == ch)
+		(*res)(recs, len, arg);
+
+	/* XXX: else?  corrupt database error? */
+out:
+	for (i = 0; i < len; i++) {
+		free(recs[i].file);
+		free(recs[i].cat);
+		free(recs[i].title);
+		free(recs[i].arch);
+		free(recs[i].desc);
+	}
+
+	free(srec.file);
+	free(srec.cat);
+	free(srec.title);
+	free(srec.arch);
+	free(srec.desc);
+
+	if (mc)
+		mchars_free(mc);
+	if (btree)
+		(*btree->close)(btree);
+	if (idx)
+		(*idx->close)(idx);
+
+	free(buf);
+	free(recs);
+}
+
+struct expr *
+exprcomp(int cs, char *argv[], int argc)
+{
+	struct expr	*p;
+	struct expr	 e;
+	int		 i, pos, ch;
+
+	pos = 0;
+
+	if (pos > argc)
+		return(NULL);
+
+	for (i = 0; 0 != types[i].mask; i++)
+		if (0 == strcmp(types[i].name, argv[pos]))
+			break;
+
+	if (0 == (e.mask = types[i].mask))
+		return(NULL);
+
+	if (++pos > argc--)
+		return(NULL);
+
+	if ('-' != *argv[pos]) 
+		e.match = cs ? MATCH_STRCASE : MATCH_STR;
+	else if (0 == strcmp("-eq", argv[pos]))
+		e.match = cs ? MATCH_STRCASE : MATCH_STR;
+	else if (0 == strcmp("-ieq", argv[pos]))
+		e.match = MATCH_STRCASE;
+	else if (0 == strcmp("-re", argv[pos]))
+		e.match = cs ? MATCH_REGEXCASE : MATCH_REGEX;
+	else if (0 == strcmp("-ire", argv[pos]))
+		e.match = MATCH_REGEXCASE;
+	else
+		return(NULL);
+
+	if ('-' == *argv[pos])
+		pos++;
+
+	if (pos > argc--)
+		return(NULL);
+
+	e.v = mandoc_strdup(argv[pos]);
+
+	if (MATCH_REGEX == e.match || MATCH_REGEXCASE == e.match) {
+		ch = REG_EXTENDED | REG_NOSUB;
+		if (MATCH_REGEXCASE == e.match)
+			ch |= REG_ICASE;
+		if (regcomp(&e.re, e.v, ch))
+			return(NULL);
+	}
+
+	p = mandoc_calloc(1, sizeof(struct expr));
+	memcpy(p, &e, sizeof(struct expr));
+	return(p);
+}
+
+void
+exprfree(struct expr *p)
+{
+
+	if (NULL == p)
+		return;
+
+	if (MATCH_REGEX == p->match)
+		regfree(&p->re);
+
+	free(p->v);
+	free(p);
+}
+
+static int
+exprexec(const struct expr *p, char *cp)
+{
+
+	if (MATCH_STR == p->match)
+		return(0 == strcmp(p->v, cp));
+	else if (MATCH_STRCASE == p->match)
+		return(0 == strcasecmp(p->v, cp));
+
+	assert(MATCH_REGEX == p->match);
+	return(0 == regexec(&p->re, cp, 0, NULL, 0));
+}
--- /dev/null
+++ apropos_db.h
@@ -0,0 +1,71 @@
+/*	$Id: apropos_db.h,v 1.1 2011/11/13 10:12:05 schwarze Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * 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 APROPOS_H
+#define APROPOS_H
+
+#define TYPE_NAME	  0x01
+#define TYPE_FUNCTION	  0x02
+#define TYPE_UTILITY	  0x04
+#define TYPE_INCLUDES	  0x08
+#define TYPE_VARIABLE	  0x10
+#define TYPE_STANDARD	  0x20
+#define TYPE_AUTHOR	  0x40
+#define TYPE_CONFIG	  0x80
+#define TYPE_DESC	  0x100
+#define TYPE_XREF	  0x200
+#define TYPE_PATH	  0x400
+#define TYPE_ENV	  0x800
+#define TYPE_ERR	  0x1000
+
+struct	rec {
+	char		*file; /* file in file-system */
+	char		*cat; /* category (3p, 3, etc.) */
+	char		*title; /* title (FOO, etc.) */
+	char		*arch; /* arch (or empty string) */
+	char		*desc; /* description (from Nd) */
+	unsigned int	 rec; /* record in index */
+	/*
+	 * By the time the apropos_search() callback is called, these
+	 * are superfluous.
+	 * Maintain a binary tree for checking the uniqueness of `rec'
+	 * when adding elements to the results array.
+	 * Since the results array is dynamic, use offset in the array
+	 * instead of a pointer to the structure.
+	 */
+	int		 lhs;
+	int		 rhs;
+};
+
+struct	opts {
+	const char	*arch; /* restrict to architecture */
+	const char	*cat; /* restrict to manual section */
+};
+
+__BEGIN_DECLS
+
+struct	expr;
+
+void	 	 apropos_search(const struct opts *, 
+			const struct expr *, void *, 
+			void (*)(struct rec *, size_t, void *));
+
+struct	expr	*exprcomp(int, char *[], int);
+void		 exprfree(struct expr *);
+
+__END_DECLS
+
+#endif /*!APROPOS_H*/
--- apropos.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*	$Id: apropos.h,v 1.2 2011/11/09 22:05:56 kristaps Exp $ */
-/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * 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 APROPOS_H
-#define APROPOS_H
-
-#define TYPE_NAME	  0x01
-#define TYPE_FUNCTION	  0x02
-#define TYPE_UTILITY	  0x04
-#define TYPE_INCLUDES	  0x08
-#define TYPE_VARIABLE	  0x10
-#define TYPE_STANDARD	  0x20
-#define TYPE_AUTHOR	  0x40
-#define TYPE_CONFIG	  0x80
-#define TYPE_DESC	  0x100
-#define TYPE_XREF	  0x200
-#define TYPE_PATH	  0x400
-#define TYPE_ENV	  0x800
-#define TYPE_ERR	  0x1000
-
-struct	rec {
-	char		*file; /* file in file-system */
-	char		*cat; /* category (3p, 3, etc.) */
-	char		*title; /* title (FOO, etc.) */
-	char		*arch; /* arch (or empty string) */
-	char		*desc; /* description (from Nd) */
-	unsigned int	 rec; /* record in index */
-	/*
-	 * By the time the apropos_search() callback is called, these
-	 * are superfluous.
-	 * Maintain a binary tree for checking the uniqueness of `rec'
-	 * when adding elements to the results array.
-	 * Since the results array is dynamic, use offset in the array
-	 * instead of a pointer to the structure.
-	 */
-	int		 lhs;
-	int		 rhs;
-};
-
-struct	opts {
-	const char	*arch; /* restrict to architecture */
-	const char	*cat; /* restrict to manual section */
-};
-
-__BEGIN_DECLS
-
-struct	expr;
-
-void	 	 apropos_search(const struct opts *, 
-			const struct expr *, void *, 
-			void (*)(struct rec *, size_t, void *));
-
-struct	expr	*exprcomp(int, char *[], int);
-void		 exprfree(struct expr *);
-
-__END_DECLS
-
-#endif /*!APROPOS_H*/
Index: cgi.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/cgi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lcgi.c -Lcgi.c -u -p -r1.2 -r1.3
--- cgi.c
+++ cgi.c
@@ -7,7 +7,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "apropos.h"
+#include "apropos_db.h"
 #include "mandoc.h"
 
 /*
Index: apropos.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -Lapropos.c -Lapropos.c -u -p -r1.10 -r1.11
--- apropos.c
+++ apropos.c
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "apropos.h"
+#include "apropos_db.h"
 #include "mandoc.h"
 
 static	int	 cmp(const void *, const void *);
Index: Makefile
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/Makefile,v
retrieving revision 1.376
retrieving revision 1.377
diff -LMakefile -LMakefile -u -p -r1.376 -r1.377
--- Makefile
+++ Makefile
@@ -278,15 +278,15 @@ PRECONV_LNS	 = preconv.ln
 
 $(PRECONV_OBJS) $(PRECONV_LNS): config.h
 
-APROPOS_OBJS	 = apropos.o db.o
-APROPOS_LNS	 = apropos.ln db.ln
+APROPOS_OBJS	 = apropos.o apropos_db.o
+APROPOS_LNS	 = apropos.ln apropos_db.ln
 
-$(APROPOS_OBJS) $(APROPOS_LNS): config.h mandoc.h apropos.h
+$(APROPOS_OBJS) $(APROPOS_LNS): config.h mandoc.h apropos_db.h
 
-CGI_OBJS	 = cgi.o db.o
-CGI_LNS	 	 = cgi.ln db.ln
+CGI_OBJS	 = cgi.o apropos_db.o
+CGI_LNS	 	 = cgi.ln apropos_db.ln
 
-$(CGI_OBJS) $(CGI_LNS): config.h mandoc.h apropos.h
+$(CGI_OBJS) $(CGI_LNS): config.h mandoc.h apropos_db.h
 
 DEMANDOC_OBJS	 = demandoc.o
 DEMANDOC_LNS	 = demandoc.ln
--- db.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/*	$Id: db.c,v 1.3 2011/11/09 23:31:36 kristaps Exp $ */
-/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * 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 <fcntl.h>
-#include <regex.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef __linux__
-# include <db_185.h>
-#else
-# include <db.h>
-#endif
-
-#include "apropos.h"
-#include "mandoc.h"
-
-enum	match {
-	MATCH_REGEX,
-	MATCH_REGEXCASE,
-	MATCH_STR,
-	MATCH_STRCASE
-};
-
-struct	expr {
-	enum match	 match;
-	int	 	 mask;
-	char		*v;
-	regex_t	 	 re;
-};
-
-struct	type {
-	int		 mask;
-	const char	*name;
-};
-
-static	const struct type types[] = {
-	{ TYPE_NAME, "name" },
-	{ TYPE_FUNCTION, "func" },
-	{ TYPE_UTILITY, "utility" },
-	{ TYPE_INCLUDES, "incl" },
-	{ TYPE_VARIABLE, "var" },
-	{ TYPE_STANDARD, "stand" },
-	{ TYPE_AUTHOR, "auth" },
-	{ TYPE_CONFIG, "conf" },
-	{ TYPE_DESC, "desc" },
-	{ TYPE_XREF, "xref" },
-	{ TYPE_PATH, "path" },
-	{ TYPE_ENV, "env" },
-	{ TYPE_ERR, "err" },
-	{ INT_MAX, "all" },
-	{ 0, NULL }
-};
-
-static	DB	*btree_open(void);
-static	int	 btree_read(const DBT *, const struct mchars *, char **);
-static	int	 exprexec(const struct expr *, char *);
-static	DB	*index_open(void);
-static	int	 index_read(const DBT *, const DBT *, 
-			const struct mchars *, struct rec *);
-static	void	 norm_string(const char *,
-			const struct mchars *, char **);
-static	size_t	 norm_utf8(unsigned int, char[7]);
-
-/*
- * Open the keyword mandoc-db database.
- */
-static DB *
-btree_open(void)
-{
-	BTREEINFO	 info;
-	DB		*db;
-
-	memset(&info, 0, sizeof(BTREEINFO));
-	info.flags = R_DUP;
-
-	db = dbopen("mandoc.db", O_RDONLY, 0, DB_BTREE, &info);
-	if (NULL != db) 
-		return(db);
-
-	return(NULL);
-}
-
-/*
- * Read a keyword from the database and normalise it.
- * Return 0 if the database is insane, else 1.
- */
-static int
-btree_read(const DBT *v, const struct mchars *mc, char **buf)
-{
-
-	/* Sanity: are we nil-terminated? */
-
-	assert(v->size > 0);
-	if ('\0' != ((char *)v->data)[(int)v->size - 1])
-		return(0);
-
-	norm_string((char *)v->data, mc, buf);
-	return(1);
-}
-
-/*
- * Take a Unicode codepoint and produce its UTF-8 encoding.
- * This isn't the best way to do this, but it works.
- * The magic numbers are from the UTF-8 packaging.  
- * They're not as scary as they seem: read the UTF-8 spec for details.
- */
-static size_t
-norm_utf8(unsigned int cp, char out[7])
-{
-	size_t		 rc;
-
-	rc = 0;
-
-	if (cp <= 0x0000007F) {
-		rc = 1;
-		out[0] = (char)cp;
-	} else if (cp <= 0x000007FF) {
-		rc = 2;
-		out[0] = (cp >> 6  & 31) | 192;
-		out[1] = (cp       & 63) | 128;
-	} else if (cp <= 0x0000FFFF) {
-		rc = 3;
-		out[0] = (cp >> 12 & 15) | 224;
-		out[1] = (cp >> 6  & 63) | 128;
-		out[2] = (cp       & 63) | 128;
-	} else if (cp <= 0x001FFFFF) {
-		rc = 4;
-		out[0] = (cp >> 18 & 7) | 240;
-		out[1] = (cp >> 12 & 63) | 128;
-		out[2] = (cp >> 6  & 63) | 128;
-		out[3] = (cp       & 63) | 128;
-	} else if (cp <= 0x03FFFFFF) {
-		rc = 5;
-		out[0] = (cp >> 24 & 3) | 248;
-		out[1] = (cp >> 18 & 63) | 128;
-		out[2] = (cp >> 12 & 63) | 128;
-		out[3] = (cp >> 6  & 63) | 128;
-		out[4] = (cp       & 63) | 128;
-	} else if (cp <= 0x7FFFFFFF) {
-		rc = 6;
-		out[0] = (cp >> 30 & 1) | 252;
-		out[1] = (cp >> 24 & 63) | 128;
-		out[2] = (cp >> 18 & 63) | 128;
-		out[3] = (cp >> 12 & 63) | 128;
-		out[4] = (cp >> 6  & 63) | 128;
-		out[5] = (cp       & 63) | 128;
-	} else
-		return(0);
-
-	out[rc] = '\0';
-	return(rc);
-}
-
-/*
- * Normalise strings from the index and database.
- * These strings are escaped as defined by mandoc_char(7) along with
- * other goop in mandoc.h (e.g., soft hyphens).
- * This function normalises these into a nice UTF-8 string.
- * Returns 0 if the database is fucked.
- */
-static void
-norm_string(const char *val, const struct mchars *mc, char **buf)
-{
-	size_t		  sz, bsz;
-	char		  utfbuf[7];
-	const char	 *seq, *cpp;
-	int		  len, u, pos;
-	enum mandoc_esc	  esc;
-	static const char res[] = { '\\', '\t', 
-				ASCII_NBRSP, ASCII_HYPH, '\0' };
-
-	/* Pre-allocate by the length of the input */
-
-	bsz = strlen(val) + 1;
-	*buf = mandoc_realloc(*buf, bsz);
-	pos = 0;
-
-	while ('\0' != *val) {
-		/*
-		 * Halt on the first escape sequence.
-		 * This also halts on the end of string, in which case
-		 * we just copy, fallthrough, and exit the loop.
-		 */
-		if ((sz = strcspn(val, res)) > 0) {
-			memcpy(&(*buf)[pos], val, sz);
-			pos += (int)sz;
-			val += (int)sz;
-		}
-
-		if (ASCII_HYPH == *val) {
-			(*buf)[pos++] = '-';
-			val++;
-			continue;
-		} else if ('\t' == *val || ASCII_NBRSP == *val) {
-			(*buf)[pos++] = ' ';
-			val++;
-			continue;
-		} else if ('\\' != *val)
-			break;
-
-		/* Read past the slash. */
-
-		val++;
-		u = 0;
-
-		/*
-		 * Parse the escape sequence and see if it's a
-		 * predefined character or special character.
-		 */
-
-		esc = mandoc_escape(&val, &seq, &len);
-		if (ESCAPE_ERROR == esc)
-			break;
-
-		/* 
-		 * XXX - this just does UTF-8, but we need to know
-		 * beforehand whether we should do text substitution.
-		 */
-
-		switch (esc) {
-		case (ESCAPE_SPECIAL):
-			if (0 != (u = mchars_spec2cp(mc, seq, len)))
-				break;
-			/* FALLTHROUGH */
-		default:
-			continue;
-		}
-
-		/*
-		 * If we have a Unicode codepoint, try to convert that
-		 * to a UTF-8 byte string.
-		 */
-
-		cpp = utfbuf;
-		if (0 == (sz = norm_utf8(u, utfbuf)))
-			continue;
-
-		/* Copy the rendered glyph into the stream. */
-
-		sz = strlen(cpp);
-		bsz += sz;
-
-		*buf = mandoc_realloc(*buf, bsz);
-
-		memcpy(&(*buf)[pos], cpp, sz);
-		pos += (int)sz;
-	}
-
-	(*buf)[pos] = '\0';
-}
-
-/*
- * Open the filename-index mandoc-db database.
- * Returns NULL if opening failed.
- */
-static DB *
-index_open(void)
-{
-	DB		*db;
-
-	db = dbopen("mandoc.index", O_RDONLY, 0, DB_RECNO, NULL);
-	if (NULL != db)
-		return(db);
-
-	return(NULL);
-}
-
-/*
- * Safely unpack from an index file record into the structure.
- * Returns 1 if an entry was unpacked, 0 if the database is insane.
- */
-static int
-index_read(const DBT *key, const DBT *val, 
-		const struct mchars *mc, struct rec *rec)
-{
-	size_t		 left;
-	char		*np, *cp;
-
-#define	INDEX_BREAD(_dst) \
-	do { \
-		if (NULL == (np = memchr(cp, '\0', left))) \
-			return(0); \
-		norm_string(cp, mc, &(_dst)); \
-		left -= (np - cp) + 1; \
-		cp = np + 1; \
-	} while (/* CONSTCOND */ 0)
-
-	left = val->size;
-	cp = (char *)val->data;
-
-	rec->rec = *(recno_t *)key->data;
-
-	INDEX_BREAD(rec->file);
-	INDEX_BREAD(rec->cat);
-	INDEX_BREAD(rec->title);
-	INDEX_BREAD(rec->arch);
-	INDEX_BREAD(rec->desc);
-	return(1);
-}
-
-/*
- * Search the mandocdb database for the expression "expr".
- * Filter out by "opts".
- * Call "res" with the results, which may be zero.
- */
-void
-apropos_search(const struct opts *opts, const struct expr *expr,
-		void *arg, void (*res)(struct rec *, size_t, void *))
-{
-	int		 i, len, root, leaf;
-	DBT		 key, val;
-	DB		*btree, *idx;
-	struct mchars	*mc;
-	int		 ch;
-	char		*buf;
-	recno_t		 rec;
-	struct rec	*recs;
-	struct rec	 srec;
-
-	root	= -1;
-	leaf	= -1;
-	btree	= NULL;
-	idx	= NULL;
-	mc	= NULL;
-	buf	= NULL;
-	recs	= NULL;
-	len	= 0;
-
-	memset(&srec, 0, sizeof(struct rec));
-
-	/* XXX: error out with bad regexp? */
-
-	mc = mchars_alloc();
-
-	/* XXX: return fact that we've errored? */
-
-	if (NULL == (btree = btree_open())) 
-		goto out;
-	if (NULL == (idx = index_open())) 
-		goto out;
-
-	while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
-		/* 
-		 * Low-water mark for key and value.
-		 * The key must have something in it, and the value must
-		 * have the correct tags/recno mix.
-		 */
-		if (key.size < 2 || 8 != val.size) 
-			break;
-		if ( ! btree_read(&key, mc, &buf))
-			break;
-
-		if ( ! exprexec(expr, buf))
-			continue;
-
-		memcpy(&rec, val.data + 4, sizeof(recno_t));
-
-		/*
-		 * O(log n) scan for prior records.  Since a record
-		 * number is unbounded, this has decent performance over
-		 * a complex hash function.
-		 */
-
-		for (leaf = root; leaf >= 0; )
-			if (rec > recs[leaf].rec && recs[leaf].rhs >= 0)
-				leaf = recs[leaf].rhs;
-			else if (rec < recs[leaf].rec && recs[leaf].lhs >= 0)
-				leaf = recs[leaf].lhs;
-			else 
-				break;
-
-		if (leaf >= 0 && recs[leaf].rec == rec)
-			continue;
-
-		/*
-		 * Now we actually extract the manpage's metadata from
-		 * the index database.
-		 */
-
-		key.data = &rec;
-		key.size = sizeof(recno_t);
-
-		if (0 != (*idx->get)(idx, &key, &val, 0))
-			break;
-
-		srec.lhs = srec.rhs = -1;
-		if ( ! index_read(&key, &val, mc, &srec))
-			break;
-
-		if (opts->cat && strcasecmp(opts->cat, srec.cat))
-			continue;
-		if (opts->arch && strcasecmp(opts->arch, srec.arch))
-			continue;
-
-		recs = mandoc_realloc
-			(recs, (len + 1) * sizeof(struct rec));
-
-		memcpy(&recs[len], &srec, sizeof(struct rec));
-
-		/* Append to our tree. */
-
-		if (leaf >= 0) {
-			if (rec > recs[leaf].rec)
-				recs[leaf].rhs = len;
-			else
-				recs[leaf].lhs = len;
-		} else
-			root = len;
-		
-		memset(&srec, 0, sizeof(struct rec));
-		len++;
-	}
-
-	if (1 == ch)
-		(*res)(recs, len, arg);
-
-	/* XXX: else?  corrupt database error? */
-out:
-	for (i = 0; i < len; i++) {
-		free(recs[i].file);
-		free(recs[i].cat);
-		free(recs[i].title);
-		free(recs[i].arch);
-		free(recs[i].desc);
-	}
-
-	free(srec.file);
-	free(srec.cat);
-	free(srec.title);
-	free(srec.arch);
-	free(srec.desc);
-
-	if (mc)
-		mchars_free(mc);
-	if (btree)
-		(*btree->close)(btree);
-	if (idx)
-		(*idx->close)(idx);
-
-	free(buf);
-	free(recs);
-}
-
-struct expr *
-exprcomp(int cs, char *argv[], int argc)
-{
-	struct expr	*p;
-	struct expr	 e;
-	int		 i, pos, ch;
-
-	pos = 0;
-
-	if (pos > argc)
-		return(NULL);
-
-	for (i = 0; 0 != types[i].mask; i++)
-		if (0 == strcmp(types[i].name, argv[pos]))
-			break;
-
-	if (0 == (e.mask = types[i].mask))
-		return(NULL);
-
-	if (++pos > argc--)
-		return(NULL);
-
-	if ('-' != *argv[pos]) 
-		e.match = cs ? MATCH_STRCASE : MATCH_STR;
-	else if (0 == strcmp("-eq", argv[pos]))
-		e.match = cs ? MATCH_STRCASE : MATCH_STR;
-	else if (0 == strcmp("-ieq", argv[pos]))
-		e.match = MATCH_STRCASE;
-	else if (0 == strcmp("-re", argv[pos]))
-		e.match = cs ? MATCH_REGEXCASE : MATCH_REGEX;
-	else if (0 == strcmp("-ire", argv[pos]))
-		e.match = MATCH_REGEXCASE;
-	else
-		return(NULL);
-
-	if ('-' == *argv[pos])
-		pos++;
-
-	if (pos > argc--)
-		return(NULL);
-
-	e.v = mandoc_strdup(argv[pos]);
-
-	if (MATCH_REGEX == e.match || MATCH_REGEXCASE == e.match) {
-		ch = REG_EXTENDED | REG_NOSUB;
-		if (MATCH_REGEXCASE == e.match)
-			ch |= REG_ICASE;
-		if (regcomp(&e.re, e.v, ch))
-			return(NULL);
-	}
-
-	p = mandoc_calloc(1, sizeof(struct expr));
-	memcpy(p, &e, sizeof(struct expr));
-	return(p);
-}
-
-void
-exprfree(struct expr *p)
-{
-
-	if (NULL == p)
-		return;
-
-	if (MATCH_REGEX == p->match)
-		regfree(&p->re);
-
-	free(p->v);
-	free(p);
-}
-
-static int
-exprexec(const struct expr *p, char *cp)
-{
-
-	if (MATCH_STR == p->match)
-		return(0 == strcmp(p->v, cp));
-	else if (MATCH_STRCASE == p->match)
-		return(0 == strcasecmp(p->v, cp));
-
-	assert(MATCH_REGEX == p->match);
-	return(0 == regexec(&p->re, cp, 0, NULL, 0));
-}
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-11-13 10:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-13 10:12 mdocml: Less misleading file names; ok kristaps@ schwarze

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).