/*
 *	Parse.c - Copyright © 1990 by S.R. & P.C.
 *
 *	Created:	16 Jun 1990
 *	Modified:	06 Jul 1990
 *
 *	Make>> make
 */

/*
#define DO_ARP_COPIES
#include <libraries/arpbase.h>
#include <functions.h>
#include <exec/memory.h>
#include <stdio.h>
*/

#include <dos_functions.h>
#include <arpdos_pragmas.h>

#include "ParM.h"

#define SYNTAX(msg) { Err(msg); return FALSE; }

/*	tokens  */

#define CMDWIN		1
#define RB			2
#define WB			3	
#define CLI			4	
#define PRI			5
#define STACK		6
#define MENU		7
#define SUBMENU		8
#define ENDSUBMENU	9
#define ITEM		10
#define COLOR		11
#define STR			12	/* not a keyword! */

#define MAX_KEYWORD 11


/*****				external functions					*****/

extern void Warn(const char *);
extern void AddMenu(char *);
extern void AddSubMenu(char *);
extern void AddEntry(char *, char *, char *, char*, char, char, long, short);
extern void EndSubMenu(void);
extern void FreeMenus(void);
extern void CleanUp(void);


/*****				 global functions					*****/

BOOL ParseMenus( void );


/*****				 global variables					*****/

extern struct Window *Win;
extern char CurCfg[];
extern char CmdWindow[];
extern UBYTE menu_pen;


/*****				 local variables					*****/

static char *KeyWordTab[] = {
	NULL,		/* possible implementation of an END keyword */
	"CMDWIN",
	"RB",
	"WB",
	"CLI",
	"PRI",
	"STACK",
	"MENU",
	"SUBMENU",
	"ENDSUBMENU",
	"ITEM",
	"COLOR"
};

/*	status  */

#define STAT_BEGIN		0
#define STAT_MENU		1
#define STAT_SUBMENU	2
#define STAT_ITEM		4

static char *filebuf,*fp;
static char tok[80];


/* add the position of the error to the error message */

static void Err( char *msg )
{
	char buf[80];

	SPrintf(buf,"%s, char %ld",msg,fp-filebuf);
	Warn(buf);
}



/* rfp is a register variable used to replace global fp pointer in
 * get_token() body. Then, fp must be restored before leaving function */

static char get_token( void )
{
	register char *p,*rfp;
	short i;
	char quote;

	rfp = fp;
retry:
	while(isspace(*rfp)) rfp++;	/* skip extra spaces */
	if(*rfp=='#') {				/* comment */
		while(*rfp!='\n' && *rfp) rfp++;
		goto retry;
	}
	if(!isprint(*rfp) || *rfp=='{' || *rfp=='}') {
		fp = rfp;
		return *fp++;		/* '{', '}', '\0', or invalid char */
	}
	/* scan string */
	p = tok;
	if(*rfp=='"') {
		rfp++;
		quote = TRUE;
	} else
		quote = FALSE;
	while( (quote && *rfp!='"') || (!quote && isspace(*rfp)==0) )
		*p++ = *rfp++;
	*p = NULL;
	if (quote) rfp++; /* skip closing '"' */
	for( i=1 ; i<=MAX_KEYWORD ; i++ ) {
		if (!Strcmp(tok ,KeyWordTab[i])) break; /* arp Strcmp() is not case sensitive */
	}
	fp = rfp;
	return i;
}


