aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2011-06-20 09:49:56 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-06-20 09:49:56 +0200
commitadcabf3235a13e77a32ff2a7b7cf80be8ee3dfe3 (patch)
tree5bb62bad050d86c1b711a19a1ea9e7ae525b9311 /libbb
parente12e0acb92329f95a77121f489b491d84b6a2c33 (diff)
downloadbusybox-adcabf3235a13e77a32ff2a7b7cf80be8ee3dfe3.tar.gz
parse_config: use getline. BIG speedup with glibc (~40%).
function old new delta config_read 559 604 +45 getline - 23 +23 config_close 29 49 +20 find_pair 169 187 +18 showmode 330 338 +8 hash_find 233 234 +1 builtin_umask 133 132 -1 lzo1x_optimize 1434 1429 -5 test_main 253 247 -6 buffer_fill_and_print 196 179 -17 create_J 1849 1826 -23 config_free_data 37 - -37 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 5/5 up/down: 138/-89) Total: 26 bytes Signed-off-by: Timo Teras <timo.teras@iki.fi> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r--libbb/parse_config.c92
1 files changed, 43 insertions, 49 deletions
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index c0c34f312..cf5ba4deb 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -83,60 +83,55 @@ parser_t* FAST_FUNC config_open(const char *filename)
return config_open2(filename, fopen_or_warn_stdin);
}
-static void config_free_data(parser_t *parser)
-{
- free(parser->line);
- parser->line = NULL;
- if (PARSE_KEEP_COPY) { /* compile-time constant */
- free(parser->data);
- parser->data = NULL;
- }
-}
-
void FAST_FUNC config_close(parser_t *parser)
{
if (parser) {
- config_free_data(parser);
+ if (PARSE_KEEP_COPY) /* compile-time constant */
+ free(parser->data);
fclose(parser->fp);
+ free(parser->line);
+ free(parser->nline);
free(parser);
}
}
-/* This function reads an entire line from a text file, up to a newline
- * or NUL byte, exclusive. It returns a malloc'ed char*.
- * *lineno is incremented for each line.
+/* This function reads an entire line from a text file,
+ * up to a newline, exclusive.
* Trailing '\' is recognized as line continuation.
- * Returns NULL if EOF/error.
+ * Returns -1 if EOF/error.
*/
-static char* get_line_with_continuation(FILE *file, int *lineno)
+static int get_line_with_continuation(parser_t *parser)
{
- int ch;
- unsigned idx = 0;
- char *linebuf = NULL;
-
- while ((ch = getc(file)) != EOF) {
- /* grow the line buffer as necessary */
- if (!(idx & 0xff))
- linebuf = xrealloc(linebuf, idx + 0x101);
- if (ch == '\n')
- ch = '\0';
- linebuf[idx] = (char) ch;
- if (ch == '\0') {
- (*lineno)++;
- if (idx == 0 || linebuf[idx-1] != '\\')
- break;
- idx--; /* go back to '/' */
- continue;
+ ssize_t len, nlen;
+ char *line;
+
+ len = getline(&parser->line, &parser->line_alloc, parser->fp);
+ if (len <= 0)
+ return len;
+
+ line = parser->line;
+ for (;;) {
+ parser->lineno++;
+ if (line[len - 1] == '\n')
+ len--;
+ if (len == 0 || line[len - 1] != '\\')
+ break;
+ len--;
+
+ nlen = getline(&parser->nline, &parser->nline_alloc, parser->fp);
+ if (nlen <= 0)
+ break;
+
+ if (parser->line_alloc < len + nlen + 1) {
+ parser->line_alloc = len + nlen + 1;
+ line = parser->line = xrealloc(line, parser->line_alloc);
}
- idx++;
- }
- if (ch == EOF) {
- /* handle corner case when the file is not ended with '\n' */
- (*lineno)++;
- if (linebuf)
- linebuf[idx] = '\0';
+ memcpy(&line[len], parser->nline, nlen);
+ len += nlen;
}
- return linebuf;
+
+ line[len] = '\0';
+ return len;
}
@@ -176,15 +171,14 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
ntokens = (uint8_t)flags;
mintokens = (uint8_t)(flags >> 8);
-again:
+ again:
memset(tokens, 0, sizeof(tokens[0]) * ntokens);
- config_free_data(parser);
/* Read one line (handling continuations with backslash) */
- line = get_line_with_continuation(parser->fp, &parser->lineno);
- if (line == NULL)
+ if (get_line_with_continuation(parser) < 0)
return 0;
- parser->line = line;
+
+ line = parser->line;
/* Skip token in the start of line? */
if (flags & PARSE_TRIM)
@@ -193,8 +187,10 @@ again:
if (line[0] == '\0' || line[0] == delims[0])
goto again;
- if (flags & PARSE_KEEP_COPY)
+ if (flags & PARSE_KEEP_COPY) {
+ free(parser->data);
parser->data = xstrdup(line);
+ }
/* Tokenize the line */
t = 0;
@@ -240,8 +236,6 @@ again:
parser->lineno, t, mintokens);
if (flags & PARSE_MIN_DIE)
xfunc_die();
- if (flags & PARSE_KEEP_COPY)
- free(parser->data);
goto again;
}