summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2014-09-14 19:44:28 +0000
committerIngo Schwarze <schwarze@openbsd.org>2014-09-14 19:44:28 +0000
commit129974c1f48bebaa4ccb4dc966694304e17bfb6f (patch)
tree22bb83ae72defb386c78542a9a87b4832bc4e896
parent8275a8e52fbf7fc40a4ad55c8d4ad9efe8f67058 (diff)
downloadmandoc-129974c1f48bebaa4ccb4dc966694304e17bfb6f.tar.gz
Support backslash-escaping of white space in the query expression,
to be more similar to apropos(1) called from the shell. Missing feature reported by Marcus MERIGHI <mcmer dash openbsd at tor dot at> on misc@.
-rw-r--r--cgi.c65
-rw-r--r--man.cgi.86
2 files changed, 38 insertions, 33 deletions
diff --git a/cgi.c b/cgi.c
index 882c33df..f02677a4 100644
--- a/cgi.c
+++ b/cgi.c
@@ -954,10 +954,10 @@ pg_search(const struct req *req)
struct mansearch search;
struct manpaths paths;
struct manpage *res;
- char **cp;
- const char *ep, *start;
+ char **argv;
+ char *query, *rp, *wp;
size_t ressz;
- int i, sz;
+ int argc;
/*
* Begin by chdir()ing into the root of the manpath.
@@ -982,46 +982,45 @@ pg_search(const struct req *req)
paths.paths[0] = mandoc_strdup(".");
/*
- * Poor man's tokenisation: just break apart by spaces.
- * Yes, this is half-ass. But it works for now.
+ * Break apart at spaces with backslash-escaping.
*/
- ep = req->q.query;
- while (ep && isspace((unsigned char)*ep))
- ep++;
-
- sz = 0;
- cp = NULL;
- while (ep && '\0' != *ep) {
- cp = mandoc_reallocarray(cp, sz + 1, sizeof(char *));
- start = ep;
- while ('\0' != *ep && ! isspace((unsigned char)*ep))
- ep++;
- cp[sz] = mandoc_malloc((ep - start) + 1);
- memcpy(cp[sz], start, ep - start);
- cp[sz++][ep - start] = '\0';
- while (isspace((unsigned char)*ep))
- ep++;
+ argc = 0;
+ argv = NULL;
+ rp = query = mandoc_strdup(req->q.query);
+ for (;;) {
+ while (isspace((unsigned char)*rp))
+ rp++;
+ if (*rp == '\0')
+ break;
+ argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *));
+ argv[argc++] = wp = rp;
+ for (;;) {
+ if (isspace((unsigned char)*rp)) {
+ *wp = '\0';
+ rp++;
+ break;
+ }
+ if (rp[0] == '\\' && rp[1] != '\0')
+ rp++;
+ if (wp != rp)
+ *wp = *rp;
+ if (*rp == '\0')
+ break;
+ wp++;
+ rp++;
+ }
}
- if (0 == mansearch(&search, &paths, sz, cp, &res, &ressz))
+ if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz))
pg_noresult(req, "You entered an invalid query.");
else if (0 == ressz)
pg_noresult(req, "No results found.");
else
pg_searchres(req, res, ressz);
- for (i = 0; i < sz; i++)
- free(cp[i]);
- free(cp);
-
- for (i = 0; i < (int)ressz; i++) {
- free(res[i].file);
- free(res[i].names);
- free(res[i].output);
- }
- free(res);
-
+ free(query);
+ mansearch_free(res, ressz);
free(paths.paths[0]);
free(paths.paths);
}
diff --git a/man.cgi.8 b/man.cgi.8
index 920330fd..39774070 100644
--- a/man.cgi.8
+++ b/man.cgi.8
@@ -43,6 +43,12 @@ either a name of a manual page or an
using the syntax described in the
.Xr apropos 1
manual; filling this in is required for each search.
+.Pp
+The expression is broken into words at whitespace.
+Whitespace characters and backslashes can be escaped
+by prepending a backslash.
+The effect of prepending a backslash to another character is undefined;
+in the current implementation, it has no effect.
.It
A
.Dq Submit