1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*34f9b3eeSRoland Mainz * Copyright (c) 1986-2009 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril 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
ppbuiltin(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;
497c2fbfb3SApril 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
2837c2fbfb3SApril 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 {
3317c2fbfb3SApril Chin for (t = p, token = a, onumber = number; ppisidig(PEEK(a, p)) && a >= p; BACK(a, p));
3327c2fbfb3SApril Chin p = pp.valbuf + 1;
3337c2fbfb3SApril Chin if (a > token)
3347c2fbfb3SApril Chin {
3357c2fbfb3SApril Chin for (; a < pp.outbuf+2*PPBUFSIZ; *p++ = *a++);
3367c2fbfb3SApril Chin a = pp.outbuf;
3377c2fbfb3SApril Chin }
3387c2fbfb3SApril 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;
3457c2fbfb3SApril Chin number = onumber;
346da2e3ebdSchin continue;
347da2e3ebdSchin }
348da2e3ebdSchin }
349da2e3ebdSchin else
350da2e3ebdSchin op = 0;
351da2e3ebdSchin break;
352da2e3ebdSchin }
353da2e3ebdSchin }
354da2e3ebdSchin if (op == 3)
3557c2fbfb3SApril 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