10dc9d1eaaddc69dcfc11842a930c198a74a265a
[pandora-libraries.git] / lib / pnd_conf.c
1
2 #include <stdio.h> /* for NULL, printf, FILE, etc */
3 #include <stdlib.h> /* for malloc */
4 #include <string.h> /* for strdup */
5 #include <ctype.h> /* for isspace */
6
7 #include "pnd_conf.h"
8 #include "pnd_container.h"
9 #include "pnd_pathiter.h"
10
11 pnd_conf_filename_t pnd_conf_filenames[] = {
12   { pnd_conf_conf,         PND_CONF_FILE },
13   { pnd_conf_apps,         "apps" },
14   { pnd_conf_startup,      "startup" },
15   { pnd_conf_desktop,      "desktop" },
16   { pnd_conf_nil,          NULL },
17 };
18
19 char *pnd_conf_query_searchpath ( void ) {
20   pnd_conf_handle ch;
21
22   // fetch base config
23   ch = pnd_conf_fetch_by_id ( pnd_conf_conf, PND_CONF_SEARCHPATH );
24
25   if ( ! ch ) {
26     //printf ( "Couldn't locate base conf file '%s'\n", PND_CONF_FILE );
27     return ( strdup ( PND_CONF_SEARCHPATH ) );
28   }
29
30   // can we find a user-specified config path? if so, use it.. if not, fall back!
31   char *searchpath;
32   char *temp;
33
34   temp = pnd_conf_get_as_char ( ch, PND_CONF_KEY );
35
36   if ( searchpath ) {
37     searchpath = strdup ( temp );
38   } else {
39     searchpath = strdup ( PND_CONF_SEARCHPATH );
40   }
41
42   return ( searchpath );
43 }
44
45 pnd_conf_handle pnd_conf_fetch_by_id ( pnd_conf_filename_e id, char *searchpath ) {
46   pnd_conf_filename_t *p = pnd_conf_filenames;
47
48   while ( p -> filename ) {
49
50     /* found the filename associated to the id? */
51     if ( p -> id == id ) {
52       return ( pnd_conf_fetch_by_name ( p -> filename, searchpath ) );
53     }
54
55     /* next! */
56     p++;
57   } /* while */
58
59   return ( NULL );
60 }
61
62 pnd_conf_handle pnd_conf_fetch_by_name ( char *filename, char *searchpath ) {
63
64   /* the fun part here is that we get to cheat; while we have to search through all the directories
65    * listed in the search path, we can stop at the first matching file. Nothign really fancy going on, and
66    * no need for comprehensive directory crawling. yay!
67    */
68   pnd_conf_handle conf;
69
70   //printf ( "Search path: '%s'\n", searchpath );
71
72   SEARCHPATH_PRE
73   {
74
75     strncat ( buffer, "/", FILENAME_MAX - 1 );
76     strncat ( buffer, filename, FILENAME_MAX - 1 );
77     conf = pnd_conf_fetch_by_path ( buffer );
78
79     if ( conf ) {
80       return ( conf );
81     }
82
83   }
84   SEARCHPATH_POST
85
86   return ( NULL );
87 }
88
89 pnd_conf_handle pnd_conf_fetch_by_path ( char *fullpath ) {
90   FILE *f;
91   char section [ 256 ] = "";
92   char buffer [ FILENAME_MAX ];
93   char inbuffer [ FILENAME_MAX ];
94   char *c, *head, *tail, *mid;
95
96   //printf ( "Attempt to load config from fullpath '%s'\n", fullpath );
97
98   /* WARN:
99    * No check yet to verify the directory is actually mounted and readable; either way
100    * this should not block or take up much time, though SD cards might be slow to open over
101    * and over again .. perhaps need some smarts or caching of results or somesuch, since this
102    * call gets spammed over and over...
103    */
104   f = fopen ( fullpath, "r" );
105
106   if ( ! f ) {
107     return ( NULL );
108   }
109
110   // damn, we actually found a file, so need to try to parse it. Shucks. Give back a box-handle
111   // so the consumer has some lists to look at
112   pnd_box_handle h;
113   h = pnd_box_new ( fullpath );
114
115   // inhale file
116   while ( fgets ( inbuffer, FILENAME_MAX, f ) ) {
117
118     // strip line-endings and DOSisms
119     if ( ( c = strchr ( inbuffer, '\r' ) ) ) {
120       *c = '\0';
121     }
122
123     if ( ( c = strchr ( inbuffer, '\n' ) ) ) {
124       *c = '\0';
125     }
126
127     //printf ( "config line: '%s'\n", inbuffer );
128
129     // strip comments
130     if ( ( c = strchr ( inbuffer, '#' ) ) ) {
131       *c = '\0';
132     }
133
134     // strip leading and trailing spaces
135     head = inbuffer;
136     while ( *head && isspace ( *head ) ) {
137       head++;
138     }
139
140     if ( inbuffer [ 0 ] == '\0' ) {
141       //printf ( "  -> discard\n" );
142       continue; // skip, the line was pure comment or blank
143     }
144
145     tail = strchr ( inbuffer, '\0' ) - 1;
146     while ( *tail && isspace ( *tail ) ) {
147       *tail = '\0';
148       tail--;
149     }
150
151     if ( inbuffer [ 0 ] == '\0' ) {
152       //printf ( "  -> discard\n" );
153       continue; // skip, the line was pure comment or blank
154     }
155
156     // decorated, ie: a section?
157     if ( *head == '[' && *tail == ']' ) {
158       // note: handle the nil-section
159
160       memset ( section, '\0', 256 );
161
162       if ( tail == head + 1 ) {
163         section [ 0 ] = '\0';
164       } else {
165         strncpy ( section, head + 1, tail - head - 1 );
166       }
167
168       //printf ( " -> section '%s'\n", section );
169
170     } else {
171
172       // must be a key (and likely a value) .. find the division
173       mid = head;
174       while ( *mid && ! isspace ( *mid ) ) {
175         mid++;
176       }
177       *mid = '\0';
178       mid++;
179
180       //printf ( "key head: '%s'\n", head );
181       //printf ( "key mid: '%s'\n", mid );
182
183       // is thjis a key/value pair, or just a key?
184       if ( mid [ 0 ] ) {
185         // key/value pairing
186         char *v;
187
188         // form the actual new key
189         if ( section [ 0 ] ) {
190           snprintf ( buffer, FILENAME_MAX - 1, "%s.%s", section, head );
191         } else {
192           strncpy ( buffer, head, FILENAME_MAX - 1 );
193         }
194
195         //printf ( "Found key '%s' in config file\n", buffer );
196
197         // alloc node into the box
198         v = pnd_box_allocinsert ( h, buffer, strlen ( mid ) + 1 ); // allow for trailing null
199
200         if ( v ) {
201           strcpy ( v, mid );
202         } else {
203           return ( NULL ); // OOM while reading conf is either sad, or really scary conf (also sad.)
204         }
205
206       } else {
207         // key/value pairing
208         char *v;
209
210         // form the actual new key
211         if ( section [ 0 ] ) {
212           snprintf ( buffer, FILENAME_MAX - 1, "%s.%s", section, head );
213         } else {
214           strncpy ( buffer, head, FILENAME_MAX - 1 );
215         }
216
217         //printf ( "Found key with no value '%s' in config file\n", buffer );
218
219         // alloc node into the box
220         v = pnd_box_allocinsert ( h, buffer, 0 ); // zero b/c of no payload
221
222         if ( ! v ) {
223           return ( NULL ); // OOM while reading conf is either sad, or really scary conf (also sad.)
224         }
225
226       } // key or key/value?
227
228     } // section or key/value line?
229     
230   } // while
231
232   // clean up a trifle
233   fclose ( f );
234
235   return ( h );
236 }
237
238 char *pnd_conf_get_as_char ( pnd_conf_handle c, char *key ) {
239   return ( pnd_box_find_by_key ( c, key ) );
240 }