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