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