xref: /illumos-gate/usr/src/cmd/sgs/m4/common/m4macs.c (revision 54719d5edb7521bb3a321ad8bd9ebc251d61a1a0)
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