1 /* (c) 2002-2004 by Marcin Wiacek */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <errno.h>
8 #ifdef HAVE_WCHAR_H
9 # include <wchar.h>
10 #endif
11 #ifdef HAVE_WCTYPE_H
12 # include <wctype.h>
13 #endif
14
15 #include <gammu-config.h>
16 #include <gammu-inifile.h>
17 #include "coding/coding.h"
18
19 #include "../../libgammu/misc/string.h"
20
21 /**
22 * Read information from file in Windows INI format style
23 */
INI_ReadFile(const char * FileName,gboolean Unicode,INI_Section ** result)24 GSM_Error INI_ReadFile(const char *FileName, gboolean Unicode, INI_Section **result)
25 {
26 FILE *f;
27 gboolean FFEEUnicode=FALSE;
28 int level = -1, buffer1used, buffer2used;
29 size_t bufferused, i, read_buffer_used=1000,read_buffer_pos=1000, num;
30 unsigned char ch[3], *buffer = NULL;
31 unsigned char *buffer2 = NULL, *buffer1 = NULL, read_buffer[1001];
32 INI_Section *INI_info = NULL, *INI_head = NULL, *heading;
33 INI_Entry *entry;
34 GSM_Error error = ERR_NONE;
35
36 *result = NULL;
37
38 if (FileName == NULL) {
39 return ERR_CANTOPENFILE;
40 }
41
42 f = fopen(FileName,"rb");
43 if (f == NULL) {
44 return ERR_CANTOPENFILE;
45 }
46
47 num = 0;
48 while(1) {
49 /* We read one line from file */
50 bufferused = 0;
51 while (1) {
52 if (read_buffer_used == read_buffer_pos) {
53 read_buffer_used = fread(read_buffer,1,1000,f);
54 read_buffer_pos = 0;
55 if (read_buffer_used == 0) {
56 error = ERR_NONE;
57 goto done;
58 }
59 }
60 if (Unicode) {
61 if (num == 0) {
62 if (read_buffer_used == read_buffer_pos) {
63 continue;
64 }
65 ch[0] = read_buffer[read_buffer_pos++];
66 num = 1;
67 }
68 if (num == 1) {
69 if (read_buffer_used == read_buffer_pos) {
70 continue;
71 }
72 ch[1] = read_buffer[read_buffer_pos++];
73 num = 0;
74 }
75 if (level == -1) {
76 if (ch[0] == 0xFF && ch[1] == 0xFE) FFEEUnicode = TRUE;
77 level = 0;
78 continue;
79 }
80 if (FFEEUnicode) {
81 ch[2] = ch[0]; ch[0] = ch[1]; ch[1] = ch[2];
82 }
83 } else {
84 if (read_buffer_used == read_buffer_pos) {
85 continue;
86 }
87 ch[0] = 0;
88 ch[1] = read_buffer[read_buffer_pos++];
89 if (level == -1) level = 0;
90 }
91 if ((ch[0] == 0 && ch[1] == 13) ||
92 (ch[0] == 0 && ch[1] == 10)) {
93 break;
94 }
95 buffer = (unsigned char *)realloc(buffer,bufferused+2);
96 if (buffer == NULL) {
97 error = ERR_MOREMEMORY;
98 goto done;
99 }
100 buffer[bufferused] = ch[0];
101 buffer[bufferused+1] = ch[1];
102 bufferused = bufferused + 2;
103 }
104
105 buffer1used = 0;
106 buffer2used = 0;
107 if (level == 1) level = 0;
108 if (level == 3 || level == 4 || level == 5) level = 2;
109
110 /* We parse read line */
111 for (i=0;i<bufferused/2;i++) {
112 ch[0] = buffer[i*2];
113 ch[1] = buffer[i*2+1];
114 if (level == 0) { /* search for name of section */
115 if (ch[0] == 0 && ch[1] == '[') level = 1;
116 if (ch[0] == 0 && ch[1] == ';') {
117 break;
118 }
119 if (ch[0] == 0 && ch[1] == '#') {
120 break;
121 }
122 continue;
123 }
124 if (level == 1) { /* section name */
125 if (ch[0] == 0 && ch[1] == ']') {
126 if (buffer1used == 0) {
127 break;
128 }
129 if (Unicode) {
130 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+2);
131 buffer1[buffer1used] = 0;
132 buffer1[buffer1used+1] = 0;
133 buffer1used = buffer1used + 2;
134 } else {
135 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+1);
136 buffer1[buffer1used] = 0x00;
137 buffer1used = buffer1used + 1;
138 }
139 heading = (INI_Section *)malloc(sizeof(*heading));
140 if (heading == NULL) {
141 error = ERR_MOREMEMORY;
142 goto done;
143 }
144 heading->SectionName = (char *)malloc(buffer1used);
145 memcpy(heading->SectionName,buffer1,buffer1used);
146 heading->Prev = INI_info;
147 heading->Next = NULL;
148 if (INI_info != NULL) {
149 INI_info->Next = heading;
150 } else {
151 INI_head = heading;
152 }
153 INI_info = heading;
154 INI_info->SubEntries = NULL;
155 level = 2;
156 break;
157 }
158 if (Unicode) {
159 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+2);
160 buffer1[buffer1used] = ch[0];
161 buffer1[buffer1used+1] = ch[1];
162 buffer1used = buffer1used + 2;
163 } else {
164 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+1);
165 buffer1[buffer1used] = ch[1];
166 buffer1used = buffer1used + 1;
167 }
168 continue;
169 }
170 if (level == 2) { /* search for key name */
171 if (ch[0] == 0 && ch[1] == ';') {
172 break;
173 }
174 if (ch[0] == 0 && ch[1] == '#') {
175 break;
176 }
177 if (ch[0] == 0 && ch[1] == '[') {
178 level = 1;
179 continue;
180 }
181 if (Unicode) {
182 if (myiswspace(ch)) {
183 continue;
184 }
185 } else {
186 if (isspace((int) ch[1])) {
187 continue;
188 }
189 }
190 level = 3;
191 }
192 if (level == 3) { /* key name */
193 if (ch[0] == 0 && ch[1] == '=') {
194 if (buffer1used == 0) {
195 break;
196 }
197 while(1) {
198 if (Unicode) {
199 if (!myiswspace(buffer1+(buffer1used-2))) {
200 break;
201 }
202 buffer1used = buffer1used - 2;
203 } else {
204 if (!isspace((int)buffer1[buffer1used-1])) {
205 break;
206 }
207 buffer1used = buffer1used - 1;
208 }
209 }
210 level = 4;
211 continue;
212 }
213 if (Unicode) {
214 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+2);
215 buffer1[buffer1used] = ch[0];
216 buffer1[buffer1used+1] = ch[1];
217 buffer1used = buffer1used + 2;
218 } else {
219 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+1);
220 buffer1[buffer1used] = ch[1];
221 buffer1used = buffer1used + 1;
222 }
223 }
224 if (level == 4) { /* search for key value */
225 if (Unicode) {
226 if (myiswspace(ch)) {
227 continue;
228 }
229 } else {
230 if (isspace((int) ch[1])) {
231 continue;
232 }
233 }
234 level = 5;
235 }
236 if (level == 5) { /* key value */
237 if (Unicode) {
238 buffer2 = (unsigned char *)realloc(buffer2,buffer2used+2);
239 buffer2[buffer2used] = ch[0];
240 buffer2[buffer2used+1] = ch[1];
241 buffer2used = buffer2used + 2;
242 } else {
243 buffer2 = (unsigned char *)realloc(buffer2,buffer2used+1);
244 buffer2[buffer2used] = ch[1];
245 buffer2used = buffer2used + 1;
246 }
247 }
248 }
249 if (level == 5) {
250 if (Unicode) {
251 while (myiswspace(buffer2 + buffer2used - 2) && buffer2used > 0) {
252 buffer2used -= 2;
253 }
254 } else {
255 while (isspace(buffer2[buffer2used - 1]) && buffer2used > 0) {
256 buffer2used -= 1;
257 }
258 }
259 if (buffer2used == 0) {
260 continue;
261 }
262
263 entry = (INI_Entry *)malloc(sizeof(*entry));
264 if (entry == NULL) {
265 error = ERR_MOREMEMORY;
266 goto done;
267 }
268 if (Unicode) {
269 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+2);
270 buffer1[buffer1used] = 0;
271 buffer1[buffer1used+1] = 0;
272 buffer1used = buffer1used + 2;
273 buffer2 = (unsigned char *)realloc(buffer2,buffer2used+2);
274 buffer2[buffer2used] = 0;
275 buffer2[buffer2used+1] = 0;
276 buffer2used = buffer2used + 2;
277 } else {
278 buffer1 = (unsigned char *)realloc(buffer1,buffer1used+1);
279 buffer1[buffer1used] = 0x00;
280 buffer1used = buffer1used + 1;
281 buffer2 = (unsigned char *)realloc(buffer2,buffer2used+1);
282 buffer2[buffer2used] = 0x00;
283 buffer2used = buffer2used + 1;
284 }
285
286 entry->EntryName = (char *)malloc(buffer1used);
287 if (entry->EntryName == NULL) {
288 error = ERR_MOREMEMORY;
289 goto done;
290 }
291 memcpy(entry->EntryName,buffer1,buffer1used);
292
293 entry->EntryValue = (char *)malloc(buffer2used);
294 if (entry->EntryValue == NULL) {
295 error = ERR_MOREMEMORY;
296 goto done;
297 }
298 memcpy(entry->EntryValue,buffer2,buffer2used);
299
300 entry->Prev = NULL;
301 entry->Next = INI_info->SubEntries;
302 if (INI_info->SubEntries != NULL) {
303 INI_info->SubEntries->Prev = entry;
304 }
305 INI_info->SubEntries = entry;
306 }
307 }
308 done:
309 free(buffer);
310 buffer=NULL;
311 free(buffer1);
312 buffer1=NULL;
313 free(buffer2);
314 buffer2=NULL;
315 fclose(f);
316
317 if (error == ERR_NONE) {
318 *result = INI_head;
319 if (INI_head == NULL) {
320 error = ERR_FILENOTSUPPORTED;
321 }
322 }
323 return error;
324 }
325
326 /**
327 * Returns integer value from configuration.
328 */
INI_GetInt(INI_Section * cfg,const unsigned char * section,const unsigned char * key,int fallback)329 int INI_GetInt(INI_Section *cfg, const unsigned char *section, const unsigned char *key, int fallback)
330 {
331 char *str;
332
333 str = (char *)INI_GetValue(cfg, section, key, FALSE);
334 if (str) {
335 return atoi(str);
336 } else {
337 return fallback;
338 }
339 }
340
341 /**
342 * Returns integer value from configuration.
343 */
INI_GetBool(INI_Section * cfg,const unsigned char * section,const unsigned char * key,gboolean fallback)344 gboolean INI_GetBool(INI_Section *cfg, const unsigned char *section, const unsigned char *key, gboolean fallback)
345 {
346 char *str;
347 gboolean ret;
348
349 str = (char *)INI_GetValue(cfg, section, key, FALSE);
350 if (str) {
351 ret = GSM_StringToBool(str);
352 if (ret == -1) {
353 return fallback;
354 }
355 return ret;
356 } else {
357 return fallback;
358 }
359 }
360
361 /**
362 * Search for key value in file in Windows INI format style
363 * Returns found value or NULL
364 */
INI_GetValue(INI_Section * cfg,const unsigned char * section,const unsigned char * key,const gboolean Unicode)365 unsigned char *INI_GetValue(INI_Section *cfg, const unsigned char *section, const unsigned char *key, const gboolean Unicode)
366 {
367 INI_Section *sec;
368 INI_Entry *ent;
369
370 if (cfg == NULL || section == NULL || key == NULL) return NULL;
371
372 if (Unicode) {
373 /* Search for section */
374 sec = cfg;
375 while (sec != NULL) {
376 if (mywstrncasecmp(section, sec->SectionName, 0)) {
377 /* Search for key inside section */
378 ent = sec->SubEntries;
379 while (ent != NULL) {
380 if (mywstrncasecmp(key,ent->EntryName,0)) {
381 return ent->EntryValue;
382 }
383 ent = ent->Next;
384 }
385 }
386 sec = sec->Next;
387 }
388 } else {
389 /* Search for section */
390 sec = cfg;
391 while (sec != NULL) {
392 if (strcasecmp(section, sec->SectionName) == 0) {
393 /* Search for key inside section */
394 ent = sec->SubEntries;
395 while (ent != NULL) {
396 if (strcasecmp(key,ent->EntryName) == 0) {
397 return ent->EntryValue;
398 }
399 ent = ent->Next;
400 }
401 }
402 sec = sec->Next;
403 }
404 }
405 return NULL;
406 }
407
408 /* Return last value in specified section */
INI_FindLastSectionEntry(INI_Section * file_info,const unsigned char * section,const gboolean Unicode)409 INI_Entry *INI_FindLastSectionEntry(INI_Section *file_info, const unsigned char *section, const gboolean Unicode)
410 {
411 INI_Section *h;
412 INI_Entry *e;
413
414 e = NULL;
415 /* First find our section */
416 for (h = file_info; h != NULL; h = h->Next) {
417 if (Unicode) {
418 if (mywstrncasecmp(section, h->SectionName, 0)) {
419 e = h->SubEntries;
420 break;
421 }
422 } else {
423 if (strcasecmp(section, h->SectionName) == 0) {
424 e = h->SubEntries;
425 break;
426 }
427 }
428 }
429
430 if (e == NULL) return NULL;
431
432 /* Goes into last value in section */
433 while (e->Next != NULL) e = e->Next;
434 return e;
435 }
436
INI_Free_Entries(INI_Entry * entry)437 void INI_Free_Entries(INI_Entry *entry)
438 {
439 INI_Entry *cur = entry, *next=NULL;
440
441 if (cur == NULL) return;
442 while (cur != NULL) {
443 next = cur->Next;
444 free(cur->EntryName);
445 cur->EntryName=NULL;
446 free(cur->EntryValue);
447 cur->EntryValue=NULL;
448 free(cur);
449 cur=NULL;
450 cur=next;
451 }
452 }
453
INI_Free(INI_Section * head)454 void INI_Free(INI_Section *head)
455 {
456 INI_Section *cur = head, *next;
457
458 if (cur == NULL) return;
459 while (cur != NULL) {
460 next = cur->Next;
461 free(cur->SectionName);
462 cur->SectionName=NULL;
463 INI_Free_Entries(cur->SubEntries);
464 free(cur);
465 cur=NULL;
466 cur=next;
467 }
468 }
469
GSM_StringToBool(const char * value)470 gboolean GSM_StringToBool(const char *value)
471 {
472 if (strcasecmp(value, "true") == 0) return TRUE;
473 if (strcasecmp(value, "yes") == 0) return TRUE;
474 if (strcasecmp(value, "y") == 0) return TRUE;
475 if (strcasecmp(value, "t") == 0) return TRUE;
476 if (strcasecmp(value, "1") == 0) return TRUE;
477 if (strcasecmp(value, "false") == 0) return FALSE;
478 if (strcasecmp(value, "no") == 0) return FALSE;
479 if (strcasecmp(value, "f") == 0) return FALSE;
480 if (strcasecmp(value, "n") == 0) return FALSE;
481 if (strcasecmp(value, "0") == 0) return FALSE;
482 return -1;
483 }
484
485 /* How should editor hadle tabs in this file? Add editor commands here.
486 * vim: noexpandtab sw=8 ts=8 sts=8:
487 */
488