199 lines
5.8 KiB
C
199 lines
5.8 KiB
C
#ifndef _IINI_H_
|
|
#define _IINI_H_
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "sysenv.h"
|
|
#if _OS_WIN
|
|
#ifndef strcasecmp
|
|
#define strcasecmp _stricmp
|
|
#endif
|
|
#ifndef strncasecmp
|
|
#define strncasecmp _strnicmp
|
|
#endif
|
|
#elif _OS_LINUX
|
|
#include <strings.h>
|
|
#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 int ini_get_str(const INICHAR* filename, const INICHAR* section, const INICHAR* key,
|
|
const INICHAR* def_vaule, INICHAR* buf, size_t szbuf);
|
|
|
|
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 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_pptr == '"') {
|
|
if (*(*end_pptr + 1) == '"') {
|
|
*end_pptr += 1; /* skip "" (both quotes) */
|
|
}
|
|
else {
|
|
is_string = !is_string;/* single quote, toggle isstring */
|
|
}
|
|
}
|
|
else if (*(*end_pptr) == '\\' && *(*end_pptr + 1) == '"') {
|
|
*end_pptr += 1; /* skip \" (both quotes */
|
|
}
|
|
}
|
|
**end_pptr = ' ';
|
|
*end_pptr = _ini_skip_trailing(*end_pptr, *start_pptr);
|
|
**end_pptr = '\0';
|
|
|
|
/* Remove double quotes surrounding a value */
|
|
if (**start_pptr == '"' && *(*end_pptr - 1) == '"') {
|
|
*end_pptr -= 1;
|
|
*start_pptr += 1;
|
|
**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 _int_get_all_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 = -1;
|
|
|
|
if (fp = fopen(filename, "rb")) {
|
|
res = _int_get_all_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_ */ |