static BOOL ParseConfig( void ) {
	char t,shortcut,mode;
	long stack;
	short pri;
	USHORT status = STAT_BEGIN;
	register char *p, c;
	char itemstr[80], cmd[80], args[200], win[80];

	while(t=get_token()) {
		switch( t ) {
		case CMDWIN :
			get_token();
			strcpy(CmdWindow, tok);
			break;
		case COLOR :
			get_token();
			menu_pen = ( (menu_pen=Atol(tok)) == Win->BlockPen ) ? Win->DetailPen : menu_pen;
			break;
		case MENU :
			if ( !(status & (STAT_MENU|STAT_ITEM)) && status != STAT_BEGIN )
				SYNTAX("Unexpected MENU statement")
			status = STAT_MENU;
			get_token();
			AddMenu(tok);
			break;
		case SUBMENU :
			if ( !(status & STAT_MENU) || (status & STAT_SUBMENU) )
				SYNTAX("Unexpected SUBMENU")
			status = STAT_SUBMENU;
			get_token();
			AddSubMenu(tok);
			break;
		case ENDSUBMENU :
			if ( !(status & STAT_SUBMENU) || !(status & STAT_ITEM) )
				SYNTAX("Unexpected ENDSUBMENU")
			EndSubMenu();
			status = STAT_MENU|STAT_ITEM;
			break;
		case ITEM :
			if (status == STAT_BEGIN) SYNTAX("Unexpected ITEM")
			status |= STAT_ITEM;
			shortcut = pri = stack = 0;
			if (get_token()=='{') {	/* command char */
				shortcut = *fp++;
				if(get_token() != '}') SYNTAX("Missing closing '}'");
				get_token();
			}
			strcpy(itemstr,tok);
			t=get_token();
			get_token();
			switch( t ) {
			case WB :
				mode = 'w';
				args[0] = '\0';
				strcpy(cmd,tok);
				break;
			case RB :
				mode = 'r';
				strcpy(cmd,tok);
				p = args;
				while ((c=*fp++) != '\n' && c ) *p++ = c;
				*p = '\0';
				break;
			case CLI :
				mode = 'c';
				strcpy(win,tok);
				while( (t=get_token())!=STR ) {
					get_token();
					switch( t ) {
					case STACK :
						stack = Atol(tok);
						break;
					case PRI :
						pri = Atol(tok);
						if (pri < -128 || pri > 127) SYNTAX("Invalid priority")
						break;
					default :
						Err("STACK | PRI Expected");
						return FALSE;
					}
				}
				strcpy(cmd,tok);
				p = args;
				while ((c=*fp++) != '\n' && c ) *p++ = c;
				*p = '\0';
				break;
			default :
				Err("WB | RB | CLI Expected");
				return FALSE;
			}
			AddEntry(itemstr, cmd, args, win, shortcut, mode, stack, pri);
			break;
		default :
			Err("Keyword expected");
			return FALSE;
		}
	}
	return TRUE;
}


BOOL ParseMenus( void )
{
	BPTR lock,cfg;
	struct FileInfoBlock *fib;
	long bufsize,nch;
	BOOL stat;
	BOOL pb = TRUE;
	char msg[80];

	if ( !(lock=Lock(CurCfg, ACCESS_READ)) ) {
		strcpy(msg, "Can't open ");
		strcat(msg, CurCfg);
		Warn(msg);
		return FALSE;
	}
	if (fib = (struct FileInfoBlock *)
			  AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR) ) {
		if (Examine(lock, (BPTR)fib)) {
			if ( fib->fib_DirEntryType < 0 ) {
				bufsize = fib->fib_Size+2;
				if (filebuf = AllocMem( bufsize , MEMF_PUBLIC|MEMF_CLEAR)) {
					cfg = Open(CurCfg, MODE_OLDFILE);
					nch = Read(cfg, filebuf, bufsize-1);
					Close(cfg);
					if (nch == fib->fib_Size) {
						fp = filebuf;
						stat = ParseConfig();
						CleanUp();	/* setup items width */
						pb = FALSE;
					}
					FreeMem(filebuf, bufsize);
				}
			}
		}
		FreeMem(fib, sizeof(struct FileInfoBlock));
	}
	UnLock(lock);
	if (pb) {
		strcpy(msg, "Error reading ");
		strcat(msg, CurCfg);
		Warn(msg);
		return FALSE;
	}
	return stat;
}

