diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-06-20 09:45:03 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-06-20 09:58:05 +0300 |
commit | 9fd53c66bea84680ac782879c5095608c14d9f4a (patch) | |
tree | ded282a00341d32ddab43b6ab694197ef96eceae | |
parent | 681919ac19e607566def43cf319e65213fc4cf6d (diff) | |
download | smap-9fd53c66bea84680ac782879c5095608c14d9f4a.tar.gz smap-9fd53c66bea84680ac782879c5095608c14d9f4a.tar.bz2 |
Improve wordsplit.
* include/smap/wordsplit.h (wordsplit)<ws_errno>: New member.
(WRDSE_NOSUPP): New define.
(wordsplit_perror,wordsplit_strerror): New prototypes.
* lib/wordsplit.c (all functions): use wordsplit_perror
for diagnostics if WRDSF_SHOWERR is set; set ws_errno to
the actual error code before returning error.
(scan_word): Revise and fix return values.
(wordsplit_len): Correctly handle errors, in particular
WRDSE_QUOTE.
(wordsplit_perror, wordsplit_strerror): New functions.
* src/cfg.c (parse_config_loop): Use wordsplit_strerror
for diagnostics.
* src/module.c (smap_modules_init): Likewise.
* src/smapc.c (read_eval_loop): Use wordsplit_perror for
diagnostics.
-rw-r--r-- | include/smap/wordsplit.h | 6 | ||||
-rw-r--r-- | lib/wordsplit.c | 104 | ||||
-rw-r--r-- | src/cfg.c | 23 | ||||
-rw-r--r-- | src/module.c | 2 | ||||
-rw-r--r-- | src/smapc.c | 4 |
5 files changed, 110 insertions, 29 deletions
diff --git a/include/smap/wordsplit.h b/include/smap/wordsplit.h index 59c3ca3..92eb264 100644 --- a/include/smap/wordsplit.h +++ b/include/smap/wordsplit.h @@ -34,6 +34,7 @@ struct wordsplit const char *ws_input; size_t ws_len; size_t ws_endp; + int ws_errno; }; /* Append the words found to the array resulting from a previous @@ -85,6 +86,7 @@ struct wordsplit #define WRDSE_EOF 0 #define WRDSE_QUOTE 1 #define WRDSE_NOSPACE 2 +#define WRDSE_NOSUPP 3 int wordsplit(const char *s, struct wordsplit *p, int flags); void wordsplit_free(struct wordsplit *p); @@ -95,4 +97,8 @@ size_t wordsplit_quoted_length(const char *str, int quote_hex, int *quote); void wordsplit_unquote_copy(char *dst, const char *src, size_t n); void wordsplit_quote_copy(char *dst, const char *src, int quote_hex); +void wordsplit_perror(struct wordsplit *ws); +const char *wordsplit_strerror(struct wordsplit *ws); + + #endif diff --git a/lib/wordsplit.c b/lib/wordsplit.c index b266f93..39b3137 100644 --- a/lib/wordsplit.c +++ b/lib/wordsplit.c @@ -34,6 +34,7 @@ # define gettext(s) s #endif #define _(msgid) gettext(msgid) +#define N_(msgid) msgid #define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n') #define ISDELIM(c,delim) (strchr(delim,(c))!=NULL) @@ -83,12 +84,11 @@ wordsplit_init(struct wordsplit *wsp, const char *input, size_t len, if ((wsp->ws_flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD)) { - if (wsp->ws_flags & WRDSF_SHOWERR) - wsp->ws_error(_("variable expansion and " - "command substitution " - "are not yet supported")); errno = EINVAL; - return 1; + wsp->ws_errno = WRDSE_NOSUPP; + if (wsp->ws_flags & WRDSF_SHOWERR) + wordsplit_perror(wsp); + return wsp->ws_errno; } wsp->ws_input = input; @@ -140,12 +140,13 @@ alloc_space(struct wordsplit *wsp) wsp->ws_wordn = newalloc; wsp->ws_wordv = ptr; } else { + errno = ENOMEM; + wsp->ws_errno = WRDSE_NOSPACE; if (wsp->ws_flags & WRDSF_ENOMEMABRT) wsp->ws_alloc_die(wsp); else if (wsp->ws_flags & WRDSF_SHOWERR) - wsp->ws_error(_("memory exhausted")); - errno = ENOMEM; - return 1; + wordsplit_perror(wsp); + return wsp->ws_errno; } return 0; } @@ -199,8 +200,10 @@ skip_delim(struct wordsplit *wsp) return start; } +#define _WRDS_EOF 0 #define _WRDS_WORD 1 #define _WRDS_CONT 2 +#define _WRDS_ERR 3 static int scan_word(struct wordsplit *wsp, size_t *pstart, size_t *pend) @@ -213,14 +216,18 @@ scan_word(struct wordsplit *wsp, size_t *pstart, size_t *pend) size_t i = start; - if (i >= len) - return WRDSE_EOF; - + if (i >= len) { + wsp->ws_errno = WRDSE_EOF; + return _WRDS_EOF; + } + if (wsp->ws_flags & WRDSF_WS) { /* Skip initial whitespace */ while (ISWS(command[i])) - if (++i == len) - return WRDSE_EOF; + if (++i == len) { + wsp->ws_errno = WRDSE_EOF; + return _WRDS_EOF; + } } start = i; @@ -262,12 +269,13 @@ scan_word(struct wordsplit *wsp, size_t *pstart, size_t *pend) && command[j] == command[i]) i = j + 1; else { + *pstart = start; + *pend = i; wsp->ws_endp = i; + wsp->ws_errno = WRDSE_QUOTE; if (wsp->ws_flags & WRDSF_SHOWERR) - wsp->ws_error( - _("missing closing %c (start near #%lu)"), - command[i], (unsigned long) i); - return WRDSE_QUOTE; + wordsplit_perror(wsp); + return _WRDS_ERR; } } } @@ -475,7 +483,7 @@ wordsplit_len(const char *command, size_t len, struct wordsplit *wsp, if (rc) return rc; - for (; (rc = scan_word(wsp, &start, &end)) > 0; + for (; (rc = scan_word(wsp, &start, &end)) != _WRDS_EOF; start = skip_delim(wsp)) { int unquote = 1; size_t n; @@ -483,9 +491,11 @@ wordsplit_len(const char *command, size_t len, struct wordsplit *wsp, if (rc == _WRDS_CONT) continue; + if (rc == _WRDS_ERR) + break; if (alloc_space(wsp)) - return WRDSE_NOSPACE; + return wsp->ws_errno; n = end - start; @@ -502,16 +512,17 @@ wordsplit_len(const char *command, size_t len, struct wordsplit *wsp, } else unquote = 0; - p = malloc (n + 1); + p = malloc(n + 1); if (!p) { + errno = ENOMEM; + wsp->ws_errno = WRDSE_NOSPACE; if (wsp->ws_flags & WRDSF_ENOMEMABRT) wsp->ws_alloc_die(wsp); if (wsp->ws_flags & WRDSF_SHOWERR) - wsp->ws_error(_("memory exhausted")); + wordsplit_perror(wsp); if (!(wsp->ws_flags & WRDSF_REUSE)) wordsplit_free(wsp); - errno = ENOMEM; - return WRDSE_NOSPACE; + return wsp->ws_errno; } if (unquote) @@ -524,7 +535,7 @@ wordsplit_len(const char *command, size_t len, struct wordsplit *wsp, wsp->ws_wordc++; } if (alloc_space (wsp)) - return WRDSE_NOSPACE; + return wsp->ws_errno; wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL; /* FIXME: if (rc) free(ws) */ return rc; @@ -542,3 +553,48 @@ wordsplit_free(struct wordsplit *ws) free(ws->ws_wordv); ws->ws_wordv = NULL; } + +void +wordsplit_perror(struct wordsplit *wsp) +{ + switch (wsp->ws_errno) { + case WRDSE_EOF: + wsp->ws_error(_("no error")); + break; + + case WRDSE_QUOTE: + wsp->ws_error(_("missing closing %c (start near #%lu)"), + wsp->ws_input[wsp->ws_endp], wsp->ws_endp); + break; + + case WRDSE_NOSPACE: + wsp->ws_error(_("memory exhausted")); + break; + + case WRDSE_NOSUPP: + wsp->ws_error(_("variable expansion and " + "command substitution " + "are not yet supported")); + + default: + wsp->ws_error(_("unknown error")); + } +} + +const char *_worsplit_errstr[] = { + N_("no error"), + N_("missing closing quote"), + N_("memory exhausted"), + N_("variable expansion and command substitution " + "are not yet supported") +}; +int _worsplit_nerrs = sizeof(_worsplit_errstr)/sizeof(_worsplit_errstr[0]); + +const char * +wordsplit_strerror(struct wordsplit *ws) +{ + if (ws->ws_errno < _worsplit_nerrs) + return _worsplit_errstr[ws->ws_errno]; + return N_("unknown error"); +} + @@ -174,6 +174,22 @@ save_words(struct wordsplit *ws, struct cfg_kw *kwp) *kwp->aval = aval; } +int +wrdse_to_ex(int code) +{ + switch (code) { + case WRDSE_EOF: + return 0; + case WRDSE_QUOTE: + return EX_CONFIG; + case WRDSE_NOSPACE: + return EX_UNAVAILABLE; + case WRDSE_NOSUPP: + return EX_SOFTWARE; + } + return EX_UNAVAILABLE; +} + void parse_config_loop(struct cfg_kw *kwtab, void *data) { @@ -190,9 +206,10 @@ parse_config_loop(struct cfg_kw *kwtab, void *data) struct cfg_kw *kwp; if (wordsplit(buf, &ws, wsflags)) { - smap_error("%s:%u: cannot parse line", - cfg_file_name, cfg_line); - exit(EX_SOFTWARE); + smap_error("%s:%u: %s", + cfg_file_name, cfg_line, + wordsplit_strerror(&ws)); + exit(wrdse_to_ex(ws.ws_errno)); } wsflags |= WRDSF_REUSE; diff --git a/src/module.c b/src/module.c index a40182f..6160893 100644 --- a/src/module.c +++ b/src/module.c @@ -53,7 +53,7 @@ smap_modules_init() WRDSF_ENOMEMABRT | WRDSF_SQUEEZE_DELIMS | WRDSF_DELIM | WRDSF_ERROR)) { smap_error("cannot parse load path: %s", - strerror(errno)); + wordsplit_strerror(&ws)); return; } diff --git a/src/smapc.c b/src/smapc.c index 13a2f0b..7cec3ca 100644 --- a/src/smapc.c +++ b/src/smapc.c @@ -660,8 +660,10 @@ read_eval_loop(FILE *fp, int interactive) continue; } if (cmdprefix == 0 || p[0] == cmdprefix) { - if (wordsplit(p + !!cmdprefix, &ws, flags)) + if (wordsplit(p + !!cmdprefix, &ws, flags)) { + wordsplit_perror(&ws); break; + } flags |= WRDSF_REUSE; if (ws.ws_wordc && handle_command(&ws)) break; |