Commit | Line | Data |
---|---|---|
0f78b815 WD |
1 | /* This modules is based on the params.c module from Samba, written by Karl Auer |
2 | and much modifed by Christopher Hertel. */ | |
0b76cd63 | 3 | |
0f78b815 | 4 | /* |
0b76cd63 | 5 | * This program is free software; you can redistribute it and/or modify |
8e41b68e WD |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 3 of the License, or | |
8 | * (at your option) any later version. | |
0b76cd63 AT |
9 | * |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
e7c67065 | 15 | * You should have received a copy of the GNU General Public License along |
4fd842f9 | 16 | * with this program; if not, visit the http://fsf.org website. |
0f78b815 WD |
17 | */ |
18 | ||
19 | /* -------------------------------------------------------------------------- ** | |
0b76cd63 AT |
20 | * |
21 | * Module name: params | |
22 | * | |
23 | * -------------------------------------------------------------------------- ** | |
24 | * | |
25 | * This module performs lexical analysis and initial parsing of a | |
26 | * Windows-like parameter file. It recognizes and handles four token | |
27 | * types: section-name, parameter-name, parameter-value, and | |
28 | * end-of-file. Comments and line continuation are handled | |
29 | * internally. | |
30 | * | |
31 | * The entry point to the module is function pm_process(). This | |
32 | * function opens the source file, calls the Parse() function to parse | |
33 | * the input, and then closes the file when either the EOF is reached | |
34 | * or a fatal error is encountered. | |
35 | * | |
36 | * A sample parameter file might look like this: | |
37 | * | |
38 | * [section one] | |
39 | * parameter one = value string | |
40 | * parameter two = another value | |
41 | * [section two] | |
42 | * new parameter = some value or t'other | |
43 | * | |
44 | * The parameter file is divided into sections by section headers: | |
45 | * section names enclosed in square brackets (eg. [section one]). | |
46 | * Each section contains parameter lines, each of which consist of a | |
47 | * parameter name and value delimited by an equal sign. Roughly, the | |
48 | * syntax is: | |
49 | * | |
50 | * <file> :== { <section> } EOF | |
51 | * | |
52 | * <section> :== <section header> { <parameter line> } | |
53 | * | |
54 | * <section header> :== '[' NAME ']' | |
55 | * | |
56 | * <parameter line> :== NAME '=' VALUE '\n' | |
57 | * | |
58 | * Blank lines and comment lines are ignored. Comment lines are lines | |
59 | * beginning with either a semicolon (';') or a pound sign ('#'). | |
60 | * | |
61 | * All whitespace in section names and parameter names is compressed | |
62 | * to single spaces. Leading and trailing whitespace is stipped from | |
63 | * both names and values. | |
64 | * | |
65 | * Only the first equals sign in a parameter line is significant. | |
66 | * Parameter values may contain equals signs, square brackets and | |
67 | * semicolons. Internal whitespace is retained in parameter values, | |
68 | * with the exception of the '\r' character, which is stripped for | |
69 | * historic reasons. Parameter names may not start with a left square | |
70 | * bracket, an equal sign, a pound sign, or a semicolon, because these | |
71 | * are used to identify other tokens. | |
72 | * | |
73 | * -------------------------------------------------------------------------- ** | |
74 | */ | |
75 | ||
76 | #include "rsync.h" | |
1b42f628 | 77 | #include "ifuncs.h" |
5dd14f0c | 78 | #include "itypes.h" |
0b76cd63 AT |
79 | |
80 | /* -------------------------------------------------------------------------- ** | |
81 | * Constants... | |
82 | */ | |
83 | ||
84 | #define BUFR_INC 1024 | |
85 | ||
86 | ||
87 | /* -------------------------------------------------------------------------- ** | |
88 | * Variables... | |
89 | * | |
90 | * bufr - pointer to a global buffer. This is probably a kludge, | |
91 | * but it was the nicest kludge I could think of (for now). | |
92 | * bSize - The size of the global buffer <bufr>. | |
93 | */ | |
94 | ||
95 | static char *bufr = NULL; | |
96 | static int bSize = 0; | |
8a3ddcfc WD |
97 | static BOOL (*the_sfunc)(char *); |
98 | static BOOL (*the_pfunc)(char *, char *); | |
0b76cd63 AT |
99 | |
100 | /* -------------------------------------------------------------------------- ** | |
101 | * Functions... | |
102 | */ | |
103 | ||
104 | static int EatWhitespace( FILE *InFile ) | |
105 | /* ------------------------------------------------------------------------ ** | |
106 | * Scan past whitespace (see ctype(3C)) and return the first non-whitespace | |
107 | * character, or newline, or EOF. | |
108 | * | |
109 | * Input: InFile - Input source. | |
110 | * | |
111 | * Output: The next non-whitespace character in the input stream. | |
112 | * | |
113 | * Notes: Because the config files use a line-oriented grammar, we | |
114 | * explicitly exclude the newline character from the list of | |
115 | * whitespace characters. | |
116 | * - Note that both EOF (-1) and the nul character ('\0') are | |
117 | * considered end-of-file markers. | |
118 | * | |
119 | * ------------------------------------------------------------------------ ** | |
120 | */ | |
121 | { | |
122 | int c; | |
123 | ||
124 | for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) ) | |
125 | ; | |
126 | return( c ); | |
127 | } /* EatWhitespace */ | |
128 | ||
129 | static int EatComment( FILE *InFile ) | |
130 | /* ------------------------------------------------------------------------ ** | |
131 | * Scan to the end of a comment. | |
132 | * | |
133 | * Input: InFile - Input source. | |
134 | * | |
135 | * Output: The character that marks the end of the comment. Normally, | |
136 | * this will be a newline, but it *might* be an EOF. | |
137 | * | |
138 | * Notes: Because the config files use a line-oriented grammar, we | |
139 | * explicitly exclude the newline character from the list of | |
140 | * whitespace characters. | |
141 | * - Note that both EOF (-1) and the nul character ('\0') are | |
142 | * considered end-of-file markers. | |
143 | * | |
144 | * ------------------------------------------------------------------------ ** | |
145 | */ | |
146 | { | |
147 | int c; | |
148 | ||
149 | for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) ) | |
150 | ; | |
151 | return( c ); | |
152 | } /* EatComment */ | |
153 | ||
154 | static int Continuation( char *line, int pos ) | |
155 | /* ------------------------------------------------------------------------ ** | |
156 | * Scan backards within a string to discover if the last non-whitespace | |
157 | * character is a line-continuation character ('\\'). | |
158 | * | |
159 | * Input: line - A pointer to a buffer containing the string to be | |
160 | * scanned. | |
161 | * pos - This is taken to be the offset of the end of the | |
162 | * string. This position is *not* scanned. | |
163 | * | |
164 | * Output: The offset of the '\\' character if it was found, or -1 to | |
165 | * indicate that it was not. | |
166 | * | |
167 | * ------------------------------------------------------------------------ ** | |
168 | */ | |
169 | { | |
170 | pos--; | |
2dc7b8bd | 171 | while( pos >= 0 && isSpace(line + pos) ) |
0b76cd63 AT |
172 | pos--; |
173 | ||
174 | return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 ); | |
175 | } /* Continuation */ | |
176 | ||
177 | ||
178 | static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) ) | |
179 | /* ------------------------------------------------------------------------ ** | |
180 | * Scan a section name, and pass the name to function sfunc(). | |
181 | * | |
182 | * Input: InFile - Input source. | |
183 | * sfunc - Pointer to the function to be called if the section | |
184 | * name is successfully read. | |
185 | * | |
186 | * Output: True if the section name was read and True was returned from | |
187 | * <sfunc>. False if <sfunc> failed or if a lexical error was | |
188 | * encountered. | |
189 | * | |
190 | * ------------------------------------------------------------------------ ** | |
191 | */ | |
192 | { | |
193 | int c; | |
194 | int i; | |
195 | int end; | |
196 | char *func = "params.c:Section() -"; | |
197 | ||
198 | i = 0; /* <i> is the offset of the next free byte in bufr[] and */ | |
199 | end = 0; /* <end> is the current "end of string" offset. In most */ | |
200 | /* cases these will be the same, but if the last */ | |
201 | /* character written to bufr[] is a space, then <end> */ | |
202 | /* will be one less than <i>. */ | |
203 | ||
204 | c = EatWhitespace( InFile ); /* We've already got the '['. Scan */ | |
205 | /* past initial white space. */ | |
206 | ||
207 | while( (EOF != c) && (c > 0) ) | |
208 | { | |
209 | ||
210 | /* Check that the buffer is big enough for the next character. */ | |
211 | if( i > (bSize - 2) ) | |
212 | { | |
213 | bSize += BUFR_INC; | |
58cadc86 | 214 | bufr = realloc_array( bufr, char, bSize ); |
0b76cd63 AT |
215 | if( NULL == bufr ) |
216 | { | |
a6c6f8e6 | 217 | rprintf(FLOG, "%s Memory re-allocation failure.", func); |
0b76cd63 AT |
218 | return( False ); |
219 | } | |
220 | } | |
221 | ||
222 | /* Handle a single character. */ | |
223 | switch( c ) | |
224 | { | |
225 | case ']': /* Found the closing bracket. */ | |
226 | bufr[end] = '\0'; | |
227 | if( 0 == end ) /* Don't allow an empty name. */ | |
228 | { | |
582831a4 | 229 | rprintf(FLOG, "%s Empty section name in config file.\n", func ); |
0b76cd63 AT |
230 | return( False ); |
231 | } | |
232 | if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */ | |
233 | return( False ); | |
234 | (void)EatComment( InFile ); /* Finish off the line. */ | |
235 | return( True ); | |
236 | ||
237 | case '\n': /* Got newline before closing ']'. */ | |
238 | i = Continuation( bufr, i ); /* Check for line continuation. */ | |
239 | if( i < 0 ) | |
240 | { | |
241 | bufr[end] = '\0'; | |
582831a4 | 242 | rprintf(FLOG, "%s Badly formed line in config file: %s\n", |
0b76cd63 AT |
243 | func, bufr ); |
244 | return( False ); | |
245 | } | |
246 | end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i); | |
247 | c = getc( InFile ); /* Continue with next line. */ | |
248 | break; | |
249 | ||
250 | default: /* All else are a valid name chars. */ | |
251 | if( isspace( c ) ) /* One space per whitespace region. */ | |
252 | { | |
253 | bufr[end] = ' '; | |
254 | i = end + 1; | |
255 | c = EatWhitespace( InFile ); | |
256 | } | |
257 | else /* All others copy verbatim. */ | |
258 | { | |
259 | bufr[i++] = c; | |
260 | end = i; | |
261 | c = getc( InFile ); | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | /* We arrive here if we've met the EOF before the closing bracket. */ | |
582831a4 | 267 | rprintf(FLOG, "%s Unexpected EOF in the config file: %s\n", func, bufr ); |
0b76cd63 AT |
268 | return( False ); |
269 | } /* Section */ | |
270 | ||
271 | static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c ) | |
272 | /* ------------------------------------------------------------------------ ** | |
273 | * Scan a parameter name and value, and pass these two fields to pfunc(). | |
274 | * | |
275 | * Input: InFile - The input source. | |
276 | * pfunc - A pointer to the function that will be called to | |
277 | * process the parameter, once it has been scanned. | |
278 | * c - The first character of the parameter name, which | |
279 | * would have been read by Parse(). Unlike a comment | |
280 | * line or a section header, there is no lead-in | |
281 | * character that can be discarded. | |
282 | * | |
283 | * Output: True if the parameter name and value were scanned and processed | |
284 | * successfully, else False. | |
285 | * | |
286 | * Notes: This function is in two parts. The first loop scans the | |
287 | * parameter name. Internal whitespace is compressed, and an | |
288 | * equal sign (=) terminates the token. Leading and trailing | |
289 | * whitespace is discarded. The second loop scans the parameter | |
290 | * value. When both have been successfully identified, they are | |
291 | * passed to pfunc() for processing. | |
292 | * | |
293 | * ------------------------------------------------------------------------ ** | |
294 | */ | |
295 | { | |
296 | int i = 0; /* Position within bufr. */ | |
297 | int end = 0; /* bufr[end] is current end-of-string. */ | |
298 | int vstart = 0; /* Starting position of the parameter value. */ | |
299 | char *func = "params.c:Parameter() -"; | |
300 | ||
301 | /* Read the parameter name. */ | |
302 | while( 0 == vstart ) /* Loop until we've found the start of the value. */ | |
303 | { | |
304 | ||
305 | if( i > (bSize - 2) ) /* Ensure there's space for next char. */ | |
306 | { | |
307 | bSize += BUFR_INC; | |
58cadc86 | 308 | bufr = realloc_array( bufr, char, bSize ); |
0b76cd63 AT |
309 | if( NULL == bufr ) |
310 | { | |
a6c6f8e6 | 311 | rprintf(FLOG, "%s Memory re-allocation failure.", func) ; |
0b76cd63 AT |
312 | return( False ); |
313 | } | |
314 | } | |
315 | ||
316 | switch( c ) | |
317 | { | |
318 | case '=': /* Equal sign marks end of param name. */ | |
319 | if( 0 == end ) /* Don't allow an empty name. */ | |
320 | { | |
582831a4 | 321 | rprintf(FLOG, "%s Invalid parameter name in config file.\n", func ); |
0b76cd63 AT |
322 | return( False ); |
323 | } | |
324 | bufr[end++] = '\0'; /* Mark end of string & advance. */ | |
582831a4 WD |
325 | i = vstart = end; /* New string starts here. */ |
326 | c = EatWhitespace(InFile); | |
0b76cd63 AT |
327 | break; |
328 | ||
329 | case '\n': /* Find continuation char, else error. */ | |
330 | i = Continuation( bufr, i ); | |
331 | if( i < 0 ) | |
332 | { | |
333 | bufr[end] = '\0'; | |
582831a4 | 334 | rprintf(FLOG, "%s Ignoring badly formed line in config file: %s\n", |
0b76cd63 AT |
335 | func, bufr ); |
336 | return( True ); | |
337 | } | |
338 | end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i); | |
339 | c = getc( InFile ); /* Read past eoln. */ | |
340 | break; | |
341 | ||
342 | case '\0': /* Shouldn't have EOF within param name. */ | |
343 | case EOF: | |
344 | bufr[i] = '\0'; | |
a6c6f8e6 | 345 | rprintf(FLOG, "%s Unexpected end-of-file at: %s\n", func, bufr ); |
0b76cd63 AT |
346 | return( True ); |
347 | ||
582831a4 WD |
348 | case ' ': |
349 | case '\t': | |
350 | /* A directive divides at the first space or tab. */ | |
351 | if (*bufr == '&') { | |
352 | bufr[end++] = '\0'; | |
353 | i = vstart = end; | |
354 | c = EatWhitespace(InFile); | |
355 | if (c == '=') | |
356 | c = EatWhitespace(InFile); | |
357 | break; | |
358 | } | |
359 | /* FALL THROUGH */ | |
360 | ||
0b76cd63 AT |
361 | default: |
362 | if( isspace( c ) ) /* One ' ' per whitespace region. */ | |
363 | { | |
364 | bufr[end] = ' '; | |
365 | i = end + 1; | |
366 | c = EatWhitespace( InFile ); | |
367 | } | |
368 | else /* All others verbatim. */ | |
369 | { | |
370 | bufr[i++] = c; | |
371 | end = i; | |
372 | c = getc( InFile ); | |
373 | } | |
374 | } | |
375 | } | |
376 | ||
377 | /* Now parse the value. */ | |
0b76cd63 AT |
378 | while( (EOF !=c) && (c > 0) ) |
379 | { | |
380 | ||
381 | if( i > (bSize - 2) ) /* Make sure there's enough room. */ | |
382 | { | |
383 | bSize += BUFR_INC; | |
58cadc86 | 384 | bufr = realloc_array( bufr, char, bSize ); |
0b76cd63 AT |
385 | if( NULL == bufr ) |
386 | { | |
a6c6f8e6 | 387 | rprintf(FLOG, "%s Memory re-allocation failure.", func) ; |
0b76cd63 AT |
388 | return( False ); |
389 | } | |
390 | } | |
391 | ||
392 | switch( c ) | |
393 | { | |
394 | case '\r': /* Explicitly remove '\r' because the older */ | |
395 | c = getc( InFile ); /* version called fgets_slash() which also */ | |
396 | break; /* removes them. */ | |
397 | ||
398 | case '\n': /* Marks end of value unless there's a '\'. */ | |
399 | i = Continuation( bufr, i ); | |
400 | if( i < 0 ) | |
401 | c = 0; | |
402 | else | |
403 | { | |
2dc7b8bd | 404 | for( end = i; end >= 0 && isSpace(bufr + end); end-- ) |
0b76cd63 AT |
405 | ; |
406 | c = getc( InFile ); | |
407 | } | |
408 | break; | |
409 | ||
410 | default: /* All others verbatim. Note that spaces do */ | |
411 | bufr[i++] = c; /* not advance <end>. This allows trimming */ | |
412 | if( !isspace( c ) ) /* of whitespace at the end of the line. */ | |
413 | end = i; | |
414 | c = getc( InFile ); | |
415 | break; | |
416 | } | |
417 | } | |
418 | bufr[end] = '\0'; /* End of value. */ | |
419 | ||
420 | return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */ | |
421 | } /* Parameter */ | |
422 | ||
8a3ddcfc WD |
423 | static int name_cmp(const void *n1, const void *n2) |
424 | { | |
425 | return strcmp(*(char * const *)n1, *(char * const *)n2); | |
426 | } | |
427 | ||
428 | static int include_config(char *include, int manage_globals) | |
429 | { | |
312b6841 WD |
430 | STRUCT_STAT sb; |
431 | int ret; | |
8a3ddcfc | 432 | |
582831a4 WD |
433 | if (do_stat(include, &sb) < 0) { |
434 | rsyserr(FLOG, errno, "unable to stat config file \"%s\"", include); | |
312b6841 | 435 | return 0; |
582831a4 | 436 | } |
8a3ddcfc | 437 | |
312b6841 | 438 | if (S_ISREG(sb.st_mode)) { |
8a3ddcfc | 439 | if (manage_globals && the_sfunc) |
312b6841 WD |
440 | the_sfunc("]push"); |
441 | ret = pm_process(include, the_sfunc, the_pfunc); | |
442 | if (manage_globals && the_sfunc) | |
443 | the_sfunc("]pop"); | |
444 | } else if (S_ISDIR(sb.st_mode)) { | |
445 | char buf[MAXPATHLEN], **bpp; | |
446 | item_list conf_list; | |
447 | struct dirent *di; | |
448 | size_t j; | |
449 | DIR *d; | |
450 | ||
582831a4 WD |
451 | if (!(d = opendir(include))) { |
452 | rsyserr(FLOG, errno, "unable to open config dir \"%s\"", include); | |
312b6841 | 453 | return 0; |
582831a4 | 454 | } |
312b6841 WD |
455 | |
456 | memset(&conf_list, 0, sizeof conf_list); | |
457 | ||
458 | while ((di = readdir(d)) != NULL) { | |
459 | char *dname = d_name(di); | |
460 | if (!wildmatch("*.conf", dname)) | |
461 | continue; | |
462 | bpp = EXPAND_ITEM_LIST(&conf_list, char *, 32); | |
463 | pathjoin(buf, sizeof buf, include, dname); | |
464 | *bpp = strdup(buf); | |
465 | } | |
466 | closedir(d); | |
467 | ||
468 | if (!(bpp = conf_list.items)) | |
469 | return 1; | |
470 | ||
471 | if (conf_list.count > 1) | |
472 | qsort(bpp, conf_list.count, sizeof (char *), name_cmp); | |
473 | ||
474 | for (j = 0, ret = 1; j < conf_list.count; j++) { | |
475 | if (manage_globals && the_sfunc) | |
476 | the_sfunc(j == 0 ? "]push" : "]reset"); | |
477 | if ((ret = pm_process(bpp[j], the_sfunc, the_pfunc)) != 1) | |
478 | break; | |
479 | } | |
8a3ddcfc | 480 | |
312b6841 WD |
481 | if (manage_globals && the_sfunc) |
482 | the_sfunc("]pop"); | |
8a3ddcfc | 483 | |
312b6841 WD |
484 | for (j = 0; j < conf_list.count; j++) |
485 | free(bpp[j]); | |
486 | free(bpp); | |
487 | } else | |
488 | ret = 0; | |
8a3ddcfc WD |
489 | |
490 | return ret; | |
491 | } | |
492 | ||
493 | static int parse_directives(char *name, char *val) | |
494 | { | |
582831a4 | 495 | if (strcasecmp(name, "&include") == 0) |
8a3ddcfc | 496 | return include_config(val, 1); |
582831a4 | 497 | if (strcasecmp(name, "&merge") == 0) |
8a3ddcfc | 498 | return include_config(val, 0); |
582831a4 | 499 | rprintf(FLOG, "Unknown directive: %s.\n", name); |
8a3ddcfc WD |
500 | return 0; |
501 | } | |
502 | ||
503 | static int Parse( FILE *InFile, | |
0b76cd63 AT |
504 | BOOL (*sfunc)(char *), |
505 | BOOL (*pfunc)(char *, char *) ) | |
506 | /* ------------------------------------------------------------------------ ** | |
507 | * Scan & parse the input. | |
508 | * | |
509 | * Input: InFile - Input source. | |
510 | * sfunc - Function to be called when a section name is scanned. | |
511 | * See Section(). | |
512 | * pfunc - Function to be called when a parameter is scanned. | |
513 | * See Parameter(). | |
514 | * | |
8a3ddcfc WD |
515 | * Output: 1 if the file was successfully scanned, 2 if the file was |
516 | * scanned until a section header with no section function, else 0. | |
0b76cd63 AT |
517 | * |
518 | * Notes: The input can be viewed in terms of 'lines'. There are four | |
519 | * types of lines: | |
520 | * Blank - May contain whitespace, otherwise empty. | |
521 | * Comment - First non-whitespace character is a ';' or '#'. | |
522 | * The remainder of the line is ignored. | |
523 | * Section - First non-whitespace character is a '['. | |
524 | * Parameter - The default case. | |
8a3ddcfc | 525 | * |
0b76cd63 AT |
526 | * ------------------------------------------------------------------------ ** |
527 | */ | |
528 | { | |
529 | int c; | |
530 | ||
531 | c = EatWhitespace( InFile ); | |
532 | while( (EOF != c) && (c > 0) ) | |
533 | { | |
534 | switch( c ) | |
535 | { | |
536 | case '\n': /* Blank line. */ | |
537 | c = EatWhitespace( InFile ); | |
538 | break; | |
539 | ||
540 | case ';': /* Comment line. */ | |
541 | case '#': | |
542 | c = EatComment( InFile ); | |
543 | break; | |
544 | ||
545 | case '[': /* Section Header. */ | |
8a3ddcfc WD |
546 | if (!sfunc) |
547 | return 2; | |
548 | if( !Section( InFile, sfunc ) ) | |
549 | return 0; | |
550 | c = EatWhitespace( InFile ); | |
551 | break; | |
0b76cd63 AT |
552 | |
553 | case '\\': /* Bogus backslash. */ | |
554 | c = EatWhitespace( InFile ); | |
555 | break; | |
556 | ||
8a3ddcfc WD |
557 | case '&': /* Handle directives */ |
558 | the_sfunc = sfunc; | |
559 | the_pfunc = pfunc; | |
8a3ddcfc WD |
560 | c = Parameter( InFile, parse_directives, c ); |
561 | if (c != 1) | |
562 | return c; | |
563 | c = EatWhitespace( InFile ); | |
564 | break; | |
565 | ||
0b76cd63 AT |
566 | default: /* Parameter line. */ |
567 | if( !Parameter( InFile, pfunc, c ) ) | |
8a3ddcfc | 568 | return 0; |
0b76cd63 AT |
569 | c = EatWhitespace( InFile ); |
570 | break; | |
571 | } | |
572 | } | |
8a3ddcfc | 573 | return 1; |
0b76cd63 AT |
574 | } /* Parse */ |
575 | ||
576 | static FILE *OpenConfFile( char *FileName ) | |
577 | /* ------------------------------------------------------------------------ ** | |
582831a4 | 578 | * Open a config file. |
0b76cd63 AT |
579 | * |
580 | * Input: FileName - The pathname of the config file to be opened. | |
581 | * | |
582 | * Output: A pointer of type (FILE *) to the opened file, or NULL if the | |
583 | * file could not be opened. | |
584 | * | |
585 | * ------------------------------------------------------------------------ ** | |
586 | */ | |
587 | { | |
588 | FILE *OpenedFile; | |
589 | char *func = "params.c:OpenConfFile() -"; | |
590 | ||
591 | if( NULL == FileName || 0 == *FileName ) | |
592 | { | |
582831a4 | 593 | rprintf(FLOG, "%s No config filename specified.\n", func); |
0b76cd63 AT |
594 | return( NULL ); |
595 | } | |
596 | ||
0090cbdb | 597 | OpenedFile = fopen( FileName, "r" ); |
0b76cd63 AT |
598 | if( NULL == OpenedFile ) |
599 | { | |
582831a4 | 600 | rsyserr(FLOG, errno, "unable to open config file \"%s\"", |
45c49b52 | 601 | FileName); |
0b76cd63 AT |
602 | } |
603 | ||
604 | return( OpenedFile ); | |
605 | } /* OpenConfFile */ | |
606 | ||
8a3ddcfc | 607 | int pm_process( char *FileName, |
0b76cd63 AT |
608 | BOOL (*sfunc)(char *), |
609 | BOOL (*pfunc)(char *, char *) ) | |
610 | /* ------------------------------------------------------------------------ ** | |
611 | * Process the named parameter file. | |
612 | * | |
613 | * Input: FileName - The pathname of the parameter file to be opened. | |
614 | * sfunc - A pointer to a function that will be called when | |
615 | * a section name is discovered. | |
616 | * pfunc - A pointer to a function that will be called when | |
617 | * a parameter name and value are discovered. | |
618 | * | |
8a3ddcfc WD |
619 | * Output: 1 if the file was successfully parsed, 2 if parsing ended at a |
620 | * section header w/o a section function, else 0. | |
0b76cd63 AT |
621 | * |
622 | * ------------------------------------------------------------------------ ** | |
623 | */ | |
624 | { | |
625 | int result; | |
626 | FILE *InFile; | |
627 | char *func = "params.c:pm_process() -"; | |
628 | ||
629 | InFile = OpenConfFile( FileName ); /* Open the config file. */ | |
630 | if( NULL == InFile ) | |
631 | return( False ); | |
632 | ||
633 | if( NULL != bufr ) /* If we already have a buffer */ | |
634 | result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */ | |
635 | /* use it. */ | |
636 | ||
637 | else /* If we don't have a buffer */ | |
638 | { /* allocate one, then parse, */ | |
639 | bSize = BUFR_INC; /* then free. */ | |
58cadc86 | 640 | bufr = new_array( char, bSize ); |
0b76cd63 AT |
641 | if( NULL == bufr ) |
642 | { | |
a6c6f8e6 | 643 | rprintf(FLOG, "%s memory allocation failure.\n", func); |
0b76cd63 AT |
644 | fclose(InFile); |
645 | return( False ); | |
646 | } | |
647 | result = Parse( InFile, sfunc, pfunc ); | |
648 | free( bufr ); | |
649 | bufr = NULL; | |
650 | bSize = 0; | |
651 | } | |
652 | ||
653 | fclose(InFile); | |
654 | ||
655 | if( !result ) /* Generic failure. */ | |
656 | { | |
a6c6f8e6 | 657 | rprintf(FLOG, "%s Failed. Error returned from params.c:parse().\n", func); |
8a3ddcfc | 658 | return 0; |
0b76cd63 AT |
659 | } |
660 | ||
8a3ddcfc | 661 | return result; |
0b76cd63 AT |
662 | } /* pm_process */ |
663 | ||
664 | /* -------------------------------------------------------------------------- */ | |
f9e940ef | 665 |