Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libpp/ppbuiltin.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1986-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
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
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
407