]> git.decadent.org.uk Git - ion3.git/blob - libextl/readconfig.c
[svn-inject] Installing original source of ion3
[ion3.git] / libextl / readconfig.c
1 /*
2  * libextl/readconfig.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2005.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  */
11
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17
18 #include "readconfig.h"
19 #include "extl.h"
20 #include "private.h"
21
22
23 typedef struct{
24     ExtlFn fn;
25     ExtlTab tab;
26     int status;
27 } TryCallParam;
28
29
30 /*{{{ Path setup */
31
32
33 static char *userdir=NULL;
34 static char *sessiondir=NULL;
35 static char *scriptpath=NULL;
36
37
38 bool extl_add_searchdir(const char *dir)
39 {
40     if(scriptpath==NULL){
41         scriptpath=extl_scopy(dir);
42         if(scriptpath==NULL)
43             return FALSE;
44     }else{
45         char *p=extl_scat3(dir, ":", scriptpath);
46         if(p==NULL)
47             return FALSE;
48         free(scriptpath);
49         scriptpath=p;
50     }
51     
52     return TRUE;
53 }
54
55
56 bool extl_set_searchpath(const char *path)
57 {
58     char *s=NULL;
59     
60     if(path!=NULL){
61         s=extl_scopy(path);
62         if(s==NULL)
63             return FALSE;
64     }
65     
66     if(scriptpath!=NULL)
67         free(scriptpath);
68     
69     scriptpath=s;
70     return TRUE;
71 }
72
73
74 bool extl_set_userdirs(const char *appname)
75 {
76     const char *home;
77     char *tmp;
78     int fails=2;
79     
80     if(userdir!=NULL)
81         return FALSE;
82     
83     home=getenv("HOME");
84     
85     if(home==NULL){
86         extl_warn(TR("$HOME not set"));
87     }else{
88         libtu_asprintf(&userdir, "%s/.%s", home, appname);
89         if(userdir!=NULL)
90             fails-=extl_add_searchdir(userdir);
91         
92         libtu_asprintf(&tmp, "%s/.%s/lib", home, appname);
93         if(tmp!=NULL){
94             fails-=extl_add_searchdir(tmp);
95             free(tmp);
96         }
97     }
98     
99     return (fails==0);
100 }
101
102
103 bool extl_set_sessiondir(const char *session)
104 {
105     char *tmp;
106     bool ret=FALSE;
107     
108     if(strchr(session, '/')!=NULL){
109         tmp=extl_scopy(session);
110     }else if(userdir!=NULL){
111         libtu_asprintf(&tmp, "%s/%s", userdir, session);
112     }else{
113         extl_warn(TR("User directory not set. "
114                      "Unable to set session directory."));
115         return FALSE;
116     }
117     
118     if(tmp==NULL)
119         return FALSE;
120     
121     if(sessiondir!=NULL)
122         free(sessiondir);
123     
124     sessiondir=tmp;
125     
126     return TRUE;
127 }
128
129
130 const char *extl_userdir()
131 {
132     return userdir;
133 }
134
135
136 const char *extl_sessiondir()
137 {
138     return sessiondir;
139 }
140
141
142 const char *extl_searchpath()
143 {
144     return scriptpath;
145 }
146
147
148 /*}}}*/
149
150
151 /*{{{ try_etcpath, do_include, etc. */
152
153
154 static int do_try(const char *dir, const char *file, ExtlTryConfigFn *tryfn,
155                   void *tryfnparam)
156 {
157     char *tmp=NULL;
158     int ret;
159     
160     libtu_asprintf(&tmp, "%s/%s", dir, file);
161     if(tmp==NULL)
162         return EXTL_TRYCONFIG_MEMERROR;
163
164     ret=tryfn(tmp, tryfnparam);
165     free(tmp);
166     return ret;
167 }
168
169
170 static int try_dir(const char *const *files, const char *cfdir,
171                    ExtlTryConfigFn *tryfn, void *tryfnparam)
172 {
173     const char *const *file;
174     int ret, ret2=EXTL_TRYCONFIG_NOTFOUND;
175     
176     for(file=files; *file!=NULL; file++){
177         if(cfdir==NULL)
178             ret=tryfn(*file, tryfnparam);
179         else
180             ret=do_try(cfdir, *file, tryfn, tryfnparam);
181         if(ret>=0)
182             return ret;
183         if(ret2==EXTL_TRYCONFIG_NOTFOUND)
184             ret2=ret;
185     }
186     
187     return ret2;
188 }
189
190
191 static int try_etcpath(const char *const *files, 
192                        ExtlTryConfigFn *tryfn, void *tryfnparam)
193 {
194     const char *const *file=NULL;
195     int i, ret, ret2=EXTL_TRYCONFIG_NOTFOUND;
196     char *path, *colon, *dir;
197
198     if(sessiondir!=NULL){
199         for(file=files; *file!=NULL; file++){
200             ret=do_try(sessiondir, *file, tryfn, tryfnparam);
201             if(ret>=0)
202                 return ret;
203             if(ret2==EXTL_TRYCONFIG_NOTFOUND)
204                 ret2=ret;
205         }
206     }
207     
208     path=scriptpath;
209     while(path!=NULL){
210         colon=strchr(path, ':');
211         if(colon!=NULL){
212             dir=extl_scopyn(path, colon-path);
213             path=colon+1;
214         }else{
215             dir=extl_scopy(path);
216             path=NULL;
217         }
218         
219         if(dir!=NULL){
220             if(*dir!='\0'){
221                 for(file=files; *file!=NULL; file++){
222                     ret=do_try(dir, *file, tryfn, tryfnparam);
223                     if(ret>=0){
224                         free(dir);
225                         return ret;
226                     }
227                     if(ret2==EXTL_TRYCONFIG_NOTFOUND)
228                         ret2=ret;
229                 }
230             }
231             free(dir);
232         }
233     }
234     
235     return ret2;
236 }
237
238
239 static int try_lookup(const char *file, char **ptr)
240 {
241     if(access(file, F_OK)!=0)
242         return EXTL_TRYCONFIG_NOTFOUND;
243     *ptr=extl_scopy(file);
244     return (*ptr!=NULL);
245 }
246
247
248 static int try_load(const char *file, TryCallParam *param)
249 {
250     if(access(file, F_OK)!=0)
251         return EXTL_TRYCONFIG_NOTFOUND;
252     
253     if(param->status==1)
254         extl_warn(TR("Falling back to %s."), file);
255     
256     if(!extl_loadfile(file, &(param->fn))){
257         param->status=1;
258         return EXTL_TRYCONFIG_LOAD_FAILED;
259     }
260     
261     return EXTL_TRYCONFIG_OK;
262 }
263
264
265 static int try_call(const char *file, TryCallParam *param)
266 {
267     int ret=try_load(file, param);
268     
269     if(ret!=EXTL_TRYCONFIG_OK)
270         return ret;
271     
272     ret=extl_call(param->fn, NULL, NULL);
273     
274     extl_unref_fn(param->fn);
275     
276     return (ret ? EXTL_TRYCONFIG_OK : EXTL_TRYCONFIG_CALL_FAILED);
277 }
278
279
280 static int try_read_savefile(const char *file, TryCallParam *param)
281 {
282     int ret=try_load(file, param);
283     
284     if(ret!=EXTL_TRYCONFIG_OK)
285         return ret;
286     
287     ret=extl_call(param->fn, NULL, "t", &(param->tab));
288     
289     extl_unref_fn(param->fn);
290     
291     return (ret ? EXTL_TRYCONFIG_OK : EXTL_TRYCONFIG_CALL_FAILED);
292 }
293
294
295 int extl_try_config(const char *fname, const char *cfdir,
296                     ExtlTryConfigFn *tryfn, void *tryfnparam,
297                     const char *ext1, const char *ext2)
298 {
299     char *files[]={NULL, NULL, NULL, NULL};
300     int n=0, ret=EXTL_TRYCONFIG_NOTFOUND, ret2;
301     bool search=FALSE, has_ext;
302     
303     /* Search etcpath only if path is not absolute */
304     search=(fname[0]!='/');
305
306     /* Build list of files to look for */
307     has_ext=strrchr(fname, '.')>strrchr(fname, '/');
308
309     if(!has_ext){
310         if(ext1!=NULL){
311             files[n]=extl_scat3(fname, ".", ext1);
312             if(files[n]!=NULL)
313                 n++;
314         }
315
316         if(ext2!=NULL){
317             files[n]=extl_scat3(fname, ".", ext2);
318             if(files[n]!=NULL)
319                 n++;
320         }
321     }
322     
323     if(has_ext || !search){
324         files[n]=extl_scopy(fname);
325         if(files[n]!=NULL)
326             n++;
327     }
328     
329     /* NOTE for future changes: cfdir must not be scanned first for
330      * user configuration files to take precedence.
331      */
332
333     /* Scan through all possible files */
334     if(search){
335         ret2=try_etcpath((const char**)&files, tryfn, tryfnparam);
336         if(ret==EXTL_TRYCONFIG_NOTFOUND)
337             ret=ret2;
338         if(ret<0)
339             ret=try_dir((const char**)&files, cfdir, tryfn, tryfnparam);
340     }else{
341         ret=try_dir((const char**)&files, NULL, tryfn, tryfnparam);
342     }
343     
344     while(n>0)
345         free(files[--n]);
346     
347     return ret;
348 }
349
350
351 /*EXTL_DOC
352  * Lookup script \var{file}. If \var{try_in_dir} is set, it is tried
353  * before the standard search path.
354  */
355 EXTL_EXPORT
356 char *extl_lookup_script(const char *file, const char *sp)
357 {
358     const char *files[]={NULL, NULL};
359     char* tmp=NULL;
360     
361     if(file!=NULL){
362         files[0]=file;
363
364         if(sp!=NULL)
365             try_dir(files, sp, (ExtlTryConfigFn*)try_lookup, &tmp);
366         if(tmp==NULL)
367             try_etcpath(files, (ExtlTryConfigFn*)try_lookup, &tmp);
368     }
369     
370     return tmp;
371 }
372
373
374 bool extl_read_config(const char *file, const char *sp, bool warn_nx)
375 {
376     TryCallParam param;
377     int retval;
378     
379     if(file==NULL)
380         return FALSE;
381     
382     param.status=0;
383     
384     retval=extl_try_config(file, sp, (ExtlTryConfigFn*)try_call, &param,
385                               EXTL_COMPILED_EXTENSION, EXTL_EXTENSION);
386     
387     if(retval==EXTL_TRYCONFIG_NOTFOUND && warn_nx)
388         extl_warn(TR("Unable to find '%s' on search path."), file);
389
390     return (retval==EXTL_TRYCONFIG_OK);
391 }
392
393
394 bool extl_read_savefile(const char *basename, ExtlTab *tabret)
395 {
396     TryCallParam param;
397     int retval;
398     
399     param.status=0;
400     param.tab=extl_table_none();
401     
402     retval=extl_try_config(basename, NULL, (ExtlTryConfigFn*)try_read_savefile,
403                               &param, EXTL_EXTENSION, NULL);
404
405     *tabret=param.tab;
406     
407     return (retval==EXTL_TRYCONFIG_OK);
408 }
409
410
411 /*EXTL_DOC
412  * Read a savefile.
413  */
414 EXTL_EXPORT_AS(extl, read_savefile)
415 ExtlTab extl_extl_read_savefile(const char *basename)
416 {
417     ExtlTab tab;
418     if(!extl_read_savefile(basename, &tab))
419         return extl_table_none();
420     return tab;
421 }
422     
423
424 /*}}}*/
425
426
427 /*{{{ extl_get_savefile */
428
429
430 static bool ensuredir(char *f)
431 {
432     char *p;
433     int tryno=0;
434     bool ret=TRUE;
435     
436     if(access(f, F_OK)==0)
437         return TRUE;
438     
439     if(mkdir(f, 0700)==0)
440         return TRUE;
441     
442     p=strrchr(f, '/');
443     if(p==NULL){
444         extl_warn_err_obj(f);
445         return FALSE;
446     }
447     
448     *p='\0';
449     if(!ensuredir(f))
450         return FALSE;
451     *p='/';
452         
453     if(mkdir(f, 0700)==0)
454         return TRUE;
455     
456     extl_warn_err_obj(f);
457     return FALSE;
458 }
459
460
461 /*EXTL_DOC
462  * Get a file name to save (session) data in. The string \var{basename} 
463  * should contain no path or extension components.
464  */
465 EXTL_EXPORT
466 char *extl_get_savefile(const char *basename)
467 {
468     char *res=NULL;
469     
470     if(sessiondir==NULL)
471         return NULL;
472     
473     if(!ensuredir(sessiondir)){
474         extl_warn(TR("Unable to create session directory \"%s\"."), 
475                   sessiondir);
476         return NULL;
477     }
478     
479     libtu_asprintf(&res, "%s/%s." EXTL_EXTENSION, sessiondir, basename);
480     
481     return res;
482 }
483
484
485 /*EXTL_DOC
486  * Write \var{tab} in file with basename \var{basename} in the
487  * session directory.
488  */
489 EXTL_EXPORT
490 bool extl_write_savefile(const char *basename, ExtlTab tab)
491 {
492     bool ret=FALSE;
493     char *fname=extl_get_savefile(basename);
494     
495     if(fname!=NULL){
496         ret=extl_serialise(fname, tab);
497         free(fname);
498     }
499     
500     return ret;
501 }
502
503
504 /*}}}*/
505