source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Integrate a moderately-patched version of schwarze@'s support
@ 2011-11-20 15:43 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2011-11-20 15:43 UTC (permalink / raw)
  To: source

Log Message:
-----------
Integrate a moderately-patched version of schwarze@'s support for multiple
directories containing mandocdb(8) databases.  Some changes follow:

 (1) don't support -M yet;
 (2) fall back to cwd if no prior manpath has been specified;
 (3) resolve manpages using realpath() to prevent consecutive chdir()'s
     over relative paths;
 (4) note where further error-reporting is required;
 (5) fix leaking memory on exit in several cases.

Modified Files:
--------------
    mdocml:
        apropos.1
        apropos.c
        apropos_db.c
        apropos_db.h

Revision Data
-------------
Index: apropos_db.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos_db.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -Lapropos_db.c -Lapropos_db.c -u -p -r1.7 -r1.8
--- apropos_db.c
+++ apropos_db.c
@@ -22,6 +22,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #ifdef __linux__
 # include <db_185.h>
@@ -64,6 +65,11 @@ struct	type {
 	const char	*name;
 };
 
+struct	rectree {
+	struct rec	*node; /* record array for dir tree */
+	int		 len; /* length of record array */
+};
+
 static	const struct type types[] = {
 	{ TYPE_An, "An" },
 	{ TYPE_Ar, "Ar" },
@@ -125,6 +131,9 @@ static	void	 norm_string(const char *,
 			const struct mchars *, char **);
 static	size_t	 norm_utf8(unsigned int, char[7]);
 static	void	 recfree(struct rec *);
+static	int	 single_search(struct rectree *, const struct opts *,
+			const struct expr *, size_t terms,
+			struct mchars *);
 
 /*
  * Open the keyword mandoc-db database.
@@ -365,46 +374,92 @@ index_read(const DBT *key, const DBT *va
 }
 
 /*
- * Search the mandocdb database for the expression "expr".
+ * Search mandocdb databases in argv (size argc) for the expression
+ * "expr".
  * Filter out by "opts".
  * Call "res" with the results, which may be zero.
  * Return 0 if there was a database error, else return 1.
  */
 int
-apropos_search(const struct opts *opts, const struct expr *expr,
-		size_t terms, void *arg, 
+apropos_search(int argc, char *argv[], const struct opts *opts,
+		const struct expr *expr, size_t terms, void *arg, 
 		void (*res)(struct res *, size_t, void *))
 {
-	int		 i, rsz, root, leaf, mlen, rc, ch;
+	struct rectree	 tree;
+	struct mchars	*mc;
+	struct res	*ress;
+	int		 i, mlen, rc;
+
+	memset(&tree, 0, sizeof(struct rectree));
+
+	mc = mchars_alloc();
+
+	for (rc = 1, i = 0; rc && i < argc; i++) {
+		/* FIXME: ugly warning: we shouldn't get here! */
+		if (chdir(argv[i]))
+			continue;
+		rc = single_search(&tree, opts, expr, terms, mc);
+		/* FIXME: warn and continue... ? */
+	}
+
+	/*
+	 * Count the matching files
+	 * and feed them to the output handler.
+	 */
+
+	for (mlen = i = 0; i < tree.len; i++)
+		if (tree.node[i].matched)
+			mlen++;
+
+	ress = mandoc_malloc(mlen * sizeof(struct res));
+
+	for (mlen = i = 0; i < tree.len; i++)
+		if (tree.node[i].matched)
+			memcpy(&ress[mlen++], &tree.node[i].res, 
+					sizeof(struct res));
+
+	(*res)(ress, mlen, arg);
+	free(ress);
+
+	for (i = 0; i < tree.len; i++)
+		recfree(&tree.node[i]);
+
+	free(tree.node);
+	mchars_free(mc);
+	return(rc);
+}
+
+static int
+single_search(struct rectree *tree, const struct opts *opts,
+		const struct expr *expr, size_t terms,
+		struct mchars *mc)
+{
+	int		 root, leaf, ch;
 	uint64_t	 mask;
 	DBT		 key, val;
 	DB		*btree, *idx;
-	struct mchars	*mc;
 	char		*buf;
 	recno_t		 rec;
 	struct rec	*rs;
-	struct res	*ress;
 	struct rec	 r;
 	struct db_val	*vbuf;
 
-	rc	= 0;
 	root	= -1;
 	leaf	= -1;
 	btree	= NULL;
 	idx	= NULL;
-	mc	= NULL;
 	buf	= NULL;
-	rs	= NULL;
-	rsz	= 0;
+	rs	= tree->node;
 
 	memset(&r, 0, sizeof(struct rec));
 
-	mc = mchars_alloc();
-
 	if (NULL == (btree = btree_open())) 
-		goto out;
-	if (NULL == (idx = index_open())) 
-		goto out;
+		return(0);
+
+	if (NULL == (idx = index_open())) {
+		(*btree->close)(btree);
+		return(0);
+	}
 
 	while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
  		if (key.size < 2 || sizeof(struct db_val) != val.size) 
@@ -474,62 +529,33 @@ apropos_search(const struct opts *opts, 
 		if (opts->arch && strcasecmp(opts->arch, r.res.arch))
 			continue;
 
-		rs = mandoc_realloc
-			(rs, (rsz + 1) * sizeof(struct rec));
+		tree->node = rs = mandoc_realloc
+			(rs, (tree->len + 1) * sizeof(struct rec));
 
-		memcpy(&rs[rsz], &r, sizeof(struct rec));
-		rs[rsz].matches = mandoc_calloc(terms, sizeof(int));
+		memcpy(&rs[tree->len], &r, sizeof(struct rec));
+		rs[tree->len].matches = 
+			mandoc_calloc(terms, sizeof(int));
 
-		exprexec(expr, buf, mask, &rs[rsz]); 
+		exprexec(expr, buf, mask, &rs[tree->len]); 
 		/* Append to our tree. */
 
 		if (leaf >= 0) {
 			if (rec > rs[leaf].res.rec)
-				rs[leaf].rhs = rsz;
+				rs[leaf].rhs = tree->len;
 			else
-				rs[leaf].lhs = rsz;
+				rs[leaf].lhs = tree->len;
 		} else
-			root = rsz;
+			root = tree->len;
 		
 		memset(&r, 0, sizeof(struct rec));
-		rsz++;
+		tree->len++;
 	}
 	
-	/*
-	 * If we haven't encountered any database errors, then construct
-	 * an array of results and push them to the caller.
-	 */
-
-	if (1 == ch) {
-		for (mlen = i = 0; i < rsz; i++)
-			if (rs[i].matched)
-				mlen++;
-		ress = mandoc_malloc(mlen * sizeof(struct res));
-		for (mlen = i = 0; i < rsz; i++)
-			if (rs[i].matched)
-				memcpy(&ress[mlen++], &rs[i].res, 
-						sizeof(struct res));
-		(*res)(ress, mlen, arg);
-		free(ress);
-		rc = 1;
-	}
-
-out:
-	for (i = 0; i < rsz; i++)
-		recfree(&rs[i]);
-
-	recfree(&r);
-
-	if (mc)
-		mchars_free(mc);
-	if (btree)
-		(*btree->close)(btree);
-	if (idx)
-		(*idx->close)(idx);
+	(*btree->close)(btree);
+	(*idx->close)(idx);
 
 	free(buf);
-	free(rs);
-	return(rc);
+	return(1 == ch);
 }
 
 static void
@@ -570,7 +596,7 @@ exprcomp(int argc, char *argv[], size_t 
  * Return the root of the expression sequence if alright.
  */
 static struct expr *
-exprexpr(int argc, char *argv[], int *pos, int *lvl, size_t *tt)
+exprexpr(int argc, char **argv, int *pos, int *lvl, size_t *tt)
 {
 	struct expr	*e, *first, *next;
 	int		 log;
Index: apropos_db.h
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos_db.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -Lapropos_db.h -Lapropos_db.h -u -p -r1.5 -r1.6
--- apropos_db.h
+++ apropos_db.h
@@ -35,7 +35,7 @@ __BEGIN_DECLS
 
 struct	expr;
 
-int	 	 apropos_search(const struct opts *, 
+int	 	 apropos_search(int, char **, const struct opts *, 
 			const struct expr *, size_t, void *, 
 			void (*)(struct res *, size_t, void *));
 struct	expr	*exprcomp(int, char *[], size_t *);
Index: apropos.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -Lapropos.c -Lapropos.c -u -p -r1.14 -r1.15
--- apropos.c
+++ apropos.c
@@ -1,6 +1,7 @@
 /*	$Id$ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -28,8 +29,18 @@
 #include "apropos_db.h"
 #include "mandoc.h"
 
+/*
+ * List of paths to be searched for manual databases.
+ */
+struct	manpaths {
+	int	  sz;
+	char	**paths;
+};
+
 static	int	 cmp(const void *, const void *);
 static	void	 list(struct res *, size_t, void *);
+static	int	 manpath_add(struct manpaths *, const char *);
+static	int	 manpath_parse(struct manpaths *, char *);
 static	void	 usage(void);
 
 static	char	*progname;
@@ -37,23 +48,32 @@ static	char	*progname;
 int
 main(int argc, char *argv[])
 {
-	int		 ch;
+	int		 i, ch, rc;
+	struct manpaths	 paths;
 	size_t		 terms;
 	struct opts	 opts;
 	struct expr	*e;
 	extern int	 optind;
 	extern char	*optarg;
 
-	memset(&opts, 0, sizeof(struct opts));
-
 	progname = strrchr(argv[0], '/');
 	if (progname == NULL)
 		progname = argv[0];
 	else
 		++progname;
 
-	while (-1 != (ch = getopt(argc, argv, "S:s:"))) 
+	memset(&paths, 0, sizeof(struct manpaths));
+	memset(&opts, 0, sizeof(struct opts));
+
+	e = NULL;
+	rc = 0;
+
+	while (-1 != (ch = getopt(argc, argv, "m:S:s:"))) 
 		switch (ch) {
+		case ('m'):
+			if ( ! manpath_parse(&paths, optarg))
+				goto out;
+			break;
 		case ('S'):
 			opts.arch = optarg;
 			break;
@@ -62,32 +82,40 @@ main(int argc, char *argv[])
 			break;
 		default:
 			usage();
-			return(EXIT_FAILURE);
+			goto out;
 		}
 
 	argc -= optind;
 	argv += optind;
 
-	if (0 == argc) 
-		return(EXIT_SUCCESS);
+	if (0 == argc) {
+		rc = 1;
+		goto out;
+	}
+
+	if (0 == paths.sz && ! manpath_add(&paths, "."))
+		goto out;
 
 	if (NULL == (e = exprcomp(argc, argv, &terms))) {
+		/* FIXME: be more specific about this. */
 		fprintf(stderr, "Bad expression\n");
-		return(EXIT_FAILURE);
+		goto out;
 	}
 
-	/*
-	 * Configure databases.
-	 * The keyword database is a btree that allows for duplicate
-	 * entries.
-	 * The index database is a recno.
-	 */
+	rc = apropos_search
+		(paths.sz, paths.paths, 
+		 &opts, e, terms, NULL, list);
+
+	/* FIXME: report an error based on ch. */
+
+out:
+	for (i = 0; i < paths.sz; i++)
+		free(paths.paths[i]);
 
-	ch = apropos_search(&opts, e, terms, NULL, list);
+	free(paths.paths);
 	exprfree(e);
-	if (0 == ch)
-		fprintf(stderr, "%s: Database error\n", progname);
-	return(ch ? EXIT_SUCCESS : EXIT_FAILURE);
+
+	return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
 }
 
 /* ARGSUSED */
@@ -118,6 +146,48 @@ static void
 usage(void)
 {
 
-	fprintf(stderr, "usage: %s [-S arch] [-s section] "
+	fprintf(stderr, "usage: %s "
+			"[-m dirs] "
+			"[-S arch] "
+			"[-s section] "
 			"expression...\n", progname);
+}
+
+/*
+ * Parse a FULL pathname from a colon-separated list of arrays.
+ */
+static int
+manpath_parse(struct manpaths *dirs, char *path) 
+{
+	char	*dir;
+
+	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
+		if ( ! manpath_add(dirs, dir))
+			return(0);
+
+	return(1);
+}
+
+/*
+ * Add a directory to the array.
+ * Grow the array one-by-one for simplicity's sake.
+ * Return 0 if the directory is not a real path.
+ */
+static int
+manpath_add(struct manpaths *dirs, const char *dir) 
+{
+	char		 buf[PATH_MAX];
+	char		*cp;
+
+	if (NULL == (cp = realpath(dir, buf))) {
+		fprintf(stderr, "%s: Invalid path\n", dir);
+		return(0);
+	}
+
+	dirs->paths = mandoc_realloc
+		(dirs->paths, 
+		 ((size_t)dirs->sz + 1) * sizeof(char *));
+
+	dirs->paths[dirs->sz++] = mandoc_strdup(cp);
+	return(1);
 }
Index: apropos.1
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos.1,v
retrieving revision 1.4
retrieving revision 1.5
diff -Lapropos.1 -Lapropos.1 -u -p -r1.4 -r1.5
--- apropos.1
+++ apropos.1
@@ -19,22 +19,28 @@
 .Os
 .Sh NAME
 .Nm apropos
-.Nd search the manual page database
+.Nd search manual page databases
 .Sh SYNOPSIS
 .Nm
+.Op Fl m Ar manpath
 .Op Fl S Ar arch
 .Op Fl s Ar section
 .Ar expression...
 .Sh DESCRIPTION
 The
 .Nm
-utility queries a manual page database generated by
+utility queries manual page databases generated by
 .Xr mandocdb 8 , 
 evaluating on
 .Ar expression
-for each file in the database.
+for each file in each database.
 Its arguments are as follows:
 .Bl -tag -width Ds
+.It Fl m Ar manpath
+A colon-separated list of paths containing
+.Xr mandocdb 8
+databases.
+Paths may be relative or absolute.
 .It Fl S Ar arch
 Search only for a particular architecture.
 .It Fl s Ar cat
@@ -105,6 +111,9 @@ is evaluated case-insensitively.
 .Pp
 By default,
 .Nm
+searches for
+.Xr mandocdb 8
+database in the current working directory and
 parses terms as case-sensitive regular expressions
 .Pq the Li \&~ operator
 over manual names and descriptions
--
 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-20 15:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-20 15:43 mdocml: Integrate a moderately-patched version of schwarze@'s support kristaps

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).