aboutsummaryrefslogtreecommitdiff
path: root/libbb/parse_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/parse_config.c')
-rw-r--r--libbb/parse_config.c140
1 files changed, 83 insertions, 57 deletions
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index 4b0236028..cf5ba4deb 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -8,11 +8,27 @@
8 * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later. 8 * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later.
9 */ 9 */
10 10
11/* 11/* Uncomment to enable test applet */
12////config:config PARSE
13////config: bool "Uniform config file parser debugging applet: parse"
14////config: default n
15////config: help
16////config: Typical usage of parse API:
17////config: char *t[3];
18////config: parser_t *p = config_open(filename);
19////config: while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
20////config: bb_error_msg("TOKENS: '%s''%s''%s'", t[0], t[1], t[2]);
21////config: }
22////config: config_close(p);
23
24////applet:IF_PARSE(APPLET(parse, BB_DIR_USR_BIN, BB_SUID_DROP))
25
26//kbuild:lib-y += parse_config.o
27
12//usage:#define parse_trivial_usage 28//usage:#define parse_trivial_usage
13//usage: "[-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..." 29//usage: "[-x] [-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..."
14//usage:#define parse_full_usage "" 30//usage:#define parse_full_usage "\n\n"
15*/ 31//usage: " -x Suppress output (for benchmarking)"
16 32
17#include "libbb.h" 33#include "libbb.h"
18 34
@@ -21,52 +37,34 @@ int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
21int parse_main(int argc UNUSED_PARAM, char **argv) 37int parse_main(int argc UNUSED_PARAM, char **argv)
22{ 38{
23 const char *delims = "# \t"; 39 const char *delims = "# \t";
40 char **t;
24 unsigned flags = PARSE_NORMAL; 41 unsigned flags = PARSE_NORMAL;
25 int mintokens = 0, ntokens = 128; 42 int mintokens = 0, ntokens = 128;
43 unsigned noout;
26 44
27 opt_complementary = "-1:n+:m+:f+"; 45 opt_complementary = "-1:n+:m+:f+";
28 getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); 46 noout = 1 & getopt32(argv, "xn:m:d:f:", &ntokens, &mintokens, &delims, &flags);
29 //argc -= optind; 47 //argc -= optind;
30 argv += optind; 48 argv += optind;
49
50 t = xmalloc(sizeof(t[0]) * ntokens);
31 while (*argv) { 51 while (*argv) {
52 int n;
32 parser_t *p = config_open(*argv); 53 parser_t *p = config_open(*argv);
33 if (p) { 54 while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) {
34 int n; 55 if (!noout) {
35 char **t = xmalloc(sizeof(char *) * ntokens);
36 while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) {
37 for (int i = 0; i < n; ++i) 56 for (int i = 0; i < n; ++i)
38 printf("[%s]", t[i]); 57 printf("[%s]", t[i]);
39 puts(""); 58 puts("");
40 } 59 }
41 config_close(p);
42 } 60 }
61 config_close(p);
43 argv++; 62 argv++;
44 } 63 }
45 return EXIT_SUCCESS; 64 return EXIT_SUCCESS;
46} 65}
47#endif 66#endif
48 67
49/*
50
51Typical usage:
52
53----- CUT -----
54 char *t[3]; // tokens placeholder
55 parser_t *p = config_open(filename);
56 if (p) {
57 // parse line-by-line
58 while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
59 // use tokens
60 bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]);
61 }
62 ...
63 // free parser
64 config_close(p);
65 }
66----- CUT -----
67
68*/
69
70parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) 68parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path))
71{ 69{
72 FILE* fp; 70 FILE* fp;
@@ -85,25 +83,58 @@ parser_t* FAST_FUNC config_open(const char *filename)
85 return config_open2(filename, fopen_or_warn_stdin); 83 return config_open2(filename, fopen_or_warn_stdin);
86} 84}
87 85
88static void config_free_data(parser_t *parser)
89{
90 free(parser->line);
91 parser->line = NULL;
92 if (PARSE_KEEP_COPY) { /* compile-time constant */
93 free(parser->data);
94 parser->data = NULL;
95 }
96}
97
98void FAST_FUNC config_close(parser_t *parser) 86void FAST_FUNC config_close(parser_t *parser)
99{ 87{
100 if (parser) { 88 if (parser) {
101 config_free_data(parser); 89 if (PARSE_KEEP_COPY) /* compile-time constant */
90 free(parser->data);
102 fclose(parser->fp); 91 fclose(parser->fp);
92 free(parser->line);
93 free(parser->nline);
103 free(parser); 94 free(parser);
104 } 95 }
105} 96}
106 97
98/* This function reads an entire line from a text file,
99 * up to a newline, exclusive.
100 * Trailing '\' is recognized as line continuation.
101 * Returns -1 if EOF/error.
102 */
103static int get_line_with_continuation(parser_t *parser)
104{
105 ssize_t len, nlen;
106 char *line;
107
108 len = getline(&parser->line, &parser->line_alloc, parser->fp);
109 if (len <= 0)
110 return len;
111
112 line = parser->line;
113 for (;;) {
114 parser->lineno++;
115 if (line[len - 1] == '\n')
116 len--;
117 if (len == 0 || line[len - 1] != '\\')
118 break;
119 len--;
120
121 nlen = getline(&parser->nline, &parser->nline_alloc, parser->fp);
122 if (nlen <= 0)
123 break;
124
125 if (parser->line_alloc < len + nlen + 1) {
126 parser->line_alloc = len + nlen + 1;
127 line = parser->line = xrealloc(line, parser->line_alloc);
128 }
129 memcpy(&line[len], parser->nline, nlen);
130 len += nlen;
131 }
132
133 line[len] = '\0';
134 return len;
135}
136
137
107/* 138/*
1080. If parser is NULL return 0. 1390. If parser is NULL return 0.
1091. Read a line from config file. If nothing to read then return 0. 1401. Read a line from config file. If nothing to read then return 0.
@@ -132,27 +163,22 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
132{ 163{
133 char *line; 164 char *line;
134 int ntokens, mintokens; 165 int ntokens, mintokens;
135 int t, len; 166 int t;
167
168 if (!parser)
169 return 0;
136 170
137 ntokens = (uint8_t)flags; 171 ntokens = (uint8_t)flags;
138 mintokens = (uint8_t)(flags >> 8); 172 mintokens = (uint8_t)(flags >> 8);
139 173
140 if (parser == NULL) 174 again:
141 return 0;
142
143again:
144 memset(tokens, 0, sizeof(tokens[0]) * ntokens); 175 memset(tokens, 0, sizeof(tokens[0]) * ntokens);
145 config_free_data(parser);
146 176
147 /* Read one line (handling continuations with backslash) */ 177 /* Read one line (handling continuations with backslash) */
148 line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno); 178 if (get_line_with_continuation(parser) < 0)
149 if (line == NULL)
150 return 0; 179 return 0;
151 parser->line = line;
152 180
153 /* Strip trailing line-feed if any */ 181 line = parser->line;
154 if (len && line[len-1] == '\n')
155 line[len-1] = '\0';
156 182
157 /* Skip token in the start of line? */ 183 /* Skip token in the start of line? */
158 if (flags & PARSE_TRIM) 184 if (flags & PARSE_TRIM)
@@ -161,8 +187,10 @@ again:
161 if (line[0] == '\0' || line[0] == delims[0]) 187 if (line[0] == '\0' || line[0] == delims[0])
162 goto again; 188 goto again;
163 189
164 if (flags & PARSE_KEEP_COPY) 190 if (flags & PARSE_KEEP_COPY) {
191 free(parser->data);
165 parser->data = xstrdup(line); 192 parser->data = xstrdup(line);
193 }
166 194
167 /* Tokenize the line */ 195 /* Tokenize the line */
168 t = 0; 196 t = 0;
@@ -208,8 +236,6 @@ again:
208 parser->lineno, t, mintokens); 236 parser->lineno, t, mintokens);
209 if (flags & PARSE_MIN_DIE) 237 if (flags & PARSE_MIN_DIE)
210 xfunc_die(); 238 xfunc_die();
211 if (flags & PARSE_KEEP_COPY)
212 free(parser->data);
213 goto again; 239 goto again;
214 } 240 }
215 241