diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-10-23 12:12:02 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-12-17 15:25:24 +0200 |
commit | e66e2edfa50c8535e05b334c6a5d867fafeb9469 (patch) | |
tree | 5af187dea3750df11c404658c624300bae324d97 | |
parent | beda81512afdcf16432ebd5b76930392f427a7fc (diff) | |
download | grecs-e66e2edfa50c8535e05b334c6a5d867fafeb9469.tar.gz grecs-e66e2edfa50c8535e05b334c6a5d867fafeb9469.tar.bz2 |
Change prototypes of ws_getvar and ws_command.
New invocation sequence ensures proper error handling.
This is an incompatible change. Authors using ws_getvar member will
have to rewrite their ws_getvar function accordingly.
* src/wordsplit.c (wordsplit_init0): Call wordsplit_clearerr
on reuse.
(wordsplit_init): Fix ws_errno
(expvar): Change invocation of ws_getvar.
(expcmd): Change invocation of ws_command.
(wordsplit_clearerr): New function.
(wordsplit_strerror): Handle WRDSE_USERERR.
* src/wordsplit.h (ws_getvar): Change return value and signature of
ws_getvar and ws_command.
New member 'ws_usererr'.
(WRDSF_ARGV): New flag.
(WRDSE_OK): New define. Same as WRDSE_EOF.
(WRDSE_USERERR): New error code.
(wordsplit_clearerr): New proto.
* tests/wsp.c (wsp_getvar, wsp_runcmd): Rewrite.
-rw-r--r-- | src/wordsplit.c | 67 | ||||
-rw-r--r-- | src/wordsplit.h | 14 | ||||
-rw-r--r-- | tests/wsp.c | 50 |
3 files changed, 104 insertions, 27 deletions
diff --git a/src/wordsplit.c b/src/wordsplit.c index f17ed98..2b99b42 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c @@ -96,6 +96,7 @@ wordsplit_init0 (struct wordsplit *wsp) { if (!(wsp->ws_flags & WRDSF_APPEND)) wordsplit_free_words (wsp); + wordsplit_clearerr (wsp); } else { @@ -134,7 +135,7 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, if (!wsp->ws_command) { errno = EINVAL; - wsp->ws_errno = WRDSE_NOSUPP; + wsp->ws_errno = WRDSE_USAGE; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return wsp->ws_errno; @@ -786,7 +787,30 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, return _wsplt_nomem (wsp); } else if (wsp->ws_flags & WRDSF_GETVAR) - value = wsp->ws_getvar (str, i, wsp->ws_closure); + { + int rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure); + switch (rc) + { + case WRDSE_OK: + break; + + case WRDSE_NOSPACE: + return _wsplt_nomem (wsp); + + case WRDSE_UNDEF: + value = NULL; + break; + + case WRDSE_USERERR: + wsp->ws_usererr = value; + /* fall through */ + default: + wsp->ws_errno = rc; + if (wsp->ws_flags & WRDSF_SHOWERR) + wordsplit_perror (wsp); + return 1; + } + } else value = NULL; @@ -818,7 +842,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, else if (wsp->ws_flags & WRDSF_UNDEF) { wsp->ws_errno = WRDSE_UNDEF; - if (wsp->ws_flags & WRDSF_SHOWERR) + if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return 1; } @@ -1033,6 +1057,7 @@ static int expcmd (struct wordsplit *wsp, const char *str, size_t len, struct wordsplit_node **ptail, const char **pend, int flg) { + int rc; size_t j; char *value; struct wordsplit_node *newnode; @@ -1047,7 +1072,30 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len, } *pend = str + j; - value = wsp->ws_command (str, j, wsp); + if (wsp->ws_flags & WRDSF_ARGV) + { + struct wordsplit ws; + + ws.ws_delim = wsp->ws_delim; + rc = wordsplit_len (str, j, &ws, + WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM | + (wsp->ws_flags & (WRDSF_WS | WRDSF_QUOTE))); + rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure); + } + else + rc = wsp->ws_command (&value, str, j, NULL, wsp->ws_closure); + + if (rc == WRDSE_NOSPACE) + return _wsplt_nomem (wsp); + else if (rc) + { + if (rc == WRDSE_USERERR) + wsp->ws_usererr = value; + wsp->ws_errno = rc; + if (wsp->ws_flags & WRDSF_SHOWERR) + wordsplit_perror (wsp); + return 1; + } if (value) { @@ -1752,6 +1800,15 @@ wordsplit_free_words (struct wordsplit *ws) } void +wordsplit_clearerr (struct wordsplit *ws) +{ + if (ws->ws_errno == WRDSE_USERERR) + free (ws->ws_usererr); + ws->ws_usererr = NULL; + ws->ws_errno = WRDSE_OK; +} + +void wordsplit_free (struct wordsplit *ws) { wordsplit_free_words (ws); @@ -1819,6 +1876,8 @@ int _wordsplit_nerrs = const char * wordsplit_strerror (struct wordsplit *ws) { + if (ws->ws_errno == WRDSE_USERERR) + return ws->ws_usererr; if (ws->ws_errno < _wordsplit_nerrs) return _wordsplit_errstr[ws->ws_errno]; return N_("unknown error"); diff --git a/src/wordsplit.h b/src/wordsplit.h index 96088f9..4a0cd88 100644 --- a/src/wordsplit.h +++ b/src/wordsplit.h @@ -36,19 +36,20 @@ struct wordsplit __attribute__ ((__format__ (__printf__, 1, 2))); const char **ws_env; - char *(*ws_getvar) (const char *, size_t, void *); + int (*ws_getvar) (char **, const char *, size_t, void *); void *ws_closure; - char *(*ws_command) (const char *, size_t, struct wordsplit const *); + int (*ws_command) (char **, const char *, size_t, char **, void *); const char *ws_input; size_t ws_len; size_t ws_endp; int ws_errno; + char *ws_usererr; struct wordsplit_node *ws_head, *ws_tail; }; -/* Wordsplit flags. Only 2 bits of a 32-bit word remain unused. +/* Wordsplit flags. Only 1 bit of a 32-bit word remains unused. It is getting crowded... */ /* Append the words found to the array resulting from a previous call. */ @@ -125,10 +126,14 @@ struct wordsplit /* Incremental mode */ #define WRDSF_INCREMENTAL 0x20000000 +/* ws_command needs argv parameter */ +#define WRDSF_ARGV 0x40000000 + #define WRDSF_DEFFLAGS \ (WRDSF_NOVAR | WRDSF_NOCMD | \ WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES) +#define WRDSE_OK 0 #define WRDSE_EOF 0 #define WRDSE_QUOTE 1 #define WRDSE_NOSPACE 2 @@ -137,6 +142,7 @@ struct wordsplit #define WRDSE_CBRACE 5 #define WRDSE_UNDEF 6 #define WRDSE_NOINPUT 7 +#define WRDSE_USERERR 8 int wordsplit (const char *s, struct wordsplit *p, int flags); int wordsplit_len (const char *s, size_t len, @@ -157,5 +163,7 @@ void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex); void wordsplit_perror (struct wordsplit *ws); const char *wordsplit_strerror (struct wordsplit *ws); +void wordsplit_clearerr (struct wordsplit *ws); + #endif diff --git a/tests/wsp.c b/tests/wsp.c index 6fb61da..f01f6b6 100644 --- a/tests/wsp.c +++ b/tests/wsp.c @@ -22,6 +22,7 @@ #include <string.h> #include <assert.h> #include <errno.h> +#include "grecs.h" #include "wordsplit.h" extern char **environ; @@ -163,8 +164,8 @@ make_env_kv () return newenv; } -static char * -wsp_getvar (const char *vptr, size_t vlen, void *data) +static int +wsp_getvar (char **ret, const char *vptr, size_t vlen, void *data) { char **base = data; int i; @@ -175,15 +176,17 @@ wsp_getvar (const char *vptr, size_t vlen, void *data) if (l == vlen && memcmp (base[i], vptr, vlen) == 0) { char *p = strdup (base[i] + vlen + 1); - assert (p != NULL); - return p; + if (p == NULL) + return WRDSE_NOSPACE; + *ret = p; + return WRDSE_OK; } } - return NULL; + return WRDSE_UNDEF; } -static char * -wsp_runcmd (const char *str, size_t len, struct wordsplit const *parent) +static int +wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure) { FILE *fp; char *cmd; @@ -194,18 +197,20 @@ wsp_runcmd (const char *str, size_t len, struct wordsplit const *parent) cmd = malloc (len + 1); if (!cmd) - { - parent->ws_error ("memory exhausted"); - abort (); - } + return WRDSE_NOSPACE; memcpy (cmd, str, len); cmd[len] = 0; fp = popen(cmd, "r"); if (!fp) { - parent->ws_error ("can't run %s: %s", cmd, strerror (errno)); - return NULL; + size_t size = 0; + ret = NULL; + if (grecs_asprintf (ret, &size, "can't run %s: %s", + cmd, strerror (errno))) + return WRDSE_NOSPACE; + else + return WRDSE_USERERR; } while ((c = fgetc (fp)) != EOF) @@ -215,16 +220,20 @@ wsp_runcmd (const char *str, size_t len, struct wordsplit const *parent) c = ' '; if (buflen == bufsize) { + char *p; + if (bufsize == 0) bufsize = 80; else bufsize *= 2; - buffer = realloc (buffer, bufsize); - if (!buffer) + p = realloc (buffer, bufsize); + if (!p) { - parent->ws_error ("can't run %s: %s", cmd, strerror (errno)); - return NULL; + free (buffer); + free (cmd); + return WRDSE_NOSPACE; } + buffer = p; } buffer[buflen++] = c; } @@ -236,10 +245,11 @@ wsp_runcmd (const char *str, size_t len, struct wordsplit const *parent) buffer[buflen] = 0; } - close (fp); + pclose (fp); free (cmd); - return buffer; + *ret = buffer; + return WRDSE_OK; } int @@ -379,7 +389,7 @@ main (int argc, char **argv) continue; } - if (strchr(opt, '=')) + if (strchr (opt, '=')) { assert (fenvidx < fenvmax - 1); fenvbase[fenvidx++] = opt; |