aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-08-09 17:16:40 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-08-09 17:16:40 +0000
commit69f4f9a6f40e2825c93fad4d3adf453c9b33d9bb (patch)
tree5e35a08d3b3db69b6dc212cbdf681d78bf4425ff
parent3fd15e197e21aa313ce56126ee814f0ebc884dee (diff)
downloadbusybox-w32-69f4f9a6f40e2825c93fad4d3adf453c9b33d9bb.tar.gz
busybox-w32-69f4f9a6f40e2825c93fad4d3adf453c9b33d9bb.tar.bz2
busybox-w32-69f4f9a6f40e2825c93fad4d3adf453c9b33d9bb.zip
optimize config_read() (by Timo Teras <timo.teras AT iki.fi>)
function old new delta bb_get_chunk_with_continuation - 176 +176 find_pair 169 187 +18 ... process_stdin 443 433 -10 config_read 549 456 -93 bb_get_chunk_from_file 139 7 -132 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 7/7 up/down: 215/-254) Total: -39 bytes
-rw-r--r--include/libbb.h1
-rw-r--r--libbb/get_line_from_file.c30
-rw-r--r--libbb/parse_config.c175
3 files changed, 91 insertions, 115 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 075fa055d..388e2f9ef 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -613,6 +613,7 @@ extern void xopen_xwrite_close(const char* file, const char *str) FAST_FUNC;
613extern void xprint_and_close_file(FILE *file) FAST_FUNC; 613extern void xprint_and_close_file(FILE *file) FAST_FUNC;
614 614
615extern char *bb_get_chunk_from_file(FILE *file, int *end) FAST_FUNC; 615extern char *bb_get_chunk_from_file(FILE *file, int *end) FAST_FUNC;
616extern char *bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno) FAST_FUNC;
616/* Reads up to (and including) TERMINATING_STRING: */ 617/* Reads up to (and including) TERMINATING_STRING: */
617extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC; 618extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC;
618/* Chops off TERMINATING_STRING from the end: */ 619/* Chops off TERMINATING_STRING from the end: */
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index 968d7572d..3cb46d240 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -9,18 +9,22 @@
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 */ 10 */
11 11
12/* for getline() [GNUism] */ 12/* for getline() [GNUism]
13#ifndef _GNU_SOURCE 13#ifndef _GNU_SOURCE
14#define _GNU_SOURCE 1 14#define _GNU_SOURCE 1
15#endif 15#endif
16*/
16#include "libbb.h" 17#include "libbb.h"
17 18
18/* This function reads an entire line from a text file, up to a newline 19/* This function reads an entire line from a text file, up to a newline
19 * or NUL byte, inclusive. It returns a malloc'ed char * which 20 * or NUL byte, inclusive. It returns a malloc'ed char * which
20 * must be free'ed by the caller. If end is NULL '\n' isn't considered 21 * must be free'ed by the caller. If end is NULL '\n' isn't considered
21 * end of line. If end isn't NULL, length of the chunk read is stored in it. 22 * end of line. If end isn't NULL, length of the chunk is stored in it.
22 * Return NULL if EOF/error */ 23 * If lineno is not NULL, *lineno is incremented for each line,
23char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) 24 * and also trailing '\' is recognized as line continuation.
25 *
26 * Returns NULL if EOF/error. */
27char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno)
24{ 28{
25 int ch; 29 int ch;
26 int idx = 0; 30 int idx = 0;
@@ -30,12 +34,20 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
30 while ((ch = getc(file)) != EOF) { 34 while ((ch = getc(file)) != EOF) {
31 /* grow the line buffer as necessary */ 35 /* grow the line buffer as necessary */
32 if (idx >= linebufsz) { 36 if (idx >= linebufsz) {
33 linebufsz += 80; 37 linebufsz += 256;
34 linebuf = xrealloc(linebuf, linebufsz); 38 linebuf = xrealloc(linebuf, linebufsz);
35 } 39 }
36 linebuf[idx++] = (char) ch; 40 linebuf[idx++] = (char) ch;
37 if (!ch || (end && ch == '\n')) 41 if (!ch)
38 break; 42 break;
43 if (end && ch == '\n') {
44 if (lineno == NULL)
45 break;
46 (*lineno)++;
47 if (idx < 2 || linebuf[idx-2] != '\\')
48 break;
49 idx -= 2;
50 }
39 } 51 }
40 if (end) 52 if (end)
41 *end = idx; 53 *end = idx;
@@ -52,6 +64,11 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
52 return linebuf; 64 return linebuf;
53} 65}
54 66
67char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
68{
69 return bb_get_chunk_with_continuation(file, end, NULL);
70}
71
55/* Get line, including trailing \n if any */ 72/* Get line, including trailing \n if any */
56char* FAST_FUNC xmalloc_fgets(FILE *file) 73char* FAST_FUNC xmalloc_fgets(FILE *file)
57{ 74{
@@ -72,7 +89,6 @@ char* FAST_FUNC xmalloc_fgetline(FILE *file)
72} 89}
73 90
74#if 0 91#if 0
75
76/* GNUism getline() should be faster (not tested) than a loop with fgetc */ 92/* GNUism getline() should be faster (not tested) than a loop with fgetc */
77 93
78/* Get line, including trailing \n if any */ 94/* Get line, including trailing \n if any */
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index ace6f3ad3..a0599d4b4 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -123,137 +123,96 @@ mintokens > 0 make config_read() print error message if less than mintokens
123#undef config_read 123#undef config_read
124int 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)
125{ 125{
126 char *line, *q; 126 char *line;
127 char comment; 127 int ntokens, mintokens;
128 int ii; 128 int t, len;
129 int ntokens;
130 int mintokens;
131 129
132 comment = *delims++;
133 ntokens = flags & 0xFF; 130 ntokens = flags & 0xFF;
134 mintokens = (flags & 0xFF00) >> 8; 131 mintokens = (flags & 0xFF00) >> 8;
135 132
136 again: 133 if (parser == NULL)
137 memset(tokens, 0, sizeof(tokens[0]) * ntokens);
138 if (!parser)
139 return 0; 134 return 0;
135
136again:
137 memset(tokens, 0, sizeof(tokens[0]) * ntokens);
140 config_free_data(parser); 138 config_free_data(parser);
141 139
142 while (1) { 140 /* Read one line (handling continuations with backslash) */
143//TODO: speed up xmalloc_fgetline by internally using fgets, not fgetc 141 line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno);
144 line = xmalloc_fgetline(parser->fp); 142 if (line == NULL)
145 if (!line) 143 return 0;
146 return 0; 144 parser->line = line;
147 145
148 parser->lineno++; 146 /* Strip trailing line-feed if any */
149 // handle continuations. Tito's code stolen :) 147 if (len && line[len-1] == '\n')
150 while (1) { 148 line[len-1] = '\0';
151 ii = strlen(line);
152 if (!ii)
153 goto next_line;
154 if (line[ii - 1] != '\\')
155 break;
156 // multi-line object
157 line[--ii] = '\0';
158//TODO: add xmalloc_fgetline-like iface but with appending to existing str
159 q = xmalloc_fgetline(parser->fp);
160 if (!q)
161 break;
162 parser->lineno++;
163 line = xasprintf("%s%s", line, q);
164 free(q);
165 }
166 // discard comments
167 if (comment) {
168 q = strchrnul(line, comment);
169 *q = '\0';
170 ii = q - line;
171 }
172 // skip leading and trailing delimiters
173 if (flags & PARSE_TRIM) {
174 // skip leading
175 int n = strspn(line, delims);
176 if (n) {
177 ii -= n;
178 overlapping_strcpy(line, line + n);
179 }
180 // cut trailing
181 if (ii) {
182 while (strchr(delims, line[--ii]))
183 continue;
184 line[++ii] = '\0';
185 }
186 }
187 // if something still remains -> return it
188 if (ii)
189 break;
190 149
191 next_line: 150 /* Skip token in the start of line? */
192 // skip empty line 151 if (flags & PARSE_TRIM)
193 free(line); 152 line += strspn(line, delims + 1);
194 }
195 // non-empty line found, parse and return the number of tokens
196 153
197 // store line 154 if (line[0] == '\0' || line[0] == delims[0])
198 parser->line = line = xrealloc(line, ii + 1); 155 goto again;
199 if (flags & PARSE_KEEP_COPY) { 156
157 if (flags & PARSE_KEEP_COPY)
200 parser->data = xstrdup(line); 158 parser->data = xstrdup(line);
201 }
202 159
203 // split line to tokens 160 /* Tokenize the line */
204 ntokens--; // now it's max allowed token no 161 for (t = 0; *line && *line != delims[0] && t < ntokens; t++) {
205 // N.B. non-empty remainder is also a token, 162 /* Pin token */
206 // so if ntokens <= 1, we just return the whole line 163 tokens[t] = line;
207 // N.B. if PARSE_GREEDY is set the remainder of the line is stuck to the last token 164
208 ii = 0; 165 /* Combine remaining arguments? */
209 while (*line && ii <= ntokens) { 166 if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) {
210 //bb_info_msg("L[%s]", line); 167 /* Vanilla token, find next delimiter */
211 // get next token 168 line += strcspn(line, delims[0] ? delims : delims + 1);
212 // at last token and need greedy token ->
213 if ((flags & PARSE_GREEDY) && (ii == ntokens)) {
214 // skip possible delimiters
215 if (flags & PARSE_COLLAPSE)
216 line += strspn(line, delims);
217 // don't cut the line
218 q = line + strlen(line);
219 } else { 169 } else {
220 // vanilla token. cut the line at the first delim 170 /* Combining, find comment char if any */
221 q = line + strcspn(line, delims); 171 line = strchrnul(line, delims[0]);
222 if (*q) // watch out: do not step past the line end! 172
223 *q++ = '\0'; 173 /* Trim any extra delimiters from the end */
174 if (flags & PARSE_TRIM) {
175 while (strchr(delims + 1, line[-1]) != NULL)
176 line--;
177 }
224 } 178 }
225 // pin token 179
226 if (!(flags & (PARSE_COLLAPSE | PARSE_TRIM)) || *line) { 180 /* Token not terminated? */
227 //bb_info_msg("N[%d] T[%s]", ii, line); 181 if (line[0] == delims[0])
228 tokens[ii++] = line; 182 *line = '\0';
229 // process escapes in token 183 else if (line[0] != '\0')
230#if 0 // unused so far 184 *(line++) = '\0';
231 if (flags & PARSE_ESCAPE) { 185
232 char *s = line; 186#if 0 /* unused so far */
233 while (*s) { 187 if (flags & PARSE_ESCAPE) {
234 if (*s == '\\') { 188 const char *from;
235 s++; 189 char *to;
236 *line++ = bb_process_escape_sequence((const char **)&s); 190
237 } else { 191 from = to = tokens[t];
238 *line++ = *s++; 192 while (*from) {
239 } 193 if (*from == '\\') {
194 from++;
195 *to++ = bb_process_escape_sequence(&from);
196 } else {
197 *to++ = *from++;
240 } 198 }
241 *line = '\0';
242 } 199 }
243#endif 200 *to = '\0';
244 } 201 }
245 line = q; 202#endif
246 //bb_info_msg("A[%s]", line); 203
204 /* Skip possible delimiters */
205 if (flags & PARSE_COLLAPSE)
206 line += strspn(line, delims + 1);
247 } 207 }
248 208
249 if (ii < mintokens) { 209 if (t < mintokens) {
250 bb_error_msg("bad line %u: %d tokens found, %d needed", 210 bb_error_msg("bad line %u: %d tokens found, %d needed",
251 parser->lineno, ii, mintokens); 211 parser->lineno, t, mintokens);
252 if (flags & PARSE_MIN_DIE) 212 if (flags & PARSE_MIN_DIE)
253 xfunc_die(); 213 xfunc_die();
254 ntokens++;
255 goto again; 214 goto again;
256 } 215 }
257 216
258 return ii; 217 return t;
259} 218}