/*
   File:		ModParse.c

   Modifications:

   Changed 08/30/98 by Dan Espen:
   - Copied from FvwmEvent/Parse.c.  Set up for general use by modules.
   Still to be done, try to integrate with Parse.c which is used by fvwm
   itself for parsing.
*/


#include "fvwmlib.h"
#include "ModParse.h"

/*
** PeekArgument: returns next token from string, leaving string intact
**            (you should free returned string later)
**
** notes - quotes and brakets deonte blocks, which are returned MINUS
**         the start & end delimiters.  Delims within block may be escaped
**         with a backslash \ (which is removed when returned).  Backslash
**         must be escaped too, if you want one... (\\).  Arguments may be up
**         to MAX_TOKEN_LENGTH in size.
*/


char *DoPeekArgument(const char *pstr, char **pret)
{
  char *tok=NULL;
  const char *p;
  char bc=0,be=0,tmptok[MAX_TOKEN_LENGTH];
  int len=0;

  if (!pstr)
    return NULL;

  p=pstr;
  EatWS(p); /* skip leading space */
  if (*p)
  {
    if (IsQuote(*p) || IsBlockStart(*p)) /* quoted string or block start? */
    {
      bc = *p; /* save block start char */
      p++;
    }
    /* find end of token */
    while (*p && len < MAX_TOKEN_LENGTH)
    {
      /* first, check stop conditions based on block or normal token */
      if (bc)
      {
        if ((IsQuote(*p) && bc == *p) || IsBlockEnd(*p,bc))
        {
          be = *p;
          break;
        }
      }
      else /* normal token */
      {
        if (isspace(*p) || *p == ',')
          break;
      }

      if (*p == '\\' && *(p+1)) /* if \, copy next char verbatim */
        p++;
      tmptok[len] = *p;
      len++;
      p++;
    }

    /* sanity checks: */
    if (bc && !be) /* did we have block start, but not end? */
    {
      /* should yell about this */
      return NULL;
    }

    if (len)
    {
      tok = (char *)safemalloc(len+1);
      strncpy(tok,tmptok,len);
      tok[len]='\0';
    }
  }

  if (!isspace(*p)) p++;
  if (pret) *pret = p;
  return tok;
}

char *PeekArgument(const char *pstr)
{
  return DoPeekArgument(pstr, NULL);
}

/*
** GetArgument: destructively rips next token from string, returning it
**           (you should free returned string later)
*/
char *GetArgument(char **pstr)
{
  char *tok ;

  if (!pstr || !*pstr || !(tok=DoPeekArgument(*pstr, pstr)))
    return NULL;			/* *pstr=NULL; ???? */

  /* skip tok and following whitespace/separators in pstr & DON'T realloc */
  EatWS(*pstr);

  if (!**pstr) 
      *pstr=NULL;			/* change \0 to NULL */

  return tok;
}

/*
** CmpArgument: does case-insensitive compare on next token in string, leaving
**           string intact (return code like strcmp)
*/
int CmpArgument(const char *pstr,char *tok)
{
  int rc=0;
  char *ntok=PeekArgument(pstr);
  if (ntok)
  {
    rc = strcasecmp(tok,ntok);
    free(ntok);
  }
  return rc;
}

/*
** MatchArgument: does case-insensitive compare on next token in string, leaving
**             string intact (returns true if matches, false otherwise)
*/
int MatchArgument(const char *pstr,char *tok)
{
  int rc=0;
  char *ntok=PeekArgument(pstr);
  if (ntok)
  {
    rc = (strcasecmp(tok,ntok)==0);
    free(ntok);
  }
  return rc;
}


#if 0
/*
** GetNextArgument: equiv interface of old parsing routine, for ease of transition
*/
char *GetNextArgument(char *indata,char **token)
{
  char *nindata=indata;

  *token = PeekArgument(indata);

  if (*token)
    nindata+=strlen(*token);
  EatWS(nindata);

  return nindata;
}
#else
/****************************************************************************
 *
 * Gets the next "word" of input from char string indata.
 * "word" is a string with no spaces, or a qouted string.
 * Return value is ptr to indata,updated to point to text after the word
 * which is extracted.
 * token is the extracted word, which is copied into a malloced
 * space, and must be freed after use. 
 *
 **************************************************************************/
char *GetNextArgument(char *indata,char **token)
{ 
  char *t,*start, *end, *text;

  t = indata;
  if(t == NULL)
    {
      *token = NULL;
      return NULL;
    }
  while(isspace(*t)&&(*t != 0))t++;
  start = t;
  while(!isspace(*t)&&(*t != 0))
    {
      /* Check for qouted text */
      if(*t == '"')
	{
	  t++;
	  while((*t != '"')&&(*t != 0))
	    {
	      /* Skip over escaped text, ie \" or \space " */
	      if((*t == '\\')&&(*(t+1) != 0))
		t++;
	      t++;
	    }
	  if(*t == '"')
	    t++;
	}
      else
	{
	  /* Skip over escaped text, ie \" or \space " */
	  if((*t == '\\')&&(*(t+1) != 0))
	    t++;
	  t++;
	}
    }
  end = t;

  text = safemalloc(end-start+1);
  *token = text;

  while(start < end)
    {
      /* Check for qouted text */
      if(*start == '"')
	{	
	  start++;
	  while((*start != '"')&&(*start != 0))
	    {
	      /* Skip over escaped text, ie \" or \space " */
	      if((*start == '\\')&&(*(start+1) != 0))
		start++;
	      *text++ = *start++;
	    }
	  if(*start == '"')
	    start++;
	}
      else
	{
	  /* Skip over escaped text, ie \" or \space " */
	  if((*start == '\\')&&(*(start+1) != 0))
	    start++;
	  *text++ = *start++;
	}
    }
  *text = 0;
  if(*end != 0)
    end++;

  return end;
}
#endif /* 0 */



/*
   function:		MatchToken
   description:	        matches one word
   returns:		pointer to delimiter character
                        NULL if no match
*/

#if 0					/* supported in 2.0.47b */
const char *MatchToken(register const char *s, register const char *w)
{
    if (s==NULL) return NULL;
    assert(w!=NULL);	/* the token may not be NULL -> design flaw */

    while (*w && (*s==*w ||
#ifdef WORD_IS_UPPERCASE
		            isupper(*s) && _toupper(*s)==*w
#else
		            toupper(*s)==toupper(*w)
#endif
		  ))
	s++,w++;

    if (*w=='\0' &&			          /* end of word and */
	(*s=='\0' || ispunct(*s) || isspace(*s))) /* same in string */
	return s;				  /* return endptr */
    else 
	return NULL;				  /* no match */
}
#endif

/*
   function:		CmpToken
   description:	        compare 1st word of s to 1st word of w
   returns:		< 0  if s < t
                        = 0  if s = t
                        > 0  if s > t

   Note arguments are not declares register, so the function can be 
   used with the bsearch() <search.h> function of the c library.

*/

int XCmpToken(char *s, char **t)
{
    register char *w=*t;

    if (w==NULL) return 1;		/* non existant word */
    if (s==NULL) return -1;		/* non existant string */

    while (*w && (*s==*w ||
#ifdef WORD_IS_UPPERCASE
		            isupper(*s) && _toupper(*s)==*w
#else
		            toupper(*s)==toupper(*w)
#endif
		  ))
	s++,w++;

    if ((*s=='\0' && (ispunct(*w) || isspace(*w)))||
	(*w=='\0' && (ispunct(*s) || isspace(*s))) )
	return 0;			/* 1st word equal */
    else 
	return toupper(*s)-toupper(*w);	/* smaller/greater */
}

