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
dochcom(wchar_t ** ap,int c)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
docq(wchar_t ** ap,int c)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
dodecr(wchar_t ** ap,int c)81 dodecr(wchar_t **ap, int c)
82 {
83 pbnum(ctol(arg(1))-1);
84 }
85
86 void
dodef(wchar_t ** ap,int c)87 dodef(wchar_t **ap, int c)
88 {
89 def(ap, c, NOPUSH);
90 }
91
92 static void
def(wchar_t ** ap,int c,int mode)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
dodefn(wchar_t ** ap,int c)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
dodiv(wchar_t ** ap,int c)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
dodivnum(wchar_t ** ap,int c)149 dodivnum(wchar_t **ap, int c)
150 {
151 pbnum((long)ofx);
152 }
153
154 /* ARGSUSED */
155 static void
dodnl(wchar_t ** ap,int c)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
dodump(wchar_t ** ap,int c)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
dump(wchar_t * name,wchar_t * defnn)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
doerrp(wchar_t ** ap,int c)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
doeval(wchar_t ** ap,int c)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
doexit(wchar_t ** ap,int c)245 doexit(wchar_t **ap, int c)
246 {
247 delexit(wstoi(arg(1)), 1);
248 }
249
250 static void
doif(wchar_t ** ap,int c)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
doifdef(wchar_t ** ap,int c)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
doincl(wchar_t ** ap,int c)287 doincl(wchar_t **ap, int c)
288 {
289 incl(ap, c, 1);
290 }
291
292 static void
incl(wchar_t ** ap,int c,int noisy)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
doincr(wchar_t ** ap,int c)312 doincr(wchar_t **ap, int c)
313 {
314 pbnum(ctol(arg(1))+1);
315 }
316
317 static void
doindex(wchar_t ** ap,int c)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
leftmatch(wchar_t * str,wchar_t * substr)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
dolen(wchar_t ** ap,int c)344 dolen(wchar_t **ap, int c)
345 {
346 pbnum((long)wcslen(arg(1)));
347 }
348
349 static void
domake(wchar_t ** ap,int c)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
dopopdef(wchar_t ** ap,int c)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
dopushdef(wchar_t ** ap,int c)372 dopushdef(wchar_t **ap, int c)
373 {
374 def(ap, c, PUSH);
375 }
376
377 static void
doshift(wchar_t ** ap,int c)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
dosincl(wchar_t ** ap,int c)396 dosincl(wchar_t **ap, int c)
397 {
398 incl(ap, c, 0);
399 }
400
401 static void
dosubstr(wchar_t ** ap,int c)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
dosyscmd(wchar_t ** ap,int c)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
dosysval(wchar_t ** ap,int c)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
dotransl(wchar_t ** ap,int c)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
dotroff(wchar_t ** ap,int c)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
dotron(wchar_t ** ap,int c)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
doundef(wchar_t ** ap,int c)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
undef(wchar_t * nam)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
doundiv(wchar_t ** ap,int c)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
dowrap(wchar_t ** ap,int c)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
mkpid(char * as)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