chan.c (chan_open): Actually initialize the error indicator.
[fwd] / conf.c
CommitLineData
e82f7154 1/* -*-c-*-
2 *
e82f7154 3 * Configuration parsing
4 *
61e3dbdf 5 * (c) 1999 Straylight/Edgeware
e82f7154 6 */
7
206212ca 8/*----- Licensing notice --------------------------------------------------*
e82f7154 9 *
9155ea97 10 * This file is part of the `fwd' port forwarder.
e82f7154 11 *
9155ea97 12 * `fwd' is free software; you can redistribute it and/or modify
e82f7154 13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
206212ca 16 *
9155ea97 17 * `fwd' is distributed in the hope that it will be useful,
e82f7154 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
206212ca 21 *
e82f7154 22 * You should have received a copy of the GNU General Public License
9155ea97 23 * along with `fwd'; if not, write to the Free Software Foundation,
e82f7154 24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
9155ea97 27#include "fwd.h"
e82f7154 28
29/*----- Main code ---------------------------------------------------------*/
30
2234f01d 31/* --- @conf_undelim@ --- *
e73034b0 32 *
2234f01d 33 * Arguments: @scanner *sc@ = pointer to scanner definition
34 * @const char *d, *dd@ = pointer to characters to escape
e73034b0 35 *
36 * Returns: ---
37 *
38 * Use: Modifies the tokenizer. Characters in the first list will
39 * always be considered to begin a word. Characters in the
40 * second list will always be allowed to continue a word.
41 */
42
2234f01d 43void conf_undelim(scanner *sc, const char *d, const char *dd)
44{
45 sc->wbegin = d;
46 sc->wcont = dd;
47}
e73034b0 48
e82f7154 49/* --- @token@ --- *
50 *
51 * Arguments: @scanner *sc@ = pointer to scanner definition
52 *
53 * Returns: Type of token scanned.
54 *
55 * Use: Reads the next token from the character scanner.
56 */
57
61e3dbdf 58int token(scanner *sc)
e82f7154 59{
61e3dbdf 60#define SELFDELIM \
61 '{': case '}': case '/': case ',': \
62 case '=': case ':': case ';': \
63 case '.': case '[': case ']'
e82f7154 64
65 int ch;
66
61e3dbdf 67 DRESET(&sc->d);
68
69 /* --- Main tokenization --- */
70
e82f7154 71 for (;;) {
61e3dbdf 72 ch = scan(sc);
73
74 /* --- Deal with pushed-back tokens --- */
75
76 if (sc->head->tok) {
77 dstr_puts(&sc->d, sc->head->tok);
c36e735a 78 xfree(sc->head->tok);
61e3dbdf 79 sc->head->tok = 0;
80 sc->t = sc->head->t;
81 goto done;
82 }
83
9e1c09df 84 else if (isspace(ch))
e82f7154 85 ;
86 else switch (ch) {
61e3dbdf 87
88 /* --- End of file --- */
89
e82f7154 90 case EOF:
61e3dbdf 91 sc->t = CTOK_EOF;
92 goto done;
93
94 /* --- Comment character --- */
95
e82f7154 96 case '#':
61e3dbdf 97 do ch = scan(sc); while (ch != EOF && ch != '\n');
e82f7154 98 break;
61e3dbdf 99
100 /* --- Various self-delimiting characters --- */
101
102 case SELFDELIM:
2234f01d 103 if (!sc->wbegin || strchr(sc->wbegin, ch) == 0) {
e73034b0 104 dstr_putc(&sc->d, ch);
105 dstr_putz(&sc->d);
106 sc->t = ch;
107 goto done;
108 }
61e3dbdf 109
110 /* --- Bare words --- *
111 *
112 * These aren't as bare any more. You can now backslash-escape
113 * individual characters, and enclose sections in double-quotes.
114 */
115
116 default: {
117 int q = 0;
118
119 for (;;) {
120 switch (ch) {
121 case EOF:
122 goto word;
123 case '\\':
124 ch = scan(sc);
125 if (ch == EOF)
126 goto word;
127 DPUTC(&sc->d, ch);
128 break;
129 case '\"':
130 q = !q;
131 break;
132 case SELFDELIM:
2234f01d 133 if (q || (sc->wcont && strchr(sc->wcont, ch)))
61e3dbdf 134 goto insert;
135 goto word;
136 default:
9e1c09df 137 if (!q && isspace(ch))
61e3dbdf 138 goto word;
139 insert:
140 DPUTC(&sc->d, ch);
141 break;
142 }
143 ch = scan(sc);
144 }
145 word:
146 unscan(sc, ch);
e82f7154 147 DPUTZ(&sc->d);
61e3dbdf 148 sc->t = CTOK_WORD;
149 goto done;
150 }
e82f7154 151 }
152 }
153
61e3dbdf 154done:
61e3dbdf 155 return (sc->t);
156}
157
158/* --- @pushback@ --- *
159 *
160 * Arguments: @scanner *sc@ = pointer to scanner definition
161 *
162 * Returns: ---
163 *
164 * Use: Pushes the current token back. This is normally a precursor
165 * to pushing a new scanner source.
166 */
167
c36e735a 168void pushback(scanner *sc)
61e3dbdf 169{
170 sc->head->tok = xstrdup(sc->d.buf);
171 sc->head->t = sc->t;
e82f7154 172}
173
174/* --- @error@ --- *
175 *
176 * Arguments: @scanner *sc@ = pointer to scanner definition
177 * @const char *msg@ = message skeleton string
178 * @...@ = extra arguments for the skeleton
179 *
180 * Returns: Doesn't
181 *
182 * Use: Reports an error at the current scanner location.
183 */
184
61e3dbdf 185void error(scanner *sc, const char *msg, ...)
e82f7154 186{
187 va_list ap;
188 va_start(ap, msg);
61e3dbdf 189 fprintf(stderr, "%s: %s:%i: ", QUIS, sc->head->src, sc->head->line);
e82f7154 190 vfprintf(stderr, msg, ap);
191 fputc('\n', stderr);
192 exit(1);
193}
194
61e3dbdf 195/* --- @conf_enum@ --- *
e82f7154 196 *
61e3dbdf 197 * Arguments: @scanner *sc@ = pointer to a scanner object
198 * @const char *list@ = comma-separated things to allow
199 * @unsigned f@ = flags for the search
200 * @const char *err@ = error message if not found
e82f7154 201 *
61e3dbdf 202 * Returns: Index into list, zero-based, or @-1@.
e82f7154 203 *
61e3dbdf 204 * Use: Checks whether the current token is a string which matches
82793759 205 * one of the comma-separated items given. The return value is
206 * the index (zero-based) of the matched string in the list.
207 *
208 * The flags control the behaviour if no exact match is found.
209 * If @ENUM_ABBREV@ is set, and the current token is a left
210 * substring of exactly one of the possibilities, then that one
211 * is chosen. If @ENUM_NONE@ is set, the value @-1@ is
212 * returned; otherwise an error is reported and the program is
213 * terminated.
e82f7154 214 */
215
61e3dbdf 216int conf_enum(scanner *sc, const char *list, unsigned f, const char *err)
e82f7154 217{
61e3dbdf 218 const char *p, *q;
219 int chosen = -1;
220 int ok;
221 int index;
222
223 /* --- Make sure it's a string --- */
224
225 if (sc->t != CTOK_WORD)
226 error(sc, "parse error, expected %s", err);
227
228 /* --- Grind through the list --- */
229
230 q = sc->d.buf;
231 ok = 1;
232 index = 0;
233 p = list;
234 for (;;) {
235 switch (*p) {
236 case 0:
237 if (ok && !*q) {
238 token(sc);
239 return (index);
240 } else if (chosen != -1) {
241 token(sc);
242 return (chosen);
243 }
244 else if (f & ENUM_NONE)
245 return (-1);
246 else
247 error(sc, "unknown %s `%s'", err, sc->d.buf);
248 break;
249 case ',':
250 if (ok && !*q) {
251 token(sc);
252 return (index);
253 }
254 ok = 1;
255 q = sc->d.buf;
256 index++;
257 break;
258 default:
259 if (!ok)
260 break;
261 if ((f & ENUM_ABBREV) && !*q) {
262 if (chosen != -1)
263 error(sc, "ambiguous %s `%s'", err, sc->d.buf);
264 chosen = index;
265 ok = 0;
266 }
267 if (*p == *q)
268 q++;
269 else
270 ok = 0;
271 break;
272 }
273 p++;
274 }
e82f7154 275}
276
61e3dbdf 277/* --- @conf_prefix@ --- *
e82f7154 278 *
61e3dbdf 279 * Arguments: @scanner *sc@ = pointer to a scanner object
280 * @const char *p@ = pointer to prefix string to check
e82f7154 281 *
61e3dbdf 282 * Returns: Nonzero if the prefix matches.
e82f7154 283 *
61e3dbdf 284 * Use: If the current token is a word matching the given prefix
285 * string, then it and an optional `.' character are removed and
286 * a nonzero result is returned. Otherwise the current token is
287 * left as it is, and zero is returned.
288 *
289 * Typical options parsing code would remove an expected prefix,
290 * scan an option anyway (since qualifying prefixes are
291 * optional) and if a match is found, claim the option. If no
292 * match is found, and a prefix was stripped, then an error
293 * should be reported.
e82f7154 294 */
295
61e3dbdf 296int conf_prefix(scanner *sc, const char *p)
e82f7154 297{
61e3dbdf 298 if (sc->t == CTOK_WORD && strcmp(p, sc->d.buf) == 0) {
299 token(sc);
300 if (sc->t == '.')
301 token(sc);
302 return (1);
303 }
304 return (0);
305}
e82f7154 306
61e3dbdf 307/* --- @conf_name@ --- *
308 *
309 * Arguments: @scanner *sc@ = pointer to scanner
310 * @char delim@ = delimiter character to look for
311 * @dstr *d@ = pointer to dynamic string for output
312 *
313 * Returns: ---
314 *
315 * Use: Reads in a compound name consisting of words separated by
316 * delimiters. Leading and trailing delimiters are permitted,
317 * although they'll probably cause confusion if used. The name
318 * may be enclosed in square brackets if that helps at all.
319 *
320 * Examples of compound names are filenames (delimited by `/')
321 * and IP addresses (delimited by `.').
322 */
e82f7154 323
61e3dbdf 324void conf_name(scanner *sc, char delim, dstr *d)
325{
326 unsigned f = 0;
a8b9c5eb 327
328#define f_ok 1u
329#define f_bra 2u
e82f7154 330
61e3dbdf 331 /* --- Read an optional opening bracket --- */
e82f7154 332
61e3dbdf 333 if (sc->t == '[') {
e82f7154 334 token(sc);
2234f01d 335 f |= f_bra | f_ok;
61e3dbdf 336 }
e82f7154 337
61e3dbdf 338 /* --- Do the main reading sequence --- */
e82f7154 339
61e3dbdf 340 do {
341 if (sc->t == delim) {
342 DPUTC(d, delim);
343 f |= f_ok;
e82f7154 344 token(sc);
61e3dbdf 345 }
346 if (sc->t == CTOK_WORD) {
347 DPUTD(d, &sc->d);
348 f |= f_ok;
e82f7154 349 token(sc);
350 }
61e3dbdf 351 } while (sc->t == delim);
e82f7154 352
61e3dbdf 353 /* --- Check that the string was OK --- */
e82f7154 354
61e3dbdf 355 if (!(f & f_ok))
356 error(sc, "parse error, name expected");
e82f7154 357
61e3dbdf 358 /* --- Read a closing bracket --- */
e82f7154 359
61e3dbdf 360 if (f & f_bra) {
361 if (sc->t == ']')
362 token(sc);
363 else
364 error(sc, "parse error, missing `]'");
365 }
366 DPUTZ(d);
a8b9c5eb 367
368#undef f_ok
369#undef f_bra
e82f7154 370}
371
35a142ca
MW
372/* --- @conf_fname@ --- *
373 *
374 * Arguments: @scanner *sc@ = pointer to scanner
375 * @dstr *d@ = pointer to dynamic string for output
376 *
377 * Returns: ---
378 *
379 * Use: Reads a file name from the input and stores it in @d@.
380 */
381
382void conf_fname(scanner *sc, dstr *d)
383{
52aea6fe 384 const char fnchars[] = ".-+";
35a142ca
MW
385 conf_undelim(sc, fnchars, fnchars);
386 conf_name(sc, '/', d);
387 conf_undelim(sc, 0, 0);
388}
389
e82f7154 390/*----- That's all, folks -------------------------------------------------*/