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.
This commit is contained in:
Sergey Poznyakoff 2014-10-30 18:55:04 +02:00
parent 943d725e7f
commit b712b11eef
3 changed files with 156 additions and 14 deletions

View file

@ -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>

View file

@ -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"),

View file

@ -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);