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