| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- /* Copyright (c) 2000-2007 by Nicolas Devillard.
- * Copyright (x) 2009 by Tim Post <tinkertim@gmail.com>
- * MIT License
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- /** @addtogroup ciniparser
- * @{
- */
- /**
- * @file ciniparser.c
- * @author N. Devillard
- * @date Sep 2007
- * @version 3.0
- * @brief Parser for ini files.
- */
- #include <ctype.h>
- #include <ccan/ciniparser/ciniparser.h>
- #define ASCIILINESZ (1024)
- #define INI_INVALID_KEY ((char*) NULL)
- /**
- * This enum stores the status for each parsed line (internal use only).
- */
- typedef enum _line_status_ {
- LINE_UNPROCESSED,
- LINE_ERROR,
- LINE_EMPTY,
- LINE_COMMENT,
- LINE_SECTION,
- LINE_VALUE
- } line_status;
- /**
- * @brief Convert a string to lowercase.
- * @param s String to convert.
- * @return ptr to statically allocated string.
- *
- * This function returns a pointer to a statically allocated string
- * containing a lowercased version of the input string. Do not free
- * or modify the returned string! Since the returned string is statically
- * allocated, it will be modified at each function call (not re-entrant).
- */
- static char *strlwc(const char *s)
- {
- static char l[ASCIILINESZ+1];
- int i;
- if (s == NULL)
- return NULL;
- for (i = 0; s[i] && i < ASCIILINESZ; i++)
- l[i] = tolower(s[i]);
- l[i] = '\0';
- return l;
- }
- /**
- * @brief Remove blanks at the beginning and the end of a string.
- * @param s String to parse.
- * @return ptr to statically allocated string.
- *
- * This function returns a pointer to a statically allocated string,
- * which is identical to the input string, except that all blank
- * characters at the end and the beg. of the string have been removed.
- * Do not free or modify the returned string! Since the returned string
- * is statically allocated, it will be modified at each function call
- * (not re-entrant).
- */
- static char *strstrip(const char *s)
- {
- static char l[ASCIILINESZ+1];
- unsigned int i, numspc;
- if (s == NULL)
- return NULL;
- while (isspace(*s))
- s++;
- for (i = numspc = 0; s[i] && i < ASCIILINESZ; i++) {
- l[i] = s[i];
- if (isspace(l[i]))
- numspc++;
- else
- numspc = 0;
- }
- l[i - numspc] = '\0';
- return l;
- }
- /**
- * @brief Load a single line from an INI file
- * @param input_line Input line, may be concatenated multi-line input
- * @param section Output space to store section
- * @param key Output space to store key
- * @param value Output space to store value
- * @return line_status value
- */
- static
- line_status ciniparser_line(char *input_line, char *section,
- char *key, char *value)
- {
- line_status sta;
- char line[ASCIILINESZ+1];
- int len;
- strcpy(line, strstrip(input_line));
- len = (int) strlen(line);
- if (len < 1) {
- /* Empty line */
- sta = LINE_EMPTY;
- } else if (line[0] == '#') {
- /* Comment line */
- sta = LINE_COMMENT;
- } else if (line[0] == '[' && line[len-1] == ']') {
- /* Section name */
- sscanf(line, "[%[^]]", section);
- strcpy(section, strstrip(section));
- strcpy(section, strlwc(section));
- sta = LINE_SECTION;
- } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
- || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
- || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
- /* Usual key=value, with or without comments */
- strcpy(key, strstrip(key));
- strcpy(key, strlwc(key));
- strcpy(value, strstrip(value));
- /*
- * sscanf cannot handle '' or "" as empty values
- * this is done here
- */
- if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
- value[0] = 0;
- }
- sta = LINE_VALUE;
- } else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2
- || sscanf(line, "%[^=] %[=]", key, value) == 2) {
- /*
- * Special cases:
- * key=
- * key=;
- * key=#
- */
- strcpy(key, strstrip(key));
- strcpy(key, strlwc(key));
- value[0] = 0;
- sta = LINE_VALUE;
- } else {
- /* Generate syntax error */
- sta = LINE_ERROR;
- }
- return sta;
- }
- /* The remaining public functions are documented in ciniparser.h */
- int ciniparser_getnsec(dictionary *d)
- {
- int i;
- int nsec;
- if (d == NULL)
- return -1;
- nsec = 0;
- for (i = 0; i < d->size; i++) {
- if (d->key[i] == NULL)
- continue;
- if (strchr(d->key[i], ':') == NULL) {
- nsec ++;
- }
- }
- return nsec;
- }
- char *ciniparser_getsecname(dictionary *d, int n)
- {
- int i;
- int foundsec;
- if (d == NULL || n < 0)
- return NULL;
- if (n == 0)
- n ++;
- foundsec = 0;
- for (i = 0; i < d->size; i++) {
- if (d->key[i] == NULL)
- continue;
- if (! strchr(d->key[i], ':')) {
- foundsec++;
- if (foundsec >= n)
- break;
- }
- }
- if (foundsec == n) {
- return d->key[i];
- }
- return (char *) NULL;
- }
- void ciniparser_dump(dictionary *d, FILE *f)
- {
- int i;
- if (d == NULL || f == NULL)
- return;
- for (i = 0; i < d->size; i++) {
- if (d->key[i] == NULL)
- continue;
- if (d->val[i] != NULL) {
- fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
- } else {
- fprintf(f, "[%s]=UNDEF\n", d->key[i]);
- }
- }
- return;
- }
- void ciniparser_dump_ini(dictionary *d, FILE *f)
- {
- int i, j;
- char keym[ASCIILINESZ+1];
- int nsec;
- char *secname;
- int seclen;
- if (d == NULL || f == NULL)
- return;
- memset(keym, 0, ASCIILINESZ + 1);
- nsec = ciniparser_getnsec(d);
- if (nsec < 1) {
- /* No section in file: dump all keys as they are */
- for (i = 0; i < d->size; i++) {
- if (d->key[i] == NULL)
- continue;
- fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
- }
- return;
- }
- for (i = 0; i < nsec; i++) {
- secname = ciniparser_getsecname(d, i);
- seclen = (int)strlen(secname);
- fprintf(f, "\n[%s]\n", secname);
- snprintf(keym, ASCIILINESZ + 1, "%s:", secname);
- for (j = 0; j < d->size; j++) {
- if (d->key[j] == NULL)
- continue;
- if (!strncmp(d->key[j], keym, seclen+1)) {
- fprintf(f, "%-30s = %s\n",
- d->key[j]+seclen+1,
- d->val[j] ? d->val[j] : "");
- }
- }
- }
- fprintf(f, "\n");
- return;
- }
- char *ciniparser_getstring(dictionary *d, const char *key, char *def)
- {
- char *lc_key;
- char *sval;
- if (d == NULL || key == NULL)
- return def;
- lc_key = strlwc(key);
- sval = dictionary_get(d, lc_key, def);
- return sval;
- }
- int ciniparser_getint(dictionary *d, const char *key, int notfound)
- {
- char *str;
- str = ciniparser_getstring(d, key, INI_INVALID_KEY);
- if (str == INI_INVALID_KEY)
- return notfound;
- return (int) strtol(str, NULL, 10);
- }
- double ciniparser_getdouble(dictionary *d, char *key, double notfound)
- {
- char *str;
- str = ciniparser_getstring(d, key, INI_INVALID_KEY);
- if (str == INI_INVALID_KEY)
- return notfound;
- return atof(str);
- }
- int ciniparser_getboolean(dictionary *d, const char *key, int notfound)
- {
- char *c;
- int ret;
- c = ciniparser_getstring(d, key, INI_INVALID_KEY);
- if (c == INI_INVALID_KEY)
- return notfound;
- switch(c[0]) {
- case 'y': case 'Y': case '1': case 't': case 'T':
- ret = 1;
- break;
- case 'n': case 'N': case '0': case 'f': case 'F':
- ret = 0;
- break;
- default:
- ret = notfound;
- break;
- }
- return ret;
- }
- int ciniparser_find_entry(dictionary *ini, char *entry)
- {
- int found = 0;
- if (ciniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) {
- found = 1;
- }
- return found;
- }
- int ciniparser_set(dictionary *d, char *entry, char *val)
- {
- return dictionary_set(d, strlwc(entry), val);
- }
- void ciniparser_unset(dictionary *ini, char *entry)
- {
- dictionary_unset(ini, strlwc(entry));
- }
- dictionary *ciniparser_load(const char *ininame)
- {
- FILE *in;
- char line[ASCIILINESZ+1];
- char section[ASCIILINESZ+1];
- char key[ASCIILINESZ+1];
- char tmp[ASCIILINESZ+1];
- char val[ASCIILINESZ+1];
- int last = 0, len, lineno = 0, errs = 0;
- dictionary *dict;
- if ((in = fopen(ininame, "r")) == NULL) {
- fprintf(stderr, "ciniparser: cannot open %s\n", ininame);
- return NULL;
- }
- dict = dictionary_new(0);
- if (!dict) {
- fclose(in);
- return NULL;
- }
- memset(line, 0, ASCIILINESZ + 1);
- memset(section, 0, ASCIILINESZ + 1);
- memset(key, 0, ASCIILINESZ + 1);
- memset(val, 0, ASCIILINESZ + 1);
- last = 0;
- while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
- lineno++;
- len = (int) strlen(line)-1;
- /* Safety check against buffer overflows */
- if (line[len] != '\n') {
- fprintf(stderr,
- "ciniparser: input line too long in %s (%d)\n",
- ininame,
- lineno);
- dictionary_del(dict);
- fclose(in);
- return NULL;
- }
- /* Get rid of \n and spaces at end of line */
- while ((len >= 0) &&
- ((line[len] == '\n') || (isspace(line[len])))) {
- line[len] = 0;
- len--;
- }
- /* Detect multi-line */
- if (len >= 0 && line[len] == '\\') {
- /* Multi-line value */
- last = len;
- continue;
- }
- switch (ciniparser_line(line, section, key, val)) {
- case LINE_EMPTY:
- case LINE_COMMENT:
- break;
- case LINE_SECTION:
- errs = dictionary_set(dict, section, NULL);
- break;
- case LINE_VALUE:
- snprintf(tmp, ASCIILINESZ + 1, "%s:%s", section, key);
- errs = dictionary_set(dict, tmp, val);
- break;
- case LINE_ERROR:
- fprintf(stderr, "ciniparser: syntax error in %s (%d):\n",
- ininame, lineno);
- fprintf(stderr, "-> %s\n", line);
- errs++;
- break;
- default:
- break;
- }
- memset(line, 0, ASCIILINESZ);
- last = 0;
- if (errs < 0) {
- fprintf(stderr, "ciniparser: memory allocation failure\n");
- break;
- }
- }
- if (errs) {
- dictionary_del(dict);
- dict = NULL;
- }
- fclose(in);
- return dict;
- }
- void ciniparser_freedict(dictionary *d)
- {
- dictionary_del(d);
- }
- /** @}
- */
|