/* normal C section */
%{

#include "kiss.h"
#include "parser.tab.h"

#ifdef USE_READLINE		    /* support for GNU's readline */

static int ignorechar (int count, int key)
{
    /* reset buffer */
    *rl_line_buffer = '\0';

    return (0);
}    
    
static int myread (char *buf, int max)
{
    static char
	*lineread;
    register int
	res;
    static int
	initialized;

    /* see if we need more keybindings */
    if (! initialized)
    {
	initialized++;
	rl_bind_key (3, ignorechar);
    }

    /* if not interactive mode: just do the read */
    if (! isatty (fileno (yyin)) )
    {
	if ( (res = read (fileno (yyin), buf, max)) < 0 )
	    res = 0;
        return (res);
    }
    

    /* free previous line if necessary */
    if (lineread)
    {
	free (lineread);
	lineread = NULL;
    }

    /* get the input */
    lineread = readline (getprompt ());

    /* EOF condition? */
    if (! lineread)
    {
	*buf = '\0';
	return (0);
    }
    /* \n character? */
    if (! *lineread)
    {
	*buf = '\n';
	return (1);
    }

    /* otherwise: must be a string */
    if (strlen (lineread) > max - 1)
    {
	warning ("[lexer] input buffer overflow");
	*buf = '\n';
	return (1);
    }
    strcpy (buf, lineread);
    strcat (buf, "\n");
    add_history (lineread);
    return (strlen (buf));
}    

#endif				    /* USE_READLINE */

#ifdef USE_GETLINE		    /* getline support */
static int myread (char *buf, int max)
{
    register char
	*input;
    register int
	res;

    if (! isatty (fileno (yyin)))   /* do read() if in a pipe or so */
    {
	if ( (res = read (fileno (yyin), buf, max)) < 0 )
	    res = 0;
	return (res);
    }

    input = getline (getprompt ()); /* otherwise: the getline version */

    if (! *input)		    /* EOF */
	return (0);

    if (strlen (input) > max - 1)   /* line too long ? */
    {
	warning ("[lexer] input buffer overflow");
	*buf = '\n';
	return (1);
    }
    
    strcpy (buf, input);
    gl_histadd (input);
    return (strlen (input));
}
    
	

#endif				    /* USE_GETLINE */

#ifdef USE_BARE			    /* no getline, no readline */

static int myread (char *buf, int max)
{
    int
	res;
	
    /* show prompt if interactive */
    if (isatty (fileno (yyin)))
    {
	fflush (stdout);
	fflush (stderr);
	printf ("%s", getprompt ());
	fflush (stdout);
    } 

    /* do the read */
    if ( (res = read (fileno (yyin), buf, max)) < 0 )
	res = 0;
    return (res);
}    

#endif				    /* USE_BARE */



/* remap YY_INPUT to one of the versions of myread () */
#undef YY_INPUT
#define YY_INPUT(buf,res,max)   res = myread (buf, max)

/* remap the macro yywrap to indicate that more files are there */
#undef yywrap
int yywrap ()
{
    /* if closing sourced file: continue parsing next buffer */
    if (yypopfile ())
	return (0);
	
    /* if no scripts (interactive mode): we're done */
    if (! lastfile)
	return (1);

    while (1)
    {
	/* done with this script */
	if (yyin)
	{
	    fclose (yyin);
	    yyin = NULL;
	}
	lastfile++;

	/* if no more scripts: we're done */
	if (lastfile >= orgargc)
	    return (1);

	/* if we can open it, then proceed */
	if ( (yyin = fopen (orgargv [lastfile], "r")) )
	    return (0);

	/* issue warning and continue with next file */
	warning ("cannot open script \"%s\" for reading", orgargv [lastfile]);
    }
}    

%}

/* rules */
%%
\#.+				/* ignore */ ;
\!				{ return (RECALLCMD); }
\|				{ return (PIPETO); }
\&				{ return (BACKGROUND); }
\>				{ return (REDIRTO); }
\>\>				{ return (REDIRAPPEND); }
\<				{ return (REDIRFROM); }
\$[a-zA-Z]+			{ return (VARIABLE); }
\$\$				{ return (VARIABLE); }
\$\?				{ return (VARIABLE); }
\$\!				{ return (VARIABLE); }
\'.*\'				{ return (SQUOTESTRING); }
\".*\"				{ return (DQUOTESTRING); }
\`.*\`				{ return (BQUOTESTRING); }
[^\ \!\;\n\t\|\&\>\<]+		{ return (IDENT); }
\=				{ return (IDENT); }
\n				{ return (ENDLINE); }
\;				{ return (ENDLINE); }
[\ \t]+				/* ignore */ ;
\\[ \t]*\n			/* ignore */ ;
.				{
				    warning ("[lexer] unmatched "
					     "input \"%s\"",
					     yytext);
				}

%%
/* support for pushing and popping files, used in "source" */
static YY_BUFFER_STATE
    *bufstate;
static int
    nbufstate;
    
void yypushfile (FILE *inf)
{
    bufstate = realloc (bufstate, (nbufstate + 1) * sizeof (YY_BUFFER_STATE));
    bufstate [nbufstate] = yy_create_buffer (inf, YY_BUF_SIZE);
    yy_switch_to_buffer (bufstate [nbufstate++]);
}

int yypopfile ()
{
    if (nbufstate > 1)
    {
	nbufstate--;
	yy_delete_buffer (bufstate [nbufstate]);
	yy_switch_to_buffer (bufstate [nbufstate - 1]);
	return (1);
    }
    return (0);
}
