xref: /onnv-gate/usr/src/lib/libast/common/disc/sfkeyprintf.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * Glenn Fowler
264887Schin  * AT&T Research
274887Schin  *
284887Schin  * keyword printf support
294887Schin  */
304887Schin 
314887Schin #include <ast.h>
324887Schin #include <ccode.h>
334887Schin #include <ctype.h>
344887Schin #include <sfdisc.h>
354887Schin #include <regex.h>
364887Schin 
374887Schin #define FMT_case	1
384887Schin #define FMT_edit	2
394887Schin 
404887Schin typedef struct
414887Schin {
424887Schin 	Sffmt_t			fmt;
434887Schin 	void*			handle;
444887Schin 	Sf_key_lookup_t		lookup;
454887Schin 	Sf_key_convert_t	convert;
464887Schin 	Sfio_t*			tmp[2];
474887Schin 	regex_t			red[2];
484887Schin 	regex_t*		re[2];
494887Schin 	int			invisible;
504887Schin 	int			level;
514887Schin 	int			version;
524887Schin } Fmt_t;
534887Schin 
544887Schin typedef struct
554887Schin {
564887Schin 	char*			next;
574887Schin 	int			delimiter;
584887Schin 	int			first;
594887Schin } Field_t;
604887Schin 
614887Schin typedef union
624887Schin {
634887Schin 	char**			p;
644887Schin 	char*			s;
654887Schin 	Sflong_t		q;
664887Schin 	long			l;
674887Schin 	int			i;
684887Schin 	short			h;
694887Schin 	char			c;
704887Schin } Value_t;
714887Schin 
724887Schin #define initfield(f,s)	((f)->first = (f)->delimiter = *((f)->next = (s)))
734887Schin 
744887Schin static char*
getfield(register Field_t * f,int restore)754887Schin getfield(register Field_t* f, int restore)
764887Schin {
774887Schin 	register char*	s;
784887Schin 	register int	n;
794887Schin 	register int	c;
804887Schin 	register int	lp;
814887Schin 	register int	rp;
824887Schin 	char*		b;
834887Schin 
844887Schin 	if (!f->delimiter)
854887Schin 		return 0;
864887Schin 	s = f->next;
874887Schin 	if (f->first)
884887Schin 		f->first = 0;
894887Schin 	else if (restore)
904887Schin 		*s = f->delimiter;
914887Schin 	b = ++s;
924887Schin 	lp = rp = n = 0;
934887Schin 	for (;;)
944887Schin 	{
954887Schin 		if (!(c = *s++))
964887Schin 		{
974887Schin 			f->delimiter = 0;
984887Schin 			break;
994887Schin 		}
1004887Schin 		else if (c == CC_esc || c == '\\')
1014887Schin 		{
1024887Schin 			if (*s)
1034887Schin 				s++;
1044887Schin 		}
1054887Schin 		else if (c == lp)
1064887Schin 			n++;
1074887Schin 		else if (c == rp)
1084887Schin 			n--;
1094887Schin 		else if (n <= 0)
1104887Schin 		{
1114887Schin 			if (c == '(' && restore)
1124887Schin 			{
1134887Schin 				lp = '(';
1144887Schin 				rp = ')';
1154887Schin 				n = 1;
1164887Schin 			}
1174887Schin 			else if (c == '[' && restore)
1184887Schin 			{
1194887Schin 				lp = '[';
1204887Schin 				rp = ']';
1214887Schin 				n = 1;
1224887Schin 			}
1234887Schin 			else if (c == f->delimiter)
1244887Schin 			{
1254887Schin 				*(f->next = --s) = 0;
1264887Schin 				break;
1274887Schin 			}
1284887Schin 		}
1294887Schin 	}
1304887Schin 	return b;
1314887Schin }
1324887Schin 
1334887Schin /*
1344887Schin  * sfio %! extension function
1354887Schin  */
1364887Schin 
1374887Schin static int
getfmt(Sfio_t * sp,void * vp,Sffmt_t * dp)1384887Schin getfmt(Sfio_t* sp, void* vp, Sffmt_t* dp)
1394887Schin {
1404887Schin 	register Fmt_t*	fp = (Fmt_t*)dp;
1414887Schin 	Value_t*	value = (Value_t*)vp;
1424887Schin 	register char*	v;
1434887Schin 	char*		t;
1444887Schin 	char*		b;
1454887Schin 	char*		a = 0;
1464887Schin 	char*		s = 0;
1474887Schin 	Sflong_t	n = 0;
1484887Schin 	int		h = 0;
1494887Schin 	int		i = 0;
1504887Schin 	int		x = 0;
1514887Schin 	int		d;
1524887Schin 	Field_t		f;
1534887Schin 	regmatch_t	match[10];
1544887Schin 
1554887Schin 	fp->level++;
1564887Schin 	if (fp->fmt.t_str && fp->fmt.n_str > 0 && (v = fmtbuf(fp->fmt.n_str + 1)))
1574887Schin 	{
1584887Schin 		memcpy(v, fp->fmt.t_str, fp->fmt.n_str);
1594887Schin 		v[fp->fmt.n_str] = 0;
1604887Schin 		b = v;
1614887Schin 		for (;;)
1624887Schin 		{
1634887Schin 			switch (*v++)
1644887Schin 			{
1654887Schin 			case 0:
1664887Schin 				break;
1674887Schin 			case '(':
1684887Schin 				h++;
1694887Schin 				continue;
1704887Schin 			case ')':
1714887Schin 				h--;
1724887Schin 				continue;
1734887Schin 			case '=':
1744887Schin 			case ':':
1754887Schin 			case ',':
1764887Schin 				if (h <= 0)
1774887Schin 				{
1784887Schin 					a = v;
1794887Schin 					break;
1804887Schin 				}
1814887Schin 				continue;
1824887Schin 			default:
1834887Schin 				continue;
1844887Schin 			}
1854887Schin 			if (i = *--v)
1864887Schin 			{
1874887Schin 				*v = 0;
1884887Schin 				if (i == ':' && fp->fmt.fmt == 's' && strlen(a) > 4 && !isalnum(*(a + 4)))
1894887Schin 				{
1904887Schin 					d = *(a + 4);
1914887Schin 					*(a + 4) = 0;
1924887Schin 					if (streq(a, "case"))
1934887Schin 						x = FMT_case;
1944887Schin 					else if (streq(a, "edit"))
1954887Schin 						x = FMT_edit;
1964887Schin 					*(a + 4) = d;
1974887Schin 					if (x)
1984887Schin 						a = 0;
1994887Schin 				}
2004887Schin 			}
2014887Schin 			break;
2024887Schin 		}
2034887Schin 		n = i;
2044887Schin 		t = fp->fmt.t_str;
2054887Schin 		fp->fmt.t_str = b;
2064887Schin 		h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
2074887Schin 		fp->fmt.t_str = t;
2084887Schin 		if (i)
2094887Schin 			*v++ = i;
2104887Schin 	}
2114887Schin 	else
2124887Schin 	{
2134887Schin 		h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
2144887Schin 		v = 0;
2154887Schin 	}
2164887Schin 	fp->fmt.flags |= SFFMT_VALUE;
2174887Schin 	switch (fp->fmt.fmt)
2184887Schin 	{
2194887Schin 	case 'c':
2204887Schin 		value->c = s ? *s : n;
2214887Schin 		break;
2224887Schin 	case 'd':
2234887Schin 	case 'i':
2244887Schin 		fp->fmt.size = sizeof(Sflong_t);
2254887Schin 		value->q = (Sflong_t)(s ? strtoll(s, NiL, 0) : n);
2264887Schin 		break;
2274887Schin 	case 'o':
2284887Schin 	case 'u':
2294887Schin 	case 'x':
2304887Schin 		fp->fmt.size = sizeof(Sflong_t);
2314887Schin 		value->q = s ? (Sflong_t)strtoull(s, NiL, 0) : n;
2324887Schin 		break;
2334887Schin 	case 'p':
2344887Schin 		if (s)
2354887Schin 			n = strtoll(s, NiL, 0);
2364887Schin 		value->p = pointerof(n);
2374887Schin 		break;
2384887Schin 	case 'q':
2394887Schin 		if (s)
2404887Schin 		{
2414887Schin 			fp->fmt.fmt = 's';
2424887Schin 			value->s = fmtquote(s, "$'", "'", strlen(s), 0);
2434887Schin 		}
2444887Schin 		else
2454887Schin 		{
2464887Schin 			fp->fmt.fmt = 'd';
2474887Schin 			value->q = n;
2484887Schin 		}
2494887Schin 		break;
2504887Schin 	case 's':
2514887Schin 		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]))))
2524887Schin 			s = "";
2534887Schin 		if (x)
2544887Schin 		{
2554887Schin 			h = 0;
2564887Schin 			d = initfield(&f, v + 4);
2574887Schin 			switch (x)
2584887Schin 			{
2594887Schin 			case FMT_case:
2604887Schin 				while ((a = getfield(&f, 1)) && (v = getfield(&f, 0)))
2614887Schin 				{
2624887Schin 					if (strmatch(s, a))
2634887Schin 					{
2644887Schin 						Fmt_t	fmt;
2654887Schin 
2664887Schin 						fmt = *fp;
2674887Schin 						fmt.fmt.form = v;
2684887Schin 						for (h = 0; h < elementsof(fmt.tmp); h++)
2694887Schin 							fmt.tmp[h] = 0;
2704887Schin 						if (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%!", &fmt) <= 0 || !(s = sfstruse(fp->tmp[0])))
2714887Schin 							s = "";
2724887Schin 						*(v - 1) = d;
2734887Schin 						if (f.delimiter)
2744887Schin 							*f.next = d;
2754887Schin 						for (h = 0; h < elementsof(fmt.tmp); h++)
2764887Schin 							if (fmt.tmp[h])
2774887Schin 								sfclose(fmt.tmp[h]);
2784887Schin 						h = 1;
2794887Schin 						break;
2804887Schin 					}
2814887Schin 					*(v - 1) = d;
2824887Schin 				}
2834887Schin 				break;
2844887Schin 			case FMT_edit:
2854887Schin 				for (x = 0; *f.next; x ^= 1)
2864887Schin 				{
2874887Schin 					if (fp->re[x])
2884887Schin 						regfree(fp->re[x]);
2894887Schin 					else
2904887Schin 						fp->re[x] = &fp->red[x];
2914887Schin 					if (regcomp(fp->re[x], f.next, REG_DELIMITED|REG_NULL))
2924887Schin 						break;
2934887Schin 					f.next += fp->re[x]->re_npat;
2944887Schin 					if (regsubcomp(fp->re[x], f.next, NiL, 0, 0))
2954887Schin 						break;
2964887Schin 					f.next += fp->re[x]->re_npat;
2974887Schin 					if (!regexec(fp->re[x], s, elementsof(match), match, 0) && !regsubexec(fp->re[x], s, elementsof(match), match))
2984887Schin 					{
2994887Schin 						s = fp->re[x]->re_sub->re_buf;
3004887Schin 						if (fp->re[x]->re_sub->re_flags & REG_SUB_STOP)
3014887Schin 							break;
3024887Schin 					}
3034887Schin 				}
3044887Schin 				h = 1;
3054887Schin 				break;
3064887Schin 			}
3074887Schin 			if (!h)
3084887Schin 				s = "";
3094887Schin 		}
3104887Schin 		value->s = s;
3114887Schin 		if (fp->level == 1)
3124887Schin 			while ((s = strchr(s, CC_esc)) && *(s + 1) == '[')
3134887Schin 				do fp->invisible++; while (*s && !islower(*s++));
3144887Schin 		break;
3154887Schin 	case 'Z':
3164887Schin 		fp->fmt.fmt = 'c';
3174887Schin 		value->c = 0;
3184887Schin 		break;
3194887Schin 	case '\n':
3204887Schin 		value->s = "\n";
3214887Schin 		break;
3224887Schin 	case '.':
3234887Schin 		value->i = n;
3244887Schin 		break;
3254887Schin 	default:
3264887Schin 		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]))))
3274887Schin 			value->s = "";
3284887Schin 		break;
3294887Schin 	}
3304887Schin 	fp->level--;
3314887Schin 	return 0;
3324887Schin }
3334887Schin 
3344887Schin /*
3354887Schin  * this is the 20000308 interface with Sffmt_t* callback args
3364887Schin  */
3374887Schin 
3384887Schin int
sfkeyprintf(Sfio_t * sp,void * handle,const char * format,Sf_key_lookup_t lookup,Sf_key_convert_t convert)3394887Schin sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
3404887Schin {
3414887Schin 	register int	i;
3424887Schin 	int		r;
3434887Schin 	Fmt_t		fmt;
3444887Schin 
3454887Schin 	memset(&fmt, 0, sizeof(fmt));
3464887Schin 	fmt.version = 20030909;
3474887Schin 	fmt.fmt.version = SFIO_VERSION;
3484887Schin 	fmt.fmt.form = (char*)format;
3494887Schin 	fmt.fmt.extf = getfmt;
3504887Schin 	fmt.handle = handle;
3514887Schin 	fmt.lookup = lookup;
3524887Schin 	fmt.convert = convert;
3534887Schin 	r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
3544887Schin 	for (i = 0; i < elementsof(fmt.tmp); i++)
3554887Schin 		if (fmt.tmp[i])
3564887Schin 			sfclose(fmt.tmp[i]);
3574887Schin 	return r;
3584887Schin }
3594887Schin 
3604887Schin /*
3614887Schin  * this is the original interface
3624887Schin  */
3634887Schin 
3644887Schin #undef	sfkeyprintf
3654887Schin 
3664887Schin int
sfkeyprintf(Sfio_t * sp,void * handle,const char * format,Sf_key_lookup_t lookup,Sf_key_convert_t convert)3674887Schin sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
3684887Schin {
3694887Schin 	register int	i;
3704887Schin 	int		r;
3714887Schin 	Fmt_t		fmt;
3724887Schin 
3734887Schin 	memset(&fmt, 0, sizeof(fmt));
3744887Schin 	fmt.fmt.version = SFIO_VERSION;
3754887Schin 	fmt.fmt.form = (char*)format;
3764887Schin 	fmt.fmt.extf = getfmt;
3774887Schin 	fmt.handle = handle;
3784887Schin 	fmt.lookup = lookup;
3794887Schin 	fmt.convert = convert;
3804887Schin 	r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
3814887Schin 	for (i = 0; i < elementsof(fmt.tmp); i++)
3824887Schin 		if (fmt.tmp[i])
3834887Schin 			sfclose(fmt.tmp[i]);
3844887Schin 	for (i = 0; i < elementsof(fmt.re); i++)
3854887Schin 		if (fmt.re[i])
3864887Schin 			regfree(fmt.re[i]);
3874887Schin 	return r;
3884887Schin }
389