1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 
29*b30d1939SAndy Fiddaman static const char id[] = "\n@(#)$Id: getconf (AT&T Research) 2012-05-01 $\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>
39*b30d1939SAndy Fiddaman #include <ls.h>
40*b30d1939SAndy Fiddaman #include <sys/utsname.h>
41da2e3ebdSchin 
42da2e3ebdSchin #include "conftab.h"
43da2e3ebdSchin #include "FEATURE/libpath"
44da2e3ebdSchin 
4534f9b3eeSRoland Mainz #ifndef DEBUG_astconf
4634f9b3eeSRoland Mainz #define DEBUG_astconf		0
4734f9b3eeSRoland Mainz #endif
4834f9b3eeSRoland Mainz 
49da2e3ebdSchin #ifndef _pth_getconf
50da2e3ebdSchin #undef	ASTCONF_system
51da2e3ebdSchin #define ASTCONF_system		0
52da2e3ebdSchin #endif
53da2e3ebdSchin 
54da2e3ebdSchin #if _sys_systeminfo
55da2e3ebdSchin # if !_lib_sysinfo
56da2e3ebdSchin #   if _lib_systeminfo
57da2e3ebdSchin #     define _lib_sysinfo	1
58da2e3ebdSchin #     define sysinfo(a,b,c)	systeminfo(a,b,c)
59da2e3ebdSchin #   else
60da2e3ebdSchin #     if _lib_syscall && _sys_syscall
61da2e3ebdSchin #       include <sys/syscall.h>
62da2e3ebdSchin #       if defined(SYS_systeminfo)
63da2e3ebdSchin #         define _lib_sysinfo	1
64da2e3ebdSchin #         define sysinfo(a,b,c)	syscall(SYS_systeminfo,a,b,c)
65da2e3ebdSchin #       endif
66da2e3ebdSchin #     endif
67da2e3ebdSchin #   endif
68da2e3ebdSchin # endif
69da2e3ebdSchin #else
70da2e3ebdSchin # undef	_lib_sysinfo
71da2e3ebdSchin #endif
72da2e3ebdSchin 
73da2e3ebdSchin #define CONF_ERROR	(CONF_USER<<0)
74da2e3ebdSchin #define CONF_READONLY	(CONF_USER<<1)
75da2e3ebdSchin #define CONF_ALLOC	(CONF_USER<<2)
767c2fbfb3SApril Chin #define CONF_GLOBAL	(CONF_USER<<3)
77da2e3ebdSchin 
7834f9b3eeSRoland Mainz #define DEFAULT(o)	((state.std||!dynamic[o].ast)?dynamic[o].std:dynamic[o].ast)
79da2e3ebdSchin #define INITIALIZE()	do{if(!state.data)synthesize(NiL,NiL,NiL);}while(0)
8034f9b3eeSRoland Mainz #define STANDARD(v)	(streq(v,"standard")||streq(v,"strict")||streq(v,"posix")||streq(v,"xopen"))
81da2e3ebdSchin 
82da2e3ebdSchin #define MAXVAL		256
83da2e3ebdSchin 
84da2e3ebdSchin #if MAXVAL <= UNIV_SIZE
85da2e3ebdSchin #undef	MAXVAL
86da2e3ebdSchin #define	MAXVAL		(UNIV_SIZE+1)
87da2e3ebdSchin #endif
88da2e3ebdSchin 
89da2e3ebdSchin #ifndef _UNIV_DEFAULT
90da2e3ebdSchin #define _UNIV_DEFAULT	"att"
91da2e3ebdSchin #endif
92da2e3ebdSchin 
93*b30d1939SAndy Fiddaman static char		null[1];
94*b30d1939SAndy Fiddaman static char		root[2] = "/";
95da2e3ebdSchin 
96da2e3ebdSchin typedef struct Feature_s
97da2e3ebdSchin {
98da2e3ebdSchin 	struct Feature_s*next;
99da2e3ebdSchin 	const char*	name;
100da2e3ebdSchin 	char*		value;
10134f9b3eeSRoland Mainz 	char*		std;
10234f9b3eeSRoland Mainz 	char*		ast;
103da2e3ebdSchin 	short		length;
104da2e3ebdSchin 	short		standard;
1057c2fbfb3SApril Chin 	unsigned int	flags;
106da2e3ebdSchin 	short		op;
107da2e3ebdSchin } Feature_t;
108da2e3ebdSchin 
109*b30d1939SAndy Fiddaman typedef struct Lookup_s
110da2e3ebdSchin {
111da2e3ebdSchin 	Conf_t*		conf;
112da2e3ebdSchin 	const char*	name;
1137c2fbfb3SApril Chin 	unsigned int	flags;
114da2e3ebdSchin 	short		call;
115da2e3ebdSchin 	short		standard;
116da2e3ebdSchin 	short		section;
117da2e3ebdSchin } Lookup_t;
118da2e3ebdSchin 
119da2e3ebdSchin static Feature_t	dynamic[] =
120da2e3ebdSchin {
121*b30d1939SAndy Fiddaman #define OP_architecture	0
122*b30d1939SAndy Fiddaman 	{
123*b30d1939SAndy Fiddaman 		&dynamic[OP_architecture+1],
124*b30d1939SAndy Fiddaman 		"ARCHITECTURE",
125*b30d1939SAndy Fiddaman 		&null[0],
126*b30d1939SAndy Fiddaman 		0,
127*b30d1939SAndy Fiddaman 		0,
128*b30d1939SAndy Fiddaman 		12,
129*b30d1939SAndy Fiddaman 		CONF_AST,
130*b30d1939SAndy Fiddaman 		0,
131*b30d1939SAndy Fiddaman 		OP_architecture
132*b30d1939SAndy Fiddaman 	},
133*b30d1939SAndy Fiddaman #define OP_conformance	1
134da2e3ebdSchin 	{
13534f9b3eeSRoland Mainz 		&dynamic[OP_conformance+1],
136da2e3ebdSchin 		"CONFORMANCE",
137da2e3ebdSchin 		"ast",
138da2e3ebdSchin 		"standard",
13934f9b3eeSRoland Mainz 		"ast",
140da2e3ebdSchin 		11,
141da2e3ebdSchin 		CONF_AST,
142da2e3ebdSchin 		0,
143da2e3ebdSchin 		OP_conformance
144da2e3ebdSchin 	},
145*b30d1939SAndy Fiddaman #define OP_fs_3d	2
146da2e3ebdSchin 	{
14734f9b3eeSRoland Mainz 		&dynamic[OP_fs_3d+1],
148da2e3ebdSchin 		"FS_3D",
149da2e3ebdSchin 		&null[0],
150da2e3ebdSchin 		"0",
15134f9b3eeSRoland Mainz 		0,
152da2e3ebdSchin 		5,
153da2e3ebdSchin 		CONF_AST,
154da2e3ebdSchin 		0,
155da2e3ebdSchin 		OP_fs_3d
156da2e3ebdSchin 	},
157*b30d1939SAndy Fiddaman #define OP_getconf	3
158da2e3ebdSchin 	{
15934f9b3eeSRoland Mainz 		&dynamic[OP_getconf+1],
160da2e3ebdSchin 		"GETCONF",
161da2e3ebdSchin #ifdef _pth_getconf
162da2e3ebdSchin 		_pth_getconf,
163da2e3ebdSchin #else
164da2e3ebdSchin 		&null[0],
165da2e3ebdSchin #endif
16634f9b3eeSRoland Mainz 		0,
167da2e3ebdSchin 		0,
168da2e3ebdSchin 		7,
169da2e3ebdSchin 		CONF_AST,
170da2e3ebdSchin 		CONF_READONLY,
171da2e3ebdSchin 		OP_getconf
172da2e3ebdSchin 	},
173*b30d1939SAndy Fiddaman #define OP_hosttype	4
174da2e3ebdSchin 	{
17534f9b3eeSRoland Mainz 		&dynamic[OP_hosttype+1],
176da2e3ebdSchin 		"HOSTTYPE",
177da2e3ebdSchin 		HOSTTYPE,
178da2e3ebdSchin 		0,
17934f9b3eeSRoland Mainz 		0,
180da2e3ebdSchin 		8,
181da2e3ebdSchin 		CONF_AST,
182da2e3ebdSchin 		CONF_READONLY,
183da2e3ebdSchin 		OP_hosttype
184da2e3ebdSchin 	},
185*b30d1939SAndy Fiddaman #define OP_libpath	5
186da2e3ebdSchin 	{
18734f9b3eeSRoland Mainz 		&dynamic[OP_libpath+1],
188da2e3ebdSchin 		"LIBPATH",
189da2e3ebdSchin #ifdef CONF_LIBPATH
190da2e3ebdSchin 		CONF_LIBPATH,
191da2e3ebdSchin #else
192da2e3ebdSchin 		&null[0],
193da2e3ebdSchin #endif
19434f9b3eeSRoland Mainz 		0,
195da2e3ebdSchin 		0,
196da2e3ebdSchin 		7,
197da2e3ebdSchin 		CONF_AST,
198da2e3ebdSchin 		0,
199da2e3ebdSchin 		OP_libpath
200da2e3ebdSchin 	},
201*b30d1939SAndy Fiddaman #define OP_libprefix	6
202da2e3ebdSchin 	{
20334f9b3eeSRoland Mainz 		&dynamic[OP_libprefix+1],
204da2e3ebdSchin 		"LIBPREFIX",
205da2e3ebdSchin #ifdef CONF_LIBPREFIX
206da2e3ebdSchin 		CONF_LIBPREFIX,
207da2e3ebdSchin #else
208da2e3ebdSchin 		"lib",
209da2e3ebdSchin #endif
21034f9b3eeSRoland Mainz 		0,
211da2e3ebdSchin 		0,
212da2e3ebdSchin 		9,
213da2e3ebdSchin 		CONF_AST,
214da2e3ebdSchin 		0,
215da2e3ebdSchin 		OP_libprefix
216da2e3ebdSchin 	},
217*b30d1939SAndy Fiddaman #define OP_libsuffix	7
218da2e3ebdSchin 	{
21934f9b3eeSRoland Mainz 		&dynamic[OP_libsuffix+1],
220da2e3ebdSchin 		"LIBSUFFIX",
221da2e3ebdSchin #ifdef CONF_LIBSUFFIX
222da2e3ebdSchin 		CONF_LIBSUFFIX,
223da2e3ebdSchin #else
224da2e3ebdSchin 		".so",
225da2e3ebdSchin #endif
22634f9b3eeSRoland Mainz 		0,
227da2e3ebdSchin 		0,
228da2e3ebdSchin 		9,
229da2e3ebdSchin 		CONF_AST,
230da2e3ebdSchin 		0,
231da2e3ebdSchin 		OP_libsuffix
232da2e3ebdSchin 	},
233*b30d1939SAndy Fiddaman #define OP_path_attributes	8
234da2e3ebdSchin 	{
23534f9b3eeSRoland Mainz 		&dynamic[OP_path_attributes+1],
236da2e3ebdSchin 		"PATH_ATTRIBUTES",
237da2e3ebdSchin #if _WINIX
238da2e3ebdSchin 		"c",
239da2e3ebdSchin #else
240da2e3ebdSchin 		&null[0],
241da2e3ebdSchin #endif
242da2e3ebdSchin 		&null[0],
24334f9b3eeSRoland Mainz 		0,
244da2e3ebdSchin 		15,
245da2e3ebdSchin 		CONF_AST,
246da2e3ebdSchin 		CONF_READONLY,
247da2e3ebdSchin 		OP_path_attributes
248da2e3ebdSchin 	},
249*b30d1939SAndy Fiddaman #define OP_path_resolve	9
250da2e3ebdSchin 	{
25134f9b3eeSRoland Mainz 		&dynamic[OP_path_resolve+1],
252da2e3ebdSchin 		"PATH_RESOLVE",
253da2e3ebdSchin 		&null[0],
25434f9b3eeSRoland Mainz 		"physical",
255da2e3ebdSchin 		"metaphysical",
256da2e3ebdSchin 		12,
257da2e3ebdSchin 		CONF_AST,
258da2e3ebdSchin 		0,
259da2e3ebdSchin 		OP_path_resolve
260da2e3ebdSchin 	},
261*b30d1939SAndy Fiddaman #define OP_universe	10
262da2e3ebdSchin 	{
263da2e3ebdSchin 		0,
264da2e3ebdSchin 		"UNIVERSE",
265da2e3ebdSchin 		&null[0],
266da2e3ebdSchin 		"att",
26734f9b3eeSRoland Mainz 		0,
268da2e3ebdSchin 		8,
269da2e3ebdSchin 		CONF_AST,
270da2e3ebdSchin 		0,
271da2e3ebdSchin 		OP_universe
272da2e3ebdSchin 	},
273da2e3ebdSchin 	{
274da2e3ebdSchin 		0
275da2e3ebdSchin 	}
276da2e3ebdSchin };
277da2e3ebdSchin 
278*b30d1939SAndy Fiddaman typedef struct State_s
279da2e3ebdSchin {
280da2e3ebdSchin 
281da2e3ebdSchin 	const char*	id;
282da2e3ebdSchin 	const char*	name;
283*b30d1939SAndy Fiddaman 	const char*	standard;
284*b30d1939SAndy Fiddaman 	const char*	strict;
285da2e3ebdSchin 	Feature_t*	features;
286da2e3ebdSchin 
28734f9b3eeSRoland Mainz 	int		std;
28834f9b3eeSRoland Mainz 
289da2e3ebdSchin 	/* default initialization from here down */
290da2e3ebdSchin 
291da2e3ebdSchin 	int		prefix;
292da2e3ebdSchin 	int		synthesizing;
293da2e3ebdSchin 
294da2e3ebdSchin 	char*		data;
295da2e3ebdSchin 	char*		last;
296da2e3ebdSchin 
297da2e3ebdSchin 	Feature_t*	recent;
298da2e3ebdSchin 
299da2e3ebdSchin 	Ast_confdisc_f	notify;
300da2e3ebdSchin 
301da2e3ebdSchin } State_t;
302da2e3ebdSchin 
303*b30d1939SAndy Fiddaman static State_t	state = { "getconf", "_AST_FEATURES", "CONFORMANCE = standard", "POSIXLY_CORRECT", dynamic, -1 };
304da2e3ebdSchin 
305*b30d1939SAndy Fiddaman static char*	feature(Feature_t*, const char*, const char*, const char*, unsigned int, Error_f);
306da2e3ebdSchin 
307da2e3ebdSchin /*
308da2e3ebdSchin  * return fmtbuf() copy of s
309da2e3ebdSchin  */
310da2e3ebdSchin 
311da2e3ebdSchin static char*
buffer(char * s)312da2e3ebdSchin buffer(char* s)
313da2e3ebdSchin {
314da2e3ebdSchin 	return strcpy(fmtbuf(strlen(s) + 1), s);
315da2e3ebdSchin }
316da2e3ebdSchin 
317da2e3ebdSchin /*
318da2e3ebdSchin  * synthesize state for fp
319da2e3ebdSchin  * fp==0 initializes from getenv(state.name)
320da2e3ebdSchin  * value==0 just does lookup
321da2e3ebdSchin  * otherwise state is set to value
322da2e3ebdSchin  */
323da2e3ebdSchin 
324da2e3ebdSchin static char*
synthesize(register Feature_t * fp,const char * path,const char * value)325da2e3ebdSchin synthesize(register Feature_t* fp, const char* path, const char* value)
326da2e3ebdSchin {
327da2e3ebdSchin 	register char*		s;
328da2e3ebdSchin 	register char*		d;
329da2e3ebdSchin 	register char*		v;
33034f9b3eeSRoland Mainz 	register char*		p;
331da2e3ebdSchin 	register int		n;
332da2e3ebdSchin 
33334f9b3eeSRoland Mainz #if DEBUG_astconf
3347c2fbfb3SApril Chin 	if (fp)
335*b30d1939SAndy Fiddaman 		error(-6, "astconf synthesize name=%s path=%s value=%s fp=%p%s", fp->name, path, value, fp, state.synthesizing ? " SYNTHESIZING" : "");
3367c2fbfb3SApril Chin #endif
337da2e3ebdSchin 	if (state.synthesizing)
338da2e3ebdSchin 		return null;
339da2e3ebdSchin 	if (!state.data)
340da2e3ebdSchin 	{
341da2e3ebdSchin 		char*		se;
342da2e3ebdSchin 		char*		de;
343da2e3ebdSchin 		char*		ve;
344da2e3ebdSchin 
345da2e3ebdSchin 		state.prefix = strlen(state.name) + 1;
346da2e3ebdSchin 		n = state.prefix + 3 * MAXVAL;
347*b30d1939SAndy Fiddaman 		if ((s = getenv(state.name)) || getenv(state.strict) && (s = (char*)state.standard))
348da2e3ebdSchin 			n += strlen(s) + 1;
349da2e3ebdSchin 		n = roundof(n, 32);
350da2e3ebdSchin 		if (!(state.data = newof(0, char, n, 0)))
351da2e3ebdSchin 			return 0;
352da2e3ebdSchin 		state.last = state.data + n - 1;
353da2e3ebdSchin 		strcpy(state.data, state.name);
354da2e3ebdSchin 		state.data += state.prefix - 1;
355da2e3ebdSchin 		*state.data++ = '=';
356da2e3ebdSchin 		if (s)
357da2e3ebdSchin 			strcpy(state.data, s);
358da2e3ebdSchin 		ve = state.data;
359da2e3ebdSchin 		state.synthesizing = 1;
360da2e3ebdSchin 		for (;;)
361da2e3ebdSchin 		{
362da2e3ebdSchin 			for (s = ve; isspace(*s); s++);
363da2e3ebdSchin 			for (d = s; *d && !isspace(*d); d++);
364da2e3ebdSchin 			for (se = d; isspace(*d); d++);
365da2e3ebdSchin 			for (v = d; *v && !isspace(*v); v++);
366da2e3ebdSchin 			for (de = v; isspace(*v); v++);
367da2e3ebdSchin 			if (!*v)
368da2e3ebdSchin 				break;
369da2e3ebdSchin 			for (ve = v; *ve && !isspace(*ve); ve++);
370da2e3ebdSchin 			if (*ve)
371da2e3ebdSchin 				*ve = 0;
372da2e3ebdSchin 			else
373da2e3ebdSchin 				ve = 0;
374da2e3ebdSchin 			*de = 0;
375da2e3ebdSchin 			*se = 0;
376*b30d1939SAndy Fiddaman 			feature(0, s, d, v, 0, 0);
377da2e3ebdSchin 			*se = ' ';
378da2e3ebdSchin 			*de = ' ';
379da2e3ebdSchin 			if (!ve)
380da2e3ebdSchin 				break;
381da2e3ebdSchin 			*ve++ = ' ';
382da2e3ebdSchin 		}
383da2e3ebdSchin 		state.synthesizing = 0;
384da2e3ebdSchin 	}
385da2e3ebdSchin 	if (!fp)
386da2e3ebdSchin 		return state.data;
387da2e3ebdSchin 	if (!state.last)
388da2e3ebdSchin 	{
389da2e3ebdSchin 		if (!value)
390da2e3ebdSchin 			return 0;
391da2e3ebdSchin 		n = strlen(value);
392da2e3ebdSchin 		goto ok;
393da2e3ebdSchin 	}
394da2e3ebdSchin 	s = (char*)fp->name;
395da2e3ebdSchin 	n = fp->length;
396da2e3ebdSchin 	d = state.data;
397da2e3ebdSchin 	for (;;)
398da2e3ebdSchin 	{
399da2e3ebdSchin 		while (isspace(*d))
400da2e3ebdSchin 			d++;
401da2e3ebdSchin 		if (!*d)
402da2e3ebdSchin 			break;
403da2e3ebdSchin 		if (strneq(d, s, n) && isspace(d[n]))
404da2e3ebdSchin 		{
405da2e3ebdSchin 			if (!value)
406da2e3ebdSchin 			{
407da2e3ebdSchin 				for (d += n + 1; *d && !isspace(*d); d++);
408da2e3ebdSchin 				for (; isspace(*d); d++);
409da2e3ebdSchin 				for (s = d; *s && !isspace(*s); s++);
410da2e3ebdSchin 				n = s - d;
411da2e3ebdSchin 				value = (const char*)d;
412da2e3ebdSchin 				goto ok;
413da2e3ebdSchin 			}
41434f9b3eeSRoland Mainz 			for (s = p = d + n + 1; *s && !isspace(*s); s++);
415da2e3ebdSchin 			for (; isspace(*s); s++);
416da2e3ebdSchin 			for (v = s; *s && !isspace(*s); s++);
417da2e3ebdSchin 			n = s - v;
41834f9b3eeSRoland Mainz 			if ((!path || *path == *p && strlen(path) == (v - p - 1) && !memcmp(path, p, v - p - 1)) && strneq(v, value, n))
419da2e3ebdSchin 				goto ok;
420da2e3ebdSchin 			for (; isspace(*s); s++);
421da2e3ebdSchin 			if (*s)
422da2e3ebdSchin 				for (; *d = *s++; d++);
423da2e3ebdSchin 			else if (d != state.data)
424da2e3ebdSchin 				d--;
425da2e3ebdSchin 			break;
426da2e3ebdSchin 		}
427da2e3ebdSchin 		for (; *d && !isspace(*d); d++);
428da2e3ebdSchin 		for (; isspace(*d); d++);
429da2e3ebdSchin 		for (; *d && !isspace(*d); d++);
430da2e3ebdSchin 		for (; isspace(*d); d++);
431da2e3ebdSchin 		for (; *d && !isspace(*d); d++);
432da2e3ebdSchin 	}
433da2e3ebdSchin 	if (!value)
434da2e3ebdSchin 	{
435da2e3ebdSchin 		if (!fp->op)
436da2e3ebdSchin 		{
437da2e3ebdSchin 			if (fp->flags & CONF_ALLOC)
438da2e3ebdSchin 				fp->value[0] = 0;
439da2e3ebdSchin 			else
440da2e3ebdSchin 				fp->value = null;
441da2e3ebdSchin 		}
442da2e3ebdSchin 		return 0;
443da2e3ebdSchin 	}
444da2e3ebdSchin 	if (!value[0])
445da2e3ebdSchin 		value = "0";
446da2e3ebdSchin 	if (!path || !path[0] || path[0] == '/' && !path[1])
447da2e3ebdSchin 		path = "-";
448da2e3ebdSchin 	n += strlen(path) + strlen(value) + 3;
449da2e3ebdSchin 	if (d + n >= state.last)
450da2e3ebdSchin 	{
451da2e3ebdSchin 		int	c;
452da2e3ebdSchin 		int	i;
453da2e3ebdSchin 
454da2e3ebdSchin 		i = d - state.data;
455da2e3ebdSchin 		state.data -= state.prefix;
456da2e3ebdSchin 		c = n + state.last - state.data + 3 * MAXVAL;
457da2e3ebdSchin 		c = roundof(c, 32);
458da2e3ebdSchin 		if (!(state.data = newof(state.data, char, c, 0)))
459da2e3ebdSchin 			return 0;
460da2e3ebdSchin 		state.last = state.data + c - 1;
461da2e3ebdSchin 		state.data += state.prefix;
462da2e3ebdSchin 		d = state.data + i;
463da2e3ebdSchin 	}
464da2e3ebdSchin 	if (d != state.data)
465da2e3ebdSchin 		*d++ = ' ';
466da2e3ebdSchin 	for (s = (char*)fp->name; *d = *s++; d++);
467da2e3ebdSchin 	*d++ = ' ';
468da2e3ebdSchin 	for (s = (char*)path; *d = *s++; d++);
469da2e3ebdSchin 	*d++ = ' ';
470da2e3ebdSchin 	for (s = (char*)value; *d = *s++; d++);
47134f9b3eeSRoland Mainz #if DEBUG_astconf
472*b30d1939SAndy Fiddaman 	error(-7, "astconf synthesize %s", state.data - state.prefix);
47334f9b3eeSRoland Mainz #endif
474da2e3ebdSchin 	setenviron(state.data - state.prefix);
475da2e3ebdSchin 	if (state.notify)
476da2e3ebdSchin 		(*state.notify)(NiL, NiL, state.data - state.prefix);
477da2e3ebdSchin 	n = s - (char*)value - 1;
478da2e3ebdSchin  ok:
479da2e3ebdSchin 	if (!(fp->flags & CONF_ALLOC))
480da2e3ebdSchin 		fp->value = 0;
481da2e3ebdSchin 	if (n == 1 && (*value == '0' || *value == '-'))
482da2e3ebdSchin 		n = 0;
483da2e3ebdSchin 	if (!(fp->value = newof(fp->value, char, n, 1)))
484da2e3ebdSchin 		fp->value = null;
485da2e3ebdSchin 	else
486da2e3ebdSchin 	{
487da2e3ebdSchin 		fp->flags |= CONF_ALLOC;
488da2e3ebdSchin 		memcpy(fp->value, value, n);
489da2e3ebdSchin 		fp->value[n] = 0;
490da2e3ebdSchin 	}
491da2e3ebdSchin 	return fp->value;
492da2e3ebdSchin }
493da2e3ebdSchin 
494da2e3ebdSchin /*
495da2e3ebdSchin  * initialize the value for fp
496da2e3ebdSchin  * if command!=0 then it is checked for on $PATH
497da2e3ebdSchin  * synthesize(fp,path,succeed) called on success
498da2e3ebdSchin  * otherwise synthesize(fp,path,fail) called
499da2e3ebdSchin  */
500da2e3ebdSchin 
501da2e3ebdSchin static void
initialize(register Feature_t * fp,const char * path,const char * command,const char * succeed,const char * fail)502da2e3ebdSchin initialize(register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail)
503da2e3ebdSchin {
504da2e3ebdSchin 	register char*	p;
505da2e3ebdSchin 	register int	ok = 1;
506da2e3ebdSchin 
50734f9b3eeSRoland Mainz #if DEBUG_astconf
508*b30d1939SAndy Fiddaman 	error(-6, "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" : "");
5097c2fbfb3SApril Chin #endif
510da2e3ebdSchin 	switch (fp->op)
511da2e3ebdSchin 	{
512*b30d1939SAndy Fiddaman 	case OP_architecture:
513*b30d1939SAndy Fiddaman 		ok = 1;
514*b30d1939SAndy Fiddaman 		break;
515da2e3ebdSchin 	case OP_conformance:
516*b30d1939SAndy Fiddaman 		ok = getenv(state.strict) != 0;
517da2e3ebdSchin 		break;
518da2e3ebdSchin 	case OP_hosttype:
519da2e3ebdSchin 		ok = 1;
520da2e3ebdSchin 		break;
521da2e3ebdSchin 	case OP_path_attributes:
522da2e3ebdSchin 		ok = 1;
523da2e3ebdSchin 		break;
524da2e3ebdSchin 	case OP_path_resolve:
525da2e3ebdSchin 		ok = fs3d(FS3D_TEST);
526da2e3ebdSchin 		break;
527da2e3ebdSchin 	case OP_universe:
52834f9b3eeSRoland Mainz 		ok = streq(_UNIV_DEFAULT, DEFAULT(OP_universe));
529da2e3ebdSchin 		/*FALLTHROUGH...*/
530da2e3ebdSchin 	default:
531da2e3ebdSchin 		if (p = getenv("PATH"))
532da2e3ebdSchin 		{
533da2e3ebdSchin 			register int	r = 1;
534da2e3ebdSchin 			register char*	d = p;
535da2e3ebdSchin 			Sfio_t*		tmp;
536da2e3ebdSchin 
53734f9b3eeSRoland Mainz #if DEBUG_astconf
538*b30d1939SAndy Fiddaman 			error(-6, "astconf initialize name=%s ok=%d PATH=%s", fp->name, ok, p);
5397c2fbfb3SApril Chin #endif
540da2e3ebdSchin 			if (tmp = sfstropen())
541da2e3ebdSchin 			{
542da2e3ebdSchin 				for (;;)
543da2e3ebdSchin 				{
544da2e3ebdSchin 					switch (*p++)
545da2e3ebdSchin 					{
546da2e3ebdSchin 					case 0:
547da2e3ebdSchin 						break;
548da2e3ebdSchin 					case ':':
549*b30d1939SAndy Fiddaman 						if (command && fp->op != OP_universe)
550da2e3ebdSchin 						{
551da2e3ebdSchin 							if (r = p - d - 1)
552da2e3ebdSchin 							{
553da2e3ebdSchin 								sfwrite(tmp, d, r);
554da2e3ebdSchin 								sfputc(tmp, '/');
555da2e3ebdSchin 								sfputr(tmp, command, 0);
556da2e3ebdSchin 								if ((d = sfstruse(tmp)) && !eaccess(d, X_OK))
557da2e3ebdSchin 								{
558da2e3ebdSchin 									ok = 1;
559da2e3ebdSchin 									if (fp->op != OP_universe)
560da2e3ebdSchin 										break;
561da2e3ebdSchin 								}
562da2e3ebdSchin 							}
563da2e3ebdSchin 							d = p;
564da2e3ebdSchin 						}
565da2e3ebdSchin 						r = 1;
566da2e3ebdSchin 						continue;
567da2e3ebdSchin 					case '/':
568da2e3ebdSchin 						if (r)
569da2e3ebdSchin 						{
570da2e3ebdSchin 							r = 0;
571da2e3ebdSchin 							if (fp->op == OP_universe)
572da2e3ebdSchin 							{
5737c2fbfb3SApril Chin 								if (p[0] == 'u' && p[1] == 's' && p[2] == 'r' && p[3] == '/')
5747c2fbfb3SApril Chin 									for (p += 4; *p == '/'; p++);
5757c2fbfb3SApril Chin 								if (p[0] == 'b' && p[1] == 'i' && p[2] == 'n')
5767c2fbfb3SApril Chin 								{
5777c2fbfb3SApril Chin 									for (p += 3; *p == '/'; p++);
5787c2fbfb3SApril Chin 									if (!*p || *p == ':')
5797c2fbfb3SApril Chin 										break;
5807c2fbfb3SApril Chin 								}
581da2e3ebdSchin 							}
582da2e3ebdSchin 						}
583da2e3ebdSchin 						if (fp->op == OP_universe)
584da2e3ebdSchin 						{
585*b30d1939SAndy Fiddaman 							if (strneq(p, "xpg", 3))
586da2e3ebdSchin 							{
587da2e3ebdSchin 								ok = 1;
588da2e3ebdSchin 								break;
589da2e3ebdSchin 							}
590da2e3ebdSchin 							if (strneq(p, "bsd", 3) || strneq(p, "ucb", 3))
591da2e3ebdSchin 							{
592da2e3ebdSchin 								ok = 0;
593da2e3ebdSchin 								break;
594da2e3ebdSchin 							}
595da2e3ebdSchin 						}
596da2e3ebdSchin 						continue;
597da2e3ebdSchin 					default:
598da2e3ebdSchin 						r = 0;
599da2e3ebdSchin 						continue;
600da2e3ebdSchin 					}
601da2e3ebdSchin 					break;
602da2e3ebdSchin 				}
603da2e3ebdSchin 				sfclose(tmp);
604da2e3ebdSchin 			}
605da2e3ebdSchin 			else
606da2e3ebdSchin 				ok = 1;
607da2e3ebdSchin 		}
608da2e3ebdSchin 		break;
609da2e3ebdSchin 	}
61034f9b3eeSRoland Mainz #if DEBUG_astconf
611*b30d1939SAndy Fiddaman 	error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s ok=%d", state.std, fp->name, ok ? succeed : fail, fp->std, fp->ast, fp->value, ok);
61234f9b3eeSRoland Mainz #endif
613da2e3ebdSchin 	synthesize(fp, path, ok ? succeed : fail);
614da2e3ebdSchin }
615da2e3ebdSchin 
616da2e3ebdSchin /*
617da2e3ebdSchin  * format synthesized value
618da2e3ebdSchin  */
619da2e3ebdSchin 
620da2e3ebdSchin static char*
format(register Feature_t * fp,const char * path,const char * value,unsigned int flags,Error_f conferror)6217c2fbfb3SApril Chin format(register Feature_t* fp, const char* path, const char* value, unsigned int flags, Error_f conferror)
622da2e3ebdSchin {
623da2e3ebdSchin 	register Feature_t*	sp;
624da2e3ebdSchin 	register int		n;
625*b30d1939SAndy Fiddaman #if _UWIN && ( _X86_ || _X64_ )
626*b30d1939SAndy Fiddaman 	struct stat		st;
627*b30d1939SAndy Fiddaman #else
628*b30d1939SAndy Fiddaman 	static struct utsname	uts;
629*b30d1939SAndy Fiddaman #endif
630da2e3ebdSchin 
63134f9b3eeSRoland Mainz #if DEBUG_astconf
632*b30d1939SAndy Fiddaman 	error(-6, "astconf format name=%s path=%s value=%s flags=%04x fp=%p%s", fp->name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
6337c2fbfb3SApril Chin #endif
6347c2fbfb3SApril Chin 	if (value)
6357c2fbfb3SApril Chin 		fp->flags &= ~CONF_GLOBAL;
6367c2fbfb3SApril Chin 	else if (fp->flags & CONF_GLOBAL)
6377c2fbfb3SApril Chin 		return fp->value;
638da2e3ebdSchin 	switch (fp->op)
639da2e3ebdSchin 	{
640da2e3ebdSchin 
641*b30d1939SAndy Fiddaman 	case OP_architecture:
642*b30d1939SAndy Fiddaman #if _UWIN && ( _X86_ || _X64_ )
643*b30d1939SAndy Fiddaman 		if (!stat("/", &st))
644*b30d1939SAndy Fiddaman 		{
645*b30d1939SAndy Fiddaman 			if (st.st_ino == 64)
646*b30d1939SAndy Fiddaman 			{
647*b30d1939SAndy Fiddaman 				fp->value = "x64";
648*b30d1939SAndy Fiddaman 				break;
649*b30d1939SAndy Fiddaman 			}
650*b30d1939SAndy Fiddaman 			if (st.st_ino == 32)
651*b30d1939SAndy Fiddaman 			{
652*b30d1939SAndy Fiddaman 				fp->value = "x86";
653*b30d1939SAndy Fiddaman 				break;
654*b30d1939SAndy Fiddaman 			}
655*b30d1939SAndy Fiddaman 		}
656*b30d1939SAndy Fiddaman #if _X64_
657*b30d1939SAndy Fiddaman 		fp->value = "x64";
658*b30d1939SAndy Fiddaman #else
659*b30d1939SAndy Fiddaman 		fp->value = "x86";
660*b30d1939SAndy Fiddaman #endif
661*b30d1939SAndy Fiddaman #else
662*b30d1939SAndy Fiddaman 		if (!uname(&uts))
663*b30d1939SAndy Fiddaman 			return fp->value = uts.machine;
664*b30d1939SAndy Fiddaman 		if (!(fp->value = getenv("HOSTNAME")))
665*b30d1939SAndy Fiddaman 			fp->value = "unknown";
666*b30d1939SAndy Fiddaman #endif
667*b30d1939SAndy Fiddaman 		break;
668*b30d1939SAndy Fiddaman 
669da2e3ebdSchin 	case OP_conformance:
67034f9b3eeSRoland Mainz 		if (value && STANDARD(value))
67134f9b3eeSRoland Mainz 			value = fp->std;
672*b30d1939SAndy Fiddaman 		state.std = streq(fp->value, fp->std);
67334f9b3eeSRoland Mainz #if DEBUG_astconf
674*b30d1939SAndy Fiddaman 		error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s", state.std, fp->name, value, fp->std, fp->ast, fp->value);
67534f9b3eeSRoland Mainz #endif
676*b30d1939SAndy Fiddaman 		if (state.synthesizing && value == (char*)fp->std)
677*b30d1939SAndy Fiddaman 			fp->value = (char*)value;
678*b30d1939SAndy Fiddaman 		else if (!synthesize(fp, path, value))
67934f9b3eeSRoland Mainz 			initialize(fp, path, NiL, fp->std, fp->value);
68034f9b3eeSRoland Mainz #if DEBUG_astconf
681*b30d1939SAndy Fiddaman 		error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s", state.std, fp->name, value, fp->std, fp->ast, fp->value);
68234f9b3eeSRoland Mainz #endif
683*b30d1939SAndy Fiddaman 		if (!state.std && value == fp->std)
68434f9b3eeSRoland Mainz 		{
68534f9b3eeSRoland Mainz 			state.std = 1;
686da2e3ebdSchin 			for (sp = state.features; sp; sp = sp->next)
68734f9b3eeSRoland Mainz 				if (sp->std && sp->op && sp->op != OP_conformance)
688*b30d1939SAndy Fiddaman 					feature(sp, 0, path, sp->std, 0, 0);
68934f9b3eeSRoland Mainz 		}
69034f9b3eeSRoland Mainz #if DEBUG_astconf
691*b30d1939SAndy Fiddaman 		error(-6, "state.std=%d %s [%s] std=%s ast=%s value=%s", state.std, fp->name, value, fp->std, fp->ast, fp->value);
69234f9b3eeSRoland Mainz #endif
693da2e3ebdSchin 		break;
694da2e3ebdSchin 
695da2e3ebdSchin 	case OP_fs_3d:
696da2e3ebdSchin 		fp->value = fs3d(value ? value[0] ? FS3D_ON : FS3D_OFF : FS3D_TEST) ? "1" : null;
697da2e3ebdSchin 		break;
698da2e3ebdSchin 
699da2e3ebdSchin 	case OP_hosttype:
700da2e3ebdSchin 		break;
701da2e3ebdSchin 
702da2e3ebdSchin 	case OP_path_attributes:
703da2e3ebdSchin #ifdef _PC_PATH_ATTRIBUTES
704da2e3ebdSchin 		{
705da2e3ebdSchin 			register char*	s;
706da2e3ebdSchin 			register char*	e;
707da2e3ebdSchin 			intmax_t	v;
708da2e3ebdSchin 
709da2e3ebdSchin 			/*
710da2e3ebdSchin 			 * _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
711da2e3ebdSchin 			 */
712da2e3ebdSchin 
713da2e3ebdSchin 			if ((v = pathconf(path, _PC_PATH_ATTRIBUTES)) == -1L)
714da2e3ebdSchin 				return 0;
715da2e3ebdSchin 			s = fp->value;
716da2e3ebdSchin 			e = s + sizeof(fp->value) - 1;
717da2e3ebdSchin 			for (n = 'a'; n <= 'z'; n++)
718da2e3ebdSchin 				if (v & (1 << (n - 'a')))
719da2e3ebdSchin 				{
720da2e3ebdSchin 					*s++ = n;
721da2e3ebdSchin 					if (s >= e)
722da2e3ebdSchin 						break;
723da2e3ebdSchin 				}
724da2e3ebdSchin 			*s = 0;
725da2e3ebdSchin 		}
726da2e3ebdSchin #endif
727da2e3ebdSchin 		break;
728da2e3ebdSchin 
729da2e3ebdSchin 	case OP_path_resolve:
730*b30d1939SAndy Fiddaman 		if (state.synthesizing && value == (char*)fp->std)
731*b30d1939SAndy Fiddaman 			fp->value = (char*)value;
732*b30d1939SAndy Fiddaman 		else if (!synthesize(fp, path, value))
73334f9b3eeSRoland Mainz 			initialize(fp, path, NiL, "logical", DEFAULT(OP_path_resolve));
734da2e3ebdSchin 		break;
735da2e3ebdSchin 
736da2e3ebdSchin 	case OP_universe:
737da2e3ebdSchin #if _lib_universe
738da2e3ebdSchin 		if (getuniverse(fp->value) < 0)
73934f9b3eeSRoland Mainz 			strcpy(fp->value, DEFAULT(OP_universe));
740da2e3ebdSchin 		if (value)
741da2e3ebdSchin 			setuniverse(value);
742da2e3ebdSchin #else
743da2e3ebdSchin #ifdef UNIV_MAX
744da2e3ebdSchin 		n = 0;
745da2e3ebdSchin 		if (value)
746da2e3ebdSchin 		{
747*b30d1939SAndy Fiddaman 			while (n < univ_max && !streq(value, univ_name[n]))
748da2e3ebdSchin 				n++;
749da2e3ebdSchin 			if (n >= univ_max)
750da2e3ebdSchin 			{
751da2e3ebdSchin 				if (conferror)
752da2e3ebdSchin 					(*conferror)(&state, &state, 2, "%s: %s: universe value too large", fp->name, value);
753da2e3ebdSchin 				return 0;
754da2e3ebdSchin 			}
755da2e3ebdSchin 		}
756da2e3ebdSchin #ifdef ATT_UNIV
757da2e3ebdSchin 		n = setuniverse(n + 1);
758da2e3ebdSchin 		if (!value && n > 0)
759da2e3ebdSchin 			setuniverse(n);
760da2e3ebdSchin #else
761da2e3ebdSchin 		n = universe(value ? n + 1 : U_GET);
762da2e3ebdSchin #endif
763da2e3ebdSchin 		if (n <= 0 || n >= univ_max)
764da2e3ebdSchin 			n = 1;
765da2e3ebdSchin 		strcpy(fp->value, univ_name[n - 1]);
766da2e3ebdSchin #else
7677c2fbfb3SApril Chin 		if (value && streq(path, "="))
76834f9b3eeSRoland Mainz 		{
76934f9b3eeSRoland Mainz 			if (state.synthesizing)
77034f9b3eeSRoland Mainz 			{
77134f9b3eeSRoland Mainz 				if (!(fp->flags & CONF_ALLOC))
77234f9b3eeSRoland Mainz 					fp->value = 0;
77334f9b3eeSRoland Mainz 				n = strlen(value);
77434f9b3eeSRoland Mainz 				if (!(fp->value = newof(fp->value, char, n, 1)))
77534f9b3eeSRoland Mainz 					fp->value = null;
77634f9b3eeSRoland Mainz 				else
77734f9b3eeSRoland Mainz 				{
77834f9b3eeSRoland Mainz 					fp->flags |= CONF_ALLOC;
77934f9b3eeSRoland Mainz 					memcpy(fp->value, value, n);
78034f9b3eeSRoland Mainz 					fp->value[n] = 0;
78134f9b3eeSRoland Mainz 				}
78234f9b3eeSRoland Mainz 			}
78334f9b3eeSRoland Mainz 			else
78434f9b3eeSRoland Mainz 				synthesize(fp, path, value);
78534f9b3eeSRoland Mainz 		}
7867c2fbfb3SApril Chin 		else
78734f9b3eeSRoland Mainz 			initialize(fp, path, "echo", DEFAULT(OP_universe), "ucb");
788da2e3ebdSchin #endif
789da2e3ebdSchin #endif
790da2e3ebdSchin 		break;
791da2e3ebdSchin 
792da2e3ebdSchin 	default:
793*b30d1939SAndy Fiddaman 		if (state.synthesizing && value == (char*)fp->std)
794*b30d1939SAndy Fiddaman 			fp->value = (char*)value;
795*b30d1939SAndy Fiddaman 		else
796*b30d1939SAndy Fiddaman 			synthesize(fp, path, value);
797da2e3ebdSchin 		break;
798da2e3ebdSchin 
799da2e3ebdSchin 	}
8007c2fbfb3SApril Chin 	if (streq(path, "="))
8017c2fbfb3SApril Chin 		fp->flags |= CONF_GLOBAL;
802da2e3ebdSchin 	return fp->value;
803da2e3ebdSchin }
804da2e3ebdSchin 
805da2e3ebdSchin /*
806da2e3ebdSchin  * value==0 get feature name
807da2e3ebdSchin  * value!=0 set feature name
808da2e3ebdSchin  * 0 returned if error or not defined; otherwise previous value
809da2e3ebdSchin  */
810da2e3ebdSchin 
811da2e3ebdSchin static char*
feature(register Feature_t * fp,const char * name,const char * path,const char * value,unsigned int flags,Error_f conferror)812*b30d1939SAndy Fiddaman feature(register Feature_t* fp, const char* name, const char* path, const char* value, unsigned int flags, Error_f conferror)
813da2e3ebdSchin {
814da2e3ebdSchin 	register int		n;
815da2e3ebdSchin 
816da2e3ebdSchin 	if (value && (streq(value, "-") || streq(value, "0")))
817da2e3ebdSchin 		value = null;
818*b30d1939SAndy Fiddaman 	if (!fp)
819*b30d1939SAndy Fiddaman 		for (fp = state.features; fp && !streq(fp->name, name); fp = fp->next);
82034f9b3eeSRoland Mainz #if DEBUG_astconf
821*b30d1939SAndy Fiddaman 	error(-6, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p%s", name, path, value, flags, fp, state.synthesizing ? " SYNTHESIZING" : "");
822da2e3ebdSchin #endif
823da2e3ebdSchin 	if (!fp)
824da2e3ebdSchin 	{
825da2e3ebdSchin 		if (!value)
826da2e3ebdSchin 			return 0;
827da2e3ebdSchin 		if (state.notify && !(*state.notify)(name, path, value))
828da2e3ebdSchin 			return 0;
829da2e3ebdSchin 		n = strlen(name);
830da2e3ebdSchin 		if (!(fp = newof(0, Feature_t, 1, n + 1)))
831da2e3ebdSchin 		{
832da2e3ebdSchin 			if (conferror)
833da2e3ebdSchin 				(*conferror)(&state, &state, 2, "%s: out of space", name);
834da2e3ebdSchin 			return 0;
835da2e3ebdSchin 		}
83634f9b3eeSRoland Mainz 		fp->op = -1;
837da2e3ebdSchin 		fp->name = (const char*)fp + sizeof(Feature_t);
838da2e3ebdSchin 		strcpy((char*)fp->name, name);
839da2e3ebdSchin 		fp->length = n;
84034f9b3eeSRoland Mainz 		fp->std = &null[0];
841da2e3ebdSchin 		fp->next = state.features;
842da2e3ebdSchin 		state.features = fp;
843da2e3ebdSchin 	}
844da2e3ebdSchin 	else if (value)
845da2e3ebdSchin 	{
846da2e3ebdSchin 		if (fp->flags & CONF_READONLY)
847da2e3ebdSchin 		{
848da2e3ebdSchin 			if (conferror)
849da2e3ebdSchin 				(*conferror)(&state, &state, 2, "%s: cannot set readonly symbol", fp->name);
850da2e3ebdSchin 			return 0;
851da2e3ebdSchin 		}
852da2e3ebdSchin 		if (state.notify && !streq(fp->value, value) && !(*state.notify)(name, path, value))
853da2e3ebdSchin 			return 0;
854da2e3ebdSchin 	}
855da2e3ebdSchin 	else
856da2e3ebdSchin 		state.recent = fp;
857da2e3ebdSchin 	return format(fp, path, value, flags, conferror);
858da2e3ebdSchin }
859da2e3ebdSchin 
860da2e3ebdSchin /*
861da2e3ebdSchin  * binary search for name in conf[]
862da2e3ebdSchin  */
863da2e3ebdSchin 
864da2e3ebdSchin static int
lookup(register Lookup_t * look,const char * name,unsigned int flags)8657c2fbfb3SApril Chin lookup(register Lookup_t* look, const char* name, unsigned int flags)
866da2e3ebdSchin {
867da2e3ebdSchin 	register Conf_t*	mid = (Conf_t*)conf;
868da2e3ebdSchin 	register Conf_t*	lo = mid;
869da2e3ebdSchin 	register Conf_t*	hi = mid + conf_elements;
870da2e3ebdSchin 	register int		v;
871da2e3ebdSchin 	register int		c;
872da2e3ebdSchin 	char*			e;
873da2e3ebdSchin 	const Prefix_t*		p;
874da2e3ebdSchin 
875da2e3ebdSchin 	static Conf_t		num;
876da2e3ebdSchin 
877da2e3ebdSchin 	look->flags = 0;
878da2e3ebdSchin 	look->call = -1;
879da2e3ebdSchin 	look->standard = (flags & ASTCONF_AST) ? CONF_AST : -1;
880da2e3ebdSchin 	look->section = -1;
881da2e3ebdSchin 	while (*name == '_')
882da2e3ebdSchin 		name++;
883da2e3ebdSchin  again:
884da2e3ebdSchin 	for (p = prefix; p < &prefix[prefix_elements]; p++)
8857c2fbfb3SApril 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] == '_')))
886da2e3ebdSchin 		{
887da2e3ebdSchin 			if (p->call < 0)
888da2e3ebdSchin 			{
889da2e3ebdSchin 				if (look->standard >= 0)
890da2e3ebdSchin 					break;
891da2e3ebdSchin 				look->standard = p->standard;
892da2e3ebdSchin 			}
893da2e3ebdSchin 			else
894da2e3ebdSchin 			{
895da2e3ebdSchin 				if (look->call >= 0)
896da2e3ebdSchin 					break;
897da2e3ebdSchin 				look->call = p->call;
898da2e3ebdSchin 			}
8997c2fbfb3SApril Chin 			if (name[p->length] == '(' || name[p->length] == '#')
900da2e3ebdSchin 			{
901da2e3ebdSchin 				look->conf = &num;
902*b30d1939SAndy Fiddaman 				strlcpy((char*)num.name, name, sizeof(num.name));
903da2e3ebdSchin 				num.call = p->call;
904da2e3ebdSchin 				num.flags = *name == 'C' ? CONF_STRING : 0;
905da2e3ebdSchin 				num.op = (short)strtol(name + p->length + 1, &e, 10);
9067c2fbfb3SApril Chin 				if (name[p->length] == '(' && *e == ')')
9077c2fbfb3SApril Chin 					e++;
9087c2fbfb3SApril Chin 				if (*e)
909da2e3ebdSchin 					break;
910da2e3ebdSchin 				return 1;
911da2e3ebdSchin 			}
912da2e3ebdSchin 			name += p->length + c;
913da2e3ebdSchin 			if (look->section < 0 && !c && v)
914da2e3ebdSchin 			{
915da2e3ebdSchin 				look->section = name[0] - '0';
916da2e3ebdSchin 				name += 2;
917da2e3ebdSchin 			}
918da2e3ebdSchin 			goto again;
919da2e3ebdSchin 		}
920da2e3ebdSchin #if HUH_2006_02_10
921da2e3ebdSchin 	if (look->section < 0)
922da2e3ebdSchin 		look->section = 1;
923da2e3ebdSchin #endif
924da2e3ebdSchin 	look->name = name;
92534f9b3eeSRoland Mainz #if DEBUG_astconf
926*b30d1939SAndy Fiddaman 	error(-6, "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);
927da2e3ebdSchin #endif
928da2e3ebdSchin 	c = *((unsigned char*)name);
929da2e3ebdSchin 	while (lo <= hi)
930da2e3ebdSchin 	{
931da2e3ebdSchin 		mid = lo + (hi - lo) / 2;
93234f9b3eeSRoland Mainz #if DEBUG_astconf
933*b30d1939SAndy Fiddaman 		error(-7, "astconf lookup name=%s mid=%s", name, mid->name);
934da2e3ebdSchin #endif
935da2e3ebdSchin 		if (!(v = c - *((unsigned char*)mid->name)) && !(v = strcmp(name, mid->name)))
936da2e3ebdSchin 		{
937da2e3ebdSchin 			hi = mid;
938da2e3ebdSchin 			lo = (Conf_t*)conf;
939da2e3ebdSchin 			do
940da2e3ebdSchin 			{
941da2e3ebdSchin 				if ((look->standard < 0 || look->standard == mid->standard) &&
942da2e3ebdSchin 				    (look->section < 0 || look->section == mid->section) &&
943da2e3ebdSchin 				    (look->call < 0 || look->call == mid->call))
944da2e3ebdSchin 					goto found;
945da2e3ebdSchin 			} while (mid-- > lo && streq(mid->name, look->name));
946da2e3ebdSchin 			mid = hi;
947da2e3ebdSchin 			hi = lo + conf_elements - 1;
948da2e3ebdSchin 			while (++mid < hi && streq(mid->name, look->name))
949da2e3ebdSchin 			{
950da2e3ebdSchin 				if ((look->standard < 0 || look->standard == mid->standard) &&
951da2e3ebdSchin 				    (look->section < 0 || look->section == mid->section) &&
952da2e3ebdSchin 				    (look->call < 0 || look->call == mid->call))
953da2e3ebdSchin 					goto found;
954da2e3ebdSchin 			}
955da2e3ebdSchin 			break;
956da2e3ebdSchin 		}
957da2e3ebdSchin 		else if (v > 0)
958da2e3ebdSchin 			lo = mid + 1;
959da2e3ebdSchin 		else
960da2e3ebdSchin 			hi = mid - 1;
961da2e3ebdSchin 	}
962da2e3ebdSchin 	return 0;
963da2e3ebdSchin  found:
964da2e3ebdSchin 	if (look->call < 0 && look->standard >= 0 && (look->section <= 1 || (mid->flags & CONF_MINMAX)))
965da2e3ebdSchin 		look->flags |= CONF_MINMAX;
966da2e3ebdSchin 	look->conf = mid;
96734f9b3eeSRoland Mainz #if DEBUG_astconf
968*b30d1939SAndy Fiddaman 	error(-6, "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);
969da2e3ebdSchin #endif
970da2e3ebdSchin 	return 1;
971da2e3ebdSchin }
972da2e3ebdSchin 
973da2e3ebdSchin /*
974da2e3ebdSchin  * return a tolower'd copy of s
975da2e3ebdSchin  */
976da2e3ebdSchin 
977da2e3ebdSchin static char*
fmtlower(register const char * s)978da2e3ebdSchin fmtlower(register const char* s)
979da2e3ebdSchin {
980da2e3ebdSchin 	register int	c;
981da2e3ebdSchin 	register char*	t;
982da2e3ebdSchin 	char*		b;
983da2e3ebdSchin 
984da2e3ebdSchin 	b = t = fmtbuf(strlen(s) + 1);
985da2e3ebdSchin 	while (c = *s++)
986da2e3ebdSchin 	{
987da2e3ebdSchin 		if (isupper(c))
988da2e3ebdSchin 			c = tolower(c);
989da2e3ebdSchin 		*t++ = c;
990da2e3ebdSchin 	}
991da2e3ebdSchin 	*t = 0;
992da2e3ebdSchin 	return b;
993da2e3ebdSchin }
994da2e3ebdSchin 
995da2e3ebdSchin /*
996da2e3ebdSchin  * print value line for p
997da2e3ebdSchin  * if !name then value prefixed by "p->name="
998da2e3ebdSchin  * if (flags & CONF_MINMAX) then default minmax value used
999da2e3ebdSchin  */
1000da2e3ebdSchin 
1001da2e3ebdSchin static char*
print(Sfio_t * sp,register Lookup_t * look,const char * name,const char * path,int listflags,Error_f conferror)1002da2e3ebdSchin print(Sfio_t* sp, register Lookup_t* look, const char* name, const char* path, int listflags, Error_f conferror)
1003da2e3ebdSchin {
1004da2e3ebdSchin 	register Conf_t*	p = look->conf;
10057c2fbfb3SApril Chin 	register unsigned int	flags = look->flags;
1006*b30d1939SAndy Fiddaman 	Feature_t*		fp;
1007da2e3ebdSchin 	char*			call;
1008da2e3ebdSchin 	char*			f;
1009da2e3ebdSchin 	const char*		s;
1010da2e3ebdSchin 	int			i;
10117c2fbfb3SApril Chin 	int			n;
1012da2e3ebdSchin 	int			olderrno;
1013da2e3ebdSchin 	int			drop;
1014da2e3ebdSchin 	int			defined;
1015da2e3ebdSchin 	intmax_t		v;
1016da2e3ebdSchin 	char			buf[PATH_MAX];
1017da2e3ebdSchin 	char			flg[16];
1018da2e3ebdSchin 
1019da2e3ebdSchin 	if (!name && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_LIMIT|CONF_MINMAX)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
1020da2e3ebdSchin 		flags |= CONF_PREFIXED;
1021da2e3ebdSchin 	olderrno = errno;
1022da2e3ebdSchin 	errno = 0;
102334f9b3eeSRoland Mainz #if DEBUG_astconf
1024*b30d1939SAndy Fiddaman 	error(-5, "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"
102534f9b3eeSRoland Mainz 		, name, look->name, p->name, p->standard, p->section, prefix[p->call + CONF_call].name, p->op
1026da2e3ebdSchin 		, (flags & CONF_FEATURE) ? "FEATURE|" : ""
1027da2e3ebdSchin 		, (flags & CONF_LIMIT) ? "LIMIT|" : ""
1028da2e3ebdSchin 		, (flags & CONF_MINMAX) ? "MINMAX|" : ""
1029da2e3ebdSchin 		, (flags & CONF_PREFIXED) ? "PREFIXED|" : ""
1030da2e3ebdSchin 		, (flags & CONF_STRING) ? "STRING|" : ""
1031da2e3ebdSchin 		, (p->flags & CONF_DEFER_CALL) ? "DEFER_CALL|" : ""
1032da2e3ebdSchin 		, (p->flags & CONF_DEFER_MM) ? "DEFER_MM|" : ""
1033da2e3ebdSchin 		, (p->flags & CONF_FEATURE) ? "FEATURE|" : ""
1034da2e3ebdSchin 		, (p->flags & CONF_LIMIT_DEF) ? "LIMIT_DEF|" : (p->flags & CONF_LIMIT) ? "LIMIT|" : ""
1035da2e3ebdSchin 		, (p->flags & CONF_MINMAX_DEF) ? "MINMAX_DEF|" : (p->flags & CONF_MINMAX) ? "MINMAX|" : ""
1036da2e3ebdSchin 		, (p->flags & CONF_NOUNDERSCORE) ? "NOUNDERSCORE|" : ""
1037da2e3ebdSchin 		, (p->flags & CONF_PREFIXED) ? "PREFIXED|" : ""
1038da2e3ebdSchin 		, (p->flags & CONF_PREFIX_ONLY) ? "PREFIX_ONLY|" : ""
1039da2e3ebdSchin 		, (p->flags & CONF_STANDARD) ? "STANDARD|" : ""
1040da2e3ebdSchin 		, (p->flags & CONF_STRING) ? "STRING|" : ""
1041da2e3ebdSchin 		, (p->flags & CONF_UNDERSCORE) ? "UNDERSCORE|" : ""
1042da2e3ebdSchin 		);
1043da2e3ebdSchin #endif
1044da2e3ebdSchin 	flags |= CONF_LIMIT_DEF|CONF_MINMAX_DEF;
1045da2e3ebdSchin 	if (conferror && name)
1046da2e3ebdSchin 	{
1047da2e3ebdSchin 		if ((p->flags & CONF_PREFIX_ONLY) && look->standard < 0)
1048da2e3ebdSchin 			goto bad;
1049da2e3ebdSchin 		if (!(flags & CONF_MINMAX) || !(p->flags & CONF_MINMAX))
1050da2e3ebdSchin 		{
1051da2e3ebdSchin 			switch (p->call)
1052da2e3ebdSchin 			{
1053da2e3ebdSchin 			case CONF_pathconf:
1054da2e3ebdSchin 				if (path == root)
1055da2e3ebdSchin 				{
1056da2e3ebdSchin 					(*conferror)(&state, &state, 2, "%s: path expected", name);
1057da2e3ebdSchin 					goto bad;
1058da2e3ebdSchin 				}
1059da2e3ebdSchin 				break;
1060da2e3ebdSchin 			default:
1061da2e3ebdSchin 				if (path != root)
1062da2e3ebdSchin 				{
1063da2e3ebdSchin 					(*conferror)(&state, &state, 2, "%s: path not expected", name);
1064da2e3ebdSchin 					goto bad;
1065da2e3ebdSchin 				}
1066da2e3ebdSchin 				break;
1067da2e3ebdSchin 			}
1068da2e3ebdSchin #ifdef _pth_getconf
1069da2e3ebdSchin 			if (p->flags & CONF_DEFER_CALL)
1070da2e3ebdSchin 				goto bad;
1071da2e3ebdSchin #endif
1072da2e3ebdSchin 		}
1073da2e3ebdSchin 		else
1074da2e3ebdSchin 		{
1075da2e3ebdSchin 			if (path != root)
1076da2e3ebdSchin 			{
1077da2e3ebdSchin 				(*conferror)(&state, &state, 2, "%s: path not expected", name);
1078da2e3ebdSchin 				goto bad;
1079da2e3ebdSchin 			}
1080da2e3ebdSchin #ifdef _pth_getconf
1081da2e3ebdSchin 			if ((p->flags & CONF_DEFER_MM) || !(p->flags & CONF_MINMAX_DEF))
1082da2e3ebdSchin 				goto bad;
1083da2e3ebdSchin #endif
1084da2e3ebdSchin 		}
1085da2e3ebdSchin 		if (look->standard >= 0 && (name[0] != '_' && ((p->flags & CONF_UNDERSCORE) || look->section <= 1) || name[0] == '_' && (p->flags & CONF_NOUNDERSCORE)) || look->standard < 0 && name[0] == '_')
1086da2e3ebdSchin 			goto bad;
1087da2e3ebdSchin 	}
1088da2e3ebdSchin 	s = 0;
1089da2e3ebdSchin 	defined = 1;
1090da2e3ebdSchin 	switch (i = (p->op < 0 || (flags & CONF_MINMAX) && (p->flags & CONF_MINMAX_DEF)) ? 0 : p->call)
1091da2e3ebdSchin 	{
1092da2e3ebdSchin 	case CONF_confstr:
1093da2e3ebdSchin 		call = "confstr";
1094da2e3ebdSchin #if _lib_confstr
1095da2e3ebdSchin 		if (!(v = confstr(p->op, buf, sizeof(buf))))
1096da2e3ebdSchin 		{
1097da2e3ebdSchin 			defined = 0;
1098da2e3ebdSchin 			v = -1;
1099da2e3ebdSchin 			errno = EINVAL;
1100da2e3ebdSchin 		}
1101da2e3ebdSchin 		else if (v > 0)
1102da2e3ebdSchin 		{
1103da2e3ebdSchin 			buf[sizeof(buf) - 1] = 0;
1104da2e3ebdSchin 			s = (const char*)buf;
1105da2e3ebdSchin 		}
1106da2e3ebdSchin 		else
1107da2e3ebdSchin 			defined = 0;
1108da2e3ebdSchin 		break;
1109da2e3ebdSchin #else
1110da2e3ebdSchin 		goto predef;
1111da2e3ebdSchin #endif
1112da2e3ebdSchin 	case CONF_pathconf:
1113da2e3ebdSchin 		call = "pathconf";
1114da2e3ebdSchin #if _lib_pathconf
1115da2e3ebdSchin 		if ((v = pathconf(path, p->op)) < 0)
1116da2e3ebdSchin 			defined = 0;
1117da2e3ebdSchin 		break;
1118da2e3ebdSchin #else
1119da2e3ebdSchin 		goto predef;
1120da2e3ebdSchin #endif
1121da2e3ebdSchin 	case CONF_sysconf:
1122da2e3ebdSchin 		call = "sysconf";
1123da2e3ebdSchin #if _lib_sysconf
1124da2e3ebdSchin 		if ((v = sysconf(p->op)) < 0)
1125da2e3ebdSchin 			defined = 0;
1126da2e3ebdSchin 		break;
1127da2e3ebdSchin #else
1128da2e3ebdSchin 		goto predef;
1129da2e3ebdSchin #endif
1130da2e3ebdSchin 	case CONF_sysinfo:
1131da2e3ebdSchin 		call = "sysinfo";
1132da2e3ebdSchin #if _lib_sysinfo
1133da2e3ebdSchin 		if ((v = sysinfo(p->op, buf, sizeof(buf))) >= 0)
1134da2e3ebdSchin 		{
1135da2e3ebdSchin 			buf[sizeof(buf) - 1] = 0;
1136da2e3ebdSchin 			s = (const char*)buf;
1137da2e3ebdSchin 		}
1138da2e3ebdSchin 		else
1139da2e3ebdSchin 			defined = 0;
1140da2e3ebdSchin 		break;
1141da2e3ebdSchin #else
1142da2e3ebdSchin 		goto predef;
1143da2e3ebdSchin #endif
1144da2e3ebdSchin 	default:
1145da2e3ebdSchin 		call = "synthesis";
1146da2e3ebdSchin 		errno = EINVAL;
1147da2e3ebdSchin 		v = -1;
1148da2e3ebdSchin 		defined = 0;
1149da2e3ebdSchin 		break;
1150da2e3ebdSchin 	case 0:
1151da2e3ebdSchin 		call = 0;
11527c2fbfb3SApril Chin 		if (p->standard == CONF_AST)
11537c2fbfb3SApril Chin 		{
1154*b30d1939SAndy Fiddaman 			if (streq(p->name, "RELEASE") && (i = open("/proc/version", O_RDONLY|O_cloexec)) >= 0)
11557c2fbfb3SApril Chin 			{
11567c2fbfb3SApril Chin 				n = read(i, buf, sizeof(buf) - 1);
11577c2fbfb3SApril Chin 				close(i);
11587c2fbfb3SApril Chin 				if (n > 0 && buf[n - 1] == '\n')
11597c2fbfb3SApril Chin 					n--;
11607c2fbfb3SApril Chin 				if (n > 0 && buf[n - 1] == '\r')
11617c2fbfb3SApril Chin 					n--;
11627c2fbfb3SApril Chin 				buf[n] = 0;
11637c2fbfb3SApril Chin 				if (buf[0])
11647c2fbfb3SApril Chin 				{
11657c2fbfb3SApril Chin 					v = 0;
11667c2fbfb3SApril Chin 					s = buf;
11677c2fbfb3SApril Chin 					break;
11687c2fbfb3SApril Chin 				}
11697c2fbfb3SApril Chin 			}
11707c2fbfb3SApril Chin 		}
1171da2e3ebdSchin 		if (p->flags & CONF_MINMAX_DEF)
1172da2e3ebdSchin 		{
1173da2e3ebdSchin 			if (!((p->flags & CONF_LIMIT_DEF)))
1174da2e3ebdSchin 				flags |= CONF_MINMAX;
1175da2e3ebdSchin 			listflags &= ~ASTCONF_system;
1176da2e3ebdSchin 		}
1177da2e3ebdSchin 	predef:
1178da2e3ebdSchin 		if (look->standard == CONF_AST)
1179da2e3ebdSchin 		{
118034f9b3eeSRoland Mainz 			if (streq(p->name, "VERSION"))
1181da2e3ebdSchin 			{
11823e14f97fSRoger A. Faulkner 				v = ast.version;
1183da2e3ebdSchin 				break;
1184da2e3ebdSchin 			}
1185da2e3ebdSchin 		}
1186da2e3ebdSchin 		if (flags & CONF_MINMAX)
1187da2e3ebdSchin 		{
1188da2e3ebdSchin 			if ((p->flags & CONF_MINMAX_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_MM)))
1189da2e3ebdSchin 			{
1190da2e3ebdSchin 				v = p->minmax.number;
1191da2e3ebdSchin 				s = p->minmax.string;
1192da2e3ebdSchin 				break;
1193da2e3ebdSchin 			}
1194da2e3ebdSchin 		}
1195da2e3ebdSchin 		else if ((p->flags & CONF_LIMIT_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_CALL)))
1196da2e3ebdSchin 		{
1197da2e3ebdSchin 			v = p->limit.number;
1198da2e3ebdSchin 			s = p->limit.string;
1199da2e3ebdSchin 			break;
1200da2e3ebdSchin 		}
1201da2e3ebdSchin 		flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1202da2e3ebdSchin 		v = -1;
1203da2e3ebdSchin 		errno = EINVAL;
1204da2e3ebdSchin 		defined = 0;
1205da2e3ebdSchin 		break;
1206da2e3ebdSchin 	}
1207da2e3ebdSchin 	if (!defined)
1208da2e3ebdSchin 	{
1209da2e3ebdSchin 		if (!errno)
1210da2e3ebdSchin 		{
1211da2e3ebdSchin 			if ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX)))
1212da2e3ebdSchin 				flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1213da2e3ebdSchin 		}
1214da2e3ebdSchin 		else if (flags & CONF_PREFIXED)
1215da2e3ebdSchin 			flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1216da2e3ebdSchin 		else if (errno != EINVAL || !i)
1217da2e3ebdSchin 		{
1218da2e3ebdSchin 			if (!sp)
1219da2e3ebdSchin 			{
1220da2e3ebdSchin 				if (conferror)
1221da2e3ebdSchin 				{
1222da2e3ebdSchin 					if (call)
1223da2e3ebdSchin 						(*conferror)(&state, &state, ERROR_SYSTEM|2, "%s: %s error", p->name, call);
1224da2e3ebdSchin 					else if (!(listflags & ASTCONF_system))
1225da2e3ebdSchin 						(*conferror)(&state, &state, 2, "%s: unknown name", p->name);
1226da2e3ebdSchin 				}
1227da2e3ebdSchin 				goto bad;
1228da2e3ebdSchin 			}
1229da2e3ebdSchin 			else
1230da2e3ebdSchin 			{
1231da2e3ebdSchin 				flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1232da2e3ebdSchin 				flags |= CONF_ERROR;
1233da2e3ebdSchin 			}
1234da2e3ebdSchin 		}
1235da2e3ebdSchin 	}
1236da2e3ebdSchin 	errno = olderrno;
1237da2e3ebdSchin 	if ((listflags & ASTCONF_defined) && !(flags & (CONF_LIMIT_DEF|CONF_MINMAX_DEF)))
1238da2e3ebdSchin 		goto bad;
1239da2e3ebdSchin 	if ((drop = !sp) && !(sp = sfstropen()))
1240da2e3ebdSchin 		goto bad;
1241da2e3ebdSchin 	if (listflags & ASTCONF_table)
1242da2e3ebdSchin 	{
1243da2e3ebdSchin 		f = flg;
1244da2e3ebdSchin 		if (p->flags & CONF_DEFER_CALL)
1245da2e3ebdSchin 			*f++ = 'C';
1246da2e3ebdSchin 		if (p->flags & CONF_DEFER_MM)
1247da2e3ebdSchin 			*f++ = 'D';
1248da2e3ebdSchin 		if (p->flags & CONF_FEATURE)
1249da2e3ebdSchin 			*f++ = 'F';
1250da2e3ebdSchin 		if (p->flags & CONF_LIMIT)
1251da2e3ebdSchin 			*f++ = 'L';
1252da2e3ebdSchin 		if (p->flags & CONF_MINMAX)
1253da2e3ebdSchin 			*f++ = 'M';
1254da2e3ebdSchin 		if (p->flags & CONF_NOSECTION)
1255da2e3ebdSchin 			*f++ = 'N';
1256da2e3ebdSchin 		if (p->flags & CONF_PREFIXED)
1257da2e3ebdSchin 			*f++ = 'P';
1258da2e3ebdSchin 		if (p->flags & CONF_STANDARD)
1259da2e3ebdSchin 			*f++ = 'S';
1260da2e3ebdSchin 		if (p->flags & CONF_UNDERSCORE)
1261da2e3ebdSchin 			*f++ = 'U';
1262da2e3ebdSchin 		if (p->flags & CONF_NOUNDERSCORE)
1263da2e3ebdSchin 			*f++ = 'V';
1264da2e3ebdSchin 		if (p->flags & CONF_PREFIX_ONLY)
1265da2e3ebdSchin 			*f++ = 'W';
1266da2e3ebdSchin 		if (f == flg)
1267da2e3ebdSchin 			*f++ = 'X';
1268da2e3ebdSchin 		*f = 0;
1269da2e3ebdSchin 		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);
1270da2e3ebdSchin 		if (p->flags & CONF_LIMIT_DEF)
1271da2e3ebdSchin 		{
1272da2e3ebdSchin 			if (p->limit.string)
1273da2e3ebdSchin 				sfprintf(sp, "L[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->limit.string, "\"", "\"", strlen(p->limit.string), FMT_SHELL) : p->limit.string);
1274da2e3ebdSchin 			else
1275da2e3ebdSchin 				sfprintf(sp, "L[%I*d] ", sizeof(p->limit.number), p->limit.number);
1276da2e3ebdSchin 		}
1277da2e3ebdSchin 		if (p->flags & CONF_MINMAX_DEF)
1278da2e3ebdSchin 		{
1279da2e3ebdSchin 			if (p->minmax.string)
1280da2e3ebdSchin 				sfprintf(sp, "M[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->minmax.string, "\"", "\"", strlen(p->minmax.string), FMT_SHELL) : p->minmax.string);
1281da2e3ebdSchin 			else
1282da2e3ebdSchin 				sfprintf(sp, "M[%I*d] ", sizeof(p->minmax.number), p->minmax.number);
1283da2e3ebdSchin 		}
1284da2e3ebdSchin 		if (flags & CONF_ERROR)
1285da2e3ebdSchin 			sfprintf(sp, "error");
1286da2e3ebdSchin 		else if (defined)
1287da2e3ebdSchin 		{
1288da2e3ebdSchin 			if (s)
1289da2e3ebdSchin 				sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1290da2e3ebdSchin 			else if (v != -1)
1291da2e3ebdSchin 				sfprintf(sp, "%I*d", sizeof(v), v);
1292da2e3ebdSchin 			else
1293da2e3ebdSchin 				sfprintf(sp, "%I*u", sizeof(v), v);
1294da2e3ebdSchin 		}
1295da2e3ebdSchin 		sfprintf(sp, "\n");
1296da2e3ebdSchin 	}
1297da2e3ebdSchin 	else
1298da2e3ebdSchin 	{
1299da2e3ebdSchin 		if (!(flags & CONF_PREFIXED) || (listflags & ASTCONF_base))
1300da2e3ebdSchin 		{
1301da2e3ebdSchin 			if (!name)
1302da2e3ebdSchin 			{
1303da2e3ebdSchin 				if ((p->flags & (CONF_PREFIXED|CONF_STRING)) == (CONF_PREFIXED|CONF_STRING) && (!(listflags & ASTCONF_base) || p->standard != CONF_POSIX))
1304da2e3ebdSchin 				{
1305da2e3ebdSchin 					if ((p->flags & CONF_UNDERSCORE) && !(listflags & ASTCONF_base))
1306da2e3ebdSchin 						sfprintf(sp, "_");
1307da2e3ebdSchin 					sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1308da2e3ebdSchin 					if (p->section > 1)
1309da2e3ebdSchin 						sfprintf(sp, "%d", p->section);
1310da2e3ebdSchin 					sfprintf(sp, "_");
1311da2e3ebdSchin 				}
1312da2e3ebdSchin 				sfprintf(sp, "%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1313da2e3ebdSchin 			}
1314da2e3ebdSchin 			if (flags & CONF_ERROR)
1315da2e3ebdSchin 				sfprintf(sp, "error");
1316da2e3ebdSchin 			else if (defined)
1317da2e3ebdSchin 			{
1318da2e3ebdSchin 				if (s)
1319da2e3ebdSchin 					sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1320da2e3ebdSchin 				else if (v != -1)
1321da2e3ebdSchin 					sfprintf(sp, "%I*d", sizeof(v), v);
1322da2e3ebdSchin 				else
1323da2e3ebdSchin 					sfprintf(sp, "%I*u", sizeof(v), v);
1324da2e3ebdSchin 			}
1325da2e3ebdSchin 			else
1326da2e3ebdSchin 				sfprintf(sp, "undefined");
1327da2e3ebdSchin 			if (!name)
1328da2e3ebdSchin 				sfprintf(sp, "\n");
1329da2e3ebdSchin 		}
1330da2e3ebdSchin 		if (!name && !(listflags & ASTCONF_base) && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
1331da2e3ebdSchin 		{
1332da2e3ebdSchin 			if (p->flags & CONF_UNDERSCORE)
1333da2e3ebdSchin 				sfprintf(sp, "_");
1334da2e3ebdSchin 			sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1335da2e3ebdSchin 			if (p->section > 1)
1336da2e3ebdSchin 				sfprintf(sp, "%d", p->section);
1337da2e3ebdSchin 			sfprintf(sp, "_%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1338*b30d1939SAndy Fiddaman 			if (!defined && !name && (p->flags & CONF_MINMAX_DEF))
1339*b30d1939SAndy Fiddaman 			{
1340*b30d1939SAndy Fiddaman 				defined = 1;
1341*b30d1939SAndy Fiddaman 				v = p->minmax.number;
1342*b30d1939SAndy Fiddaman 			}
1343da2e3ebdSchin 			if (v != -1)
1344da2e3ebdSchin 				sfprintf(sp, "%I*d", sizeof(v), v);
1345da2e3ebdSchin 			else if (defined)
1346da2e3ebdSchin 				sfprintf(sp, "%I*u", sizeof(v), v);
1347da2e3ebdSchin 			else
1348da2e3ebdSchin 				sfprintf(sp, "undefined");
1349da2e3ebdSchin 			sfprintf(sp, "\n");
1350da2e3ebdSchin 		}
1351da2e3ebdSchin 	}
1352da2e3ebdSchin 	if (drop)
1353da2e3ebdSchin 	{
1354da2e3ebdSchin 		if (call = sfstruse(sp))
1355da2e3ebdSchin 			call = buffer(call);
1356da2e3ebdSchin 		else
1357da2e3ebdSchin 			call = "[ out of space ]";
1358da2e3ebdSchin 		sfclose(sp);
1359da2e3ebdSchin 		return call;
1360da2e3ebdSchin 	}
1361da2e3ebdSchin  bad:
1362*b30d1939SAndy Fiddaman 	if (!(listflags & ~(ASTCONF_error|ASTCONF_system)))
1363*b30d1939SAndy Fiddaman 		for (fp = state.features; fp; fp = fp->next)
1364*b30d1939SAndy Fiddaman 			if (streq(name, fp->name))
1365*b30d1939SAndy Fiddaman 				return format(fp, path, 0, listflags, conferror);
1366da2e3ebdSchin 	return (listflags & ASTCONF_error) ? (char*)0 : null;
1367da2e3ebdSchin }
1368da2e3ebdSchin 
1369da2e3ebdSchin /*
1370da2e3ebdSchin  * return read stream to native getconf utility
1371da2e3ebdSchin  */
1372da2e3ebdSchin 
1373da2e3ebdSchin static Sfio_t*
nativeconf(Proc_t ** pp,const char * operand)1374da2e3ebdSchin nativeconf(Proc_t** pp, const char* operand)
1375da2e3ebdSchin {
1376da2e3ebdSchin #ifdef _pth_getconf
1377da2e3ebdSchin 	Sfio_t*		sp;
1378da2e3ebdSchin 	char*		cmd[3];
1379da2e3ebdSchin 	long		ops[2];
1380da2e3ebdSchin 
138134f9b3eeSRoland Mainz #if DEBUG_astconf
1382*b30d1939SAndy Fiddaman 	error(-6, "astconf defer %s %s", _pth_getconf, operand);
1383da2e3ebdSchin #endif
1384da2e3ebdSchin 	cmd[0] = (char*)state.id;
1385da2e3ebdSchin 	cmd[1] = (char*)operand;
1386da2e3ebdSchin 	cmd[2] = 0;
1387da2e3ebdSchin 	ops[0] = PROC_FD_DUP(open("/dev/null",O_WRONLY,0), 2, PROC_FD_CHILD);
1388da2e3ebdSchin 	ops[1] = 0;
1389da2e3ebdSchin 	if (*pp = procopen(_pth_getconf, cmd, environ, ops, PROC_READ))
1390da2e3ebdSchin 	{
1391da2e3ebdSchin 		if (sp = sfnew(NiL, NiL, SF_UNBOUND, (*pp)->rfd, SF_READ))
1392da2e3ebdSchin 		{
1393da2e3ebdSchin 			sfdisc(sp, SF_POPDISC);
1394da2e3ebdSchin 			return sp;
1395da2e3ebdSchin 		}
1396da2e3ebdSchin 		procclose(*pp);
1397da2e3ebdSchin 	}
1398da2e3ebdSchin #endif
1399da2e3ebdSchin 	return 0;
1400da2e3ebdSchin }
1401da2e3ebdSchin 
1402da2e3ebdSchin /*
1403da2e3ebdSchin  * value==0 gets value for name
1404da2e3ebdSchin  * value!=0 sets value for name and returns previous value
1405da2e3ebdSchin  * path==0 implies path=="/"
1406da2e3ebdSchin  *
1407da2e3ebdSchin  * settable return values are in permanent store
1408da2e3ebdSchin  * non-settable return values copied to a tmp fmtbuf() buffer
1409da2e3ebdSchin  *
1410da2e3ebdSchin  *	if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
1411da2e3ebdSchin  *		our_way();
1412da2e3ebdSchin  *
1413da2e3ebdSchin  *	universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
1414da2e3ebdSchin  *	astgetconf("UNIVERSE", NiL, universe, 0, 0);
1415da2e3ebdSchin  *
1416da2e3ebdSchin  * if (flags&ASTCONF_error)!=0 then error return value is 0
1417da2e3ebdSchin  * otherwise 0 not returned
1418da2e3ebdSchin  */
1419da2e3ebdSchin 
1420da2e3ebdSchin #define ALT	16
1421da2e3ebdSchin 
1422da2e3ebdSchin char*
astgetconf(const char * name,const char * path,const char * value,int flags,Error_f conferror)1423da2e3ebdSchin astgetconf(const char* name, const char* path, const char* value, int flags, Error_f conferror)
1424da2e3ebdSchin {
1425da2e3ebdSchin 	register char*	s;
1426da2e3ebdSchin 	int		n;
1427da2e3ebdSchin 	Lookup_t	look;
1428da2e3ebdSchin 	Sfio_t*		tmp;
1429da2e3ebdSchin 
1430da2e3ebdSchin #if __OBSOLETE__ < 20080101
1431da2e3ebdSchin 	if (pointerof(flags) == (void*)errorf)
1432da2e3ebdSchin 	{
1433da2e3ebdSchin 		conferror = errorf;
1434da2e3ebdSchin 		flags = ASTCONF_error;
1435da2e3ebdSchin 	}
1436da2e3ebdSchin 	else if (conferror && conferror != errorf)
1437da2e3ebdSchin 		conferror = 0;
1438da2e3ebdSchin #endif
1439da2e3ebdSchin 	if (!name)
1440da2e3ebdSchin 	{
1441da2e3ebdSchin 		if (path)
1442da2e3ebdSchin 			return null;
1443da2e3ebdSchin 		if (!(name = value))
1444da2e3ebdSchin 		{
1445da2e3ebdSchin 			if (state.data)
1446da2e3ebdSchin 			{
1447da2e3ebdSchin 				Ast_confdisc_f	notify;
1448da2e3ebdSchin 
1449da2e3ebdSchin #if _HUH20000515 /* doesn't work for shell builtins */
1450da2e3ebdSchin 				free(state.data - state.prefix);
1451da2e3ebdSchin #endif
1452da2e3ebdSchin 				state.data = 0;
1453da2e3ebdSchin 				notify = state.notify;
1454da2e3ebdSchin 				state.notify = 0;
1455da2e3ebdSchin 				INITIALIZE();
1456da2e3ebdSchin 				state.notify = notify;
1457da2e3ebdSchin 			}
1458da2e3ebdSchin 			return null;
1459da2e3ebdSchin 		}
1460da2e3ebdSchin 		value = 0;
1461da2e3ebdSchin 	}
1462da2e3ebdSchin 	INITIALIZE();
1463da2e3ebdSchin 	if (!path)
1464da2e3ebdSchin 		path = root;
1465da2e3ebdSchin 	if (state.recent && streq(name, state.recent->name) && (s = format(state.recent, path, value, flags, conferror)))
1466da2e3ebdSchin 		return s;
1467da2e3ebdSchin 	if (lookup(&look, name, flags))
1468da2e3ebdSchin 	{
1469da2e3ebdSchin 		if (value)
1470da2e3ebdSchin 		{
1471da2e3ebdSchin 		ro:
1472da2e3ebdSchin 			errno = EINVAL;
1473da2e3ebdSchin 			if (conferror)
1474da2e3ebdSchin 				(*conferror)(&state, &state, 2, "%s: cannot set value", name);
1475da2e3ebdSchin 			return (flags & ASTCONF_error) ? (char*)0 : null;
1476da2e3ebdSchin 		}
1477da2e3ebdSchin 		return print(NiL, &look, name, path, flags, conferror);
1478da2e3ebdSchin 	}
1479da2e3ebdSchin 	if ((n = strlen(name)) > 3 && n < (ALT + 3))
1480da2e3ebdSchin 	{
1481da2e3ebdSchin 		if (streq(name + n - 3, "DEV"))
1482da2e3ebdSchin 		{
1483da2e3ebdSchin 			if (tmp = sfstropen())
1484da2e3ebdSchin 			{
1485da2e3ebdSchin 				sfprintf(tmp, "/dev/");
1486da2e3ebdSchin 				for (s = (char*)name; s < (char*)name + n - 3; s++)
1487da2e3ebdSchin 					sfputc(tmp, isupper(*s) ? tolower(*s) : *s);
1488da2e3ebdSchin 				if ((s = sfstruse(tmp)) && !access(s, F_OK))
1489da2e3ebdSchin 				{
1490da2e3ebdSchin 					if (value)
1491da2e3ebdSchin 						goto ro;
1492da2e3ebdSchin 					s = buffer(s);
1493da2e3ebdSchin 					sfclose(tmp);
1494da2e3ebdSchin 					return s;
1495da2e3ebdSchin 				}
1496da2e3ebdSchin 				sfclose(tmp);
1497da2e3ebdSchin 			}
1498da2e3ebdSchin 		}
1499da2e3ebdSchin 		else if (streq(name + n - 3, "DIR"))
1500da2e3ebdSchin 		{
1501da2e3ebdSchin 			Lookup_t		altlook;
1502da2e3ebdSchin 			char			altname[ALT];
1503da2e3ebdSchin 
1504da2e3ebdSchin 			static const char*	dirs[] = { "/usr/lib", "/usr", null };
1505da2e3ebdSchin 
1506da2e3ebdSchin 			strcpy(altname, name);
1507da2e3ebdSchin 			altname[n - 3] = 0;
1508da2e3ebdSchin 			if (lookup(&altlook, altname, flags))
1509da2e3ebdSchin 			{
1510da2e3ebdSchin 				if (value)
1511da2e3ebdSchin 				{
1512da2e3ebdSchin 					errno = EINVAL;
1513da2e3ebdSchin 					if (conferror)
1514da2e3ebdSchin 						(*conferror)(&state, &state, 2, "%s: cannot set value", altname);
1515da2e3ebdSchin 					return (flags & ASTCONF_error) ? (char*)0 : null;
1516da2e3ebdSchin 				}
1517da2e3ebdSchin 				return print(NiL, &altlook, altname, path, flags, conferror);
1518da2e3ebdSchin 			}
1519da2e3ebdSchin 			for (s = altname; *s; s++)
1520da2e3ebdSchin 				if (isupper(*s))
1521da2e3ebdSchin 					*s = tolower(*s);
1522da2e3ebdSchin 			if (tmp = sfstropen())
1523da2e3ebdSchin 			{
1524da2e3ebdSchin 				for (n = 0; n < elementsof(dirs); n++)
1525da2e3ebdSchin 				{
1526da2e3ebdSchin 					sfprintf(tmp, "%s/%s/.", dirs[n], altname);
1527da2e3ebdSchin 					if ((s = sfstruse(tmp)) && !access(s, F_OK))
1528da2e3ebdSchin 					{
1529da2e3ebdSchin 						if (value)
1530da2e3ebdSchin 							goto ro;
1531da2e3ebdSchin 						s = buffer(s);
1532da2e3ebdSchin 						sfclose(tmp);
1533da2e3ebdSchin 						return s;
1534da2e3ebdSchin 					}
1535da2e3ebdSchin 				}
1536da2e3ebdSchin 				sfclose(tmp);
1537da2e3ebdSchin 			}
1538da2e3ebdSchin 		}
1539da2e3ebdSchin 	}
1540*b30d1939SAndy Fiddaman 	if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(0, look.name, path, value, flags, conferror)))
1541da2e3ebdSchin 		return s;
1542da2e3ebdSchin 	errno = EINVAL;
1543da2e3ebdSchin 	if (conferror && !(flags & ASTCONF_system))
1544da2e3ebdSchin 		(*conferror)(&state, &state, 2, "%s: unknown name", name);
1545da2e3ebdSchin 	return (flags & ASTCONF_error) ? (char*)0 : null;
1546da2e3ebdSchin }
1547da2e3ebdSchin 
1548da2e3ebdSchin /*
1549da2e3ebdSchin  * astconf() never returns 0
1550da2e3ebdSchin  */
1551da2e3ebdSchin 
1552da2e3ebdSchin char*
astconf(const char * name,const char * path,const char * value)1553da2e3ebdSchin astconf(const char* name, const char* path, const char* value)
1554da2e3ebdSchin {
1555da2e3ebdSchin 	return astgetconf(name, path, value, 0, 0);
1556da2e3ebdSchin }
1557da2e3ebdSchin 
1558da2e3ebdSchin /*
1559da2e3ebdSchin  * set discipline function to be called when features change
1560da2e3ebdSchin  * old discipline function returned
1561da2e3ebdSchin  */
1562da2e3ebdSchin 
1563da2e3ebdSchin Ast_confdisc_f
astconfdisc(Ast_confdisc_f new_notify)1564da2e3ebdSchin astconfdisc(Ast_confdisc_f new_notify)
1565da2e3ebdSchin {
1566da2e3ebdSchin 	Ast_confdisc_f	old_notify;
1567da2e3ebdSchin 
1568da2e3ebdSchin 	INITIALIZE();
1569da2e3ebdSchin 	old_notify = state.notify;
1570da2e3ebdSchin 	state.notify = new_notify;
1571da2e3ebdSchin 	return old_notify;
1572da2e3ebdSchin }
1573da2e3ebdSchin 
1574da2e3ebdSchin /*
1575da2e3ebdSchin  * list all name=value entries on sp
1576da2e3ebdSchin  * path==0 implies path=="/"
1577da2e3ebdSchin  */
1578da2e3ebdSchin 
1579da2e3ebdSchin void
astconflist(Sfio_t * sp,const char * path,int flags,const char * pattern)1580da2e3ebdSchin astconflist(Sfio_t* sp, const char* path, int flags, const char* pattern)
1581da2e3ebdSchin {
1582da2e3ebdSchin 	char*		s;
1583da2e3ebdSchin 	char*		f;
1584da2e3ebdSchin 	char*		call;
1585da2e3ebdSchin 	Feature_t*	fp;
1586da2e3ebdSchin 	Lookup_t	look;
1587da2e3ebdSchin 	regex_t		re;
1588da2e3ebdSchin 	regdisc_t	redisc;
1589da2e3ebdSchin 	int		olderrno;
1590da2e3ebdSchin 	char		flg[8];
1591da2e3ebdSchin #ifdef _pth_getconf_a
1592da2e3ebdSchin 	Proc_t*		proc;
1593da2e3ebdSchin 	Sfio_t*		pp;
1594da2e3ebdSchin #endif
1595da2e3ebdSchin 
1596da2e3ebdSchin 	INITIALIZE();
1597da2e3ebdSchin 	if (!path)
1598da2e3ebdSchin 		path = root;
1599da2e3ebdSchin 	else if (access(path, F_OK))
1600da2e3ebdSchin 	{
1601da2e3ebdSchin 		errorf(&state, &state, 2, "%s: not found", path);
1602da2e3ebdSchin 		return;
1603da2e3ebdSchin 	}
1604da2e3ebdSchin 	olderrno = errno;
1605da2e3ebdSchin 	look.flags = 0;
1606da2e3ebdSchin 	if (!(flags & (ASTCONF_read|ASTCONF_write|ASTCONF_parse)))
1607da2e3ebdSchin 		flags |= ASTCONF_read|ASTCONF_write;
1608da2e3ebdSchin 	else if (flags & ASTCONF_parse)
1609da2e3ebdSchin 		flags |= ASTCONF_write;
1610da2e3ebdSchin 	if (!(flags & (ASTCONF_matchcall|ASTCONF_matchname|ASTCONF_matchstandard)))
1611da2e3ebdSchin 		pattern = 0;
1612da2e3ebdSchin 	if (pattern)
1613da2e3ebdSchin 	{
1614da2e3ebdSchin 		memset(&redisc, 0, sizeof(redisc));
1615da2e3ebdSchin 		redisc.re_version = REG_VERSION;
1616da2e3ebdSchin 		redisc.re_errorf = (regerror_t)errorf;
1617da2e3ebdSchin 		re.re_disc = &redisc;
1618da2e3ebdSchin 		if (regcomp(&re, pattern, REG_DISCIPLINE|REG_EXTENDED|REG_LENIENT|REG_NULL))
1619da2e3ebdSchin 			return;
1620da2e3ebdSchin 	}
1621da2e3ebdSchin 	if (flags & ASTCONF_read)
1622da2e3ebdSchin 	{
1623da2e3ebdSchin 		for (look.conf = (Conf_t*)conf; look.conf < (Conf_t*)&conf[conf_elements]; look.conf++)
1624da2e3ebdSchin 		{
1625da2e3ebdSchin 			if (pattern)
1626da2e3ebdSchin 			{
1627da2e3ebdSchin 				if (flags & ASTCONF_matchcall)
1628da2e3ebdSchin 				{
1629da2e3ebdSchin 					if (regexec(&re, prefix[look.conf->call + CONF_call].name, 0, NiL, 0))
1630da2e3ebdSchin 						continue;
1631da2e3ebdSchin 				}
1632da2e3ebdSchin 				else if (flags & ASTCONF_matchname)
1633da2e3ebdSchin 				{
1634da2e3ebdSchin 					if (regexec(&re, look.conf->name, 0, NiL, 0))
1635da2e3ebdSchin 						continue;
1636da2e3ebdSchin 				}
1637da2e3ebdSchin 				else if (flags & ASTCONF_matchstandard)
1638da2e3ebdSchin 				{
1639da2e3ebdSchin 					if (regexec(&re, prefix[look.conf->standard].name, 0, NiL, 0))
1640da2e3ebdSchin 						continue;
1641da2e3ebdSchin 				}
1642da2e3ebdSchin 			}
1643*b30d1939SAndy Fiddaman 			look.standard = look.conf->standard;
1644*b30d1939SAndy Fiddaman 			look.section = look.conf->section;
1645da2e3ebdSchin 			print(sp, &look, NiL, path, flags, errorf);
1646da2e3ebdSchin 		}
1647da2e3ebdSchin #ifdef _pth_getconf_a
1648da2e3ebdSchin 		if (pp = nativeconf(&proc, _pth_getconf_a))
1649da2e3ebdSchin 		{
1650da2e3ebdSchin 			call = "GC";
1651da2e3ebdSchin 			while (f = sfgetr(pp, '\n', 1))
1652da2e3ebdSchin 			{
1653da2e3ebdSchin 				for (s = f; *s && *s != '=' && *s != ':' && !isspace(*s); s++);
1654da2e3ebdSchin 				if (*s)
1655da2e3ebdSchin 					for (*s++ = 0; isspace(*s); s++);
1656da2e3ebdSchin 				if (!lookup(&look, f, flags))
1657da2e3ebdSchin 				{
1658da2e3ebdSchin 					if (flags & ASTCONF_table)
1659da2e3ebdSchin 					{
1660da2e3ebdSchin 						if (look.standard < 0)
1661da2e3ebdSchin 							look.standard = 0;
1662da2e3ebdSchin 						if (look.section < 1)
1663da2e3ebdSchin 							look.section = 1;
1664da2e3ebdSchin 						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);
1665da2e3ebdSchin 					}
1666da2e3ebdSchin 					else if (flags & ASTCONF_parse)
1667da2e3ebdSchin 						sfprintf(sp, "%s %s - %s\n", state.id, f, s);
1668da2e3ebdSchin 					else
1669da2e3ebdSchin 						sfprintf(sp, "%s=%s\n", f, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1670da2e3ebdSchin 				}
1671da2e3ebdSchin 			}
1672da2e3ebdSchin 			sfclose(pp);
1673da2e3ebdSchin 			procclose(proc);
1674da2e3ebdSchin 		}
1675da2e3ebdSchin #endif
1676da2e3ebdSchin 	}
1677da2e3ebdSchin 	if (flags & ASTCONF_write)
1678da2e3ebdSchin 	{
1679da2e3ebdSchin 		call = "AC";
1680da2e3ebdSchin 		for (fp = state.features; fp; fp = fp->next)
1681da2e3ebdSchin 		{
1682da2e3ebdSchin 			if (pattern)
1683da2e3ebdSchin 			{
1684da2e3ebdSchin 				if (flags & ASTCONF_matchcall)
1685da2e3ebdSchin 				{
1686da2e3ebdSchin 					if (regexec(&re, call, 0, NiL, 0))
1687da2e3ebdSchin 						continue;
1688da2e3ebdSchin 				}
1689da2e3ebdSchin 				else if (flags & ASTCONF_matchname)
1690da2e3ebdSchin 				{
1691da2e3ebdSchin 					if (regexec(&re, fp->name, 0, NiL, 0))
1692da2e3ebdSchin 						continue;
1693da2e3ebdSchin 				}
1694da2e3ebdSchin 				else if (flags & ASTCONF_matchstandard)
1695da2e3ebdSchin 				{
1696da2e3ebdSchin 					if (regexec(&re, prefix[fp->standard].name, 0, NiL, 0))
1697da2e3ebdSchin 						continue;
1698da2e3ebdSchin 				}
1699da2e3ebdSchin 			}
1700*b30d1939SAndy Fiddaman 			if (!(s = feature(fp, 0, path, NiL, 0, 0)) || !*s)
1701da2e3ebdSchin 				s = "0";
1702da2e3ebdSchin 			if (flags & ASTCONF_table)
1703da2e3ebdSchin 			{
1704da2e3ebdSchin 				f = flg;
1705da2e3ebdSchin 				if (fp->flags & CONF_ALLOC)
1706da2e3ebdSchin 					*f++ = 'A';
1707da2e3ebdSchin 				if (fp->flags & CONF_READONLY)
1708da2e3ebdSchin 					*f++ = 'R';
1709da2e3ebdSchin 				if (f == flg)
1710da2e3ebdSchin 					*f++ = 'X';
1711da2e3ebdSchin 				*f = 0;
1712da2e3ebdSchin 				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);
1713da2e3ebdSchin 			}
1714da2e3ebdSchin 			else if (flags & ASTCONF_parse)
1715da2e3ebdSchin 				sfprintf(sp, "%s %s - %s\n", state.id, (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL));
1716da2e3ebdSchin 			else
1717da2e3ebdSchin 				sfprintf(sp, "%s=%s\n", (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1718da2e3ebdSchin 		}
1719da2e3ebdSchin 	}
1720da2e3ebdSchin 	if (pattern)
1721da2e3ebdSchin 		regfree(&re);
1722da2e3ebdSchin 	errno = olderrno;
1723da2e3ebdSchin }
1724