xref: /dflybsd-src/usr.bin/dfregress/parser.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (c) 2009-2011 Alex Hornung <alex@alexhornung.com>.
3*86d7f5d3SJohn Marino  * All rights reserved.
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino  * are met:
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
10*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
11*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
12*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in
13*86d7f5d3SJohn Marino  *    the documentation and/or other materials provided with the
14*86d7f5d3SJohn Marino  *    distribution.
15*86d7f5d3SJohn Marino  *
16*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17*86d7f5d3SJohn Marino  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18*86d7f5d3SJohn Marino  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19*86d7f5d3SJohn Marino  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
20*86d7f5d3SJohn Marino  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21*86d7f5d3SJohn Marino  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22*86d7f5d3SJohn Marino  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23*86d7f5d3SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24*86d7f5d3SJohn Marino  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25*86d7f5d3SJohn Marino  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26*86d7f5d3SJohn Marino  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*86d7f5d3SJohn Marino  * SUCH DAMAGE.
28*86d7f5d3SJohn Marino  */
29*86d7f5d3SJohn Marino 
30*86d7f5d3SJohn Marino #include <stdio.h>
31*86d7f5d3SJohn Marino #include <stdarg.h>
32*86d7f5d3SJohn Marino #include <string.h>
33*86d7f5d3SJohn Marino #include <stdlib.h>
34*86d7f5d3SJohn Marino #include <unistd.h>
35*86d7f5d3SJohn Marino #include <errno.h>
36*86d7f5d3SJohn Marino #include <err.h>
37*86d7f5d3SJohn Marino #include "parser.h"
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino #define _iswhitespace(X)	((((X) == ' ') || ((X) == '\t'))?1:0)
40*86d7f5d3SJohn Marino 
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino static int line_no = 1;
43*86d7f5d3SJohn Marino 
iswhitespace(char c)44*86d7f5d3SJohn Marino static int iswhitespace(char c)
45*86d7f5d3SJohn Marino {
46*86d7f5d3SJohn Marino 	return _iswhitespace(c);
47*86d7f5d3SJohn Marino }
48*86d7f5d3SJohn Marino 
iscomma(char c)49*86d7f5d3SJohn Marino static int iscomma(char c)
50*86d7f5d3SJohn Marino {
51*86d7f5d3SJohn Marino 	return (c == ',');
52*86d7f5d3SJohn Marino }
53*86d7f5d3SJohn Marino 
54*86d7f5d3SJohn Marino void
syntax_error(const char * fmt,...)55*86d7f5d3SJohn Marino syntax_error(const char *fmt, ...)
56*86d7f5d3SJohn Marino {
57*86d7f5d3SJohn Marino 	char buf[1024];
58*86d7f5d3SJohn Marino 	va_list ap;
59*86d7f5d3SJohn Marino 
60*86d7f5d3SJohn Marino 	va_start(ap, fmt);
61*86d7f5d3SJohn Marino 	vsnprintf(buf, sizeof(buf), fmt, ap);
62*86d7f5d3SJohn Marino 	va_end(ap);
63*86d7f5d3SJohn Marino 	errx(1, "syntax error on line %d: %s\n", line_no, buf);
64*86d7f5d3SJohn Marino }
65*86d7f5d3SJohn Marino 
66*86d7f5d3SJohn Marino 
67*86d7f5d3SJohn Marino int
entry_check_num_args(char ** tokens,int num)68*86d7f5d3SJohn Marino entry_check_num_args(char **tokens, int num)
69*86d7f5d3SJohn Marino {
70*86d7f5d3SJohn Marino 	int i;
71*86d7f5d3SJohn Marino 
72*86d7f5d3SJohn Marino 	for (i = 0; tokens[i] != NULL; i++)
73*86d7f5d3SJohn Marino 		;
74*86d7f5d3SJohn Marino 
75*86d7f5d3SJohn Marino 	if (i < num) {
76*86d7f5d3SJohn Marino 		syntax_error("at least %d tokens were expected but only %d "
77*86d7f5d3SJohn Marino 		    "were found", num, i);
78*86d7f5d3SJohn Marino 		return 1;
79*86d7f5d3SJohn Marino 	}
80*86d7f5d3SJohn Marino 	return 0;
81*86d7f5d3SJohn Marino }
82*86d7f5d3SJohn Marino 
83*86d7f5d3SJohn Marino static int
line_tokenize(char * buffer,int (* is_sep)(char),char comment_char,char ** tokens)84*86d7f5d3SJohn Marino line_tokenize(char *buffer, int (*is_sep)(char), char comment_char, char **tokens)
85*86d7f5d3SJohn Marino {
86*86d7f5d3SJohn Marino 	int c, n, i;
87*86d7f5d3SJohn Marino 	int quote = 0;
88*86d7f5d3SJohn Marino 
89*86d7f5d3SJohn Marino 	i = strlen(buffer) + 1;
90*86d7f5d3SJohn Marino 	c = 0;
91*86d7f5d3SJohn Marino 
92*86d7f5d3SJohn Marino 	/* Skip leading white-space */
93*86d7f5d3SJohn Marino 	while ((_iswhitespace(buffer[c])) && (c < i)) c++;
94*86d7f5d3SJohn Marino 
95*86d7f5d3SJohn Marino 	/*
96*86d7f5d3SJohn Marino 	 * If this line effectively (after indentation) begins with the comment
97*86d7f5d3SJohn Marino 	 * character, we ignore the rest of the line.
98*86d7f5d3SJohn Marino 	 */
99*86d7f5d3SJohn Marino 	if (buffer[c] == comment_char)
100*86d7f5d3SJohn Marino 		return 0;
101*86d7f5d3SJohn Marino 
102*86d7f5d3SJohn Marino 	tokens[0] = &buffer[c];
103*86d7f5d3SJohn Marino 	for (n = 1; c < i; c++) {
104*86d7f5d3SJohn Marino 		if (buffer[c] == '"') {
105*86d7f5d3SJohn Marino 			quote = !quote;
106*86d7f5d3SJohn Marino 			if (quote) {
107*86d7f5d3SJohn Marino 				if ((c >= 1) && (&buffer[c] != tokens[n-1])) {
108*86d7f5d3SJohn Marino #if 0
109*86d7f5d3SJohn Marino 					syntax_error("stray opening quote not "
110*86d7f5d3SJohn Marino 					    "at beginning of token");
111*86d7f5d3SJohn Marino 					/* NOTREACHED */
112*86d7f5d3SJohn Marino #endif
113*86d7f5d3SJohn Marino 				} else {
114*86d7f5d3SJohn Marino 					tokens[n-1] = &buffer[c+1];
115*86d7f5d3SJohn Marino 				}
116*86d7f5d3SJohn Marino 			} else {
117*86d7f5d3SJohn Marino 				if ((c < i-1) && (!is_sep(buffer[c+1]))) {
118*86d7f5d3SJohn Marino #if 0
119*86d7f5d3SJohn Marino 					syntax_error("stray closing quote not "
120*86d7f5d3SJohn Marino 					    "at end of token");
121*86d7f5d3SJohn Marino 					/* NOTREACHED */
122*86d7f5d3SJohn Marino #endif
123*86d7f5d3SJohn Marino 				} else {
124*86d7f5d3SJohn Marino 					buffer[c] = '\0';
125*86d7f5d3SJohn Marino 				}
126*86d7f5d3SJohn Marino 			}
127*86d7f5d3SJohn Marino 		}
128*86d7f5d3SJohn Marino 
129*86d7f5d3SJohn Marino 		if (quote) {
130*86d7f5d3SJohn Marino 			continue;
131*86d7f5d3SJohn Marino 		}
132*86d7f5d3SJohn Marino 
133*86d7f5d3SJohn Marino 		if (is_sep(buffer[c])) {
134*86d7f5d3SJohn Marino 			buffer[c++] = '\0';
135*86d7f5d3SJohn Marino 			while ((_iswhitespace(buffer[c])) && (c < i)) c++;
136*86d7f5d3SJohn Marino 			tokens[n++] = &buffer[c--];
137*86d7f5d3SJohn Marino 		}
138*86d7f5d3SJohn Marino 	}
139*86d7f5d3SJohn Marino 	tokens[n] = NULL;
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino 	if (quote) {
142*86d7f5d3SJohn Marino 		tokens[0] = NULL;
143*86d7f5d3SJohn Marino 		return 0;
144*86d7f5d3SJohn Marino 	}
145*86d7f5d3SJohn Marino 
146*86d7f5d3SJohn Marino 	return n;
147*86d7f5d3SJohn Marino }
148*86d7f5d3SJohn Marino 
149*86d7f5d3SJohn Marino static int
process_line(FILE * fd,parser_t parser,void * arg)150*86d7f5d3SJohn Marino process_line(FILE* fd, parser_t parser, void *arg)
151*86d7f5d3SJohn Marino {
152*86d7f5d3SJohn Marino 	char buffer[4096];
153*86d7f5d3SJohn Marino 	char *tokens[256];
154*86d7f5d3SJohn Marino 	int c, n, i = 0;
155*86d7f5d3SJohn Marino 	int ret = 0;
156*86d7f5d3SJohn Marino 
157*86d7f5d3SJohn Marino 	while (((c = fgetc(fd)) != EOF) && (c != '\n')) {
158*86d7f5d3SJohn Marino 		buffer[i++] = (char)c;
159*86d7f5d3SJohn Marino 		if (i == (sizeof(buffer) -1))
160*86d7f5d3SJohn Marino 			break;
161*86d7f5d3SJohn Marino 	}
162*86d7f5d3SJohn Marino 	buffer[i] = '\0';
163*86d7f5d3SJohn Marino 
164*86d7f5d3SJohn Marino 	if (feof(fd) || ferror(fd))
165*86d7f5d3SJohn Marino 		ret = 1;
166*86d7f5d3SJohn Marino 
167*86d7f5d3SJohn Marino 
168*86d7f5d3SJohn Marino 	n = line_tokenize(buffer, &iswhitespace, '#', tokens);
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino 	/*
171*86d7f5d3SJohn Marino 	 * If there are not enough arguments for any function or it is
172*86d7f5d3SJohn Marino 	 * a line full of whitespaces, we just return here. Or if a
173*86d7f5d3SJohn Marino 	 * quote wasn't closed.
174*86d7f5d3SJohn Marino 	 */
175*86d7f5d3SJohn Marino 	if ((n < 1) || (tokens[0][0] == '\0'))
176*86d7f5d3SJohn Marino 		return ret;
177*86d7f5d3SJohn Marino 
178*86d7f5d3SJohn Marino 	parser(arg, tokens);
179*86d7f5d3SJohn Marino 
180*86d7f5d3SJohn Marino 	return ret;
181*86d7f5d3SJohn Marino }
182*86d7f5d3SJohn Marino 
183*86d7f5d3SJohn Marino int
parse_options(char * str,char ** options)184*86d7f5d3SJohn Marino parse_options(char *str, char **options)
185*86d7f5d3SJohn Marino {
186*86d7f5d3SJohn Marino 	int i;
187*86d7f5d3SJohn Marino 
188*86d7f5d3SJohn Marino 	i = line_tokenize(str, &iscomma, '#', options);
189*86d7f5d3SJohn Marino 	if (i == 0)
190*86d7f5d3SJohn Marino 		syntax_error("Invalid expression in options token");
191*86d7f5d3SJohn Marino 		/* NOTREACHED */
192*86d7f5d3SJohn Marino 
193*86d7f5d3SJohn Marino 	return i;
194*86d7f5d3SJohn Marino }
195*86d7f5d3SJohn Marino 
196*86d7f5d3SJohn Marino int
process_file(const char * file,parser_t parser,void * arg,int * nlines)197*86d7f5d3SJohn Marino process_file(const char *file, parser_t parser, void *arg, int *nlines)
198*86d7f5d3SJohn Marino {
199*86d7f5d3SJohn Marino 	FILE *fd;
200*86d7f5d3SJohn Marino 
201*86d7f5d3SJohn Marino 	line_no = 0;
202*86d7f5d3SJohn Marino 
203*86d7f5d3SJohn Marino 	fd = fopen(file, "r");
204*86d7f5d3SJohn Marino 	if (fd == NULL)
205*86d7f5d3SJohn Marino 		err(1, "fopen");
206*86d7f5d3SJohn Marino 		/* NOTREACHED */
207*86d7f5d3SJohn Marino 
208*86d7f5d3SJohn Marino 	while (process_line(fd, parser, arg) == 0)
209*86d7f5d3SJohn Marino 		++line_no;
210*86d7f5d3SJohn Marino 
211*86d7f5d3SJohn Marino 	fclose(fd);
212*86d7f5d3SJohn Marino 
213*86d7f5d3SJohn Marino 	if (nlines != NULL)
214*86d7f5d3SJohn Marino 		*nlines = line_no;
215*86d7f5d3SJohn Marino 
216*86d7f5d3SJohn Marino 	return 0;
217*86d7f5d3SJohn Marino }
218*86d7f5d3SJohn Marino 
219