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