Speeds up considerably config file parsing.
Signed-off-by: Timo Teräs <[email protected]>
---
include/libbb.h | 3 +-
libbb/parse_config.c | 74 +++++++++++++++++++++++++------------------------
2 files changed, 40 insertions(+), 37 deletions(-)
diff --git a/include/libbb.h b/include/libbb.h
index 2cac7e6..953bec3 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1184,8 +1184,9 @@ enum {
};
typedef struct parser_t {
FILE *fp;
- char *line;
char *data;
+ char *line, *nline;
+ size_t line_alloc, nline_alloc;
int lineno;
} parser_t;
parser_t* config_open(const char *filename) FAST_FUNC;
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index c0c34f3..bb5832d 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -85,8 +85,6 @@ parser_t* FAST_FUNC config_open(const char *filename)
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;
@@ -98,45 +96,49 @@ void FAST_FUNC config_close(parser_t *parser)
if (parser) {
config_free_data(parser);
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 -1;
+
+ line = parser->line;
+ do {
+ parser->lineno++;
+ if (len && 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';
- }
- return linebuf;
+ memcpy(&line[len], parser->nline, nlen);
+ len += nlen;
+ } while (1);
+
+ line[len] = 0;
+ return len;
}
@@ -181,10 +183,10 @@ again:
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)
--
1.7.1
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox