libbb: updated config_parse() from Vladimir

function                                             old     new   delta
config_read                                          385     460     +75
runsvdir_main                                       1701    1716     +15
readit                                               331     338      +7
passwd_main                                         1049    1053      +4
parse_command                                       1504    1507      +3
decode_format_string                                 822     824      +2
bb__parsespent                                       117     119      +2
udhcp_get_option                                     221     222      +1
changepath                                           196     194      -2
parse_inittab                                        400     396      -4
nameif_main                                          683     679      -4
make_device                                         1176    1172      -4
config_open                                           48      40      -8
expand_main                                          698     689      -9
readcmd                                             1012    1002     -10
config_free_data                                      37      21     -16
SynchronizeFile                                      683     643     -40
sleep_main                                           474     362    -112
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 8/10 up/down: 109/-209)        Total: -100 bytes
This commit is contained in:
Denis Vlasenko
2008-07-19 09:27:19 +00:00
parent bd28f6bf7f
commit 2e157ddf9e
10 changed files with 205 additions and 53 deletions

View File

@@ -9,23 +9,51 @@
#include "libbb.h"
#if ENABLE_PARSE
int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int parse_main(int argc UNUSED_PARAM, char **argv)
{
const char *delims = "# \t";
unsigned flags = 0;
int mintokens = 0, ntokens = 128;
opt_complementary = "-1:n+:m+:f+";
getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags);
//argc -= optind;
argv += optind;
while (*argv) {
parser_t *p = config_open(*argv);
if (p) {
int n;
char **t = xmalloc(sizeof(char *) * ntokens);
while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) > 0) {
for (int i = 0; i < n; ++i)
printf("[%s]", t[i]);
puts("");
}
config_close(p);
}
argv++;
}
return EXIT_SUCCESS;
}
#endif
/*
Typical usage:
----- CUT -----
char *t[3]; // tokens placeholder
parser_t p; // parser structure
// open file
if (config_open(filename, &p)) {
parser_t *p = config_open(filename);
if (p) {
// parse line-by-line
while (*config_read(&p, t, 3, 0, delimiters, comment_char) >= 0) { // 0..3 tokens
while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
// use tokens
bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]);
}
...
// free parser
config_close(&p);
config_close(p);
}
----- CUT -----
@@ -35,44 +63,69 @@ parser_t* FAST_FUNC config_open(const char *filename)
{
parser_t *parser = xzalloc(sizeof(parser_t));
/* empty file configures nothing */
parser->fp = fopen_or_warn(filename, "r");
parser->fp = fopen_or_warn_stdin(filename);
if (parser->fp)
return parser;
config_close (parser);
if (ENABLE_FEATURE_CLEAN_UP)
free(parser);
free(parser);
return NULL;
}
static void config_free_data(parser_t *const parser)
{
free(parser->line);
free(parser->data);
parser->line = parser->data = NULL;
parser->line = NULL;
USE_FEATURE_PARSE_COPY(
free(parser->data);
parser->data = NULL;
)
}
void FAST_FUNC config_close(parser_t *parser)
{
config_free_data(parser);
fclose(parser->fp);
}
int FAST_FUNC config_read(parser_t *parser, char **tokens, int ntokens, int mintokens, const char *delims, char comment)
/*
1. Read a line from config file. If nothing to read then bail out returning 0.
Handle continuation character. Advance lineno for each physical line. Cut comments.
2. if PARSE_DONT_TRIM is not set (default) skip leading and cut trailing delimiters, if any.
3. If resulting line is empty goto 1.
4. Look for first delimiter. If PARSE_DONT_REDUCE or PARSE_DONT_TRIM is set then pin empty token.
5. Else (default) if number of seen tokens is equal to max number of tokens (token is the last one)
and PARSE_LAST_IS_GREEDY is set then pin the remainder of the line as the last token.
Else (token is not last or PARSE_LAST_IS_GREEDY is not set) just replace first delimiter with '\0'
thus delimiting token and pin it.
6. Advance line pointer past the end of token. If number of seen tokens is less than required number
of tokens then goto 4.
7. Control the number of seen tokens is not less the min number of tokens. Die if condition is not met.
8. Return the number of seen tokens.
mintokens > 0 make config_read() exit with error message if less than mintokens
(but more than 0) are found. Empty lines are always skipped (not warned about).
*/
#undef config_read
int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims)
{
char *line, *q;
int ii, seen;
/* do not treat consecutive delimiters as one delimiter */
bool noreduce = (ntokens < 0);
if (noreduce)
ntokens = -ntokens;
char comment = *delims++;
int ii;
int ntokens = flags & 0xFF;
int mintokens = (flags & 0xFF00) >> 8;
memset(tokens, 0, sizeof(tokens[0]) * ntokens);
/*
// N.B. this could only be used in read-in-one-go version, or when tokens use xstrdup(). TODO
if (!parser->lineno || !(flags & PARSE_DONT_NULL))
*/
memset(tokens, 0, sizeof(tokens[0]) * ntokens);
config_free_data(parser);
while (1) {
//TODO: speed up xmalloc_fgetline by internally using fgets, not fgetc
line = xmalloc_fgetline(parser->fp);
if (!line)
return -1;
return 0;
parser->lineno++;
// handle continuations. Tito's code stolen :)
@@ -98,12 +151,22 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, int ntokens, int mint
*q = '\0';
ii = q - line;
}
// skip leading delimiters
seen = strspn(line, delims);
if (seen) {
ii -= seen;
strcpy(line, line + seen);
// skip leading and trailing delimiters
if (!(flags & PARSE_DONT_TRIM)) {
// skip leading
int n = strspn(line, delims);
if (n) {
ii -= n;
strcpy(line, line + n);
}
// cut trailing
if (ii) {
while (strchr(delims, line[--ii]))
continue;
line[++ii] = '\0';
}
}
// if something still remains -> return it
if (ii)
break;
@@ -112,36 +175,39 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, int ntokens, int mint
free(line);
}
// non-empty line found, parse and return
// non-empty line found, parse and return the number of tokens
// store line
parser->line = line = xrealloc(line, ii + 1);
parser->data = xstrdup(line);
USE_FEATURE_PARSE_COPY(
parser->data = xstrdup(line);
)
/* now split line to tokens */
ii = noreduce ? seen : 0;
ntokens--; // now it's max allowed token no
while (1) {
// N.B, non-empty remainder is also a token,
// so if ntokens <= 1, we just return the whole line
// N.B. if PARSE_LAST_IS_GREEDY is set the remainder of the line is stuck to the last token
for (ii = 0; *line && ii <= ntokens; ) {
//bb_info_msg("L[%s]", line);
// get next token
if (ii == ntokens)
break;
q = line + strcspn(line, delims);
if (!*q)
break;
// at the last token and need greedy token ->
if ((flags & PARSE_LAST_IS_GREEDY) && (ii == ntokens)) {
// ... don't cut the line
q = line + strlen(line);
} else {
// vanilla token. cut the line at the first delim
q = line + strcspn(line, delims);
*q++ = '\0';
}
// pin token
*q++ = '\0';
if (noreduce || *line) {
if ((flags & (PARSE_DONT_REDUCE|PARSE_DONT_TRIM)) || *line) {
//bb_info_msg("N[%d] T[%s]", ii, line);
tokens[ii++] = line;
//bb_info_msg("L[%d] T[%s]\n", ii, line);
}
line = q;
}
// non-empty remainder is also a token,
// so if ntokens <= 1, we just return the whole line
if (noreduce || *line)
tokens[ii++] = line;
if (ii < mintokens)
bb_error_msg_and_die("bad line %u: %d tokens found, %d needed",
parser->lineno, ii, mintokens);