xref: /illumos-gate/usr/src/cmd/sgs/m4/common/m4macs.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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
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
79 dodecr(wchar_t **ap, int c)
80 {
81 	pbnum(ctol(arg(1))-1);
82 }
83 
84 void
85 dodef(wchar_t **ap, int c)
86 {
87 	def(ap, c, NOPUSH);
88 }
89 
90 static void
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
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
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
147 dodivnum(wchar_t **ap, int c)
148 {
149 	pbnum((long)ofx);
150 }
151 
152 /* ARGSUSED */
153 static void
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
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
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
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
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
243 doexit(wchar_t **ap, int c)
244 {
245 	delexit(wstoi(arg(1)), 1);
246 }
247 
248 static void
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
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
285 doincl(wchar_t **ap, int c)
286 {
287 	incl(ap, c, 1);
288 }
289 
290 static void
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
310 doincr(wchar_t **ap, int c)
311 {
312 	pbnum(ctol(arg(1))+1);
313 }
314 
315 static void
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
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
342 dolen(wchar_t **ap, int c)
343 {
344 	pbnum((long)wcslen(arg(1)));
345 }
346 
347 static void
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
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
370 dopushdef(wchar_t **ap, int c)
371 {
372 	def(ap, c, PUSH);
373 }
374 
375 static void
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
394 dosincl(wchar_t **ap, int c)
395 {
396 	incl(ap, c, 0);
397 }
398 
399 static void
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
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
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
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
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
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
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
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
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
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
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