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