/* @(#)parse.c 1.11 16/02/14 Copyright 2001-2010 J. Schilling */ #include #ifndef lint static UConst char sccsid[] = "@(#)parse.c 1.11 16/02/14 Copyright 2001-2010 J. Schilling"; #endif /* * Interactive command parser for cdda2wav * * Copyright (c) 2001-2010 J. Schilling */ /* * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * See the file CDDL.Schily.txt in this distribution for details. * A copy of the CDDL is also available via the Internet at * http://www.opensource.org/licenses/cddl1.txt * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file CDDL.Schily.txt from this distribution. */ /* * Commands: * read * * Replies: * 200 OK * 400 Bad Request * 404 Not Found */ #include #include #include #include #include #include #include #include #include #include #include "toc.h" #define E_ISOK 200 /* E_OK is used with euid access() */ #define E_BAD 400 #define E_NOTFOUND 404 #define C_BAD 0 #define C_STOP 1 #define C_CONT 2 #define C_READ 3 #define C_EXIT 4 #define C_HELP 5 typedef struct cmd { int cmd; int argtype; long arg; } cmd_t; typedef struct keyw { char *k_name; int k_type; } keyw_t; LOCAL keyw_t keywords[] = { { "stop", C_STOP }, { "cont", C_CONT }, { "read", C_READ }, { "exit", C_EXIT }, { "quit", C_EXIT }, { "help", C_HELP }, { NULL, 0 }, }; typedef struct err { int num; char *name; } err_t; LOCAL err_t errs[] = { { E_ISOK, "OK" }, { E_BAD, "Bad Request" }, { E_NOTFOUND, "Not Found" }, { -1, NULL }, }; LOCAL sigjmps_t jmp; EXPORT int parse __PR((long *lp)); LOCAL keyw_t *lookup __PR((char *word, keyw_t table[])); LOCAL FILE *pfopen __PR((char *name)); #ifdef __needed__ LOCAL char *pfname __PR((void)); #endif LOCAL char *nextline __PR((FILE *f)); #ifdef __needed__ LOCAL void ungetline __PR((void)); #endif LOCAL char *skipwhite __PR((const char *s)); LOCAL char *peekword __PR((void)); LOCAL char *lineend __PR((void)); LOCAL char *markword __PR((char *delim)); #ifdef __needed__ LOCAL char getworddelim __PR((void)); #endif LOCAL char *getnextitem __PR((char *delim)); #ifdef __needed__ LOCAL char *neednextitem __PR((char *delim)); #endif LOCAL char *nextword __PR((void)); #ifdef __needed__ LOCAL char *needword __PR((void)); LOCAL char *curword __PR((void)); LOCAL char *nextitem __PR((void)); LOCAL char *needitem __PR((void)); #endif LOCAL void checkextra __PR((void)); LOCAL void pabort __PR((int errnum, const char *fmt, ...)); LOCAL void wok __PR((void)); LOCAL void pusage __PR((void)); EXPORT int parse(lp) long *lp; { long l; register keyw_t *kp; char *p; cmd_t cmd; static FILE *f; if (f == NULL) f = pfopen(NULL); if (f == NULL) return (-1); again: if (sigsetjmp(jmp.jb, 1) != 0) { /* * We come here from siglongjmp() */ ; } if ((p = nextline(f)) == NULL) return (-1); p = nextword(); kp = lookup(p, keywords); if (kp) { extern void drop_all_buffers __PR((void)); cmd.cmd = kp->k_type; switch (kp->k_type) { case C_STOP: /* Flush buffers */ #ifdef _is_working_ drop_all_buffers(); #endif wok(); goto again; case C_CONT: wok(); return (0); case C_READ: p = nextword(); if (streql(p, "sectors")) { p = nextword(); if (*astol(p, &l) != '\0') { pabort(E_BAD, _("Not a number '%s'"), p); } *lp = l; } else if (streql(p, "tracks")) { p = nextword(); if (*astol(p, &l) != '\0') { pabort(E_BAD, _("Not a number '%s'"), p); } if (l < FirstAudioTrack() || l > LastAudioTrack()) pabort(E_BAD, _("Bad track number '%s'"), p); *lp = Get_StartSector(l); } else { pabort(E_BAD, _("Bad 'read' parameter '%s'"), p); } wok(); break; case C_EXIT: wok(); return (-1); case C_HELP: pusage(); wok(); goto again; default: pabort(E_NOTFOUND, _("Unknown command '%s'"), p); return (0); } checkextra(); return (0); } /* checkextra();*/ pabort(E_NOTFOUND, _("Unknown command '%s'"), p); return (0); } LOCAL keyw_t * lookup(word, table) char *word; keyw_t table[]; { register keyw_t *kp = table; while (kp->k_name) { if (streql(kp->k_name, word)) return (kp); kp++; } return (NULL); } /*--------------------------------------------------------------------------*/ /* * Parser low level functions start here... */ LOCAL char linebuf[4096]; LOCAL char *fname; LOCAL char *linep; LOCAL char *wordendp; LOCAL char wordendc; LOCAL int olinelen; LOCAL int linelen; LOCAL int lineno; LOCAL char worddelim[] = "=:,/"; #ifdef __needed__ LOCAL char nulldelim[] = ""; #endif #ifdef DEBUG LOCAL void wdebug() { printf("WORD: '%s' rest '%s'\n", linep, peekword()); printf("linep %lX peekword %lX end %lX\n", (long)linep, (long)peekword(), (long)&linebuf[linelen]); } #endif LOCAL FILE * pfopen(name) char *name; { FILE *f; if (name == NULL) { fname = "stdin"; return (stdin); } f = fileopen(name, "r"); if (f == NULL) comerr(_("Cannot open '%s'.\n"), name); fname = name; return (f); } #ifdef __needed__ LOCAL char * pfname() { return (fname); } #endif LOCAL char * nextline(f) FILE *f; { do { register int len; fillbytes(linebuf, sizeof (linebuf), '\0'); len = fgetline(f, linebuf, sizeof (linebuf)); if (len < 0) return (NULL); if (len > 0 && linebuf[len-1] == '\r') { linebuf[len-1] = '\0'; len--; } linelen = len; lineno++; } while (linebuf[0] == '#'); olinelen = linelen; linep = linebuf; wordendp = linep; wordendc = *linep; return (linep); } #ifdef __needed__ LOCAL void ungetline() { linelen = olinelen; linep = linebuf; *wordendp = wordendc; wordendp = linep; wordendc = *linep; } #endif LOCAL char * skipwhite(s) const char *s; { register const Uchar *p = (const Uchar *)s; while (*p) { if (!isspace(*p)) break; p++; } return ((char *)p); } LOCAL char * peekword() { return (&wordendp[1]); } LOCAL char * lineend() { return (&linebuf[linelen]); } LOCAL char * markword(delim) char *delim; { register BOOL quoted = FALSE; register Uchar c; register Uchar *s; register Uchar *from; register Uchar *to; for (s = (Uchar *)linep; (c = *s) != '\0'; s++) { if (c == '"') { quoted = !quoted; for (to = s, from = &s[1]; *from; ) { c = *from++; if (c == '\\' && quoted && (*from == '\\' || *from == '"')) c = *from++; *to++ = c; } *to = '\0'; c = *s; linelen--; } if (!quoted && isspace(c)) break; if (!quoted && strchr(delim, c) && s > (Uchar *)linep) break; } wordendp = (char *)s; wordendc = (char)*s; *s = '\0'; return (linep); } #ifdef __needed__ LOCAL char getworddelim() { return (wordendc); } #endif LOCAL char * getnextitem(delim) char *delim; { *wordendp = wordendc; linep = skipwhite(wordendp); return (markword(delim)); } #ifdef __needed__ LOCAL char * neednextitem(delim) char *delim; { char *olinep = linep; char *nlinep; nlinep = getnextitem(delim); if ((olinep == nlinep) || (*nlinep == '\0')) pabort(E_BAD, _("Missing text")); return (nlinep); } #endif LOCAL char * nextword() { return (getnextitem(worddelim)); } #ifdef __needed__ LOCAL char * needword() { return (neednextitem(worddelim)); } LOCAL char * curword() { return (linep); } LOCAL char * nextitem() { return (getnextitem(nulldelim)); } LOCAL char * needitem() { return (neednextitem(nulldelim)); } #endif LOCAL void checkextra() { if (peekword() < lineend()) pabort(E_BAD, _("Extra text '%s'"), peekword()); } /* VARARGS1 */ #ifdef PROTOTYPES LOCAL void pabort(int errnum, const char *fmt, ...) #else LOCAL void pabort(errnum, fmt, va_alist) int errnum; char *fmt; va_dcl #endif { va_list args; err_t *ep = errs; #ifdef PROTOTYPES va_start(args, fmt); #else va_start(args); #endif while (ep->num >= 0) { if (ep->num == errnum) break; ep++; } if (ep->num >= 0) { error("%d %s. ", ep->num, ep->name); } errmsgno(EX_BAD, _("%r on line %d in '%s'.\n"), fmt, args, lineno, fname); va_end(args); siglongjmp(jmp.jb, 1); } LOCAL void wok() { error("200 OK\n"); } LOCAL void pusage() { error(_("Usage:\n")); error(_(" command parameters descriptionn\n")); error(_(" ============================================\n")); error(_(" stop stop processing and wait for new input.\n")); error(_(" cont continue processing.\n")); error(_(" read sectors read sectors starting from sector number.\n")); error(_(" read tracks read sectors starting from track number.\n")); error(_(" exit exit processing.\n")); error(_(" quit exit processing.\n")); error(_(" help print this help and wait for new input.\n")); }