Branch update for mygnokii2002_03_17_19_29nl
[gnokii.git] / common / files / cfgreader.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Released under the terms of the GNU GPL, see file COPYING for more details.
10
11   Config file (/etc/gnokiirc and ~/.gnokiirc) reader.
12
13   Modified from code by Tim Potter.
14
15 */
16
17 #include "misc.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #if __unices__
23 #  include <strings.h>
24 #endif
25 #include <ctype.h>
26 #include <errno.h>
27
28 #include "files/cfgreader.h"
29
30 #ifndef UCLINUX
31
32 /* Read configuration information from a ".INI" style file */
33 static struct CFG_Header *CFG_ReadFile(char *filename)
34 {
35         FILE *handle;
36         char *line;
37         char *buf;
38         struct CFG_Header *cfg_info = NULL, *cfg_head = NULL;
39
40         /* Error check */
41         if (filename == NULL) {
42                 return NULL;
43         }
44
45         /* Initialisation */
46         if ((buf = (char *)malloc(255)) == NULL) {
47                 return NULL;
48         }
49     
50         /* Open file */
51         if ((handle = fopen(filename, "r")) == NULL) {
52 #ifdef DEBUG
53 //                fprintf( stderr, "CFG_ReadFile - open %s: %s\n", filename, strerror(errno));
54 #endif /* DEBUG */
55                 return NULL;
56         }
57 #ifdef DEBUG
58         else
59                 fprintf( stderr, "Opened configuration file %s\n", filename );
60 #endif /* DEBUG */
61
62         /* Iterate over lines in the file */
63         while (fgets(buf, 255, handle) != NULL) {
64
65                 line = buf;
66
67                 /* Strip leading, trailing whitespace */
68                 while(isspace((int) *line))
69                         line++;
70
71                 while((strlen(line) > 0) && isspace((int) line[strlen(line) - 1]))
72                         line[strlen(line) - 1] = '\0';
73         
74                 /* Ignore blank lines and comments */
75                 if ((*line == '\n') || (*line == '\0') || (*line == '#'))
76                         continue;
77
78                 /* Look for "headings" enclosed in square brackets */
79                 if ((line[0] == '[') && (line[strlen(line) - 1] == ']')) {
80                         struct CFG_Header *heading;
81
82                         /* Allocate new heading entry */
83                         if ((heading = (struct CFG_Header *)malloc(sizeof(*heading))) == NULL) {
84                                 return NULL;
85                         }
86
87                         /* Fill in fields */
88                         memset(heading, '\0', sizeof(*heading));
89             
90                         line++;
91                         line[strlen(line) - 1] = '\0';
92
93                         /* FIXME: strdup is not ANSI C compliant. */
94                         heading->section = strdup(line);
95
96                         /* Add to tail of list  */
97                         heading->prev = cfg_info;
98
99                         if (cfg_info != NULL) {
100                                 cfg_info->next = heading;
101                         } else {
102                                 /* Store copy of head of list for return value */
103                                 cfg_head = heading;
104                         }
105
106                         cfg_info = heading;
107
108 #ifdef DEBUG
109 //                        fprintf(stderr, "Added new section %s\n", heading->section);
110 #endif
111                         /* Go on to next line */
112
113                         continue;
114                 }
115
116                 /* Process key/value line */
117
118                 if ((strchr(line, '=') != NULL) && cfg_info != NULL) {
119                         struct CFG_Entry *entry;
120                         char *value;
121
122                         /* Allocate new entry */
123                         if ((entry = (struct CFG_Entry *)malloc(sizeof(*entry))) == NULL) {
124                                 return NULL;
125                         }
126
127                         /* Fill in fields */
128                         memset(entry, '\0', sizeof(*entry));
129
130                         value = strchr(line, '=');
131                         *value = '\0';                /* Split string */
132                         value++;
133             
134                         while(isspace((int) *value)) {      /* Remove leading white */
135                                 value++;
136                         }
137
138                         entry->value = strdup(value);
139
140                         while((strlen(line) > 0) && isspace((int) line[strlen(line) - 1])) {
141                                 line[strlen(line) - 1] = '\0';  /* Remove trailing white */
142                         }
143
144                         /* FIXME: strdup is not ANSI C compliant. */
145                         entry->key = strdup(line);
146
147                         /* Add to head of list */
148
149                         entry->next = cfg_info->entries;
150
151                         if (cfg_info->entries != NULL) {
152                                 cfg_info->entries->prev = entry;
153                         }
154
155                         cfg_info->entries = entry;
156
157 #ifdef DEBUG
158 //                        fprintf(stderr, "Adding key/value %s/%s\n", entry->key, entry->value);
159 #endif
160                         /* Go on to next line */
161                         continue;
162                 }
163
164                         /* Line not part of any heading */
165                 fprintf(stderr, "Orphaned line: %s\n", line);
166         }
167
168         /* Return pointer to configuration information */
169         return cfg_head;
170 }
171
172 /*  Write configuration information to a config file */
173
174 static int CFG_WriteFile(struct CFG_Header *cfg, char *filename)
175 {
176   /* Not implemented - tricky to do and preserve comments */
177
178   return 0;
179 }
180
181 /* 
182  * Find the value of a key in a config file.  Return value associated
183  * with key or NULL if no such key exists. 
184  */
185
186 char *CFG_Get(struct CFG_Header *cfg, char *section, char *key)
187 {
188         struct CFG_Header *h;
189         struct CFG_Entry *e;
190
191         if ((cfg == NULL) || (section == NULL) || (key == NULL)) {
192                 return NULL;
193         }
194
195         /* Search for section name */
196         for (h = cfg; h != NULL; h = h->next) {
197                 if (strcmp(section, h->section) == 0) {
198                         /* Search for key within section */
199                         for (e = h->entries; e != NULL; e = e->next) {
200                                 if (strcmp(key, e->key) == 0) {
201                                         /* Found! */
202                                         return e->value;
203                                 }
204                         }
205                 }
206         }
207         /* Key not found in section */
208         return NULL;
209 }
210
211 /*  Set the value of a key in a config file.  Return the new value if
212     the section/key can be found, else return NULL.  */
213
214 static char *CFG_Set(struct CFG_Header *cfg, char *section, char *key, 
215                     char *value)
216 {
217         struct CFG_Header *h;
218         struct CFG_Entry *e;
219
220         if ((cfg == NULL) || (section == NULL) || (key == NULL) || 
221             (value == NULL)) {
222                 return NULL;
223         }
224
225         /* Search for section name */
226         for (h = cfg; h != NULL; h = h->next) {
227                 if (strcmp(section, h->section) == 0) {
228                         /* Search for key within section */
229                         for (e = h->entries; e != NULL; e = e->next) {
230                                 if ((e->key != NULL) && strcmp(key, e->key) == 0) {
231                                         /* Found - set value */
232                                         free(e->key);
233                                         /* FIXME: strdup is not ANSI C compliant. */
234                                         e->key = strdup(value);
235                                         return e->value;
236                                 }
237                         }
238                 }
239         }
240         /* Key not found in section */
241         return NULL;    
242 }
243
244 struct CFG_Header *CFG_FindGnokiirc()
245 {
246         struct CFG_Header *cfg_info;
247         char *homedir;
248         char rcfile[200];
249
250 #ifdef WIN32
251         homedir = getenv("HOMEDRIVE");
252         strncpy(rcfile, homedir ? homedir : "", 200);
253         homedir = getenv("HOMEPATH");
254         strncat(rcfile, homedir ? homedir : "", 200);
255         strncat(rcfile, "\gnokiirc", 200);
256 #else
257         homedir = getenv("HOME");
258         if (homedir) strncpy(rcfile, homedir, 200);
259         strncat(rcfile, "/.gnokiirc", 200);
260 #endif
261
262         /* Try opening .gnokirc from users home directory first */
263         if ((cfg_info = CFG_ReadFile(rcfile)) == NULL) {
264 #ifndef WIN32
265
266                 /* It failed so try for /etc/gnokiirc */
267                 if ((cfg_info = CFG_ReadFile("/etc/gnokiirc")) == NULL) {
268                         /* That failed too so exit */
269 #ifdef DEBUG
270 //                        fprintf(stderr, _("Couldn't open %s or /etc/gnokiirc. Using defaults...\n"), rcfile);
271 #endif /* DEBUG */
272                         return NULL;
273                 }
274
275 #else /* WIN32 */
276
277                 /* It failed so try for gnokiirc */
278                 if ((cfg_info = CFG_ReadFile("gnokiirc")) == NULL) {
279                         /* That failed too so exit */
280 #ifdef DEBUG
281 //                        fprintf(stderr, _("Couldn't open %s or gnokiirc. Using defaults...\n"), rcfile);
282 #endif /* DEBUG */
283                         return NULL;
284                 }
285
286 #endif /* WIN32 */
287         }
288
289         return cfg_info;
290 }
291
292 #endif /* UCLINUX */
293
294 int CFG_ReadConfig(char **model, char **port, char **initlength,
295                char **connection, char **bindir,
296                bool isgnokiid)
297 {
298 #ifdef UCLINUX
299
300         *model=strdup(CONFIG_CFG_MODEL);
301         *port=strdup(CONFIG_CFG_PORT);
302         *initlength=strdup(CONFIG_CFG_INITLENGTH);
303         *connection=strdup("fbus");
304         *bindir=NULL;
305
306 #else /* UCLINUX */
307         struct CFG_Header *cfg_info;
308 #ifdef WIN32
309         char *DefaultPort            = "com2:";
310 #else
311         char *DefaultPort            = "/dev/ttyS1";
312 #endif
313         char *DefaultModel           = "auto";
314         char *DefaultConnection      = "fbus";
315         char *DefaultBindir          = "/usr/local/sbin/";
316         char *DefaultInitLength      = "30";
317
318         char *section = "global";
319
320         (char *)*model = DefaultModel;
321         (char *)*port = DefaultPort;
322         (char *)*connection = DefaultConnection;
323         (char *)*bindir = DefaultBindir;
324         (char *)*initlength = DefaultInitLength;
325         
326         cfg_info=CFG_FindGnokiirc();
327         if (cfg_info==NULL) return 0;
328
329         if (isgnokiid) (char *)section = "gnokiid";
330         
331         (char *)*model = CFG_Get(cfg_info, section, "model");
332         if (!*model) (char *)*model = DefaultModel;
333
334         (char *)*port = CFG_Get(cfg_info, section, "port");
335         if (!*port) (char *)*port = DefaultPort;
336
337         (char *)*connection = CFG_Get(cfg_info, section, "connection");
338         if (!*connection) (char *)*connection = DefaultConnection;
339
340         (char *)*bindir = CFG_Get(cfg_info, section, "bindir");
341         if (!*bindir) (char *)*bindir = DefaultBindir;
342
343         (char *)*initlength = CFG_Get(cfg_info, section, "initlength");
344         if (!*initlength) (char *)*initlength = "default";
345 #endif /* UCLINUX */
346
347         return 0;
348 }