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