Improve wordsplit documentation and debug output.

This commit is contained in:
Sergey Poznyakoff 2014-10-24 22:41:25 +03:00
parent 731d730447
commit 73180a045d
2 changed files with 145 additions and 47 deletions

View file

@ -100,6 +100,43 @@ _wsplt_nomem (struct wordsplit *wsp)
return wsp->ws_errno;
}
static int wordsplit_run (const char *command, size_t length,
struct wordsplit *wsp,
int flags, int lvl);
static int
_wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss,
char const *str, int len,
int flags)
{
wss->ws_delim = wsp->ws_delim;
wss->ws_debug = wsp->ws_debug;
wss->ws_error = wsp->ws_error;
wss->ws_alloc_die = wsp->ws_alloc_die;
flags |= WRDSF_DELIM
| WRDSF_ALLOC_DIE
| WRDSF_ERROR
| WRDSF_DEBUG
| (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR));
return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1);
}
static void
_wsplt_seterr_sub (struct wordsplit *wsp, struct wordsplit *wss)
{
if (wsp->ws_errno == WRDSE_USERERR)
free (wsp->ws_usererr);
wsp->ws_errno = wss->ws_errno;
if (wss->ws_errno == WRDSE_USERERR)
{
wsp->ws_usererr = wss->ws_usererr;
wss->ws_errno = WRDSE_EOF;
wss->ws_usererr = NULL;
}
}
static void
wordsplit_init0 (struct wordsplit *wsp)
{
@ -429,10 +466,12 @@ wordsplit_dump_nodes (struct wordsplit *wsp)
for (p = wsp->ws_head, n = 0; p; p = p->next, n++)
{
if (p->flags & _WSNF_WORD)
wsp->ws_debug ("%4d: %p: %#04x (%s):%s;",
wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%s;",
wsp->ws_lvl,
n, p, p->flags, wsnode_flagstr (p->flags), p->v.word);
else
wsp->ws_debug ("%4d: %p: %#04x (%s):%.*s;",
wsp->ws_debug ("(%02d) %4d: %p: %#04x (%s):%.*s;",
wsp->ws_lvl,
n, p, p->flags, wsnode_flagstr (p->flags),
(int) (p->v.segm.end - p->v.segm.beg),
wsp->ws_input + p->v.segm.beg);
@ -897,14 +936,14 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
{
struct wordsplit ws;
int i, rc;
ws.ws_delim = wsp->ws_delim;
rc = wordsplit (value, &ws,
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM |
WRDSF_WS | WRDSF_QUOTE);
rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
WRDSF_NOVAR | WRDSF_NOCMD |
WRDSF_WS | WRDSF_QUOTE);
free (value);
if (rc)
{
_wsplt_seterr_sub (wsp, &ws);
wordsplit_free (&ws);
return 1;
}
@ -1076,11 +1115,17 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len,
{
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 = _wsplt_subsplit (wsp, &ws, str, j,
WRDSF_NOVAR | WRDSF_NOCMD |
WRDSF_WS | WRDSF_QUOTE);
if (rc)
{
_wsplt_seterr_sub (wsp, &ws);
wordsplit_free (&ws);
return 1;
}
rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure);
wordsplit_free (&ws);
}
else
rc = wsp->ws_command (&value, str, j, NULL, wsp->ws_closure);
@ -1125,13 +1170,13 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len,
struct wordsplit ws;
int i, rc;
ws.ws_delim = wsp->ws_delim;
rc = wordsplit (value, &ws,
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM |
WRDSF_WS | WRDSF_QUOTE);
rc = _wsplt_subsplit (wsp, &ws, value, strlen (value),
WRDSF_NOVAR | WRDSF_NOCMD |
WRDSF_WS | WRDSF_QUOTE);
free (value);
if (rc)
{
_wsplt_seterr_sub (wsp, &ws);
wordsplit_free (&ws);
return 1;
}
@ -1858,7 +1903,7 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
if (wsp->ws_flags & WRDSF_SHOWDBG)
{
wsp->ws_debug (_("Initial list:"));
wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _("Initial list:"));
wordsplit_dump_nodes (wsp);
}
@ -1873,7 +1918,8 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
break;
if (wsp->ws_flags & WRDSF_SHOWDBG)
{
wsp->ws_debug (_("Coalesced list:"));
wsp->ws_debug ("(%02d) %s", wsp->ws_lvl,
_("Coalesced list:"));
wordsplit_dump_nodes (wsp);
}
}
@ -1883,7 +1929,7 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
break;
if (wsp->ws_flags & WRDSF_SHOWDBG)
{
wsp->ws_debug ("%s:", _(p->descr));
wsp->ws_debug ("(%02d) %s", wsp->ws_lvl, _(p->descr));
wordsplit_dump_nodes (wsp);
}
}
@ -1892,9 +1938,9 @@ wordsplit_process_list (struct wordsplit *wsp, size_t start)
return wsp->ws_errno;
}
int
wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
int flags)
static int
wordsplit_run (const char *command, size_t length, struct wordsplit *wsp,
int flags, int lvl)
{
int rc;
size_t start;
@ -1923,10 +1969,11 @@ wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
rc = wordsplit_init (wsp, cmdptr, cmdlen, flags);
if (rc)
return rc;
wsp->ws_lvl = lvl;
}
if (wsp->ws_flags & WRDSF_SHOWDBG)
wsp->ws_debug (_("Input:%.*s;"), (int) cmdlen, cmdptr);
wsp->ws_debug (_("(%02d) Input:%.*s;"), wsp->ws_lvl, (int) cmdlen, cmdptr);
rc = wordsplit_process_list (wsp, start);
if (rc == 0 && (flags & WRDSF_INCREMENTAL))
@ -1938,7 +1985,8 @@ wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
{
cmdptr = wsp->ws_input + wsp->ws_endp;
cmdlen = wsp->ws_len - wsp->ws_endp;
wsp->ws_debug (_("Restart:%.*s;"), (int) cmdlen, cmdptr);
wsp->ws_debug (_("(%02d) Restart:%.*s;"),
wsp->ws_lvl, (int) cmdlen, cmdptr);
}
rc = wordsplit_process_list (wsp, start);
if (rc)
@ -1955,6 +2003,13 @@ wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
return wsp->ws_errno;
}
int
wordsplit_len (const char *command, size_t length, struct wordsplit *wsp,
int flags)
{
return wordsplit_run (command, length, wsp, flags, 0);
}
int
wordsplit (const char *command, struct wordsplit *ws, int flags)
{

View file

@ -19,39 +19,82 @@
#include <stddef.h>
struct wordsplit
/* Structure used to direct the splitting. Members marked with [Input]
can be defined before calling wordsplit(), those marked with [Output]
provide return values when the function returns. If neither mark is
used, the member is internal and must not be used by the caller.
In the comments below, the
identifiers in parentheses indicate bits that must be set (or unset, if
starting with !) in the ws_flags to initialize or use the given member.
If not redefined explicitly, most of them are set to some reasonable
default value upon entry to wordsplit(). */
struct wordsplit
{
size_t ws_wordc;
char **ws_wordv;
size_t ws_offs;
size_t ws_wordn;
int ws_flags;
int ws_options;
const char *ws_delim;
const char *ws_comment;
const char *ws_escape;
void (*ws_alloc_die) (struct wordsplit * wsp);
size_t ws_wordc; /* [Output] Number of words in ws_wordv. */
char **ws_wordv; /* [Output] Array of parsed out words. */
size_t ws_offs; /* [Input] (WRDSF_DOOFFS) Number of initial
elements in ws_wordv to fill with NULLs. */
size_t ws_wordn; /* Number of elements ws_wordv can accomodate. */
int ws_flags; /* [Input] Flags passed to wordsplit. */
int ws_options; /* [Input] (WRDSF_PATHEXPAND)
Additional options. */
const char *ws_delim; /* [Input] (WRDSF_DELIM) Word delimiters. */
const char *ws_comment; /* [Input] (WRDSF_COMMENT) Comment characters. */
const char *ws_escape; /* [Input] (WRDSF_ESCAPE) Characters to be escaped
with backslash. */
void (*ws_alloc_die) (struct wordsplit *wsp);
/* [Input] (WRDSF_ALLOC_DIE) Function called when
out of memory. Must not return. */
void (*ws_error) (const char *, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
/* [Input] (WRDSF_ERROR) Function used for error
reporting */
void (*ws_debug) (const char *, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
/* [Input] (WRDSF_DEBUG) Function used for debug
output. */
const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
environment variables. */
int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos);
/* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
the name VAR (LEN bytes long) in the table of
variables and if found returns in memory
location pointed to by RET the value of that
variable. Returns WRDSE_OK (0) on success,
and an error code (see WRDSE_* defines below)
on error. User-specific errors can be returned
by storing the error diagnostic string in RET
and returning WRDSE_USERERR.
Whatever is stored in RET, it must be allocated
using malloc(3). */
void *ws_closure; /* [Input] (WRDSF_CLOSURE) Passed as the CLOS
argument to ws_getvar and ws_command. */
int (*ws_command) (char **ret, const char *cmd, size_t len, char **argv,
void *clos);
/* [Input] (!WRDSF_NOCMD) Returns in the memory
location pointed to by RET the expansion of
the command CMD (LEN bytes nong). If WRDSF_ARGV
flag is set, ARGV contains CMD split out to
words. Otherwise ARGV is NULL.
const char **ws_env;
int (*ws_getvar) (char **, const char *, size_t, void *);
void *ws_closure;
int (*ws_command) (char **, const char *, size_t, char **, void *);
See ws_getvar for a discussion of possible
return values. */
const char *ws_input;
size_t ws_len;
size_t ws_endp;
int ws_errno;
char *ws_usererr;
const char *ws_input; /* Input string (the S argument to wordsplit. */
size_t ws_len; /* Length of ws_input. */
size_t ws_endp; /* Points past the last processed byte in
ws_input. */
int ws_errno; /* [Output] Error code, if an error occurred. */
char *ws_usererr; /* [Input/Output] Points to textual description of
the error, if ws_errno is WRDSE_USERERR. Must
be allocated with malloc(3). */
struct wordsplit_node *ws_head, *ws_tail;
/* Doubly-linked list of parsed out nodes. */
int ws_lvl; /* Invocation nesting level. */
};
/* Wordsplit flags. Only 1 bit of a 32-bit word remains unused.
It is getting crowded... */
/* Wordsplit flags. */
/* Append the words found to the array resulting from a previous
call. */
#define WRDSF_APPEND 0x00000001
@ -134,7 +177,7 @@ struct wordsplit
#define WRDSO_NULLGLOB 0x01
/* Print error message if path expansion produces empty string */
#define WRDSO_FAILGLOB 0x02
/* Allow a leading period to be matched by metacharacters. */
/* Allow a leading period to be matched by metacharacters. */
#define WRDSO_DOTGLOB 0x04
#define WRDSE_OK 0