/* vi: set sw=4 ts=4: */ /* * config file parser helper * * Copyright (C) 2008 by Vladimir Dronnikov * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ #include "libbb.h" /* Typical usage: ----- CUT ----- char *t[3]; // tokens placeholder parser_t p; // parser structure // open file if (config_open(filename, &p)) { // parse line-by-line while (*config_read(&p, t, 3, 0, delimiters, comment_char) >= 0) { // 0..3 tokens // use tokens bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]); } ... // free parser config_close(&p); } ----- CUT ----- */ 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"); if (parser->fp) return parser; config_close (parser); if (ENABLE_FEATURE_CLEAN_UP) free(parser); return NULL; } static void config_free_data(parser_t *const parser) { free(parser->line); free(parser->data); parser->line = 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) { char *line, *q; int ii, seen; /* do not treat subsequent delimiters as one delimiter */ bool noreduce = (ntokens < 0); if (noreduce) ntokens = -ntokens; memset(tokens, 0, sizeof(void *) * 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; parser->lineno++; // handle continuations. Tito's code stolen :) while (1) { ii = strlen(line); if (!ii) goto next_line; if (line[ii - 1] != '\\') break; // multi-line object line[--ii] = '\0'; //TODO: add xmalloc_fgetline-like iface but with appending to existing str q = xmalloc_fgetline(parser->fp); if (q) { parser->lineno++; line = xasprintf("%s%s", line, q); free(q); } } // comments mean EOLs if (comment) { q = strchrnul(line, comment); *q = '\0'; ii = q - line; } // skip leading delimiters seen = strspn(line, delims); if (seen) { ii -= seen; strcpy(line, line + seen); } if (ii) break; next_line: /* skip empty line */ free(line); } // non-empty line found, parse and return // store line parser->line = line = xrealloc(line, ii + 1); parser->data = xstrdup(line); /* now split line to tokens */ ii = noreduce ? seen : 0; ntokens--; // now it's max allowed token no while (1) { // get next token if (ii == ntokens) break; q = line + strcspn(line, delims); if (!*q) break; // pin token *q++ = '\0'; if (noreduce || *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); return ii; }