source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Flip apropos to use mansearch instead of apropos_db.
@ 2012-06-08 10:44 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2012-06-08 10:44 UTC (permalink / raw)
  To: source

Log Message:
-----------
Flip apropos to use mansearch instead of apropos_db.
This makes the utility much smaller and simpler.
A lot of functionality has been omitted while the sqlite3 search routines
improve (logical operations, etc.).
It still needs work to make the output more conventional.
Also add the manpage utility, which I use extensively as a mind-meld of
apropos and man.

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

Added Files:
-----------
    mdocml:
        manpage.c

Revision Data
-------------
--- /dev/null
+++ manpage.c
@@ -0,0 +1,178 @@
+/*	$Id: manpage.c,v 1.1 2012/06/08 10:44:52 kristaps Exp $ */
+/*
+ * Copyright (c) 2012 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.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sys/param.h>
+
+#include <assert.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "manpath.h"
+#include "mansearch.h"
+
+static	void	 show(const char *, const char *);
+
+int
+main(int argc, char *argv[])
+{
+	int		 ch, term;
+	size_t		 i, sz, len;
+	struct manpage	*res;
+	char		*conf_file, *defpaths, *auxpaths, *cp,
+			*arch, *sec;
+	char		 buf[MAXPATHLEN];
+	const char	*cmd;
+	struct manpaths	 paths;
+	char		*progname;
+	extern char	*optarg;
+	extern int	 optind;
+
+	term = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
+
+	progname = strrchr(argv[0], '/');
+	if (progname == NULL)
+		progname = argv[0];
+	else
+		++progname;
+
+	auxpaths = defpaths = conf_file = arch = sec = NULL;
+	memset(&paths, 0, sizeof(struct manpaths));
+
+	while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
+		switch (ch) {
+		case ('C'):
+			conf_file = optarg;
+			break;
+		case ('M'):
+			defpaths = optarg;
+			break;
+		case ('m'):
+			auxpaths = optarg;
+			break;
+		case ('S'):
+			arch = optarg;
+			break;
+		case ('s'):
+			sec = optarg;
+			break;
+		default:
+			goto usage;
+		}
+
+	argc -= optind;
+	argv += optind;
+
+	if (0 == argc)
+		goto usage;
+
+	manpath_parse(&paths, conf_file, defpaths, auxpaths);
+	ch = mansearch(&paths, arch, sec, argc, argv, &res, &sz);
+	manpath_free(&paths);
+
+	if (0 == ch)
+		goto usage;
+
+	if (0 == sz) {
+		free(res);
+		return(EXIT_FAILURE);
+	} else if (1 == sz && term) {
+		i = 1;
+		goto show;
+	} else if (NULL == res)
+		return(EXIT_FAILURE);
+
+	for (i = 0; i < sz; i++) {
+		printf("%6zu  %s: %s\n", 
+			i + 1, res[i].file, res[i].desc);
+		free(res[i].desc);
+	}
+
+	if (0 == term) {
+		free(res);
+		return(EXIT_SUCCESS);
+	}
+
+	i = 1;
+	printf("Enter a choice [1]: ");
+	fflush(stdout);
+
+	if (NULL != (cp = fgetln(stdin, &len)))
+		if ('\n' == cp[--len] && len > 0) {
+			cp[len] = '\0';
+			if ((i = atoi(cp)) < 1 || i > sz)
+				i = 0;
+		}
+
+	if (0 == i) {
+		free(res);
+		return(EXIT_SUCCESS);
+	}
+show:
+	cmd = res[i - 1].form ? "mandoc" : "cat";
+	strlcpy(buf, res[i - 1].file, MAXPATHLEN);
+	free(res);
+
+	show(cmd, buf);
+	/* NOTREACHED */
+usage:
+	fprintf(stderr, "usage: %s [-C conf] "
+			 	  "[-M paths] "
+				  "[-m paths] "
+				  "[-S arch] "
+				  "[-s section] "
+			          "expr ...\n", 
+				  progname);
+	return(EXIT_FAILURE);
+}
+
+static void
+show(const char *cmd, const char *file)
+{
+	int		 fds[2];
+	pid_t		 pid;
+
+	if (-1 == pipe(fds)) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	}
+
+	if (-1 == (pid = fork())) {
+		perror(NULL);
+		exit(EXIT_FAILURE);
+	} else if (pid > 0) {
+		dup2(fds[0], STDIN_FILENO);
+		close(fds[1]);
+		cmd = NULL != getenv("MANPAGER") ? 
+			getenv("MANPAGER") :
+			(NULL != getenv("PAGER") ? 
+			 getenv("PAGER") : "more");
+		execlp(cmd, cmd, (char *)NULL);
+		perror(cmd);
+		exit(EXIT_FAILURE);
+	}
+
+	dup2(fds[1], STDOUT_FILENO);
+	close(fds[0]);
+	execlp(cmd, cmd, file, (char *)NULL);
+	perror(cmd);
+	exit(EXIT_FAILURE);
+}
Index: apropos.1
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos.1,v
retrieving revision 1.17
retrieving revision 1.18
diff -Lapropos.1 -Lapropos.1 -u -p -r1.17 -r1.18
--- apropos.1
+++ apropos.1
@@ -42,13 +42,11 @@ By default,
 searches for
 .Xr mandocdb 8
 databases in the default paths stipulated by
