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]) 38static void mkpid(char *); 39static void def(wchar_t **, int, int); 40static void dump(wchar_t *, wchar_t *); 41static void incl(wchar_t **, int, int); 42static int leftmatch(wchar_t *, wchar_t *); 43 44static void 45dochcom(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 57static void 58docq(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 78static void 79dodecr(wchar_t **ap, int c) 80{ 81 pbnum(ctol(arg(1))-1); 82} 83 84void 85dodef(wchar_t **ap, int c) 86{ 87 def(ap, c, NOPUSH); 88} 89 90static void 91def(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 113static void 114dodefn(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 127static void 128dodiv(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 */ 146static void 147dodivnum(wchar_t **ap, int c) 148{ 149 pbnum((long)ofx); 150} 151 152/* ARGSUSED */ 153static void 154dodnl(wchar_t **ap, int c) 155{ 156 wchar_t t; 157 158 while ((t = getchr()) != '\n' && t != WEOF) 159 ; 160} 161 162static void 163dodump(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*/ 180static void 181dump(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*/ 208static void 209doerrp(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 217long evalval; /* return value from yacc stuff */ 218wchar_t *pe; /* used by grammar */ 219 220static void 221doeval(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 */ 242static void 243doexit(wchar_t **ap, int c) 244{ 245 delexit(wstoi(arg(1)), 1); 246} 247 248static void 249doif(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 265static void 266doifdef(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 284static void 285doincl(wchar_t **ap, int c) 286{ 287 incl(ap, c, 1); 288} 289 290static void 291incl(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 309static void 310doincr(wchar_t **ap, int c) 311{ 312 pbnum(ctol(arg(1))+1); 313} 314 315static void 316doindex(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 331static int 332leftmatch(wchar_t *str, wchar_t *substr) 333{ 334 while (*substr) 335 if (*str++ != *substr++) 336 return (0); 337 338 return (1); 339} 340 341static void 342dolen(wchar_t **ap, int c) 343{ 344 pbnum((long)wcslen(arg(1))); 345} 346 347static void 348domake(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 360static void 361dopopdef(wchar_t **ap, int c) 362{ 363 int i; 364 365 for (i = 1; i <= c; ++i) 366 (void) undef(ap[i]); 367} 368 369static void 370dopushdef(wchar_t **ap, int c) 371{ 372 def(ap, c, PUSH); 373} 374 375static void 376doshift(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 393static void 394dosincl(wchar_t **ap, int c) 395{ 396 incl(ap, c, 0); 397} 398 399static void 400dosubstr(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 419static void 420dosyscmd(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 */ 430static void 431dosysval(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 438static void 439dotransl(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 470static void 471dotroff(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 482static void 483dotron(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 494void 495doundef(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 504int 505undef(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 526static void 527doundiv(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 */ 544static void 545dowrap(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 558static void 559mkpid(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 629struct 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