1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 1986-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril Chin * by AT&T Intellectual Property * 8da2e3ebdSchin * * 9da2e3ebdSchin * A copy of the License is available at * 10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12da2e3ebdSchin * * 13da2e3ebdSchin * Information and Software Systems Research * 14da2e3ebdSchin * AT&T Research * 15da2e3ebdSchin * Florham Park NJ * 16da2e3ebdSchin * * 17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18da2e3ebdSchin * * 19da2e3ebdSchin ***********************************************************************/ 20da2e3ebdSchin #pragma prototyped 21da2e3ebdSchin /* 22da2e3ebdSchin * Glenn Fowler 23da2e3ebdSchin * AT&T Research 24da2e3ebdSchin * 25da2e3ebdSchin * preprocessor builtin macro support 26da2e3ebdSchin */ 27da2e3ebdSchin 28da2e3ebdSchin #include "pplib.h" 29da2e3ebdSchin 30da2e3ebdSchin #include <times.h> 31da2e3ebdSchin 32da2e3ebdSchin /* 33da2e3ebdSchin * process a #(...) builtin macro call 34da2e3ebdSchin * `#(' has already been seen 35da2e3ebdSchin */ 36da2e3ebdSchin 37da2e3ebdSchin void 38da2e3ebdSchin ppbuiltin(void) 39da2e3ebdSchin { 40da2e3ebdSchin register int c; 41da2e3ebdSchin register char* p; 42da2e3ebdSchin register char* a; 43da2e3ebdSchin 44da2e3ebdSchin int n; 45da2e3ebdSchin int op; 46da2e3ebdSchin char* token; 47da2e3ebdSchin char* t; 48da2e3ebdSchin long number; 49*7c2fbfb3SApril Chin long onumber; 50da2e3ebdSchin struct ppinstk* in; 51da2e3ebdSchin struct pplist* list; 52da2e3ebdSchin struct ppsymbol* sym; 53da2e3ebdSchin Sfio_t* sp; 54da2e3ebdSchin 55da2e3ebdSchin number = pp.state; 56da2e3ebdSchin pp.state |= DISABLE|FILEPOP|NOSPACE; 57da2e3ebdSchin token = pp.token; 58da2e3ebdSchin p = pp.token = pp.tmpbuf; 59da2e3ebdSchin *(a = pp.args) = 0; 60da2e3ebdSchin if ((c = pplex()) != T_ID) 61da2e3ebdSchin { 62da2e3ebdSchin error(2, "%s: #(<identifier>...) expected", p); 63da2e3ebdSchin *p = 0; 64da2e3ebdSchin } 65da2e3ebdSchin switch (op = (int)hashget(pp.strtab, p)) 66da2e3ebdSchin { 67da2e3ebdSchin case V_DEFAULT: 68da2e3ebdSchin n = 0; 69da2e3ebdSchin p = pp.token = pp.valbuf; 70da2e3ebdSchin if ((c = pplex()) == ',') 71da2e3ebdSchin { 72da2e3ebdSchin op = -1; 73da2e3ebdSchin c = pplex(); 74da2e3ebdSchin } 75da2e3ebdSchin pp.state &= ~NOSPACE; 76da2e3ebdSchin for (;;) 77da2e3ebdSchin { 78da2e3ebdSchin if (!c) 79da2e3ebdSchin { 80da2e3ebdSchin error(2, "%s in #(...) argument", pptokchr(c)); 81da2e3ebdSchin break; 82da2e3ebdSchin } 83da2e3ebdSchin if (c == '(') n++; 84da2e3ebdSchin else if (c == ')' && !n--) break; 85da2e3ebdSchin else if (c == ',' && !n && op > 0) op = 0; 86da2e3ebdSchin if (op) pp.token = pp.toknxt; 87da2e3ebdSchin c = pplex(); 88da2e3ebdSchin } 89da2e3ebdSchin *pp.token = 0; 90da2e3ebdSchin pp.token = token; 91da2e3ebdSchin pp.state = number; 92da2e3ebdSchin break; 93da2e3ebdSchin case V_EMPTY: 94da2e3ebdSchin p = pp.valbuf; 95da2e3ebdSchin if ((c = pplex()) == ')') *p = '1'; 96da2e3ebdSchin else 97da2e3ebdSchin { 98da2e3ebdSchin *p = '0'; 99da2e3ebdSchin n = 0; 100da2e3ebdSchin for (;;) 101da2e3ebdSchin { 102da2e3ebdSchin if (!c) 103da2e3ebdSchin { 104da2e3ebdSchin error(2, "%s in #(...) argument", pptokchr(c)); 105da2e3ebdSchin break; 106da2e3ebdSchin } 107da2e3ebdSchin if (c == '(') n++; 108da2e3ebdSchin else if (c == ')' && !n--) break; 109da2e3ebdSchin c = pplex(); 110da2e3ebdSchin } 111da2e3ebdSchin } 112da2e3ebdSchin *(p + 1) = 0; 113da2e3ebdSchin pp.token = token; 114da2e3ebdSchin pp.state = number; 115da2e3ebdSchin break; 116da2e3ebdSchin case V_ITERATE: 117da2e3ebdSchin n = 0; 118da2e3ebdSchin pp.token = pp.valbuf; 119da2e3ebdSchin if ((c = pplex()) != T_ID || !(sym = ppsymref(pp.symtab, pp.token)) || !sym->macro || sym->macro->arity != 1 || (c = pplex()) != ',') 120da2e3ebdSchin { 121da2e3ebdSchin error(2, "#(%s <macro(x)>, ...) expected", p); 122da2e3ebdSchin for (;;) 123da2e3ebdSchin { 124da2e3ebdSchin if (!c) 125da2e3ebdSchin { 126da2e3ebdSchin error(2, "%s in #(...) argument", pptokchr(c)); 127da2e3ebdSchin break; 128da2e3ebdSchin } 129da2e3ebdSchin if (c == '(') n++; 130da2e3ebdSchin else if (c == ')' && !n--) break; 131da2e3ebdSchin c = pplex(); 132da2e3ebdSchin } 133da2e3ebdSchin *pp.valbuf = 0; 134da2e3ebdSchin } 135da2e3ebdSchin else while (c != ')') 136da2e3ebdSchin { 137da2e3ebdSchin p = pp.token; 138da2e3ebdSchin if (pp.token > pp.valbuf) *pp.token++ = ' '; 139da2e3ebdSchin STRCOPY(pp.token, sym->name, a); 140da2e3ebdSchin *pp.token++ = '('; 141da2e3ebdSchin if (!c || !(c = pplex())) 142da2e3ebdSchin { 143da2e3ebdSchin pp.token = p; 144da2e3ebdSchin error(2, "%s in #(...) argument", pptokchr(c)); 145da2e3ebdSchin break; 146da2e3ebdSchin } 147da2e3ebdSchin pp.state &= ~NOSPACE; 148da2e3ebdSchin while (c) 149da2e3ebdSchin { 150da2e3ebdSchin if (c == '(') n++; 151da2e3ebdSchin else if (c == ')' && !n--) break; 152da2e3ebdSchin else if (c == ',' && !n) break; 153da2e3ebdSchin pp.token = pp.toknxt; 154da2e3ebdSchin c = pplex(); 155da2e3ebdSchin } 156da2e3ebdSchin *pp.token++ = ')'; 157da2e3ebdSchin pp.state |= NOSPACE; 158da2e3ebdSchin } 159da2e3ebdSchin p = pp.valbuf; 160da2e3ebdSchin pp.token = token; 161da2e3ebdSchin pp.state = number; 162da2e3ebdSchin break; 163da2e3ebdSchin default: 164da2e3ebdSchin pp.token = token; 165da2e3ebdSchin while (c != ')') 166da2e3ebdSchin { 167da2e3ebdSchin if (!c) 168da2e3ebdSchin { 169da2e3ebdSchin error(2, "%s in #(...) argument", pptokchr(c)); 170da2e3ebdSchin break; 171da2e3ebdSchin } 172da2e3ebdSchin if ((c = pplex()) == T_ID && !*a) 173da2e3ebdSchin strcpy(a, pp.token); 174da2e3ebdSchin } 175da2e3ebdSchin pp.state = number; 176da2e3ebdSchin switch (op) 177da2e3ebdSchin { 178da2e3ebdSchin case V_ARGC: 179da2e3ebdSchin c = -1; 180da2e3ebdSchin for (in = pp.in; in; in = in->prev) 181da2e3ebdSchin if ((in->type == IN_MACRO || in->type == IN_MULTILINE) && (in->symbol->flags & SYM_FUNCTION)) 182da2e3ebdSchin { 183da2e3ebdSchin c = *((unsigned char*)(pp.macp->arg[0] - 2)); 184da2e3ebdSchin break; 185da2e3ebdSchin } 186da2e3ebdSchin sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", c); 187da2e3ebdSchin break; 188da2e3ebdSchin case V_BASE: 189da2e3ebdSchin p = (a = strrchr(error_info.file, '/')) ? a + 1 : error_info.file; 190da2e3ebdSchin break; 191da2e3ebdSchin case V_DATE: 192da2e3ebdSchin if (!(p = pp.date)) 193da2e3ebdSchin { 194da2e3ebdSchin time_t tm; 195da2e3ebdSchin 196da2e3ebdSchin time(&tm); 197da2e3ebdSchin a = p = ctime(&tm) + 4; 198da2e3ebdSchin *(p + 20) = 0; 199da2e3ebdSchin for (p += 7; *p = *(p + 9); p++); 200da2e3ebdSchin pp.date = p = strdup(a); 201da2e3ebdSchin } 202da2e3ebdSchin break; 203da2e3ebdSchin case V_FILE: 204da2e3ebdSchin p = error_info.file; 205da2e3ebdSchin break; 206da2e3ebdSchin case V_LINE: 207da2e3ebdSchin sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", error_info.line); 208da2e3ebdSchin break; 209da2e3ebdSchin case V_PATH: 210da2e3ebdSchin p = pp.path; 211da2e3ebdSchin break; 212da2e3ebdSchin case V_SOURCE: 213da2e3ebdSchin p = error_info.file; 214da2e3ebdSchin for (in = pp.in; in->prev; in = in->prev) 215da2e3ebdSchin if (in->prev->type == IN_FILE && in->file) 216da2e3ebdSchin p = in->file; 217da2e3ebdSchin break; 218da2e3ebdSchin case V_STDC: 219da2e3ebdSchin p = pp.valbuf; 220da2e3ebdSchin p[0] = ((pp.state & (COMPATIBILITY|TRANSITION)) || (pp.mode & (HOSTED|HOSTEDTRANSITION)) == (HOSTED|HOSTEDTRANSITION)) ? '0' : '1'; 221da2e3ebdSchin p[1] = 0; 222da2e3ebdSchin break; 223da2e3ebdSchin case V_TIME: 224da2e3ebdSchin if (!(p = pp.time)) 225da2e3ebdSchin { 226da2e3ebdSchin time_t tm; 227da2e3ebdSchin 228da2e3ebdSchin time(&tm); 229da2e3ebdSchin p = ctime(&tm) + 11; 230da2e3ebdSchin *(p + 8) = 0; 231da2e3ebdSchin pp.time = p = strdup(p); 232da2e3ebdSchin } 233da2e3ebdSchin break; 234da2e3ebdSchin case V_VERSION: 235da2e3ebdSchin p = (char*)pp.version; 236da2e3ebdSchin break; 237da2e3ebdSchin case V_DIRECTIVE: 238da2e3ebdSchin pp.state |= NEWLINE; 239da2e3ebdSchin pp.mode |= RELAX; 240da2e3ebdSchin strcpy(p = pp.valbuf, "#"); 241da2e3ebdSchin break; 242da2e3ebdSchin case V_GETENV: 243da2e3ebdSchin if (!(p = getenv(a))) p = ""; 244da2e3ebdSchin break; 245da2e3ebdSchin case V_GETMAC: 246da2e3ebdSchin p = (sym = pprefmac(a, REF_NORMAL)) ? sym->macro->value : ""; 247da2e3ebdSchin break; 248da2e3ebdSchin case V_GETOPT: 249da2e3ebdSchin sfsprintf(p = pp.valbuf, MAXTOKEN, "%ld", ppoption(a)); 250da2e3ebdSchin break; 251da2e3ebdSchin case V_GETPRD: 252da2e3ebdSchin p = (list = (struct pplist*)hashget(pp.prdtab, a)) ? list->value : ""; 253da2e3ebdSchin break; 254da2e3ebdSchin case V__PRAGMA: 255da2e3ebdSchin if ((c = pplex()) == '(') 256da2e3ebdSchin { 257da2e3ebdSchin number = pp.state; 258da2e3ebdSchin pp.state |= NOSPACE|STRIP; 259da2e3ebdSchin c = pplex(); 260da2e3ebdSchin pp.state = number; 261da2e3ebdSchin if (c == T_STRING || c == T_WSTRING) 262da2e3ebdSchin { 263da2e3ebdSchin if (!(sp = sfstropen())) 264da2e3ebdSchin error(3, "temporary buffer allocation error"); 265da2e3ebdSchin sfprintf(sp, "#%s %s\n", dirname(PRAGMA), pp.token); 266da2e3ebdSchin a = sfstruse(sp); 267da2e3ebdSchin if ((c = pplex()) == ')') 268da2e3ebdSchin { 269da2e3ebdSchin pp.state |= NEWLINE; 270da2e3ebdSchin PUSH_BUFFER(p, a, 1); 271da2e3ebdSchin } 272da2e3ebdSchin sfstrclose(sp); 273da2e3ebdSchin } 274da2e3ebdSchin } 275da2e3ebdSchin if (c != ')') 276da2e3ebdSchin error(2, "%s: (\"...\") expected", p); 277da2e3ebdSchin return; 278da2e3ebdSchin case V_FUNCTION: 279da2e3ebdSchin 280da2e3ebdSchin #define BACK(a,p) ((a>p)?*--a:(number++?0:((p=pp.outbuf+PPBUFSIZ),(a=pp.outbuf+2*PPBUFSIZ),*--a))) 281da2e3ebdSchin #define PEEK(a,p) ((a>p)?*(a-1):(number?0:*(pp.outbuf+2*PPBUFSIZ-1))) 282da2e3ebdSchin 283*7c2fbfb3SApril Chin number = pp.outbuf != pp.outb; 284da2e3ebdSchin a = pp.outp; 285da2e3ebdSchin p = pp.outb; 286da2e3ebdSchin op = 0; 287da2e3ebdSchin while (c = BACK(a, p)) 288da2e3ebdSchin { 289da2e3ebdSchin if (c == '"' || c == '\'') 290da2e3ebdSchin { 291da2e3ebdSchin op = 0; 292da2e3ebdSchin while ((n = BACK(a, p)) && n != c || PEEK(a, p) == '\\'); 293da2e3ebdSchin } 294da2e3ebdSchin else if (c == '\n') 295da2e3ebdSchin { 296da2e3ebdSchin token = a; 297da2e3ebdSchin while (c = BACK(a, p)) 298da2e3ebdSchin if (c == '\n') 299da2e3ebdSchin { 300da2e3ebdSchin a = token; 301da2e3ebdSchin break; 302da2e3ebdSchin } 303da2e3ebdSchin else if (c == '#' && PEEK(a, p) == '\n') 304da2e3ebdSchin break; 305da2e3ebdSchin } 306da2e3ebdSchin else if (c == ' ') 307da2e3ebdSchin /*ignore*/; 308da2e3ebdSchin else if (c == '{') /* '}' */ 309da2e3ebdSchin op = 1; 310da2e3ebdSchin else if (op == 1) 311da2e3ebdSchin { 312da2e3ebdSchin if (c == ')') 313da2e3ebdSchin { 314da2e3ebdSchin op = 2; 315da2e3ebdSchin n = 1; 316da2e3ebdSchin } 317da2e3ebdSchin else 318da2e3ebdSchin op = 0; 319da2e3ebdSchin } 320da2e3ebdSchin else if (op == 2) 321da2e3ebdSchin { 322da2e3ebdSchin if (c == ')') 323da2e3ebdSchin n++; 324da2e3ebdSchin else if (c == '(' && !--n) 325da2e3ebdSchin op = 3; 326da2e3ebdSchin } 327da2e3ebdSchin else if (op == 3) 328da2e3ebdSchin { 329da2e3ebdSchin if (ppisidig(c)) 330da2e3ebdSchin { 331*7c2fbfb3SApril Chin for (t = p, token = a, onumber = number; ppisidig(PEEK(a, p)) && a >= p; BACK(a, p)); 332*7c2fbfb3SApril Chin p = pp.valbuf + 1; 333*7c2fbfb3SApril Chin if (a > token) 334*7c2fbfb3SApril Chin { 335*7c2fbfb3SApril Chin for (; a < pp.outbuf+2*PPBUFSIZ; *p++ = *a++); 336*7c2fbfb3SApril Chin a = pp.outbuf; 337*7c2fbfb3SApril Chin } 338*7c2fbfb3SApril Chin for (; a <= token; *p++ = *a++); 339da2e3ebdSchin *p = 0; 340da2e3ebdSchin p = pp.valbuf + 1; 341da2e3ebdSchin if (streq(p, "for") || streq(p, "if") || streq(p, "switch") || streq(p, "while")) 342da2e3ebdSchin { 343da2e3ebdSchin op = 0; 344da2e3ebdSchin p = t; 345*7c2fbfb3SApril Chin number = onumber; 346da2e3ebdSchin continue; 347da2e3ebdSchin } 348da2e3ebdSchin } 349da2e3ebdSchin else 350da2e3ebdSchin op = 0; 351da2e3ebdSchin break; 352da2e3ebdSchin } 353da2e3ebdSchin } 354da2e3ebdSchin if (op == 3) 355*7c2fbfb3SApril Chin p = strncpy(pp.funbuf, p, sizeof(pp.funbuf) - 1); 356da2e3ebdSchin else if (*pp.funbuf) 357da2e3ebdSchin p = pp.funbuf; 358da2e3ebdSchin else 359da2e3ebdSchin p = "__FUNCTION__"; 360da2e3ebdSchin break; 361da2e3ebdSchin default: 362da2e3ebdSchin if (pp.builtin && (a = (*pp.builtin)(pp.valbuf, p, a))) 363da2e3ebdSchin p = a; 364da2e3ebdSchin break; 365da2e3ebdSchin } 366da2e3ebdSchin break; 367da2e3ebdSchin } 368da2e3ebdSchin if (strchr(p, MARK)) 369da2e3ebdSchin { 370da2e3ebdSchin a = pp.tmpbuf; 371da2e3ebdSchin strcpy(a, p); 372da2e3ebdSchin c = p != pp.valbuf; 373da2e3ebdSchin p = pp.valbuf + c; 374da2e3ebdSchin for (;;) 375da2e3ebdSchin { 376da2e3ebdSchin if (p < pp.valbuf + MAXTOKEN - 2) 377da2e3ebdSchin switch (*p++ = *a++) 378da2e3ebdSchin { 379da2e3ebdSchin case 0: 380da2e3ebdSchin break; 381da2e3ebdSchin case MARK: 382da2e3ebdSchin *p++ = MARK; 383da2e3ebdSchin /*FALLTHROUGH*/ 384da2e3ebdSchin default: 385da2e3ebdSchin continue; 386da2e3ebdSchin } 387da2e3ebdSchin break; 388da2e3ebdSchin } 389da2e3ebdSchin p = pp.valbuf + c; 390da2e3ebdSchin } 391da2e3ebdSchin if (p == pp.valbuf) 392da2e3ebdSchin PUSH_STRING(p); 393da2e3ebdSchin else 394da2e3ebdSchin { 395da2e3ebdSchin if (p == pp.valbuf + 1) 396da2e3ebdSchin *pp.valbuf = '"'; 397da2e3ebdSchin else 398da2e3ebdSchin { 399da2e3ebdSchin if (strlen(p) > MAXTOKEN - 2) 400da2e3ebdSchin error(1, "%-.16s: builtin value truncated", p); 401da2e3ebdSchin sfsprintf(pp.valbuf, MAXTOKEN, "\"%-.*s", MAXTOKEN - 2, p); 402da2e3ebdSchin } 403da2e3ebdSchin PUSH_QUOTE(pp.valbuf, 1); 404da2e3ebdSchin } 405da2e3ebdSchin } 406