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