1 /* @(#)parse.c 1.11 16/02/14 Copyright 2001-2010 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)parse.c 1.11 16/02/14 Copyright 2001-2010 J. Schilling";
6 #endif
7 /*
8 * Interactive command parser for cdda2wav
9 *
10 * Copyright (c) 2001-2010 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 /*
27 * Commands:
28 * read <start-sector>
29 *
30 * Replies:
31 * 200 OK
32 * 400 Bad Request
33 * 404 Not Found
34 */
35
36 #include <schily/mconfig.h>
37 #include <schily/stdio.h>
38 #include <schily/standard.h>
39 #include <schily/ctype.h>
40 #include <schily/jmpdefs.h>
41 #include <schily/string.h>
42 #include <schily/utypes.h>
43 #include <schily/varargs.h>
44 #include <schily/schily.h>
45 #include <schily/nlsdefs.h>
46
47 #include "toc.h"
48
49 #define E_ISOK 200 /* E_OK is used with euid access() */
50 #define E_BAD 400
51 #define E_NOTFOUND 404
52
53 #define C_BAD 0
54 #define C_STOP 1
55 #define C_CONT 2
56 #define C_READ 3
57 #define C_EXIT 4
58 #define C_HELP 5
59
60 typedef struct cmd {
61 int cmd;
62 int argtype;
63 long arg;
64 } cmd_t;
65
66 typedef struct keyw {
67 char *k_name;
68 int k_type;
69 } keyw_t;
70
71 LOCAL keyw_t keywords[] = {
72 { "stop", C_STOP },
73 { "cont", C_CONT },
74 { "read", C_READ },
75 { "exit", C_EXIT },
76 { "quit", C_EXIT },
77 { "help", C_HELP },
78 { NULL, 0 },
79 };
80
81 typedef struct err {
82 int num;
83 char *name;
84 } err_t;
85
86 LOCAL err_t errs[] = {
87 { E_ISOK, "OK" },
88 { E_BAD, "Bad Request" },
89 { E_NOTFOUND, "Not Found" },
90 { -1, NULL },
91 };
92
93 LOCAL sigjmps_t jmp;
94
95
96 EXPORT int parse __PR((long *lp));
97 LOCAL keyw_t *lookup __PR((char *word, keyw_t table[]));
98
99 LOCAL FILE *pfopen __PR((char *name));
100 #ifdef __needed__
101 LOCAL char *pfname __PR((void));
102 #endif
103 LOCAL char *nextline __PR((FILE *f));
104 #ifdef __needed__
105 LOCAL void ungetline __PR((void));
106 #endif
107 LOCAL char *skipwhite __PR((const char *s));
108 LOCAL char *peekword __PR((void));
109 LOCAL char *lineend __PR((void));
110 LOCAL char *markword __PR((char *delim));
111 #ifdef __needed__
112 LOCAL char getworddelim __PR((void));
113 #endif
114 LOCAL char *getnextitem __PR((char *delim));
115 #ifdef __needed__
116 LOCAL char *neednextitem __PR((char *delim));
117 #endif
118 LOCAL char *nextword __PR((void));
119 #ifdef __needed__
120 LOCAL char *needword __PR((void));
121 LOCAL char *curword __PR((void));
122 LOCAL char *nextitem __PR((void));
123 LOCAL char *needitem __PR((void));
124 #endif
125 LOCAL void checkextra __PR((void));
126 LOCAL void pabort __PR((int errnum, const char *fmt, ...));
127 LOCAL void wok __PR((void));
128 LOCAL void pusage __PR((void));
129
130
131 EXPORT int
parse(lp)132 parse(lp)
133 long *lp;
134 {
135 long l;
136 register keyw_t *kp;
137 char *p;
138 cmd_t cmd;
139 static FILE *f;
140
141 if (f == NULL)
142 f = pfopen(NULL);
143 if (f == NULL)
144 return (-1);
145 again:
146 if (sigsetjmp(jmp.jb, 1) != 0) {
147 /*
148 * We come here from siglongjmp()
149 */
150 ;
151 }
152 if ((p = nextline(f)) == NULL)
153 return (-1);
154
155 p = nextword();
156 kp = lookup(p, keywords);
157 if (kp) {
158 extern void drop_all_buffers __PR((void));
159
160 cmd.cmd = kp->k_type;
161 switch (kp->k_type) {
162
163 case C_STOP:
164 /* Flush buffers */
165 #ifdef _is_working_
166 drop_all_buffers();
167 #endif
168 wok();
169 goto again;
170 case C_CONT:
171 wok();
172 return (0);
173 case C_READ:
174 p = nextword();
175 if (streql(p, "sectors")) {
176 p = nextword();
177 if (*astol(p, &l) != '\0') {
178 pabort(E_BAD, _("Not a number '%s'"), p);
179 }
180 *lp = l;
181 } else if (streql(p, "tracks")) {
182 p = nextword();
183 if (*astol(p, &l) != '\0') {
184 pabort(E_BAD, _("Not a number '%s'"), p);
185 }
186 if (l < FirstAudioTrack() || l > LastAudioTrack())
187 pabort(E_BAD, _("Bad track number '%s'"), p);
188 *lp = Get_StartSector(l);
189 } else {
190 pabort(E_BAD, _("Bad 'read' parameter '%s'"), p);
191 }
192 wok();
193 break;
194 case C_EXIT:
195 wok();
196 return (-1);
197 case C_HELP:
198 pusage();
199 wok();
200 goto again;
201 default:
202 pabort(E_NOTFOUND, _("Unknown command '%s'"), p);
203 return (0);
204 }
205 checkextra();
206 return (0);
207 }
208 /* checkextra();*/
209 pabort(E_NOTFOUND, _("Unknown command '%s'"), p);
210 return (0);
211 }
212
213 LOCAL keyw_t *
lookup(word,table)214 lookup(word, table)
215 char *word;
216 keyw_t table[];
217 {
218 register keyw_t *kp = table;
219
220 while (kp->k_name) {
221 if (streql(kp->k_name, word))
222 return (kp);
223 kp++;
224 }
225 return (NULL);
226 }
227
228 /*--------------------------------------------------------------------------*/
229 /*
230 * Parser low level functions start here...
231 */
232
233 LOCAL char linebuf[4096];
234 LOCAL char *fname;
235 LOCAL char *linep;
236 LOCAL char *wordendp;
237 LOCAL char wordendc;
238 LOCAL int olinelen;
239 LOCAL int linelen;
240 LOCAL int lineno;
241
242 LOCAL char worddelim[] = "=:,/";
243 #ifdef __needed__
244 LOCAL char nulldelim[] = "";
245 #endif
246
247 #ifdef DEBUG
248 LOCAL void
wdebug()249 wdebug()
250 {
251 printf("WORD: '%s' rest '%s'\n", linep, peekword());
252 printf("linep %lX peekword %lX end %lX\n",
253 (long)linep, (long)peekword(), (long)&linebuf[linelen]);
254 }
255 #endif
256
257 LOCAL FILE *
pfopen(name)258 pfopen(name)
259 char *name;
260 {
261 FILE *f;
262
263 if (name == NULL) {
264 fname = "stdin";
265 return (stdin);
266 }
267 f = fileopen(name, "r");
268 if (f == NULL)
269 comerr(_("Cannot open '%s'.\n"), name);
270
271 fname = name;
272 return (f);
273 }
274
275 #ifdef __needed__
276 LOCAL char *
pfname()277 pfname()
278 {
279 return (fname);
280 }
281 #endif
282
283 LOCAL char *
nextline(f)284 nextline(f)
285 FILE *f;
286 {
287 do {
288 register int len;
289
290 fillbytes(linebuf, sizeof (linebuf), '\0');
291 len = fgetline(f, linebuf, sizeof (linebuf));
292 if (len < 0)
293 return (NULL);
294 if (len > 0 && linebuf[len-1] == '\r') {
295 linebuf[len-1] = '\0';
296 len--;
297 }
298 linelen = len;
299 lineno++;
300 } while (linebuf[0] == '#');
301
302 olinelen = linelen;
303 linep = linebuf;
304 wordendp = linep;
305 wordendc = *linep;
306
307 return (linep);
308 }
309
310 #ifdef __needed__
311 LOCAL void
ungetline()312 ungetline()
313 {
314 linelen = olinelen;
315 linep = linebuf;
316 *wordendp = wordendc;
317 wordendp = linep;
318 wordendc = *linep;
319 }
320 #endif
321
322 LOCAL char *
skipwhite(s)323 skipwhite(s)
324 const char *s;
325 {
326 register const Uchar *p = (const Uchar *)s;
327
328 while (*p) {
329 if (!isspace(*p))
330 break;
331 p++;
332 }
333 return ((char *)p);
334 }
335
336 LOCAL char *
peekword()337 peekword()
338 {
339 return (&wordendp[1]);
340 }
341
342 LOCAL char *
lineend()343 lineend()
344 {
345 return (&linebuf[linelen]);
346 }
347
348 LOCAL char *
markword(delim)349 markword(delim)
350 char *delim;
351 {
352 register BOOL quoted = FALSE;
353 register Uchar c;
354 register Uchar *s;
355 register Uchar *from;
356 register Uchar *to;
357
358 for (s = (Uchar *)linep; (c = *s) != '\0'; s++) {
359 if (c == '"') {
360 quoted = !quoted;
361 for (to = s, from = &s[1]; *from; ) {
362 c = *from++;
363 if (c == '\\' && quoted && (*from == '\\' || *from == '"'))
364 c = *from++;
365 *to++ = c;
366 }
367 *to = '\0';
368 c = *s;
369 linelen--;
370 }
371 if (!quoted && isspace(c))
372 break;
373 if (!quoted && strchr(delim, c) && s > (Uchar *)linep)
374 break;
375 }
376 wordendp = (char *)s;
377 wordendc = (char)*s;
378 *s = '\0';
379
380 return (linep);
381 }
382
383 #ifdef __needed__
384 LOCAL char
getworddelim()385 getworddelim()
386 {
387 return (wordendc);
388 }
389 #endif
390
391 LOCAL char *
getnextitem(delim)392 getnextitem(delim)
393 char *delim;
394 {
395 *wordendp = wordendc;
396
397 linep = skipwhite(wordendp);
398 return (markword(delim));
399 }
400
401 #ifdef __needed__
402 LOCAL char *
neednextitem(delim)403 neednextitem(delim)
404 char *delim;
405 {
406 char *olinep = linep;
407 char *nlinep;
408
409 nlinep = getnextitem(delim);
410
411 if ((olinep == nlinep) || (*nlinep == '\0'))
412 pabort(E_BAD, _("Missing text"));
413
414 return (nlinep);
415 }
416 #endif
417
418 LOCAL char *
nextword()419 nextword()
420 {
421 return (getnextitem(worddelim));
422 }
423
424 #ifdef __needed__
425 LOCAL char *
needword()426 needword()
427 {
428 return (neednextitem(worddelim));
429 }
430
431 LOCAL char *
curword()432 curword()
433 {
434 return (linep);
435 }
436
437 LOCAL char *
nextitem()438 nextitem()
439 {
440 return (getnextitem(nulldelim));
441 }
442
443 LOCAL char *
needitem()444 needitem()
445 {
446 return (neednextitem(nulldelim));
447 }
448 #endif
449
450 LOCAL void
checkextra()451 checkextra()
452 {
453 if (peekword() < lineend())
454 pabort(E_BAD, _("Extra text '%s'"), peekword());
455 }
456
457 /* VARARGS1 */
458 #ifdef PROTOTYPES
459 LOCAL void
pabort(int errnum,const char * fmt,...)460 pabort(int errnum, const char *fmt, ...)
461 #else
462 LOCAL void
463 pabort(errnum, fmt, va_alist)
464 int errnum;
465 char *fmt;
466 va_dcl
467 #endif
468 {
469 va_list args;
470 err_t *ep = errs;
471
472 #ifdef PROTOTYPES
473 va_start(args, fmt);
474 #else
475 va_start(args);
476 #endif
477 while (ep->num >= 0) {
478 if (ep->num == errnum)
479 break;
480 ep++;
481 }
482 if (ep->num >= 0) {
483 error("%d %s. ", ep->num, ep->name);
484 }
485 errmsgno(EX_BAD, _("%r on line %d in '%s'.\n"),
486 fmt, args, lineno, fname);
487 va_end(args);
488 siglongjmp(jmp.jb, 1);
489 }
490
491 LOCAL void
wok()492 wok()
493 {
494 error("200 OK\n");
495 }
496
497 LOCAL void
pusage()498 pusage()
499 {
500 error(_("Usage:\n"));
501 error(_(" command parameters descriptionn\n"));
502 error(_(" ============================================\n"));
503 error(_(" stop stop processing and wait for new input.\n"));
504 error(_(" cont continue processing.\n"));
505 error(_(" read sectors <sector number> read sectors starting from sector number.\n"));
506 error(_(" read tracks <track number> read sectors starting from track number.\n"));
507 error(_(" exit exit processing.\n"));
508 error(_(" quit exit processing.\n"));
509 error(_(" help print this help and wait for new input.\n"));
510 }
511