Magellan Linux

Annotation of /tags/mkinitrd-6_2_3/busybox/libbb/parse_config.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1054 - (hide annotations) (download)
Mon May 31 20:54:44 2010 UTC (14 years, 1 month ago) by niro
File MIME type: text/plain
File size: 5460 byte(s)
tagged 'mkinitrd-6_2_3'
1 niro 816 /* vi: set sw=4 ts=4: */
2     /*
3     * config file parser helper
4     *
5     * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
6     *
7     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 niro 984 * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later.
9 niro 816 */
10    
11     #include "libbb.h"
12    
13     #if defined ENABLE_PARSE && ENABLE_PARSE
14     int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
15     int parse_main(int argc UNUSED_PARAM, char **argv)
16     {
17     const char *delims = "# \t";
18     unsigned flags = PARSE_NORMAL;
19     int mintokens = 0, ntokens = 128;
20    
21     opt_complementary = "-1:n+:m+:f+";
22     getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags);
23     //argc -= optind;
24     argv += optind;
25     while (*argv) {
26     parser_t *p = config_open(*argv);
27     if (p) {
28     int n;
29     char **t = xmalloc(sizeof(char *) * ntokens);
30     while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) {
31     for (int i = 0; i < n; ++i)
32     printf("[%s]", t[i]);
33     puts("");
34     }
35     config_close(p);
36     }
37     argv++;
38     }
39     return EXIT_SUCCESS;
40     }
41     #endif
42    
43     /*
44    
45     Typical usage:
46    
47     ----- CUT -----
48     char *t[3]; // tokens placeholder
49     parser_t *p = config_open(filename);
50     if (p) {
51     // parse line-by-line
52     while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
53     // use tokens
54     bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]);
55     }
56     ...
57     // free parser
58     config_close(p);
59     }
60     ----- CUT -----
61    
62     */
63    
64     parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path))
65     {
66     FILE* fp;
67     parser_t *parser;
68    
69     fp = fopen_func(filename);
70     if (!fp)
71     return NULL;
72     parser = xzalloc(sizeof(*parser));
73     parser->fp = fp;
74     return parser;
75     }
76    
77     parser_t* FAST_FUNC config_open(const char *filename)
78     {
79     return config_open2(filename, fopen_or_warn_stdin);
80     }
81    
82 niro 984 static void config_free_data(parser_t *parser)
83 niro 816 {
84     free(parser->line);
85     parser->line = NULL;
86     if (PARSE_KEEP_COPY) { /* compile-time constant */
87     free(parser->data);
88     parser->data = NULL;
89     }
90     }
91    
92     void FAST_FUNC config_close(parser_t *parser)
93     {
94     if (parser) {
95     config_free_data(parser);
96     fclose(parser->fp);
97     free(parser);
98     }
99     }
100    
101     /*
102     0. If parser is NULL return 0.
103     1. Read a line from config file. If nothing to read then return 0.
104     Handle continuation character. Advance lineno for each physical line.
105 niro 984 Discard everything past comment character.
106 niro 816 2. if PARSE_TRIM is set (default), remove leading and trailing delimiters.
107     3. If resulting line is empty goto 1.
108     4. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then
109     remember the token as empty.
110     5. Else (default) if number of seen tokens is equal to max number of tokens
111     (token is the last one) and PARSE_GREEDY is set then the remainder
112     of the line is the last token.
113     Else (token is not last or PARSE_GREEDY is not set) just replace
114     first delimiter with '\0' thus delimiting the token.
115     6. Advance line pointer past the end of token. If number of seen tokens
116     is less than required number of tokens then goto 4.
117     7. Check the number of seen tokens is not less the min number of tokens.
118     Complain or die otherwise depending on PARSE_MIN_DIE.
119     8. Return the number of seen tokens.
120    
121     mintokens > 0 make config_read() print error message if less than mintokens
122     (but more than 0) are found. Empty lines are always skipped (not warned about).
123     */
124     #undef config_read
125     int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims)
126     {
127     char *line;
128     int ntokens, mintokens;
129     int t, len;
130    
131     ntokens = flags & 0xFF;
132     mintokens = (flags & 0xFF00) >> 8;
133    
134     if (parser == NULL)
135     return 0;
136    
137     again:
138     memset(tokens, 0, sizeof(tokens[0]) * ntokens);
139     config_free_data(parser);
140    
141     /* Read one line (handling continuations with backslash) */
142     line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno);
143     if (line == NULL)
144     return 0;
145     parser->line = line;
146    
147     /* Strip trailing line-feed if any */
148     if (len && line[len-1] == '\n')
149     line[len-1] = '\0';
150    
151     /* Skip token in the start of line? */
152     if (flags & PARSE_TRIM)
153     line += strspn(line, delims + 1);
154    
155     if (line[0] == '\0' || line[0] == delims[0])
156     goto again;
157    
158     if (flags & PARSE_KEEP_COPY)
159     parser->data = xstrdup(line);
160    
161     /* Tokenize the line */
162     for (t = 0; *line && *line != delims[0] && t < ntokens; t++) {
163     /* Pin token */
164     tokens[t] = line;
165    
166     /* Combine remaining arguments? */
167     if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) {
168     /* Vanilla token, find next delimiter */
169     line += strcspn(line, delims[0] ? delims : delims + 1);
170     } else {
171     /* Combining, find comment char if any */
172     line = strchrnul(line, delims[0]);
173    
174     /* Trim any extra delimiters from the end */
175     if (flags & PARSE_TRIM) {
176     while (strchr(delims + 1, line[-1]) != NULL)
177     line--;
178     }
179     }
180    
181     /* Token not terminated? */
182     if (line[0] == delims[0])
183     *line = '\0';
184     else if (line[0] != '\0')
185     *(line++) = '\0';
186    
187     #if 0 /* unused so far */
188     if (flags & PARSE_ESCAPE) {
189     const char *from;
190     char *to;
191    
192     from = to = tokens[t];
193     while (*from) {
194     if (*from == '\\') {
195     from++;
196     *to++ = bb_process_escape_sequence(&from);
197     } else {
198     *to++ = *from++;
199     }
200     }
201     *to = '\0';
202     }
203     #endif
204    
205     /* Skip possible delimiters */
206     if (flags & PARSE_COLLAPSE)
207     line += strspn(line, delims + 1);
208     }
209    
210     if (t < mintokens) {
211     bb_error_msg("bad line %u: %d tokens found, %d needed",
212     parser->lineno, t, mintokens);
213     if (flags & PARSE_MIN_DIE)
214     xfunc_die();
215     goto again;
216     }
217    
218     return t;
219     }