int
skip_to_delim (string, start, delims, flags)
     char *string;
     int start;
     char *delims;
     int flags;
{
  int i, pass_next, backq, dquote, si, c, oldjmp;
  int invert, skipquote, skipcmd, noprocsub, completeflag;
  int arithexp, skipcol;
  size_t slen;
  char *temp, open[3];
  DECLARE_MBSTATE;

  slen = strlen (string + start) + start;
  oldjmp = no_longjmp_on_fatal_error;
  if (flags & SD_NOJMP)
    no_longjmp_on_fatal_error = 1;
  invert = (flags & SD_INVERT);
  skipcmd = (flags & SD_NOSKIPCMD) == 0;
  noprocsub = (flags & SD_NOPROCSUB);
  completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;

  arithexp = (flags & SD_ARITHEXP);
  skipcol = 0;

  i = start;
  pass_next = backq = dquote = 0;
  while (c = string[i])
    {
      /* If this is non-zero, we should not let quote characters be delimiters
	 and the current character is a single or double quote.  We should not
	 test whether or not it's a delimiter until after we skip single- or
	 double-quoted strings. */
      skipquote = ((flags & SD_NOQUOTEDELIM) && (c == '\'' || c =='"'));
      if (pass_next)
	{
	  pass_next = 0;
	  if (c == 0)
	    CQ_RETURN(i);
	  ADVANCE_CHAR (string, slen, i);
	  continue;
	}
      else if (c == '\\')
	{
	  pass_next = 1;
	  i++;
	  continue;
	}
      else if (backq)
	{
	  if (c == '`')
	    backq = 0;
	  ADVANCE_CHAR (string, slen, i);
	  continue;
	}
      else if (c == '`')
	{
	  backq = 1;
	  i++;
	  continue;
	}
      else if (arithexp && skipcol && c == ':')
	{
	  skipcol--;
	  i++;
	  continue;
	}
      else if (arithexp && c == '?')
	{
	  skipcol++;
	  i++;
	  continue;
	}
      else if (skipquote == 0 && invert == 0 && member (c, delims))
	break;
      /* the usual case is to use skip_xxx_quoted, but we don't skip over double
	 quoted strings when looking for the history expansion character as a
	 delimiter. */
      /* special case for programmable completion which takes place before
         parser converts backslash-escaped single quotes between $'...' to
         `regular' single-quoted strings. */
      else if (completeflag && i > 0 && string[i-1] == '$' && c == '\'')
	i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
      else if (c == '\'')
	i = skip_single_quoted (string, slen, ++i, 0);
      else if (c == '"')
	i = skip_double_quoted (string, slen, ++i, completeflag);
      else if (c == LPAREN && arithexp)
        {
          si = i + 1;
          if (string[si] == '\0')
	    CQ_RETURN(si);

	  temp = extract_delimited_string (string, &si, "(", "(", ")", SX_NOALLOC); /* ) */
	  i = si;
	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
	    break;
	  i++;
	  continue;         
        }
      else if (c == '$' && ((skipcmd && string[i+1] == LPAREN) || string[i+1] == LBRACE))
	{
	  si = i + 2;
	  if (string[si] == '\0')
	    CQ_RETURN(si);

	  if (string[i+1] == LPAREN)
	    temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
	  else
	    temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
	  i = si;
	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
	    break;
	  i++;
	  continue;
	}
#if defined (PROCESS_SUBSTITUTION)
      else if (skipcmd && noprocsub == 0 && (c == '<' || c == '>') && string[i+1] == LPAREN)
	{
	  si = i + 2;
	  if (string[si] == '\0')
	    CQ_RETURN(si);
#if 1
	  temp = extract_delimited_string (string, &si, (c == '<') ? "<(" : ">(", "(", ")", SX_COMMAND|SX_NOALLOC); /* )) */
#else
	  temp = extract_process_subst (string, (c == '<') ? "<(" : ">(", &si, 0);
	  free (temp);		/* XXX - not using SX_NOALLOC here yet */
#endif
	  i = si;
	  if (string[i] == '\0')
	    break;
	  i++;
	  continue;
	}
#endif /* PROCESS_SUBSTITUTION */
#if defined (EXTENDED_GLOB)
      else if ((flags & SD_EXTGLOB) && extended_glob && string[i+1] == LPAREN && member (c, "?*+!@"))
	{
	  si = i + 2;
	  if (string[si] == '\0')
	    CQ_RETURN(si);

	  open[0] = c;
	  open[1] = LPAREN;
	  open[2] = '\0';
	  temp = extract_delimited_string (string, &si, open, "(", ")", SX_NOALLOC); /* ) */

	  i = si;
	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
	    break;
	  i++;
	  continue;
	}
#endif
      else if ((flags & SD_GLOB) && c == LBRACK)
	{
	  si = i + 1;
	  if (string[si] == '\0')
	    CQ_RETURN(si);

	  temp = extract_delimited_string (string, &si, "[", "[", "]", SX_NOALLOC); /* ] */

	  i = si;
	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
	    break;
	  i++;
	  continue;
	}
      else if ((skipquote || invert) && (member (c, delims) == 0))
	break;
      else
	ADVANCE_CHAR (string, slen, i);
    }

  CQ_RETURN(i);