blob: dc733575dc741a4c12c4e30da0ca1863fbaec788 [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
haiyang.ren004fee82024-06-26 03:21:54 +000025#include "aml_malloc_debug.h"
Lei Qian7bf98232018-09-20 17:56:38 +080026#include "ini.h"
27
28#if !INI_USE_STACK
29#include <stdlib.h>
30#endif
31
32#define MAX_SECTION 50
33#define MAX_NAME 50
34
35/* Strip whitespace chars off end of given string, in place. Return s. */
36static char* rstrip(char* s) {
37 char* p = s + strlen(s);
38 while (p > s && isspace((unsigned char) (*--p)))
39 *p = '\0';
40 return s;
41}
42
43/* Return pointer to first non-whitespace char in given string. */
44static char* lskip(const char* s) {
45 while (*s && isspace((unsigned char) (*s)))
46 s++;
47 return (char*) s;
48}
49
50/* Return pointer to first char c or ';' comment in given string, or pointer to
51 null at end of string if neither found. ';' must be prefixed by a whitespace
52 character to register as a comment. */
53static char* find_char_or_comment(const char* s, char c) {
54 int was_whitespace = 0;
55 while (*s && *s != c && !(was_whitespace && *s == ';')) {
56 was_whitespace = isspace((unsigned char) (*s));
57 s++;
58 }
59 return (char*) s;
60}
61
62/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
63static char* strncpy0(char* dest, const char* src, size_t size) {
64 strncpy(dest, src, size);
65 dest[size - 1] = '\0';
66 return dest;
67}
68
69/* See documentation in header file. */
70int ini_parse_file(FILE* file,
71 int (*handler)(void*, const char*, const char*, const char*),
72 void* user) {
73 /* Uses a fair bit of stack (use heap instead if you need to) */
74#if INI_USE_STACK
75 char line[INI_MAX_LINE];
76#else
77 char* line;
78#endif
79 char section[MAX_SECTION] = "";
80 char prev_name[MAX_NAME] = "";
81
82 char* start;
83 char* end;
84 char* name;
85 char* value;
86 int lineno = 0;
87 int error = 0;
88
89#if !INI_USE_STACK
haiyang.ren004fee82024-06-26 03:21:54 +000090 line = (char*)aml_audio_malloc(INI_MAX_LINE);
Lei Qian7bf98232018-09-20 17:56:38 +080091 if (!line) {
92 return -2;
93 }
94#endif
95
96 /* Scan through file line by line */
97 while (fgets(line, INI_MAX_LINE, file) != NULL) {
98 lineno++;
99
100 start = line;
101#if INI_ALLOW_BOM
102 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
103 (unsigned char)start[1] == 0xBB &&
104 (unsigned char)start[2] == 0xBF) {
105 start += 3;
106 }
107#endif
108 start = lskip(rstrip(start));
109
110 if (*start == ';' || *start == '#') {
111 /* Per Python ConfigParser, allow '#' comments at start of line */
112 }
113 else if (*start == '[') {
114 /* A "[section]" line */
115 end = find_char_or_comment(start + 1, ']');
116 if (*end == ']') {
117 *end = '\0';
118 strncpy0(section, start + 1, sizeof(section));
119 *prev_name = '\0';
120 } else if (!error) {
121 /* No ']' found on section line */
122 error = lineno;
123 }
124 }
125#if INI_ALLOW_MULTILINE
126 else if (*prev_name && *start && (start > line || strstr(start, "=") == NULL)) {
127 /* Non-black line with leading whitespace, treat as continuation
128 of previous name's value (as per Python ConfigParser). */
129 if (!handler(user, section, prev_name, start) && !error)
130 error = lineno;
131 }
132#endif
133 else if (*start && *start != ';') {
134 /* Not a comment, must be a name[=:]value pair */
135 end = find_char_or_comment(start, '=');
136 if (*end != '=') {
137 end = find_char_or_comment(start, ':');
138 }
139 if (*end == '=' || *end == ':') {
140 *end = '\0';
141 name = rstrip(start);
142 value = lskip(end + 1);
143 end = find_char_or_comment(value, '\0');
144 if (*end == ';')
145 *end = '\0';
146 rstrip(value);
147
148 /* Valid name[=:]value pair found, call handler */
149 strncpy0(prev_name, name, sizeof(prev_name));
150 if (!handler(user, section, name, value) && !error)
151 error = lineno;
152 } else if (!error) {
153 /* No '=' or ':' found on name[=:]value line */
154 error = lineno;
155 }
156 }
157 }
158
159#if !INI_USE_STACK
haiyang.ren004fee82024-06-26 03:21:54 +0000160 aml_audio_free(line);
Lei Qian7bf98232018-09-20 17:56:38 +0800161#endif
162
163 return error;
164}
165
166int ini_parse_mem(const char* buf,
167 int (*handler)(void* user, const char* section, const char* name,
168 const char* value), void* user) {
169 char* bufptr = (char*) buf;
170
171 /* Uses a fair bit of stack (use heap instead if you need to) */
172#if INI_USE_STACK
173 char line[INI_MAX_LINE];
174#else
175 char* line;
176#endif
177 char section[MAX_SECTION] = "";
178 char prev_name[MAX_NAME] = "";
179
180 char* start;
181 char* end;
182 char* name;
183 char* value;
184 int lineno = 0;
185 int error = 0;
186
187#if !INI_USE_STACK
haiyang.ren004fee82024-06-26 03:21:54 +0000188 line = (char*)aml_audio_malloc(INI_MAX_LINE);
Lei Qian7bf98232018-09-20 17:56:38 +0800189 if (!line) {
190 return -2;
191 }
192#endif
193
194 while (1) {
195 int ncount = 0;
196 while (*bufptr != '\0') {
197 if (*bufptr == '\r' || *bufptr == '\n')
198 break;
199
200 line[ncount] = *bufptr++;
201 ncount++;
202 }
203 while (*bufptr == '\r' || *bufptr == '\n')
204 bufptr++;
205 line[ncount] = 0;
206
207 if (ncount == 0)
208 break;
209
210 /* Scan through file line by line */
211 //while (fgets(line, INI_MAX_LINE, file) != NULL) {
212 lineno++;
213
214 start = line;
215#if INI_ALLOW_BOM
216 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
217 (unsigned char)start[1] == 0xBB &&
218 (unsigned char)start[2] == 0xBF) {
219 start += 3;
220 }
221#endif
222 start = lskip(rstrip(start));
223
224 if (*start == ';' || *start == '#') {
225 /* Per Python ConfigParser, allow '#' comments at start of line */
226 }
227#if INI_ALLOW_MULTILINE
228 else if (*prev_name && *start && start > line) {
229 /* Non-black line with leading whitespace, treat as continuation
230 of previous name's value (as per Python ConfigParser). */
231 if (!handler(user, section, prev_name, start) && !error)
232 error = lineno;
233 }
234#endif
235 else if (*start == '[') {
236 /* A "[section]" line */
237 end = find_char_or_comment(start + 1, ']');
238 if (*end == ']') {
239 *end = '\0';
240 strncpy0(section, start + 1, sizeof(section));
241 *prev_name = '\0';
242 } else if (!error) {
243 /* No ']' found on section line */
244 error = lineno;
245 }
246 } else if (*start && *start != ';') {
247 /* Not a comment, must be a name[=:]value pair */
248 end = find_char_or_comment(start, '=');
249 if (*end != '=') {
250 end = find_char_or_comment(start, ':');
251 }
252 if (*end == '=' || *end == ':') {
253 *end = '\0';
254 name = rstrip(start);
255 value = lskip(end + 1);
256 end = find_char_or_comment(value, '\0');
257 if (*end == ';')
258 *end = '\0';
259 rstrip(value);
260
261 /* Valid name[=:]value pair found, call handler */
262 strncpy0(prev_name, name, sizeof(prev_name));
263 if (!handler(user, section, name, value) && !error)
264 error = lineno;
265 } else if (!error) {
266 /* No '=' or ':' found on name[=:]value line */
267 error = lineno;
268 }
269 }
270 }
271
272#if !INI_USE_STACK
haiyang.ren004fee82024-06-26 03:21:54 +0000273 aml_audio_free(line);
Lei Qian7bf98232018-09-20 17:56:38 +0800274#endif
275
276 return error;
277}
278
279/* See documentation in header file. */
280int ini_parse(const char* filename,
281 int (*handler)(void*, const char*, const char*, const char*),
282 void* user) {
283 FILE* file;
284 int error;
285
286 file = fopen(filename, "r");
287 if (!file)
288 return -1;
289 error = ini_parse_file(file, handler, user);
290 fclose(file);
291 return error;
292}