From 82e125d0ef5bc08e5e0bd12f792b133c849a094f Mon Sep 17 00:00:00 2001 From: batt Date: Mon, 8 Jun 2009 13:40:18 +0000 Subject: [PATCH] Add INI file reader module; update test harness. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@2709 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_ini_reader.h | 49 +++++++++++ bertos/mware/ini_reader.c | 152 +++++++++++++++++++++++++++++++++ bertos/mware/ini_reader.h | 67 +++++++++++++++ bertos/mware/ini_reader_test.c | 98 +++++++++++++++++++++ test/ini_reader_file.ini | 15 ++++ test/run_tests.sh | 5 +- 6 files changed, 384 insertions(+), 2 deletions(-) create mode 100644 bertos/cfg/cfg_ini_reader.h create mode 100644 bertos/mware/ini_reader.c create mode 100644 bertos/mware/ini_reader.h create mode 100644 bertos/mware/ini_reader_test.c create mode 100644 test/ini_reader_file.ini diff --git a/bertos/cfg/cfg_ini_reader.h b/bertos/cfg/cfg_ini_reader.h new file mode 100644 index 00000000..2d466f05 --- /dev/null +++ b/bertos/cfg/cfg_ini_reader.h @@ -0,0 +1,49 @@ +/** + * \file + * + * + * \brief Configuration file for ini reader module. + * + * \version $Id$ + * + * \author Luca Ottaviano + */ + +#ifndef CFG_INI_READER_H +#define CFG_INI_READER_H + +/** + * Maximum ini file line length (chars). + * $WIZ$ type = "int"; min = 1 + */ +#define CONFIG_INI_MAX_LINE_LEN 512 + +#endif /* CFG_INI_READER_H */ diff --git a/bertos/mware/ini_reader.c b/bertos/mware/ini_reader.c new file mode 100644 index 00000000..037570dc --- /dev/null +++ b/bertos/mware/ini_reader.c @@ -0,0 +1,152 @@ +/** + * \file + * + * + * \brief Ini file reader module. + * + * \version $Id$ + * \author Luca Ottaviano + */ + +#include "ini_reader.h" +#include "cfg/cfg_ini_reader.h" +#include +#include +#include + +/* + * Returns when the line containing the section is found. + * The file pointer is positioned at the start of the next line. + * Returns EOF if no section was found, 0 otherwise. + */ +static int findSection(KFile *fd, const char *section, char *line, size_t size) +{ + while (kfile_gets(fd, line, size) != EOF) + { + char *ptr = line; + unsigned i; + /* accept only sections that begin at first char */ + if (*ptr++ != '[') + continue; + /* find the end-of-section character */ + for (i = 0; i < size && *ptr != ']'; ++i, ++ptr) + ; + /* did we find the correct section? */ + if(strncmp(&line[1], section, i)) + continue; + else + return 0; + } + return EOF; +} + +/* + * Fills the argument with the key found in line + */ +static char *getKey(const char *line, char *key, size_t size) +{ + /* null-terminated string */ + while (isspace(*line)) + ++line; + int i = 0; + while (*line != '=' && !isspace(*line) && size) + { + key[i++] = *line; + ++line; + --size; + } + size ? (key[i] = '\0') : (key[i-1] = '\0'); + return key; +} + +/* + * Fills the argument with the value found in line. + */ +static char *getValue(const char *line, char *value, size_t size) +{ + while (*line++ != '=') + ; + while (isspace(*line)) + ++line; + int i = 0; + while (*line && size) + { + value[i++] = *line++; + --size; + } + size ? (value[i] = '\0') : (value[i-1] = '\0'); + return value; +} + +/** + * Look for key inside a section. + * + * The function reads lines from input file. It fills the line parameter to allow splitting + * the key-value couple. It returns with error if a new section begins and no key was found. + * \return 0 if key was found, EOF on errors. + */ +static int findKey(KFile *fd, const char *key, char *line, size_t size) +{ + while (kfile_gets(fd, line, size) != EOF && *line != '[') + { + char curr_key[30]; + getKey(line, curr_key, 30); + /* check key */ + if (!strcmp(curr_key, key)) + return 0; + } + return EOF; +} + +/* + * On errors, the function returns EOF and fills the buffer with the default value. + */ +int ini_getString(KFile *fd, const char *section, const char *key, const char *default_value, char *buf, size_t size) +{ + char line[CONFIG_INI_MAX_LINE_LEN]; + if (kfile_seek(fd, 0, KSM_SEEK_SET) == EOF) + goto error; + + if (findSection(fd, section, line, CONFIG_INI_MAX_LINE_LEN) == EOF) + goto error; + + if (findKey(fd, key, line, CONFIG_INI_MAX_LINE_LEN) == EOF) + goto error; + else + getValue(line, buf, size); + return 0; + +error: + strncpy(buf, default_value, size); + if (size > 0) + buf[size - 1] = '\0'; + return EOF; +} diff --git a/bertos/mware/ini_reader.h b/bertos/mware/ini_reader.h new file mode 100644 index 00000000..3e66028e --- /dev/null +++ b/bertos/mware/ini_reader.h @@ -0,0 +1,67 @@ +/** + * \file + * + * + * \brief Ini file reader module. + * + * The format accepted is: + * - Sections must begin at beginning of line. [ Long name ] will be found only if " Long name " is specified as section name. + * - key can contain any spaces at the beginning and before '=' but not in the middle. Eg. "long key name" is not valid. + * - values will be stripped of spaces at the beginning and will run until end-of-line. Eg. "= long value" will be treated as "long value". + * - no nested sections are allowed. + * - no comments are allowed inside a line with key=value pair. + * - every line that doesn't contain a '=' or doesn't start with '[' will be ignored. + * + * \version $Id$ + * \author Luca Ottaviano + */ + +#ifndef INI_READER_H +#define INI_READER_H + +#include + +/** + * \brief Returns the value for the given string in char* format. + * Reads the whole input file looking for section and key and fills the provided buffer with + * the corresponding value. + * On errors, the function fills the provided buffer with the default value and returns EOF. + * \param fd An initialized KFile structure. + * \param section The section to be looked for. + * \param key The key to search for. + * \param default_value The default value. + * \param buf The buffer to be filled. + * \param size The size of the provided buffer. + * \return 0 if section and key were found, EOF on errors. + */ +int ini_getString(KFile *fd, const char *section, const char *key, const char *default_value, char *buf, size_t size); + +#endif /* INI_READER_H */ diff --git a/bertos/mware/ini_reader_test.c b/bertos/mware/ini_reader_test.c new file mode 100644 index 00000000..495685eb --- /dev/null +++ b/bertos/mware/ini_reader_test.c @@ -0,0 +1,98 @@ +/** + * \file + * + * + * \brief Test function for ini_reader module. + * + * $test$: cp bertos/cfg/cfg_kfile.h $cfgdir/ + * $test$: echo "#undef CONFIG_KFILE_GETS" >> $cfgdir/cfg_kfile.h + * $test$: echo "#define CONFIG_KFILE_GETS 1" >> $cfgdir/cfg_kfile.h + * + * \version $Id$ + * \author Luca Ottaviano + */ + +#include +#include + +#include // strcmp + +#include "ini_reader.h" + +const char ini_file[] = "./test/ini_reader_file.ini"; +static KFilePosix kf; + +int ini_reader_testSetup(void) +{ + kdbg_init(); + if (!kfile_posix_init(&kf, ini_file, "r")) + { + kprintf("No test file found\n"); + return -1; + } + return 0; +} + +int ini_reader_testRun(void) +{ + char buf[30]; + memset(buf, 0, 30); + + ASSERT(ini_getString(&kf.fd, "First", "String", "default", buf, 30) != EOF); + ASSERT(strcmp(buf, "noot") == 0); + + ASSERT(ini_getString(&kf.fd, "Second", "Val", "default", buf, 30) != EOF); + ASSERT(strcmp(buf, "2") == 0); + + ASSERT(ini_getString(&kf.fd, "First", "Empty", "default", buf, 30) != EOF); + ASSERT(strcmp(buf, "") == 0); + + ASSERT(ini_getString(&kf.fd, "Second", "Bar", "default", buf, 30) == EOF); + ASSERT(strcmp(buf, "default") == 0); + + ASSERT(ini_getString(&kf.fd, "Foo", "Bar", "default", buf, 30) == EOF); + ASSERT(strcmp(buf, "default") == 0); + + ASSERT(ini_getString(&kf.fd, "Second", "Long key", "", buf, 30) == EOF); + + ASSERT(ini_getString(&kf.fd, "Second", "comment", "", buf, 30) != EOF); + ASSERT(strcmp(buf, "line with #comment") == 0); + + ASSERT(ini_getString(&kf.fd, "Long section with spaces", "value", "", buf, 30) != EOF); + ASSERT(strcmp(buf, "long value") == 0); + return 0; +} + +int ini_reader_testTearDown(void) +{ + return kfile_close(&kf.fd); +} + +TEST_MAIN(ini_reader); diff --git a/test/ini_reader_file.ini b/test/ini_reader_file.ini new file mode 100644 index 00000000..8837e105 --- /dev/null +++ b/test/ini_reader_file.ini @@ -0,0 +1,15 @@ +[First] +String=noot +Val=1 +Empty= +#comment + +[Second] +Val = 2 +String = mies +Long key = "long value" +comment = line with #comment +#comment=3 + +[Long section with spaces] +value = long value diff --git a/test/run_tests.sh b/test/run_tests.sh index 193b20c2..f7eb6465 100755 --- a/test/run_tests.sh +++ b/test/run_tests.sh @@ -17,7 +17,8 @@ VERBOSE=${VERBOSE:-1} CC=gcc #FIXME: -Ibertos/emul should not be needed -CFLAGS="-W -Wall -Wextra -O0 -g3 -ggdb -Ibertos -Ibertos/emul -std=gnu99 -fno-builtin -D_DEBUG -DARCH=(ARCH_EMUL|ARCH_UNITTEST) -DCPU_FREQ=(12288000UL)" +CFLAGS="-W -Wall -Wextra -O0 -g3 -ggdb -Ibertos -Ibertos/emul -std=gnu99 -fno-builtin -D_DEBUG -DARCH=(ARCH_EMUL|ARCH_UNITTEST) \ +-DCPU_FREQ=(12288000UL) -ffunction-sections -fdata-sections -Wl,--gc-sections" CXX=g++ CXXFLAGS="$CFLAGS" @@ -27,7 +28,7 @@ TESTS=${TESTS:-`find . \ -o -name "*_test.c" -print` } TESTOUT="testout" -SRC_LIST="bertos/algo/ramp.c bertos/drv/kdebug.c bertos/drv/timer.c bertos/fs/battfs.c bertos/kern/coop.c bertos/kern/idle.c bertos/kern/kfile.c bertos/kern/monitor.c bertos/kern/proc.c bertos/kern/signal.c bertos/kern/sem.c bertos/mware/event.c bertos/mware/formatwr.c bertos/mware/hex.c bertos/mware/sprintf.c bertos/os/hptime.c bertos/struct/kfile_fifo.c bertos/fs/fatfs/ff.c bertos/emul/diskio_emul.c bertos/fs/fat.c bertos/emul/switch_ctx_emul.S" +SRC_LIST="bertos/algo/ramp.c bertos/drv/kdebug.c bertos/drv/timer.c bertos/fs/battfs.c bertos/kern/coop.c bertos/kern/idle.c bertos/kern/kfile.c bertos/kern/monitor.c bertos/kern/proc.c bertos/kern/signal.c bertos/kern/sem.c bertos/mware/event.c bertos/mware/formatwr.c bertos/mware/hex.c bertos/mware/sprintf.c bertos/os/hptime.c bertos/struct/kfile_fifo.c bertos/fs/fatfs/ff.c bertos/emul/diskio_emul.c bertos/fs/fat.c bertos/emul/switch_ctx_emul.S bertos/mware/ini_reader.c bertos/emul/kfile_posix.c" buildout='/dev/null' runout='/dev/null' -- 2.25.1