xref: /onnv-gate/usr/src/lib/libast/common/disc/sfkeyprintf.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  * Glenn Fowler
26*4887Schin  * AT&T Research
27*4887Schin  *
28*4887Schin  * keyword printf support
29*4887Schin  */
30*4887Schin 
31*4887Schin #include <ast.h>
32*4887Schin #include <ccode.h>
33*4887Schin #include <ctype.h>
34*4887Schin #include <sfdisc.h>
35*4887Schin #include <regex.h>
36*4887Schin 
37*4887Schin #define FMT_case	1
38*4887Schin #define FMT_edit	2
39*4887Schin 
40*4887Schin typedef struct
41*4887Schin {
42*4887Schin 	Sffmt_t			fmt;
43*4887Schin 	void*			handle;
44*4887Schin 	Sf_key_lookup_t		lookup;
45*4887Schin 	Sf_key_convert_t	convert;
46*4887Schin 	Sfio_t*			tmp[2];
47*4887Schin 	regex_t			red[2];
48*4887Schin 	regex_t*		re[2];
49*4887Schin 	int			invisible;
50*4887Schin 	int			level;
51*4887Schin 	int			version;
52*4887Schin } Fmt_t;
53*4887Schin 
54*4887Schin typedef struct
55*4887Schin {
56*4887Schin 	char*			next;
57*4887Schin 	int			delimiter;
58*4887Schin 	int			first;
59*4887Schin } Field_t;
60*4887Schin 
61*4887Schin typedef union
62*4887Schin {
63*4887Schin 	char**			p;
64*4887Schin 	char*			s;
65*4887Schin 	Sflong_t		q;
66*4887Schin 	long			l;
67*4887Schin 	int			i;
68*4887Schin 	short			h;
69*4887Schin 	char			c;
70*4887Schin } Value_t;
71*4887Schin 
72*4887Schin #define initfield(f,s)	((f)->first = (f)->delimiter = *((f)->next = (s)))
73*4887Schin 
74*4887Schin static char*
75*4887Schin getfield(register Field_t* f, int restore)
76*4887Schin {
77*4887Schin 	register char*	s;
78*4887Schin 	register int	n;
79*4887Schin 	register int	c;
80*4887Schin 	register int	lp;
81*4887Schin 	register int	rp;
82*4887Schin 	char*		b;
83*4887Schin 
84*4887Schin 	if (!f->delimiter)
85*4887Schin 		return 0;
86*4887Schin 	s = f->next;
87*4887Schin 	if (f->first)
88*4887Schin 		f->first = 0;
89*4887Schin 	else if (restore)
90*4887Schin 		*s = f->delimiter;
91*4887Schin 	b = ++s;
92*4887Schin 	lp = rp = n = 0;
93*4887Schin 	for (;;)
94*4887Schin 	{
95*4887Schin 		if (!(c = *s++))
96*4887Schin 		{
97*4887Schin 			f->delimiter = 0;
98*4887Schin 			break;
99*4887Schin 		}
100*4887Schin 		else if (c == CC_esc || c == '\\')
101*4887Schin 		{
102*4887Schin 			if (*s)
103*4887Schin 				s++;
104*4887Schin 		}
105*4887Schin 		else if (c == lp)
106*4887Schin 			n++;
107*4887Schin 		else if (c == rp)
108*4887Schin 			n--;
109*4887Schin 		else if (n <= 0)
110*4887Schin 		{
111*4887Schin 			if (c == '(' && restore)
112*4887Schin 			{
113*4887Schin 				lp = '(';
114*4887Schin 				rp = ')';
115*4887Schin 				n = 1;
116*4887Schin 			}
117*4887Schin 			else if (c == '[' && restore)
118*4887Schin 			{
119*4887Schin 				lp = '[';
120*4887Schin 				rp = ']';
121*4887Schin 				n = 1;
122*4887Schin 			}
123*4887Schin 			else if (c == f->delimiter)
124*4887Schin 			{
125*4887Schin 				*(f->next = --s) = 0;
126*4887Schin 				break;
127*4887Schin 			}
128*4887Schin 		}
129*4887Schin 	}
130*4887Schin 	return b;
131*4887Schin }
132*4887Schin 
133*4887Schin /*
134*4887Schin  * sfio %! extension function
135*4887Schin  */
136*4887Schin 
137*4887Schin static int
138*4887Schin getfmt(Sfio_t* sp, void* vp, Sffmt_t* dp)
139*4887Schin {
140*4887Schin 	register Fmt_t*	fp = (Fmt_t*)dp;
141*4887Schin 	Value_t*	value = (Value_t*)vp;
142*4887Schin 	register char*	v;
143*4887Schin 	char*		t;
144*4887Schin 	char*		b;
145*4887Schin 	char*		a = 0;
146*4887Schin 	char*		s = 0;
147*4887Schin 	Sflong_t	n = 0;
148*4887Schin 	int		h = 0;
149*4887Schin 	int		i = 0;
150*4887Schin 	int		x = 0;
151*4887Schin 	int		d;
152*4887Schin 	Field_t		f;
153*4887Schin 	regmatch_t	match[10];
154*4887Schin 
155*4887Schin 	fp->level++;
156*4887Schin 	if (fp->fmt.t_str && fp->fmt.n_str > 0 && (v = fmtbuf(fp->fmt.n_str + 1)))
157*4887Schin 	{
158*4887Schin 		memcpy(v, fp->fmt.t_str, fp->fmt.n_str);
159*4887Schin 		v[fp->fmt.n_str] = 0;
160*4887Schin 		b = v;
161*4887Schin 		for (;;)
162*4887Schin 		{
163*4887Schin 			switch (*v++)
164*4887Schin 			{
165*4887Schin 			case 0:
166*4887Schin 				break;
167*4887Schin 			case '(':
168*4887Schin 				h++;
169*4887Schin 				continue;
170*4887Schin 			case ')':
171*4887Schin 				h--;
172*4887Schin 				continue;
173*4887Schin 			case '=':
174*4887Schin 			case ':':
175*4887Schin 			case ',':
176*4887Schin 				if (h <= 0)
177*4887Schin 				{
178*4887Schin 					a = v;
179*4887Schin 					break;
180*4887Schin 				}
181*4887Schin 				continue;
182*4887Schin 			default:
183*4887Schin 				continue;
184*4887Schin 			}
185*4887Schin 			if (i = *--v)
186*4887Schin 			{
187*4887Schin 				*v = 0;
188*4887Schin 				if (i == ':' && fp->fmt.fmt == 's' && strlen(a) > 4 && !isalnum(*(a + 4)))
189*4887Schin 				{
190*4887Schin 					d = *(a + 4);
191*4887Schin 					*(a + 4) = 0;
192*4887Schin 					if (streq(a, "case"))
193*4887Schin 						x = FMT_case;
194*4887Schin 					else if (streq(a, "edit"))
195*4887Schin 						x = FMT_edit;
196*4887Schin 					*(a + 4) = d;
197*4887Schin 					if (x)
198*4887Schin 						a = 0;
199*4887Schin 				}
200*4887Schin 			}
201*4887Schin 			break;
202*4887Schin 		}
203*4887Schin 		n = i;
204*4887Schin 		t = fp->fmt.t_str;
205*4887Schin 		fp->fmt.t_str = b;
206*4887Schin 		h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
207*4887Schin 		fp->fmt.t_str = t;
208*4887Schin 		if (i)
209*4887Schin 			*v++ = i;
210*4887Schin 	}
211*4887Schin 	else
212*4887Schin 	{
213*4887Schin 		h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
214*4887Schin 		v = 0;
215*4887Schin 	}
216*4887Schin 	fp->fmt.flags |= SFFMT_VALUE;
217*4887Schin 	switch (fp->fmt.fmt)
218*4887Schin 	{
219*4887Schin 	case 'c':
220*4887Schin 		value->c = s ? *s : n;
221*4887Schin 		break;
222*4887Schin 	case 'd':
223*4887Schin 	case 'i':
224*4887Schin 		fp->fmt.size = sizeof(Sflong_t);
225*4887Schin 		value->q = (Sflong_t)(s ? strtoll(s, NiL, 0) : n);
226*4887Schin 		break;
227*4887Schin 	case 'o':
228*4887Schin 	case 'u':
229*4887Schin 	case 'x':
230*4887Schin 		fp->fmt.size = sizeof(Sflong_t);
231*4887Schin 		value->q = s ? (Sflong_t)strtoull(s, NiL, 0) : n;
232*4887Schin 		break;
233*4887Schin 	case 'p':
234*4887Schin 		if (s)
235*4887Schin 			n = strtoll(s, NiL, 0);
236*4887Schin 		value->p = pointerof(n);
237*4887Schin 		break;
238*4887Schin 	case 'q':
239*4887Schin 		if (s)
240*4887Schin 		{
241*4887Schin 			fp->fmt.fmt = 's';
242*4887Schin 			value->s = fmtquote(s, "$'", "'", strlen(s), 0);
243*4887Schin 		}
244*4887Schin 		else
245*4887Schin 		{
246*4887Schin 			fp->fmt.fmt = 'd';
247*4887Schin 			value->q = n;
248*4887Schin 		}
249*4887Schin 		break;
250*4887Schin 	case 's':
251*4887Schin 		if (!s && (!h || !fp->tmp[1] && !(fp->tmp[1] = sfstropen()) || sfprintf(fp->tmp[1], "%I*d", sizeof(n), n) <= 0 || !(s = sfstruse(fp->tmp[1]))))
252*4887Schin 			s = "";
253*4887Schin 		if (x)
254*4887Schin 		{
255*4887Schin 			h = 0;
256*4887Schin 			d = initfield(&f, v + 4);
257*4887Schin 			switch (x)
258*4887Schin 			{
259*4887Schin 			case FMT_case:
260*4887Schin 				while ((a = getfield(&f, 1)) && (v = getfield(&f, 0)))
261*4887Schin 				{
262*4887Schin 					if (strmatch(s, a))
263*4887Schin 					{
264*4887Schin 						Fmt_t	fmt;
265*4887Schin 
266*4887Schin 						fmt = *fp;
267*4887Schin 						fmt.fmt.form = v;
268*4887Schin 						for (h = 0; h < elementsof(fmt.tmp); h++)
269*4887Schin 							fmt.tmp[h] = 0;
270*4887Schin 						if (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%!", &fmt) <= 0 || !(s = sfstruse(fp->tmp[0])))
271*4887Schin 							s = "";
272*4887Schin 						*(v - 1) = d;
273*4887Schin 						if (f.delimiter)
274*4887Schin 							*f.next = d;
275*4887Schin 						for (h = 0; h < elementsof(fmt.tmp); h++)
276*4887Schin 							if (fmt.tmp[h])
277*4887Schin 								sfclose(fmt.tmp[h]);
278*4887Schin 						h = 1;
279*4887Schin 						break;
280*4887Schin 					}
281*4887Schin 					*(v - 1) = d;
282*4887Schin 				}
283*4887Schin 				break;
284*4887Schin 			case FMT_edit:
285*4887Schin 				for (x = 0; *f.next; x ^= 1)
286*4887Schin 				{
287*4887Schin 					if (fp->re[x])
288*4887Schin 						regfree(fp->re[x]);
289*4887Schin 					else
290*4887Schin 						fp->re[x] = &fp->red[x];
291*4887Schin 					if (regcomp(fp->re[x], f.next, REG_DELIMITED|REG_NULL))
292*4887Schin 						break;
293*4887Schin 					f.next += fp->re[x]->re_npat;
294*4887Schin 					if (regsubcomp(fp->re[x], f.next, NiL, 0, 0))
295*4887Schin 						break;
296*4887Schin 					f.next += fp->re[x]->re_npat;
297*4887Schin 					if (!regexec(fp->re[x], s, elementsof(match), match, 0) && !regsubexec(fp->re[x], s, elementsof(match), match))
298*4887Schin 					{
299*4887Schin 						s = fp->re[x]->re_sub->re_buf;
300*4887Schin 						if (fp->re[x]->re_sub->re_flags & REG_SUB_STOP)
301*4887Schin 							break;
302*4887Schin 					}
303*4887Schin 				}
304*4887Schin 				h = 1;
305*4887Schin 				break;
306*4887Schin 			}
307*4887Schin 			if (!h)
308*4887Schin 				s = "";
309*4887Schin 		}
310*4887Schin 		value->s = s;
311*4887Schin 		if (fp->level == 1)
312*4887Schin 			while ((s = strchr(s, CC_esc)) && *(s + 1) == '[')
313*4887Schin 				do fp->invisible++; while (*s && !islower(*s++));
314*4887Schin 		break;
315*4887Schin 	case 'Z':
316*4887Schin 		fp->fmt.fmt = 'c';
317*4887Schin 		value->c = 0;
318*4887Schin 		break;
319*4887Schin 	case '\n':
320*4887Schin 		value->s = "\n";
321*4887Schin 		break;
322*4887Schin 	case '.':
323*4887Schin 		value->i = n;
324*4887Schin 		break;
325*4887Schin 	default:
326*4887Schin 		if ((!fp->convert || !(value->s = (*fp->convert)(fp->handle, &fp->fmt, a, s, n))) && (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%%%c", fp->fmt.fmt) <= 0 || !(value->s = sfstruse(fp->tmp[0]))))
327*4887Schin 			value->s = "";
328*4887Schin 		break;
329*4887Schin 	}
330*4887Schin 	fp->level--;
331*4887Schin 	return 0;
332*4887Schin }
333*4887Schin 
334*4887Schin /*
335*4887Schin  * this is the 20000308 interface with Sffmt_t* callback args
336*4887Schin  */
337*4887Schin 
338*4887Schin int
339*4887Schin sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
340*4887Schin {
341*4887Schin 	register int	i;
342*4887Schin 	int		r;
343*4887Schin 	Fmt_t		fmt;
344*4887Schin 
345*4887Schin 	memset(&fmt, 0, sizeof(fmt));
346*4887Schin 	fmt.version = 20030909;
347*4887Schin 	fmt.fmt.version = SFIO_VERSION;
348*4887Schin 	fmt.fmt.form = (char*)format;
349*4887Schin 	fmt.fmt.extf = getfmt;
350*4887Schin 	fmt.handle = handle;
351*4887Schin 	fmt.lookup = lookup;
352*4887Schin 	fmt.convert = convert;
353*4887Schin 	r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
354*4887Schin 	for (i = 0; i < elementsof(fmt.tmp); i++)
355*4887Schin 		if (fmt.tmp[i])
356*4887Schin 			sfclose(fmt.tmp[i]);
357*4887Schin 	return r;
358*4887Schin }
359*4887Schin 
360*4887Schin /*
361*4887Schin  * this is the original interface
362*4887Schin  */
363*4887Schin 
364*4887Schin #undef	sfkeyprintf
365*4887Schin 
366*4887Schin int
367*4887Schin sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
368*4887Schin {
369*4887Schin 	register int	i;
370*4887Schin 	int		r;
371*4887Schin 	Fmt_t		fmt;
372*4887Schin 
373*4887Schin 	memset(&fmt, 0, sizeof(fmt));
374*4887Schin 	fmt.fmt.version = SFIO_VERSION;
375*4887Schin 	fmt.fmt.form = (char*)format;
376*4887Schin 	fmt.fmt.extf = getfmt;
377*4887Schin 	fmt.handle = handle;
378*4887Schin 	fmt.lookup = lookup;
379*4887Schin 	fmt.convert = convert;
380*4887Schin 	r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
381*4887Schin 	for (i = 0; i < elementsof(fmt.tmp); i++)
382*4887Schin 		if (fmt.tmp[i])
383*4887Schin 			sfclose(fmt.tmp[i]);
384*4887Schin 	for (i = 0; i < elementsof(fmt.re); i++)
385*4887Schin 		if (fmt.re[i])
386*4887Schin 			regfree(fmt.re[i]);
387*4887Schin 	return r;
388*4887Schin }
389