1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2011 Gary Mills 29 */ 30 31 /* Copyright (c) 1988 AT&T */ 32 /* All Rights Reserved */ 33 34 #include <limits.h> 35 #include <unistd.h> 36 #include <sys/types.h> 37 #include "m4.h" 38 39 #define arg(n) (c < (n) ? nullstr: ap[n]) 40 static void mkpid(char *); 41 static void def(wchar_t **, int, int); 42 static void dump(wchar_t *, wchar_t *); 43 static void incl(wchar_t **, int, int); 44 static int leftmatch(wchar_t *, wchar_t *); 45 46 static void 47 dochcom(wchar_t **ap, int c) 48 { 49 wchar_t *l = arg(1); 50 wchar_t *r = arg(2); 51 52 if (wcslen(l) > MAXSYM || wcslen(r) > MAXSYM) 53 error2(gettext( 54 "comment marker longer than %d chars"), MAXSYM); 55 (void) wcscpy(lcom, l); 56 (void) wcscpy(rcom, *r ? r : L"\n"); 57 } 58 59 static void 60 docq(wchar_t **ap, int c) 61 { 62 wchar_t *l = arg(1); 63 wchar_t *r = arg(2); 64 65 if (wcslen(l) > MAXSYM || wcslen(r) > MAXSYM) 66 error2(gettext( 67 "quote marker longer than %d chars"), MAXSYM); 68 69 if (c <= 1 && !*l) { 70 l = L"`"; 71 r = L"'"; 72 } else if (c == 1) { 73 r = l; 74 } 75 76 (void) wcscpy(lquote, l); 77 (void) wcscpy(rquote, r); 78 } 79 80 static void 81 dodecr(wchar_t **ap, int c) 82 { 83 pbnum(ctol(arg(1))-1); 84 } 85 86 void 87 dodef(wchar_t **ap, int c) 88 { 89 def(ap, c, NOPUSH); 90 } 91 92 static void 93 def(wchar_t **ap, int c, int mode) 94 { 95 wchar_t *s; 96 97 if (c < 1) 98 return; 99 100 s = ap[1]; 101 if (is_alpha(*s) || *s == '_') { 102 s++; 103 while (is_alnum(*s) || *s == '_') 104 s++; 105 } 106 if (*s || s == ap[1]) 107 error(gettext("bad macro name")); 108 109 if ((ap[2] != NULL) && (wcscmp(ap[1], ap[2]) == 0)) 110 error(gettext("macro defined as itself")); 111 112 install(ap[1], arg(2), mode); 113 } 114 115 static void 116 dodefn(wchar_t **ap, int c) 117 { 118 wchar_t *d; 119 120 while (c > 0) 121 if ((d = lookup(ap[c--])->def) != NULL) { 122 putbak(*rquote); 123 while (*d) 124 putbak(*d++); 125 putbak(*lquote); 126 } 127 } 128 129 static void 130 dodiv(wchar_t **ap, int c) 131 { 132 int f; 133 134 f = wstoi(arg(1)); 135 if (f >= 10 || f < 0) { 136 cf = NULL; 137 ofx = f; 138 return; 139 } 140 tempfile[7] = 'a'+f; 141 if (ofile[f] || (ofile[f] = xfopen(tempfile, "w"))) { 142 ofx = f; 143 cf = ofile[f]; 144 } 145 } 146 147 /* ARGSUSED */ 148 static void 149 dodivnum(wchar_t **ap, int c) 150 { 151 pbnum((long)ofx); 152 } 153 154 /* ARGSUSED */ 155 static void 156 dodnl(wchar_t **ap, int c) 157 { 158 wchar_t t; 159 160 while ((t = getchr()) != '\n' && t != WEOF) 161 ; 162 } 163 164 static void 165 dodump(wchar_t **ap, int c) 166 { 167 struct nlist *np; 168 int i; 169 170 if (c > 0) 171 while (c--) { 172 if ((np = lookup(*++ap))->name != NULL) 173 dump(np->name, np->def); 174 } 175 else 176 for (i = 0; i < hshsize; i++) 177 for (np = hshtab[i]; np != NULL; np = np->next) 178 dump(np->name, np->def); 179 } 180 181 /*ARGSUSED*/ 182 static void 183 dump(wchar_t *name, wchar_t *defnn) 184 { 185 wchar_t *s = defnn; 186 187 #if !defined(__lint) /* lint doesn't grok "%ws" */ 188 (void) fprintf(stderr, "%ws:\t", name); 189 #endif 190 191 while (*s++) 192 ; 193 --s; 194 195 while (s > defnn) { 196 --s; 197 if (is_builtin(*s)) { 198 #if !defined(__lint) /* lint doesn't grok "%ws" */ 199 (void) fprintf(stderr, "<%ws>", 200 barray[builtin_idx(*s)].bname); 201 } else { 202 #endif 203 (void) fputwc(*s, stderr); 204 } 205 } 206 (void) fputc('\n', stderr); 207 } 208 209 /*ARGSUSED*/ 210 static void 211 doerrp(wchar_t **ap, int c) 212 { 213 #if !defined(__lint) /* lint doesn't grok "%ws" */ 214 if (c > 0) 215 (void) fprintf(stderr, "%ws", ap[1]); 216 #endif 217 } 218 219 long evalval; /* return value from yacc stuff */ 220 wchar_t *pe; /* used by grammar */ 221 222 static void 223 doeval(wchar_t **ap, int c) 224 { 225 int base = wstoi(arg(2)); 226 int pad = wstoi(arg(3)); 227 extern int yyparse(void); 228 229 evalval = 0; 230 if (c > 0) { 231 pe = ap[1]; 232 if (yyparse() != 0) 233 error(gettext( 234 "invalid expression")); 235 } 236 pbnbr(evalval, base > 0 ? base:10, pad > 0 ? pad : 1); 237 } 238 239 /* 240 * doexit 241 * 242 * Process m4exit macro. 243 */ 244 static void 245 doexit(wchar_t **ap, int c) 246 { 247 delexit(wstoi(arg(1)), 1); 248 } 249 250 static void 251 doif(wchar_t **ap, int c) 252 { 253 if (c < 3) 254 return; 255 while (c >= 3) { 256 if (wcscmp(ap[1], ap[2]) == 0) { 257 pbstr(ap[3]); 258 return; 259 } 260 c -= 3; 261 ap += 3; 262 } 263 if (c > 0) 264 pbstr(ap[1]); 265 } 266 267 static void 268 doifdef(wchar_t **ap, int c) 269 { 270 if (c < 2) 271 return; 272 273 while (c >= 2) { 274 if (lookup(ap[1])->name != NULL) { 275 pbstr(ap[2]); 276 return; 277 } 278 c -= 2; 279 ap += 2; 280 } 281 282 if (c > 0) 283 pbstr(ap[1]); 284 } 285 286 static void 287 doincl(wchar_t **ap, int c) 288 { 289 incl(ap, c, 1); 290 } 291 292 static void 293 incl(wchar_t **ap, int c, int noisy) 294 { 295 if (c > 0 && wcslen(ap[1]) > 0) { 296 if (ifx >= 9) 297 error(gettext( 298 "input file nesting too deep (9)")); 299 if ((ifile[++ifx] = fopen(wstr2str(ap[1], 0), "r")) == NULL) { 300 --ifx; 301 if (noisy) 302 errorf(gettext("cannot open file: %s"), 303 strerror(errno)); 304 } else { 305 ipstk[ifx] = ipflr = ip; 306 setfname(wstr2str(ap[1], 0)); 307 } 308 } 309 } 310 311 static void 312 doincr(wchar_t **ap, int c) 313 { 314 pbnum(ctol(arg(1))+1); 315 } 316 317 static void 318 doindex(wchar_t **ap, int c) 319 { 320 wchar_t *subj = arg(1); 321 wchar_t *obj = arg(2); 322 int i; 323 324 for (i = 0; *subj; ++i) 325 if (leftmatch(subj++, obj)) { 326 pbnum((long)i); 327 return; 328 } 329 330 pbnum((long)-1); 331 } 332 333 static int 334 leftmatch(wchar_t *str, wchar_t *substr) 335 { 336 while (*substr) 337 if (*str++ != *substr++) 338 return (0); 339 340 return (1); 341 } 342 343 static void 344 dolen(wchar_t **ap, int c) 345 { 346 pbnum((long)wcslen(arg(1))); 347 } 348 349 static void 350 domake(wchar_t **ap, int c) 351 { 352 char *path; 353 354 if (c > 0) { 355 path = wstr2str(ap[1], 1); 356 mkpid(path); 357 pbstr(str2wstr(path, 0)); 358 free(path); 359 } 360 } 361 362 static void 363 dopopdef(wchar_t **ap, int c) 364 { 365 int i; 366 367 for (i = 1; i <= c; ++i) 368 (void) undef(ap[i]); 369 } 370 371 static void 372 dopushdef(wchar_t **ap, int c) 373 { 374 def(ap, c, PUSH); 375 } 376 377 static void 378 doshift(wchar_t **ap, int c) 379 { 380 if (c <= 1) 381 return; 382 383 for (;;) { 384 pbstr(rquote); 385 pbstr(ap[c--]); 386 pbstr(lquote); 387 388 if (c <= 1) 389 break; 390 391 pbstr(L","); 392 } 393 } 394 395 static void 396 dosincl(wchar_t **ap, int c) 397 { 398 incl(ap, c, 0); 399 } 400 401 static void 402 dosubstr(wchar_t **ap, int c) 403 { 404 wchar_t *str; 405 int inlen, outlen; 406 int offset, ix; 407 408 inlen = wcslen(str = arg(1)); 409 offset = wstoi(arg(2)); 410 411 if (offset < 0 || offset >= inlen) 412 return; 413 414 outlen = c >= 3 ? wstoi(ap[3]) : inlen; 415 ix = min(offset+outlen, inlen); 416 417 while (ix > offset) 418 putbak(str[--ix]); 419 } 420 421 static void 422 dosyscmd(wchar_t **ap, int c) 423 { 424 sysrval = 0; 425 if (c > 0) { 426 (void) fflush(stdout); 427 sysrval = system(wstr2str(ap[1], 0)); 428 } 429 } 430 431 /* ARGSUSED */ 432 static void 433 dosysval(wchar_t **ap, int c) 434 { 435 pbnum((long)(sysrval < 0 ? sysrval : 436 (sysrval >> 8) & ((1 << 8) - 1)) | 437 ((sysrval & ((1 << 8) - 1)) << 8)); 438 } 439 440 static void 441 dotransl(wchar_t **ap, int c) 442 { 443 wchar_t *sink, *fr, *sto; 444 wchar_t *source, *to; 445 446 if (c < 1) 447 return; 448 449 sink = ap[1]; 450 fr = arg(2); 451 sto = arg(3); 452 453 for (source = ap[1]; *source; source++) { 454 wchar_t *i; 455 to = sto; 456 for (i = fr; *i; ++i) { 457 if (*source == *i) 458 break; 459 if (*to) 460 ++to; 461 } 462 if (*i) { 463 if (*to) 464 *sink++ = *to; 465 } else 466 *sink++ = *source; 467 } 468 *sink = EOS; 469 pbstr(ap[1]); 470 } 471 472 static void 473 dotroff(wchar_t **ap, int c) 474 { 475 struct nlist *np; 476 477 trace = 0; 478 479 while (c > 0) 480 if ((np = lookup(ap[c--]))->name) 481 np->tflag = 0; 482 } 483 484 static void 485 dotron(wchar_t **ap, int c) 486 { 487 struct nlist *np; 488 489 trace = !*arg(1); 490 491 while (c > 0) 492 if ((np = lookup(ap[c--]))->name) 493 np->tflag = 1; 494 } 495 496 void 497 doundef(wchar_t **ap, int c) 498 { 499 int i; 500 501 for (i = 1; i <= c; ++i) 502 while (undef(ap[i])) 503 ; 504 } 505 506 int 507 undef(wchar_t *nam) 508 { 509 struct nlist *np, *tnp; 510 511 if ((np = lookup(nam))->name == NULL) 512 return (0); 513 tnp = hshtab[hshval]; /* lookup sets hshval */ 514 if (tnp == np) /* it's in first place */ 515 hshtab[hshval] = tnp->next; 516 else { 517 while (tnp->next != np) 518 tnp = tnp->next; 519 520 tnp->next = np->next; 521 } 522 free(np->name); 523 free(np->def); 524 free(np); 525 return (1); 526 } 527 528 static void 529 doundiv(wchar_t **ap, int c) 530 { 531 int i; 532 533 if (c <= 0) 534 for (i = 1; i < 10; i++) 535 undiv(i, OK); 536 else 537 while (--c >= 0) 538 undiv(wstoi(*++ap), OK); 539 } 540 541 /* 542 * dowrap 543 * 544 * Process m4wrap macro. 545 */ 546 static void 547 dowrap(wchar_t **ap, int c) 548 { 549 wchar_t *a = arg(1); 550 struct Wrap *wrapentry; /* entry for list of "m4wrap" strings */ 551 552 wrapentry = xmalloc(sizeof (struct Wrap)); 553 /* store m4wrap string */ 554 wrapentry->wrapstr = wstrdup(a); 555 /* add this entry to the front of the list of Wrap entries */ 556 wrapentry->nxt = wrapstart; 557 wrapstart = wrapentry; 558 } 559 560 static void 561 mkpid(char *as) 562 { 563 char *s = as; 564 char *l; 565 char *first_X; 566 unsigned xcnt = 0; 567 char my_pid[32]; 568 int pid_len; 569 int i = 0; 570 571 /* 572 * Count number of X. 573 */ 574 l = &s[strlen(s)-1]; 575 while (l != as) { 576 if (*l == 'X') { 577 first_X = l; 578 l--; 579 xcnt++; 580 } else if (xcnt == 0) 581 l--; 582 else { 583 break; 584 } 585 } 586 587 /* 588 * 1) If there is no X in the passed string, 589 * then it just return the passed string. 590 * 2) If the length of the continuous right most X's of 591 * the string is shorter than the length of pid, 592 * then right most X's will be substitued with 593 * upper digits of pid. 594 * 3) If the length of the continuous right most X's of 595 * the string is equat to the length of pid, 596 * then X's will be replaced with pid. 597 * 4) If the lenght of the continuous right most X's of 598 * the string is longer than the length of pid, 599 * then X's will have leading 0 followed by 600 * pid. 601 */ 602 603 /* 604 * If there were no X, don't do anything. 605 */ 606 if (xcnt == 0) 607 return; 608 609 /* 610 * Get pid 611 */ 612 (void) snprintf(my_pid, sizeof (my_pid), "%d", (int)getpid()); 613 pid_len = strlen(my_pid); 614 615 if (pid_len > xcnt) 616 my_pid[xcnt] = 0; 617 else if (pid_len < xcnt) { 618 while (xcnt != pid_len) { 619 *first_X++ = '0'; 620 xcnt--; 621 } 622 } 623 624 /* 625 * Copy pid 626 */ 627 while (i != xcnt) 628 *first_X++ = my_pid[i++]; 629 } 630 631 struct bs barray[] = { 632 dochcom, L"changecom", 633 docq, L"changequote", 634 dodecr, L"decr", 635 dodef, L"define", 636 dodefn, L"defn", 637 dodiv, L"divert", 638 dodivnum, L"divnum", 639 dodnl, L"dnl", 640 dodump, L"dumpdef", 641 doerrp, L"errprint", 642 doeval, L"eval", 643 doexit, L"m4exit", 644 doif, L"ifelse", 645 doifdef, L"ifdef", 646 doincl, L"include", 647 doincr, L"incr", 648 doindex, L"index", 649 dolen, L"len", 650 domake, L"maketemp", 651 dopopdef, L"popdef", 652 dopushdef, L"pushdef", 653 doshift, L"shift", 654 dosincl, L"sinclude", 655 dosubstr, L"substr", 656 dosyscmd, L"syscmd", 657 dosysval, L"sysval", 658 dotransl, L"translit", 659 dotroff, L"traceoff", 660 dotron, L"traceon", 661 doundef, L"undefine", 662 doundiv, L"undivert", 663 dowrap, L"m4wrap", 664 0, 0 665 }; 666