1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin
24da2e3ebdSchin /*
25da2e3ebdSchin * string interface to confstr(),pathconf(),sysconf(),sysinfo()
26da2e3ebdSchin * extended to allow some features to be set per-process
27da2e3ebdSchin */
28da2e3ebdSchin
2934f9b3eeSRoland Mainz static const char id[] = "\n@(#)$Id: getconf (AT&T Research) 2009-07-02 $\0\n";
30da2e3ebdSchin
31da2e3ebdSchin #include "univlib.h"
32da2e3ebdSchin
33da2e3ebdSchin #include <ast.h>
34da2e3ebdSchin #include <error.h>
35da2e3ebdSchin #include <fs3d.h>
36da2e3ebdSchin #include <ctype.h>
37da2e3ebdSchin #include <regex.h>
38da2e3ebdSchin #include <proc.h>
39da2e3ebdSchin
40da2e3ebdSchin #include "conftab.h"
41da2e3ebdSchin #include "FEATURE/libpath"
42da2e3ebdSchin
4334f9b3eeSRoland Mainz #ifndef DEBUG_astconf
4434f9b3eeSRoland Mainz #define DEBUG_astconf 0
4534f9b3eeSRoland Mainz #endif
4634f9b3eeSRoland Mainz
47da2e3ebdSchin #ifndef _pth_getconf
48da2e3ebdSchin #undef ASTCONF_system
49da2e3ebdSchin #define ASTCONF_system 0
50da2e3ebdSchin #endif
51da2e3ebdSchin
52da2e3ebdSchin #if _sys_systeminfo
53da2e3ebdSchin # if !_lib_sysinfo
54da2e3ebdSchin # if _lib_systeminfo
55da2e3ebdSchin # define _lib_sysinfo 1
56da2e3ebdSchin # define sysinfo(a,b,c) systeminfo(a,b,c)
57da2e3ebdSchin # else
58da2e3ebdSchin # if _lib_syscall && _sys_syscall
59da2e3ebdSchin # include <sys/syscall.h>
60da2e3ebdSchin # if defined(SYS_systeminfo)
61da2e3ebdSchin # define _lib_sysinfo 1
62da2e3ebdSchin # define sysinfo(a,b,c) syscall(SYS_systeminfo,a,b,c)
63da2e3ebdSchin # endif
64da2e3ebdSchin # endif
65da2e3ebdSchin # endif
66da2e3ebdSchin # endif
67da2e3ebdSchin #else
68da2e3ebdSchin # undef _lib_sysinfo
69da2e3ebdSchin #endif
70da2e3ebdSchin
71da2e3ebdSchin #define CONF_ERROR (CONF_USER<<0)
72da2e3ebdSchin #define CONF_READONLY (CONF_USER<<1)
73da2e3ebdSchin #define CONF_ALLOC (CONF_USER<<2)
747c2fbfb3SApril Chin #define CONF_GLOBAL (CONF_USER<<3)
75da2e3ebdSchin
7634f9b3eeSRoland Mainz #define DEFAULT(o) ((state.std||!dynamic[o].ast)?dynamic[o].std:dynamic[o].ast)
77da2e3ebdSchin #define INITIALIZE() do{if(!state.data)synthesize(NiL,NiL,NiL);}while(0)
7834f9b3eeSRoland Mainz #define STANDARD(v) (streq(v,"standard")||streq(v,"strict")||streq(v,"posix")||streq(v,"xopen"))
79da2e3ebdSchin
80da2e3ebdSchin #define MAXVAL 256
81da2e3ebdSchin
82da2e3ebdSchin #if MAXVAL <= UNIV_SIZE
83da2e3ebdSchin #undef MAXVAL
84da2e3ebdSchin #define MAXVAL (UNIV_SIZE+1)
85da2e3ebdSchin #endif
86da2e3ebdSchin
87da2e3ebdSchin #ifndef _UNIV_DEFAULT
88da2e3ebdSchin #define _UNIV_DEFAULT "att"
89da2e3ebdSchin #endif
90da2e3ebdSchin
91da2e3ebdSchin static char null[1];
92da2e3ebdSchin static char root[2] = "/";
93da2e3ebdSchin
94da2e3ebdSchin typedef struct Feature_s
95da2e3ebdSchin {
96da2e3ebdSchin struct Feature_s*next;
97da2e3ebdSchin const char* name;
98da2e3ebdSchin char* value;
9934f9b3eeSRoland Mainz char* std;
10034f9b3eeSRoland Mainz char* ast;
101da2e3ebdSchin short length;
102da2e3ebdSchin short standard;
1037c2fbfb3SApril Chin unsigned int flags;
104da2e3ebdSchin short op;
105da2e3ebdSchin } Feature_t;
106da2e3ebdSchin
107da2e3ebdSchin typedef struct
108da2e3ebdSchin {
109da2e3ebdSchin Conf_t* conf;
110da2e3ebdSchin const char* name;
1117c2fbfb3SApril Chin unsigned int flags;
112da2e3ebdSchin short call;
113da2e3ebdSchin short standard;
114da2e3ebdSchin short section;
115da2e3ebdSchin } Lookup_t;
116da2e3ebdSchin
117da2e3ebdSchin static Feature_t dynamic[] =
118da2e3ebdSchin {
11934f9b3eeSRoland Mainz #define OP_conformance 0
120da2e3ebdSchin {
12134f9b3eeSRoland Mainz &dynamic[OP_conformance+1],
122da2e3ebdSchin "CONFORMANCE",
123da2e3ebdSchin "ast",
124da2e3ebdSchin "standard",
12534f9b3eeSRoland Mainz "ast",
126da2e3ebdSchin 11,
127da2e3ebdSchin CONF_AST,
128da2e3ebdSchin 0,
129da2e3ebdSchin OP_conformance
130da2e3ebdSchin },
13134f9b3eeSRoland Mainz #define OP_fs_3d 1
132da2e3ebdSchin {
13334f9b3eeSRoland Mainz &dynamic[OP_fs_3d+1],
134da2e3ebdSchin "FS_3D",
135da2e3ebdSchin &null[0],
136da2e3ebdSchin "0",
13734f9b3eeSRoland Mainz 0,
138da2e3ebdSchin 5,
139da2e3ebdSchin CONF_AST,
140da2e3ebdSchin 0,
141da2e3ebdSchin OP_fs_3d
142da2e3ebdSchin },
14334f9b3eeSRoland Mainz #define OP_getconf 2
144da2e3ebdSchin {
14534f9b3eeSRoland Mainz &dynamic[OP_getconf+1],
146da2e3ebdSchin "GETCONF",
147da2e3ebdSchin #ifdef _pth_getconf
148da2e3ebdSchin _pth_getconf,
149da2e3ebdSchin #else
150da2e3ebdSchin &null[0],
151da2e3ebdSchin #endif
152da2e3ebdSchin 0,
15334f9b3eeSRoland Mainz 0,
154da2e3ebdSchin 7,
155da2e3ebdSchin CONF_AST,
156da2e3ebdSchin CONF_READONLY,
157da2e3ebdSchin OP_getconf
158da2e3ebdSchin },
15934f9b3eeSRoland Mainz #define OP_hosttype 3
160da2e3ebdSchin {
16134f9b3eeSRoland Mainz &dynamic[OP_hosttype+1],
162da2e3ebdSchin "HOSTTYPE",
163da2e3ebdSchin HOSTTYPE,
164da2e3ebdSchin 0,
16534f9b3eeSRoland Mainz 0,
166da2e3ebdSchin 8,
167da2e3ebdSchin CONF_AST,
168da2e3ebdSchin CONF_READONLY,
169da2e3ebdSchin OP_hosttype
170da2e3ebdSchin },
17134f9b3eeSRoland Mainz #define OP_libpath 4
172da2e3ebdSchin {
17334f9b3eeSRoland Mainz &dynamic[OP_libpath+1],
174da2e3ebdSchin "LIBPATH",
175da2e3ebdSchin #ifdef CONF_LIBPATH
176da2e3ebdSchin CONF_LIBPATH,
177da2e3ebdSchin #else
178da2e3ebdSchin &null[0],
179da2e3ebdSchin #endif
180da2e3ebdSchin 0,
18134f9b3eeSRoland Mainz 0,
182da2e3ebdSchin 7,
183da2e3ebdSchin CONF_AST,
184da2e3ebdSchin 0,
185da2e3ebdSchin OP_libpath
186da2e3ebdSchin },
18734f9b3eeSRoland Mainz #define OP_libprefix 5
188da2e3ebdSchin {
18934f9b3eeSRoland Mainz &dynamic[OP_libprefix+1],
190da2e3ebdSchin "LIBPREFIX",
191da2e3ebdSchin #ifdef CONF_LIBPREFIX
192da2e3ebdSchin CONF_LIBPREFIX,
193da2e3ebdSchin #else
194da2e3ebdSchin "lib",
195da2e3ebdSchin #endif
196da2e3ebdSchin 0,
19734f9b3eeSRoland Mainz 0,
198da2e3ebdSchin 9,
199da2e3ebdSchin CONF_AST,
200da2e3ebdSchin 0,
201da2e3ebdSchin OP_libprefix
202da2e3ebdSchin },
20334f9b3eeSRoland Mainz #define OP_libsuffix 6
204da2e3ebdSchin {
20534f9b3eeSRoland Mainz &dynamic[OP_libsuffix+1],
206da2e3ebdSchin "LIBSUFFIX",
207da2e3ebdSchin #ifdef CONF_LIBSUFFIX
208da2e3ebdSchin CONF_LIBSUFFIX,
209da2e3ebdSchin #else
210da2e3ebdSchin ".so",
211da2e3ebdSchin #endif
212da2e3ebdSchin 0,
21334f9b3eeSRoland Mainz 0,
214da2e3ebdSchin 9,
215da2e3ebdSchin CONF_AST,
216da2e3ebdSchin 0,
217da2e3ebdSchin OP_libsuffix
218da2e3ebdSchin },
21934f9b3eeSRoland Mainz #define OP_path_attributes 7
220da2e3ebdSchin {
22134f9b3eeSRoland Mainz &dynamic[OP_path_attributes+1],
222da2e3ebdSchin "PATH_ATTRIBUTES",
223da2e3ebdSchin #if _WINIX
224da2e3ebdSchin "c",
225da2e3ebdSchin #else
226da2e3ebdSchin &null[0],
227da2e3ebdSchin #endif
228da2e3ebdSchin &null[0],
22934f9b3eeSRoland Mainz 0,
230da2e3ebdSchin 15,
231da2e3ebdSchin CONF_AST,
232da2e3ebdSchin CONF_READONLY,
233da2e3ebdSchin OP_path_attributes
234da2e3ebdSchin },
23534f9b3eeSRoland Mainz #define OP_path_resolve 8
236da2e3ebdSchin {
23734f9b3eeSRoland Mainz &dynamic[OP_path_resolve+1],
238da2e3ebdSchin "PATH_RESOLVE",
239da2e3ebdSchin &null[0],
24034f9b3eeSRoland Mainz "physical",
241da2e3ebdSchin "metaphysical",
242da2e3ebdSchin 12,
243da2e3ebdSchin CONF_AST,
244da2e3ebdSchin 0,
245da2e3ebdSchin OP_path_resolve
246da2e3ebdSchin },
24734f9b3eeSRoland Mainz #define OP_universe 9
248da2e3ebdSchin {
249da2e3ebdSchin 0,
250da2e3ebdSchin "UNIVERSE",
251da2e3ebdSchin &null[0],
252da2e3ebdSchin "att",
25334f9b3eeSRoland Mainz 0,
254da2e3ebdSchin 8,
255da2e3ebdSchin CONF_AST,
256da2e3ebdSchin 0,
257da2e3ebdSchin OP_universe
258da2e3ebdSchin },
259da2e3ebdSchin {
260da2e3ebdSchin 0
261da2e3ebdSchin }
262da2e3ebdSchin };
263da2e3ebdSchin
264da2e3ebdSchin typedef struct
265da2e3ebdSchin {
266da2e3ebdSchin
267da2e3ebdSchin const char* id;
268da2e3ebdSchin const char* name;
269da2e3ebdSchin Feature_t* features;
270da2e3ebdSchin
27134f9b3eeSRoland Mainz int std;
27234f9b3eeSRoland Mainz
273da2e3ebdSchin /* default initialization from here down */
274da2e3ebdSchin
275da2e3ebdSchin int prefix;
276da2e3ebdSchin int synthesizing;
277da2e3ebdSchin
278da2e3ebdSchin char* data;
279da2e3ebdSchin char* last;
280da2e3ebdSchin
281da2e3ebdSchin Feature_t* recent;
282da2e3ebdSchin
283da2e3ebdSchin Ast_confdisc_f notify;
284da2e3ebdSchin
285da2e3ebdSchin } State_t;
286da2e3ebdSchin
28734f9b3eeSRoland Mainz static State_t state = { "getconf", "_AST_FEATURES", dynamic, -1 };
288da2e3ebdSchin
2897c2fbfb3SApril Chin static char* feature(const char*, const char*, const char*, unsigned int, Error_f);
290da2e3ebdSchin
291da2e3ebdSchin /*
292da2e3ebdSchin * return fmtbuf() copy of s
293da2e3ebdSchin */
294da2e3ebdSchin
295da2e3ebdSchin static char*
buffer(char * s)296da2e3ebdSchin buffer(char* s)
297da2e3ebdSchin {
298da2e3ebdSchin return strcpy(fmtbuf(strlen(s) + 1), s);
299da2e3ebdSchin }
300da2e3ebdSchin
301da2e3ebdSchin /*
302da2e3ebdSchin * synthesize state for fp
303da2e3ebdSchin * fp==0 initializes from getenv(state.name)
304da2e3ebdSchin * value==0 just does lookup
305da2e3ebdSchin * otherwise state is set to value
306da2e3ebdSchin */
307da2e3ebdSchin
308da2e3ebdSchin static char*
synthesize(register Feature_t * fp,const char * path,const char * value)309da2e3ebdSchin synthesize(register Feature_t* fp, const char* path, const char* value)
310da2e3ebdSchin {
311da2e3ebdSchin register char* s;
312da2e3ebdSchin register char* d;
313da2e3ebdSchin register char* v;
31434f9b3eeSRoland Mainz register char* p;
315da2e3ebdSchin register int n;
316da2e3ebdSchin
31734f9b3eeSRoland Mainz #if DEBUG_astconf
3187c2fbfb3SApril Chin if (fp)
3197c2fbfb3SApril Chin error(-2, "astconf synthesize name=%s path=%s value=%s fp=%p%s", fp->name, path, value, fp, state.synthesizing ? " SYNTHESIZING" : "");
3207c2fbfb3SApril Chin #endif
321da2e3ebdSchin if (state.synthesizing)
322da2e3ebdSchin return null;
323da2e3ebdSchin if (!state.data)
324da2e3ebdSchin {
325da2e3ebdSchin char* se;
326da2e3ebdSchin char* de;
327da2e3ebdSchin char* ve;
328da2e3ebdSchin
329da2e3ebdSchin state.prefix = strlen(state.name) + 1;
330da2e3ebdSchin n = state.prefix + 3 * MAXVAL;
331da2e3ebdSchin if (s = getenv(state.name))
332da2e3ebdSchin n += strlen(s) + 1;
333da2e3ebdSchin n = roundof(n, 32);
334da2e3ebdSchin if (!(state.data = newof(0, char, n, 0)))
335da2e3ebdSchin return 0;
336da2e3ebdSchin state.last = state.data + n - 1;
337da2e3ebdSchin strcpy(state.data, state.name);
338da2e3ebdSchin state.data += state.prefix - 1;
339da2e3ebdSchin *state.data++ = '=';
340da2e3ebdSchin if (s)
341da2e3ebdSchin strcpy(state.data, s);
342da2e3ebdSchin ve = state.data;
343da2e3ebdSchin state.synthesizing = 1;
344da2e3ebdSchin for (;;)
345da2e3ebdSchin {
346da2e3ebdSchin for (s = ve; isspace(*s); s++);
347da2e3ebdSchin for (d = s; *d && !isspace(*d); d++);
348da2e3ebdSchin for (se = d; isspace(*d); d++);
349da2e3ebdSchin for (v = d; *v && !isspace(*v); v++);
350da2e3ebdSchin for (de = v; isspace(*v); v++);
351da2e3ebdSchin if (!*v)
352da2e3ebdSchin break;
353da2e3ebdSchin for (ve = v; *ve && !isspace(*ve); ve++);
354da2e3ebdSchin if (*ve)
355da2e3ebdSchin *ve = 0;
356da2e3ebdSchin else
357da2e3ebdSchin ve = 0;
358da2e3ebdSchin *de = 0;
359da2e3ebdSchin *se = 0;
360da2e3ebdSchin feature(s, d, v, 0, 0);
361da2e3ebdSchin *se = ' ';
362da2e3ebdSchin *de = ' ';
363da2e3ebdSchin if (!ve)
364da2e3ebdSchin break;
365da2e3ebdSchin *ve++ = ' ';
366da2e3ebdSchin }
367da2e3ebdSchin state.synthesizing = 0;
368da2e3ebdSchin }
369da2e3ebdSchin if (!fp)
370da2e3ebdSchin return state.data;
371da2e3ebdSchin if (!state.last)
372da2e3ebdSchin {
373da2e3ebdSchin if (!value)
374da2e3ebdSchin return 0;
375da2e3ebdSchin n = strlen(value);
376da2e3ebdSchin goto ok;
377da2e3ebdSchin }
378da2e3ebdSchin s = (char*)fp->name;
379da2e3ebdSchin n = fp->length;
380da2e3ebdSchin d = state.data;
381da2e3ebdSchin for (;;)
382da2e3ebdSchin {
383da2e3ebdSchin while (isspace(*d))
384da2e3ebdSchin d++;
385da2e3ebdSchin if (!*d)
386da2e3ebdSchin break;
387da2e3ebdSchin if (strneq(d, s, n) && isspace(d[n]))
388da2e3ebdSchin {
389da2e3ebdSchin if (!value)
390da2e3ebdSchin {
391da2e3ebdSchin for (d += n + 1; *d && !isspace(*d); d++);
392da2e3ebdSchin for (; isspace(*d); d++);
393da2e3ebdSchin for (s = d; *s && !isspace(*s); s++);
394da2e3ebdSchin n = s - d;
395da2e3ebdSchin value = (const char*)d;
396da2e3ebdSchin goto ok;
397da2e3ebdSchin }
39834f9b3eeSRoland Mainz for (s = p = d + n + 1; *s && !isspace(*s); s++);
399da2e3ebdSchin for (; isspace(*s); s++);
400da2e3ebdSchin for (v = s; *s && !isspace(*s); s++);
401da2e3ebdSchin n = s - v;
40234f9b3eeSRoland Mainz if ((!path || *path == *p && strlen(path) == (v - p - 1) && !memcmp(path, p, v - p - 1)) && strneq(v, value, n))
403da2e3ebdSchin goto ok;
404da2e3ebdSchin for (; isspace(*s); s++);
405da2e3ebdSchin if (*s)
406da2e3ebdSchin for (; *d = *s++; d++);
407da2e3ebdSchin else if (d != state.data)
408da2e3ebdSchin d--;
409da2e3ebdSchin break;
410da2e3ebdSchin }
411da2e3ebdSchin for (; *d && !isspace(*d); d++);
412da2e3ebdSchin for (; isspace(*d); d++);
413da2e3ebdSchin for (; *d && !isspace(*d); d++);
414da2e3ebdSchin for (; isspace(*d); d++);
415da2e3ebdSchin for (; *d && !isspace(*d); d++);
416da2e3ebdSchin }
417da2e3ebdSchin if (!value)
418da2e3ebdSchin {
419da2e3ebdSchin if (!fp->op)
420da2e3ebdSchin {
421da2e3ebdSchin if (fp->flags & CONF_ALLOC)
422da2e3ebdSchin fp->value[0] = 0;
423da2e3ebdSchin else
424da2e3ebdSchin fp->value = null;
425da2e3ebdSchin }
426da2e3ebdSchin return 0;
427da2e3ebdSchin }
428da2e3ebdSchin if (!value[0])
429da2e3ebdSchin value = "0";
430da2e3ebdSchin if (!path || !path[0] || path[0] == '/' && !path[1])
431da2e3ebdSchin path = "-";
432da2e3ebdSchin n += strlen(path) + strlen(value) + 3;
433da2e3ebdSchin if (d + n >= state.last)
434da2e3ebdSchin {
435da2e3ebdSchin int c;
436da2e3ebdSchin int i;
437da2e3ebdSchin
438da2e3ebdSchin i = d - state.data;
439da2e3ebdSchin state.data -= state.prefix;
440da2e3ebdSchin c = n + state.last - state.data + 3 * MAXVAL;
441da2e3ebdSchin c = roundof(c, 32);
442da2e3ebdSchin if (!(state.data = newof(state.data, char, c, 0)))
443da2e3ebdSchin return 0;
444da2e3ebdSchin state.last = state.data + c - 1;
445da2e3ebdSchin state.data += state.prefix;
446da2e3ebdSchin d = state.data + i;
447da2e3ebdSchin }
448da2e3ebdSchin if (d != state.data)
449da2e3ebdSchin *d++ = ' ';
450da2e3ebdSchin for (s = (char*)fp->name; *d = *s++; d++);
451da2e3ebdSchin *d++ = ' ';
452da2e3ebdSchin for (s = (char*)path; *d = *s++; d++);
453da2e3ebdSchin *d++ = ' ';
454da2e3ebdSchin for (s = (char*)value; *d = *s++; d++);
45534f9b3eeSRoland Mainz #if DEBUG_astconf
45634f9b3eeSRoland Mainz error(-3, "astconf synthesize %s", state.data - state.prefix);
45734f9b3eeSRoland Mainz #endif
458da2e3ebdSchin setenviron(state.data - state.prefix);
459da2e3ebdSchin if (state.notify)
460da2e3ebdSchin (*state.notify)(NiL, NiL, state.data - state.prefix);
461da2e3ebdSchin n = s - (char*)value - 1;
462da2e3ebdSchin ok:
463da2e3ebdSchin if (!(fp->flags & CONF_ALLOC))
464da2e3ebdSchin fp->value = 0;
465da2e3ebdSchin if (n == 1 && (*value == '0' || *value == '-'))
466da2e3ebdSchin n = 0;
467da2e3ebdSchin if (!(fp->value = newof(fp->value, char, n, 1)))
468da2e3ebdSchin fp->value = null;
469da2e3ebdSchin else
470da2e3ebdSchin {
471da2e3ebdSchin fp->flags |= CONF_ALLOC;
472da2e3ebdSchin memcpy(fp->value, value, n);
473da2e3ebdSchin fp->value[n] = 0;
474da2e3ebdSchin }
475da2e3ebdSchin return fp->value;
476da2e3ebdSchin }
477da2e3ebdSchin
478da2e3ebdSchin /*
479da2e3ebdSchin * initialize the value for fp
480da2e3ebdSchin * if command!=0 then it is checked for on $PATH
481da2e3ebdSchin * synthesize(fp,path,succeed) called on success
482da2e3ebdSchin * otherwise synthesize(fp,path,fail) called
483da2e3ebdSchin */
484da2e3ebdSchin
485da2e3ebdSchin static void
initialize(register Feature_t * fp,const char * path,const char * command,const char * succeed,const char * fail)486da2e3ebdSchin initialize(register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail)
487da2e3ebdSchin {
488da2e3ebdSchin register char* p;
489da2e3ebdSchin register int ok = 1;
490da2e3ebdSchin
49134f9b3eeSRoland Mainz #if DEBUG_astconf
4927c2fbfb3SApril Chin error(-2, "astconf initialize name=%s path=%s command=%s succeed=%s fail=%s fp=%p%s", fp->name, path, command, succeed, fail, fp, state.synthesizing ? " SYNTHESIZING" : "");
4937c2fbfb3SApril Chin #endif
494da2e3ebdSchin switch (fp->op)
495da2e3ebdSchin {
496da2e3ebdSchin case OP_conformance:
497da2e3ebdSchin ok = getenv("POSIXLY_CORRECT") != 0;
498da2e3ebdSchin break;
499da2e3ebdSchin case OP_hosttype:
500da2e3ebdSchin ok = 1;
501da2e3ebdSchin break;
502da2e3ebdSchin case OP_path_attributes:
503da2e3ebdSchin ok = 1;
504da2e3ebdSchin break;
505da2e3ebdSchin case OP_path_resolve:
506da2e3ebdSchin ok = fs3d(FS3D_TEST);
507da2e3ebdSchin break;
508da2e3ebdSchin case OP_universe:
50934f9b3eeSRoland Mainz ok = streq(_UNIV_DEFAULT, DEFAULT(OP_universe));
510da2e3ebdSchin /*FALLTHROUGH...*/
511da2e3ebdSchin default:
512da2e3ebdSchin if (p = getenv("PATH"))
513da2e3ebdSchin {
514da2e3ebdSchin register int r = 1;
515da2e3ebdSchin register char* d = p;
516da2e3ebdSchin Sfio_t* tmp;
517da2e3ebdSchin
51834f9b3eeSRoland Mainz #if DEBUG_astconf
5197c2fbfb3SApril Chin error(-2, "astconf initialize name=%s ok=%d PATH=%s", fp->name, ok, p);
5207c2fbfb3SApril Chin #endif
521da2e3ebdSchin if (tmp = sfstropen())
522da2e3ebdSchin {
523da2e3ebdSchin for (;;)
524da2e3ebdSchin {
525da2e3ebdSchin switch (*p++)
526da2e3ebdSchin {
527da2e3ebdSchin case 0:
528da2e3ebdSchin break;
529da2e3ebdSchin case ':':
530da2e3ebdSchin if (command && (fp->op != OP_universe || !ok))
531da2e3ebdSchin {
532da2e3ebdSchin if (r = p - d - 1)
533da2e3ebdSchin {
534da2e3ebdSchin sfwrite(tmp, d, r);
535da2e3ebdSchin sfputc(tmp, '/');
536da2e3ebdSchin sfputr(tmp, command, 0);
537da2e3ebdSchin if ((d = sfstruse(tmp)) && !eaccess(d, X_OK))
538da2e3ebdSchin {
539da2e3ebdSchin ok = 1;
540da2e3ebdSchin if (fp->op != OP_universe)
541da2e3ebdSchin break;
542da2e3ebdSchin }
543da2e3ebdSchin }
544da2e3ebdSchin d = p;
545da2e3ebdSchin }
546da2e3ebdSchin r = 1;
547da2e3ebdSchin continue;
548da2e3ebdSchin case '/':
549da2e3ebdSchin if (r)
550da2e3ebdSchin {
551da2e3ebdSchin r = 0;
552da2e3ebdSchin if (fp->op == OP_universe)
553da2e3ebdSchin {
5547c2fbfb3SApril Chin if (p[0] == 'u' && p[1] == 's' && p[2] == 'r' && p[3] == '/')
5557c2fbfb3SApril Chin for (p += 4; *p == '/'; p++);
5567c2fbfb3SApril Chin if (p[0] == 'b' && p[1] == 'i' && p[2] == 'n')
5577c2fbfb3SApril Chin {
5587c2fbfb3SApril Chin for (p += 3; *p == '/'; p++);
5597c2fbfb3SApril Chin if (!*p || *p == ':')
560da2e3ebdSchin break;
561da2e3ebdSchin }
562da2e3ebdSchin }
5637c2fbfb3SApril Chin }
564da2e3ebdSchin if (fp->op == OP_universe)
565da2e3ebdSchin {
5667c2fbfb3SApril Chin if (strneq(p, "xpg", 3) || strneq(p, "5bin", 4))
567da2e3ebdSchin {
568da2e3ebdSchin ok = 1;
569da2e3ebdSchin break;
570da2e3ebdSchin }
571da2e3ebdSchin if (strneq(p, "bsd", 3) || strneq(p, "ucb", 3))
572da2e3ebdSchin {
573da2e3ebdSchin ok = 0;
574da2e3ebdSchin break;
575da2e3ebdSchin }
576da2e3ebdSchin }
577da2e3ebdSchin continue;
578da2e3ebdSchin default:
579da2e3ebdSchin r = 0;
580da2e3ebdSchin continue;
581da2e3ebdSchin }
582da2e3ebdSchin break;
583da2e3ebdSchin }
584da2e3ebdSchin sfclose(tmp);
585da2e3ebdSchin }
586da2e3ebdSchin else
587da2e3ebdSchin ok = 1;
588da2e3ebdSchin }
589da2e3ebdSchin break;
590da2e3ebdSchin }
59134f9b3eeSRoland Mainz #if DEBUG_astconf
59234f9b3eeSRoland Mainz error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s ok=%d", __LINE__, state.std, fp->name, ok ? succeed : fail, fp->std, fp->ast, fp->value, ok);
59334f9b3eeSRoland Mainz #endif
594da2e3ebdSchin synthesize(fp, path, ok ? succeed : fail);
595da2e3ebdSchin }
596da2e3ebdSchin
597da2e3ebdSchin /*
598da2e3ebdSchin * format synthesized value
599da2e3ebdSchin */
600da2e3ebdSchin
601da2e3ebdSchin static char*
format(register Feature_t * fp,const char * path,const char * value,unsigned int flags,Error_f conferror)6027c2fbfb3SApril Chin format(register Feature_t* fp, const char* path, const char* value, unsigned int flags, Error_f conferror)
603da2e3ebdSchin {
604da2e3ebdSchin register Feature_t* sp;
605da2e3ebdSchin register int n;
606da2e3ebdSchin
60734f9b3eeSRoland Mainz #if DEBUG_astconf
6087c2fbfb3SApril Chin error(-2, "astconf format name=%s path=%s value=%s flags=%04x fp=%p%s", fp->name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
6097c2fbfb3SApril Chin #endif
6107c2fbfb3SApril Chin if (value)
6117c2fbfb3SApril Chin fp->flags &= ~CONF_GLOBAL;
6127c2fbfb3SApril Chin else if (fp->flags & CONF_GLOBAL)
6137c2fbfb3SApril Chin return fp->value;
614da2e3ebdSchin switch (fp->op)
615da2e3ebdSchin {
616da2e3ebdSchin
617da2e3ebdSchin case OP_conformance:
61834f9b3eeSRoland Mainz if (value && STANDARD(value))
61934f9b3eeSRoland Mainz value = fp->std;
62034f9b3eeSRoland Mainz n = state.std = streq(fp->value, fp->std);
62134f9b3eeSRoland Mainz #if DEBUG_astconf
62234f9b3eeSRoland Mainz error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s", __LINE__, state.std, fp->name, value, fp->std, fp->ast, fp->value);
62334f9b3eeSRoland Mainz #endif
624da2e3ebdSchin if (!synthesize(fp, path, value))
62534f9b3eeSRoland Mainz initialize(fp, path, NiL, fp->std, fp->value);
62634f9b3eeSRoland Mainz #if DEBUG_astconf
62734f9b3eeSRoland Mainz error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s", __LINE__, state.std, fp->name, value, fp->std, fp->ast, fp->value);
62834f9b3eeSRoland Mainz #endif
62934f9b3eeSRoland Mainz if (!n && STANDARD(fp->value))
63034f9b3eeSRoland Mainz {
63134f9b3eeSRoland Mainz state.std = 1;
632da2e3ebdSchin for (sp = state.features; sp; sp = sp->next)
63334f9b3eeSRoland Mainz if (sp->std && sp->op && sp->op != OP_conformance)
63434f9b3eeSRoland Mainz astconf(sp->name, path, sp->std);
63534f9b3eeSRoland Mainz }
63634f9b3eeSRoland Mainz #if DEBUG_astconf
63734f9b3eeSRoland Mainz error(-1, "AHA#%d state.std=%d %s [%s] std=%s ast=%s value=%s", __LINE__, state.std, fp->name, value, fp->std, fp->ast, fp->value);
63834f9b3eeSRoland Mainz #endif
639da2e3ebdSchin break;
640da2e3ebdSchin
641da2e3ebdSchin case OP_fs_3d:
642da2e3ebdSchin fp->value = fs3d(value ? value[0] ? FS3D_ON : FS3D_OFF : FS3D_TEST) ? "1" : null;
643da2e3ebdSchin break;
644da2e3ebdSchin
645da2e3ebdSchin case OP_hosttype:
646da2e3ebdSchin break;
647da2e3ebdSchin
648da2e3ebdSchin case OP_path_attributes:
649da2e3ebdSchin #ifdef _PC_PATH_ATTRIBUTES
650da2e3ebdSchin {
651da2e3ebdSchin register char* s;
652da2e3ebdSchin register char* e;
653da2e3ebdSchin intmax_t v;
654da2e3ebdSchin
655da2e3ebdSchin /*
656da2e3ebdSchin * _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
657da2e3ebdSchin */
658da2e3ebdSchin
659da2e3ebdSchin if ((v = pathconf(path, _PC_PATH_ATTRIBUTES)) == -1L)
660da2e3ebdSchin return 0;
661da2e3ebdSchin s = fp->value;
662da2e3ebdSchin e = s + sizeof(fp->value) - 1;
663da2e3ebdSchin for (n = 'a'; n <= 'z'; n++)
664da2e3ebdSchin if (v & (1 << (n - 'a')))
665da2e3ebdSchin {
666da2e3ebdSchin *s++ = n;
667da2e3ebdSchin if (s >= e)
668da2e3ebdSchin break;
669da2e3ebdSchin }
670da2e3ebdSchin *s = 0;
671da2e3ebdSchin }
672da2e3ebdSchin #endif
673da2e3ebdSchin break;
674da2e3ebdSchin
675da2e3ebdSchin case OP_path_resolve:
676da2e3ebdSchin if (!synthesize(fp, path, value))
67734f9b3eeSRoland Mainz initialize(fp, path, NiL, "logical", DEFAULT(OP_path_resolve));
678da2e3ebdSchin break;
679da2e3ebdSchin
680da2e3ebdSchin case OP_universe:
681da2e3ebdSchin #if _lib_universe
682da2e3ebdSchin if (getuniverse(fp->value) < 0)
68334f9b3eeSRoland Mainz strcpy(fp->value, DEFAULT(OP_universe));
684da2e3ebdSchin if (value)
685da2e3ebdSchin setuniverse(value);
686da2e3ebdSchin #else
687da2e3ebdSchin #ifdef UNIV_MAX
688da2e3ebdSchin n = 0;
689da2e3ebdSchin if (value)
690da2e3ebdSchin {
691da2e3ebdSchin while (n < univ_max && !streq(value, univ_name[n])
692da2e3ebdSchin n++;
693da2e3ebdSchin if (n >= univ_max)
694da2e3ebdSchin {
695da2e3ebdSchin if (conferror)
696da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: %s: universe value too large", fp->name, value);
697da2e3ebdSchin return 0;
698da2e3ebdSchin }
699da2e3ebdSchin }
700da2e3ebdSchin #ifdef ATT_UNIV
701da2e3ebdSchin n = setuniverse(n + 1);
702da2e3ebdSchin if (!value && n > 0)
703da2e3ebdSchin setuniverse(n);
704da2e3ebdSchin #else
705da2e3ebdSchin n = universe(value ? n + 1 : U_GET);
706da2e3ebdSchin #endif
707da2e3ebdSchin if (n <= 0 || n >= univ_max)
708da2e3ebdSchin n = 1;
709da2e3ebdSchin strcpy(fp->value, univ_name[n - 1]);
710da2e3ebdSchin #else
7117c2fbfb3SApril Chin if (value && streq(path, "="))
71234f9b3eeSRoland Mainz {
71334f9b3eeSRoland Mainz if (state.synthesizing)
71434f9b3eeSRoland Mainz {
71534f9b3eeSRoland Mainz if (!(fp->flags & CONF_ALLOC))
71634f9b3eeSRoland Mainz fp->value = 0;
71734f9b3eeSRoland Mainz n = strlen(value);
71834f9b3eeSRoland Mainz if (!(fp->value = newof(fp->value, char, n, 1)))
71934f9b3eeSRoland Mainz fp->value = null;
7207c2fbfb3SApril Chin else
72134f9b3eeSRoland Mainz {
72234f9b3eeSRoland Mainz fp->flags |= CONF_ALLOC;
72334f9b3eeSRoland Mainz memcpy(fp->value, value, n);
72434f9b3eeSRoland Mainz fp->value[n] = 0;
72534f9b3eeSRoland Mainz }
72634f9b3eeSRoland Mainz }
72734f9b3eeSRoland Mainz else
72834f9b3eeSRoland Mainz synthesize(fp, path, value);
72934f9b3eeSRoland Mainz }
73034f9b3eeSRoland Mainz else
73134f9b3eeSRoland Mainz initialize(fp, path, "echo", DEFAULT(OP_universe), "ucb");
732da2e3ebdSchin #endif
733da2e3ebdSchin #endif
734da2e3ebdSchin break;
735da2e3ebdSchin
736da2e3ebdSchin default:
737da2e3ebdSchin synthesize(fp, path, value);
738da2e3ebdSchin break;
739da2e3ebdSchin
740da2e3ebdSchin }
7417c2fbfb3SApril Chin if (streq(path, "="))
7427c2fbfb3SApril Chin fp->flags |= CONF_GLOBAL;
743da2e3ebdSchin return fp->value;
744da2e3ebdSchin }
745da2e3ebdSchin
746da2e3ebdSchin /*
747da2e3ebdSchin * value==0 get feature name
748da2e3ebdSchin * value!=0 set feature name
749da2e3ebdSchin * 0 returned if error or not defined; otherwise previous value
750da2e3ebdSchin */
751da2e3ebdSchin
752da2e3ebdSchin static char*
7537c2fbfb3SApril Chin feature(const char* name, const char* path, const char* value, unsigned int flags, Error_f conferror)
754da2e3ebdSchin {
755da2e3ebdSchin register Feature_t* fp;
756da2e3ebdSchin register int n;
757da2e3ebdSchin
758da2e3ebdSchin if (value && (streq(value, "-") || streq(value, "0")))
759da2e3ebdSchin value = null;
760da2e3ebdSchin for (fp = state.features; fp && !streq(fp->name, name); fp = fp->next);
76134f9b3eeSRoland Mainz #if DEBUG_astconf
7627c2fbfb3SApril Chin error(-2, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p%s", name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
763da2e3ebdSchin #endif
764da2e3ebdSchin if (!fp)
765da2e3ebdSchin {
766da2e3ebdSchin if (!value)
767da2e3ebdSchin return 0;
768da2e3ebdSchin if (state.notify && !(*state.notify)(name, path, value))
769da2e3ebdSchin return 0;
770da2e3ebdSchin n = strlen(name);
771da2e3ebdSchin if (!(fp = newof(0, Feature_t, 1, n + 1)))
772da2e3ebdSchin {
773da2e3ebdSchin if (conferror)
774da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: out of space", name);
775da2e3ebdSchin return 0;
776da2e3ebdSchin }
77734f9b3eeSRoland Mainz fp->op = -1;
778da2e3ebdSchin fp->name = (const char*)fp + sizeof(Feature_t);
779da2e3ebdSchin strcpy((char*)fp->name, name);
780da2e3ebdSchin fp->length = n;
78134f9b3eeSRoland Mainz fp->std = &null[0];
782da2e3ebdSchin fp->next = state.features;
783da2e3ebdSchin state.features = fp;
784da2e3ebdSchin }
785da2e3ebdSchin else if (value)
786da2e3ebdSchin {
787da2e3ebdSchin if (fp->flags & CONF_READONLY)
788da2e3ebdSchin {
789da2e3ebdSchin if (conferror)
790da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: cannot set readonly symbol", fp->name);
791da2e3ebdSchin return 0;
792da2e3ebdSchin }
793da2e3ebdSchin if (state.notify && !streq(fp->value, value) && !(*state.notify)(name, path, value))
794da2e3ebdSchin return 0;
795da2e3ebdSchin }
796da2e3ebdSchin else
797da2e3ebdSchin state.recent = fp;
798da2e3ebdSchin return format(fp, path, value, flags, conferror);
799da2e3ebdSchin }
800da2e3ebdSchin
801da2e3ebdSchin /*
802da2e3ebdSchin * binary search for name in conf[]
803da2e3ebdSchin */
804da2e3ebdSchin
805da2e3ebdSchin static int
8067c2fbfb3SApril Chin lookup(register Lookup_t* look, const char* name, unsigned int flags)
807da2e3ebdSchin {
808da2e3ebdSchin register Conf_t* mid = (Conf_t*)conf;
809da2e3ebdSchin register Conf_t* lo = mid;
810da2e3ebdSchin register Conf_t* hi = mid + conf_elements;
811da2e3ebdSchin register int v;
812da2e3ebdSchin register int c;
813da2e3ebdSchin char* e;
814da2e3ebdSchin const Prefix_t* p;
815da2e3ebdSchin
816da2e3ebdSchin static Conf_t num;
817da2e3ebdSchin
818da2e3ebdSchin look->flags = 0;
819da2e3ebdSchin look->call = -1;
820da2e3ebdSchin look->standard = (flags & ASTCONF_AST) ? CONF_AST : -1;
821da2e3ebdSchin look->section = -1;
822da2e3ebdSchin while (*name == '_')
823da2e3ebdSchin name++;
824da2e3ebdSchin again:
825da2e3ebdSchin for (p = prefix; p < &prefix[prefix_elements]; p++)
8267c2fbfb3SApril Chin if (strneq(name, p->name, p->length) && ((c = name[p->length] == '_' || name[p->length] == '(' || name[p->length] == '#') || (v = isdigit(name[p->length]) && name[p->length + 1] == '_')))
827da2e3ebdSchin {
828da2e3ebdSchin if (p->call < 0)
829da2e3ebdSchin {
830da2e3ebdSchin if (look->standard >= 0)
831da2e3ebdSchin break;
832da2e3ebdSchin look->standard = p->standard;
833da2e3ebdSchin }
834da2e3ebdSchin else
835da2e3ebdSchin {
836da2e3ebdSchin if (look->call >= 0)
837da2e3ebdSchin break;
838da2e3ebdSchin look->call = p->call;
839da2e3ebdSchin }
8407c2fbfb3SApril Chin if (name[p->length] == '(' || name[p->length] == '#')
841da2e3ebdSchin {
842da2e3ebdSchin look->conf = #
843da2e3ebdSchin strncpy((char*)num.name, name, sizeof(num.name));
844da2e3ebdSchin num.call = p->call;
845da2e3ebdSchin num.flags = *name == 'C' ? CONF_STRING : 0;
846da2e3ebdSchin num.op = (short)strtol(name + p->length + 1, &e, 10);
8477c2fbfb3SApril Chin if (name[p->length] == '(' && *e == ')')
8487c2fbfb3SApril Chin e++;
8497c2fbfb3SApril Chin if (*e)
850da2e3ebdSchin break;
851da2e3ebdSchin return 1;
852da2e3ebdSchin }
853da2e3ebdSchin name += p->length + c;
854da2e3ebdSchin if (look->section < 0 && !c && v)
855da2e3ebdSchin {
856da2e3ebdSchin look->section = name[0] - '0';
857da2e3ebdSchin name += 2;
858da2e3ebdSchin }
859da2e3ebdSchin goto again;
860da2e3ebdSchin }
861da2e3ebdSchin #if HUH_2006_02_10
862da2e3ebdSchin if (look->section < 0)
863da2e3ebdSchin look->section = 1;
864da2e3ebdSchin #endif
865da2e3ebdSchin look->name = name;
86634f9b3eeSRoland Mainz #if DEBUG_astconf
867da2e3ebdSchin error(-2, "astconf normal name=%s standard=%d section=%d call=%d flags=%04x elements=%d", look->name, look->standard, look->section, look->call, flags, conf_elements);
868da2e3ebdSchin #endif
869da2e3ebdSchin c = *((unsigned char*)name);
870da2e3ebdSchin while (lo <= hi)
871da2e3ebdSchin {
872da2e3ebdSchin mid = lo + (hi - lo) / 2;
87334f9b3eeSRoland Mainz #if DEBUG_astconf
874da2e3ebdSchin error(-3, "astconf lookup name=%s mid=%s", name, mid->name);
875da2e3ebdSchin #endif
876da2e3ebdSchin if (!(v = c - *((unsigned char*)mid->name)) && !(v = strcmp(name, mid->name)))
877da2e3ebdSchin {
878da2e3ebdSchin hi = mid;
879da2e3ebdSchin lo = (Conf_t*)conf;
880da2e3ebdSchin do
881da2e3ebdSchin {
882da2e3ebdSchin if ((look->standard < 0 || look->standard == mid->standard) &&
883da2e3ebdSchin (look->section < 0 || look->section == mid->section) &&
884da2e3ebdSchin (look->call < 0 || look->call == mid->call))
885da2e3ebdSchin goto found;
886da2e3ebdSchin } while (mid-- > lo && streq(mid->name, look->name));
887da2e3ebdSchin mid = hi;
888da2e3ebdSchin hi = lo + conf_elements - 1;
889da2e3ebdSchin while (++mid < hi && streq(mid->name, look->name))
890da2e3ebdSchin {
891da2e3ebdSchin if ((look->standard < 0 || look->standard == mid->standard) &&
892da2e3ebdSchin (look->section < 0 || look->section == mid->section) &&
893da2e3ebdSchin (look->call < 0 || look->call == mid->call))
894da2e3ebdSchin goto found;
895da2e3ebdSchin }
896da2e3ebdSchin break;
897da2e3ebdSchin }
898da2e3ebdSchin else if (v > 0)
899da2e3ebdSchin lo = mid + 1;
900da2e3ebdSchin else
901da2e3ebdSchin hi = mid - 1;
902da2e3ebdSchin }
903da2e3ebdSchin return 0;
904da2e3ebdSchin found:
905da2e3ebdSchin if (look->call < 0 && look->standard >= 0 && (look->section <= 1 || (mid->flags & CONF_MINMAX)))
906da2e3ebdSchin look->flags |= CONF_MINMAX;
907da2e3ebdSchin look->conf = mid;
90834f9b3eeSRoland Mainz #if DEBUG_astconf
909da2e3ebdSchin error(-2, "astconf lookup name=%s standard=%d:%d section=%d:%d call=%d:%d", look->name, look->standard, mid->standard, look->section, mid->section, look->call, mid->call);
910da2e3ebdSchin #endif
911da2e3ebdSchin return 1;
912da2e3ebdSchin }
913da2e3ebdSchin
914da2e3ebdSchin /*
915da2e3ebdSchin * return a tolower'd copy of s
916da2e3ebdSchin */
917da2e3ebdSchin
918da2e3ebdSchin static char*
919da2e3ebdSchin fmtlower(register const char* s)
920da2e3ebdSchin {
921da2e3ebdSchin register int c;
922da2e3ebdSchin register char* t;
923da2e3ebdSchin char* b;
924da2e3ebdSchin
925da2e3ebdSchin b = t = fmtbuf(strlen(s) + 1);
926da2e3ebdSchin while (c = *s++)
927da2e3ebdSchin {
928da2e3ebdSchin if (isupper(c))
929da2e3ebdSchin c = tolower(c);
930da2e3ebdSchin *t++ = c;
931da2e3ebdSchin }
932da2e3ebdSchin *t = 0;
933da2e3ebdSchin return b;
934da2e3ebdSchin }
935da2e3ebdSchin
936da2e3ebdSchin /*
937da2e3ebdSchin * print value line for p
938da2e3ebdSchin * if !name then value prefixed by "p->name="
939da2e3ebdSchin * if (flags & CONF_MINMAX) then default minmax value used
940da2e3ebdSchin */
941da2e3ebdSchin
942da2e3ebdSchin static char*
943da2e3ebdSchin print(Sfio_t* sp, register Lookup_t* look, const char* name, const char* path, int listflags, Error_f conferror)
944da2e3ebdSchin {
945da2e3ebdSchin register Conf_t* p = look->conf;
9467c2fbfb3SApril Chin register unsigned int flags = look->flags;
947da2e3ebdSchin char* call;
948da2e3ebdSchin char* f;
949da2e3ebdSchin const char* s;
950da2e3ebdSchin int i;
9517c2fbfb3SApril Chin int n;
952da2e3ebdSchin int olderrno;
953da2e3ebdSchin int drop;
954da2e3ebdSchin int defined;
955da2e3ebdSchin intmax_t v;
956da2e3ebdSchin char buf[PATH_MAX];
957da2e3ebdSchin char flg[16];
958da2e3ebdSchin
959da2e3ebdSchin if (!name && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_LIMIT|CONF_MINMAX)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
960da2e3ebdSchin flags |= CONF_PREFIXED;
961da2e3ebdSchin olderrno = errno;
962da2e3ebdSchin errno = 0;
96334f9b3eeSRoland Mainz #if DEBUG_astconf
96434f9b3eeSRoland Mainz error(-1, "astconf name=%s:%s:%s standard=%d section=%d call=%s op=%d flags=|%s%s%s%s%s:|%s%s%s%s%s%s%s%s%s%s"
96534f9b3eeSRoland Mainz , name, look->name, p->name, p->standard, p->section, prefix[p->call + CONF_call].name, p->op
966da2e3ebdSchin , (flags & CONF_FEATURE) ? "FEATURE|" : ""
967da2e3ebdSchin , (flags & CONF_LIMIT) ? "LIMIT|" : ""
968da2e3ebdSchin , (flags & CONF_MINMAX) ? "MINMAX|" : ""
969da2e3ebdSchin , (flags & CONF_PREFIXED) ? "PREFIXED|" : ""
970da2e3ebdSchin , (flags & CONF_STRING) ? "STRING|" : ""
971da2e3ebdSchin , (p->flags & CONF_DEFER_CALL) ? "DEFER_CALL|" : ""
972da2e3ebdSchin , (p->flags & CONF_DEFER_MM) ? "DEFER_MM|" : ""
973da2e3ebdSchin , (p->flags & CONF_FEATURE) ? "FEATURE|" : ""
974da2e3ebdSchin , (p->flags & CONF_LIMIT_DEF) ? "LIMIT_DEF|" : (p->flags & CONF_LIMIT) ? "LIMIT|" : ""
975da2e3ebdSchin , (p->flags & CONF_MINMAX_DEF) ? "MINMAX_DEF|" : (p->flags & CONF_MINMAX) ? "MINMAX|" : ""
976da2e3ebdSchin , (p->flags & CONF_NOUNDERSCORE) ? "NOUNDERSCORE|" : ""
977da2e3ebdSchin , (p->flags & CONF_PREFIXED) ? "PREFIXED|" : ""
978da2e3ebdSchin , (p->flags & CONF_PREFIX_ONLY) ? "PREFIX_ONLY|" : ""
979da2e3ebdSchin , (p->flags & CONF_STANDARD) ? "STANDARD|" : ""
980da2e3ebdSchin , (p->flags & CONF_STRING) ? "STRING|" : ""
981da2e3ebdSchin , (p->flags & CONF_UNDERSCORE) ? "UNDERSCORE|" : ""
982da2e3ebdSchin );
983da2e3ebdSchin #endif
984da2e3ebdSchin flags |= CONF_LIMIT_DEF|CONF_MINMAX_DEF;
985da2e3ebdSchin if (conferror && name)
986da2e3ebdSchin {
987da2e3ebdSchin if ((p->flags & CONF_PREFIX_ONLY) && look->standard < 0)
988da2e3ebdSchin goto bad;
989da2e3ebdSchin if (!(flags & CONF_MINMAX) || !(p->flags & CONF_MINMAX))
990da2e3ebdSchin {
991da2e3ebdSchin switch (p->call)
992da2e3ebdSchin {
993da2e3ebdSchin case CONF_pathconf:
994da2e3ebdSchin if (path == root)
995da2e3ebdSchin {
996da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: path expected", name);
997da2e3ebdSchin goto bad;
998da2e3ebdSchin }
999da2e3ebdSchin break;
1000da2e3ebdSchin default:
1001da2e3ebdSchin if (path != root)
1002da2e3ebdSchin {
1003da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: path not expected", name);
1004da2e3ebdSchin goto bad;
1005da2e3ebdSchin }
1006da2e3ebdSchin break;
1007da2e3ebdSchin }
1008da2e3ebdSchin #ifdef _pth_getconf
1009da2e3ebdSchin if (p->flags & CONF_DEFER_CALL)
1010da2e3ebdSchin goto bad;
1011da2e3ebdSchin #endif
1012da2e3ebdSchin }
1013da2e3ebdSchin else
1014da2e3ebdSchin {
1015da2e3ebdSchin if (path != root)
1016da2e3ebdSchin {
1017da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: path not expected", name);
1018da2e3ebdSchin goto bad;
1019da2e3ebdSchin }
1020da2e3ebdSchin #ifdef _pth_getconf
1021da2e3ebdSchin if ((p->flags & CONF_DEFER_MM) || !(p->flags & CONF_MINMAX_DEF))
1022da2e3ebdSchin goto bad;
1023da2e3ebdSchin #endif
1024da2e3ebdSchin }
1025da2e3ebdSchin if (look->standard >= 0 && (name[0] != '_' && ((p->flags & CONF_UNDERSCORE) || look->section <= 1) || name[0] == '_' && (p->flags & CONF_NOUNDERSCORE)) || look->standard < 0 && name[0] == '_')
1026da2e3ebdSchin goto bad;
1027da2e3ebdSchin }
1028da2e3ebdSchin s = 0;
1029da2e3ebdSchin defined = 1;
1030da2e3ebdSchin switch (i = (p->op < 0 || (flags & CONF_MINMAX) && (p->flags & CONF_MINMAX_DEF)) ? 0 : p->call)
1031da2e3ebdSchin {
1032da2e3ebdSchin case CONF_confstr:
1033da2e3ebdSchin call = "confstr";
1034da2e3ebdSchin #if _lib_confstr
1035da2e3ebdSchin if (!(v = confstr(p->op, buf, sizeof(buf))))
1036da2e3ebdSchin {
1037da2e3ebdSchin defined = 0;
1038da2e3ebdSchin v = -1;
1039da2e3ebdSchin errno = EINVAL;
1040da2e3ebdSchin }
1041da2e3ebdSchin else if (v > 0)
1042da2e3ebdSchin {
1043da2e3ebdSchin buf[sizeof(buf) - 1] = 0;
1044da2e3ebdSchin s = (const char*)buf;
1045da2e3ebdSchin }
1046da2e3ebdSchin else
1047da2e3ebdSchin defined = 0;
1048da2e3ebdSchin break;
1049da2e3ebdSchin #else
1050da2e3ebdSchin goto predef;
1051da2e3ebdSchin #endif
1052da2e3ebdSchin case CONF_pathconf:
1053da2e3ebdSchin call = "pathconf";
1054da2e3ebdSchin #if _lib_pathconf
1055da2e3ebdSchin if ((v = pathconf(path, p->op)) < 0)
1056da2e3ebdSchin defined = 0;
1057da2e3ebdSchin break;
1058da2e3ebdSchin #else
1059da2e3ebdSchin goto predef;
1060da2e3ebdSchin #endif
1061da2e3ebdSchin case CONF_sysconf:
1062da2e3ebdSchin call = "sysconf";
1063da2e3ebdSchin #if _lib_sysconf
1064da2e3ebdSchin if ((v = sysconf(p->op)) < 0)
1065da2e3ebdSchin defined = 0;
1066da2e3ebdSchin break;
1067da2e3ebdSchin #else
1068da2e3ebdSchin goto predef;
1069da2e3ebdSchin #endif
1070da2e3ebdSchin case CONF_sysinfo:
1071da2e3ebdSchin call = "sysinfo";
1072da2e3ebdSchin #if _lib_sysinfo
1073da2e3ebdSchin if ((v = sysinfo(p->op, buf, sizeof(buf))) >= 0)
1074da2e3ebdSchin {
1075da2e3ebdSchin buf[sizeof(buf) - 1] = 0;
1076da2e3ebdSchin s = (const char*)buf;
1077da2e3ebdSchin }
1078da2e3ebdSchin else
1079da2e3ebdSchin defined = 0;
1080da2e3ebdSchin break;
1081da2e3ebdSchin #else
1082da2e3ebdSchin goto predef;
1083da2e3ebdSchin #endif
1084da2e3ebdSchin default:
1085da2e3ebdSchin call = "synthesis";
1086da2e3ebdSchin errno = EINVAL;
1087da2e3ebdSchin v = -1;
1088da2e3ebdSchin defined = 0;
1089da2e3ebdSchin break;
1090da2e3ebdSchin case 0:
1091da2e3ebdSchin call = 0;
10927c2fbfb3SApril Chin if (p->standard == CONF_AST)
10937c2fbfb3SApril Chin {
109434f9b3eeSRoland Mainz if (streq(p->name, "RELEASE") && (i = open("/proc/version", O_RDONLY)) >= 0)
10957c2fbfb3SApril Chin {
10967c2fbfb3SApril Chin n = read(i, buf, sizeof(buf) - 1);
10977c2fbfb3SApril Chin close(i);
10987c2fbfb3SApril Chin if (n > 0 && buf[n - 1] == '\n')
10997c2fbfb3SApril Chin n--;
11007c2fbfb3SApril Chin if (n > 0 && buf[n - 1] == '\r')
11017c2fbfb3SApril Chin n--;
11027c2fbfb3SApril Chin buf[n] = 0;
11037c2fbfb3SApril Chin if (buf[0])
11047c2fbfb3SApril Chin {
11057c2fbfb3SApril Chin v = 0;
11067c2fbfb3SApril Chin s = buf;
11077c2fbfb3SApril Chin break;
11087c2fbfb3SApril Chin }
11097c2fbfb3SApril Chin }
11107c2fbfb3SApril Chin }
1111da2e3ebdSchin if (p->flags & CONF_MINMAX_DEF)
1112da2e3ebdSchin {
1113da2e3ebdSchin if (!((p->flags & CONF_LIMIT_DEF)))
1114da2e3ebdSchin flags |= CONF_MINMAX;
1115da2e3ebdSchin listflags &= ~ASTCONF_system;
1116da2e3ebdSchin }
1117da2e3ebdSchin predef:
1118da2e3ebdSchin if (look->standard == CONF_AST)
1119da2e3ebdSchin {
112034f9b3eeSRoland Mainz if (streq(p->name, "VERSION"))
1121da2e3ebdSchin {
1122*3e14f97fSRoger A. Faulkner v = ast.version;
1123da2e3ebdSchin break;
1124da2e3ebdSchin }
1125da2e3ebdSchin }
1126da2e3ebdSchin if (flags & CONF_MINMAX)
1127da2e3ebdSchin {
1128da2e3ebdSchin if ((p->flags & CONF_MINMAX_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_MM)))
1129da2e3ebdSchin {
1130da2e3ebdSchin v = p->minmax.number;
1131da2e3ebdSchin s = p->minmax.string;
1132da2e3ebdSchin break;
1133da2e3ebdSchin }
1134da2e3ebdSchin }
1135da2e3ebdSchin else if ((p->flags & CONF_LIMIT_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_CALL)))
1136da2e3ebdSchin {
1137da2e3ebdSchin v = p->limit.number;
1138da2e3ebdSchin s = p->limit.string;
1139da2e3ebdSchin break;
1140da2e3ebdSchin }
1141da2e3ebdSchin flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1142da2e3ebdSchin v = -1;
1143da2e3ebdSchin errno = EINVAL;
1144da2e3ebdSchin defined = 0;
1145da2e3ebdSchin break;
1146da2e3ebdSchin }
1147da2e3ebdSchin if (!defined)
1148da2e3ebdSchin {
1149da2e3ebdSchin if (!errno)
1150da2e3ebdSchin {
1151da2e3ebdSchin if ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX)))
1152da2e3ebdSchin flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1153da2e3ebdSchin }
1154da2e3ebdSchin else if (flags & CONF_PREFIXED)
1155da2e3ebdSchin flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1156da2e3ebdSchin else if (errno != EINVAL || !i)
1157da2e3ebdSchin {
1158da2e3ebdSchin if (!sp)
1159da2e3ebdSchin {
1160da2e3ebdSchin if (conferror)
1161da2e3ebdSchin {
1162da2e3ebdSchin if (call)
1163da2e3ebdSchin (*conferror)(&state, &state, ERROR_SYSTEM|2, "%s: %s error", p->name, call);
1164da2e3ebdSchin else if (!(listflags & ASTCONF_system))
1165da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: unknown name", p->name);
1166da2e3ebdSchin }
1167da2e3ebdSchin goto bad;
1168da2e3ebdSchin }
1169da2e3ebdSchin else
1170da2e3ebdSchin {
1171da2e3ebdSchin flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1172da2e3ebdSchin flags |= CONF_ERROR;
1173da2e3ebdSchin }
1174da2e3ebdSchin }
1175da2e3ebdSchin }
1176da2e3ebdSchin errno = olderrno;
1177da2e3ebdSchin if ((listflags & ASTCONF_defined) && !(flags & (CONF_LIMIT_DEF|CONF_MINMAX_DEF)))
1178da2e3ebdSchin goto bad;
1179da2e3ebdSchin if ((drop = !sp) && !(sp = sfstropen()))
1180da2e3ebdSchin goto bad;
1181da2e3ebdSchin if (listflags & ASTCONF_table)
1182da2e3ebdSchin {
1183da2e3ebdSchin f = flg;
1184da2e3ebdSchin if (p->flags & CONF_DEFER_CALL)
1185da2e3ebdSchin *f++ = 'C';
1186da2e3ebdSchin if (p->flags & CONF_DEFER_MM)
1187da2e3ebdSchin *f++ = 'D';
1188da2e3ebdSchin if (p->flags & CONF_FEATURE)
1189da2e3ebdSchin *f++ = 'F';
1190da2e3ebdSchin if (p->flags & CONF_LIMIT)
1191da2e3ebdSchin *f++ = 'L';
1192da2e3ebdSchin if (p->flags & CONF_MINMAX)
1193da2e3ebdSchin *f++ = 'M';
1194da2e3ebdSchin if (p->flags & CONF_NOSECTION)
1195da2e3ebdSchin *f++ = 'N';
1196da2e3ebdSchin if (p->flags & CONF_PREFIXED)
1197da2e3ebdSchin *f++ = 'P';
1198da2e3ebdSchin if (p->flags & CONF_STANDARD)
1199da2e3ebdSchin *f++ = 'S';
1200da2e3ebdSchin if (p->flags & CONF_UNDERSCORE)
1201da2e3ebdSchin *f++ = 'U';
1202da2e3ebdSchin if (p->flags & CONF_NOUNDERSCORE)
1203da2e3ebdSchin *f++ = 'V';
1204da2e3ebdSchin if (p->flags & CONF_PREFIX_ONLY)
1205da2e3ebdSchin *f++ = 'W';
1206da2e3ebdSchin if (f == flg)
1207da2e3ebdSchin *f++ = 'X';
1208da2e3ebdSchin *f = 0;
1209da2e3ebdSchin sfprintf(sp, "%*s %*s %d %2s %4d %6s ", sizeof(p->name), p->name, sizeof(prefix[p->standard].name), prefix[p->standard].name, p->section, prefix[p->call + CONF_call].name, p->op, flg);
1210da2e3ebdSchin if (p->flags & CONF_LIMIT_DEF)
1211da2e3ebdSchin {
1212da2e3ebdSchin if (p->limit.string)
1213da2e3ebdSchin sfprintf(sp, "L[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->limit.string, "\"", "\"", strlen(p->limit.string), FMT_SHELL) : p->limit.string);
1214da2e3ebdSchin else
1215da2e3ebdSchin sfprintf(sp, "L[%I*d] ", sizeof(p->limit.number), p->limit.number);
1216da2e3ebdSchin }
1217da2e3ebdSchin if (p->flags & CONF_MINMAX_DEF)
1218da2e3ebdSchin {
1219da2e3ebdSchin if (p->minmax.string)
1220da2e3ebdSchin sfprintf(sp, "M[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->minmax.string, "\"", "\"", strlen(p->minmax.string), FMT_SHELL) : p->minmax.string);
1221da2e3ebdSchin else
1222da2e3ebdSchin sfprintf(sp, "M[%I*d] ", sizeof(p->minmax.number), p->minmax.number);
1223da2e3ebdSchin }
1224da2e3ebdSchin if (flags & CONF_ERROR)
1225da2e3ebdSchin sfprintf(sp, "error");
1226da2e3ebdSchin else if (defined)
1227da2e3ebdSchin {
1228da2e3ebdSchin if (s)
1229da2e3ebdSchin sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1230da2e3ebdSchin else if (v != -1)
1231da2e3ebdSchin sfprintf(sp, "%I*d", sizeof(v), v);
1232da2e3ebdSchin else
1233da2e3ebdSchin sfprintf(sp, "%I*u", sizeof(v), v);
1234da2e3ebdSchin }
1235da2e3ebdSchin sfprintf(sp, "\n");
1236da2e3ebdSchin }
1237da2e3ebdSchin else
1238da2e3ebdSchin {
1239da2e3ebdSchin if (!(flags & CONF_PREFIXED) || (listflags & ASTCONF_base))
1240da2e3ebdSchin {
1241da2e3ebdSchin if (!name)
1242da2e3ebdSchin {
1243da2e3ebdSchin if ((p->flags & (CONF_PREFIXED|CONF_STRING)) == (CONF_PREFIXED|CONF_STRING) && (!(listflags & ASTCONF_base) || p->standard != CONF_POSIX))
1244da2e3ebdSchin {
1245da2e3ebdSchin if ((p->flags & CONF_UNDERSCORE) && !(listflags & ASTCONF_base))
1246da2e3ebdSchin sfprintf(sp, "_");
1247da2e3ebdSchin sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1248da2e3ebdSchin if (p->section > 1)
1249da2e3ebdSchin sfprintf(sp, "%d", p->section);
1250da2e3ebdSchin sfprintf(sp, "_");
1251da2e3ebdSchin }
1252da2e3ebdSchin sfprintf(sp, "%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1253da2e3ebdSchin }
1254da2e3ebdSchin if (flags & CONF_ERROR)
1255da2e3ebdSchin sfprintf(sp, "error");
1256da2e3ebdSchin else if (defined)
1257da2e3ebdSchin {
1258da2e3ebdSchin if (s)
1259da2e3ebdSchin sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1260da2e3ebdSchin else if (v != -1)
1261da2e3ebdSchin sfprintf(sp, "%I*d", sizeof(v), v);
1262da2e3ebdSchin else
1263da2e3ebdSchin sfprintf(sp, "%I*u", sizeof(v), v);
1264da2e3ebdSchin }
1265da2e3ebdSchin else
1266da2e3ebdSchin sfprintf(sp, "undefined");
1267da2e3ebdSchin if (!name)
1268da2e3ebdSchin sfprintf(sp, "\n");
1269da2e3ebdSchin }
1270da2e3ebdSchin if (!name && !(listflags & ASTCONF_base) && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
1271da2e3ebdSchin {
1272da2e3ebdSchin if (p->flags & CONF_UNDERSCORE)
1273da2e3ebdSchin sfprintf(sp, "_");
1274da2e3ebdSchin sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1275da2e3ebdSchin if (p->section > 1)
1276da2e3ebdSchin sfprintf(sp, "%d", p->section);
1277da2e3ebdSchin sfprintf(sp, "_%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1278da2e3ebdSchin if (v != -1)
1279da2e3ebdSchin sfprintf(sp, "%I*d", sizeof(v), v);
1280da2e3ebdSchin else if (defined)
1281da2e3ebdSchin sfprintf(sp, "%I*u", sizeof(v), v);
1282da2e3ebdSchin else
1283da2e3ebdSchin sfprintf(sp, "undefined");
1284da2e3ebdSchin sfprintf(sp, "\n");
1285da2e3ebdSchin }
1286da2e3ebdSchin }
1287da2e3ebdSchin if (drop)
1288da2e3ebdSchin {
1289da2e3ebdSchin if (call = sfstruse(sp))
1290da2e3ebdSchin call = buffer(call);
1291da2e3ebdSchin else
1292da2e3ebdSchin call = "[ out of space ]";
1293da2e3ebdSchin sfclose(sp);
1294da2e3ebdSchin return call;
1295da2e3ebdSchin }
1296da2e3ebdSchin bad:
1297da2e3ebdSchin return (listflags & ASTCONF_error) ? (char*)0 : null;
1298da2e3ebdSchin }
1299da2e3ebdSchin
1300da2e3ebdSchin /*
1301da2e3ebdSchin * return read stream to native getconf utility
1302da2e3ebdSchin */
1303da2e3ebdSchin
1304da2e3ebdSchin static Sfio_t*
1305da2e3ebdSchin nativeconf(Proc_t** pp, const char* operand)
1306da2e3ebdSchin {
1307da2e3ebdSchin #ifdef _pth_getconf
1308da2e3ebdSchin Sfio_t* sp;
1309da2e3ebdSchin char* cmd[3];
1310da2e3ebdSchin long ops[2];
1311da2e3ebdSchin
131234f9b3eeSRoland Mainz #if DEBUG_astconf
1313da2e3ebdSchin error(-2, "astconf defer %s %s", _pth_getconf, operand);
1314da2e3ebdSchin #endif
1315da2e3ebdSchin cmd[0] = (char*)state.id;
1316da2e3ebdSchin cmd[1] = (char*)operand;
1317da2e3ebdSchin cmd[2] = 0;
1318da2e3ebdSchin ops[0] = PROC_FD_DUP(open("/dev/null",O_WRONLY,0), 2, PROC_FD_CHILD);
1319da2e3ebdSchin ops[1] = 0;
1320da2e3ebdSchin if (*pp = procopen(_pth_getconf, cmd, environ, ops, PROC_READ))
1321da2e3ebdSchin {
1322da2e3ebdSchin if (sp = sfnew(NiL, NiL, SF_UNBOUND, (*pp)->rfd, SF_READ))
1323da2e3ebdSchin {
1324da2e3ebdSchin sfdisc(sp, SF_POPDISC);
1325da2e3ebdSchin return sp;
1326da2e3ebdSchin }
1327da2e3ebdSchin procclose(*pp);
1328da2e3ebdSchin }
1329da2e3ebdSchin #endif
1330da2e3ebdSchin return 0;
1331da2e3ebdSchin }
1332da2e3ebdSchin
1333da2e3ebdSchin /*
1334da2e3ebdSchin * value==0 gets value for name
1335da2e3ebdSchin * value!=0 sets value for name and returns previous value
1336da2e3ebdSchin * path==0 implies path=="/"
1337da2e3ebdSchin *
1338da2e3ebdSchin * settable return values are in permanent store
1339da2e3ebdSchin * non-settable return values copied to a tmp fmtbuf() buffer
1340da2e3ebdSchin *
1341da2e3ebdSchin * if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
1342da2e3ebdSchin * our_way();
1343da2e3ebdSchin *
1344da2e3ebdSchin * universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
1345da2e3ebdSchin * astgetconf("UNIVERSE", NiL, universe, 0, 0);
1346da2e3ebdSchin *
1347da2e3ebdSchin * if (flags&ASTCONF_error)!=0 then error return value is 0
1348da2e3ebdSchin * otherwise 0 not returned
1349da2e3ebdSchin */
1350da2e3ebdSchin
1351da2e3ebdSchin #define ALT 16
1352da2e3ebdSchin
1353da2e3ebdSchin char*
1354da2e3ebdSchin astgetconf(const char* name, const char* path, const char* value, int flags, Error_f conferror)
1355da2e3ebdSchin {
1356da2e3ebdSchin register char* s;
1357da2e3ebdSchin int n;
1358da2e3ebdSchin Lookup_t look;
1359da2e3ebdSchin Sfio_t* tmp;
1360da2e3ebdSchin
1361da2e3ebdSchin #if __OBSOLETE__ < 20080101
1362da2e3ebdSchin if (pointerof(flags) == (void*)errorf)
1363da2e3ebdSchin {
1364da2e3ebdSchin conferror = errorf;
1365da2e3ebdSchin flags = ASTCONF_error;
1366da2e3ebdSchin }
1367da2e3ebdSchin else if (conferror && conferror != errorf)
1368da2e3ebdSchin conferror = 0;
1369da2e3ebdSchin #endif
1370da2e3ebdSchin if (!name)
1371da2e3ebdSchin {
1372da2e3ebdSchin if (path)
1373da2e3ebdSchin return null;
1374da2e3ebdSchin if (!(name = value))
1375da2e3ebdSchin {
1376da2e3ebdSchin if (state.data)
1377da2e3ebdSchin {
1378da2e3ebdSchin Ast_confdisc_f notify;
1379da2e3ebdSchin
1380da2e3ebdSchin #if _HUH20000515 /* doesn't work for shell builtins */
1381da2e3ebdSchin free(state.data - state.prefix);
1382da2e3ebdSchin #endif
1383da2e3ebdSchin state.data = 0;
1384da2e3ebdSchin notify = state.notify;
1385da2e3ebdSchin state.notify = 0;
1386da2e3ebdSchin INITIALIZE();
1387da2e3ebdSchin state.notify = notify;
1388da2e3ebdSchin }
1389da2e3ebdSchin return null;
1390da2e3ebdSchin }
1391da2e3ebdSchin value = 0;
1392da2e3ebdSchin }
1393da2e3ebdSchin INITIALIZE();
1394da2e3ebdSchin if (!path)
1395da2e3ebdSchin path = root;
1396da2e3ebdSchin if (state.recent && streq(name, state.recent->name) && (s = format(state.recent, path, value, flags, conferror)))
1397da2e3ebdSchin return s;
1398da2e3ebdSchin if (lookup(&look, name, flags))
1399da2e3ebdSchin {
1400da2e3ebdSchin if (value)
1401da2e3ebdSchin {
1402da2e3ebdSchin ro:
1403da2e3ebdSchin errno = EINVAL;
1404da2e3ebdSchin if (conferror)
1405da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: cannot set value", name);
1406da2e3ebdSchin return (flags & ASTCONF_error) ? (char*)0 : null;
1407da2e3ebdSchin }
1408da2e3ebdSchin return print(NiL, &look, name, path, flags, conferror);
1409da2e3ebdSchin }
1410da2e3ebdSchin if ((n = strlen(name)) > 3 && n < (ALT + 3))
1411da2e3ebdSchin {
1412da2e3ebdSchin if (streq(name + n - 3, "DEV"))
1413da2e3ebdSchin {
1414da2e3ebdSchin if (tmp = sfstropen())
1415da2e3ebdSchin {
1416da2e3ebdSchin sfprintf(tmp, "/dev/");
1417da2e3ebdSchin for (s = (char*)name; s < (char*)name + n - 3; s++)
1418da2e3ebdSchin sfputc(tmp, isupper(*s) ? tolower(*s) : *s);
1419da2e3ebdSchin if ((s = sfstruse(tmp)) && !access(s, F_OK))
1420da2e3ebdSchin {
1421da2e3ebdSchin if (value)
1422da2e3ebdSchin goto ro;
1423da2e3ebdSchin s = buffer(s);
1424da2e3ebdSchin sfclose(tmp);
1425da2e3ebdSchin return s;
1426da2e3ebdSchin }
1427da2e3ebdSchin sfclose(tmp);
1428da2e3ebdSchin }
1429da2e3ebdSchin }
1430da2e3ebdSchin else if (streq(name + n - 3, "DIR"))
1431da2e3ebdSchin {
1432da2e3ebdSchin Lookup_t altlook;
1433da2e3ebdSchin char altname[ALT];
1434da2e3ebdSchin
1435da2e3ebdSchin static const char* dirs[] = { "/usr/lib", "/usr", null };
1436da2e3ebdSchin
1437da2e3ebdSchin strcpy(altname, name);
1438da2e3ebdSchin altname[n - 3] = 0;
1439da2e3ebdSchin if (lookup(&altlook, altname, flags))
1440da2e3ebdSchin {
1441da2e3ebdSchin if (value)
1442da2e3ebdSchin {
1443da2e3ebdSchin errno = EINVAL;
1444da2e3ebdSchin if (conferror)
1445da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: cannot set value", altname);
1446da2e3ebdSchin return (flags & ASTCONF_error) ? (char*)0 : null;
1447da2e3ebdSchin }
1448da2e3ebdSchin return print(NiL, &altlook, altname, path, flags, conferror);
1449da2e3ebdSchin }
1450da2e3ebdSchin for (s = altname; *s; s++)
1451da2e3ebdSchin if (isupper(*s))
1452da2e3ebdSchin *s = tolower(*s);
1453da2e3ebdSchin if (tmp = sfstropen())
1454da2e3ebdSchin {
1455da2e3ebdSchin for (n = 0; n < elementsof(dirs); n++)
1456da2e3ebdSchin {
1457da2e3ebdSchin sfprintf(tmp, "%s/%s/.", dirs[n], altname);
1458da2e3ebdSchin if ((s = sfstruse(tmp)) && !access(s, F_OK))
1459da2e3ebdSchin {
1460da2e3ebdSchin if (value)
1461da2e3ebdSchin goto ro;
1462da2e3ebdSchin s = buffer(s);
1463da2e3ebdSchin sfclose(tmp);
1464da2e3ebdSchin return s;
1465da2e3ebdSchin }
1466da2e3ebdSchin }
1467da2e3ebdSchin sfclose(tmp);
1468da2e3ebdSchin }
1469da2e3ebdSchin }
1470da2e3ebdSchin }
1471da2e3ebdSchin if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(look.name, path, value, flags, conferror)))
1472da2e3ebdSchin return s;
1473da2e3ebdSchin errno = EINVAL;
1474da2e3ebdSchin if (conferror && !(flags & ASTCONF_system))
1475da2e3ebdSchin (*conferror)(&state, &state, 2, "%s: unknown name", name);
1476da2e3ebdSchin return (flags & ASTCONF_error) ? (char*)0 : null;
1477da2e3ebdSchin }
1478da2e3ebdSchin
1479da2e3ebdSchin /*
1480da2e3ebdSchin * astconf() never returns 0
1481da2e3ebdSchin */
1482da2e3ebdSchin
1483da2e3ebdSchin char*
1484da2e3ebdSchin astconf(const char* name, const char* path, const char* value)
1485da2e3ebdSchin {
1486da2e3ebdSchin return astgetconf(name, path, value, 0, 0);
1487da2e3ebdSchin }
1488da2e3ebdSchin
1489da2e3ebdSchin /*
1490da2e3ebdSchin * set discipline function to be called when features change
1491da2e3ebdSchin * old discipline function returned
1492da2e3ebdSchin */
1493da2e3ebdSchin
1494da2e3ebdSchin Ast_confdisc_f
1495da2e3ebdSchin astconfdisc(Ast_confdisc_f new_notify)
1496da2e3ebdSchin {
1497da2e3ebdSchin Ast_confdisc_f old_notify;
1498da2e3ebdSchin
1499da2e3ebdSchin INITIALIZE();
1500da2e3ebdSchin old_notify = state.notify;
1501da2e3ebdSchin state.notify = new_notify;
1502da2e3ebdSchin return old_notify;
1503da2e3ebdSchin }
1504da2e3ebdSchin
1505da2e3ebdSchin /*
1506da2e3ebdSchin * list all name=value entries on sp
1507da2e3ebdSchin * path==0 implies path=="/"
1508da2e3ebdSchin */
1509da2e3ebdSchin
1510da2e3ebdSchin void
1511da2e3ebdSchin astconflist(Sfio_t* sp, const char* path, int flags, const char* pattern)
1512da2e3ebdSchin {
1513da2e3ebdSchin char* s;
1514da2e3ebdSchin char* f;
1515da2e3ebdSchin char* call;
1516da2e3ebdSchin Feature_t* fp;
1517da2e3ebdSchin Lookup_t look;
1518da2e3ebdSchin regex_t re;
1519da2e3ebdSchin regdisc_t redisc;
1520da2e3ebdSchin int olderrno;
1521da2e3ebdSchin char flg[8];
1522da2e3ebdSchin #ifdef _pth_getconf_a
1523da2e3ebdSchin Proc_t* proc;
1524da2e3ebdSchin Sfio_t* pp;
1525da2e3ebdSchin #endif
1526da2e3ebdSchin
1527da2e3ebdSchin INITIALIZE();
1528da2e3ebdSchin if (!path)
1529da2e3ebdSchin path = root;
1530da2e3ebdSchin else if (access(path, F_OK))
1531da2e3ebdSchin {
1532da2e3ebdSchin errorf(&state, &state, 2, "%s: not found", path);
1533da2e3ebdSchin return;
1534da2e3ebdSchin }
1535da2e3ebdSchin olderrno = errno;
1536da2e3ebdSchin look.flags = 0;
1537da2e3ebdSchin if (!(flags & (ASTCONF_read|ASTCONF_write|ASTCONF_parse)))
1538da2e3ebdSchin flags |= ASTCONF_read|ASTCONF_write;
1539da2e3ebdSchin else if (flags & ASTCONF_parse)
1540da2e3ebdSchin flags |= ASTCONF_write;
1541da2e3ebdSchin if (!(flags & (ASTCONF_matchcall|ASTCONF_matchname|ASTCONF_matchstandard)))
1542da2e3ebdSchin pattern = 0;
1543da2e3ebdSchin if (pattern)
1544da2e3ebdSchin {
1545da2e3ebdSchin memset(&redisc, 0, sizeof(redisc));
1546da2e3ebdSchin redisc.re_version = REG_VERSION;
1547da2e3ebdSchin redisc.re_errorf = (regerror_t)errorf;
1548da2e3ebdSchin re.re_disc = &redisc;
1549da2e3ebdSchin if (regcomp(&re, pattern, REG_DISCIPLINE|REG_EXTENDED|REG_LENIENT|REG_NULL))
1550da2e3ebdSchin return;
1551da2e3ebdSchin }
1552da2e3ebdSchin if (flags & ASTCONF_read)
1553da2e3ebdSchin {
1554da2e3ebdSchin for (look.conf = (Conf_t*)conf; look.conf < (Conf_t*)&conf[conf_elements]; look.conf++)
1555da2e3ebdSchin {
1556da2e3ebdSchin if (pattern)
1557da2e3ebdSchin {
1558da2e3ebdSchin if (flags & ASTCONF_matchcall)
1559da2e3ebdSchin {
1560da2e3ebdSchin if (regexec(&re, prefix[look.conf->call + CONF_call].name, 0, NiL, 0))
1561da2e3ebdSchin continue;
1562da2e3ebdSchin }
1563da2e3ebdSchin else if (flags & ASTCONF_matchname)
1564da2e3ebdSchin {
1565da2e3ebdSchin if (regexec(&re, look.conf->name, 0, NiL, 0))
1566da2e3ebdSchin continue;
1567da2e3ebdSchin }
1568da2e3ebdSchin else if (flags & ASTCONF_matchstandard)
1569da2e3ebdSchin {
1570da2e3ebdSchin if (regexec(&re, prefix[look.conf->standard].name, 0, NiL, 0))
1571da2e3ebdSchin continue;
1572da2e3ebdSchin }
1573da2e3ebdSchin }
1574da2e3ebdSchin print(sp, &look, NiL, path, flags, errorf);
1575da2e3ebdSchin }
1576da2e3ebdSchin #ifdef _pth_getconf_a
1577da2e3ebdSchin if (pp = nativeconf(&proc, _pth_getconf_a))
1578da2e3ebdSchin {
1579da2e3ebdSchin call = "GC";
1580da2e3ebdSchin while (f = sfgetr(pp, '\n', 1))
1581da2e3ebdSchin {
1582da2e3ebdSchin for (s = f; *s && *s != '=' && *s != ':' && !isspace(*s); s++);
1583da2e3ebdSchin if (*s)
1584da2e3ebdSchin for (*s++ = 0; isspace(*s); s++);
1585da2e3ebdSchin if (!lookup(&look, f, flags))
1586da2e3ebdSchin {
1587da2e3ebdSchin if (flags & ASTCONF_table)
1588da2e3ebdSchin {
1589da2e3ebdSchin if (look.standard < 0)
1590da2e3ebdSchin look.standard = 0;
1591da2e3ebdSchin if (look.section < 1)
1592da2e3ebdSchin look.section = 1;
1593da2e3ebdSchin sfprintf(sp, "%*s %*s %d %2s %4d %5s %s\n", sizeof(conf[0].name), f, sizeof(prefix[look.standard].name), prefix[look.standard].name, look.section, call, 0, "N", s);
1594da2e3ebdSchin }
1595da2e3ebdSchin else if (flags & ASTCONF_parse)
1596da2e3ebdSchin sfprintf(sp, "%s %s - %s\n", state.id, f, s);
1597da2e3ebdSchin else
1598da2e3ebdSchin sfprintf(sp, "%s=%s\n", f, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1599da2e3ebdSchin }
1600da2e3ebdSchin }
1601da2e3ebdSchin sfclose(pp);
1602da2e3ebdSchin procclose(proc);
1603da2e3ebdSchin }
1604da2e3ebdSchin #endif
1605da2e3ebdSchin }
1606da2e3ebdSchin if (flags & ASTCONF_write)
1607da2e3ebdSchin {
1608da2e3ebdSchin call = "AC";
1609da2e3ebdSchin for (fp = state.features; fp; fp = fp->next)
1610da2e3ebdSchin {
1611da2e3ebdSchin if (pattern)
1612da2e3ebdSchin {
1613da2e3ebdSchin if (flags & ASTCONF_matchcall)
1614da2e3ebdSchin {
1615da2e3ebdSchin if (regexec(&re, call, 0, NiL, 0))
1616da2e3ebdSchin continue;
1617da2e3ebdSchin }
1618da2e3ebdSchin else if (flags & ASTCONF_matchname)
1619da2e3ebdSchin {
1620da2e3ebdSchin if (regexec(&re, fp->name, 0, NiL, 0))
1621da2e3ebdSchin continue;
1622da2e3ebdSchin }
1623da2e3ebdSchin else if (flags & ASTCONF_matchstandard)
1624da2e3ebdSchin {
1625da2e3ebdSchin if (regexec(&re, prefix[fp->standard].name, 0, NiL, 0))
1626da2e3ebdSchin continue;
1627da2e3ebdSchin }
1628da2e3ebdSchin }
1629da2e3ebdSchin if (!(s = feature(fp->name, path, NiL, 0, 0)) || !*s)
1630da2e3ebdSchin s = "0";
1631da2e3ebdSchin if (flags & ASTCONF_table)
1632da2e3ebdSchin {
1633da2e3ebdSchin f = flg;
1634da2e3ebdSchin if (fp->flags & CONF_ALLOC)
1635da2e3ebdSchin *f++ = 'A';
1636da2e3ebdSchin if (fp->flags & CONF_READONLY)
1637da2e3ebdSchin *f++ = 'R';
1638da2e3ebdSchin if (f == flg)
1639da2e3ebdSchin *f++ = 'X';
1640da2e3ebdSchin *f = 0;
1641da2e3ebdSchin sfprintf(sp, "%*s %*s %d %2s %4d %5s %s\n", sizeof(conf[0].name), fp->name, sizeof(prefix[fp->standard].name), prefix[fp->standard].name, 1, call, 0, flg, s);
1642da2e3ebdSchin }
1643da2e3ebdSchin else if (flags & ASTCONF_parse)
1644da2e3ebdSchin sfprintf(sp, "%s %s - %s\n", state.id, (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL));
1645da2e3ebdSchin else
1646da2e3ebdSchin sfprintf(sp, "%s=%s\n", (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1647da2e3ebdSchin }
1648da2e3ebdSchin }
1649da2e3ebdSchin if (pattern)
1650da2e3ebdSchin regfree(&re);
1651da2e3ebdSchin errno = olderrno;
1652da2e3ebdSchin }
1653