diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-26 23:08:31 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-26 23:08:31 +0000 |
commit | 084266ed520805bbc4ec3f9b4d14e644ecd75880 (patch) | |
tree | fe2c8531dc039c81c12a39f39fcfdf6c1b8ec996 /libbb/parse_config.c | |
parent | 8895c2073e9341d8e0348365e75ba6aa4b9b8d05 (diff) | |
download | busybox-w32-084266ed520805bbc4ec3f9b4d14e644ecd75880.tar.gz busybox-w32-084266ed520805bbc4ec3f9b4d14e644ecd75880.tar.bz2 busybox-w32-084266ed520805bbc4ec3f9b4d14e644ecd75880.zip |
fix several problems with config parser:
a bug where it underflows the string
a bug where it never frees parser_t struct
make read_config() return 0 if parser is NULL,
make config_close() accept and ignore NULL parser -
eliminates many if() blocks
reverse the sense of parser bit flags - negative flags
are harder to grok.
hexdump: revert the change to use config parser, it is BIGGER
and also requires additional quirks in parser
*: explicitly use PARSER_NORMAL instead of 0
function old new delta
login_main 1575 1596 +21
config_close 18 29 +11
bbunpack 383 391 +8
qgravechar 106 109 +3
rtnl_tab_initialize 121 117 -4
expand 1697 1693 -4
man_main 717 712 -5
nameif_main 674 668 -6
hexdump_main 597 591 -6
read_config 217 209 -8
dnsd_main 1478 1470 -8
sysctl_main 203 189 -14
config_open2 44 25 -19
make_device 1177 1141 -36
config_read 597 549 -48
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/11 up/down: 43/-158) Total: -115 bytes
Diffstat (limited to 'libbb/parse_config.c')
-rw-r--r-- | libbb/parse_config.c | 102 |
1 files changed, 60 insertions, 42 deletions
diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 83dc997f6..ace6f3ad3 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c | |||
@@ -14,8 +14,9 @@ int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
14 | int parse_main(int argc UNUSED_PARAM, char **argv) | 14 | int parse_main(int argc UNUSED_PARAM, char **argv) |
15 | { | 15 | { |
16 | const char *delims = "# \t"; | 16 | const char *delims = "# \t"; |
17 | unsigned flags = 0; | 17 | unsigned flags = PARSE_NORMAL; |
18 | int mintokens = 0, ntokens = 128; | 18 | int mintokens = 0, ntokens = 128; |
19 | |||
19 | opt_complementary = "-1:n+:m+:f+"; | 20 | opt_complementary = "-1:n+:m+:f+"; |
20 | getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); | 21 | getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); |
21 | //argc -= optind; | 22 | //argc -= optind; |
@@ -61,13 +62,15 @@ Typical usage: | |||
61 | 62 | ||
62 | parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) | 63 | parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) |
63 | { | 64 | { |
64 | parser_t *parser = xzalloc(sizeof(parser_t)); | 65 | FILE* fp; |
65 | /* empty file configures nothing */ | 66 | parser_t *parser; |
66 | parser->fp = fopen_func(filename); | 67 | |
67 | if (parser->fp) | 68 | fp = fopen_func(filename); |
68 | return parser; | 69 | if (!fp) |
69 | free(parser); | 70 | return NULL; |
70 | return NULL; | 71 | parser = xzalloc(sizeof(*parser)); |
72 | parser->fp = fp; | ||
73 | return parser; | ||
71 | } | 74 | } |
72 | 75 | ||
73 | parser_t* FAST_FUNC config_open(const char *filename) | 76 | parser_t* FAST_FUNC config_open(const char *filename) |
@@ -87,41 +90,53 @@ static void config_free_data(parser_t *const parser) | |||
87 | 90 | ||
88 | void FAST_FUNC config_close(parser_t *parser) | 91 | void FAST_FUNC config_close(parser_t *parser) |
89 | { | 92 | { |
90 | config_free_data(parser); | 93 | if (parser) { |
91 | fclose(parser->fp); | 94 | config_free_data(parser); |
95 | fclose(parser->fp); | ||
96 | free(parser); | ||
97 | } | ||
92 | } | 98 | } |
93 | 99 | ||
94 | /* | 100 | /* |
95 | 1. Read a line from config file. If nothing to read then bail out returning 0. | 101 | 0. If parser is NULL return 0. |
96 | Handle continuation character. Advance lineno for each physical line. Cut comments. | 102 | 1. Read a line from config file. If nothing to read then return 0. |
97 | 2. if PARSE_DONT_TRIM is not set (default) skip leading and cut trailing delimiters, if any. | 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. | ||
98 | 3. If resulting line is empty goto 1. | 106 | 3. If resulting line is empty goto 1. |
99 | 4. Look for first delimiter. If PARSE_DONT_REDUCE or PARSE_DONT_TRIM is set then pin empty token. | 107 | 4. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then |
100 | 5. Else (default) if number of seen tokens is equal to max number of tokens (token is the last one) | 108 | remember the token as empty. |
101 | and PARSE_LAST_IS_GREEDY is set then pin the remainder of the line as the last token. | 109 | 5. Else (default) if number of seen tokens is equal to max number of tokens |
102 | Else (token is not last or PARSE_LAST_IS_GREEDY is not set) just replace first delimiter with '\0' | 110 | (token is the last one) and PARSE_GREEDY is set then the remainder |
103 | thus delimiting token and pin it. | 111 | of the line is the last token. |
104 | 6. Advance line pointer past the end of token. If number of seen tokens is less than required number | 112 | Else (token is not last or PARSE_GREEDY is not set) just replace |
105 | of tokens then goto 4. | 113 | first delimiter with '\0' thus delimiting the token. |
106 | 7. Control the number of seen tokens is not less the min number of tokens. Die if condition is not met. | 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. | ||
107 | 8. Return the number of seen tokens. | 118 | 8. Return the number of seen tokens. |
108 | 119 | ||
109 | mintokens > 0 make config_read() exit with error message if less than mintokens | 120 | mintokens > 0 make config_read() print error message if less than mintokens |
110 | (but more than 0) are found. Empty lines are always skipped (not warned about). | 121 | (but more than 0) are found. Empty lines are always skipped (not warned about). |
111 | */ | 122 | */ |
112 | #undef config_read | 123 | #undef config_read |
113 | int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) | 124 | int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) |
114 | { | 125 | { |
115 | char *line, *q; | 126 | char *line, *q; |
116 | char comment = *delims++; | 127 | char comment; |
117 | int ii; | 128 | int ii; |
118 | int ntokens = flags & 0xFF; | 129 | int ntokens; |
119 | int mintokens = (flags & 0xFF00) >> 8; | 130 | int mintokens; |
131 | |||
132 | comment = *delims++; | ||
133 | ntokens = flags & 0xFF; | ||
134 | mintokens = (flags & 0xFF00) >> 8; | ||
120 | 135 | ||
121 | again: | 136 | again: |
122 | // N.B. this could only be used in read-in-one-go version, or when tokens use xstrdup(). TODO | 137 | memset(tokens, 0, sizeof(tokens[0]) * ntokens); |
123 | //if (!parser->lineno || !(flags & PARSE_DONT_NULL)) | 138 | if (!parser) |
124 | memset(tokens, 0, sizeof(tokens[0]) * ntokens); | 139 | return 0; |
125 | config_free_data(parser); | 140 | config_free_data(parser); |
126 | 141 | ||
127 | while (1) { | 142 | while (1) { |
@@ -142,20 +157,20 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
142 | line[--ii] = '\0'; | 157 | line[--ii] = '\0'; |
143 | //TODO: add xmalloc_fgetline-like iface but with appending to existing str | 158 | //TODO: add xmalloc_fgetline-like iface but with appending to existing str |
144 | q = xmalloc_fgetline(parser->fp); | 159 | q = xmalloc_fgetline(parser->fp); |
145 | if (q) { | 160 | if (!q) |
146 | parser->lineno++; | 161 | break; |
147 | line = xasprintf("%s%s", line, q); | 162 | parser->lineno++; |
148 | free(q); | 163 | line = xasprintf("%s%s", line, q); |
149 | } | 164 | free(q); |
150 | } | 165 | } |
151 | // comments mean EOLs | 166 | // discard comments |
152 | if (comment) { | 167 | if (comment) { |
153 | q = strchrnul(line, comment); | 168 | q = strchrnul(line, comment); |
154 | *q = '\0'; | 169 | *q = '\0'; |
155 | ii = q - line; | 170 | ii = q - line; |
156 | } | 171 | } |
157 | // skip leading and trailing delimiters | 172 | // skip leading and trailing delimiters |
158 | if (!(flags & PARSE_DONT_TRIM)) { | 173 | if (flags & PARSE_TRIM) { |
159 | // skip leading | 174 | // skip leading |
160 | int n = strspn(line, delims); | 175 | int n = strspn(line, delims); |
161 | if (n) { | 176 | if (n) { |
@@ -177,7 +192,6 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
177 | // skip empty line | 192 | // skip empty line |
178 | free(line); | 193 | free(line); |
179 | } | 194 | } |
180 | |||
181 | // non-empty line found, parse and return the number of tokens | 195 | // non-empty line found, parse and return the number of tokens |
182 | 196 | ||
183 | // store line | 197 | // store line |
@@ -190,14 +204,15 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
190 | ntokens--; // now it's max allowed token no | 204 | ntokens--; // now it's max allowed token no |
191 | // N.B. non-empty remainder is also a token, | 205 | // N.B. non-empty remainder is also a token, |
192 | // so if ntokens <= 1, we just return the whole line | 206 | // so if ntokens <= 1, we just return the whole line |
193 | // N.B. if PARSE_LAST_IS_GREEDY is set the remainder of the line is stuck to the last token | 207 | // N.B. if PARSE_GREEDY is set the remainder of the line is stuck to the last token |
194 | for (ii = 0; *line && ii <= ntokens; ) { | 208 | ii = 0; |
209 | while (*line && ii <= ntokens) { | ||
195 | //bb_info_msg("L[%s]", line); | 210 | //bb_info_msg("L[%s]", line); |
196 | // get next token | 211 | // get next token |
197 | // at the last token and need greedy token -> | 212 | // at last token and need greedy token -> |
198 | if ((flags & PARSE_LAST_IS_GREEDY) && (ii == ntokens)) { | 213 | if ((flags & PARSE_GREEDY) && (ii == ntokens)) { |
199 | // skip possible delimiters | 214 | // skip possible delimiters |
200 | if (!(flags & PARSE_DONT_REDUCE)) | 215 | if (flags & PARSE_COLLAPSE) |
201 | line += strspn(line, delims); | 216 | line += strspn(line, delims); |
202 | // don't cut the line | 217 | // don't cut the line |
203 | q = line + strlen(line); | 218 | q = line + strlen(line); |
@@ -208,10 +223,11 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
208 | *q++ = '\0'; | 223 | *q++ = '\0'; |
209 | } | 224 | } |
210 | // pin token | 225 | // pin token |
211 | if ((flags & (PARSE_DONT_REDUCE|PARSE_DONT_TRIM)) || *line) { | 226 | if (!(flags & (PARSE_COLLAPSE | PARSE_TRIM)) || *line) { |
212 | //bb_info_msg("N[%d] T[%s]", ii, line); | 227 | //bb_info_msg("N[%d] T[%s]", ii, line); |
213 | tokens[ii++] = line; | 228 | tokens[ii++] = line; |
214 | // process escapes in token | 229 | // process escapes in token |
230 | #if 0 // unused so far | ||
215 | if (flags & PARSE_ESCAPE) { | 231 | if (flags & PARSE_ESCAPE) { |
216 | char *s = line; | 232 | char *s = line; |
217 | while (*s) { | 233 | while (*s) { |
@@ -224,6 +240,7 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
224 | } | 240 | } |
225 | *line = '\0'; | 241 | *line = '\0'; |
226 | } | 242 | } |
243 | #endif | ||
227 | } | 244 | } |
228 | line = q; | 245 | line = q; |
229 | //bb_info_msg("A[%s]", line); | 246 | //bb_info_msg("A[%s]", line); |
@@ -234,6 +251,7 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const | |||
234 | parser->lineno, ii, mintokens); | 251 | parser->lineno, ii, mintokens); |
235 | if (flags & PARSE_MIN_DIE) | 252 | if (flags & PARSE_MIN_DIE) |
236 | xfunc_die(); | 253 | xfunc_die(); |
254 | ntokens++; | ||
237 | goto again; | 255 | goto again; |
238 | } | 256 | } |
239 | 257 | ||