14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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* 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 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 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 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