1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <common.h>
15#include <command.h>
16#include <env.h>
17#include <linux/ctype.h>
18#include <linux/string.h>
19
20#ifdef CONFIG_INI_MAX_LINE
21#define MAX_LINE CONFIG_INI_MAX_LINE
22#else
23#define MAX_LINE 200
24#endif
25
26#ifdef CONFIG_INI_MAX_SECTION
27#define MAX_SECTION CONFIG_INI_MAX_SECTION
28#else
29#define MAX_SECTION 50
30#endif
31
32#ifdef CONFIG_INI_MAX_NAME
33#define MAX_NAME CONFIG_INI_MAX_NAME
34#else
35#define MAX_NAME 50
36#endif
37
38
39static char *rstrip(char *s)
40{
41 char *p = s + strlen(s);
42
43 while (p > s && isspace(*--p))
44 *p = '\0';
45 return s;
46}
47
48
49static char *lskip(const char *s)
50{
51 while (*s && isspace(*s))
52 s++;
53 return (char *)s;
54}
55
56
57
58
59static char *find_char_or_comment(const char *s, char c)
60{
61 int was_whitespace = 0;
62
63 while (*s && *s != c && !(was_whitespace && *s == ';')) {
64 was_whitespace = isspace(*s);
65 s++;
66 }
67 return (char *)s;
68}
69
70
71static char *strncpy0(char *dest, const char *src, size_t size)
72{
73 strncpy(dest, src, size);
74 dest[size - 1] = '\0';
75 return dest;
76}
77
78
79static char *memgets(char *str, int num, char **mem, size_t *memsize)
80{
81 char *end;
82 int len;
83 int newline = 1;
84
85 end = memchr(*mem, '\n', *memsize);
86 if (end == NULL) {
87 if (*memsize == 0)
88 return NULL;
89 end = *mem + *memsize;
90 newline = 0;
91 }
92 len = min((end - *mem) + newline, num);
93 memcpy(str, *mem, len);
94 if (len < num)
95 str[len] = '\0';
96
97
98 *memsize -= (end - *mem) + newline;
99 *mem += (end - *mem) + newline;
100
101 return str;
102}
103
104
105
106
107
108
109
110
111
112
113
114
115
116static int ini_parse(char *filestart, size_t filelen,
117 int (*handler)(void *, char *, char *, char *), void *user)
118{
119
120 char line[MAX_LINE];
121 char section[MAX_SECTION] = "";
122 char prev_name[MAX_NAME] = "";
123
124 char *curmem = filestart;
125 char *start;
126 char *end;
127 char *name;
128 char *value;
129 size_t memleft = filelen;
130 int lineno = 0;
131 int error = 0;
132
133
134 while (memgets(line, sizeof(line), &curmem, &memleft) != NULL) {
135 lineno++;
136 start = lskip(rstrip(line));
137
138 if (*start == ';' || *start == '#') {
139
140
141
142
143 }
144#if CONFIG_INI_ALLOW_MULTILINE
145 else if (*prev_name && *start && start > line) {
146
147
148
149
150
151 if (!handler(user, section, prev_name, start) && !error)
152 error = lineno;
153 }
154#endif
155 else if (*start == '[') {
156
157 end = find_char_or_comment(start + 1, ']');
158 if (*end == ']') {
159 *end = '\0';
160 strncpy0(section, start + 1, sizeof(section));
161 *prev_name = '\0';
162 } else if (!error) {
163
164 error = lineno;
165 }
166 } else if (*start && *start != ';') {
167
168 end = find_char_or_comment(start, '=');
169 if (*end != '=')
170 end = find_char_or_comment(start, ':');
171 if (*end == '=' || *end == ':') {
172 *end = '\0';
173 name = rstrip(start);
174 value = lskip(end + 1);
175 end = find_char_or_comment(value, '\0');
176 if (*end == ';')
177 *end = '\0';
178 rstrip(value);
179
180 if (value[0] == '"' &&
181 value[strlen(value)-1] == '"') {
182 value[strlen(value)-1] = '\0';
183 value += 1;
184 }
185
186
187
188
189 strncpy0(prev_name, name, sizeof(prev_name));
190 if (!handler(user, section, name, value) &&
191 !error)
192 error = lineno;
193 } else if (!error)
194
195 error = lineno;
196 }
197 }
198
199 return error;
200}
201
202static int ini_handler(void *user, char *section, char *name, char *value)
203{
204 char *requested_section = (char *)user;
205#ifdef CONFIG_INI_CASE_INSENSITIVE
206 int i;
207
208 for (i = 0; i < strlen(requested_section); i++)
209 requested_section[i] = tolower(requested_section[i]);
210 for (i = 0; i < strlen(section); i++)
211 section[i] = tolower(section[i]);
212#endif
213
214 if (!strcmp(section, requested_section)) {
215#ifdef CONFIG_INI_CASE_INSENSITIVE
216 for (i = 0; i < strlen(name); i++)
217 name[i] = tolower(name[i]);
218 for (i = 0; i < strlen(value); i++)
219 value[i] = tolower(value[i]);
220#endif
221 env_set(name, value);
222 printf("ini: Imported %s as %s\n", name, value);
223 }
224
225
226 return 1;
227}
228
229static int do_ini(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
230{
231 const char *section;
232 char *file_address;
233 size_t file_size;
234
235 if (argc == 1)
236 return CMD_RET_USAGE;
237
238 section = argv[1];
239 file_address = (char *)hextoul(argc < 3 ? env_get("loadaddr") : argv[2],
240 NULL);
241 file_size = (size_t)hextoul(argc < 4 ? env_get("filesize") : argv[3],
242 NULL);
243
244 return ini_parse(file_address, file_size, ini_handler, (void *)section);
245}
246
247U_BOOT_CMD(
248 ini, 4, 0, do_ini,
249 "parse an ini file in memory and merge the specified section into the env",
250 "section [[file-address] file-size]"
251);
252