static int scan_qstring (struct wordsplit *wsp, size_t start, size_t * end) { size_t j; const char *command = wsp->ws_input; size_t len = wsp->ws_len; char q = command[start]; for (j = start + 1; j < len && command[j] != q; j++) if (q == '"' && command[j] == '\\') j++; if (j < len && command[j] == q) { int flags = _WSNF_QUOTE | _WSNF_EMPTYOK; if (q == '\'') flags |= _WSNF_NOEXPAND; if (wordsplit_add_segm (wsp, start + 1, j, flags)) return _WRDS_ERR; *end = j; } else { wsp->ws_endp = start; wsp->ws_errno = WRDSE_QUOTE; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return _WRDS_ERR; } return 0; }
static int _wsplt_seterr (struct wordsplit *wsp, int ec) { wsp->ws_errno = ec; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return ec; }
static int _wsplt_nomem (struct wordsplit *wsp) { errno = ENOMEM; wsp->ws_errno = WRDSE_NOSPACE; if (wsp->ws_flags & WRDSF_ENOMEMABRT) wsp->ws_alloc_die (wsp); if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); if (!(wsp->ws_flags & WRDSF_REUSE)) wordsplit_free (wsp); wordsplit_free_nodes (wsp); return wsp->ws_errno; }
static int expvar (struct wordsplit *wsp, const char *str, size_t len, struct wordsplit_node **ptail, const char **pend, int flg) { size_t i = 0; const char *defstr = NULL; const char *value; const char *vptr; struct wordsplit_node *newnode; const char *start = str - 1; if (ISALPHA (str[0]) || str[0] == '_') { for (i = 1; i < len; i++) if (!(ISALNUM (str[i]) || str[i] == '_')) break; *pend = str + i - 1; } else if (str[0] == '{') { str++; len--; for (i = 1; i < len; i++) if (str[i] == '}' || str[i] == ':') break; if (str[i] == ':') { size_t j; defstr = str + i + 1; if (find_closing_cbrace (str, i + 1, len, &j)) { wsp->ws_errno = WRDSE_CBRACE; return 1; } *pend = str + j; } else if (str[i] == '}') { defstr = NULL; *pend = str + i; } else { wsp->ws_errno = WRDSE_CBRACE; return 1; } } else { if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_WORD | flg; newnode->v.word = malloc (3); if (!newnode->v.word) return _wsplt_nomem (wsp); newnode->v.word[0] = '$'; newnode->v.word[1] = str[0]; newnode->v.word[2] = 0; *pend = str; return 0; } /* Actually expand the variable */ /* str - start of the variable name i - its length defstr - default replacement str */ vptr = wordsplit_find_env (wsp, str, i); if (vptr) { value = strdup (vptr); if (!value) return _wsplt_nomem (wsp); } else if (wsp->ws_flags & WRDSF_GETVAR) value = wsp->ws_getvar (str, i, wsp->ws_closure); else if (wsp->ws_flags & WRDSF_UNDEF) { wsp->ws_errno = WRDSE_UNDEF; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return 1; } else { if (wsp->ws_flags & WRDSF_KEEPUNDEF) value = NULL; else value = ""; } /* FIXME: handle defstr */ (void) defstr; if (value) { if (flg & _WSNF_QUOTE) { if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; newnode->v.word = strdup (value); if (!newnode->v.word) return _wsplt_nomem (wsp); } else if (*value == 0) { /* Empty string is a special case */ if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_NULL; } else { struct wordsplit ws; int i; ws.ws_delim = wsp->ws_delim; if (wordsplit (value, &ws, WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM | WRDSF_WS)) { wordsplit_free (&ws); return 1; } for (i = 0; i < ws.ws_wordc; i++) { if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg); newnode->v.word = strdup (ws.ws_wordv[i]); if (!newnode->v.word) return _wsplt_nomem (wsp); } wordsplit_free (&ws); } } else if (wsp->ws_flags & WRDSF_KEEPUNDEF) { size_t size = *pend - start + 1; if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; newnode->v.word = malloc (size + 1); if (!newnode->v.word) return _wsplt_nomem (wsp); memcpy (newnode->v.word, start, size); newnode->v.word[size] = 0; } else { if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_NULL; } return 0; }
int wordsplit_len (const char *command, size_t length, struct wordsplit *wsp, int flags) { int rc; size_t start; const char *cmdptr; size_t cmdlen; if (!command) { if (!(flags & WRDSF_INCREMENTAL)) return EINVAL; start = skip_delim (wsp); if (wsp->ws_endp == wsp->ws_len) { wsp->ws_errno = WRDSE_NOINPUT; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return wsp->ws_errno; } cmdptr = wsp->ws_input + wsp->ws_endp; cmdlen = wsp->ws_len - wsp->ws_endp; wsp->ws_flags |= WRDSF_REUSE; wordsplit_init0 (wsp); } else { cmdptr = command; cmdlen = length; start = 0; rc = wordsplit_init (wsp, cmdptr, cmdlen, flags); if (rc) return rc; } if (wsp->ws_flags & WRDSF_SHOWDBG) wsp->ws_debug ("Input:%.*s;", (int) cmdlen, cmdptr); rc = wordsplit_process_list (wsp, start); if (rc == 0 && (flags & WRDSF_INCREMENTAL)) { while (!wsp->ws_head && wsp->ws_endp < wsp->ws_len) { start = skip_delim (wsp); if (wsp->ws_flags & WRDSF_SHOWDBG) { cmdptr = wsp->ws_input + wsp->ws_endp; cmdlen = wsp->ws_len - wsp->ws_endp; wsp->ws_debug ("Restart:%.*s;", (int) cmdlen, cmdptr); } rc = wordsplit_process_list (wsp, start); if (rc) break; } } if (rc) { wordsplit_free_nodes (wsp); return rc; } wordsplit_finish (wsp); wordsplit_free_nodes (wsp); return wsp->ws_errno; }
static int wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, int flags) { wsp->ws_flags = flags; if (!(wsp->ws_flags & WRDSF_ALLOC_DIE)) wsp->ws_alloc_die = _wsplt_alloc_die; if (!(wsp->ws_flags & WRDSF_ERROR)) wsp->ws_error = _wsplt_error; if (!(wsp->ws_flags & WRDSF_NOVAR) && !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR))) { errno = EINVAL; wsp->ws_errno = WRDSE_USAGE; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return wsp->ws_errno; } if (!(wsp->ws_flags & WRDSF_NOCMD)) { errno = EINVAL; wsp->ws_errno = WRDSE_NOSUPP; if (wsp->ws_flags & WRDSF_SHOWERR) wordsplit_perror (wsp); return wsp->ws_errno; } if (wsp->ws_flags & WRDSF_SHOWDBG) { if (!(wsp->ws_flags & WRDSF_DEBUG)) { if (wsp->ws_flags & WRDSF_ERROR) wsp->ws_debug = wsp->ws_error; else if (wsp->ws_flags & WRDSF_SHOWERR) wsp->ws_debug = _wsplt_error; else wsp->ws_flags &= ~WRDSF_SHOWDBG; } } wsp->ws_input = input; wsp->ws_len = len; if (!(wsp->ws_flags & WRDSF_DOOFFS)) wsp->ws_offs = 0; if (!(wsp->ws_flags & WRDSF_DELIM)) wsp->ws_delim = " \t\n"; if (!(wsp->ws_flags & WRDSF_COMMENT)) wsp->ws_comment = NULL; if (!(wsp->ws_flags & WRDSF_CLOSURE)) wsp->ws_closure = NULL; wsp->ws_endp = 0; wordsplit_init0 (wsp); return 0; }