mirror of
git://git.gnu.org.ua/wordsplit.git
synced 2025-04-26 00:29:54 +03:00
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.
This commit is contained in:
parent
2795912aa5
commit
4650905537
3 changed files with 104 additions and 27 deletions
|
@ -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)
|
||||
{
|
||||
|
@ -1751,6 +1799,15 @@ wordsplit_free_words (struct wordsplit *ws)
|
|||
ws->ws_wordc = 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
50
tests/wsp.c
50
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue