diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-19 09:27:19 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-19 09:27:19 +0000 |
commit | 2e157ddf9ecd9d58864425f0e87409ddc218df94 (patch) | |
tree | 18f415d4847897a12d790b545f94c32ae68c199c /libbb/parse_config.c | |
parent | bd28f6bf7f53ede8df39112d40cb52f2a3d00177 (diff) | |
download | busybox-w32-2e157ddf9ecd9d58864425f0e87409ddc218df94.tar.gz busybox-w32-2e157ddf9ecd9d58864425f0e87409ddc218df94.tar.bz2 busybox-w32-2e157ddf9ecd9d58864425f0e87409ddc218df94.zip |
libbb: updated config_parse() from Vladimir
function old new delta
config_read 385 460 +75
runsvdir_main 1701 1716 +15
readit 331 338 +7
passwd_main 1049 1053 +4
parse_command 1504 1507 +3
decode_format_string 822 824 +2
bb__parsespent 117 119 +2
udhcp_get_option 221 222 +1
changepath 196 194 -2
parse_inittab 400 396 -4
nameif_main 683 679 -4
make_device 1176 1172 -4
config_open 48 40 -8
expand_main 698 689 -9
readcmd 1012 1002 -10
config_free_data 37 21 -16
SynchronizeFile 683 643 -40
sleep_main 474 362 -112
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 8/10 up/down: 109/-209) Total: -100 bytes
Diffstat (limited to 'libbb/parse_config.c')
-rw-r--r-- | libbb/parse_config.c | 148 |
1 files changed, 107 insertions, 41 deletions
diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 5f6dbbde1..3945501ad 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c | |||
@@ -9,23 +9,51 @@ | |||
9 | 9 | ||
10 | #include "libbb.h" | 10 | #include "libbb.h" |
11 | 11 | ||
12 | #if 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 = 0; | ||
18 | int mintokens = 0, ntokens = 128; | ||
19 | opt_complementary = "-1:n+:m+:f+"; | ||
20 | getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); | ||
21 | //argc -= optind; | ||
22 | argv += optind; | ||
23 | while (*argv) { | ||
24 | parser_t *p = config_open(*argv); | ||
25 | if (p) { | ||
26 | int n; | ||
27 | char **t = xmalloc(sizeof(char *) * ntokens); | ||
28 | while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) > 0) { | ||
29 | for (int i = 0; i < n; ++i) | ||
30 | printf("[%s]", t[i]); | ||
31 | puts(""); | ||
32 | } | ||
33 | config_close(p); | ||
34 | } | ||
35 | argv++; | ||
36 | } | ||
37 | return EXIT_SUCCESS; | ||
38 | } | ||
39 | #endif | ||
40 | |||
12 | /* | 41 | /* |
13 | 42 | ||
14 | Typical usage: | 43 | Typical usage: |
15 | 44 | ||
16 | ----- CUT ----- | 45 | ----- CUT ----- |
17 | char *t[3]; // tokens placeholder | 46 | char *t[3]; // tokens placeholder |
18 | parser_t p; // parser structure | 47 | parser_t *p = config_open(filename); |
19 | // open file | 48 | if (p) { |
20 | if (config_open(filename, &p)) { | ||
21 | // parse line-by-line | 49 | // parse line-by-line |
22 | while (*config_read(&p, t, 3, 0, delimiters, comment_char) >= 0) { // 0..3 tokens | 50 | while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens |
23 | // use tokens | 51 | // use tokens |
24 | bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]); | 52 | bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]); |
25 | } | 53 | } |
26 | ... | 54 | ... |
27 | // free parser | 55 | // free parser |
28 | config_close(&p); | 56 | config_close(p); |
29 | } | 57 | } |
30 | ----- CUT ----- | 58 | ----- CUT ----- |
31 | 59 | ||
@@ -35,44 +63,69 @@ parser_t* FAST_FUNC config_open(const char *filename) | |||
35 | { | 63 | { |
36 | parser_t *parser = xzalloc(sizeof(parser_t)); | 64 | parser_t *parser = xzalloc(sizeof(parser_t)); |
37 | /* empty file configures nothing */ | 65 | /* empty file configures nothing */ |
38 | parser->fp = fopen_or_warn(filename, "r"); | 66 | parser->fp = fopen_or_warn_stdin(filename); |
39 | if (parser->fp) | 67 | if (parser->fp) |
40 | return parser; | 68 | return parser; |
41 | config_close (parser); | ||
42 | if (ENABLE_FEATURE_CLEAN_UP) | 69 | if (ENABLE_FEATURE_CLEAN_UP) |
43 | free(parser); | 70 | free(parser); |
44 | return NULL; | 71 | return NULL; |
45 | } | 72 | } |
46 | 73 | ||
47 | static void config_free_data(parser_t *const parser) | 74 | static void config_free_data(parser_t *const parser) |
48 | { | 75 | { |
49 | free(parser->line); | 76 | free(parser->line); |
50 | free(parser->data); | 77 | parser->line = NULL; |
51 | parser->line = parser->data = NULL; | 78 | USE_FEATURE_PARSE_COPY( |
79 | free(parser->data); | ||
80 | parser->data = NULL; | ||
81 | ) | ||
52 | } | 82 | } |
83 | |||
53 | void FAST_FUNC config_close(parser_t *parser) | 84 | void FAST_FUNC config_close(parser_t *parser) |
54 | { | 85 | { |
55 | config_free_data(parser); | 86 | config_free_data(parser); |
56 | fclose(parser->fp); | 87 | fclose(parser->fp); |
57 | } | 88 | } |
58 | 89 | ||
59 | int FAST_FUNC config_read(parser_t *parser, char **tokens, int ntokens, int mintokens, const char *delims, char comment) | 90 | /* |
91 | 1. Read a line from config file. If nothing to read then bail out returning 0. | ||
92 | Handle continuation character. Advance lineno for each physical line. Cut comments. | ||
93 | 2. if PARSE_DONT_TRIM is not set (default) skip leading and cut trailing delimiters, if any. | ||
94 | 3. If resulting line is empty goto 1. | ||
95 | 4. Look for first delimiter. If PARSE_DONT_REDUCE or PARSE_DONT_TRIM is set then pin empty token. | ||
96 | 5. Else (default) if number of seen tokens is equal to max number of tokens (token is the last one) | ||
97 | and PARSE_LAST_IS_GREEDY is set then pin the remainder of the line as the last token. | ||
98 | Else (token is not last or PARSE_LAST_IS_GREEDY is not set) just replace first delimiter with '\0' | ||
99 | thus delimiting token and pin it. | ||
100 | 6. Advance line pointer past the end of token. If number of seen tokens is less than required number | ||
101 | of tokens then goto 4. | ||
102 | 7. Control the number of seen tokens is not less the min number of tokens. Die if condition is not met. | ||
103 | 8. Return the number of seen tokens. | ||
104 | |||
105 | mintokens > 0 make config_read() exit with error message if less than mintokens | ||
106 | (but more than 0) are found. Empty lines are always skipped (not warned about). | ||
107 | */ | ||
108 | #undef config_read | ||
109 | int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) | ||
60 | { | 110 | { |
61 | char *line, *q; | 111 | char *line, *q; |
62 | int ii, seen; | 112 | char comment = *delims++; |
63 | /* do not treat consecutive delimiters as one delimiter */ | 113 | int ii; |
64 | bool noreduce = (ntokens < 0); | 114 | int ntokens = flags & 0xFF; |
65 | if (noreduce) | 115 | int mintokens = (flags & 0xFF00) >> 8; |
66 | ntokens = -ntokens; | 116 | |
67 | 117 | /* | |
68 | memset(tokens, 0, sizeof(tokens[0]) * ntokens); | 118 | // N.B. this could only be used in read-in-one-go version, or when tokens use xstrdup(). TODO |
119 | if (!parser->lineno || !(flags & PARSE_DONT_NULL)) | ||
120 | */ | ||
121 | memset(tokens, 0, sizeof(tokens[0]) * ntokens); | ||
69 | config_free_data(parser); | 122 | config_free_data(parser); |
70 | 123 | ||
71 | while (1) { | 124 | while (1) { |
72 | //TODO: speed up xmalloc_fgetline by internally using fgets, not fgetc | 125 | //TODO: speed up xmalloc_fgetline by internally using fgets, not fgetc |
73 | line = xmalloc_fgetline(parser->fp); | 126 | line = xmalloc_fgetline(parser->fp); |
74 | if (!line) | 127 | if (!line) |
75 | return -1; | 128 | return 0; |
76 | 129 | ||
77 | parser->lineno++; | 130 | parser->lineno++; |
78 | // handle continuations. Tito's code stolen :) | 131 | // handle continuations. Tito's code stolen :) |
@@ -98,12 +151,22 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, int ntokens, int mint | |||
98 | *q = '\0'; | 151 | *q = '\0'; |
99 | ii = q - line; | 152 | ii = q - line; |
100 | } | 153 | } |
101 | // skip leading delimiters | 154 | // skip leading and trailing delimiters |
102 | seen = strspn(line, delims); | 155 | if (!(flags & PARSE_DONT_TRIM)) { |
103 | if (seen) { | 156 | // skip leading |
104 | ii -= seen; | 157 | int n = strspn(line, delims); |
105 | strcpy(line, line + seen); | 158 | if (n) { |
159 | ii -= n; | ||
160 | strcpy(line, line + n); | ||
161 | } | ||
162 | // cut trailing | ||
163 | if (ii) { | ||
164 | while (strchr(delims, line[--ii])) | ||
165 | continue; | ||
166 | line[++ii] = '\0'; | ||
167 | } | ||
106 | } | 168 | } |
169 | // if something still remains -> return it | ||
107 | if (ii) | 170 | if (ii) |
108 | break; | 171 | break; |
109 | 172 | ||
@@ -112,36 +175,39 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, int ntokens, int mint | |||
112 | free(line); | 175 | free(line); |
113 | } | 176 | } |
114 | 177 | ||
115 | // non-empty line found, parse and return | 178 | // non-empty line found, parse and return the number of tokens |
116 | 179 | ||
117 | // store line | 180 | // store line |
118 | parser->line = line = xrealloc(line, ii + 1); | 181 | parser->line = line = xrealloc(line, ii + 1); |
119 | parser->data = xstrdup(line); | 182 | USE_FEATURE_PARSE_COPY( |
183 | parser->data = xstrdup(line); | ||
184 | ) | ||
120 | 185 | ||
121 | /* now split line to tokens */ | 186 | /* now split line to tokens */ |
122 | ii = noreduce ? seen : 0; | ||
123 | ntokens--; // now it's max allowed token no | 187 | ntokens--; // now it's max allowed token no |
124 | while (1) { | 188 | // N.B, non-empty remainder is also a token, |
189 | // so if ntokens <= 1, we just return the whole line | ||
190 | // N.B. if PARSE_LAST_IS_GREEDY is set the remainder of the line is stuck to the last token | ||
191 | for (ii = 0; *line && ii <= ntokens; ) { | ||
192 | //bb_info_msg("L[%s]", line); | ||
125 | // get next token | 193 | // get next token |
126 | if (ii == ntokens) | 194 | // at the last token and need greedy token -> |
127 | break; | 195 | if ((flags & PARSE_LAST_IS_GREEDY) && (ii == ntokens)) { |
128 | q = line + strcspn(line, delims); | 196 | // ... don't cut the line |
129 | if (!*q) | 197 | q = line + strlen(line); |
130 | break; | 198 | } else { |
199 | // vanilla token. cut the line at the first delim | ||
200 | q = line + strcspn(line, delims); | ||
201 | *q++ = '\0'; | ||
202 | } | ||
131 | // pin token | 203 | // pin token |
132 | *q++ = '\0'; | 204 | if ((flags & (PARSE_DONT_REDUCE|PARSE_DONT_TRIM)) || *line) { |
133 | if (noreduce || *line) { | 205 | //bb_info_msg("N[%d] T[%s]", ii, line); |
134 | tokens[ii++] = line; | 206 | tokens[ii++] = line; |
135 | //bb_info_msg("L[%d] T[%s]\n", ii, line); | ||
136 | } | 207 | } |
137 | line = q; | 208 | line = q; |
138 | } | 209 | } |
139 | 210 | ||
140 | // non-empty remainder is also a token, | ||
141 | // so if ntokens <= 1, we just return the whole line | ||
142 | if (noreduce || *line) | ||
143 | tokens[ii++] = line; | ||
144 | |||
145 | if (ii < mintokens) | 211 | if (ii < mintokens) |
146 | bb_error_msg_and_die("bad line %u: %d tokens found, %d needed", | 212 | bb_error_msg_and_die("bad line %u: %d tokens found, %d needed", |
147 | parser->lineno, ii, mintokens); | 213 | parser->lineno, ii, mintokens); |