xref: /onnv-gate/usr/src/lib/libast/common/port/astconf.c (revision 4887:feebf9260c2e)
1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin 
24*4887Schin /*
25*4887Schin  * string interface to confstr(),pathconf(),sysconf(),sysinfo()
26*4887Schin  * extended to allow some features to be set per-process
27*4887Schin  */
28*4887Schin 
29*4887Schin static const char id[] = "\n@(#)$Id: getconf (AT&T Research) 2006-11-15 $\0\n";
30*4887Schin 
31*4887Schin #include "univlib.h"
32*4887Schin 
33*4887Schin #include <ast.h>
34*4887Schin #include <error.h>
35*4887Schin #include <fs3d.h>
36*4887Schin #include <ctype.h>
37*4887Schin #include <regex.h>
38*4887Schin #include <proc.h>
39*4887Schin 
40*4887Schin #include "conftab.h"
41*4887Schin #include "FEATURE/libpath"
42*4887Schin 
43*4887Schin #ifndef _pth_getconf
44*4887Schin #undef	ASTCONF_system
45*4887Schin #define ASTCONF_system		0
46*4887Schin #endif
47*4887Schin 
48*4887Schin #if _sys_systeminfo
49*4887Schin # if !_lib_sysinfo
50*4887Schin #   if _lib_systeminfo
51*4887Schin #     define _lib_sysinfo	1
52*4887Schin #     define sysinfo(a,b,c)	systeminfo(a,b,c)
53*4887Schin #   else
54*4887Schin #     if _lib_syscall && _sys_syscall
55*4887Schin #       include <sys/syscall.h>
56*4887Schin #       if defined(SYS_systeminfo)
57*4887Schin #         define _lib_sysinfo	1
58*4887Schin #         define sysinfo(a,b,c)	syscall(SYS_systeminfo,a,b,c)
59*4887Schin #       endif
60*4887Schin #     endif
61*4887Schin #   endif
62*4887Schin # endif
63*4887Schin #else
64*4887Schin # undef	_lib_sysinfo
65*4887Schin #endif
66*4887Schin 
67*4887Schin #define OP_conformance		1
68*4887Schin #define OP_fs_3d		2
69*4887Schin #define OP_getconf		3
70*4887Schin #define OP_hosttype		4
71*4887Schin #define OP_libpath		5
72*4887Schin #define OP_libprefix		6
73*4887Schin #define OP_libsuffix		7
74*4887Schin #define OP_path_attributes	8
75*4887Schin #define OP_path_resolve		9
76*4887Schin #define OP_universe		10
77*4887Schin 
78*4887Schin #define CONF_ERROR	(CONF_USER<<0)
79*4887Schin #define CONF_READONLY	(CONF_USER<<1)
80*4887Schin #define CONF_ALLOC	(CONF_USER<<2)
81*4887Schin 
82*4887Schin #define INITIALIZE()	do{if(!state.data)synthesize(NiL,NiL,NiL);}while(0)
83*4887Schin 
84*4887Schin #define MAXVAL		256
85*4887Schin 
86*4887Schin #if MAXVAL <= UNIV_SIZE
87*4887Schin #undef	MAXVAL
88*4887Schin #define	MAXVAL		(UNIV_SIZE+1)
89*4887Schin #endif
90*4887Schin 
91*4887Schin #ifndef _UNIV_DEFAULT
92*4887Schin #define _UNIV_DEFAULT	"att"
93*4887Schin #endif
94*4887Schin 
95*4887Schin static char	null[1];
96*4887Schin static char	root[2] = "/";
97*4887Schin 
98*4887Schin typedef struct Feature_s
99*4887Schin {
100*4887Schin 	struct Feature_s*next;
101*4887Schin 	const char*	name;
102*4887Schin 	char*		value;
103*4887Schin 	char*		strict;
104*4887Schin 	short		length;
105*4887Schin 	short		standard;
106*4887Schin 	unsigned short	flags;
107*4887Schin 	short		op;
108*4887Schin } Feature_t;
109*4887Schin 
110*4887Schin typedef struct
111*4887Schin {
112*4887Schin 	Conf_t*		conf;
113*4887Schin 	const char*	name;
114*4887Schin 	unsigned short	flags;
115*4887Schin 	short		call;
116*4887Schin 	short		standard;
117*4887Schin 	short		section;
118*4887Schin } Lookup_t;
119*4887Schin 
120*4887Schin static Feature_t	dynamic[] =
121*4887Schin {
122*4887Schin 	{
123*4887Schin 		&dynamic[1],
124*4887Schin 		"CONFORMANCE",
125*4887Schin 		"ast",
126*4887Schin 		"standard",
127*4887Schin 		11,
128*4887Schin 		CONF_AST,
129*4887Schin 		0,
130*4887Schin 		OP_conformance
131*4887Schin 	},
132*4887Schin 	{
133*4887Schin 		&dynamic[2],
134*4887Schin 		"FS_3D",
135*4887Schin 		&null[0],
136*4887Schin 		"0",
137*4887Schin 		5,
138*4887Schin 		CONF_AST,
139*4887Schin 		0,
140*4887Schin 		OP_fs_3d
141*4887Schin 	},
142*4887Schin 	{
143*4887Schin 		&dynamic[3],
144*4887Schin 		"GETCONF",
145*4887Schin #ifdef _pth_getconf
146*4887Schin 		_pth_getconf,
147*4887Schin #else
148*4887Schin 		&null[0],
149*4887Schin #endif
150*4887Schin 		0,
151*4887Schin 		7,
152*4887Schin 		CONF_AST,
153*4887Schin 		CONF_READONLY,
154*4887Schin 		OP_getconf
155*4887Schin 	},
156*4887Schin 	{
157*4887Schin 		&dynamic[4],
158*4887Schin 		"HOSTTYPE",
159*4887Schin 		HOSTTYPE,
160*4887Schin 		0,
161*4887Schin 		8,
162*4887Schin 		CONF_AST,
163*4887Schin 		CONF_READONLY,
164*4887Schin 		OP_hosttype
165*4887Schin 	},
166*4887Schin 	{
167*4887Schin 		&dynamic[5],
168*4887Schin 		"LIBPATH",
169*4887Schin #ifdef CONF_LIBPATH
170*4887Schin 		CONF_LIBPATH,
171*4887Schin #else
172*4887Schin 		&null[0],
173*4887Schin #endif
174*4887Schin 		0,
175*4887Schin 		7,
176*4887Schin 		CONF_AST,
177*4887Schin 		0,
178*4887Schin 		OP_libpath
179*4887Schin 	},
180*4887Schin 	{
181*4887Schin 		&dynamic[6],
182*4887Schin 		"LIBPREFIX",
183*4887Schin #ifdef CONF_LIBPREFIX
184*4887Schin 		CONF_LIBPREFIX,
185*4887Schin #else
186*4887Schin 		"lib",
187*4887Schin #endif
188*4887Schin 		0,
189*4887Schin 		9,
190*4887Schin 		CONF_AST,
191*4887Schin 		0,
192*4887Schin 		OP_libprefix
193*4887Schin 	},
194*4887Schin 	{
195*4887Schin 		&dynamic[7],
196*4887Schin 		"LIBSUFFIX",
197*4887Schin #ifdef CONF_LIBSUFFIX
198*4887Schin 		CONF_LIBSUFFIX,
199*4887Schin #else
200*4887Schin 		".so",
201*4887Schin #endif
202*4887Schin 		0,
203*4887Schin 		9,
204*4887Schin 		CONF_AST,
205*4887Schin 		0,
206*4887Schin 		OP_libsuffix
207*4887Schin 	},
208*4887Schin 	{
209*4887Schin 		&dynamic[8],
210*4887Schin 		"PATH_ATTRIBUTES",
211*4887Schin #if _WINIX
212*4887Schin 		"c",
213*4887Schin #else
214*4887Schin 		&null[0],
215*4887Schin #endif
216*4887Schin 		&null[0],
217*4887Schin 		15,
218*4887Schin 		CONF_AST,
219*4887Schin 		CONF_READONLY,
220*4887Schin 		OP_path_attributes
221*4887Schin 	},
222*4887Schin 	{
223*4887Schin 		&dynamic[9],
224*4887Schin 		"PATH_RESOLVE",
225*4887Schin 		&null[0],
226*4887Schin 		"metaphysical",
227*4887Schin 		12,
228*4887Schin 		CONF_AST,
229*4887Schin 		0,
230*4887Schin 		OP_path_resolve
231*4887Schin 	},
232*4887Schin 	{
233*4887Schin 		0,
234*4887Schin 		"UNIVERSE",
235*4887Schin 		&null[0],
236*4887Schin 		"att",
237*4887Schin 		8,
238*4887Schin 		CONF_AST,
239*4887Schin 		0,
240*4887Schin 		OP_universe
241*4887Schin 	},
242*4887Schin 	{
243*4887Schin 		0
244*4887Schin 	}
245*4887Schin };
246*4887Schin 
247*4887Schin typedef struct
248*4887Schin {
249*4887Schin 
250*4887Schin 	const char*	id;
251*4887Schin 	const char*	name;
252*4887Schin 	Feature_t*	features;
253*4887Schin 
254*4887Schin 	/* default initialization from here down */
255*4887Schin 
256*4887Schin 	int		prefix;
257*4887Schin 	int		synthesizing;
258*4887Schin 
259*4887Schin 	char*		data;
260*4887Schin 	char*		last;
261*4887Schin 
262*4887Schin 	Feature_t*	recent;
263*4887Schin 
264*4887Schin 	Ast_confdisc_f	notify;
265*4887Schin 
266*4887Schin } State_t;
267*4887Schin 
268*4887Schin static State_t	state = { "getconf", "_AST_FEATURES", dynamic };
269*4887Schin 
270*4887Schin static char*	feature(const char*, const char*, const char*, int, Error_f);
271*4887Schin 
272*4887Schin /*
273*4887Schin  * return fmtbuf() copy of s
274*4887Schin  */
275*4887Schin 
276*4887Schin static char*
277*4887Schin buffer(char* s)
278*4887Schin {
279*4887Schin 	return strcpy(fmtbuf(strlen(s) + 1), s);
280*4887Schin }
281*4887Schin 
282*4887Schin /*
283*4887Schin  * synthesize state for fp
284*4887Schin  * fp==0 initializes from getenv(state.name)
285*4887Schin  * value==0 just does lookup
286*4887Schin  * otherwise state is set to value
287*4887Schin  */
288*4887Schin 
289*4887Schin static char*
290*4887Schin synthesize(register Feature_t* fp, const char* path, const char* value)
291*4887Schin {
292*4887Schin 	register char*		s;
293*4887Schin 	register char*		d;
294*4887Schin 	register char*		v;
295*4887Schin 	register int		n;
296*4887Schin 
297*4887Schin 	if (state.synthesizing)
298*4887Schin 		return null;
299*4887Schin 	if (!state.data)
300*4887Schin 	{
301*4887Schin 		char*		se;
302*4887Schin 		char*		de;
303*4887Schin 		char*		ve;
304*4887Schin 
305*4887Schin 		state.prefix = strlen(state.name) + 1;
306*4887Schin 		n = state.prefix + 3 * MAXVAL;
307*4887Schin 		if (s = getenv(state.name))
308*4887Schin 			n += strlen(s) + 1;
309*4887Schin 		n = roundof(n, 32);
310*4887Schin 		if (!(state.data = newof(0, char, n, 0)))
311*4887Schin 			return 0;
312*4887Schin 		state.last = state.data + n - 1;
313*4887Schin 		strcpy(state.data, state.name);
314*4887Schin 		state.data += state.prefix - 1;
315*4887Schin 		*state.data++ = '=';
316*4887Schin 		if (s)
317*4887Schin 			strcpy(state.data, s);
318*4887Schin 		ve = state.data;
319*4887Schin 		state.synthesizing = 1;
320*4887Schin 		for (;;)
321*4887Schin 		{
322*4887Schin 			for (s = ve; isspace(*s); s++);
323*4887Schin 			for (d = s; *d && !isspace(*d); d++);
324*4887Schin 			for (se = d; isspace(*d); d++);
325*4887Schin 			for (v = d; *v && !isspace(*v); v++);
326*4887Schin 			for (de = v; isspace(*v); v++);
327*4887Schin 			if (!*v)
328*4887Schin 				break;
329*4887Schin 			for (ve = v; *ve && !isspace(*ve); ve++);
330*4887Schin 			if (*ve)
331*4887Schin 				*ve = 0;
332*4887Schin 			else
333*4887Schin 				ve = 0;
334*4887Schin 			*de = 0;
335*4887Schin 			*se = 0;
336*4887Schin 			feature(s, d, v, 0, 0);
337*4887Schin 			*se = ' ';
338*4887Schin 			*de = ' ';
339*4887Schin 			if (!ve)
340*4887Schin 				break;
341*4887Schin 			*ve++ = ' ';
342*4887Schin 		}
343*4887Schin 		state.synthesizing = 0;
344*4887Schin 	}
345*4887Schin 	if (!fp)
346*4887Schin 		return state.data;
347*4887Schin 	if (!state.last)
348*4887Schin 	{
349*4887Schin 		if (!value)
350*4887Schin 			return 0;
351*4887Schin 		n = strlen(value);
352*4887Schin 		goto ok;
353*4887Schin 	}
354*4887Schin 	s = (char*)fp->name;
355*4887Schin 	n = fp->length;
356*4887Schin 	d = state.data;
357*4887Schin 	for (;;)
358*4887Schin 	{
359*4887Schin 		while (isspace(*d))
360*4887Schin 			d++;
361*4887Schin 		if (!*d)
362*4887Schin 			break;
363*4887Schin 		if (strneq(d, s, n) && isspace(d[n]))
364*4887Schin 		{
365*4887Schin 			if (!value)
366*4887Schin 			{
367*4887Schin 				for (d += n + 1; *d && !isspace(*d); d++);
368*4887Schin 				for (; isspace(*d); d++);
369*4887Schin 				for (s = d; *s && !isspace(*s); s++);
370*4887Schin 				n = s - d;
371*4887Schin 				value = (const char*)d;
372*4887Schin 				goto ok;
373*4887Schin 			}
374*4887Schin 			for (s = d + n + 1; *s && !isspace(*s); s++);
375*4887Schin 			for (; isspace(*s); s++);
376*4887Schin 			for (v = s; *s && !isspace(*s); s++);
377*4887Schin 			n = s - v;
378*4887Schin 			if (strneq(v, value, n))
379*4887Schin 				goto ok;
380*4887Schin 			for (; isspace(*s); s++);
381*4887Schin 			if (*s)
382*4887Schin 				for (; *d = *s++; d++);
383*4887Schin 			else if (d != state.data)
384*4887Schin 				d--;
385*4887Schin 			break;
386*4887Schin 		}
387*4887Schin 		for (; *d && !isspace(*d); d++);
388*4887Schin 		for (; isspace(*d); d++);
389*4887Schin 		for (; *d && !isspace(*d); d++);
390*4887Schin 		for (; isspace(*d); d++);
391*4887Schin 		for (; *d && !isspace(*d); d++);
392*4887Schin 	}
393*4887Schin 	if (!value)
394*4887Schin 	{
395*4887Schin 		if (!fp->op)
396*4887Schin 		{
397*4887Schin 			if (fp->flags & CONF_ALLOC)
398*4887Schin 				fp->value[0] = 0;
399*4887Schin 			else
400*4887Schin 				fp->value = null;
401*4887Schin 		}
402*4887Schin 		return 0;
403*4887Schin 	}
404*4887Schin 	if (!value[0])
405*4887Schin 		value = "0";
406*4887Schin 	if (!path || !path[0] || path[0] == '/' && !path[1])
407*4887Schin 		path = "-";
408*4887Schin 	n += strlen(path) + strlen(value) + 3;
409*4887Schin 	if (d + n >= state.last)
410*4887Schin 	{
411*4887Schin 		int	c;
412*4887Schin 		int	i;
413*4887Schin 
414*4887Schin 		i = d - state.data;
415*4887Schin 		state.data -= state.prefix;
416*4887Schin 		c = n + state.last - state.data + 3 * MAXVAL;
417*4887Schin 		c = roundof(c, 32);
418*4887Schin 		if (!(state.data = newof(state.data, char, c, 0)))
419*4887Schin 			return 0;
420*4887Schin 		state.last = state.data + c - 1;
421*4887Schin 		state.data += state.prefix;
422*4887Schin 		d = state.data + i;
423*4887Schin 	}
424*4887Schin 	if (d != state.data)
425*4887Schin 		*d++ = ' ';
426*4887Schin 	for (s = (char*)fp->name; *d = *s++; d++);
427*4887Schin 	*d++ = ' ';
428*4887Schin 	for (s = (char*)path; *d = *s++; d++);
429*4887Schin 	*d++ = ' ';
430*4887Schin 	for (s = (char*)value; *d = *s++; d++);
431*4887Schin 	setenviron(state.data - state.prefix);
432*4887Schin 	if (state.notify)
433*4887Schin 		(*state.notify)(NiL, NiL, state.data - state.prefix);
434*4887Schin 	n = s - (char*)value - 1;
435*4887Schin  ok:
436*4887Schin 	if (!(fp->flags & CONF_ALLOC))
437*4887Schin 		fp->value = 0;
438*4887Schin 	if (n == 1 && (*value == '0' || *value == '-'))
439*4887Schin 		n = 0;
440*4887Schin 	if (!(fp->value = newof(fp->value, char, n, 1)))
441*4887Schin 		fp->value = null;
442*4887Schin 	else
443*4887Schin 	{
444*4887Schin 		fp->flags |= CONF_ALLOC;
445*4887Schin 		memcpy(fp->value, value, n);
446*4887Schin 		fp->value[n] = 0;
447*4887Schin 	}
448*4887Schin 	return fp->value;
449*4887Schin }
450*4887Schin 
451*4887Schin /*
452*4887Schin  * initialize the value for fp
453*4887Schin  * if command!=0 then it is checked for on $PATH
454*4887Schin  * synthesize(fp,path,succeed) called on success
455*4887Schin  * otherwise synthesize(fp,path,fail) called
456*4887Schin  */
457*4887Schin 
458*4887Schin static void
459*4887Schin initialize(register Feature_t* fp, const char* path, const char* command, const char* succeed, const char* fail)
460*4887Schin {
461*4887Schin 	register char*	p;
462*4887Schin 	register int	ok = 1;
463*4887Schin 
464*4887Schin 	switch (fp->op)
465*4887Schin 	{
466*4887Schin 	case OP_conformance:
467*4887Schin 		ok = getenv("POSIXLY_CORRECT") != 0;
468*4887Schin 		break;
469*4887Schin 	case OP_hosttype:
470*4887Schin 		ok = 1;
471*4887Schin 		break;
472*4887Schin 	case OP_path_attributes:
473*4887Schin 		ok = 1;
474*4887Schin 		break;
475*4887Schin 	case OP_path_resolve:
476*4887Schin 		ok = fs3d(FS3D_TEST);
477*4887Schin 		break;
478*4887Schin 	case OP_universe:
479*4887Schin 		ok = streq(_UNIV_DEFAULT, "att");
480*4887Schin 		/*FALLTHROUGH...*/
481*4887Schin 	default:
482*4887Schin 		if (p = getenv("PATH"))
483*4887Schin 		{
484*4887Schin 			register int	r = 1;
485*4887Schin 			register char*	d = p;
486*4887Schin 			Sfio_t*		tmp;
487*4887Schin 
488*4887Schin 			if (tmp = sfstropen())
489*4887Schin 			{
490*4887Schin 				for (;;)
491*4887Schin 				{
492*4887Schin 					switch (*p++)
493*4887Schin 					{
494*4887Schin 					case 0:
495*4887Schin 						break;
496*4887Schin 					case ':':
497*4887Schin 						if (command && (fp->op != OP_universe || !ok))
498*4887Schin 						{
499*4887Schin 							if (r = p - d - 1)
500*4887Schin 							{
501*4887Schin 								sfwrite(tmp, d, r);
502*4887Schin 								sfputc(tmp, '/');
503*4887Schin 								sfputr(tmp, command, 0);
504*4887Schin 								if ((d = sfstruse(tmp)) && !eaccess(d, X_OK))
505*4887Schin 								{
506*4887Schin 									ok = 1;
507*4887Schin 									if (fp->op != OP_universe)
508*4887Schin 										break;
509*4887Schin 								}
510*4887Schin 							}
511*4887Schin 							d = p;
512*4887Schin 						}
513*4887Schin 						r = 1;
514*4887Schin 						continue;
515*4887Schin 					case '/':
516*4887Schin 						if (r)
517*4887Schin 						{
518*4887Schin 							r = 0;
519*4887Schin 							if (fp->op == OP_universe)
520*4887Schin 							{
521*4887Schin 								if (strneq(p, "bin:", 4) || strneq(p, "usr/bin:", 8))
522*4887Schin 									break;
523*4887Schin 							}
524*4887Schin 						}
525*4887Schin 						if (fp->op == OP_universe)
526*4887Schin 						{
527*4887Schin 							if (strneq(p, "5bin", 4))
528*4887Schin 							{
529*4887Schin 								ok = 1;
530*4887Schin 								break;
531*4887Schin 							}
532*4887Schin 							if (strneq(p, "bsd", 3) || strneq(p, "ucb", 3))
533*4887Schin 							{
534*4887Schin 								ok = 0;
535*4887Schin 								break;
536*4887Schin 							}
537*4887Schin 						}
538*4887Schin 						continue;
539*4887Schin 					default:
540*4887Schin 						r = 0;
541*4887Schin 						continue;
542*4887Schin 					}
543*4887Schin 					break;
544*4887Schin 				}
545*4887Schin 				sfclose(tmp);
546*4887Schin 			}
547*4887Schin 			else
548*4887Schin 				ok = 1;
549*4887Schin 		}
550*4887Schin 		break;
551*4887Schin 	}
552*4887Schin 	synthesize(fp, path, ok ? succeed : fail);
553*4887Schin }
554*4887Schin 
555*4887Schin /*
556*4887Schin  * format synthesized value
557*4887Schin  */
558*4887Schin 
559*4887Schin static char*
560*4887Schin format(register Feature_t* fp, const char* path, const char* value, int flags, Error_f conferror)
561*4887Schin {
562*4887Schin 	register Feature_t*	sp;
563*4887Schin 	register int		n;
564*4887Schin 
565*4887Schin 	switch (fp->op)
566*4887Schin 	{
567*4887Schin 
568*4887Schin 	case OP_conformance:
569*4887Schin 		if (value && (streq(value, "strict") || streq(value, "posix") || streq(value, "xopen")))
570*4887Schin 			value = fp->strict;
571*4887Schin 		n = streq(fp->value, fp->strict);
572*4887Schin 		if (!synthesize(fp, path, value))
573*4887Schin 			initialize(fp, path, NiL, fp->strict, fp->value);
574*4887Schin 		if (!n && streq(fp->value, fp->strict))
575*4887Schin 			for (sp = state.features; sp; sp = sp->next)
576*4887Schin 				if (sp->strict && sp->op && sp->op != OP_conformance)
577*4887Schin 					astconf(sp->name, path, sp->strict);
578*4887Schin 		break;
579*4887Schin 
580*4887Schin 	case OP_fs_3d:
581*4887Schin 		fp->value = fs3d(value ? value[0] ? FS3D_ON : FS3D_OFF : FS3D_TEST) ? "1" : null;
582*4887Schin 		break;
583*4887Schin 
584*4887Schin 	case OP_hosttype:
585*4887Schin 		break;
586*4887Schin 
587*4887Schin 	case OP_path_attributes:
588*4887Schin #ifdef _PC_PATH_ATTRIBUTES
589*4887Schin 		{
590*4887Schin 			register char*	s;
591*4887Schin 			register char*	e;
592*4887Schin 			intmax_t	v;
593*4887Schin 
594*4887Schin 			/*
595*4887Schin 			 * _PC_PATH_ATTRIBUTES is a bitmap for 'a' to 'z'
596*4887Schin 			 */
597*4887Schin 
598*4887Schin 			if ((v = pathconf(path, _PC_PATH_ATTRIBUTES)) == -1L)
599*4887Schin 				return 0;
600*4887Schin 			s = fp->value;
601*4887Schin 			e = s + sizeof(fp->value) - 1;
602*4887Schin 			for (n = 'a'; n <= 'z'; n++)
603*4887Schin 				if (v & (1 << (n - 'a')))
604*4887Schin 				{
605*4887Schin 					*s++ = n;
606*4887Schin 					if (s >= e)
607*4887Schin 						break;
608*4887Schin 				}
609*4887Schin 			*s = 0;
610*4887Schin 		}
611*4887Schin #endif
612*4887Schin 		break;
613*4887Schin 
614*4887Schin 	case OP_path_resolve:
615*4887Schin 		if (!synthesize(fp, path, value))
616*4887Schin 			initialize(fp, path, NiL, "logical", "metaphysical");
617*4887Schin 		break;
618*4887Schin 
619*4887Schin 	case OP_universe:
620*4887Schin #if _lib_universe
621*4887Schin 		if (getuniverse(fp->value) < 0)
622*4887Schin 			strcpy(fp->value, "att");
623*4887Schin 		if (value)
624*4887Schin 			setuniverse(value);
625*4887Schin #else
626*4887Schin #ifdef UNIV_MAX
627*4887Schin 		n = 0;
628*4887Schin 		if (value)
629*4887Schin 		{
630*4887Schin 			while (n < univ_max && !streq(value, univ_name[n])
631*4887Schin 				n++;
632*4887Schin 			if (n >= univ_max)
633*4887Schin 			{
634*4887Schin 				if (conferror)
635*4887Schin 					(*conferror)(&state, &state, 2, "%s: %s: universe value too large", fp->name, value);
636*4887Schin 				return 0;
637*4887Schin 			}
638*4887Schin 		}
639*4887Schin #ifdef ATT_UNIV
640*4887Schin 		n = setuniverse(n + 1);
641*4887Schin 		if (!value && n > 0)
642*4887Schin 			setuniverse(n);
643*4887Schin #else
644*4887Schin 		n = universe(value ? n + 1 : U_GET);
645*4887Schin #endif
646*4887Schin 		if (n <= 0 || n >= univ_max)
647*4887Schin 			n = 1;
648*4887Schin 		strcpy(fp->value, univ_name[n - 1]);
649*4887Schin #else
650*4887Schin 		if (!synthesize(fp, path, value))
651*4887Schin 			initialize(fp, path, "echo", "att", "ucb");
652*4887Schin #endif
653*4887Schin #endif
654*4887Schin 		break;
655*4887Schin 
656*4887Schin 	default:
657*4887Schin 		synthesize(fp, path, value);
658*4887Schin 		break;
659*4887Schin 
660*4887Schin 	}
661*4887Schin 	return fp->value;
662*4887Schin }
663*4887Schin 
664*4887Schin /*
665*4887Schin  * value==0 get feature name
666*4887Schin  * value!=0 set feature name
667*4887Schin  * 0 returned if error or not defined; otherwise previous value
668*4887Schin  */
669*4887Schin 
670*4887Schin static char*
671*4887Schin feature(const char* name, const char* path, const char* value, int flags, Error_f conferror)
672*4887Schin {
673*4887Schin 	register Feature_t*	fp;
674*4887Schin 	register int		n;
675*4887Schin 
676*4887Schin 	if (value && (streq(value, "-") || streq(value, "0")))
677*4887Schin 		value = null;
678*4887Schin 	for (fp = state.features; fp && !streq(fp->name, name); fp = fp->next);
679*4887Schin #if DEBUG || DEBUG_astconf
680*4887Schin 	error(-2, "astconf feature name=%s path=%s value=%s flags=%04x fp=%p", name, path, value, flags, fp);
681*4887Schin #endif
682*4887Schin 	if (!fp)
683*4887Schin 	{
684*4887Schin 		if (!value)
685*4887Schin 			return 0;
686*4887Schin 		if (state.notify && !(*state.notify)(name, path, value))
687*4887Schin 			return 0;
688*4887Schin 		n = strlen(name);
689*4887Schin 		if (!(fp = newof(0, Feature_t, 1, n + 1)))
690*4887Schin 		{
691*4887Schin 			if (conferror)
692*4887Schin 				(*conferror)(&state, &state, 2, "%s: out of space", name);
693*4887Schin 			return 0;
694*4887Schin 		}
695*4887Schin 		fp->name = (const char*)fp + sizeof(Feature_t);
696*4887Schin 		strcpy((char*)fp->name, name);
697*4887Schin 		fp->length = n;
698*4887Schin 		fp->next = state.features;
699*4887Schin 		state.features = fp;
700*4887Schin 	}
701*4887Schin 	else if (value)
702*4887Schin 	{
703*4887Schin 		if (fp->flags & CONF_READONLY)
704*4887Schin 		{
705*4887Schin 			if (conferror)
706*4887Schin 				(*conferror)(&state, &state, 2, "%s: cannot set readonly symbol", fp->name);
707*4887Schin 			return 0;
708*4887Schin 		}
709*4887Schin 		if (state.notify && !streq(fp->value, value) && !(*state.notify)(name, path, value))
710*4887Schin 			return 0;
711*4887Schin 	}
712*4887Schin 	else
713*4887Schin 		state.recent = fp;
714*4887Schin 	return format(fp, path, value, flags, conferror);
715*4887Schin }
716*4887Schin 
717*4887Schin /*
718*4887Schin  * binary search for name in conf[]
719*4887Schin  */
720*4887Schin 
721*4887Schin static int
722*4887Schin lookup(register Lookup_t* look, const char* name, int flags)
723*4887Schin {
724*4887Schin 	register Conf_t*	mid = (Conf_t*)conf;
725*4887Schin 	register Conf_t*	lo = mid;
726*4887Schin 	register Conf_t*	hi = mid + conf_elements;
727*4887Schin 	register int		v;
728*4887Schin 	register int		c;
729*4887Schin 	char*			e;
730*4887Schin 	const Prefix_t*		p;
731*4887Schin 
732*4887Schin 	static Conf_t		num;
733*4887Schin 
734*4887Schin 	look->flags = 0;
735*4887Schin 	look->call = -1;
736*4887Schin 	look->standard = (flags & ASTCONF_AST) ? CONF_AST : -1;
737*4887Schin 	look->section = -1;
738*4887Schin 	while (*name == '_')
739*4887Schin 		name++;
740*4887Schin  again:
741*4887Schin 	for (p = prefix; p < &prefix[prefix_elements]; p++)
742*4887Schin 		if (strneq(name, p->name, p->length) && ((c = name[p->length] == '_' || name[p->length] == '(') || (v = isdigit(name[p->length]) && name[p->length + 1] == '_')))
743*4887Schin 		{
744*4887Schin 			if (p->call < 0)
745*4887Schin 			{
746*4887Schin 				if (look->standard >= 0)
747*4887Schin 					break;
748*4887Schin 				look->standard = p->standard;
749*4887Schin 			}
750*4887Schin 			else
751*4887Schin 			{
752*4887Schin 				if (look->call >= 0)
753*4887Schin 					break;
754*4887Schin 				look->call = p->call;
755*4887Schin 			}
756*4887Schin 			if (name[p->length] == '(')
757*4887Schin 			{
758*4887Schin 				look->conf = &num;
759*4887Schin 				strncpy((char*)num.name, name, sizeof(num.name));
760*4887Schin 				num.call = p->call;
761*4887Schin 				num.flags = *name == 'C' ? CONF_STRING : 0;
762*4887Schin 				num.op = (short)strtol(name + p->length + 1, &e, 10);
763*4887Schin 				if (*e++ != ')' || *e)
764*4887Schin 					break;
765*4887Schin 				return 1;
766*4887Schin 			}
767*4887Schin 			name += p->length + c;
768*4887Schin 			if (look->section < 0 && !c && v)
769*4887Schin 			{
770*4887Schin 				look->section = name[0] - '0';
771*4887Schin 				name += 2;
772*4887Schin 			}
773*4887Schin 			goto again;
774*4887Schin 		}
775*4887Schin #if HUH_2006_02_10
776*4887Schin 	if (look->section < 0)
777*4887Schin 		look->section = 1;
778*4887Schin #endif
779*4887Schin 	look->name = name;
780*4887Schin #if DEBUG || DEBUG_astconf
781*4887Schin 	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);
782*4887Schin #endif
783*4887Schin 	c = *((unsigned char*)name);
784*4887Schin 	while (lo <= hi)
785*4887Schin 	{
786*4887Schin 		mid = lo + (hi - lo) / 2;
787*4887Schin #if DEBUG || DEBUG_astconf
788*4887Schin 		error(-3, "astconf lookup name=%s mid=%s", name, mid->name);
789*4887Schin #endif
790*4887Schin 		if (!(v = c - *((unsigned char*)mid->name)) && !(v = strcmp(name, mid->name)))
791*4887Schin 		{
792*4887Schin 			hi = mid;
793*4887Schin 			lo = (Conf_t*)conf;
794*4887Schin 			do
795*4887Schin 			{
796*4887Schin 				if ((look->standard < 0 || look->standard == mid->standard) &&
797*4887Schin 				    (look->section < 0 || look->section == mid->section) &&
798*4887Schin 				    (look->call < 0 || look->call == mid->call))
799*4887Schin 					goto found;
800*4887Schin 			} while (mid-- > lo && streq(mid->name, look->name));
801*4887Schin 			mid = hi;
802*4887Schin 			hi = lo + conf_elements - 1;
803*4887Schin 			while (++mid < hi && streq(mid->name, look->name))
804*4887Schin 			{
805*4887Schin 				if ((look->standard < 0 || look->standard == mid->standard) &&
806*4887Schin 				    (look->section < 0 || look->section == mid->section) &&
807*4887Schin 				    (look->call < 0 || look->call == mid->call))
808*4887Schin 					goto found;
809*4887Schin 			}
810*4887Schin 			break;
811*4887Schin 		}
812*4887Schin 		else if (v > 0)
813*4887Schin 			lo = mid + 1;
814*4887Schin 		else
815*4887Schin 			hi = mid - 1;
816*4887Schin 	}
817*4887Schin 	return 0;
818*4887Schin  found:
819*4887Schin 	if (look->call < 0 && look->standard >= 0 && (look->section <= 1 || (mid->flags & CONF_MINMAX)))
820*4887Schin 		look->flags |= CONF_MINMAX;
821*4887Schin 	look->conf = mid;
822*4887Schin #if DEBUG || DEBUG_astconf
823*4887Schin 	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);
824*4887Schin #endif
825*4887Schin 	return 1;
826*4887Schin }
827*4887Schin 
828*4887Schin /*
829*4887Schin  * return a tolower'd copy of s
830*4887Schin  */
831*4887Schin 
832*4887Schin static char*
833*4887Schin fmtlower(register const char* s)
834*4887Schin {
835*4887Schin 	register int	c;
836*4887Schin 	register char*	t;
837*4887Schin 	char*		b;
838*4887Schin 
839*4887Schin 	b = t = fmtbuf(strlen(s) + 1);
840*4887Schin 	while (c = *s++)
841*4887Schin 	{
842*4887Schin 		if (isupper(c))
843*4887Schin 			c = tolower(c);
844*4887Schin 		*t++ = c;
845*4887Schin 	}
846*4887Schin 	*t = 0;
847*4887Schin 	return b;
848*4887Schin }
849*4887Schin 
850*4887Schin /*
851*4887Schin  * print value line for p
852*4887Schin  * if !name then value prefixed by "p->name="
853*4887Schin  * if (flags & CONF_MINMAX) then default minmax value used
854*4887Schin  */
855*4887Schin 
856*4887Schin static char*
857*4887Schin print(Sfio_t* sp, register Lookup_t* look, const char* name, const char* path, int listflags, Error_f conferror)
858*4887Schin {
859*4887Schin 	register Conf_t*	p = look->conf;
860*4887Schin 	register int		flags = look->flags;
861*4887Schin 	char*			call;
862*4887Schin 	char*			f;
863*4887Schin 	const char*		s;
864*4887Schin 	int			i;
865*4887Schin 	int			olderrno;
866*4887Schin 	int			drop;
867*4887Schin 	int			defined;
868*4887Schin 	intmax_t		v;
869*4887Schin 	char			buf[PATH_MAX];
870*4887Schin 	char			flg[16];
871*4887Schin 
872*4887Schin 	if (!name && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_LIMIT|CONF_MINMAX)) && (p->flags & (CONF_LIMIT|CONF_PREFIXED)) != CONF_LIMIT)
873*4887Schin 		flags |= CONF_PREFIXED;
874*4887Schin 	olderrno = errno;
875*4887Schin 	errno = 0;
876*4887Schin #if DEBUG || DEBUG_astconf
877*4887Schin 	error(-1, "astconf name=%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"
878*4887Schin 		, name , p->name, p->standard, p->section, prefix[p->call + CONF_call].name, p->op
879*4887Schin 		, (flags & CONF_FEATURE) ? "FEATURE|" : ""
880*4887Schin 		, (flags & CONF_LIMIT) ? "LIMIT|" : ""
881*4887Schin 		, (flags & CONF_MINMAX) ? "MINMAX|" : ""
882*4887Schin 		, (flags & CONF_PREFIXED) ? "PREFIXED|" : ""
883*4887Schin 		, (flags & CONF_STRING) ? "STRING|" : ""
884*4887Schin 		, (p->flags & CONF_DEFER_CALL) ? "DEFER_CALL|" : ""
885*4887Schin 		, (p->flags & CONF_DEFER_MM) ? "DEFER_MM|" : ""
886*4887Schin 		, (p->flags & CONF_FEATURE) ? "FEATURE|" : ""
887*4887Schin 		, (p->flags & CONF_LIMIT_DEF) ? "LIMIT_DEF|" : (p->flags & CONF_LIMIT) ? "LIMIT|" : ""
888*4887Schin 		, (p->flags & CONF_MINMAX_DEF) ? "MINMAX_DEF|" : (p->flags & CONF_MINMAX) ? "MINMAX|" : ""
889*4887Schin 		, (p->flags & CONF_NOUNDERSCORE) ? "NOUNDERSCORE|" : ""
890*4887Schin 		, (p->flags & CONF_PREFIXED) ? "PREFIXED|" : ""
891*4887Schin 		, (p->flags & CONF_PREFIX_ONLY) ? "PREFIX_ONLY|" : ""
892*4887Schin 		, (p->flags & CONF_STANDARD) ? "STANDARD|" : ""
893*4887Schin 		, (p->flags & CONF_STRING) ? "STRING|" : ""
894*4887Schin 		, (p->flags & CONF_UNDERSCORE) ? "UNDERSCORE|" : ""
895*4887Schin 		);
896*4887Schin #endif
897*4887Schin 	flags |= CONF_LIMIT_DEF|CONF_MINMAX_DEF;
898*4887Schin 	if (conferror && name)
899*4887Schin 	{
900*4887Schin 		if ((p->flags & CONF_PREFIX_ONLY) && look->standard < 0)
901*4887Schin 			goto bad;
902*4887Schin 		if (!(flags & CONF_MINMAX) || !(p->flags & CONF_MINMAX))
903*4887Schin 		{
904*4887Schin 			switch (p->call)
905*4887Schin 			{
906*4887Schin 			case CONF_pathconf:
907*4887Schin 				if (path == root)
908*4887Schin 				{
909*4887Schin 					(*conferror)(&state, &state, 2, "%s: path expected", name);
910*4887Schin 					goto bad;
911*4887Schin 				}
912*4887Schin 				break;
913*4887Schin 			default:
914*4887Schin 				if (path != root)
915*4887Schin 				{
916*4887Schin 					(*conferror)(&state, &state, 2, "%s: path not expected", name);
917*4887Schin 					goto bad;
918*4887Schin 				}
919*4887Schin 				break;
920*4887Schin 			}
921*4887Schin #ifdef _pth_getconf
922*4887Schin 			if (p->flags & CONF_DEFER_CALL)
923*4887Schin 				goto bad;
924*4887Schin #endif
925*4887Schin 		}
926*4887Schin 		else
927*4887Schin 		{
928*4887Schin 			if (path != root)
929*4887Schin 			{
930*4887Schin 				(*conferror)(&state, &state, 2, "%s: path not expected", name);
931*4887Schin 				goto bad;
932*4887Schin 			}
933*4887Schin #ifdef _pth_getconf
934*4887Schin 			if ((p->flags & CONF_DEFER_MM) || !(p->flags & CONF_MINMAX_DEF))
935*4887Schin 				goto bad;
936*4887Schin #endif
937*4887Schin 		}
938*4887Schin 		if (look->standard >= 0 && (name[0] != '_' && ((p->flags & CONF_UNDERSCORE) || look->section <= 1) || name[0] == '_' && (p->flags & CONF_NOUNDERSCORE)) || look->standard < 0 && name[0] == '_')
939*4887Schin 			goto bad;
940*4887Schin 	}
941*4887Schin 	s = 0;
942*4887Schin 	defined = 1;
943*4887Schin 	switch (i = (p->op < 0 || (flags & CONF_MINMAX) && (p->flags & CONF_MINMAX_DEF)) ? 0 : p->call)
944*4887Schin 	{
945*4887Schin 	case CONF_confstr:
946*4887Schin 		call = "confstr";
947*4887Schin #if _lib_confstr
948*4887Schin 		if (!(v = confstr(p->op, buf, sizeof(buf))))
949*4887Schin 		{
950*4887Schin 			defined = 0;
951*4887Schin 			v = -1;
952*4887Schin 			errno = EINVAL;
953*4887Schin 		}
954*4887Schin 		else if (v > 0)
955*4887Schin 		{
956*4887Schin 			buf[sizeof(buf) - 1] = 0;
957*4887Schin 			s = (const char*)buf;
958*4887Schin 		}
959*4887Schin 		else
960*4887Schin 			defined = 0;
961*4887Schin 		break;
962*4887Schin #else
963*4887Schin 		goto predef;
964*4887Schin #endif
965*4887Schin 	case CONF_pathconf:
966*4887Schin 		call = "pathconf";
967*4887Schin #if _lib_pathconf
968*4887Schin 		if ((v = pathconf(path, p->op)) < 0)
969*4887Schin 			defined = 0;
970*4887Schin 		break;
971*4887Schin #else
972*4887Schin 		goto predef;
973*4887Schin #endif
974*4887Schin 	case CONF_sysconf:
975*4887Schin 		call = "sysconf";
976*4887Schin #if _lib_sysconf
977*4887Schin 		if ((v = sysconf(p->op)) < 0)
978*4887Schin 			defined = 0;
979*4887Schin 		break;
980*4887Schin #else
981*4887Schin 		goto predef;
982*4887Schin #endif
983*4887Schin 	case CONF_sysinfo:
984*4887Schin 		call = "sysinfo";
985*4887Schin #if _lib_sysinfo
986*4887Schin 		if ((v = sysinfo(p->op, buf, sizeof(buf))) >= 0)
987*4887Schin 		{
988*4887Schin 			buf[sizeof(buf) - 1] = 0;
989*4887Schin 			s = (const char*)buf;
990*4887Schin 		}
991*4887Schin 		else
992*4887Schin 			defined = 0;
993*4887Schin 		break;
994*4887Schin #else
995*4887Schin 		goto predef;
996*4887Schin #endif
997*4887Schin 	default:
998*4887Schin 		call = "synthesis";
999*4887Schin 		errno = EINVAL;
1000*4887Schin 		v = -1;
1001*4887Schin 		defined = 0;
1002*4887Schin 		break;
1003*4887Schin 	case 0:
1004*4887Schin 		call = 0;
1005*4887Schin 		if (p->flags & CONF_MINMAX_DEF)
1006*4887Schin 		{
1007*4887Schin 			if (!((p->flags & CONF_LIMIT_DEF)))
1008*4887Schin 				flags |= CONF_MINMAX;
1009*4887Schin 			listflags &= ~ASTCONF_system;
1010*4887Schin 		}
1011*4887Schin 	predef:
1012*4887Schin 		if (look->standard == CONF_AST)
1013*4887Schin 		{
1014*4887Schin 			if (streq(look->name, "VERSION"))
1015*4887Schin 			{
1016*4887Schin 				v = _AST_VERSION;
1017*4887Schin 				break;
1018*4887Schin 			}
1019*4887Schin 		}
1020*4887Schin 		if (flags & CONF_MINMAX)
1021*4887Schin 		{
1022*4887Schin 			if ((p->flags & CONF_MINMAX_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_MM)))
1023*4887Schin 			{
1024*4887Schin 				v = p->minmax.number;
1025*4887Schin 				s = p->minmax.string;
1026*4887Schin 				break;
1027*4887Schin 			}
1028*4887Schin 		}
1029*4887Schin 		else if ((p->flags & CONF_LIMIT_DEF) && (!(listflags & ASTCONF_system) || !(p->flags & CONF_DEFER_CALL)))
1030*4887Schin 		{
1031*4887Schin 			v = p->limit.number;
1032*4887Schin 			s = p->limit.string;
1033*4887Schin 			break;
1034*4887Schin 		}
1035*4887Schin 		flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1036*4887Schin 		v = -1;
1037*4887Schin 		errno = EINVAL;
1038*4887Schin 		defined = 0;
1039*4887Schin 		break;
1040*4887Schin 	}
1041*4887Schin 	if (!defined)
1042*4887Schin 	{
1043*4887Schin 		if (!errno)
1044*4887Schin 		{
1045*4887Schin 			if ((p->flags & CONF_FEATURE) || !(p->flags & (CONF_LIMIT|CONF_MINMAX)))
1046*4887Schin 				flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1047*4887Schin 		}
1048*4887Schin 		else if (flags & CONF_PREFIXED)
1049*4887Schin 			flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1050*4887Schin 		else if (errno != EINVAL || !i)
1051*4887Schin 		{
1052*4887Schin 			if (!sp)
1053*4887Schin 			{
1054*4887Schin 				if (conferror)
1055*4887Schin 				{
1056*4887Schin 					if (call)
1057*4887Schin 						(*conferror)(&state, &state, ERROR_SYSTEM|2, "%s: %s error", p->name, call);
1058*4887Schin 					else if (!(listflags & ASTCONF_system))
1059*4887Schin 						(*conferror)(&state, &state, 2, "%s: unknown name", p->name);
1060*4887Schin 				}
1061*4887Schin 				goto bad;
1062*4887Schin 			}
1063*4887Schin 			else
1064*4887Schin 			{
1065*4887Schin 				flags &= ~(CONF_LIMIT_DEF|CONF_MINMAX_DEF);
1066*4887Schin 				flags |= CONF_ERROR;
1067*4887Schin 			}
1068*4887Schin 		}
1069*4887Schin 	}
1070*4887Schin 	errno = olderrno;
1071*4887Schin 	if ((listflags & ASTCONF_defined) && !(flags & (CONF_LIMIT_DEF|CONF_MINMAX_DEF)))
1072*4887Schin 		goto bad;
1073*4887Schin 	if ((drop = !sp) && !(sp = sfstropen()))
1074*4887Schin 		goto bad;
1075*4887Schin 	if (listflags & ASTCONF_table)
1076*4887Schin 	{
1077*4887Schin 		f = flg;
1078*4887Schin 		if (p->flags & CONF_DEFER_CALL)
1079*4887Schin 			*f++ = 'C';
1080*4887Schin 		if (p->flags & CONF_DEFER_MM)
1081*4887Schin 			*f++ = 'D';
1082*4887Schin 		if (p->flags & CONF_FEATURE)
1083*4887Schin 			*f++ = 'F';
1084*4887Schin 		if (p->flags & CONF_LIMIT)
1085*4887Schin 			*f++ = 'L';
1086*4887Schin 		if (p->flags & CONF_MINMAX)
1087*4887Schin 			*f++ = 'M';
1088*4887Schin 		if (p->flags & CONF_NOSECTION)
1089*4887Schin 			*f++ = 'N';
1090*4887Schin 		if (p->flags & CONF_PREFIXED)
1091*4887Schin 			*f++ = 'P';
1092*4887Schin 		if (p->flags & CONF_STANDARD)
1093*4887Schin 			*f++ = 'S';
1094*4887Schin 		if (p->flags & CONF_UNDERSCORE)
1095*4887Schin 			*f++ = 'U';
1096*4887Schin 		if (p->flags & CONF_NOUNDERSCORE)
1097*4887Schin 			*f++ = 'V';
1098*4887Schin 		if (p->flags & CONF_PREFIX_ONLY)
1099*4887Schin 			*f++ = 'W';
1100*4887Schin 		if (f == flg)
1101*4887Schin 			*f++ = 'X';
1102*4887Schin 		*f = 0;
1103*4887Schin 		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);
1104*4887Schin 		if (p->flags & CONF_LIMIT_DEF)
1105*4887Schin 		{
1106*4887Schin 			if (p->limit.string)
1107*4887Schin 				sfprintf(sp, "L[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->limit.string, "\"", "\"", strlen(p->limit.string), FMT_SHELL) : p->limit.string);
1108*4887Schin 			else
1109*4887Schin 				sfprintf(sp, "L[%I*d] ", sizeof(p->limit.number), p->limit.number);
1110*4887Schin 		}
1111*4887Schin 		if (p->flags & CONF_MINMAX_DEF)
1112*4887Schin 		{
1113*4887Schin 			if (p->minmax.string)
1114*4887Schin 				sfprintf(sp, "M[%s] ", (listflags & ASTCONF_quote) ? fmtquote(p->minmax.string, "\"", "\"", strlen(p->minmax.string), FMT_SHELL) : p->minmax.string);
1115*4887Schin 			else
1116*4887Schin 				sfprintf(sp, "M[%I*d] ", sizeof(p->minmax.number), p->minmax.number);
1117*4887Schin 		}
1118*4887Schin 		if (flags & CONF_ERROR)
1119*4887Schin 			sfprintf(sp, "error");
1120*4887Schin 		else if (defined)
1121*4887Schin 		{
1122*4887Schin 			if (s)
1123*4887Schin 				sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1124*4887Schin 			else if (v != -1)
1125*4887Schin 				sfprintf(sp, "%I*d", sizeof(v), v);
1126*4887Schin 			else
1127*4887Schin 				sfprintf(sp, "%I*u", sizeof(v), v);
1128*4887Schin 		}
1129*4887Schin 		sfprintf(sp, "\n");
1130*4887Schin 	}
1131*4887Schin 	else
1132*4887Schin 	{
1133*4887Schin 		if (!(flags & CONF_PREFIXED) || (listflags & ASTCONF_base))
1134*4887Schin 		{
1135*4887Schin 			if (!name)
1136*4887Schin 			{
1137*4887Schin 				if ((p->flags & (CONF_PREFIXED|CONF_STRING)) == (CONF_PREFIXED|CONF_STRING) && (!(listflags & ASTCONF_base) || p->standard != CONF_POSIX))
1138*4887Schin 				{
1139*4887Schin 					if ((p->flags & CONF_UNDERSCORE) && !(listflags & ASTCONF_base))
1140*4887Schin 						sfprintf(sp, "_");
1141*4887Schin 					sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1142*4887Schin 					if (p->section > 1)
1143*4887Schin 						sfprintf(sp, "%d", p->section);
1144*4887Schin 					sfprintf(sp, "_");
1145*4887Schin 				}
1146*4887Schin 				sfprintf(sp, "%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1147*4887Schin 			}
1148*4887Schin 			if (flags & CONF_ERROR)
1149*4887Schin 				sfprintf(sp, "error");
1150*4887Schin 			else if (defined)
1151*4887Schin 			{
1152*4887Schin 				if (s)
1153*4887Schin 					sfprintf(sp, "%s", (listflags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1154*4887Schin 				else if (v != -1)
1155*4887Schin 					sfprintf(sp, "%I*d", sizeof(v), v);
1156*4887Schin 				else
1157*4887Schin 					sfprintf(sp, "%I*u", sizeof(v), v);
1158*4887Schin 			}
1159*4887Schin 			else
1160*4887Schin 				sfprintf(sp, "undefined");
1161*4887Schin 			if (!name)
1162*4887Schin 				sfprintf(sp, "\n");
1163*4887Schin 		}
1164*4887Schin 		if (!name && !(listflags & ASTCONF_base) && !(p->flags & CONF_STRING) && (p->flags & (CONF_FEATURE|CONF_MINMAX)))
1165*4887Schin 		{
1166*4887Schin 			if (p->flags & CONF_UNDERSCORE)
1167*4887Schin 				sfprintf(sp, "_");
1168*4887Schin 			sfprintf(sp, "%s", (listflags & ASTCONF_lower) ? fmtlower(prefix[p->standard].name) : prefix[p->standard].name);
1169*4887Schin 			if (p->section > 1)
1170*4887Schin 				sfprintf(sp, "%d", p->section);
1171*4887Schin 			sfprintf(sp, "_%s=", (listflags & ASTCONF_lower) ? fmtlower(p->name) : p->name);
1172*4887Schin 			if (v != -1)
1173*4887Schin 				sfprintf(sp, "%I*d", sizeof(v), v);
1174*4887Schin 			else if (defined)
1175*4887Schin 				sfprintf(sp, "%I*u", sizeof(v), v);
1176*4887Schin 			else
1177*4887Schin 				sfprintf(sp, "undefined");
1178*4887Schin 			sfprintf(sp, "\n");
1179*4887Schin 		}
1180*4887Schin 	}
1181*4887Schin 	if (drop)
1182*4887Schin 	{
1183*4887Schin 		if (call = sfstruse(sp))
1184*4887Schin 			call = buffer(call);
1185*4887Schin 		else
1186*4887Schin 			call = "[ out of space ]";
1187*4887Schin 		sfclose(sp);
1188*4887Schin 		return call;
1189*4887Schin 	}
1190*4887Schin  bad:
1191*4887Schin 	return (listflags & ASTCONF_error) ? (char*)0 : null;
1192*4887Schin }
1193*4887Schin 
1194*4887Schin /*
1195*4887Schin  * return read stream to native getconf utility
1196*4887Schin  */
1197*4887Schin 
1198*4887Schin static Sfio_t*
1199*4887Schin nativeconf(Proc_t** pp, const char* operand)
1200*4887Schin {
1201*4887Schin #ifdef _pth_getconf
1202*4887Schin 	Sfio_t*		sp;
1203*4887Schin 	char*		cmd[3];
1204*4887Schin 	long		ops[2];
1205*4887Schin 
1206*4887Schin #if DEBUG || DEBUG_astconf
1207*4887Schin 	error(-2, "astconf defer %s %s", _pth_getconf, operand);
1208*4887Schin #endif
1209*4887Schin 	cmd[0] = (char*)state.id;
1210*4887Schin 	cmd[1] = (char*)operand;
1211*4887Schin 	cmd[2] = 0;
1212*4887Schin 	ops[0] = PROC_FD_DUP(open("/dev/null",O_WRONLY,0), 2, PROC_FD_CHILD);
1213*4887Schin 	ops[1] = 0;
1214*4887Schin 	if (*pp = procopen(_pth_getconf, cmd, environ, ops, PROC_READ))
1215*4887Schin 	{
1216*4887Schin 		if (sp = sfnew(NiL, NiL, SF_UNBOUND, (*pp)->rfd, SF_READ))
1217*4887Schin 		{
1218*4887Schin 			sfdisc(sp, SF_POPDISC);
1219*4887Schin 			return sp;
1220*4887Schin 		}
1221*4887Schin 		procclose(*pp);
1222*4887Schin 	}
1223*4887Schin #endif
1224*4887Schin 	return 0;
1225*4887Schin }
1226*4887Schin 
1227*4887Schin /*
1228*4887Schin  * value==0 gets value for name
1229*4887Schin  * value!=0 sets value for name and returns previous value
1230*4887Schin  * path==0 implies path=="/"
1231*4887Schin  *
1232*4887Schin  * settable return values are in permanent store
1233*4887Schin  * non-settable return values copied to a tmp fmtbuf() buffer
1234*4887Schin  *
1235*4887Schin  *	if (streq(astgetconf("PATH_RESOLVE", NiL, NiL, 0, 0), "logical"))
1236*4887Schin  *		our_way();
1237*4887Schin  *
1238*4887Schin  *	universe = astgetconf("UNIVERSE", NiL, "att", 0, 0);
1239*4887Schin  *	astgetconf("UNIVERSE", NiL, universe, 0, 0);
1240*4887Schin  *
1241*4887Schin  * if (flags&ASTCONF_error)!=0 then error return value is 0
1242*4887Schin  * otherwise 0 not returned
1243*4887Schin  */
1244*4887Schin 
1245*4887Schin #define ALT	16
1246*4887Schin 
1247*4887Schin char*
1248*4887Schin astgetconf(const char* name, const char* path, const char* value, int flags, Error_f conferror)
1249*4887Schin {
1250*4887Schin 	register char*	s;
1251*4887Schin 	int		n;
1252*4887Schin 	Lookup_t	look;
1253*4887Schin 	Sfio_t*		tmp;
1254*4887Schin 
1255*4887Schin #if __OBSOLETE__ < 20080101
1256*4887Schin 	if (pointerof(flags) == (void*)errorf)
1257*4887Schin 	{
1258*4887Schin 		conferror = errorf;
1259*4887Schin 		flags = ASTCONF_error;
1260*4887Schin 	}
1261*4887Schin 	else if (conferror && conferror != errorf)
1262*4887Schin 		conferror = 0;
1263*4887Schin #endif
1264*4887Schin 	if (!name)
1265*4887Schin 	{
1266*4887Schin 		if (path)
1267*4887Schin 			return null;
1268*4887Schin 		if (!(name = value))
1269*4887Schin 		{
1270*4887Schin 			if (state.data)
1271*4887Schin 			{
1272*4887Schin 				Ast_confdisc_f	notify;
1273*4887Schin 
1274*4887Schin #if _HUH20000515 /* doesn't work for shell builtins */
1275*4887Schin 				free(state.data - state.prefix);
1276*4887Schin #endif
1277*4887Schin 				state.data = 0;
1278*4887Schin 				notify = state.notify;
1279*4887Schin 				state.notify = 0;
1280*4887Schin 				INITIALIZE();
1281*4887Schin 				state.notify = notify;
1282*4887Schin 			}
1283*4887Schin 			return null;
1284*4887Schin 		}
1285*4887Schin 		value = 0;
1286*4887Schin 	}
1287*4887Schin 	INITIALIZE();
1288*4887Schin 	if (!path)
1289*4887Schin 		path = root;
1290*4887Schin 	if (state.recent && streq(name, state.recent->name) && (s = format(state.recent, path, value, flags, conferror)))
1291*4887Schin 		return s;
1292*4887Schin 	if (lookup(&look, name, flags))
1293*4887Schin 	{
1294*4887Schin 		if (value)
1295*4887Schin 		{
1296*4887Schin 		ro:
1297*4887Schin 			errno = EINVAL;
1298*4887Schin 			if (conferror)
1299*4887Schin 				(*conferror)(&state, &state, 2, "%s: cannot set value", name);
1300*4887Schin 			return (flags & ASTCONF_error) ? (char*)0 : null;
1301*4887Schin 		}
1302*4887Schin 		return print(NiL, &look, name, path, flags, conferror);
1303*4887Schin 	}
1304*4887Schin 	if ((n = strlen(name)) > 3 && n < (ALT + 3))
1305*4887Schin 	{
1306*4887Schin 		if (streq(name + n - 3, "DEV"))
1307*4887Schin 		{
1308*4887Schin 			if (tmp = sfstropen())
1309*4887Schin 			{
1310*4887Schin 				sfprintf(tmp, "/dev/");
1311*4887Schin 				for (s = (char*)name; s < (char*)name + n - 3; s++)
1312*4887Schin 					sfputc(tmp, isupper(*s) ? tolower(*s) : *s);
1313*4887Schin 				if ((s = sfstruse(tmp)) && !access(s, F_OK))
1314*4887Schin 				{
1315*4887Schin 					if (value)
1316*4887Schin 						goto ro;
1317*4887Schin 					s = buffer(s);
1318*4887Schin 					sfclose(tmp);
1319*4887Schin 					return s;
1320*4887Schin 				}
1321*4887Schin 				sfclose(tmp);
1322*4887Schin 			}
1323*4887Schin 		}
1324*4887Schin 		else if (streq(name + n - 3, "DIR"))
1325*4887Schin 		{
1326*4887Schin 			Lookup_t		altlook;
1327*4887Schin 			char			altname[ALT];
1328*4887Schin 
1329*4887Schin 			static const char*	dirs[] = { "/usr/lib", "/usr", null };
1330*4887Schin 
1331*4887Schin 			strcpy(altname, name);
1332*4887Schin 			altname[n - 3] = 0;
1333*4887Schin 			if (lookup(&altlook, altname, flags))
1334*4887Schin 			{
1335*4887Schin 				if (value)
1336*4887Schin 				{
1337*4887Schin 					errno = EINVAL;
1338*4887Schin 					if (conferror)
1339*4887Schin 						(*conferror)(&state, &state, 2, "%s: cannot set value", altname);
1340*4887Schin 					return (flags & ASTCONF_error) ? (char*)0 : null;
1341*4887Schin 				}
1342*4887Schin 				return print(NiL, &altlook, altname, path, flags, conferror);
1343*4887Schin 			}
1344*4887Schin 			for (s = altname; *s; s++)
1345*4887Schin 				if (isupper(*s))
1346*4887Schin 					*s = tolower(*s);
1347*4887Schin 			if (tmp = sfstropen())
1348*4887Schin 			{
1349*4887Schin 				for (n = 0; n < elementsof(dirs); n++)
1350*4887Schin 				{
1351*4887Schin 					sfprintf(tmp, "%s/%s/.", dirs[n], altname);
1352*4887Schin 					if ((s = sfstruse(tmp)) && !access(s, F_OK))
1353*4887Schin 					{
1354*4887Schin 						if (value)
1355*4887Schin 							goto ro;
1356*4887Schin 						s = buffer(s);
1357*4887Schin 						sfclose(tmp);
1358*4887Schin 						return s;
1359*4887Schin 					}
1360*4887Schin 				}
1361*4887Schin 				sfclose(tmp);
1362*4887Schin 			}
1363*4887Schin 		}
1364*4887Schin 	}
1365*4887Schin 	if ((look.standard < 0 || look.standard == CONF_AST) && look.call <= 0 && look.section <= 1 && (s = feature(look.name, path, value, flags, conferror)))
1366*4887Schin 		return s;
1367*4887Schin 	errno = EINVAL;
1368*4887Schin 	if (conferror && !(flags & ASTCONF_system))
1369*4887Schin 		(*conferror)(&state, &state, 2, "%s: unknown name", name);
1370*4887Schin 	return (flags & ASTCONF_error) ? (char*)0 : null;
1371*4887Schin }
1372*4887Schin 
1373*4887Schin /*
1374*4887Schin  * astconf() never returns 0
1375*4887Schin  */
1376*4887Schin 
1377*4887Schin char*
1378*4887Schin astconf(const char* name, const char* path, const char* value)
1379*4887Schin {
1380*4887Schin 	return astgetconf(name, path, value, 0, 0);
1381*4887Schin }
1382*4887Schin 
1383*4887Schin /*
1384*4887Schin  * set discipline function to be called when features change
1385*4887Schin  * old discipline function returned
1386*4887Schin  */
1387*4887Schin 
1388*4887Schin Ast_confdisc_f
1389*4887Schin astconfdisc(Ast_confdisc_f new_notify)
1390*4887Schin {
1391*4887Schin 	Ast_confdisc_f	old_notify;
1392*4887Schin 
1393*4887Schin 	INITIALIZE();
1394*4887Schin 	old_notify = state.notify;
1395*4887Schin 	state.notify = new_notify;
1396*4887Schin 	return old_notify;
1397*4887Schin }
1398*4887Schin 
1399*4887Schin /*
1400*4887Schin  * list all name=value entries on sp
1401*4887Schin  * path==0 implies path=="/"
1402*4887Schin  */
1403*4887Schin 
1404*4887Schin void
1405*4887Schin astconflist(Sfio_t* sp, const char* path, int flags, const char* pattern)
1406*4887Schin {
1407*4887Schin 	char*		s;
1408*4887Schin 	char*		f;
1409*4887Schin 	char*		call;
1410*4887Schin 	Feature_t*	fp;
1411*4887Schin 	Lookup_t	look;
1412*4887Schin 	regex_t		re;
1413*4887Schin 	regdisc_t	redisc;
1414*4887Schin 	int		olderrno;
1415*4887Schin 	char		flg[8];
1416*4887Schin #ifdef _pth_getconf_a
1417*4887Schin 	Proc_t*		proc;
1418*4887Schin 	Sfio_t*		pp;
1419*4887Schin #endif
1420*4887Schin 
1421*4887Schin 	INITIALIZE();
1422*4887Schin 	if (!path)
1423*4887Schin 		path = root;
1424*4887Schin 	else if (access(path, F_OK))
1425*4887Schin 	{
1426*4887Schin 		errorf(&state, &state, 2, "%s: not found", path);
1427*4887Schin 		return;
1428*4887Schin 	}
1429*4887Schin 	olderrno = errno;
1430*4887Schin 	look.flags = 0;
1431*4887Schin 	if (!(flags & (ASTCONF_read|ASTCONF_write|ASTCONF_parse)))
1432*4887Schin 		flags |= ASTCONF_read|ASTCONF_write;
1433*4887Schin 	else if (flags & ASTCONF_parse)
1434*4887Schin 		flags |= ASTCONF_write;
1435*4887Schin 	if (!(flags & (ASTCONF_matchcall|ASTCONF_matchname|ASTCONF_matchstandard)))
1436*4887Schin 		pattern = 0;
1437*4887Schin 	if (pattern)
1438*4887Schin 	{
1439*4887Schin 		memset(&redisc, 0, sizeof(redisc));
1440*4887Schin 		redisc.re_version = REG_VERSION;
1441*4887Schin 		redisc.re_errorf = (regerror_t)errorf;
1442*4887Schin 		re.re_disc = &redisc;
1443*4887Schin 		if (regcomp(&re, pattern, REG_DISCIPLINE|REG_EXTENDED|REG_LENIENT|REG_NULL))
1444*4887Schin 			return;
1445*4887Schin 	}
1446*4887Schin 	if (flags & ASTCONF_read)
1447*4887Schin 	{
1448*4887Schin 		for (look.conf = (Conf_t*)conf; look.conf < (Conf_t*)&conf[conf_elements]; look.conf++)
1449*4887Schin 		{
1450*4887Schin 			if (pattern)
1451*4887Schin 			{
1452*4887Schin 				if (flags & ASTCONF_matchcall)
1453*4887Schin 				{
1454*4887Schin 					if (regexec(&re, prefix[look.conf->call + CONF_call].name, 0, NiL, 0))
1455*4887Schin 						continue;
1456*4887Schin 				}
1457*4887Schin 				else if (flags & ASTCONF_matchname)
1458*4887Schin 				{
1459*4887Schin 					if (regexec(&re, look.conf->name, 0, NiL, 0))
1460*4887Schin 						continue;
1461*4887Schin 				}
1462*4887Schin 				else if (flags & ASTCONF_matchstandard)
1463*4887Schin 				{
1464*4887Schin 					if (regexec(&re, prefix[look.conf->standard].name, 0, NiL, 0))
1465*4887Schin 						continue;
1466*4887Schin 				}
1467*4887Schin 			}
1468*4887Schin 			print(sp, &look, NiL, path, flags, errorf);
1469*4887Schin 		}
1470*4887Schin #ifdef _pth_getconf_a
1471*4887Schin 		if (pp = nativeconf(&proc, _pth_getconf_a))
1472*4887Schin 		{
1473*4887Schin 			call = "GC";
1474*4887Schin 			while (f = sfgetr(pp, '\n', 1))
1475*4887Schin 			{
1476*4887Schin 				for (s = f; *s && *s != '=' && *s != ':' && !isspace(*s); s++);
1477*4887Schin 				if (*s)
1478*4887Schin 					for (*s++ = 0; isspace(*s); s++);
1479*4887Schin 				if (!lookup(&look, f, flags))
1480*4887Schin 				{
1481*4887Schin 					if (flags & ASTCONF_table)
1482*4887Schin 					{
1483*4887Schin 						if (look.standard < 0)
1484*4887Schin 							look.standard = 0;
1485*4887Schin 						if (look.section < 1)
1486*4887Schin 							look.section = 1;
1487*4887Schin 						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);
1488*4887Schin 					}
1489*4887Schin 					else if (flags & ASTCONF_parse)
1490*4887Schin 						sfprintf(sp, "%s %s - %s\n", state.id, f, s);
1491*4887Schin 					else
1492*4887Schin 						sfprintf(sp, "%s=%s\n", f, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1493*4887Schin 				}
1494*4887Schin 			}
1495*4887Schin 			sfclose(pp);
1496*4887Schin 			procclose(proc);
1497*4887Schin 		}
1498*4887Schin #endif
1499*4887Schin 	}
1500*4887Schin 	if (flags & ASTCONF_write)
1501*4887Schin 	{
1502*4887Schin 		call = "AC";
1503*4887Schin 		for (fp = state.features; fp; fp = fp->next)
1504*4887Schin 		{
1505*4887Schin 			if (pattern)
1506*4887Schin 			{
1507*4887Schin 				if (flags & ASTCONF_matchcall)
1508*4887Schin 				{
1509*4887Schin 					if (regexec(&re, call, 0, NiL, 0))
1510*4887Schin 						continue;
1511*4887Schin 				}
1512*4887Schin 				else if (flags & ASTCONF_matchname)
1513*4887Schin 				{
1514*4887Schin 					if (regexec(&re, fp->name, 0, NiL, 0))
1515*4887Schin 						continue;
1516*4887Schin 				}
1517*4887Schin 				else if (flags & ASTCONF_matchstandard)
1518*4887Schin 				{
1519*4887Schin 					if (regexec(&re, prefix[fp->standard].name, 0, NiL, 0))
1520*4887Schin 						continue;
1521*4887Schin 				}
1522*4887Schin 			}
1523*4887Schin 			if (!(s = feature(fp->name, path, NiL, 0, 0)) || !*s)
1524*4887Schin 				s = "0";
1525*4887Schin 			if (flags & ASTCONF_table)
1526*4887Schin 			{
1527*4887Schin 				f = flg;
1528*4887Schin 				if (fp->flags & CONF_ALLOC)
1529*4887Schin 					*f++ = 'A';
1530*4887Schin 				if (fp->flags & CONF_READONLY)
1531*4887Schin 					*f++ = 'R';
1532*4887Schin 				if (f == flg)
1533*4887Schin 					*f++ = 'X';
1534*4887Schin 				*f = 0;
1535*4887Schin 				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);
1536*4887Schin 			}
1537*4887Schin 			else if (flags & ASTCONF_parse)
1538*4887Schin 				sfprintf(sp, "%s %s - %s\n", state.id, (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL));
1539*4887Schin 			else
1540*4887Schin 				sfprintf(sp, "%s=%s\n", (flags & ASTCONF_lower) ? fmtlower(fp->name) : fp->name, (flags & ASTCONF_quote) ? fmtquote(s, "\"", "\"", strlen(s), FMT_SHELL) : s);
1541*4887Schin 		}
1542*4887Schin 	}
1543*4887Schin 	if (pattern)
1544*4887Schin 		regfree(&re);
1545*4887Schin 	errno = olderrno;
1546*4887Schin }
1547