aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2014-10-30 18:55:04 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2015-12-17 15:26:28 +0200
commit5ce27a8cdee32f53a922c459a4f9beae307543f7 (patch)
tree0e3d4c6e0a4b260df941bd160b5b47b3990a8b9f
parent59d4374b24e9f9f077f2e2e973fa75f3c3d505e0 (diff)
downloadgrecs-5ce27a8cdee32f53a922c459a4f9beae307543f7.tar.gz
grecs-5ce27a8cdee32f53a922c459a4f9beae307543f7.tar.bz2
wordsplit: improve docs, add new function
* src/wordsplit.c (wordsplit_getwords): New functon. * src/wordsplit.h (wordsplit_getwords): New proto. * doc/wordsplit.3: Add example section, document wordsplit_getwords.
-rw-r--r--doc/wordsplit.3145
-rw-r--r--src/wordsplit.c12
-rw-r--r--src/wordsplit.h13
3 files changed, 156 insertions, 14 deletions
diff --git a/doc/wordsplit.3 b/doc/wordsplit.3
index 123bfb7..3c666bc 100644
--- a/doc/wordsplit.3
+++ b/doc/wordsplit.3
@@ -32,6 +32,9 @@ wordsplit \- split string into words
.sp
\fBvoid wordsplit_free_words (wordsplit_t *\fIws\fB);\fR
.sp
+\fBvoid wordsplit_getwords (wordsplit_t *\fIws\fB,\
+ int *\fIwordc\fB, char ***\fIwordv\fB);
+.sp
\fBvoid wordsplit_perror (wordsplit_t *\fIws\fB);\fR
.sp
\fBconst char *wordsplit_strerror (wordsplit_t *\fIws\fB);\fR
@@ -80,6 +83,14 @@ wordsplit_free(&ws);
.EE
.PP
The function
+.B wordsplit_getwords
+returns in \fIwordv\fR an array of words, and in \fIwordc\fR the number
+of elements in \fIwordv\fR. The array can be used after calling
+.BR wordsplit_free .
+The caller becomes responsible for freeing the memory allocated for
+each element of the array and the array pointer itself.
+.PP
+The function
.B wordsplit_perror
prints error message from the last invocation of \fBwordsplit\fR. It
uses the function pointed to by the
@@ -401,6 +412,17 @@ from \fBwordsplit\fR.
Error code, if the invocation of \fBwordsplit\fR or
\fBwordsplit_len\fR failed. This is the same value as returned from
the function in that case.
+.PP
+The caller should not attempt to free or reallocate \fIws_wordv\fR or
+any elements thereof, nor to modify \fIws_wordc\fR.
+.PP
+To store away the words for use after freeing \fIws\fR with
+.BR wordsplit_free ,
+the caller should use
+.BR wordsplit_getwords .
+It is more effective than copying the contents of
+.I ws_wordv
+manually.
.SS INPUT
.TP
.BI "size_t " ws_offs
@@ -496,7 +518,8 @@ must have the form \fB\(dq\fINAME\fB=\fIVALUE\fR, where \fINAME\fR is
the name of the variable, and \fIVALUE\fR is its value.
Alternatively, if the \fBWRDSF_ENV_KV\fR flag is set, each variable is
described by two elements of
-.IR ws_env : one containing variable name, and the next one with its
+.IR ws_env :
+one containing variable name, and the next one with its
value.
.TP
.BI "int (*" ws_getvar ") (char **ret, const char *var, size_t len, void *clos)"
@@ -712,7 +735,7 @@ contains variable name, and
.IR ws_env [ "n+1" ]
contains its value.
.TP
-.B WRDSF_ESCAPE 0x10000000
+.B WRDSF_ESCAPE
.I ws_escape
is set.
.TP
@@ -831,17 +854,125 @@ returns a pointer to the constant string describing the last error
condition that occurred in
.IR ws .
.SH EXAMPLE
+The short program below implements a function that parses the
+input string similarly to the shell. All expansions are performed.
+Default error reporting is used.
+.PP
+.EX
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <wordsplit.h>
+
+/* Run command from \fIstr\fR (\fIlen\fR bytes long) and store its
+ output in \fIret\fR.
+ \fIargv\fR and \fIclosure\fR are not used.
+ Return wordsplit error code.
+ */
+static int runcmd(char **ret, const char *str, size_t len,
+ char **argv, void *closure)
+{
+ FILE *fp;
+ char *cmd;
+ int c, lastc;
+ char *buffer = NULL;
+ size_t bufsize = 0;
+ size_t buflen = 0;
+
+ /* Convert to a null-terminated string for \fBpopen\fR(3) */
+ cmd = malloc(len + 1);
+ if (!cmd)
+ return WRDSE_NOSPACE;
+ memcpy(cmd, str, len);
+ cmd[len] = 0;
+
+ fp = popen(cmd, "r");
+ if (!fp) {
+ char buf[128];
+
+ snprintf(buf, sizeof buf, "can't run %s: %s",
+ cmd, strerror(errno));
+ *ret = strdup(buf);
+ if (!*ret)
+ return WRDSE_NOSPACE;
+ else
+ return WRDSE_USERERR;
+ }
+
+ /* Collect the output, reallocating \fIbuffer\fR as needed. */
+ while ((c = fgetc(fp)) != EOF) {
+ lastc = c;
+ if (c == '\n')
+ c = ' ';
+ if (buflen == bufsize) {
+ char *p;
+
+ if (bufsize == 0)
+ bufsize = 80;
+ else
+ bufsize *= 2;
+ p = realloc(buffer, bufsize);
+ if (!p) {
+ free(buffer);
+ free(cmd);
+ return WRDSE_NOSPACE;
+ }
+ buffer = p;
+ }
+ buffer[buflen++] = c;
+ }
+
+ /* Tream off the trailing newline */
+ if (buffer) {
+ if (lastc == '\n')
+ --buflen;
+ buffer[buflen] = 0;
+ }
+
+ pclose(fp);
+ free(cmd);
+
+ /* Return the composed string. */
+ *ret = buffer;
+ return WRDSE_OK;
+}
+
+extern char **environ;
+
+/* Parse \fIs\fR much as shell does. Return the array of words on
+ succes, and NULL on error.
+ */
+char **shell_parse(char *s)
+{
+ wordsplit_t ws;
+ size_t wc;
+ char **wv;
+ int rc;
+
+ /* Initialize \fIws\fR */
+ ws.ws_env = (const char **) environ;
+ ws.ws_command = runcmd;
+ /* Call \fBwordsplit\fR. Let it report the errors. */
+ rc = wordsplit(s, &ws,
+ WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_PATHEXPAND
+ | WRDSF_SHOWERR);
+ if (rc == WRDSE_OK)
+ /* Store away the resulting words on success. */
+ wordsplit_getwords(&ws, &wc, &wv);
+ else
+ wv = NULL;
+ wordsplit_free(&ws);
+ return wv;
+}
+.EE
.SH "SEE ALSO"
.SH AUTHORS
Sergey Poznyakoff
.SH "BUG REPORTS"
Report bugs to <gray+grecs@gnu.org.ua>.
-.SH COLOPHON
-The \fBGrecs\fR library is constantly changing, so this manual page
-may be incorrect or out-of-date. For the latest copy of \fBGrecs\fR
-documentation, visit <http://www.gnu.org.ua/software/grecs>.
.SH COPYRIGHT
-Copyright \(co 2011 Sergey Poznyakoff
+Copyright \(co 2009-2014 Sergey Poznyakoff
.br
.na
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
diff --git a/src/wordsplit.c b/src/wordsplit.c
index 671fcb9..29547f6 100644
--- a/src/wordsplit.c
+++ b/src/wordsplit.c
@@ -2267,6 +2267,18 @@ wordsplit_free (struct wordsplit *ws)
wordsplit_free_envbuf (ws);
}
+void
+wordsplit_getwords (struct wordsplit *ws, int *wordc, char ***wordv)
+{
+ char **p = realloc (ws->ws_wordv,
+ (ws->ws_wordc + 1) * sizeof (ws->ws_wordv[0]));
+ *wordv = p ? p : ws->ws_wordv;
+ *wordc = ws->ws_wordc;
+ ws->ws_wordv = NULL;
+ ws->ws_wordc = 0;
+ ws->ws_wordn = 0;
+}
+
const char *_wordsplit_errstr[] = {
N_("no error"),
N_("missing closing quote"),
diff --git a/src/wordsplit.h b/src/wordsplit.h
index 5f36b1e..6b0c295 100644
--- a/src/wordsplit.h
+++ b/src/wordsplit.h
@@ -226,17 +226,16 @@ struct wordsplit
#define WRDSE_GLOBERR 8
#define WRDSE_USERERR 9
-int wordsplit (const char *s, wordsplit_t *p, int flags);
-int wordsplit_len (const char *s, size_t len,
- wordsplit_t *p, int flags);
-void wordsplit_free (wordsplit_t *p);
+int wordsplit (const char *s, wordsplit_t *ws, int flags);
+int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags);
+void wordsplit_free (wordsplit_t *ws);
void wordsplit_free_words (wordsplit_t *ws);
-void wordsplit_free_envbuf (struct wordsplit *ws);
+void wordsplit_free_envbuf (wordsplit_t *ws);
+void wordsplit_getwords (wordsplit_t *ws, int *wordc, char ***wordv);
int wordsplit_c_unquote_char (int c);
int wordsplit_c_quote_char (int c);
-size_t wordsplit_c_quoted_length (const char *str, int quote_hex,
- int *quote);
+size_t wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote);
void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex);
void wordsplit_perror (wordsplit_t *ws);

Return to:

Send suggestions and report system problems to the System administrator.