From e1f5d37cf9712a021e77e13e6087f5568c583846 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 28 Jun 2023 16:03:07 +1000 Subject: [PATCH] Move parse_ini() into a separate include file. This makes it easy for it to be reused, or even take out into another package. Unlike the rest of edlib, it can be used under any popular open source license. Signed-off-by: NeilBrown --- Makefile | 2 + lib-config.c | 109 +------------------------------------------- parse-ini.h | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 107 deletions(-) create mode 100644 parse-ini.h diff --git a/Makefile b/Makefile index c927b30d..aac16c2f 100644 --- a/Makefile +++ b/Makefile @@ -145,6 +145,8 @@ edlib-static: $(OBJ) $(STATICOBJ) $(XOBJ) O/core-version.o $(OBJ) $(SHOBJ) $(LIBOBJ) $(XOBJ) $(STATICOBJ) : $(H) O/.exists $(LIBOBJ) : internal.h +O/lib-config.o : parse-ini.h + $(OBJ) : O/%.o : %.c $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC-$*) -c -o $@ $< $(QUIET_CHECK)sparse $(CPPFLAGS) $(INC-$*) $(SPARSEFLAGS) $< diff --git a/lib-config.c b/lib-config.c index 931b0a9c..f49fd448 100644 --- a/lib-config.c +++ b/lib-config.c @@ -6,126 +6,21 @@ * Sections: * global - set attr on editor * module - set trigger to load module - * file:pattern - set attributes when matching file visited - * (not implemented fully yet) + * file:glob - set attributes when matching file visited * * When not in a section, or in the "include" section, include= will * load another file. * - * Syntax for ini file - * - individual lines must not exceed 256 chars. Longer lines are - * silently truncated. - * - leading white space continues the previous line, this allowing large - * values. The newline and leading white space are stripped. - * - white space around "=", at EOL, and around section name in [section] - * is stripped - * - Double quotes at both ends of a value are stripped. - * - If first non-white is '#', line is ignored. - * - Everything after closing ']' of section is ignored - * - If value is no quoted, everything after first '#' is ignored - * - blank lines are ignored */ #include #include #include -#include -#include #include "core.h" +#include "parse-ini.h" -typedef void (*ini_handle)(void *data, char *section safe, - char *name safe, char *value safe, - const char *path safe, - int append); static void load_config(const char *path safe, void *data, const char *base); -static void parse_ini(const char *path safe, ini_handle handle, void *data) -{ - FILE *f = fopen(path, "r"); - char line[257]; - char section[257] = ""; - char name[257] = ""; - - if (!f) - return; - while (fgets(line, sizeof(line), f) != NULL) { - char *st, *eq; - char *eol = strchr(line, '\n'); - int append, quote; - - if (!eol) { - int ch; - while ((ch = fgetc(f)) != '\n' && - ch != EOF) - ; - } else - *eol = 0; - if (line[0] == '[') { - eol = strchr(line, ']'); - if (!eol) - continue; - while (eol > line && isblank(eol[-1])) - eol -= 1; - *eol = 0; - st = line+1; - while (isblank(*st)) - st += 1; - strcpy(section, st); - name[0] = 0; - continue; - } - /* find/strip comment */ - st = line; quote = 0; - while (*st && (quote || *st != '#')) { - if (*st == '"') - quote = !quote; - st += 1; - } - if (*st == '#') - *st = 0; - if (isblank(line[0])) { - if (!name[0]) - /* Nothing to continue */ - continue; - st = line; - while (isblank(*st)) - st += 1; - if (!*st) - /* Blank line */ - continue; - append = 1; - } else { - name[0] = 0; - /* There must be an '=' */ - eq = strchr(line, '='); - if (!eq) - continue; - st = eq + 1; - while (eq > line && isblank(eq[-1])) - eq -= 1; - *eq = 0; - if (!line[0]) - /* No name before '=' */ - continue; - strcpy(name, line); - append = 0; - } - /* A value is at 'st', to be set or appended */ - eol = st + strlen(st); - while (isblank(*st)) - st += 1; - while (eol > st && isblank(eol[-1])) - eol -= 1; - if (*st == '"' && eol > st + 1 && eol[-1] == '"') { - st += 1; - eol -= 1; - } - *eol = 0; - handle(data, section, name, st, path, append); - } - fclose(f); -} - static bool __glob_match(const char *patn safe, const char *path safe) { while(1) { diff --git a/parse-ini.h b/parse-ini.h new file mode 100644 index 00000000..3b14a28f --- /dev/null +++ b/parse-ini.h @@ -0,0 +1,125 @@ +/* + * Copyright Neil Brown ©2023 + * May be distributed under terms of GPLv2 - or indeed any + * "Popular / Strong Community" license approved by the Open Source Initiative + * https://opensource.org/licenses/?categories=popular-strong-community + * + * Parse an 'ini' file calling a call-back for each value found. + * + * Syntax for ini file + * - individual lines must not exceed 256 chars. Longer lines are + * silently truncated. + * - leading white space continues the previous line, this allowing large + * values. The newline and leading white space are stripped. + * Each line is provided separately to the callback, so precise detail of + * how continuation lines are merged are left up to that callback. + * - white space around "=", at EOL, and around section name in [section] + * is stripped + * - Double quotes at both ends of a value are stripped. This allows + * white space at either end of a value. + * - If first non-white is '#', line is ignored. + * - Everything after closing ']' of section is ignored + * - If value is not quoted, everything after first '#' is ignored + * - blank lines are ignored + */ +#include +#include +#include + +#ifndef safe +/* "safe" pointers can never be NULL */ +#define safe +#endif + +typedef void (*ini_handle)(void *data, char *section safe, + char *name safe, char *value safe, + const char *path safe, + int append); + +static inline void parse_ini(const char *path safe, + ini_handle handle, void *data) +{ + FILE *f = fopen(path, "r"); + char line[257]; + char section[257] = ""; + char name[257] = ""; + + if (!f) + return; + while (fgets(line, sizeof(line), f) != NULL) { + char *st, *eq; + char *eol = strchr(line, '\n'); + int append, quote; + + if (!eol) { + int ch; + while ((ch = fgetc(f)) != '\n' && + ch != EOF) + ; + } else + *eol = 0; + if (line[0] == '[') { + eol = strchr(line, ']'); + if (!eol) + continue; + while (eol > line && isblank(eol[-1])) + eol -= 1; + *eol = 0; + st = line+1; + while (isblank(*st)) + st += 1; + strcpy(section, st); + name[0] = 0; + continue; + } + /* find/strip comment */ + st = line; quote = 0; + while (*st && (quote || *st != '#')) { + if (*st == '"') + quote = !quote; + st += 1; + } + if (*st == '#') + *st = 0; + if (isblank(line[0])) { + if (!name[0]) + /* Nothing to continue */ + continue; + st = line; + while (isblank(*st)) + st += 1; + if (!*st) + /* Blank line */ + continue; + append = 1; + } else { + name[0] = 0; + /* There must be an '=' */ + eq = strchr(line, '='); + if (!eq) + continue; + st = eq + 1; + while (eq > line && isblank(eq[-1])) + eq -= 1; + *eq = 0; + if (!line[0]) + /* No name before '=' */ + continue; + strcpy(name, line); + append = 0; + } + /* A value is at 'st', to be set or appended */ + eol = st + strlen(st); + while (isblank(*st)) + st += 1; + while (eol > st && isblank(eol[-1])) + eol -= 1; + if (*st == '"' && eol > st + 1 && eol[-1] == '"') { + st += 1; + eol -= 1; + } + *eol = 0; + handle(data, section, name, st, path, append); + } + fclose(f); +} -- 2.39.5