This commit was generated by cvs2svn to compensate for changes in r164,
[gnokii.git] / common / 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   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   Config file (/etc/gnokiirc and ~/.gnokiirc) reader.
14
15   Modified from code by Tim Potter.
16
17   $Log$
18   Revision 1.1.1.2  2002/04/03 00:07:51  short
19   Found in "gnokii-working" directory, some November-patches version
20
21   Revision 1.15  2001/06/10 11:24:57  machek
22   Kill "slash star" inside comment.
23
24   Revision 1.14  2001/03/19 23:43:45  pkot
25   Solaris/ *BSD '#if defined' cleanup
26
27   Revision 1.13  2001/03/13 01:21:38  pkot
28   *BSD updates (Bert Driehuis)
29
30   Revision 1.12  2001/01/08 15:11:36  pkot
31   Documentation updates.
32   Fixed some bugs and removed FIXMEs.
33   We need to move some stuff from configure.in to aclocal.m4
34
35   Revision 1.11  2001/01/02 09:09:07  pkot
36   Misc fixes and updates.
37
38   Revision 1.10  2000/12/19 16:18:15  pkot
39   configure script updates and added shared function for configfile reading
40
41
42 */
43
44 #include "misc.h"
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #if __unices__
50 #  include <strings.h>
51 #endif
52 #include <ctype.h>
53 #include <errno.h>
54
55 #include "cfgreader.h"
56
57 struct CFG_Header *CFG_Info;
58
59 /* Read configuration information from a ".INI" style file */
60 struct CFG_Header *CFG_ReadFile(char *filename)
61 {
62         FILE *handle;
63         char *line;
64         char *buf;
65         struct CFG_Header *cfg_info = NULL, *cfg_head = NULL;
66
67         /* Error check */
68         if (filename == NULL) {
69                 return NULL;
70         }
71
72         /* Initialisation */
73         if ((buf = (char *)malloc(255)) == NULL) {
74                 return NULL;
75         }
76     
77         /* Open file */
78         if ((handle = fopen(filename, "r")) == NULL) {
79 #ifdef DEBUG
80                 fprintf( stderr, "CFG_ReadFile - open %s: %s\n", filename, strerror(errno));
81 #endif /* DEBUG */
82                 return NULL;
83         }
84 #ifdef DEBUG
85         else
86                 fprintf( stderr, "Opened configuration file %s\n", filename );
87 #endif /* DEBUG */
88
89         /* Iterate over lines in the file */
90         while (fgets(buf, 255, handle) != NULL) {
91
92                 line = buf;
93
94                 /* Strip leading, trailing whitespace */
95                 while(isspace((int) *line))
96                         line++;
97
98                 while((strlen(line) > 0) && isspace((int) line[strlen(line) - 1]))
99                         line[strlen(line) - 1] = '\0';
100         
101                 /* Ignore blank lines and comments */
102                 if ((*line == '\n') || (*line == '\0') || (*line == '#'))
103                         continue;
104
105                 /* Look for "headings" enclosed in square brackets */
106                 if ((line[0] == '[') && (line[strlen(line) - 1] == ']')) {
107                         struct CFG_Header *heading;
108
109                         /* Allocate new heading entry */
110                         if ((heading = (struct CFG_Header *)malloc(sizeof(*heading))) == NULL) {
111                                 return NULL;
112                         }
113
114                         /* Fill in fields */
115                         memset(heading, '\0', sizeof(*heading));
116             
117                         line++;
118                         line[strlen(line) - 1] = '\0';
119
120                         /* FIXME: strdup is not ANSI C compliant. */
121                         heading->section = strdup(line);
122
123                         /* Add to tail of list  */
124                         heading->prev = cfg_info;
125
126                         if (cfg_info != NULL) {
127                                 cfg_info->next = heading;
128                         } else {
129                                 /* Store copy of head of list for return value */
130                                 cfg_head = heading;
131                         }
132
133                         cfg_info = heading;
134
135 #ifdef DEBUG
136                         fprintf(stderr, "Added new section %s\n", heading->section);
137 #endif
138                         /* Go on to next line */
139
140                         continue;
141                 }
142
143                 /* Process key/value line */
144
145                 if ((strchr(line, '=') != NULL) && cfg_info != NULL) {
146                         struct CFG_Entry *entry;
147                         char *value;
148
149                         /* Allocate new entry */
150                         if ((entry = (struct CFG_Entry *)malloc(sizeof(*entry))) == NULL) {
151                                 return NULL;
152                         }
153
154                         /* Fill in fields */
155                         memset(entry, '\0', sizeof(*entry));
156
157                         value = strchr(line, '=');
158                         *value = '\0';                /* Split string */
159                         value++;
160             
161                         while(isspace((int) *value)) {      /* Remove leading white */
162                                 value++;
163                         }
164
165                         entry->value = strdup(value);
166
167                         while((strlen(line) > 0) && isspace((int) line[strlen(line) - 1])) {
168                                 line[strlen(line) - 1] = '\0';  /* Remove trailing white */
169                         }
170
171                         /* FIXME: strdup is not ANSI C compliant. */
172                         entry->key = strdup(line);
173
174                         /* Add to head of list */
175
176                         entry->next = cfg_info->entries;
177
178                         if (cfg_info->entries != NULL) {
179                                 cfg_info->entries->prev = entry;
180                         }
181
182                         cfg_info->entries = entry;
183
184 #ifdef DEBUG
185                         fprintf(stderr, "Adding key/value %s/%s\n", entry->key, entry->value);
186 #endif
187                         /* Go on to next line */
188                         continue;
189                 }
190
191                         /* Line not part of any heading */
192                 fprintf(stderr, "Orphaned line: %s\n", line);
193         }
194
195         /* Return pointer to configuration information */
196         return cfg_head;
197 }
198
199 /*  Write configuration information to a config file */
200
201 int CFG_WriteFile(struct CFG_Header *cfg, char *filename)
202 {
203   /* Not implemented - tricky to do and preserve comments */
204
205   return 0;
206 }
207
208 /* 
209  * Find the value of a key in a config file.  Return value associated
210  * with key or NULL if no such key exists. 
211  */
212
213 char *CFG_Get(struct CFG_Header *cfg, const char *section, const char *key)
214 {
215         struct CFG_Header *h;
216         struct CFG_Entry *e;
217
218         if ((cfg == NULL) || (section == NULL) || (key == NULL)) {
219                 return NULL;
220         }
221
222         /* Search for section name */
223         for (h = cfg; h != NULL; h = h->next) {
224                 if (strcmp(section, h->section) == 0) {
225                         /* Search for key within section */
226                         for (e = h->entries; e != NULL; e = e->next) {
227                                 if (strcmp(key, e->key) == 0) {
228                                         /* Found! */
229                                         return e->value;
230                                 }
231                         }
232                 }
233         }
234         /* Key not found in section */
235         return NULL;
236 }
237
238 /* 
239  * Return all the entries of the fiven section.
240  */
241
242 void CFG_GetForeach(struct CFG_Header *cfg, const char *section, CFG_GetForeach_func func)
243 {
244         struct CFG_Header *h;
245         struct CFG_Entry *e;
246
247         if ((cfg == NULL) || (section == NULL) || (func == NULL)) {
248                 return;
249         }
250
251         /* Search for section name */
252         for (h = cfg; h != NULL; h = h->next) {
253                 if (strcmp(section, h->section) == 0) {
254                         /* Search for key within section */
255                         for (e = h->entries; e != NULL; e = e->next)
256                                 (*func)(section,e->key,e->value);
257                 }
258         }
259 }
260
261 /*  Set the value of a key in a config file.  Return the new value if
262     the section/key can be found, else return NULL.  */
263
264 char *CFG_Set(struct CFG_Header *cfg, char *section, char *key, 
265                     char *value)
266 {
267         struct CFG_Header *h;
268         struct CFG_Entry *e;
269
270         if ((cfg == NULL) || (section == NULL) || (key == NULL) || 
271             (value == NULL)) {
272                 return NULL;
273         }
274
275         /* Search for section name */
276         for (h = cfg; h != NULL; h = h->next) {
277                 if (strcmp(section, h->section) == 0) {
278                         /* Search for key within section */
279                         for (e = h->entries; e != NULL; e = e->next) {
280                                 if ((e->key != NULL) && strcmp(key, e->key) == 0) {
281                                         /* Found - set value */
282                                         free(e->key);
283                                         /* FIXME: strdup is not ANSI C compliant. */
284                                         e->key = strdup(value);
285                                         return e->value;
286                                 }
287                         }
288                 }
289         }
290         /* Key not found in section */
291         return NULL;    
292 }
293
294 int readconfig(char **model, char **port, char **initlength,
295                char **connection, char **bindir)
296 {
297         char *homedir;
298         char rcfile[200];
299         char *DefaultConnection = "serial";
300         char *DefaultBindir     = "/usr/local/sbin/";
301
302         /* I know that it doesn't belong here but currently there is now generic
303          * application init function anywhere.
304          */
305         setvbuf(stdout, NULL, _IONBF, 0);
306         setvbuf(stderr, NULL, _IONBF, 0);
307
308 #ifdef WIN32
309         homedir = getenv("HOMEDRIVE");
310         strncpy(rcfile, homedir ? homedir : "", 200);
311         homedir = getenv("HOMEPATH");
312         strncat(rcfile, homedir ? homedir : "", 200);
313         strncat(rcfile, "\\_gnokiirc", 200);
314 #else
315         homedir = getenv("HOME");
316         if (homedir) strncpy(rcfile, homedir, 200);
317         strncat(rcfile, "/.gnokiirc", 200);
318 #endif
319
320         /* Try opening .gnokirc from users home directory first */
321         if ((CFG_Info = CFG_ReadFile(rcfile)) == NULL) {
322                 /* It failed so try for /etc/gnokiirc */
323                 if ((CFG_Info = CFG_ReadFile("/etc/gnokiirc")) == NULL) {
324                         /* That failed too so exit */
325                         fprintf(stderr, _("Couldn't open %s or /etc/gnokiirc. Exiting now...\n"), rcfile);
326                         return -1;
327                 }
328         }
329
330         (char *)*model = CFG_Get(CFG_Info, "global", "model");
331         if (!*model) {
332                 fprintf(stderr, _("Config error - no model specified. Exiting now...\n"));
333                 return -2;
334         }
335
336         (char *)*port = CFG_Get(CFG_Info, "global", "port");
337         if (!*port) {
338                 fprintf(stderr, _("Config error - no port specified. Exiting now...\n"));
339                 return -3;
340         }
341
342         (char *)*initlength = CFG_Get(CFG_Info, "global", "initlength");
343         if (!*initlength) (char *)*initlength = "default";
344
345         (char *)*connection = CFG_Get(CFG_Info, "global", "connection");
346         if (!*connection) (char *)*connection = DefaultConnection;
347
348         (char *)*bindir = CFG_Get(CFG_Info, "global", "bindir");
349         if (!*bindir) (char *)*bindir = DefaultBindir;
350
351         return 0;
352 }