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