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 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