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