Import libextl instead of using a submodule
[notion/jeffpc.git] / libextl / readconfig.c
blob756cbdba08d403d8b0a7454d53137023dfa99ea6
1 /*
2 * libextl/readconfig.c
4 * Copyright (c) Tuomo Valkonen 1999-2005.
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.
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
18 #include "readconfig.h"
19 #include "extl.h"
20 #include "private.h"
23 typedef struct{
24 ExtlFn fn;
25 ExtlTab tab;
26 int status;
27 } TryCallParam;
30 /*{{{ Path setup */
33 static char *userdir=NULL;
34 static char *sessiondir=NULL;
35 static char *scriptpath=NULL;
38 bool extl_add_searchdir(const char *dir)
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;
52 return TRUE;
56 bool extl_set_searchpath(const char *path)
58 char *s=NULL;
60 if(path!=NULL){
61 s=extl_scopy(path);
62 if(s==NULL)
63 return FALSE;
66 if(scriptpath!=NULL)
67 free(scriptpath);
69 scriptpath=s;
70 return TRUE;
74 bool extl_set_userdirs(const char *appname)
76 const char *home;
77 char *tmp;
78 int fails=2;
80 if(userdir!=NULL)
81 return FALSE;
83 home=getenv("HOME");
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);
92 libtu_asprintf(&tmp, "%s/.%s/lib", home, appname);
93 if(tmp!=NULL){
94 fails-=extl_add_searchdir(tmp);
95 free(tmp);
99 return (fails==0);
103 bool extl_set_sessiondir(const char *session)
105 char *tmp;
106 bool ret=FALSE;
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;
118 if(tmp==NULL)
119 return FALSE;
121 if(sessiondir!=NULL)
122 free(sessiondir);
124 sessiondir=tmp;
126 return TRUE;
130 const char *extl_userdir()
132 return userdir;
136 const char *extl_sessiondir()
138 return sessiondir;
142 const char *extl_searchpath()
144 return scriptpath;
148 /*}}}*/
151 /*{{{ try_etcpath, do_include, etc. */
154 static int do_try(const char *dir, const char *file, ExtlTryConfigFn *tryfn,
155 void *tryfnparam)
157 char *tmp=NULL;
158 int ret;
160 libtu_asprintf(&tmp, "%s/%s", dir, file);
161 if(tmp==NULL)
162 return EXTL_TRYCONFIG_MEMERROR;
164 ret=tryfn(tmp, tryfnparam);
165 free(tmp);
166 return ret;
170 static int try_dir(const char *const *files, const char *cfdir,
171 ExtlTryConfigFn *tryfn, void *tryfnparam)
173 const char *const *file;
174 int ret, ret2=EXTL_TRYCONFIG_NOTFOUND;
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;
187 return ret2;
191 static int try_etcpath(const char *const *files,
192 ExtlTryConfigFn *tryfn, void *tryfnparam)
194 const char *const *file=NULL;
195 int i, ret, ret2=EXTL_TRYCONFIG_NOTFOUND;
196 char *path, *colon, *dir;
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;
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;
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;
227 if(ret2==EXTL_TRYCONFIG_NOTFOUND)
228 ret2=ret;
231 free(dir);
235 return ret2;
239 static int try_lookup(const char *file, char **ptr)
241 if(access(file, F_OK)!=0)
242 return EXTL_TRYCONFIG_NOTFOUND;
243 *ptr=extl_scopy(file);
244 return (*ptr!=NULL);
248 static int try_load(const char *file, TryCallParam *param)
250 if(access(file, F_OK)!=0)
251 return EXTL_TRYCONFIG_NOTFOUND;
253 if(param->status==1)
254 extl_warn(TR("Falling back to %s."), file);
256 if(!extl_loadfile(file, &(param->fn))){
257 param->status=1;
258 return EXTL_TRYCONFIG_LOAD_FAILED;
261 return EXTL_TRYCONFIG_OK;
265 static int try_call(const char *file, TryCallParam *param)
267 int ret=try_load(file, param);
269 if(ret!=EXTL_TRYCONFIG_OK)
270 return ret;
272 ret=extl_call(param->fn, NULL, NULL);
274 extl_unref_fn(param->fn);
276 return (ret ? EXTL_TRYCONFIG_OK : EXTL_TRYCONFIG_CALL_FAILED);
280 static int try_read_savefile(const char *file, TryCallParam *param)
282 int ret=try_load(file, param);
284 if(ret!=EXTL_TRYCONFIG_OK)
285 return ret;
287 ret=extl_call(param->fn, NULL, "t", &(param->tab));
289 extl_unref_fn(param->fn);
291 return (ret ? EXTL_TRYCONFIG_OK : EXTL_TRYCONFIG_CALL_FAILED);
295 int extl_try_config(const char *fname, const char *cfdir,
296 ExtlTryConfigFn *tryfn, void *tryfnparam,
297 const char *ext1, const char *ext2)
299 char *files[]={NULL, NULL, NULL, NULL};
300 int n=0, ret=EXTL_TRYCONFIG_NOTFOUND, ret2;
301 bool search=FALSE, has_ext;
303 /* Search etcpath only if path is not absolute */
304 search=(fname[0]!='/');
306 /* Build list of files to look for */
307 has_ext=strrchr(fname, '.')>strrchr(fname, '/');
309 if(!has_ext){
310 if(ext1!=NULL){
311 files[n]=extl_scat3(fname, ".", ext1);
312 if(files[n]!=NULL)
313 n++;
316 if(ext2!=NULL){
317 files[n]=extl_scat3(fname, ".", ext2);
318 if(files[n]!=NULL)
319 n++;
323 if(has_ext || !search){
324 files[n]=extl_scopy(fname);
325 if(files[n]!=NULL)
326 n++;
329 /* NOTE for future changes: cfdir must not be scanned first for
330 * user configuration files to take precedence.
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);
344 while(n>0)
345 free(files[--n]);
347 return ret;
351 /*EXTL_DOC
352 * Lookup script \var{file}. If \var{try_in_dir} is set, it is tried
353 * before the standard search path.
355 EXTL_EXPORT
356 char *extl_lookup_script(const char *file, const char *sp)
358 const char *files[]={NULL, NULL};
359 char* tmp=NULL;
361 if(file!=NULL){
362 files[0]=file;
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);
370 return tmp;
373 static int warn_notfound(const char *file, void *param)
375 warn(TR("Tried: '%s'"), file);
377 return EXTL_TRYCONFIG_NOTFOUND;
380 bool extl_read_config(const char *file, const char *sp, bool warn_nx)
382 TryCallParam param;
383 int retval;
385 if(file==NULL)
386 return FALSE;
388 param.status=0;
390 retval=extl_try_config(file, sp, (ExtlTryConfigFn*)try_call, &param,
391 EXTL_COMPILED_EXTENSION, EXTL_EXTENSION);
393 if(retval==EXTL_TRYCONFIG_NOTFOUND && warn_nx){
394 extl_warn(TR("Unable to find '%s.%s' or '%s.%s' on search path..."),
395 file, EXTL_COMPILED_EXTENSION, file, EXTL_EXTENSION);
396 extl_try_config(file, sp, (ExtlTryConfigFn*)warn_notfound, NULL,
397 EXTL_COMPILED_EXTENSION, EXTL_EXTENSION);
400 return (retval==EXTL_TRYCONFIG_OK);
404 bool extl_read_savefile(const char *basename, ExtlTab *tabret)
406 TryCallParam param;
407 int retval;
409 param.status=0;
410 param.tab=extl_table_none();
412 retval=extl_try_config(basename, NULL, (ExtlTryConfigFn*)try_read_savefile,
413 &param, EXTL_EXTENSION, NULL);
415 *tabret=param.tab;
417 return (retval==EXTL_TRYCONFIG_OK);
421 /*EXTL_DOC
422 * Read a savefile.
424 EXTL_EXPORT_AS(extl, read_savefile)
425 ExtlTab extl_extl_read_savefile(const char *basename)
427 ExtlTab tab;
428 if(!extl_read_savefile(basename, &tab))
429 return extl_table_none();
430 return tab;
434 /*}}}*/
437 /*{{{ extl_get_savefile */
440 static bool ensuredir(char *f)
442 char *p;
443 int tryno=0;
444 bool ret=TRUE;
446 if(access(f, F_OK)==0)
447 return TRUE;
449 if(mkdir(f, 0700)==0)
450 return TRUE;
452 p=strrchr(f, '/');
453 if(p==NULL){
454 extl_warn_err_obj(f);
455 return FALSE;
458 *p='\0';
459 if(!ensuredir(f))
460 return FALSE;
461 *p='/';
463 if(mkdir(f, 0700)==0)
464 return TRUE;
466 extl_warn_err_obj(f);
467 return FALSE;
471 /*EXTL_DOC
472 * Get a file name to save (session) data in. The string \var{basename}
473 * should contain no path or extension components.
475 EXTL_EXPORT
476 char *extl_get_savefile(const char *basename)
478 char *res=NULL;
480 if(sessiondir==NULL)
481 return NULL;
483 if(!ensuredir(sessiondir)){
484 extl_warn(TR("Unable to create session directory \"%s\"."),
485 sessiondir);
486 return NULL;
489 libtu_asprintf(&res, "%s/%s." EXTL_EXTENSION, sessiondir, basename);
491 return res;
495 /*EXTL_DOC
496 * Write \var{tab} in file with basename \var{basename} in the
497 * session directory.
499 EXTL_EXPORT
500 bool extl_write_savefile(const char *basename, ExtlTab tab)
502 bool ret=FALSE;
503 char *fname=extl_get_savefile(basename);
505 if(fname!=NULL){
506 ret=extl_serialise(fname, tab);
507 free(fname);
510 return ret;
514 /*}}}*/