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