/* * Parse.c - Copyright © 1990 by S.R. & P.C. * * Created: 16 Jun 1990 * Modified: 09 Dec 1990 17:38:26 * * Make>> make */ #include "Tokens.h" /***** external functions *****/ 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 struct Menu Menu1; extern char CurCfg[]; extern char CmdWindow[]; extern char ShellWindow[]; extern char ShellCmd[]; extern char WaitCmd[]; extern char TmpDir[]; extern long DefaultStack; extern UBYTE menu_pen; extern char *ReqTitle; /***** local variables *****/ static char *KeyWordTab[] = { NULL, "ITEM", "ARUN", "RUN", "SHELL", "WB", "CFG", "WIN", "PRI", "STACK", "MENU", "SUBMENU", "ENDSUBMENU", "COLOR", "CMDWIN", "SHELLWIN", "SHELLCMD", "WAITCMD", "TMPDIR" }; /* status */ #define STAT_BEGIN 0 #define STAT_MENU 1 #define STAT_SUBMENU 2 #define STAT_ITEM 4 static char *FileBuffer, *CurrentLine, *NextLine, *Byte, *LastByte; static short LineNum; static char tok[200]; /* add the position of the error to the error message */ static void Err(char *msg) { SimpleRequest(ReqTitle, "%s\nLine %d, Char %ld", msg, LineNum, Byte-CurrentLine+1); } #define SYNTAX(msg) { Err(msg); return FALSE; } static BOOL get_line(void) { register char *s,c; s = CurrentLine = NextLine; if (!*s) return FALSE; while ((c = *s++) != 10 && c); if (c) *(s-1) = '\0'; NextLine = s; LineNum++; Byte = CurrentLine; return TRUE; } /* * b is a register variable used to replace global Byte pointer in * get_token() body. Then, Byte must be restored before leaving. */ static char get_token(void) { register char *p, *b, c; short i; char quote; b = Byte; while ((c = *b) == ' ' || c == '\t') b++; /* skip extra spaces */ if (c == '#') /* comment */ return 0; LastByte = b; /* save address of next token */ if (c < 32 || c == '{' || c == '}') { Byte = (c) ? b+1 : b; /* prevent skipping of sentinel */ return c; /* '{', '}', '\0', or invalid char */ } /* scan string */ p = tok; if (c == '"') { b++; quote = TRUE; } else quote = FALSE; while ((quote && *b != '"' && *b) || (!quote && *b > 32 && *b != ';')) *p++ = *b++; *p = '\0'; if (quote) b++; /* skip closing '"' */ for (i = 1; i <= MAX_KEYWORD; i++) { if (!Strcmp(tok, KeyWordTab[i])) break; /* arp Strcmp() is not case sensitive */ } Byte = b; return i; } /* * Parse a line that may contain semicolons. Backslash ('\') is the override * char. This function is called from ParseConfig() and from Command(). */ void ParseLine(char *cmd) { register char *s,*d,c; s = d = cmd; while (c = *d++ = *s++) { if (c == '\\') *(d-1) = *s++; else if (c == ';') *(d-1) = '\n'; } } static BOOL ParseConfig(void) { char t, shortcut, mode; long stack; short pri; USHORT status = STAT_BEGIN; char *args, *cmd, *win; char itemstr[80], cmdstr[100], winstr[80]; FreeMenus(); while( get_line() ) { switch (t = get_token()) { case TOK_MENU: if (!(status & (STAT_MENU | STAT_ITEM)) && status != STAT_BEGIN) SYNTAX("Unexpected MENU") status = STAT_MENU; if (get_token()) AddMenu(tok); else SYNTAX("Unexpected end of line"); break; case TOK_SUBMENU: if (!(status & STAT_MENU) || (status & STAT_SUBMENU)) SYNTAX("Unexpected SUBMENU") status = STAT_SUBMENU; if (get_token()) AddSubMenu(tok); else SYNTAX("Unexpected end of line"); break; case TOK_ENDSUBMENU: if (!(status & STAT_SUBMENU) || !(status & STAT_ITEM)) SYNTAX("Unexpected ENDSUBMENU") EndSubMenu(); status = STAT_MENU | STAT_ITEM; break; case TOK_ITEM: if (status == STAT_BEGIN) SYNTAX("Unexpected ITEM") status |= STAT_ITEM; shortcut = pri = 0; stack = DefaultStack; win = args = NULL; cmd = cmdstr; if (get_token() == '{') { /* command char */ shortcut = *Byte++; if (get_token() != '}') SYNTAX("Missing closing '}'"); get_token(); } strcpy(itemstr, tok); switch (mode = get_token()) { case TOK_WB: stack = 0; /* Tell WBRun to take icon stack as default */ case TOK_SHELL: case TOK_ARUN: case TOK_RUN: while ((t = get_token())==TOK_WIN || t==TOK_STACK || t==TOK_PRI) { if (!get_token()) SYNTAX("Unexpected end of line"); switch (t) { case TOK_WIN: if (mode == TOK_RUN || mode == TOK_WB) SYNTAX("WIN not allowed in this mode") strcpy(winstr, tok); win = winstr; break; case TOK_STACK: stack = Atol(tok); if (IoErr() || stack < 2000) SYNTAX("Invalid stack") break; case TOK_PRI: pri = Atol(tok); if (IoErr() || pri < -128 || pri > 127) SYNTAX("Priority out of range") break; } } if (!t) SYNTAX("Unexpected end of line"); switch(mode) { case TOK_ARUN: args = Byte; case TOK_WB: strcpy(cmdstr, tok); break; case TOK_SHELL: ParseLine(LastByte); default: /* RUN mode */ cmd = LastByte; } break; case TOK_CFG: if (!get_token()) SYNTAX("Unexpected end of line"); strcpy(cmdstr, tok); break; default: Err("WB, ARUN, RUN, SHELL or CFG Expected"); return FALSE; } AddEntry(itemstr, cmd, args, win, shortcut, mode, stack, pri); break; case TOK_COLOR: get_token(); menu_pen = ((menu_pen = Atol(tok)) == Win->BlockPen) ? Win->DetailPen : menu_pen; /* control if blockpen and detailpen are different */ break; case TOK_CMDWIN: if (get_token()) strcpy(CmdWindow, tok); break; case TOK_SHELLWIN: if (get_token()) strcpy(ShellWindow, tok); break; case TOK_SHELLCMD: if (get_token()) strcpy(ShellCmd, tok); break; case TOK_WAITCMD: if (get_token()) strcpy(WaitCmd, tok); break; case TOK_TMPDIR: if (get_token()) strcpy(TmpDir, tok); break; default: if (t) /* allow empty lines */ SYNTAX("Keyword expected") } } return TRUE; } BOOL ParseMenus(void) { BPTR lock, cfg; struct FileInfoBlock *fib; long bufsize, nch; BOOL stat; BOOL pb = TRUE; if (!(lock = Lock(CurCfg, ACCESS_READ))) { SimpleRequest(ReqTitle,"Can't open '%s'",CurCfg); 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 (FileBuffer = AllocMem(bufsize, MEMF_PUBLIC|MEMF_CLEAR)) { cfg = Open(CurCfg, MODE_OLDFILE); nch = Read(cfg, FileBuffer, bufsize-1); Close(cfg); if (nch == fib->fib_Size) { NextLine = FileBuffer; LineNum = 0; stat = ParseConfig(); CleanUp(); /* setup items width */ pb = FALSE; } FreeMem(FileBuffer, bufsize); } } } FreeMem(fib, sizeof(struct FileInfoBlock)); } UnLock(lock); if (pb) { SimpleRequest(ReqTitle, "Error reading '%s'", CurCfg); return FALSE; } return stat; }