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