blob: 03ea6b180ab0b60a52c00dafd5f696a64baa70b0 [file] [log] [blame]
Lei Qian7bf98232018-09-20 17:56:38 +08001/*
2 * Copyright (C) 2017 Amlogic Corporation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
dongyang.zhang967617d2024-01-05 01:23:24 +000016#define LOG_TAG "audio_hw_utils_ini"
Lei Qian7bf98232018-09-20 17:56:38 +080017
18#define _CRT_SECURE_NO_WARNINGS
19//#pragma warning (disable: 4127)
20
21#include <stdio.h>
22#include <ctype.h>
23#include <string.h>
24
25#include "ini.h"
26
27#if !INI_USE_STACK
28#include <stdlib.h>
29#endif
30
31#define MAX_SECTION 50
32#define MAX_NAME 50
33
34/* Strip whitespace chars off end of given string, in place. Return s. */
35static char* rstrip(char* s) {
36 char* p = s + strlen(s);
37 while (p > s && isspace((unsigned char) (*--p)))
38 *p = '\0';
39 return s;
40}
41
42/* Return pointer to first non-whitespace char in given string. */
43static char* lskip(const char* s) {
44 while (*s && isspace((unsigned char) (*s)))
45 s++;
46 return (char*) s;
47}
48
49/* Return pointer to first char c or ';' comment in given string, or pointer to
50 null at end of string if neither found. ';' must be prefixed by a whitespace
51 character to register as a comment. */
52static char* find_char_or_comment(const char* s, char c) {
53 int was_whitespace = 0;
54 while (*s && *s != c && !(was_whitespace && *s == ';')) {
55 was_whitespace = isspace((unsigned char) (*s));
56 s++;
57 }
58 return (char*) s;
59}
60
61/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
62static char* strncpy0(char* dest, const char* src, size_t size) {
63 strncpy(dest, src, size);
64 dest[size - 1] = '\0';
65 return dest;
66}
67
68/* See documentation in header file. */
69int ini_parse_file(FILE* file,
70 int (*handler)(void*, const char*, const char*, const char*),
71 void* user) {
72 /* Uses a fair bit of stack (use heap instead if you need to) */
73#if INI_USE_STACK
74 char line[INI_MAX_LINE];
75#else
76 char* line;
77#endif
78 char section[MAX_SECTION] = "";
79 char prev_name[MAX_NAME] = "";
80
81 char* start;
82 char* end;
83 char* name;
84 char* value;
85 int lineno = 0;
86 int error = 0;
87
88#if !INI_USE_STACK
89 line = (char*) malloc(INI_MAX_LINE);
90 if (!line) {
91 return -2;
92 }
93#endif
94
95 /* Scan through file line by line */
96 while (fgets(line, INI_MAX_LINE, file) != NULL) {
97 lineno++;
98
99 start = line;
100#if INI_ALLOW_BOM
101 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
102 (unsigned char)start[1] == 0xBB &&
103 (unsigned char)start[2] == 0xBF) {
104 start += 3;
105 }
106#endif
107 start = lskip(rstrip(start));
108
109 if (*start == ';' || *start == '#') {
110 /* Per Python ConfigParser, allow '#' comments at start of line */
111 }
112 else if (*start == '[') {
113 /* A "[section]" line */
114 end = find_char_or_comment(start + 1, ']');
115 if (*end == ']') {
116 *end = '\0';
117 strncpy0(section, start + 1, sizeof(section));
118 *prev_name = '\0';
119 } else if (!error) {
120 /* No ']' found on section line */
121 error = lineno;
122 }
123 }
124#if INI_ALLOW_MULTILINE
125 else if (*prev_name && *start && (start > line || strstr(start, "=") == NULL)) {
126 /* Non-black line with leading whitespace, treat as continuation
127 of previous name's value (as per Python ConfigParser). */
128 if (!handler(user, section, prev_name, start) && !error)
129 error = lineno;
130 }
131#endif
132 else if (*start && *start != ';') {
133 /* Not a comment, must be a name[=:]value pair */
134 end = find_char_or_comment(start, '=');
135 if (*end != '=') {
136 end = find_char_or_comment(start, ':');
137 }
138 if (*end == '=' || *end == ':') {
139 *end = '\0';
140 name = rstrip(start);
141 value = lskip(end + 1);
142 end = find_char_or_comment(value, '\0');
143 if (*end == ';')
144 *end = '\0';
145 rstrip(value);
146
147 /* Valid name[=:]value pair found, call handler */
148 strncpy0(prev_name, name, sizeof(prev_name));
149 if (!handler(user, section, name, value) && !error)
150 error = lineno;
151 } else if (!error) {
152 /* No '=' or ':' found on name[=:]value line */
153 error = lineno;
154 }
155 }
156 }
157
158#if !INI_USE_STACK
159 free(line);
160#endif
161
162 return error;
163}
164
165int ini_parse_mem(const char* buf,
166 int (*handler)(void* user, const char* section, const char* name,
167 const char* value), void* user) {
168 char* bufptr = (char*) buf;
169
170 /* Uses a fair bit of stack (use heap instead if you need to) */
171#if INI_USE_STACK
172 char line[INI_MAX_LINE];
173#else
174 char* line;
175#endif
176 char section[MAX_SECTION] = "";
177 char prev_name[MAX_NAME] = "";
178
179 char* start;
180 char* end;
181 char* name;
182 char* value;
183 int lineno = 0;
184 int error = 0;
185
186#if !INI_USE_STACK
187 line = (char*) malloc(INI_MAX_LINE);
188 if (!line) {
189 return -2;
190 }
191#endif
192
193 while (1) {
194 int ncount = 0;
195 while (*bufptr != '\0') {
196 if (*bufptr == '\r' || *bufptr == '\n')
197 break;
198
199 line[ncount] = *bufptr++;
200 ncount++;
201 }
202 while (*bufptr == '\r' || *bufptr == '\n')
203 bufptr++;
204 line[ncount] = 0;
205
206 if (ncount == 0)
207 break;
208
209 /* Scan through file line by line */
210 //while (fgets(line, INI_MAX_LINE, file) != NULL) {
211 lineno++;
212
213 start = line;
214#if INI_ALLOW_BOM
215 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
216 (unsigned char)start[1] == 0xBB &&
217 (unsigned char)start[2] == 0xBF) {
218 start += 3;
219 }
220#endif
221 start = lskip(rstrip(start));
222
223 if (*start == ';' || *start == '#') {
224 /* Per Python ConfigParser, allow '#' comments at start of line */
225 }
226#if INI_ALLOW_MULTILINE
227 else if (*prev_name && *start && start > line) {
228 /* Non-black line with leading whitespace, treat as continuation
229 of previous name's value (as per Python ConfigParser). */
230 if (!handler(user, section, prev_name, start) && !error)
231 error = lineno;
232 }
233#endif
234 else if (*start == '[') {
235 /* A "[section]" line */
236 end = find_char_or_comment(start + 1, ']');
237 if (*end == ']') {
238 *end = '\0';
239 strncpy0(section, start + 1, sizeof(section));
240 *prev_name = '\0';
241 } else if (!error) {
242 /* No ']' found on section line */
243 error = lineno;
244 }
245 } else if (*start && *start != ';') {
246 /* Not a comment, must be a name[=:]value pair */
247 end = find_char_or_comment(start, '=');
248 if (*end != '=') {
249 end = find_char_or_comment(start, ':');
250 }
251 if (*end == '=' || *end == ':') {
252 *end = '\0';
253 name = rstrip(start);
254 value = lskip(end + 1);
255 end = find_char_or_comment(value, '\0');
256 if (*end == ';')
257 *end = '\0';
258 rstrip(value);
259
260 /* Valid name[=:]value pair found, call handler */
261 strncpy0(prev_name, name, sizeof(prev_name));
262 if (!handler(user, section, name, value) && !error)
263 error = lineno;
264 } else if (!error) {
265 /* No '=' or ':' found on name[=:]value line */
266 error = lineno;
267 }
268 }
269 }
270
271#if !INI_USE_STACK
272 free(line);
273#endif
274
275 return error;
276}
277
278/* See documentation in header file. */
279int ini_parse(const char* filename,
280 int (*handler)(void*, const char*, const char*, const char*),
281 void* user) {
282 FILE* file;
283 int error;
284
285 file = fopen(filename, "r");
286 if (!file)
287 return -1;
288 error = ini_parse_file(file, handler, user);
289 fclose(file);
290 return error;
291}