clib/include/iini.h
2023-11-01 14:14:32 +08:00

188 lines
5.6 KiB
C

#ifndef _IINI_H_
#define _IINI_H_
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "sysenv.h"
#if _OS_WIN
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#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 inline INICHAR* _skip_leading(const INICHAR* str)
{
assert(str != NULL);
while ('\0' < *str && *str <= ' ')
str++;
return (INICHAR*)str;
}
static inline INICHAR* _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* _strip_trailing(INICHAR* str)
{
INICHAR* ptr = _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 inline int _
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 {
do {
if (fgets(local_buf, INI_BUFFER_SIZE, fp) == NULL) return 0;
start_ptr = _skip_leading(local_buf);
end_ptr = strchr(local_buf, ']');
} while (*start_ptr != '[' || end_ptr == NULL);
/* When arrived here, a section was found; now optionally skip leading and
* trailing whitespace.
*/
assert(start_ptr != NULL && *start_ptr == '[');
start_ptr = _skip_leading(start_ptr + 1);
assert(end_ptr != NULL && *end_ptr == ']');
end_ptr = _skip_trailing(end_ptr, start_ptr);
} 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) || *(start_ptr = _skip_leading(local_buf)) == '[')
return 0;
start_ptr = _skip_leading(local_buf);
end_ptr = strchr(start_ptr, '='); /* Parse out the equal sign */
if (end_ptr == NULL)
end_ptr = strchr(start_ptr, ':');
} while (*start_ptr != ';' && *start_ptr != '#' && end_ptr != NULL &&
(!(len != 0 && (int)(_skip_trailing(end_ptr, start_ptr) - start_ptr) == len && strncasecmp(start_ptr, key, len) == 0)));
//&& ++idx != idx_section) );
/* Copy up to BufferSize chars to buffer */
assert(end_ptr != NULL);
assert(*end_ptr == '=' || *end_ptr == ':');
start_ptr = _skip_leading(end_ptr + 1);
//sp = cleanstring(sp, &quotes); /* Remove a trailing comment */
strncpy(buf, start_ptr, szbuf);
return 1;
}
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);
(void)fclose(fp);
}
if (!res) {
strncpy(buf, ((def_vaule == NULL) ? (const char*)"" : def_vaule), szbuf);
}
return strlen(buf);
}
#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_ */