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
dochcom(wchar_t ** ap,int c)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
docq(wchar_t ** ap,int c)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
dodecr(wchar_t ** ap,int c)79 dodecr(wchar_t **ap, int c)
80 {
81 pbnum(ctol(arg(1))-1);
82 }
83
84 void
dodef(wchar_t ** ap,int c)85 dodef(wchar_t **ap, int c)
86 {
87 def(ap, c, NOPUSH);
88 }
89
90 static void
def(wchar_t ** ap,int c,int mode)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
dodefn(wchar_t ** ap,int c)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
dodiv(wchar_t ** ap,int c)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
dodivnum(wchar_t ** ap,int c)147 dodivnum(wchar_t **ap, int c)
148 {
149 pbnum((long)ofx);
150 }
151
152 /* ARGSUSED */
153 static void
dodnl(wchar_t ** ap,int c)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
dodump(wchar_t ** ap,int c)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
dump(wchar_t * name,wchar_t * defnn)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
doerrp(wchar_t ** ap,int c)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
doeval(wchar_t ** ap,int c)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
doexit(wchar_t ** ap,int c)243 doexit(wchar_t **ap, int c)
244 {
245 delexit(wstoi(arg(1)), 1);
246 }
247
248 static void
doif(wchar_t ** ap,int c)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
doifdef(wchar_t ** ap,int c)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
doincl(wchar_t ** ap,int c)285 doincl(wchar_t **ap, int c)
286 {
287 incl(ap, c, 1);
288 }
289
290 static void
incl(wchar_t ** ap,int c,int noisy)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
doincr(wchar_t ** ap,int c)310 doincr(wchar_t **ap, int c)
311 {
312 pbnum(ctol(arg(1))+1);
313 }
314
315 static void
doindex(wchar_t ** ap,int c)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
leftmatch(wchar_t * str,wchar_t * substr)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
dolen(wchar_t ** ap,int c)342 dolen(wchar_t **ap, int c)
343 {
344 pbnum((long)wcslen(arg(1)));
345 }
346
347 static void
domake(wchar_t ** ap,int c)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
dopopdef(wchar_t ** ap,int c)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
dopushdef(wchar_t ** ap,int c)370 dopushdef(wchar_t **ap, int c)
371 {
372 def(ap, c, PUSH);
373 }
374
375 static void
doshift(wchar_t ** ap,int c)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
dosincl(wchar_t ** ap,int c)394 dosincl(wchar_t **ap, int c)
395 {
396 incl(ap, c, 0);
397 }
398
399 static void
dosubstr(wchar_t ** ap,int c)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
dosyscmd(wchar_t ** ap,int c)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
dosysval(wchar_t ** ap,int c)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
dotransl(wchar_t ** ap,int c)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
dotroff(wchar_t ** ap,int c)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
dotron(wchar_t ** ap,int c)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
doundef(wchar_t ** ap,int c)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
undef(wchar_t * nam)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
doundiv(wchar_t ** ap,int c)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
dowrap(wchar_t ** ap,int c)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
mkpid(char * as)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