14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1986-2009 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 * *
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
ppbuiltin(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;
498462SApril.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
2838462SApril.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 {
3318462SApril.Chin@Sun.COM for (t = p, token = a, onumber = number; ppisidig(PEEK(a, p)) && a >= p; BACK(a, p));
3328462SApril.Chin@Sun.COM p = pp.valbuf + 1;
3338462SApril.Chin@Sun.COM if (a > token)
3348462SApril.Chin@Sun.COM {
3358462SApril.Chin@Sun.COM for (; a < pp.outbuf+2*PPBUFSIZ; *p++ = *a++);
3368462SApril.Chin@Sun.COM a = pp.outbuf;
3378462SApril.Chin@Sun.COM }
3388462SApril.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;
3458462SApril.Chin@Sun.COM number = onumber;
3464887Schin continue;
3474887Schin }
3484887Schin }
3494887Schin else
3504887Schin op = 0;
3514887Schin break;
3524887Schin }
3534887Schin }
3544887Schin if (op == 3)
3558462SApril.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