aboutsummaryrefslogtreecommitdiff
path: root/libbb/parse_config.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-26 23:08:31 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-26 23:08:31 +0000
commit084266ed520805bbc4ec3f9b4d14e644ecd75880 (patch)
treefe2c8531dc039c81c12a39f39fcfdf6c1b8ec996 /libbb/parse_config.c
parent8895c2073e9341d8e0348365e75ba6aa4b9b8d05 (diff)
downloadbusybox-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.c102
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;
14int parse_main(int argc UNUSED_PARAM, char **argv) 14int 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
62parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) 63parser_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
73parser_t* FAST_FUNC config_open(const char *filename) 76parser_t* FAST_FUNC config_open(const char *filename)
@@ -87,41 +90,53 @@ static void config_free_data(parser_t *const parser)
87 90
88void FAST_FUNC config_close(parser_t *parser) 91void 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/*
951. Read a line from config file. If nothing to read then bail out returning 0. 1010. If parser is NULL return 0.
96 Handle continuation character. Advance lineno for each physical line. Cut comments. 1021. Read a line from config file. If nothing to read then return 0.
972. 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.
1052. if PARSE_TRIM is set (default), remove leading and trailing delimiters.
983. If resulting line is empty goto 1. 1063. If resulting line is empty goto 1.
994. Look for first delimiter. If PARSE_DONT_REDUCE or PARSE_DONT_TRIM is set then pin empty token. 1074. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then
1005. 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. 1095. 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.
1046. 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.
1067. Control the number of seen tokens is not less the min number of tokens. Die if condition is not met. 1146. Advance line pointer past the end of token. If number of seen tokens
115 is less than required number of tokens then goto 4.
1167. Check the number of seen tokens is not less the min number of tokens.
117 Complain or die otherwise depending on PARSE_MIN_DIE.
1078. Return the number of seen tokens. 1188. Return the number of seen tokens.
108 119
109mintokens > 0 make config_read() exit with error message if less than mintokens 120mintokens > 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
113int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) 124int 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