/*
 * parser.c --
 *
 * Handles textual parsing.
 *
 *     *********************************************************************
 *     * Copyright (C) 1985, 1990 Regents of the University of California. *
 *     * Permission to use, copy, modify, and distribute this              *
 *     * software and its documentation for any purpose and without        *
 *     * fee is hereby granted, provided that the above copyright          *
 *     * notice appear in all copies.  The University of California        *
 *     * makes no representations about the suitability of this            *
 *     * software for any purpose.  It is provided "as is" without         *
 *     * express or implied warranty.  Export of this software outside     *
 *     * of the United States of America may require an export license.    *
 *     *********************************************************************
 *
 */

#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/parser.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <ctype.h>

#include "utils/magic.h"
#include "textio/textio.h"

#define ISEND(ch)	((ch == '\0') || (ch == ';'))


/*
 * ----------------------------------------------------------------------------
 * ParsSplit:
 *
 *	Take a string and split it into argc, argv format.
 *	The result of this split is stored back into the original string,
 *	and an array of pointers is set up to index into it.  Note that
 *	the contents of the original string are lost.
 *
 *      rajit@cs.caltech.edu: changed it so that quotes typed in by the
 *      user remain there.
 *
 * Results:
 *	TRUE if everything went OK.
 *	FALSE otherwise.
 *
 * Side effects:
 *	argc is filled in, str is changed, argv[] is changed to point into str
 * ----------------------------------------------------------------------------
 */

bool
ParsSplit(
    char *str,
    int maxArgc,
    int *argc,
    char **argv,
    const char **remainder)
{
    char **largv;
    char *newstrp;
    char *strp;
    char terminator;

    *argc = 0;
    largv = argv;
    newstrp = str;
    strp = str;

    while (isspace(*strp) && (!ISEND(*strp)) ) strp++;

    terminator = *strp;
    *largv = strp;
    while (!ISEND(*strp))
    {
	/*
	 * hackhackhackhackhack
	 * rajit@cs.caltech.edu
	 * okay. so we're changing what ' ' can be used for.
	 * One can only have a _SINGLE_ character between the
	 * two quotes. i.e. ' ' are used to quote characters.
	 */
#ifdef SCHEME_INTERPRETER
	if (*strp == '\'' && *(strp+1) && *(strp+2) == '\'')
        {
	  strp++;
	  *newstrp++ = *strp++;
	  strp++;
	}
	/*
	 * rajit@cs.caltech.edu
	 * keep " " around strings to distinguish symbols from strings.
	 * the lisp evaluator strips these quotes after parsing the
	 * string.
	 */
	else if (*strp == '"')
#else
	if (*strp == '"' || *strp == '\'')
#endif
	{
	    char compare;

#ifdef SCHEME_INTERPRETER
	    *newstrp++ = *strp;
#endif
	    compare = *strp++;
	    while ( (*strp != compare) && (*strp != '\0'))
	    {
		if (*strp == '\\')
#ifndef SCHEME_INTERPRETER
		    strp++;
#else
		    *newstrp++ = *strp++;
#endif
		*newstrp++ = *strp++;
	    }
	    if (*strp == compare)
#ifndef SCHEME_INTERPRETER
	      strp++;
#else
	      *newstrp++ = *strp++;
#endif
	    else
#ifndef SCHEME_INTERPRETER
		TxError("Unmatched %c in string, %s.\n", compare,
			"I'll pretend that there is one at the end");
#else
	    {
	        TxError ("Unmatched %c in string.\n", compare);
		return FALSE;
	    }
#endif
	}
	else
	    *newstrp++ = *strp++;
	if (isspace(*strp) || (ISEND(*strp)))
	{
	    while (isspace(*strp) && (!ISEND(*strp))) strp++;
	    terminator = *strp;
	    *newstrp++ = '\0';
	    (*argc)++;
	    if (*argc < maxArgc)
	    {
		*++largv = newstrp;
	    }
	    else
	    {
		TxError("Too many arguments.\n");
		*remainder = NULL;
		return FALSE;
	    }
	}
    }

    ASSERT(remainder != (char **) NULL, "ParsSplit");

    if (terminator != '\0')
    {
	/* save other commands (those after the ';') for later parsing */
	strp++;
	while (isspace(*strp) && (!ISEND(*strp))) strp++;
	*remainder = strp;
    }
    else
	*remainder = NULL;

    return TRUE;
}
