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