#ifndef _IINI_H_ #define _IINI_H_ #include #include #include #include "sysenv.h" #if _OS_WIN #define strcasecmp _stricmp #define strncasecmp _strnicmp #elif _OS_LINUX #include #else #error "Not Supported Operator System" #endif #ifndef INICHAR #define INICHAR char #endif #if !defined INI_BUFFER_SIZE #define INI_BUFFER_SIZE 512 #endif #ifdef __cplusplus extern "C" { #endif static inline INICHAR* _ini_skip_leading(const INICHAR* str) { assert(str != NULL); while ('\0' < *str && *str <= ' ') str++; return (INICHAR*)str; } static inline INICHAR* _ini_skip_trailing(const INICHAR* str, const INICHAR* base) { assert(str != NULL); assert(base != NULL); while (str > base && '\0' < *(str - 1) && *(str - 1) <= ' ') str--; return (INICHAR*)str; } static INICHAR* _ini_str_skip_trailing(INICHAR* str) { INICHAR* ptr = _ini_skip_trailing(strchr(str, '\0'), str); assert(ptr != NULL); *ptr = '\0'; return str; } //static TCHAR* cleanstring(TCHAR* string, enum quote_option* quotes) //{ // int isstring; // TCHAR* ep; // // assert(string != NULL); // assert(quotes != NULL); // // /* Remove a trailing comment */ // isstring = 0; // for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) { // if (*ep == '"') { // if (*(ep + 1) == '"') // ep++; /* skip "" (both quotes) */ // else // isstring = !isstring; /* single quote, toggle isstring */ // } // else if (*ep == '\\' && *(ep + 1) == '"') { // ep++; /* skip \" (both quotes */ // } // } // assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#')); // *ep = '\0'; /* terminate at a comment */ // striptrailing(string); // /* Remove double quotes surrounding a value */ // *quotes = QUOTE_NONE; // if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') { // string++; // *--ep = '\0'; // *quotes = QUOTE_DEQUOTE; /* this is a string, so remove escaped characters */ // } // return string; //} static void _ini_clean_string(INICHAR** start_pptr, INICHAR** end_pptr) { /* Remove a trailing comment */ int is_string = 0; *start_pptr = _ini_skip_leading(*end_pptr + 1); for (*end_pptr = *start_pptr; **end_pptr != '#' && **end_pptr != ';' && **end_pptr != '\0'; *end_pptr += 1) { //if(end) } **end_pptr = ' '; *end_pptr = _ini_skip_trailing(*end_pptr, *start_pptr); **end_pptr = '\0'; } static inline int _ini_str_get_section(INICHAR **start_pptr, INICHAR **end_pptr, INICHAR* buf, size_t szbuf) { *start_pptr = _ini_skip_leading(buf); *end_pptr = strchr(buf, ']'); if (**start_pptr != '[' || *end_pptr == NULL) { return -1; } /* When arrived here, a section was found; now optionally skip leading and * trailing whitespace. */ assert(*start_pptr != NULL && **start_pptr == '['); *start_pptr = _ini_skip_leading(*start_pptr + 1); assert(*end_pptr != NULL && **end_pptr == ']'); *end_pptr = _ini_skip_trailing(*end_pptr, *start_pptr); return 0; } static inline int _ini_str_get_key(INICHAR** start_pptr, INICHAR** end_pptr, INICHAR* buf, size_t szbuf) { *start_pptr = _ini_skip_leading(buf); if (**start_pptr == '[' || **start_pptr == '#' || **start_pptr == ':') return -1; *end_pptr = strchr(*start_pptr, '='); /* Parse out the equal sign */ if (*end_pptr == NULL) *end_pptr = strchr(*start_pptr, ':'); if (*end_pptr == NULL) return -1; return 0; } static int _get_key_string(FILE* fp, const INICHAR* section, const INICHAR* key, int idx_section, int idx_key, INICHAR* buf, size_t szbuf) { int len = 0, idx = 0; INICHAR* start_ptr, * end_ptr; INICHAR local_buf[INI_BUFFER_SIZE] = { 0 }; assert(fp != NULL); len = (section != NULL) ? (int)strlen(section) : 0; /* Move through file 1 line at a time until a section is matched or EOF. If * parameter Section is NULL, only look at keys above the first section. If * idxSection is positive, copy the relevant section name. */ if (len > 0 || idx_section >= 0) { assert(idx_section >= 0 || section != NULL); idx = -1; do { if (fgets(local_buf, INI_BUFFER_SIZE, fp) == NULL) return -1; if (_ini_str_get_section(&start_ptr, &end_ptr, local_buf, INI_BUFFER_SIZE) != 0) continue; } while (!((int)(end_ptr - start_ptr) == len && section != NULL && strncasecmp(start_ptr, section, len) == 0)); } /* Now that the section has been found, find the entry. * Stop searching upon leaving the section's area. */ assert(key != NULL || idx_key >= 0); len = (key != NULL) ? (int)strlen(key) : 0; idx = -1; do { if (fgets(local_buf, INI_BUFFER_SIZE, fp) == NULL) return -1; if (_ini_str_get_key(&start_ptr, &end_ptr, local_buf, INI_BUFFER_SIZE) != 0) continue; } while (len != 0 && strncasecmp(start_ptr, key, len) != 0); _ini_clean_string(&start_ptr, &end_ptr); /* Copy up to BufferSize chars to buffer */ strncpy(buf, start_ptr, szbuf); return 0; } static int ini_get_str(const INICHAR* filename, const INICHAR* section, const INICHAR* key, const INICHAR* def_vaule, INICHAR* buf, size_t szbuf) { FILE* fp = NULL; int res = 0; if (fp = fopen(filename, "rb")) { res = _get_key_string(fp, section, key, -1, -1, buf, szbuf); fclose(fp); } if (res != 0) { strncpy(buf, ((def_vaule == NULL) ? (const char*)"" : def_vaule), szbuf); buf[szbuf] = '\0'; } res = strlen(buf); return res; } #ifdef __cplusplus } #endif /* minIni - Multi-Platform INI file parser, suitable for embedded systems * * These routines are in part based on the article "Multiplatform .INI Files" * by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal. * * Copyright (c) CompuPhase, 2008-2021 * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * 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. * * Version: $Id: minIni.c 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $ */ #endif /* _IINI_H_ */