/* Variable expansion */ static int node_split_prefix (struct wordsplit *wsp, struct wordsplit_node **ptail, struct wordsplit_node *node, size_t beg, size_t len, int flg) { struct wordsplit_node *newnode = NULL; if (len == 0) return 0; if (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); if (node->flags & _WSNF_WORD) { const char *str = wsnode_ptr (wsp, node); char *newstr = malloc (len + 1); if (!newstr) return _wsplt_nomem (wsp); memcpy (newstr, str + beg, len); newstr[len] = 0; newnode->flags = _WSNF_WORD; newnode->v.word = newstr; } else { newnode->v.segm.beg = node->v.segm.beg + beg; newnode->v.segm.end = newnode->v.segm.beg + len; } newnode->flags |= flg; *ptail = newnode; return 0; }
static void wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node, struct wordsplit_node *anchor, int before) { if (!wsp->ws_head) { node->next = node->prev = NULL; wsp->ws_head = wsp->ws_tail = node; } else if (before) { if (anchor->prev) wsnode_insert (wsp, node, anchor->prev, 0); else { node->prev = NULL; node->next = anchor; anchor->prev = node; wsp->ws_head = node; } } else { struct wordsplit_node *p; p = anchor->next; if (p) p->prev = node; else wsp->ws_tail = node; node->next = p; node->prev = anchor; anchor->next = node; } }
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; }
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; char *value; const char *vptr; struct wordsplit_node *newnode; const char *start = str - 1; int rc; struct wordsplit ws; if (ISVARBEG (str[0])) { for (i = 1; i < len; i++) if (!ISVARCHR (str[i])) break; *pend = str + i - 1; } else if (str[0] == '{') { str++; len--; for (i = 1; i < len; i++) { if (str[i] == ':') { size_t j; defstr = str + i + 1; if (find_closing_paren (str, i + 1, len, &j, "{}")) return _wsplt_seterr (wsp, WRDSE_CBRACE); *pend = str + j; break; } else if (str[i] == '}') { defstr = NULL; *pend = str + i; break; } else if (strchr ("-+?=", str[i])) { size_t j; defstr = str + i; if (find_closing_paren (str, i, len, &j, "{}")) return _wsplt_seterr (wsp, WRDSE_CBRACE); *pend = str + j; break; } } if (i == len) return _wsplt_seterr (wsp, WRDSE_CBRACE); } 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 */ if (defstr && strchr("-+?=", defstr[0]) == 0) { rc = WRDSE_UNDEF; defstr = NULL; } else { rc = wordsplit_find_env (wsp, str, i, &vptr); if (rc == WRDSE_OK) { value = strdup (vptr); if (!value) rc = WRDSE_NOSPACE; } else if (wsp->ws_flags & WRDSF_GETVAR) rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure); else rc = WRDSE_UNDEF; if (rc == WRDSE_OK && value[0] == 0 && defstr && defstr[-1] == ':') { free (value); rc = WRDSE_UNDEF; } } switch (rc) { case WRDSE_OK: if (defstr && *defstr == '+') { size_t size = *pend - ++defstr; rc = _wsplt_subsplit (wsp, &ws, defstr, size, WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE | (wsp->ws_flags & (WRDSF_NOVAR | WRDSF_NOCMD))); if (rc) return rc; free (value); value = ws.ws_wordv[0]; ws.ws_wordv[0] = NULL; wordsplit_free (&ws); } break; case WRDSE_UNDEF: if (defstr) { size_t size; if (*defstr == '-' || *defstr == '=') { size = *pend - ++defstr; rc = _wsplt_subsplit (wsp, &ws, defstr, size, WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE | (wsp->ws_flags & (WRDSF_NOVAR | WRDSF_NOCMD))); if (rc) return rc; value = ws.ws_wordv[0]; ws.ws_wordv[0] = NULL; wordsplit_free (&ws); if (defstr[-1] == '=') wsplt_assign_var (wsp, str, i, value); } else { if (*defstr == '?') { size = *pend - ++defstr; if (size == 0) wsp->ws_error (_("%.*s: variable null or not set"), (int) i, str); else { rc = _wsplt_subsplit (wsp, &ws, defstr, size, WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE | (wsp->ws_flags & (WRDSF_NOVAR | WRDSF_NOCMD))); if (rc == 0) wsp->ws_error ("%.*s: %s", (int) i, str, ws.ws_wordv[0]); else wsp->ws_error ("%.*s: %.*s", (int) i, str, (int) size, defstr); wordsplit_free (&ws); } } value = NULL; } } else if (wsp->ws_flags & WRDSF_UNDEF) { _wsplt_seterr (wsp, WRDSE_UNDEF); return 1; } else { if (wsp->ws_flags & WRDSF_WARNUNDEF) wsp->ws_error (_("warning: undefined variable `%.*s'"), (int) i, str); if (wsp->ws_flags & WRDSF_KEEPUNDEF) value = NULL; else { value = strdup (""); if (!value) return _wsplt_nomem (wsp); } } break; case WRDSE_NOSPACE: return _wsplt_nomem (wsp); case WRDSE_USERERR: if (wsp->ws_errno == WRDSE_USERERR) free (wsp->ws_usererr); wsp->ws_usererr = value; /* fall through */ default: _wsplt_seterr (wsp, rc); return 1; } 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 = value; } else if (*value == 0) { free (value); /* 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, rc; rc = _wsplt_subsplit (wsp, &ws, value, strlen (value), WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE); free (value); if (rc) { _wsplt_seterr_sub (wsp, &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; }
static int wordsplit_pathexpand (struct wordsplit *wsp) { struct wordsplit_node *p, *next; char *pattern = NULL; size_t patsize = 0; size_t slen; int flags = 0; #ifdef GLOB_PERIOD if (wsp->ws_options & WRDSO_DOTGLOB) flags = GLOB_PERIOD; #endif for (p = wsp->ws_head; p; p = next) { const char *str; next = p->next; if (p->flags & _WSNF_QUOTE) continue; str = wsnode_ptr (wsp, p); slen = wsnode_len (p); if (isglob (str, slen)) { int i; glob_t g; struct wordsplit_node *prev; if (slen + 1 > patsize) { char *p = realloc (pattern, slen + 1); if (!p) return _wsplt_nomem (wsp); pattern = p; patsize = slen + 1; } memcpy (pattern, str, slen); pattern[slen] = 0; switch (glob (pattern, flags, NULL, &g)) { case 0: break; case GLOB_NOSPACE: free (pattern); return _wsplt_nomem (wsp); case GLOB_NOMATCH: if (wsp->ws_options & WRDSO_NULLGLOB) { wsnode_remove (wsp, p); wsnode_free (p); } else if (wsp->ws_options & WRDSO_FAILGLOB) { char buf[128]; if (wsp->ws_errno == WRDSE_USERERR) free (wsp->ws_usererr); snprintf (buf, sizeof (buf), _("no files match pattern %s"), pattern); free (pattern); wsp->ws_usererr = strdup (buf); if (!wsp->ws_usererr) return _wsplt_nomem (wsp); else return _wsplt_seterr (wsp, WRDSE_USERERR); } continue; default: free (pattern); return _wsplt_seterr (wsp, WRDSE_GLOBERR); } prev = p; for (i = 0; i < g.gl_pathc; i++) { struct wordsplit_node *newnode; char *newstr; if (wsnode_new (wsp, &newnode)) return 1; newstr = strdup (g.gl_pathv[i]); if (!newstr) return _wsplt_nomem (wsp); newnode->v.word = newstr; newnode->flags |= _WSNF_WORD|_WSNF_QUOTE; wsnode_insert (wsp, newnode, prev, 0); prev = newnode; } globfree (&g); wsnode_remove (wsp, p); wsnode_free (p); } } free (pattern); return 0; }
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; str++; len--; if (find_closing_paren (str, 0, len, &j, "()")) { _wsplt_seterr (wsp, WRDSE_PAREN); return 1; } *pend = str + j; if (wsp->ws_options & WRDSO_ARGV) { struct wordsplit ws; 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); if (rc == WRDSE_NOSPACE) return _wsplt_nomem (wsp); else if (rc) { if (rc == WRDSE_USERERR) { if (wsp->ws_errno == WRDSE_USERERR) free (wsp->ws_usererr); wsp->ws_usererr = value; } _wsplt_seterr (wsp, rc); return 1; } 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 = value; } else if (*value == 0) { free (value); /* 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, rc; 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; } 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 (wsnode_new (wsp, &newnode)) return 1; wsnode_insert (wsp, newnode, *ptail, 0); *ptail = newnode; newnode->flags = _WSNF_NULL; } return 0; }