0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
0011 #define _CRT_SECURE_NO_WARNINGS
0012 #endif
0013
0014 #include <stdio.h>
0015 #include <ctype.h>
0016 #include <string.h>
0017 #include <ndebug.h>
0018 #include <ndrstandard.h>
0019
0020 #include "ndrx_ini.h"
0021 #include "userlog.h"
0022
0023 #if !INI_USE_STACK
0024 #include <stdlib.h>
0025 #endif
0026
0027 #define MAX_SECTION 50
0028 #define MAX_NAME 50
0029
0030
0031 static char* rstrip(char* s)
0032 {
0033 char* p = s + strlen(s);
0034 while (p > s && isspace((unsigned char)(*--p)))
0035 *p = '\0';
0036 return s;
0037 }
0038
0039
0040 static char* lskip(const char* s)
0041 {
0042 while (*s && isspace((unsigned char)(*s)))
0043 s++;
0044 return (char*)s;
0045 }
0046
0047
0048
0049
0050 static char* find_chars_or_comment(const char* s, const char* chars)
0051 {
0052 #if INI_ALLOW_INLINE_COMMENTS
0053 int was_space = 0;
0054 while (*s && (!chars || !strchr(chars, *s)) &&
0055 !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
0056 was_space = isspace((unsigned char)(*s));
0057 s++;
0058 }
0059 #else
0060 while (*s && (!chars || !strchr(chars, *s))) {
0061 s++;
0062 }
0063 #endif
0064 return (char*)s;
0065 }
0066
0067
0068 static char* strncpy0(char* dest, const char* src, size_t size)
0069 {
0070 NDRX_STRCPY_SAFE_DST(dest, src, size);
0071
0072 return dest;
0073 }
0074
0075
0076
0077
0078
0079 int ndrx_ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
0080 void* user, void *user2, void *user3)
0081 {
0082
0083 #if INI_USE_STACK
0084 char tmp_line[INI_MAX_LINE];
0085 char tmp_line2[INI_MAX_LINE];
0086 #endif
0087 char section[MAX_SECTION] = "";
0088 char prev_name[MAX_NAME] = "";
0089
0090 char* start;
0091 char* end;
0092 char* name;
0093 char* value;
0094 int lineno = 0;
0095 int error = 0;
0096
0097 char *line;
0098 char *line2;
0099
0100
0101 #if !INI_USE_STACK
0102 line = (char*)NDRX_MALLOC(INI_MAX_LINE);
0103 if (!line) {
0104 return -2;
0105 }
0106
0107 line2 = (char*)NDRX_MALLOC(INI_MAX_LINE);
0108 if (!line2) {
0109 return -2;
0110 }
0111 #else
0112 line = tmp_line;
0113 line2 = tmp_line2;
0114 #endif
0115
0116
0117 while (reader(line, INI_MAX_LINE, stream) != NULL) {
0118 lineno++;
0119
0120 start = line;
0121
0122 #if INI_ALLOW_BOM
0123 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
0124 (unsigned char)start[1] == 0xBB &&
0125 (unsigned char)start[2] == 0xBF) {
0126 start += 3;
0127 }
0128 #endif
0129 start = lskip(rstrip(start));
0130
0131 line_buffered:
0132 if (*start == ';' || *start == '#') {
0133
0134
0135 }
0136 #if INI_ALLOW_MULTILINE
0137 else if (*prev_name && *start && start > line) {
0138
0139
0140 if (!handler(user, user2, user3, section, prev_name, start) && !error)
0141 error = lineno;
0142 }
0143 #endif
0144 else if (*start == '[') {
0145
0146 end = find_chars_or_comment(start + 1, "]");
0147 if (*end == ']') {
0148 *end = '\0';
0149 strncpy0(section, start + 1, sizeof(section));
0150 *prev_name = '\0';
0151 }
0152 else if (!error) {
0153
0154 error = lineno;
0155 }
0156 }
0157 else if (*start) {
0158
0159 end = find_chars_or_comment(start, "=:");
0160 if (*end == '=' || *end == ':') {
0161 *end = '\0';
0162 name = rstrip(start);
0163 value = lskip(end + 1);
0164 #if INI_ALLOW_INLINE_COMMENTS
0165 end = find_chars_or_comment(value, NULL);
0166 if (*end)
0167 *end = '\0';
0168 #endif
0169 rstrip(value);
0170
0171
0172 strncpy0(prev_name, name, sizeof(prev_name));
0173
0174 #if INI_ALLOW_MULTILINE
0175
0176
0177
0178
0179 while (reader(line2, INI_MAX_LINE, stream) != NULL)
0180 {
0181 lineno++;
0182
0183 start = line2;
0184 start = lskip(rstrip(start));
0185
0186 if (*start == ';' || *start == '#') {
0187
0188
0189 continue;
0190 }
0191 else if (*start && start > line2) {
0192 int free_space_in_value;
0193 int additional_value_len;
0194
0195 rstrip(start);
0196 #if INI_ALLOW_INLINE_COMMENTS
0197 end = find_chars_or_comment(start, NULL);
0198 if (*end)
0199 *end = '\0';
0200 #endif
0201
0202 free_space_in_value = INI_MAX_LINE - ((value+strlen(value)) - line);
0203 additional_value_len = strlen(start);
0204
0205 if (free_space_in_value < additional_value_len)
0206 {
0207 userlog("Failed to parse config - value too large,"
0208 "config param: %s (limit:%d) runs over by: %d",
0209 name, INI_MAX_LINE, additional_value_len,
0210 free_space_in_value);
0211 error = lineno;
0212 }
0213 else
0214 {
0215 strcat(value, start);
0216 }
0217 }
0218 else
0219 {
0220
0221 if (!handler(user, user2, user3, section, name, value) && !error)
0222 {
0223 error = lineno;
0224 }
0225 else
0226 {
0227
0228
0229
0230 char *p;
0231
0232 p = line;
0233 line = line2;
0234 line2 = p;
0235
0236 goto line_buffered;
0237 }
0238 }
0239 }
0240
0241
0242 if (!handler(user, user2, user3, section, name, value) && !error)
0243 {
0244 error = lineno;
0245 }
0246
0247 #else
0248 if (!handler(user, user2, user3, section, name, value) && !error)
0249 error = lineno;
0250 #endif
0251
0252
0253 }
0254 else if (!error) {
0255
0256 error = lineno;
0257 }
0258 }
0259
0260 #if INI_STOP_ON_FIRST_ERROR
0261 if (error)
0262 break;
0263 #endif
0264 }
0265
0266 #if !INI_USE_STACK
0267 NDRX_FREE(line);
0268 NDRX_FREE(line2);
0269 #endif
0270
0271 return error;
0272 }
0273
0274
0275 int ndrx_ini_parse_file(FILE* file, ini_handler handler, void* user, void *user2,
0276 void *user3)
0277 {
0278 return ndrx_ini_parse_stream((ini_reader)fgets, file, handler, user, user2, user3);
0279 }
0280
0281
0282 int ndrx_ini_parse(const char* filename, ini_handler handler, void* user,
0283 void *user2, void *user3)
0284 {
0285 FILE* file;
0286 int error;
0287
0288 file = NDRX_FOPEN(filename, "r");
0289 if (!file)
0290 return -1;
0291 error = ndrx_ini_parse_file(file, handler, user, user2, user3);
0292 NDRX_FCLOSE(file);
0293 return error;
0294 }