From 67be743a10fdfe0d851b5591b707898495974d13 Mon Sep 17 00:00:00 2001 From: morixinguan Date: Fri, 5 Aug 2022 01:44:33 -0400 Subject: [PATCH] add ini Parse & ini Parse demo --- board/Linux_Posix/ini_demo/CMakeLists.txt | 44 + board/Linux_Posix/ini_demo/Makefile | 50 + board/Linux_Posix/ini_demo/inc/lwipopts.h | 236 ++++ board/Linux_Posix/ini_demo/inc/tos_config.h | 51 + board/Linux_Posix/ini_demo/readme.md | 36 + board/Linux_Posix/ini_demo/src/main.c | 170 +++ components/utils/INI/Makefile | 35 + components/utils/INI/include/dictionary.h | 207 ++++ components/utils/INI/include/iniparser.h | 348 ++++++ components/utils/INI/src/dictionary.c | 489 ++++++++ components/utils/INI/src/iniparser.c | 1141 +++++++++++++++++++ components/utils/Makefile | 5 +- 12 files changed, 2811 insertions(+), 1 deletion(-) create mode 100755 board/Linux_Posix/ini_demo/CMakeLists.txt create mode 100755 board/Linux_Posix/ini_demo/Makefile create mode 100755 board/Linux_Posix/ini_demo/inc/lwipopts.h create mode 100755 board/Linux_Posix/ini_demo/inc/tos_config.h create mode 100755 board/Linux_Posix/ini_demo/readme.md create mode 100755 board/Linux_Posix/ini_demo/src/main.c create mode 100755 components/utils/INI/Makefile create mode 100755 components/utils/INI/include/dictionary.h create mode 100755 components/utils/INI/include/iniparser.h create mode 100755 components/utils/INI/src/dictionary.c create mode 100755 components/utils/INI/src/iniparser.c mode change 100644 => 100755 components/utils/Makefile diff --git a/board/Linux_Posix/ini_demo/CMakeLists.txt b/board/Linux_Posix/ini_demo/CMakeLists.txt new file mode 100755 index 00000000..00225f52 --- /dev/null +++ b/board/Linux_Posix/ini_demo/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.8) + +project(ini_test) + +set(CMAKE_BUILD_TYPE "Debug") +set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb") +set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") + +set(TINY_ROOT ../../../) + +include_directories(${TINY_ROOT}/osal/cmsis_os) +include_directories(${TINY_ROOT}/kernel/core/include) +include_directories(${TINY_ROOT}/kernel/evtdrv/include) +include_directories(${TINY_ROOT}/kernel/hal/include) +include_directories(${TINY_ROOT}/kernel/pm/include) + +set(CMSIS_SRCS ${TINY_ROOT}/osal/cmsis_os/cmsis_os.c) +aux_source_directory(${TINY_ROOT}/kernel/core CORE_SRCS) +aux_source_directory(${TINY_ROOT}/kernel/evtdrv EVTDRV_SRCS) +aux_source_directory(${TINY_ROOT}/kernel/pm PM_SRCS) + +set(ARCH_ROOT ${TINY_ROOT}/arch/linux) + +include_directories(${ARCH_ROOT}/common/include) +include_directories(${ARCH_ROOT}/posix/gcc) +include_directories(${TINY_ROOT}/components/utils/INI/include) + +aux_source_directory(${ARCH_ROOT}/common ARCH_COMMON_SRCS) +aux_source_directory(${ARCH_ROOT}/posix/gcc ARCH_POSIX_SRCS) + +aux_source_directory(${TINY_ROOT}/components/utils/INI/src INI_SRCS) + +set(ARCH_SRCS ${ARCH_COMMON_SRCS} ${ARCH_POSIX_SRCS}) + +set(TINY_SRCS ${ARCH_SRCS} ${CMSIS_SRCS} ${EVTDRV_SRCS} ${PM_SRCS} ${CORE_SRCS} ${INI_SRCS} ) + +include_directories(./) +include_directories(./inc) + +set(APP_SRCS src/main.c) + +add_executable(inidemo ${APP_SRCS} ${TINY_SRCS}) + +target_link_libraries(inidemo pthread) \ No newline at end of file diff --git a/board/Linux_Posix/ini_demo/Makefile b/board/Linux_Posix/ini_demo/Makefile new file mode 100755 index 00000000..a8c4ff01 --- /dev/null +++ b/board/Linux_Posix/ini_demo/Makefile @@ -0,0 +1,50 @@ +################################################################### +#automatic detection QTOP and LOCALDIR +CUR_DIR := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))) +TRYQTOP := $(shell if [ -n "$$QTOP" ] ; then\ + echo $$QTOP;\ + else\ + cd $(CUR_DIR); while /usr/bin/test ! -e qmk ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find QTOP in $(firstword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) +QTOP ?= $(realpath ${TRYQTOP}) + +ifeq ($(QTOP),) +$(error Please run this in a tree) +endif +LOCALDIR = $(patsubst %/,%,$(subst $(realpath $(QTOP))/,,$(CUR_DIR))) +export QTOP + +#################################################################### + + +export BP=Linux_Posix + +TREE_LIB_ENABLE=1 +lib= +subdirs = + + +all:: + make -C ${QTOP}/arch BP=${BP} + make -C ${QTOP}/kernel BP=${BP} + make -C ${QTOP}/osal BP=${BP} + make -C ${QTOP}/net BP=${BP} + make -C ${QTOP}/devices BP=${BP} +exec = +LD_A_FILES += $(LIBDIR)/libarch.a +LD_A_FILES += $(LIBDIR)/libkernel.a +LD_A_FILES += $(LIBDIR)/libini_demo.a +LD_A_FILES += $(LIBDIR)/libcmsis_os.a +LDFLAGS += -lpthread + +include ${QTOP}/qmk/generic/Make.exec + + diff --git a/board/Linux_Posix/ini_demo/inc/lwipopts.h b/board/Linux_Posix/ini_demo/inc/lwipopts.h new file mode 100755 index 00000000..7e9e2522 --- /dev/null +++ b/board/Linux_Posix/ini_demo/inc/lwipopts.h @@ -0,0 +1,236 @@ +/** + ****************************************************************************** + * @file lwipopts.h + * @author MCD Application Team + * @version V1.1.0 + * @date 31-July-2013 + * @brief lwIP Options Configuration. + * This file is based on Utilities\lwip_v1.4.1\src\include\lwip\opt.h + * and contains the lwIP configuration for the STM32F4x7 demonstration. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#define NO_SYS 0 + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#define NO_SYS_NO_TIMERS 0 + +/* ---------- Memory options ---------- */ +/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which + lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 + byte alignment -> define MEM_ALIGNMENT to 2. */ +#define MEM_ALIGNMENT 4 + +/* MEM_SIZE: the size of the heap memory. If the application will send +a lot of data that needs to be copied, this should be set high. */ +#define MEM_SIZE (5 * 1024) + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#define MEMP_NUM_PBUF 25 +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#define MEMP_NUM_UDP_PCB 4 +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#define MEMP_NUM_TCP_PCB 6 +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#define MEMP_NUM_TCP_PCB_LISTEN 6 +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#define MEMP_NUM_TCP_SEG 150 +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#define MEMP_NUM_SYS_TIMEOUT 6 + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#define PBUF_POOL_SIZE 25 +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS + 40 + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN) + +/* ---------- TCP options ---------- */ +#define LWIP_TCP 1 +#define TCP_TTL 255 + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#define TCP_QUEUE_OOSEQ 0 + +/* TCP Maximum segment size. */ +#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */ + +/* TCP sender buffer space (bytes). */ +#define TCP_SND_BUF (7 * TCP_MSS) + +/* TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */ + +#define TCP_SND_QUEUELEN (8 * TCP_SND_BUF / TCP_MSS) + +/* TCP receive window. */ +#define TCP_WND (9 * TCP_MSS) + +/* ---------- ICMP options ---------- */ +#define LWIP_ICMP 1 + +/* ---------- DHCP options ---------- */ +/* Define LWIP_DHCP to 1 if you want DHCP configuration of + interfaces. DHCP is not implemented in lwIP 0.5.1, however, so + turning this on does currently not work. */ +#define LWIP_DHCP 1 + +/* ---------- UDP options ---------- */ +#define LWIP_UDP 1 +#define UDP_TTL 255 + +/* ---------- Statistics options ---------- */ +#define LWIP_STATS 0 +#define LWIP_PROVIDE_ERRNO 1 + +/* ---------- link callback options ---------- */ +/* LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#define LWIP_NETIF_LINK_CALLBACK 0 +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ + +/* +The STM32F4x7 allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware: + - To use this feature let the following define uncommented. + - To disable it and process by CPU comment the the checksum. +*/ +#define CHECKSUM_BY_HARDWARE +//#undef CHECKSUM_BY_HARDWARE + +#ifdef CHECKSUM_BY_HARDWARE +/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/ +#define CHECKSUM_GEN_IP 0 +/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/ +#define CHECKSUM_GEN_UDP 0 +/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/ +#define CHECKSUM_GEN_TCP 0 +/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/ +#define CHECKSUM_CHECK_IP 0 +/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/ +#define CHECKSUM_CHECK_UDP 0 +/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/ +#define CHECKSUM_CHECK_TCP 0 +/* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/ +#define CHECKSUM_GEN_ICMP 0 +#else +/* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/ +#define CHECKSUM_GEN_IP 1 +/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/ +#define CHECKSUM_GEN_UDP 1 +/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/ +#define CHECKSUM_GEN_TCP 1 +/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/ +#define CHECKSUM_CHECK_IP 1 +/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/ +#define CHECKSUM_CHECK_UDP 1 +/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/ +#define CHECKSUM_CHECK_TCP 1 +/* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/ +#define CHECKSUM_GEN_ICMP 1 +#endif + +#define LWIP_TCPIP_CORE_LOCKING 1 + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN 1 + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET 1 + +/* + --------------------------------- + ---------- OS options ---------- + --------------------------------- +*/ + +#define DEFAULT_UDP_RECVMBOX_SIZE 10 +#define DEFAULT_TCP_RECVMBOX_SIZE 10 +#define DEFAULT_ACCEPTMBOX_SIZE 10 +#define DEFAULT_THREAD_STACKSIZE 1024 * 2 + +#define TCPIP_THREAD_NAME "lwip" +#define TCPIP_THREAD_STACKSIZE 1024 +#define TCPIP_MBOX_SIZE 10 +#define TCPIP_THREAD_PRIO 1 + +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#define LWIP_DNS 1 + +/** DNS server IP address */ +#ifndef DNS_SERVER_ADDRESS +#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */ +#endif + +/* + ---------------------------------------- + ---------- Lwip Debug options ---------- + ---------------------------------------- +*/ +#define LWIP_DEBUG 0 + +#define ethernet_with_mac 1 + +#endif /* __LWIPOPTS_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/board/Linux_Posix/ini_demo/inc/tos_config.h b/board/Linux_Posix/ini_demo/inc/tos_config.h new file mode 100755 index 00000000..4c75d6e4 --- /dev/null +++ b/board/Linux_Posix/ini_demo/inc/tos_config.h @@ -0,0 +1,51 @@ +#ifndef _TOS_CONFIG_H_ +#define _TOS_CONFIG_H_ + +#include "stddef.h" +#include "stdint.h" + +#define TOS_CFG_TASK_PRIO_MAX 10u // 配置TencentOS tiny默认支持的最大优先级数量 + +#define TOS_CFG_ROUND_ROBIN_EN 1u // 配置TencentOS tiny的内核是否开启时间片轮转 + +#define TOS_CFG_OBJECT_VERIFY_EN 1u // 配置TencentOS tiny是否校验指针合法 + +#define TOS_CFG_EVENT_EN 1u // TencentOS tiny 事件模块功能宏 + +#define TOS_CFG_MMHEAP_EN 1u // 配置TencentOS tiny是否开启动态内存模块 + +#define TOS_CFG_MMHEAP_POOL_SIZE 0x100 // 配置TencentOS tiny动态内存池大小 + +#define TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE 0x100 // 配置TencentOS tiny动态内存池大小 + +#define TOS_CFG_MUTEX_EN 1u // 配置TencentOS tiny是否开启互斥锁模块 + +#define TOS_CFG_MESSAGE_QUEUE_EN 1u +#define TOS_CFG_MAIL_QUEUE_EN 1u + +#define TOS_CFG_PRIORITY_MESSAGE_QUEUE_EN 1u + +#define TOS_CFG_PRIORITY_MAIL_QUEUE_EN 1u +#define TOS_CFG_TIMER_EN 1u // 配置TencentOS tiny是否开启软件定时器模块 + +#define TOS_CFG_SEM_EN 1u // 配置TencentOS tiny是否开启信号量模块 + +#define TOS_CFG_MMBLK_EN 1u + +#if (TOS_CFG_QUEUE_EN > 0u) +#define TOS_CFG_MSG_EN 1u +#else +#define TOS_CFG_MSG_EN 0u +#endif + +#define TOS_CFG_MSG_POOL_SIZE 10u // 配置TencentOS tiny消息队列大小 + +#define TOS_CFG_IDLE_TASK_STK_SIZE 256u // 配置TencentOS tiny空闲任务栈大小 + +#define TOS_CFG_CPU_TICK_PER_SECOND 1000u // 配置TencentOS tiny的tick频率 + +#define TOS_CFG_CPU_CLOCK 1000000u // 配置TencentOS tiny CPU频率 + +#define TOS_CFG_TIMER_AS_PROC 1u // 配置是否将TIMER配置成函数模式 + +#endif diff --git a/board/Linux_Posix/ini_demo/readme.md b/board/Linux_Posix/ini_demo/readme.md new file mode 100755 index 00000000..a35c15da --- /dev/null +++ b/board/Linux_Posix/ini_demo/readme.md @@ -0,0 +1,36 @@ +# How to run the demo in linux + +## step1 +make sure your develop environment. ++ `cmake` and version greater than 3.8.2 ++ `gcc` `gdb` `make` is installed + +## step2 +make `build` directory and compile in `build` + +```bash +mkdir build && cd build +cmake .. +make +``` + +## step3 +run program !! + +```bash +# in build directory +./hello_world +``` + +## other +you can copy this demo to other path, but if you want do it, +you need modify `CMakeLists.txt`. find line + +```cmake +set(TINY_ROOT ../../../) +``` + +and modify `path-to-tinyos` +```cmake +set(TINY_ROOT path-to-tinyos) +``` diff --git a/board/Linux_Posix/ini_demo/src/main.c b/board/Linux_Posix/ini_demo/src/main.c new file mode 100755 index 00000000..3de0de9a --- /dev/null +++ b/board/Linux_Posix/ini_demo/src/main.c @@ -0,0 +1,170 @@ +#include "cmsis_os.h" +#include "iniparser.h" +#define CONFIG_NAME "Config.ini" + +struct DataInfo_t +{ + int InitData; + int VolumeData; + int LanguageVersion; +}; + +#define TASK1_STK_SIZE 512 +void task1(void *arg); +osThreadDef(task1, osPriorityNormal, 1, TASK1_STK_SIZE); + +void task1(void *arg) +{ + int Len = -1; + int Ret = -1; + char Buf[128]; + char *DataPtr = NULL; + struct DataInfo_t Data; + FILE *IniTest = NULL ; + FILE *DefaultIni = NULL; + dictionary *ConfigIni = NULL; + + /*1. Create ini config file*/ + IniTest = fopen(CONFIG_NAME, "w"); + if(NULL == IniTest) + { + printf("IniTest is Null!\n"); + return ; + } + + fprintf(IniTest, + "[Setting]\n" + "init_data=0;\n" + "volume_data=1;\n" + "language_version=1;\n" + ); + + Ret = fclose(IniTest); + if(Ret != 0) + { + printf("close IniTest fail!\n"); + return ; + } + + IniTest = NULL; + + IniTest = fopen(CONFIG_NAME, "r"); + if(NULL == IniTest) + { + printf("IniTest is Null!\n"); + return ; + } + + memset(Buf, 0, sizeof(Buf)); + while(fgets(Buf, sizeof(Buf), IniTest)) + { + printf("Buf: %s", Buf); + } + + fclose(IniTest); + IniTest = NULL; + + putchar('\n'); + + /*2. Test read ini config file data*/ + ConfigIni = iniparser_load(CONFIG_NAME); + if(NULL == ConfigIni) + { + printf("ConfigIni is NULL!\n"); + return ; + } + + //iniparser_dump(ConfigIni, stderr); + Data.InitData = iniparser_getint(ConfigIni,"Setting:init_data",-1); + if(-1 == Data.InitData) + { + printf("iniparser_getint fail!\n"); + return ; + } + Data.VolumeData = iniparser_getint(ConfigIni,"Setting:volume_data",-1); + if(-1 == Data.VolumeData) + { + printf("iniparser_getint fail!\n"); + return ; + } + Data.LanguageVersion = iniparser_getint(ConfigIni,"Setting:language_version",-1); + if(-1 == Data.LanguageVersion) + { + printf("iniparser_getint fail!\n"); + return ; + } + + printf("Data.InitData:%d\n", Data.InitData); + printf("Data.VolumeData:%d\n", Data.VolumeData); + printf("Data.LanguageVersion:%d\n", Data.LanguageVersion); + + /* 3. Set modify one of the parameters*/ + iniparser_set(ConfigIni,"Setting:init_data", "111"); + iniparser_set(ConfigIni,"Setting:volume_data", "222"); + iniparser_set(ConfigIni,"Setting:language_version", "333"); + + putchar('\n'); + + /*4. Write data to int config file*/ + DefaultIni = fopen(CONFIG_NAME, "w"); + if(NULL == DefaultIni) + { + printf("DefaultIni is NULL!\n"); + return ; + } + iniparser_dump_ini(ConfigIni, DefaultIni); + Ret = fclose(DefaultIni); + if(Ret != 0) + { + printf("close DefaultIni fail!\n"); + return ; + } + + /*5.Read the modified Config ini file data*/ + Data.InitData = iniparser_getint(ConfigIni, "Setting:init_data", -1); + if(-1 == Data.InitData) + { + printf("iniparser_getint fail!\n"); + return ; + } + Data.VolumeData = iniparser_getint(ConfigIni, "Setting:volume_data", -1); + if(-1 == Data.VolumeData) + { + printf("iniparser_getint fail!\n"); + return ; + } + Data.LanguageVersion = iniparser_getint(ConfigIni, "Setting:language_version", -1); + if(-1 == Data.LanguageVersion) + { + printf("iniparser_getint fail!\n"); + return ; + } + + printf("Data.InitData:%d\n", Data.InitData); + printf("Data.VolumeData:%d\n", Data.VolumeData); + printf("Data.LanguageVersion:%d\n", Data.LanguageVersion); + + iniparser_freedict(ConfigIni); + + while(1) + { + printf("Ini test success!\n"); + osDelay(1000); + } +} + +void application_entry(void *arg) +{ + osThreadCreate(osThread(task1), NULL); // Create task1 +} + +int main(void) +{ + osKernelInitialize(); //TOS Tiny kernel initialize + application_entry(NULL); + osKernelStart(); //Start TOS Tiny + + while (1) + { + } +} diff --git a/components/utils/INI/Makefile b/components/utils/INI/Makefile new file mode 100755 index 00000000..69305393 --- /dev/null +++ b/components/utils/INI/Makefile @@ -0,0 +1,35 @@ +################################################################### +#automatic detection QTOP and LOCALDIR +CUR_DIR := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))) +TRYQTOP := $(shell if [ -n "$$QTOP" ] ; then\ + echo $$QTOP;\ + else\ + cd $(CUR_DIR); while /usr/bin/test ! -d qmk ; do \ + dir=`cd ../;pwd`; \ + if [ "$$dir" = "/" ] ; then \ + echo Cannot find QTOP in $(firstword $(MAKEFILE_LIST)) 1>&2; \ + exit 1; \ + fi ; \ + cd $$dir; \ + done ; \ + pwd; \ + fi) +QTOP ?= $(realpath ${TRYQTOP}) + +ifeq ($(QTOP),) +$(error Please run this in a tree) +endif +LOCALDIR = $(patsubst %/,%,$(subst $(realpath $(QTOP))/,,$(CUR_DIR))) + +#################################################################### + + +TREE_LIB_ENABLE=y +lib= +subdirs= + +CFGFLAGS += -I$(CUR_DIR)/include + +include ${QTOP}/qmk/generic/Make.tpl + + diff --git a/components/utils/INI/include/dictionary.h b/components/utils/INI/include/dictionary.h new file mode 100755 index 00000000..0835865e --- /dev/null +++ b/components/utils/INI/include/dictionary.h @@ -0,0 +1,207 @@ +/* + Copyright (c) 2000-2011 by Nicolas Devillard. + 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. +*/ +/*-------------------------------------------------------------------------*/ +/** + @file dictionary.h + @author N. Devillard + @brief Implements a dictionary for string variables. + + This module implements a simple dictionary object, i.e. a list + of string/string associations. This object is useful to store e.g. + informations retrieved from a configuration file (ini files). +*/ +/*--------------------------------------------------------------------------*/ + +#ifndef DICTIONARY_H +#define DICTIONARY_H + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ + +#include +#include +#include +//#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + New types + ---------------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------------*/ +/** + @brief Dictionary object + + This object contains a list of string/string associations. Each + association is identified by a unique string key. Looking up values + in the dictionary is speeded up by the use of a (hopefully collision-free) + hash function. + */ +/*-------------------------------------------------------------------------*/ +typedef struct _dictionary_ +{ + int n ; /** Number of entries in dictionary */ + int size ; /** Storage size */ + char ** val ; /** List of string values */ + char ** key ; /** List of string keys */ + unsigned * hash ; /** List of hash values for keys */ +} dictionary ; + + +/*--------------------------------------------------------------------------- + Function prototypes + ---------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*/ +/** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ +/*--------------------------------------------------------------------------*/ +unsigned dictionary_hash(const char * key); + +/*-------------------------------------------------------------------------*/ +/** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary objet. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ +/*--------------------------------------------------------------------------*/ +dictionary * dictionary_new(size_t size); + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_del(dictionary * vd); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * dictionary_get(dictionary * d, const char * key, char * def); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ +/*--------------------------------------------------------------------------*/ +int dictionary_set(dictionary * vd, const char * key, const char * val); + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_unset(dictionary * d, const char * key); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_dump(dictionary * d, FILE * out); + +/*-------------------------------------------------------------------------*/ +/** + @brief Duplicate a string + @param s String to duplicate + @return Pointer to a newly allocated string, to be freed with free() + + This is a replacement for strdup(). This implementation is provided + for systems that do not have it. + */ +/*--------------------------------------------------------------------------*/ +char * xstrdup(const char * s); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/utils/INI/include/iniparser.h b/components/utils/INI/include/iniparser.h new file mode 100755 index 00000000..4c6a59c6 --- /dev/null +++ b/components/utils/INI/include/iniparser.h @@ -0,0 +1,348 @@ +/* + Copyright (c) 2000-2011 by Nicolas Devillard. + 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. +*/ +/*-------------------------------------------------------------------------*/ +/** + @file iniparser.h + @author N. Devillard + @brief Parser for ini files. +*/ +/*--------------------------------------------------------------------------*/ + +#ifndef INIPARSER_H +#define INIPARSER_H + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ + +#include +#include +#include + +#ifdef SUPPORT_FATFS +#include "fatfs.h" +#endif +/* + * The following #include is necessary on many Unixes but not Linux. + * It is not needed for Windows platforms. + * Uncomment it if needed. + */ +/* #include */ + +#include "dictionary.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*/ +/** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ +/*--------------------------------------------------------------------------*/ + +int iniparser_getnsec(dictionary * d); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ + +char * iniparser_getsecname(dictionary * d, int n); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +#ifdef SUPPORT_FATFS +void iniparser_dump_ini(dictionary * d, FIL * f); +#else +void iniparser_dump_ini(dictionary * d, FILE * f); +#endif + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary section to a loadable ini file + @param d Dictionary to dump + @param s Section name of dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given section of a given dictionary into a loadable ini + file. It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +#ifdef SUPPORT_FATFS +void iniparser_dumpsection_ini(dictionary * d, char * s, FIL *f); +#else +void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f); +#endif +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + @return void + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ +/*--------------------------------------------------------------------------*/ +#ifdef SUPPORT_FATFS +void iniparser_dump(dictionary * d, FIL *f); +#else +void iniparser_dump(dictionary * d, FILE * f); +#endif + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return Number of keys in section + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getsecnkeys(dictionary * d, char * s); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return pointer to statically allocated character strings + + This function queries a dictionary and finds all keys in a given section. + Each pointer in the returned char pointer-to-pointer is pointing to + a string allocated in the dictionary; do not free or modify them. + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ +char ** iniparser_getseckeys(dictionary * d, char * s); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * iniparser_getstring(dictionary * d, const char * key, char * def); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getint(dictionary * d, const char * key, int notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ +/*--------------------------------------------------------------------------*/ +double iniparser_getdouble(dictionary * d, const char * key, double notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getboolean(dictionary * d, const char * key, int notfound); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, -1 is returned. + It is Ok to set val to NULL. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_set(dictionary * ini, const char * entry, const char * val); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + @return void + + If the given entry can be found, it is deleted from the dictionary. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_unset(dictionary * ini, const char * entry); + +/*-------------------------------------------------------------------------*/ +/** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_find_entry(dictionary * ini, const char * entry) ; + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load(const char * ininame); + +/*-------------------------------------------------------------------------*/ +/** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + @return void + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_freedict(dictionary * d); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/utils/INI/src/dictionary.c b/components/utils/INI/src/dictionary.c new file mode 100755 index 00000000..86cea8ab --- /dev/null +++ b/components/utils/INI/src/dictionary.c @@ -0,0 +1,489 @@ +/* + Copyright (c) 2000-2011 by Nicolas Devillard. + 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. +*/ +/*-------------------------------------------------------------------------*/ +/** + @file dictionary.c + @author N. Devillard + @brief Implements a dictionary for string variables. + + This module implements a simple dictionary object, i.e. a list + of string/string associations. This object is useful to store e.g. + informations retrieved from a configuration file (ini files). +*/ +/*--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ +#include "dictionary.h" + +#include +#include +#include +//#include + +/** Maximum value size for integers and doubles. */ +#define MAXVALSZ 1024 + +/** Minimal allocated number of entries in a dictionary */ +#define DICTMINSZ 128 + +/** Invalid key token */ +#define DICT_INVALID_KEY ((char*)-1) + +/*--------------------------------------------------------------------------- + Private functions + ---------------------------------------------------------------------------*/ + +/* Doubles the allocated size associated to a pointer */ +/* 'size' is the current allocated size. */ +static void * mem_double(void * ptr, size_t size) +{ + void * newptr ; + + newptr = calloc(2 * size, 1); + + if (newptr == NULL) + { + return NULL ; + } + + memcpy(newptr, ptr, size); + free(ptr); + return newptr ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Duplicate a string + @param s String to duplicate + @return Pointer to a newly allocated string, to be freed with free() + + This is a replacement for strdup(). This implementation is provided + for systems that do not have it. + */ +/*--------------------------------------------------------------------------*/ +char * xstrdup(const char * s) +{ + char * t ; + size_t len ; + + if (!s) + return NULL ; + + len = strlen(s) + 1 ; + t = (char *)malloc(len) ; + + if (t) + { + memcpy(t, s, len) ; + } + + return t ; +} + +/*--------------------------------------------------------------------------- + Function codes + ---------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +/** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ +/*--------------------------------------------------------------------------*/ +unsigned dictionary_hash(const char * key) +{ + size_t len ; + unsigned hash ; + size_t i ; + + len = strlen(key); + + for (hash = 0, i = 0 ; i < len ; i++) + { + hash += (unsigned)key[i] ; + hash += (hash << 10); + hash ^= (hash >> 6) ; + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary objet. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ +/*--------------------------------------------------------------------------*/ +dictionary * dictionary_new(size_t size) +{ + dictionary * d ; + + /* If no size was specified, allocate space for DICTMINSZ */ + if (size < DICTMINSZ) size = DICTMINSZ ; + + d = (dictionary *)calloc(1, sizeof * d) ; + + if (d) + { + d->size = size ; + d->val = (char **)calloc(size, sizeof * d->val); + d->key = (char **)calloc(size, sizeof * d->key); + d->hash = (unsigned int *)calloc(size, sizeof * d->hash); + } + + return d ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_del(dictionary * d) +{ + int i ; + + if (d == NULL) return ; + + for (i = 0 ; i < d->size ; i++) + { + if (d->key[i] != NULL) + free(d->key[i]); + + if (d->val[i] != NULL) + free(d->val[i]); + } + + free(d->val); + free(d->key); + free(d->hash); + free(d); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * dictionary_get(dictionary * d, const char * key, char * def) +{ + unsigned hash ; + int i ; + + hash = dictionary_hash(key); + + for (i = 0 ; i < d->size ; i++) + { + if (d->key[i] == NULL) + continue ; + + /* Compare hash */ + if (hash == d->hash[i]) + { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) + { + return d->val[i] ; + } + } + } + + return def ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ +/*--------------------------------------------------------------------------*/ +int dictionary_set(dictionary * d, const char * key, const char * val) +{ + int i ; + unsigned hash ; + + if (d == NULL || key == NULL) return -1 ; + + /* Compute hash for this key */ + hash = dictionary_hash(key) ; + + /* Find if value is already in dictionary */ + if (d->n > 0) + { + for (i = 0 ; i < d->size ; i++) + { + if (d->key[i] == NULL) + continue ; + + if (hash == d->hash[i]) /* Same hash value */ + { + if (!strcmp(key, d->key[i])) /* Same key */ + { + /* Found a value: modify and return */ + if (d->val[i] != NULL) + free(d->val[i]); + + d->val[i] = val ? xstrdup(val) : NULL ; + /* Value has been modified: return */ + return 0 ; + } + } + } + } + + /* Add a new value */ + /* See if dictionary needs to grow */ + if (d->n == d->size) + { + + /* Reached maximum size: reallocate dictionary */ + d->val = (char **)mem_double(d->val, d->size * sizeof * d->val) ; + d->key = (char **)mem_double(d->key, d->size * sizeof * d->key) ; + d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof * d->hash) ; + + if ((d->val == NULL) || (d->key == NULL) || (d->hash == NULL)) + { + /* Cannot grow dictionary */ + return -1 ; + } + + /* Double size */ + d->size *= 2 ; + } + + /* Insert key in the first empty slot. Start at d->n and wrap at + d->size. Because d->n < d->size this will necessarily + terminate. */ + for (i = d->n ; d->key[i] ; ) + { + if(++i == d->size) i = 0; + } + + /* Copy key */ + d->key[i] = xstrdup(key); + d->val[i] = val ? xstrdup(val) : NULL ; + d->hash[i] = hash; + d->n ++ ; + return 0 ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_unset(dictionary * d, const char * key) +{ + unsigned hash ; + int i ; + + if (key == NULL) + { + return; + } + + hash = dictionary_hash(key); + + for (i = 0 ; i < d->size ; i++) + { + if (d->key[i] == NULL) + continue ; + + /* Compare hash */ + if (hash == d->hash[i]) + { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) + { + /* Found key */ + break ; + } + } + } + + if (i >= d->size) + /* Key not found */ + return ; + + free(d->key[i]); + d->key[i] = NULL ; + + if (d->val[i] != NULL) + { + free(d->val[i]); + d->val[i] = NULL ; + } + + d->hash[i] = 0 ; + d->n -- ; + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_dump(dictionary * d, FILE * out) +{ + int i ; + + if (d == NULL || out == NULL) return ; + + if (d->n < 1) + { + fprintf(out, "empty dictionary\n"); + return ; + } + + for (i = 0 ; i < d->size ; i++) + { + if (d->key[i]) + { + fprintf(out, "%20s\t[%s]\n", + d->key[i], + d->val[i] ? d->val[i] : "UNDEF"); + } + } + + return ; +} + + +/* Test code */ +#ifdef TESTDIC +#define NVALS 20000 +int main(int argc, char *argv[]) +{ + dictionary * d ; + char * val ; + int i ; + char cval[90] ; + + /* Allocate dictionary */ + printf("allocating...\n"); + d = dictionary_new(0); + + /* Set values in dictionary */ + printf("setting %d values...\n", NVALS); + + for (i = 0 ; i < NVALS ; i++) + { + sprintf(cval, "%04d", i); + dictionary_set(d, cval, "salut"); + } + + printf("getting %d values...\n", NVALS); + + for (i = 0 ; i < NVALS ; i++) + { + sprintf(cval, "%04d", i); + val = dictionary_get(d, cval, DICT_INVALID_KEY); + + if (val == DICT_INVALID_KEY) + { + printf("cannot get value for key [%s]\n", cval); + } + } + + printf("unsetting %d values...\n", NVALS); + + for (i = 0 ; i < NVALS ; i++) + { + sprintf(cval, "%04d", i); + dictionary_unset(d, cval); + } + + if (d->n != 0) + { + printf("error deleting values\n"); + } + + printf("deallocating...\n"); + dictionary_del(d); + return 0 ; +} +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/components/utils/INI/src/iniparser.c b/components/utils/INI/src/iniparser.c new file mode 100755 index 00000000..4dd8662e --- /dev/null +++ b/components/utils/INI/src/iniparser.c @@ -0,0 +1,1141 @@ +/* + Copyright (c) 2000-2011 by Nicolas Devillard. + 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. +*/ +/*-------------------------------------------------------------------------*/ +/** + @file iniparser.c + @author N. Devillard + @brief Parser for ini files. +*/ +/*--------------------------------------------------------------------------*/ +/*---------------------------- Includes ------------------------------------*/ +#include +#include "iniparser.h" + +/*---------------------------- Defines -------------------------------------*/ +#define ASCIILINESZ (100) +#define INI_INVALID_KEY ((char*)-1) + +/*--------------------------------------------------------------------------- + Private to this module + ---------------------------------------------------------------------------*/ +/** + * 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. + + This function modifies the string passed, the modified string + contains a lowercased version of the input string. + */ +/*--------------------------------------------------------------------------*/ + +static void strlwc(char * s) +{ + int i ; + + if (s == NULL) return; + + i = 0 ; + + while (s[i]) + { + s[i] = (char)tolower((int)s[i]); + i++ ; + } +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Remove blanks at the beginning and the end of a string. + @param s String to parse. + + This function modifies the input string and returns a modified 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. + */ +/*--------------------------------------------------------------------------*/ +static void strstrip(char * s) +{ + if (s == NULL) return ; + + char *last = s + strlen(s); + char *dest = s; + + while (isspace((int)*s) && *s) s++; + + while (last > s) + { + if (!isspace((int) * (last - 1))) + break ; + + last -- ; + } + + *last = (char)0; + + memmove(dest, s, last - s + 1); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_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 ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ +char * iniparser_getsecname(dictionary * d, int n) +{ + int i ; + int foundsec ; + + if (d == NULL || n < 0) return NULL ; + + foundsec = 0 ; + + for (i = 0 ; i < d->size ; i++) + { + if (d->key[i] == NULL) + continue ; + + if (strchr(d->key[i], ':') == NULL) + { + foundsec++ ; + + if (foundsec > n) + break ; + } + } + + if (foundsec <= n) + { + return NULL ; + } + + return d->key[i] ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + @return void + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ +/*--------------------------------------------------------------------------*/ +#ifdef SUPPORT_FATFS +void iniparser_dump(dictionary * d, FIL *f) +#else +void iniparser_dump(dictionary * d, FILE * f) +#endif +{ + 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) + { + #ifdef SUPPORT_FATFS + f_printf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); + #else + fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); + #endif + } + else + { + #ifdef SUPPORT_FATFS + f_printf(f, "[%s]=UNDEF\n", d->key[i]); + #else + fprintf(f, "[%s]=UNDEF\n", d->key[i]); + #endif + } + } + + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +#ifdef SUPPORT_FATFS +void iniparser_dump_ini(dictionary * d, FIL *f) +#else +void iniparser_dump_ini(dictionary * d, FILE *f) +#endif +{ + int i ; + int nsec ; + char * secname ; + + if (d == NULL || f == NULL) return ; + + nsec = iniparser_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 ; + + #ifdef SUPPORT_FATFS + f_printf(f, "%s = %s\n", d->key[i], d->val[i]); + #else + fprintf(f, "%s = %s\n", d->key[i], d->val[i]); + #endif + } + + return ; + } + + for (i = 0 ; i < nsec ; i++) + { + secname = iniparser_getsecname(d, i) ; + iniparser_dumpsection_ini(d, secname, f) ; + } + + #ifdef SUPPORT_FATFS + f_printf(f, "\n"); + #else + fprintf(f, "\n"); + #endif + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary section to a loadable ini file + @param d Dictionary to dump + @param s Section name of dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given section of a given dictionary into a loadable ini + file. It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +#ifdef SUPPORT_FATFS +void iniparser_dumpsection_ini(dictionary * d, char * s, FIL *f) +#else +void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f) +#endif +{ + int j ; + char *keym; + int secsize ; + + if (d == NULL || f == NULL) return ; + + if (! iniparser_find_entry(d, s)) return ; + + #ifdef SUPPORT_FATFS + f_printf(f, "\n[%s]\n", s); + #else + fprintf(f, "\n[%s]\n", s); + #endif + secsize = (int)strlen(s) + 2; + keym = (char *)malloc(secsize); + snprintf(keym, secsize, "%s:", s); + + for (j = 0 ; j < d->size ; j++) + { + if (d->key[j] == NULL) + continue ; + + if (!strncmp(d->key[j], keym, secsize - 1)) + { + #ifdef SUPPORT_FATFS + f_printf(f, + "%-30s = %s\n", + d->key[j] + secsize - 1, + d->val[j] ? d->val[j] : ""); + #else + fprintf(f, + "%-30s = %s\n", + d->key[j]+secsize-1, + d->val[j] ? d->val[j] : ""); + #endif + } + } + + #ifdef SUPPORT_FATFS + f_printf(f, "\n"); + #else + fprintf(f, "\n"); + #endif + + free(keym); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return Number of keys in section + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getsecnkeys(dictionary * d, char * s) +{ + int secsize, nkeys ; + char *keym; + int j ; + + nkeys = 0; + + if (d == NULL) return nkeys; + + if (! iniparser_find_entry(d, s)) return nkeys; + + secsize = (int)strlen(s) + 2; + keym = (char *)malloc(secsize); + snprintf(keym, secsize, "%s:", s); + + for (j = 0 ; j < d->size ; j++) + { + if (d->key[j] == NULL) + continue ; + + if (!strncmp(d->key[j], keym, secsize - 1)) + nkeys++; + } + + free(keym); + return nkeys; + +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return pointer to statically allocated character strings + + This function queries a dictionary and finds all keys in a given section. + Each pointer in the returned char pointer-to-pointer is pointing to + a string allocated in the dictionary; do not free or modify them. + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ +char ** iniparser_getseckeys(dictionary * d, char * s) +{ + + char **keys; + + int i, j ; + char *keym; + int secsize, nkeys ; + + keys = NULL; + + if (d == NULL) return keys; + + if (! iniparser_find_entry(d, s)) return keys; + + nkeys = iniparser_getsecnkeys(d, s); + + keys = (char**) malloc(nkeys * sizeof(char*)); + + secsize = (int)strlen(s) + 2; + keym = (char *)malloc(secsize); + snprintf(keym, secsize, "%s:", s); + + i = 0; + + for (j = 0 ; j < d->size ; j++) + { + if (d->key[j] == NULL) + continue ; + + if (!strncmp(d->key[j], keym, secsize - 1)) + { + keys[i] = d->key[j]; + i++; + } + } + + free(keym); + return keys; + +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * iniparser_getstring(dictionary * d, const char * key, char * def) +{ + char * lc_key ; + char * sval ; + + if (d == NULL || key == NULL) + return def ; + + lc_key = xstrdup(key); + strlwc(lc_key); + sval = dictionary_get(d, lc_key, def); + free(lc_key); + return sval ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + "42" -> 42 + "042" -> 34 (octal -> decimal) + "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getint(dictionary * d, const char * key, int notfound) +{ + char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + + if (str == INI_INVALID_KEY) return notfound ; + + return (int)strtol(str, NULL, 0); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ +/*--------------------------------------------------------------------------*/ +double iniparser_getdouble(dictionary * d, const char * key, double notfound) +{ + char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + + if (str == INI_INVALID_KEY) return notfound ; + + return atof(str); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getboolean(dictionary * d, const char * key, int notfound) +{ + char * c ; + int ret ; + + c = iniparser_getstring(d, key, INI_INVALID_KEY); + + if (c == INI_INVALID_KEY) return notfound ; + + if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T') + { + ret = 1 ; + } + else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f' || c[0] == 'F') + { + ret = 0 ; + } + else + { + ret = notfound ; + } + + return ret; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_find_entry( + dictionary * ini, + const char * entry +) +{ + int found = 0 ; + + if (iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) + { + found = 1 ; + } + + return found ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, -1 is returned. + It is Ok to set val to NULL. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_set(dictionary * ini, const char * entry, const char * val) +{ + int result = 0; + char *lc_entry = xstrdup(entry); + strlwc(lc_entry); + result = dictionary_set(ini, lc_entry, val) ; + free(lc_entry); + return result; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + @return void + + If the given entry can be found, it is deleted from the dictionary. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_unset(dictionary * ini, const char * entry) +{ + char* lc_entry = xstrdup(entry); + strlwc(lc_entry); + dictionary_unset(ini, lc_entry); + free(lc_entry); +} + +/*-------------------------------------------------------------------------*/ +/** + @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 iniparser_line( + int line_size, + const char * input_line, + char ** section_out, + char ** key_out, + char ** value_out) +{ + line_status sta ; + int len = line_size - 1; + char * line = (char *)malloc(line_size); + char * key = NULL; + char * value = NULL; + char * equals = NULL; + + if (!line) + { + fprintf(stderr, "iniparser: memory alloc error\n"); + return LINE_ERROR; + } + + *line = 0; + + + strcpy(line, input_line); + strstrip(line); + len = (int)strlen(line); + + /* only allocate necessary space for key & val */ + equals = strchr(line, '='); + + if (equals) + { + value = (char *)malloc((len + line) - equals + 1); + key = (char *)malloc(equals - line + 1); + *value = 0; + } + else + { + key = (char *)malloc(line_size + 1); + } + + if (!key || (equals && !value)) + { + fprintf(stderr, "iniparser: memory alloc error\n"); + sta = LINE_ERROR; + goto out; + } + + *key = 0; + + sta = LINE_UNPROCESSED ; + + if (len < 1) + { + /* Empty line */ + sta = LINE_EMPTY ; + } + else if (line[0] == '#' || line[0] == ';') + { + /* Comment line */ + sta = LINE_COMMENT ; + } + else if (line[0] == '[' && line[len - 1] == ']') + { + /* Section name */ + sscanf(line, "[%[^]]", key); + strstrip(key); + strlwc(key); + sta = LINE_SECTION ; + *section_out = key; + /* don't free key's memory */ + key = NULL; + } + else if (equals && (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 + || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 + || sscanf (line, "%[^=] = %[^;#]", key, value) == 2)) + { + /* Usual key=value, with or without comments */ + strstrip(key); + strlwc(key); + strstrip(value); + + /* + * sscanf cannot handle '' or "" as empty values + * this is done here + */ + if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) + { + value[0] = 0 ; + } + + *key_out = key; + *value_out = value; + key = NULL; + value = NULL; + sta = LINE_VALUE ; + } + else if (equals && (sscanf(line, "%[^=] = %[;#]", key, value) == 2 + || sscanf(line, "%[^=] %[=]", key, value) == 2)) + { + /* + * Special cases: + * key= + * key=; + * key=# + */ + strstrip(key); + strlwc(key); + value[0] = 0 ; + *key_out = key; + *value_out = value; + + /* don't free out params key or val's memory */ + key = NULL; + value = NULL; + sta = LINE_VALUE ; + } + else + { + /* Generate syntax error */ + sta = LINE_ERROR ; + } + +out: + + if (line) + { + free(line); + line = NULL; + } + + if (key) + { + free(key); + key = NULL; + } + + if (value) + { + free(value); + value = NULL; + } + + return sta ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load(const char * ininame) +{ + char line [ASCIILINESZ + 1] ; + char *section = xstrdup(""); + char *current_section = NULL; + char *key = NULL; + char *val = NULL; + char* full_line = NULL; + char* prev_line = NULL; + + int len ; + int lineno = 0 ; + int errs = 0; + int seckey_size = 0; + + #ifndef SUPPORT_FATFS + FILE * in = NULL ; + #endif + + dictionary * dict = NULL ; + + #ifdef SUPPORT_FATFS + retUSER_SYS_CONFIG = f_open(&USER_SYS_CONFIG_File, ininame, FA_OPEN_EXISTING | FA_READ); + if(FR_OK != retUSER_SYS_CONFIG) + { + fprintf(stderr, "iniparser: cannot open %s\n", ininame); + goto out ; + } + #else + + if ((in=fopen(ininame, "r"))==NULL) { + fprintf(stderr, "iniparser: cannot open %s\n", ininame); + goto out; + } + #endif + + dict = dictionary_new(0) ; + + if (!dict) + { + goto out; + } + + memset(line, 0, ASCIILINESZ); + + #ifdef SUPPORT_FATFS + while(f_gets(line, 100, &USER_SYS_CONFIG_File) != NULL) + #else + while (fgets(line, ASCIILINESZ, in)!=NULL) + #endif + { + int prev_line_len = 0; + int multi_line = 0; + int total_size = 0; + + if (key) + { + free(key); + key = NULL; + } + + if (val) + { + free(val); + val = NULL; + } + + lineno++ ; + len = (int)strlen(line) - 1; + + if (len == 0) + continue; + + /* Safety check against buffer overflows */ + #ifdef SUPPORT_FATFS + if (line[len] != '\n' && !f_eof(&USER_SYS_CONFIG_File)) + #else + if (line[len]!='\n' && !feof(in)) + #endif + { + + fprintf(stderr, + "iniparser: input line too long in %s (%d)\n", + ininame, + lineno); + errs++; + goto out; + } + + /* Get rid of \n and spaces at end of line */ + while ((len >= 0) && + ((line[len] == '\n') || (isspace(line[len])))) + { + line[len] = 0 ; + len-- ; + } + + if (len < 0) /* Line was entirely \n and/or spaces */ + { + len = 0; + } + + /* Detect multi-line */ + if (line[len] == '\\') + { + multi_line = 1; + } + + if (multi_line) + { + /* Multi-line value */ + /* length without trailing '\' */ + /* remove multi-line indicator before appending*/ + line[len] = 0; + len--; + } + + /* + * If processing a multi-line then append it the previous portion, + * at this point 'full_line' has the previously read portion of a + * multi-line line (or NULL) + */ + prev_line = full_line; + prev_line_len = 0; + + if (prev_line) + { + prev_line_len = strlen(prev_line); + } + + /* len is not strlen(line) but strlen(line) -1 */ + total_size = (len + 1) + prev_line_len + 1; + + full_line = (char *)malloc(total_size); + + if (!full_line) + { + fprintf(stderr, + "iniparser: out of mem\n"); + errs++; + goto out; + } + + memset(full_line, 0, total_size); + + if (prev_line) + { + strcpy(full_line, prev_line); + } + + strcpy(full_line + prev_line_len, line); + free(prev_line); + prev_line = NULL; + + if (multi_line) + { + continue ; + } + + switch (iniparser_line(total_size, full_line, ¤t_section, &key, &val)) + { + case LINE_EMPTY: + case LINE_COMMENT: + break ; + + case LINE_SECTION: + if (section) + { + free(section); + section = NULL; + } + + errs = dictionary_set(dict, current_section, NULL); + section = current_section; + break ; + + case LINE_VALUE: + { + char *seckey; + /* section + ':' + key + eos */ + seckey_size = strlen(section) + strlen(key) + 2; + seckey = (char *)malloc(seckey_size); + + if (!seckey) + { + errs++; + fprintf(stderr, + "iniparser: out of mem\n"); + goto out; + } + + snprintf(seckey, seckey_size, "%s:%s", section, key); + errs = dictionary_set(dict, seckey, val) ; + free(seckey); + seckey = NULL; + } + break ; + + case LINE_ERROR: + fprintf(stderr, "iniparser: syntax error in %s (%d):\n", + ininame, + lineno); + fprintf(stderr, "-> %s\n", full_line); + errs++ ; + break; + + default: + break ; + } + + memset(line, 0, ASCIILINESZ); + + if (full_line) + { + free(full_line); + full_line = NULL; + } + + if (errs < 0) + { + fprintf(stderr, "iniparser: memory allocation failure\n"); + break ; + } + } + +out: + + if (errs) + { + dictionary_del(dict); + dict = NULL ; + } + + if (val) + { + free(val); + val = NULL; + } + + if (key) + { + free(key); + key = NULL; + } + + if (section) + { + free(section); + section = NULL; + } + + if (full_line) + { + free(full_line); + full_line = NULL; + } + + if (prev_line) + { + free(prev_line); + prev_line = NULL; + } + + #ifdef SUPPORT_FATFS + f_close(&USER_SYS_CONFIG_File); + #else + if (in) + { + fclose(in); + in = NULL; + } + #endif + return dict ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + @return void + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_freedict(dictionary * d) +{ + dictionary_del(d); +} + +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/components/utils/Makefile b/components/utils/Makefile old mode 100644 new mode 100755 index 821b1c51..32d4f597 --- a/components/utils/Makefile +++ b/components/utils/Makefile @@ -24,10 +24,13 @@ LOCALDIR = $(patsubst %/,%,$(subst $(realpath $(QTOP))/,,$(CUR_DIR))) #################################################################### -TREE_LIB_ENABLE=0 +TREE_LIB_ENABLE=y lib= subdirs= +CFGFLAGS += -I$(QTOP)/components/utils/JSON/include +CFGFLAGS += -I$(QTOP)/components/utils/INI/include + include ${QTOP}/qmk/generic/Make.tpl