Gammu internals  1.38.0
cfg.c
Go to the documentation of this file.
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 "../../helper/string.h"
20 
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 
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 
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 
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 */
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 
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 
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;
464  free(cur);
465  cur=NULL;
466  cur=next;
467  }
468 }
469 
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  */
gboolean GSM_StringToBool(const char *value)
Definition: cfg.c:470
int INI_GetInt(INI_Section *cfg, const unsigned char *section, const unsigned char *key, int fallback)
Definition: cfg.c:329
void INI_Free(INI_Section *head)
Definition: cfg.c:454
GSM_Error
Definition: gammu-error.h:23
gboolean mywstrncasecmp(unsigned const char *a, unsigned const char *b, int num)
Definition: coding.c:1437
void INI_Free_Entries(INI_Entry *entry)
Definition: cfg.c:437
INI_Entry * Prev
Definition: gammu-inifile.h:42
INI_Entry * SubEntries
Definition: gammu-inifile.h:54
int gboolean
Definition: gammu-types.h:23
#define FALSE
Definition: gammu-types.h:25
gboolean INI_GetBool(INI_Section *cfg, const unsigned char *section, const unsigned char *key, gboolean fallback)
Definition: cfg.c:344
unsigned char * EntryValue
Definition: gammu-inifile.h:44
GSM_Error INI_ReadFile(const char *FileName, gboolean Unicode, INI_Section **result)
Definition: cfg.c:24
INI_Entry * INI_FindLastSectionEntry(INI_Section *file_info, const unsigned char *section, const gboolean Unicode)
Definition: cfg.c:409
Definition: gammu-inifile.h:41
unsigned char * INI_GetValue(INI_Section *cfg, const unsigned char *section, const unsigned char *key, const gboolean Unicode)
Definition: cfg.c:365
unsigned char * SectionName
Definition: gammu-inifile.h:55
unsigned char * EntryName
Definition: gammu-inifile.h:43
#define TRUE
Definition: gammu-types.h:28
gboolean myiswspace(unsigned const char *src)
Definition: coding.c:1470
INI_Section * Next
Definition: gammu-inifile.h:53
INI_Entry * Next
Definition: gammu-inifile.h:42