-.Xr man 1 ,
-parses terms as case-sensitive regular expressions
+.Xr man 1
+and
+parses terms as case-sensitive words
 over manual names and descriptions.
-Multiple terms imply pairwise
-.Fl o .
-If standard output is a TTY, a result may be selected from a list and
-its manual displayed with the pager.
+Multiple terms are OR'd.
 .Pp
 Its arguments are as follows:
 .Bl -tag -width Ds
@@ -81,41 +79,8 @@ for a listing of manual sections.
 .Pp
 An
 .Ar expression
-consists of search terms joined by logical operators
-.Fl a
-.Pq and
-and
-.Fl o
-.Pq or .
-The
-.Fl a
-operator has precedence over
-.Fl o
-and both are evaluated left-to-right.
-.Bl -tag -width Ds
-.It \&( Ar expr No \&)
-True if the subexpression
-.Ar expr
-is true.
-.It Ar expr1 Fl a Ar expr2
-True if both
-.Ar expr1
-and
-.Ar expr2
-are true (logical
-.Qq and ) .
-.It Ar expr1 Oo Fl o Oc Ar expr2
-True if
-.Ar expr1
-and/or
-.Ar expr2
-evaluate to true (logical
-.Qq or ) .
-.It Ar term
-True if
-.Ar term
-is satisfied.
-This has syntax
+consists of type and keyword pairs.
+This pair syntax
 .Li [key[,key]*(=~)]?val ,
 where operand
 .Cm key
@@ -129,22 +94,15 @@ See
 for a list of available keys.
 Operator
 .Li \&=
-evaluates a substring, while
+evaluates a full string, while
 .Li \&~
-evaluates a regular expression.
-.It Fl i Ar term
-If
-.Ar term
-is a regular expression, it
-is evaluated case-insensitively.
-Has no effect on substring terms.
-.El
+evaluates a
+.Xr glob 7
+pattern.
 .Pp
 Results are sorted by manual title, with output formatted as
-.Pp
-.D1 title(sec) \- description
-.Pp
-Where
+.Qq title(sec) \- description
+where
 .Qq title
 is the manual's title (note multiple manual names may exist for one
 title),
@@ -153,24 +111,7 @@ is the manual section, and
 .Qq description
 is the manual's short description.
 If an architecture is specified for the manual, it is displayed as
-.Pp
-.D1 title(cat/arch) \- description
-.Pp
-If on a TTY, results are prefixed with a numeric identifier.
-.Pp
-.D1 [index] title(cat) \- description
-.Pp
-One may choose a manual be entering the index at the prompt.
-Valid choices are displayed using
-.Ev MANPAGER ,
-or failing that ,
-.Ev PAGER
-or just
-.Xr more 1 .
-Source pages are formatted with
-.Xr mandoc 1 ;
-preformatted pages with
-.Xr cat 1 .
+.Qq title(cat/arch) \- description .
 .Ss Macro Keys
 Queries evaluate over a subset of
 .Xr mdoc 7
@@ -248,14 +189,6 @@ Text production:
 .El
 .Sh ENVIRONMENT
 .Bl -tag -width Ds
-.It Ev MANPAGER
-Default pager for manuals.
-If this is unset, falls back to
-.Ev Pager .
-.It Ev PAGER
-The second choice for a manual pager.
-If this is unset, use
-.Xr more 1 .
 .It Ev MANPATH
 Colon-separated paths modifying the default list of paths searched for
 manual databases.
@@ -294,31 +227,30 @@ configuration file
 .Sh EXAMPLES
 Search for
 .Qq mdoc
