14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1986-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 * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * Glenn Fowler 234887Schin * AT&T Research 244887Schin * 254887Schin * preprocessor builtin macro support 264887Schin */ 274887Schin 284887Schin #include "pplib.h" 294887Schin 304887Schin #include <times.h> 314887Schin 324887Schin /* 334887Schin * process a #(...) builtin macro call 344887Schin * `#(' has already been seen 354887Schin */ 364887Schin 374887Schin void 384887Schin ppbuiltin(void) 394887Schin { 404887Schin register int c; 414887Schin register char* p; 424887Schin register char* a; 434887Schin 444887Schin int n; 454887Schin int op; 464887Schin char* token; 474887Schin char* t; 484887Schin long number; 49*8462SApril.Chin@Sun.COM long onumber; 504887Schin struct ppinstk* in; 514887Schin struct pplist* list; 524887Schin struct ppsymbol* sym; 534887Schin Sfio_t* sp; 544887Schin 554887Schin number = pp.state; 564887Schin pp.state |= DISABLE|FILEPOP|NOSPACE; 574887Schin token = pp.token; 584887Schin p = pp.token = pp.tmpbuf; 594887Schin *(a = pp.args) = 0; 604887Schin if ((c = pplex()) != T_ID) 614887Schin { 624887Schin error(2, "%s: #(<identifier>...) expected", p); 634887Schin *p = 0; 644887Schin } 654887Schin switch (op = (int)hashget(pp.strtab, p)) 664887Schin { 674887Schin case V_DEFAULT: 684887Schin n = 0; 694887Schin p = pp.token = pp.valbuf; 704887Schin if ((c = pplex()) == ',') 714887Schin { 724887Schin op = -1; 734887Schin c = pplex(); 744887Schin } 754887Schin pp.state &= ~NOSPACE; 764887Schin for (;;) 774887Schin { 784887Schin if (!c) 794887Schin { 804887Schin error(2, "%s in #(...) argument", pptokchr(c)); 814887Schin break; 824887Schin } 834887Schin if (c == '(') n++; 844887Schin else if (c == ')' && !n--) break; 854887Schin else if (c == ',' && !n && op > 0) op = 0; 864887Schin if (op) pp.token = pp.toknxt; 874887Schin c = pplex(); 884887Schin } 894887Schin *pp.token = 0; 904887Schin pp.token = token; 914887Schin pp.state = number; 924887Schin break; 934887Schin case V_EMPTY: 944887Schin p = pp.valbuf; 954887Schin if ((c = pplex()) == ')') *p = '1'; 964887Schin else 974887Schin { 984887Schin *p = '0'; 994887Schin n = 0; 1004887Schin for (;;) 1014887Schin { 1024887Schin if (!c) 1034887Schin { 1044887Schin error(2, "%s in #(...) argument", pptokchr(c)); 1054887Schin break; 1064887Schin } 1074887Schin if (c == '(') n++; 1084887Schin else if (c == ')' && !n--) break; 1094887Schin c = pplex(); 1104887Schin } 1114887Schin } 1124887Schin *(p + 1) = 0; 1134887Schin pp.token = token; 1144887Schin pp.state = number; 1154887Schin break; 1164887Schin case V_ITERATE: 1174887Schin n = 0; 1184887Schin pp.token = pp.valbuf; 1194887Schin if ((c = pplex()) != T_ID || !(sym = ppsymref(pp.symtab, pp.token)) || !sym->macro || sym->macro->arity != 1 || (c = pplex()) != ',') 1204887Schin { 1214887Schin error(2, "#(%s <macro(x)>, ...) expected", p); 1224887Schin for (;;) 1234887Schin { 1244887Schin if (!c) 1254887Schin { 1264887Schin error(2, "%s in #(...) argument", pptokchr(c)); 1274887Schin break; 1284887Schin } 1294887Schin if (c == '(') n++; 1304887Schin else if (c == ')' && !n--) break; 1314887Schin c = pplex(); 1324887Schin } 1334887Schin *pp.valbuf = 0; 1344887Schin } 1354887Schin else while (c != ')') 1364887Schin { 1374887Schin p = pp.token; 1384887Schin if (pp.token > pp.valbuf) *pp.token++ = ' '; 1394887Schin STRCOPY(pp.token, sym->name, a); 1404887Schin *pp.token++ = '('; 1414887Schin if (!c || !(c = pplex())) 1424887Schin { 1434887Schin pp.token = p; 1444887Schin error(2, "%s in #(...) argument", pptokchr(c)); 1454887Schin break; 1464887Schin } 1474887Schin pp.state &= ~NOSPACE; 1484887Schin while (c) 1494887Schin { 1504887Schin if (c == '(') n++; 1514887Schin else if (c == ')' && !n--) break; 1524887Schin else if (c == ',' && !n) break; 1534887Schin pp.token = pp.toknxt; 1544887Schin c = pplex(); 1554887Schin } 1564887Schin *pp.token++ = ')'; 1574887Schin pp.state |= NOSPACE; 1584887Schin } 1594887Schin p = pp.valbuf; 1604887Schin pp.token = token; 1614887Schin pp.state = number; 1624887Schin break; 1634887Schin default: 1644887Schin pp.token = token; 1654887Schin while (c != ')') 1664887Schin { 1674887Schin if (!c) 1684887Schin { 1694887Schin error(2, "%s in #(...) argument", pptokchr(c)); 1704887Schin break; 1714887Schin } 1724887Schin if ((c = pplex()) == T_ID && !*a) 1734887Schin strcpy(a, pp.token); 1744887Schin } 1754887Schin pp.state = number; 1764887Schin switch (op) 1774887Schin { 1784887Schin case V_ARGC: 1794887Schin c = -1; 1804887Schin for (in = pp.in; in; in = in->prev) 1814887Schin if ((in->type == IN_MACRO || in->type == IN_MULTILINE) && (in->symbol->flags & SYM_FUNCTION)) 1824887Schin { 1834887Schin c = *((unsigned char*)(pp.macp->arg[0] - 2)); 1844887Schin break; 1854887Schin } 1864887Schin sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", c); 1874887Schin break; 1884887Schin case V_BASE: 1894887Schin p = (a = strrchr(error_info.file, '/')) ? a + 1 : error_info.file; 1904887Schin break; 1914887Schin case V_DATE: 1924887Schin if (!(p = pp.date)) 1934887Schin { 1944887Schin time_t tm; 1954887Schin 1964887Schin time(&tm); 1974887Schin a = p = ctime(&tm) + 4; 1984887Schin *(p + 20) = 0; 1994887Schin for (p += 7; *p = *(p + 9); p++); 2004887Schin pp.date = p = strdup(a); 2014887Schin } 2024887Schin break; 2034887Schin case V_FILE: 2044887Schin p = error_info.file; 2054887Schin break; 2064887Schin case V_LINE: 2074887Schin sfsprintf(p = pp.valbuf, MAXTOKEN, "%d", error_info.line); 2084887Schin break; 2094887Schin case V_PATH: 2104887Schin p = pp.path; 2114887Schin break; 2124887Schin case V_SOURCE: 2134887Schin p = error_info.file; 2144887Schin for (in = pp.in; in->prev; in = in->prev) 2154887Schin if (in->prev->type == IN_FILE && in->file) 2164887Schin p = in->file; 2174887Schin break; 2184887Schin case V_STDC: 2194887Schin p = pp.valbuf; 2204887Schin p[0] = ((pp.state & (COMPATIBILITY|TRANSITION)) || (pp.mode & (HOSTED|HOSTEDTRANSITION)) == (HOSTED|HOSTEDTRANSITION)) ? '0' : '1'; 2214887Schin p[1] = 0; 2224887Schin break; 2234887Schin case V_TIME: 2244887Schin if (!(p = pp.time)) 2254887Schin { 2264887Schin time_t tm; 2274887Schin 2284887Schin time(&tm); 2294887Schin p = ctime(&tm) + 11; 2304887Schin *(p + 8) = 0; 2314887Schin pp.time = p = strdup(p); 2324887Schin } 2334887Schin break; 2344887Schin case V_VERSION: 2354887Schin p = (char*)pp.version; 2364887Schin break; 2374887Schin case V_DIRECTIVE: 2384887Schin pp.state |= NEWLINE; 2394887Schin pp.mode |= RELAX; 2404887Schin strcpy(p = pp.valbuf, "#"); 2414887Schin break; 2424887Schin case V_GETENV: 2434887Schin if (!(p = getenv(a))) p = ""; 2444887Schin break; 2454887Schin case V_GETMAC: 2464887Schin p = (sym = pprefmac(a, REF_NORMAL)) ? sym->macro->value : ""; 2474887Schin break; 2484887Schin case V_GETOPT: 2494887Schin sfsprintf(p = pp.valbuf, MAXTOKEN, "%ld", ppoption(a)); 2504887Schin break; 2514887Schin case V_GETPRD: 2524887Schin p = (list = (struct pplist*)hashget(pp.prdtab, a)) ? list->value : ""; 2534887Schin break; 2544887Schin case V__PRAGMA: 2554887Schin if ((c = pplex()) == '(') 2564887Schin { 2574887Schin number = pp.state; 2584887Schin pp.state |= NOSPACE|STRIP; 2594887Schin c = pplex(); 2604887Schin pp.state = number; 2614887Schin if (c == T_STRING || c == T_WSTRING) 2624887Schin { 2634887Schin if (!(sp = sfstropen())) 2644887Schin error(3, "temporary buffer allocation error"); 2654887Schin sfprintf(sp, "#%s %s\n", dirname(PRAGMA), pp.token); 2664887Schin a = sfstruse(sp); 2674887Schin if ((c = pplex()) == ')') 2684887Schin { 2694887Schin pp.state |= NEWLINE; 2704887Schin PUSH_BUFFER(p, a, 1); 2714887Schin } 2724887Schin sfstrclose(sp); 2734887Schin } 2744887Schin } 2754887Schin if (c != ')') 2764887Schin error(2, "%s: (\"...\") expected", p); 2774887Schin return; 2784887Schin case V_FUNCTION: 2794887Schin 2804887Schin #define BACK(a,p) ((a>p)?*--a:(number++?0:((p=pp.outbuf+PPBUFSIZ),(a=pp.outbuf+2*PPBUFSIZ),*--a))) 2814887Schin #define PEEK(a,p) ((a>p)?*(a-1):(number?0:*(pp.outbuf+2*PPBUFSIZ-1))) 2824887Schin 283*8462SApril.Chin@Sun.COM number = pp.outbuf != pp.outb; 2844887Schin a = pp.outp; 2854887Schin p = pp.outb; 2864887Schin op = 0; 2874887Schin while (c = BACK(a, p)) 2884887Schin { 2894887Schin if (c == '"' || c == '\'') 2904887Schin { 2914887Schin op = 0; 2924887Schin while ((n = BACK(a, p)) && n != c || PEEK(a, p) == '\\'); 2934887Schin } 2944887Schin else if (c == '\n') 2954887Schin { 2964887Schin token = a; 2974887Schin while (c = BACK(a, p)) 2984887Schin if (c == '\n') 2994887Schin { 3004887Schin a = token; 3014887Schin break; 3024887Schin } 3034887Schin else if (c == '#' && PEEK(a, p) == '\n') 3044887Schin break; 3054887Schin } 3064887Schin else if (c == ' ') 3074887Schin /*ignore*/; 3084887Schin else if (c == '{') /* '}' */ 3094887Schin op = 1; 3104887Schin else if (op == 1) 3114887Schin { 3124887Schin if (c == ')') 3134887Schin { 3144887Schin op = 2; 3154887Schin n = 1; 3164887Schin } 3174887Schin else 3184887Schin op = 0; 3194887Schin } 3204887Schin else if (op == 2) 3214887Schin { 3224887Schin if (c == ')') 3234887Schin n++; 3244887Schin else if (c == '(' && !--n) 3254887Schin op = 3; 3264887Schin } 3274887Schin else if (op == 3) 3284887Schin { 3294887Schin if (ppisidig(c)) 3304887Schin { 331*8462SApril.Chin@Sun.COM for (t = p, token = a, onumber = number; ppisidig(PEEK(a, p)) && a >= p; BACK(a, p)); 332*8462SApril.Chin@Sun.COM p = pp.valbuf + 1; 333*8462SApril.Chin@Sun.COM if (a > token) 334*8462SApril.Chin@Sun.COM { 335*8462SApril.Chin@Sun.COM for (; a < pp.outbuf+2*PPBUFSIZ; *p++ = *a++); 336*8462SApril.Chin@Sun.COM a = pp.outbuf; 337*8462SApril.Chin@Sun.COM } 338*8462SApril.Chin@Sun.COM for (; a <= token; *p++ = *a++); 3394887Schin *p = 0; 3404887Schin p = pp.valbuf + 1; 3414887Schin if (streq(p, "for") || streq(p, "if") || streq(p, "switch") || streq(p, "while")) 3424887Schin { 3434887Schin op = 0; 3444887Schin p = t; 345*8462SApril.Chin@Sun.COM number = onumber; 3464887Schin continue; 3474887Schin } 3484887Schin } 3494887Schin else 3504887Schin op = 0; 3514887Schin break; 3524887Schin } 3534887Schin } 3544887Schin if (op == 3) 355*8462SApril.Chin@Sun.COM p = strncpy(pp.funbuf, p, sizeof(pp.funbuf) - 1); 3564887Schin else if (*pp.funbuf) 3574887Schin p = pp.funbuf; 3584887Schin else 3594887Schin p = "__FUNCTION__"; 3604887Schin break; 3614887Schin default: 3624887Schin if (pp.builtin && (a = (*pp.builtin)(pp.valbuf, p, a))) 3634887Schin p = a; 3644887Schin break; 3654887Schin } 3664887Schin break; 3674887Schin } 3684887Schin if (strchr(p, MARK)) 3694887Schin { 3704887Schin a = pp.tmpbuf; 3714887Schin strcpy(a, p); 3724887Schin c = p != pp.valbuf; 3734887Schin p = pp.valbuf + c; 3744887Schin for (;;) 3754887Schin { 3764887Schin if (p < pp.valbuf + MAXTOKEN - 2) 3774887Schin switch (*p++ = *a++) 3784887Schin { 3794887Schin case 0: 3804887Schin break; 3814887Schin case MARK: 3824887Schin *p++ = MARK; 3834887Schin /*FALLTHROUGH*/ 3844887Schin default: 3854887Schin continue; 3864887Schin } 3874887Schin break; 3884887Schin } 3894887Schin p = pp.valbuf + c; 3904887Schin } 3914887Schin if (p == pp.valbuf) 3924887Schin PUSH_STRING(p); 3934887Schin else 3944887Schin { 3954887Schin if (p == pp.valbuf + 1) 3964887Schin *pp.valbuf = '"'; 3974887Schin else 3984887Schin { 3994887Schin if (strlen(p) > MAXTOKEN - 2) 4004887Schin error(1, "%-.16s: builtin value truncated", p); 4014887Schin sfsprintf(pp.valbuf, MAXTOKEN, "\"%-.*s", MAXTOKEN - 2, p); 4024887Schin } 4034887Schin PUSH_QUOTE(pp.valbuf, 1); 4044887Schin } 4054887Schin } 406