xref: /illumos-gate/usr/src/cmd/sgs/m4/common/m4macs.c (revision 3bb8546d907194e91bea367d863eb10ce3fe6621)
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
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
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
81 dodecr(wchar_t **ap, int c)
82 {
83 	pbnum(ctol(arg(1))-1);
84 }
85 
86 void
87 dodef(wchar_t **ap, int c)
88 {
89 	def(ap, c, NOPUSH);
90 }
91 
92 static void
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
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
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
149 dodivnum(wchar_t **ap, int c)
150 {
151 	pbnum((long)ofx);
152 }
153 
154 /* ARGSUSED */
155 static void
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
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
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
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
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
245 doexit(wchar_t **ap, int c)
246 {
247 	delexit(wstoi(arg(1)), 1);
248 }
249 
250 static void
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
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
287 doincl(wchar_t **ap, int c)
288 {
289 	incl(ap, c, 1);
290 }
291 
292 static void
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
312 doincr(wchar_t **ap, int c)
313 {
314 	pbnum(ctol(arg(1))+1);
315 }
316 
317 static void
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
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
344 dolen(wchar_t **ap, int c)
345 {
346 	pbnum((long)wcslen(arg(1)));
347 }
348 
349 static void
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
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
372 dopushdef(wchar_t **ap, int c)
373 {
374 	def(ap, c, PUSH);
375 }
376 
377 static void
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
396 dosincl(wchar_t **ap, int c)
397 {
398 	incl(ap, c, 0);
399 }
400 
401 static void
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
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
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
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
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
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
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
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
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
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
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