-as a substring and regular expression
-within each manual name and description:
+as a word or
+.Xr glob 7
+expression:
 .Pp
 .Dl $ apropos mdoc
-.Dl $ apropos ~^mdoc$
+.Dl $ apropos any~mdoc*
 .Pp
 Include matches for
 .Qq roff
 and
 .Qq man
-for the regular expression case:
+using
+.Xr glob 7
+expressions:
 .Pp
-.Dl $ apropos ~^mdoc$ roff man
-.Dl $ apropos ~^mdoc$ \-o roff \-o man
+.Dl $ apropos ~*mdoc* ~*roff*
 .Pp
 Search for
-.Qq optind
-and
 .Qq optarg
-as variable names in the library category:
+as a variable name in the library category:
 .Pp
-.Dl $ apropos \-s 3 Va~^optind \-a Va~^optarg$
+.Dl $ apropos \-s 3 Va=optarg
 .Sh SEE ALSO
-.Xr more 1
-.Xr re_format 7 ,
+.Xr glob 7 ,
 .Xr mandocdb 8
 .Sh AUTHORS
 The
Index: apropos.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/apropos.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -Lapropos.c -Lapropos.c -u -p -r1.30 -r1.31
--- apropos.c
+++ apropos.c
@@ -1,7 +1,6 @@
 /*	$Id$ */
 /*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012 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
@@ -27,38 +26,21 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "apropos_db.h"
-#include "mandoc.h"
 #include "manpath.h"
-
-#define	SINGLETON(_res, _sz) \
-	((_sz) && (_res)[0].matched && \
-	 (1 == (_sz) || 0 == (_res)[1].matched))
-#define	EMPTYSET(_res, _sz) \
-	((0 == (_sz)) || 0 == (_res)[0].matched)
-
-static	int	 cmp(const void *, const void *);
-static	void	 list(struct res *, size_t, void *);
-static	void	 usage(void);
-
-static	char	*progname;
+#include "mansearch.h"
 
 int
 main(int argc, char *argv[])
 {
-	int		 ch, rc, whatis, usecat;
-	struct res	*res;
+	int		 ch;
+	size_t		 i, sz;
+	struct manpage	*res;
+	char		*conf_file, *defpaths, *auxpaths,
+			*arch, *sec;
 	struct manpaths	 paths;
-	const char	*prog;
-	pid_t		 pid;
-	char		 path[PATH_MAX];
-	int		 fds[2];
-	size_t		 terms, ressz, sz;
-	struct opts	 opts;
-	struct expr	*e;
-	char		*defpaths, *auxpaths, *conf_file, *cp;
-	extern int	 optind;
+	char		*progname;
 	extern char	*optarg;
+	extern int	 optind;
 
 	progname = strrchr(argv[0], '/');
 	if (progname == NULL)
@@ -66,18 +48,8 @@ main(int argc, char *argv[])
 	else
 		++progname;
 
-	whatis = 0 == strncmp(progname, "whatis", 6);
-
+	auxpaths = defpaths = conf_file = arch = sec = NULL;
 	memset(&paths, 0, sizeof(struct manpaths));
-	memset(&opts, 0, sizeof(struct opts));
-
-	usecat = 0;
-	ressz = 0;
-	res = NULL;
-	auxpaths = defpaths = NULL;
-	conf_file = NULL;
-	e = NULL;
-	path[0] = '\0';
 
 	while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
 		switch (ch) {
@@ -91,149 +63,42 @@ main(int argc, char *argv[])
 			auxpaths = optarg;
 			break;
 		case ('S'):
-			opts.arch = optarg;
+			arch = optarg;
 			break;
 		case ('s'):
-			opts.cat = optarg;
+			sec = optarg;
 			break;
 		default:
-			usage();
-			return(EXIT_FAILURE);
+			goto usage;
 		}
 
 	argc -= optind;
 	argv += optind;
 
-	if (0 == argc) 
-		return(EXIT_SUCCESS);
-
-	rc = 0;
+	if (0 == argc)
+		goto usage;
 
 	manpath_parse(&paths, conf_file, defpaths, auxpaths);
-
-	e = whatis ? termcomp(argc, argv, &terms) :
-		     exprcomp(argc, argv, &terms);
-		
-	if (NULL == e) {
-		fprintf(stderr, "%s: Bad expression\n", progname);
-		goto out;
-	}
-
-	rc = apropos_search
-		(paths.sz, paths.paths, &opts, 
-		 e, terms, NULL, &ressz, &res, list);
-
-	terms = 1;
-
-	if (0 == rc) {
-		fprintf(stderr, "%s: Bad database\n", progname);
-		goto out;
-	} else if ( ! isatty(STDOUT_FILENO) || EMPTYSET(res, ressz))
-		goto out;
-
-	if ( ! SINGLETON(res, ressz)) {
-		printf("Which manpage would you like [1]? ");
-		fflush(stdout);
-		if (NULL != (cp = fgetln(stdin, &sz)) && 
-				sz > 1 && '\n' == cp[--sz]) {
-			if ((ch = atoi(cp)) <= 0)
-				goto out;
-			terms = (size_t)ch;
-		}
-	}
-
-	if (--terms < ressz && res[terms].matched) {
-		chdir(paths.paths[res[terms].volume]);
-		strlcpy(path, res[terms].file, PATH_MAX);
-		usecat = RESTYPE_CAT == res[terms].type;
-	}
-out:
+	ch = mansearch(&paths, arch, sec, argc, argv, &res, &sz);
 	manpath_free(&paths);
-	resfree(res, ressz);
-	exprfree(e);
 
-	if ('\0' == path[0])
-		return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
+	if (0 == ch)
+		goto usage;
 
-	if (-1 == pipe(fds)) {
-		perror(NULL);
-		exit(EXIT_FAILURE);
+	for (i = 0; i < sz; i++) {
+		printf("%s - %s\n", res[i].file, res[i].desc);
+		free(res[i].desc);
 	}
 
-	if (-1 == (pid = fork())) {
-		perror(NULL);
-		exit(EXIT_FAILURE);
-	} else if (pid > 0) {
-		dup2(fds[0], STDIN_FILENO);
-		close(fds[1]);
-		prog = NULL != getenv("MANPAGER") ? 
-			getenv("MANPAGER") :
-			(NULL != getenv("PAGER") ? 
-			 getenv("PAGER") : "more");
-		execlp(prog, prog, (char *)NULL);
-		perror(prog);
-		return(EXIT_FAILURE);
-	}
-
-	dup2(fds[1], STDOUT_FILENO);
-	close(fds[0]);
-	prog = usecat ? "cat" : "mandoc";
-	execlp(prog, prog, path, (char *)NULL);
-	perror(prog);
+	free(res);
+	return(sz ? EXIT_SUCCESS : EXIT_FAILURE);
+usage:
+	fprintf(stderr, "usage: %s [-C conf] "
+			 	  "[-M paths] "
+				  "[-m paths] "
+				  "[-S arch] "
+				  "[-s section] "
+			          "expr ...\n", 
+				  progname);
 	return(EXIT_FAILURE);
-}
-
-/* ARGSUSED */
-static void
-list(struct res *res, size_t sz, void *arg)
-{
-	size_t		 i;
-
-	qsort(res, sz, sizeof(struct res), cmp);
-
-	if (EMPTYSET(res, sz) || SINGLETON(res, sz))
-		return;
-
-	if ( ! isatty(STDOUT_FILENO))
-		for (i = 0; i < sz && res[i].matched; i++)
-			printf("%s(%s%s%s) - %.70s\n", 
-					res[i].title, res[i].cat,
-					*res[i].arch ? "/" : "",
-					*res[i].arch ? res[i].arch : "",
-					res[i].desc);
-	else
-		for (i = 0; i < sz && res[i].matched; i++)
-			printf("[%zu] %s(%s%s%s) - %.70s\n", i + 1,
-					res[i].title, res[i].cat,
-					*res[i].arch ? "/" : "",
-					*res[i].arch ? res[i].arch : "",
-					res[i].desc);
-}
-
-static int
-cmp(const void *p1, const void *p2)
-{
-	const struct res *r1 = p1;
-	const struct res *r2 = p2;
-
-	if (0 == r1->matched)
-		return(1);
-	else if (0 == r2->matched)
-		return(1);
-
-	return(strcasecmp(r1->title, r2->title));
-}
-
-static void
-usage(void)
-{
-
-	fprintf(stderr, "usage: %s "
-			"[-C file] "
-			"[-M manpath] "
-			"[-m manpath] "
-			"[-S arch] "
-			"[-s section] "
-			"expression ...\n",
-			progname);
 }
--
 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:[~2012-06-08 10:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-08 10:44 mdocml: Flip apropos to use mansearch instead of apropos_db 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).