コード例 #1
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;
  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;
}
コード例 #2
0
ファイル: wordsplit.c プロジェクト: mogaal/direvent
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;
}