Contents of /tags/mkinitrd-6_1_2/busybox/libbb/parse_config.c
Parent Directory | Revision Log
Revision 844 -
(show annotations)
(download)
Mon May 4 17:23:09 2009 UTC (15 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5385 byte(s)
Mon May 4 17:23:09 2009 UTC (15 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5385 byte(s)
tagged 'mkinitrd-6_1_2'
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * config file parser helper |
4 | * |
5 | * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> |
6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | */ |
9 | |
10 | #include "libbb.h" |
11 | |
12 | #if defined ENABLE_PARSE && ENABLE_PARSE |
13 | int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
14 | int parse_main(int argc UNUSED_PARAM, char **argv) |
15 | { |
16 | const char *delims = "# \t"; |
17 | unsigned flags = PARSE_NORMAL; |
18 | int mintokens = 0, ntokens = 128; |
19 | |
20 | opt_complementary = "-1:n+:m+:f+"; |
21 | getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); |
22 | //argc -= optind; |
23 | argv += optind; |
24 | while (*argv) { |
25 | parser_t *p = config_open(*argv); |
26 | if (p) { |
27 | int n; |
28 | char **t = xmalloc(sizeof(char *) * ntokens); |
29 | while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) { |
30 | for (int i = 0; i < n; ++i) |
31 | printf("[%s]", t[i]); |
32 | puts(""); |
33 | } |
34 | config_close(p); |
35 | } |
36 | argv++; |
37 | } |
38 | return EXIT_SUCCESS; |
39 | } |
40 | #endif |
41 | |
42 | /* |
43 | |
44 | Typical usage: |
45 | |
46 | ----- CUT ----- |
47 | char *t[3]; // tokens placeholder |
48 | parser_t *p = config_open(filename); |
49 | if (p) { |
50 | // parse line-by-line |
51 | while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens |
52 | // use tokens |
53 | bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]); |
54 | } |
55 | ... |
56 | // free parser |
57 | config_close(p); |
58 | } |
59 | ----- CUT ----- |
60 | |
61 | */ |
62 | |
63 | parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) |
64 | { |
65 | FILE* fp; |
66 | parser_t *parser; |
67 | |
68 | fp = fopen_func(filename); |
69 | if (!fp) |
70 | return NULL; |
71 | parser = xzalloc(sizeof(*parser)); |
72 | parser->fp = fp; |
73 | return parser; |
74 | } |
75 | |
76 | parser_t* FAST_FUNC config_open(const char *filename) |
77 | { |
78 | return config_open2(filename, fopen_or_warn_stdin); |
79 | } |
80 | |
81 | static void config_free_data(parser_t *const parser) |
82 | { |
83 | free(parser->line); |
84 | parser->line = NULL; |
85 | if (PARSE_KEEP_COPY) { /* compile-time constant */ |
86 | free(parser->data); |
87 | parser->data = NULL; |
88 | } |
89 | } |
90 | |
91 | void FAST_FUNC config_close(parser_t *parser) |
92 | { |
93 | if (parser) { |
94 | config_free_data(parser); |
95 | fclose(parser->fp); |
96 | free(parser); |
97 | } |
98 | } |
99 | |
100 | /* |
101 | 0. If parser is NULL return 0. |
102 | 1. Read a line from config file. If nothing to read then return 0. |
103 | Handle continuation character. Advance lineno for each physical line. |
104 | Discard everything past comment characher. |
105 | 2. if PARSE_TRIM is set (default), remove leading and trailing delimiters. |
106 | 3. If resulting line is empty goto 1. |
107 | 4. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then |
108 | remember the token as empty. |
109 | 5. Else (default) if number of seen tokens is equal to max number of tokens |
110 | (token is the last one) and PARSE_GREEDY is set then the remainder |
111 | of the line is the last token. |
112 | Else (token is not last or PARSE_GREEDY is not set) just replace |
113 | first delimiter with '\0' thus delimiting the token. |
114 | 6. Advance line pointer past the end of token. If number of seen tokens |
115 | is less than required number of tokens then goto 4. |
116 | 7. Check the number of seen tokens is not less the min number of tokens. |
117 | Complain or die otherwise depending on PARSE_MIN_DIE. |
118 | 8. Return the number of seen tokens. |
119 | |
120 | mintokens > 0 make config_read() print error message if less than mintokens |
121 | (but more than 0) are found. Empty lines are always skipped (not warned about). |
122 | */ |
123 | #undef config_read |
124 | int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) |
125 | { |
126 | char *line; |
127 | int ntokens, mintokens; |
128 | int t, len; |
129 | |
130 | ntokens = flags & 0xFF; |
131 | mintokens = (flags & 0xFF00) >> 8; |
132 | |
133 | if (parser == NULL) |
134 | return 0; |
135 | |
136 | again: |
137 | memset(tokens, 0, sizeof(tokens[0]) * ntokens); |
138 | config_free_data(parser); |
139 | |
140 | /* Read one line (handling continuations with backslash) */ |
141 | line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno); |
142 | if (line == NULL) |
143 | return 0; |
144 | parser->line = line; |
145 | |
146 | /* Strip trailing line-feed if any */ |
147 | if (len && line[len-1] == '\n') |
148 | line[len-1] = '\0'; |
149 | |
150 | /* Skip token in the start of line? */ |
151 | if (flags & PARSE_TRIM) |
152 | line += strspn(line, delims + 1); |
153 | |
154 | if (line[0] == '\0' || line[0] == delims[0]) |
155 | goto again; |
156 | |
157 | if (flags & PARSE_KEEP_COPY) |
158 | parser->data = xstrdup(line); |
159 | |
160 | /* Tokenize the line */ |
161 | for (t = 0; *line && *line != delims[0] && t < ntokens; t++) { |
162 | /* Pin token */ |
163 | tokens[t] = line; |
164 | |
165 | /* Combine remaining arguments? */ |
166 | if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) { |
167 | /* Vanilla token, find next delimiter */ |
168 | line += strcspn(line, delims[0] ? delims : delims + 1); |
169 | } else { |
170 | /* Combining, find comment char if any */ |
171 | line = strchrnul(line, delims[0]); |
172 | |
173 | /* Trim any extra delimiters from the end */ |
174 | if (flags & PARSE_TRIM) { |
175 | while (strchr(delims + 1, line[-1]) != NULL) |
176 | line--; |
177 | } |
178 | } |
179 | |
180 | /* Token not terminated? */ |
181 | if (line[0] == delims[0]) |
182 | *line = '\0'; |
183 | else if (line[0] != '\0') |
184 | *(line++) = '\0'; |
185 | |
186 | #if 0 /* unused so far */ |
187 | if (flags & PARSE_ESCAPE) { |
188 | const char *from; |
189 | char *to; |
190 | |
191 | from = to = tokens[t]; |
192 | while (*from) { |
193 | if (*from == '\\') { |
194 | from++; |
195 | *to++ = bb_process_escape_sequence(&from); |
196 | } else { |
197 | *to++ = *from++; |
198 | } |
199 | } |
200 | *to = '\0'; |
201 | } |
202 | #endif |
203 | |
204 | /* Skip possible delimiters */ |
205 | if (flags & PARSE_COLLAPSE) |
206 | line += strspn(line, delims + 1); |
207 | } |
208 | |
209 | if (t < mintokens) { |
210 | bb_error_msg("bad line %u: %d tokens found, %d needed", |
211 | parser->lineno, t, mintokens); |
212 | if (flags & PARSE_MIN_DIE) |
213 | xfunc_die(); |
214 | goto again; |
215 | } |
216 | |
217 | return t; |
218 | } |