xref: /illumos-gate/usr/src/cmd/sendmail/src/macro.c (revision 2a8bcb4efb45d99ac41c94a75c396b362c414f7f)
17c478bd9Sstevel@tonic-gate /*
2*7800901eSjbeck  * Copyright (c) 1998-2001, 2003, 2006, 2007 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate  * the sendmail distribution.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #include <sendmail.h>
157c478bd9Sstevel@tonic-gate 
16*7800901eSjbeck SM_RCSID("@(#)$Id: macro.c,v 8.107 2007/08/06 22:29:02 ca Exp $")
177c478bd9Sstevel@tonic-gate 
18058561cbSjbeck #include <sm/sendmail.h>
197c478bd9Sstevel@tonic-gate #if MAXMACROID != (BITMAPBITS - 1)
207c478bd9Sstevel@tonic-gate 	ERROR Read the comment in conf.h
217c478bd9Sstevel@tonic-gate #endif /* MAXMACROID != (BITMAPBITS - 1) */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate static char	*MacroName[MAXMACROID + 1];	/* macro id to name table */
24*7800901eSjbeck 
25*7800901eSjbeck /*
26*7800901eSjbeck **  Codes for long named macros.
27*7800901eSjbeck **  See also macname():
28*7800901eSjbeck 	* if not ASCII printable, look up the name *
29*7800901eSjbeck 	if (n <= 0x20 || n > 0x7f)
30*7800901eSjbeck **  First use 1 to NEXTMACROID_L, then use NEXTMACROID_H to MAXMACROID.
31*7800901eSjbeck */
32*7800901eSjbeck 
33*7800901eSjbeck #define NEXTMACROID_L 037
34*7800901eSjbeck #define NEXTMACROID_H 0240
35*7800901eSjbeck 
36*7800901eSjbeck #if _FFR_MORE_MACROS
37*7800901eSjbeck /* table for next id in non-printable ASCII range: disallow some value */
38*7800901eSjbeck static int NextMIdTable[] =
39*7800901eSjbeck {
40*7800901eSjbeck 	/*  0  nul */	 1,
41*7800901eSjbeck 	/*  1  soh */	 2,
42*7800901eSjbeck 	/*  2  stx */	 3,
43*7800901eSjbeck 	/*  3  etx */	 4,
44*7800901eSjbeck 	/*  4  eot */	 5,
45*7800901eSjbeck 	/*  5  enq */	 6,
46*7800901eSjbeck 	/*  6  ack */	 7,
47*7800901eSjbeck 	/*  7  bel */	 8,
48*7800901eSjbeck 	/*  8  bs  */	14,
49*7800901eSjbeck 	/*  9  ht  */	-1,
50*7800901eSjbeck 	/* 10  nl  */	-1,
51*7800901eSjbeck 	/* 11  vt  */	-1,
52*7800901eSjbeck 	/* 12  np  */	-1,
53*7800901eSjbeck 	/* 13  cr  */	-1,
54*7800901eSjbeck 	/* 14  so  */	15,
55*7800901eSjbeck 	/* 15  si  */	16,
56*7800901eSjbeck 	/* 16  dle */	17,
57*7800901eSjbeck 	/* 17  dc1 */	18,
58*7800901eSjbeck 	/* 18  dc2 */	19,
59*7800901eSjbeck 	/* 19  dc3 */	20,
60*7800901eSjbeck 	/* 20  dc4 */	21,
61*7800901eSjbeck 	/* 21  nak */	22,
62*7800901eSjbeck 	/* 22  syn */	23,
63*7800901eSjbeck 	/* 23  etb */	24,
64*7800901eSjbeck 	/* 24  can */	25,
65*7800901eSjbeck 	/* 25  em  */	26,
66*7800901eSjbeck 	/* 26  sub */	27,
67*7800901eSjbeck 	/* 27  esc */	28,
68*7800901eSjbeck 	/* 28  fs  */	29,
69*7800901eSjbeck 	/* 29  gs  */	30,
70*7800901eSjbeck 	/* 30  rs  */	31,
71*7800901eSjbeck 	/* 31  us  */	32,
72*7800901eSjbeck 	/* 32  sp  */	-1,
73*7800901eSjbeck };
74*7800901eSjbeck 
75*7800901eSjbeck #define NEXTMACROID(mid)	(		\
76*7800901eSjbeck 	(mid < NEXTMACROID_L) ? (NextMIdTable[mid]) :	\
77*7800901eSjbeck 	((mid < NEXTMACROID_H) ? NEXTMACROID_H : (mid + 1)))
78*7800901eSjbeck 
79*7800901eSjbeck int		NextMacroId = 1;	/* codes for long named macros */
80058561cbSjbeck /* see sendmail.h: Special characters in rewriting rules. */
81*7800901eSjbeck #else /* _FFR_MORE_MACROS */
82*7800901eSjbeck int		NextMacroId = 0240;	/* codes for long named macros */
83*7800901eSjbeck #define NEXTMACROID(mid)	((mid) + 1)
84*7800901eSjbeck #endif /* _FFR_MORE_MACROS */
85058561cbSjbeck 
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate **  INITMACROS -- initialize the macro system
897c478bd9Sstevel@tonic-gate **
907c478bd9Sstevel@tonic-gate **	This just involves defining some macros that are actually
917c478bd9Sstevel@tonic-gate **	used internally as metasymbols to be themselves.
927c478bd9Sstevel@tonic-gate **
937c478bd9Sstevel@tonic-gate **	Parameters:
947c478bd9Sstevel@tonic-gate **		none.
957c478bd9Sstevel@tonic-gate **
967c478bd9Sstevel@tonic-gate **	Returns:
977c478bd9Sstevel@tonic-gate **		none.
987c478bd9Sstevel@tonic-gate **
997c478bd9Sstevel@tonic-gate **	Side Effects:
1007c478bd9Sstevel@tonic-gate **		initializes several macros to be themselves.
1017c478bd9Sstevel@tonic-gate */
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate struct metamac	MetaMacros[] =
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	/* LHS pattern matching characters */
1067c478bd9Sstevel@tonic-gate 	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
1077c478bd9Sstevel@tonic-gate 	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	/* these are RHS metasymbols */
1107c478bd9Sstevel@tonic-gate 	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
1117c478bd9Sstevel@tonic-gate 	{ '>', CALLSUBR },
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/* the conditional operations */
1147c478bd9Sstevel@tonic-gate 	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/* the hostname lookup characters */
1177c478bd9Sstevel@tonic-gate 	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
1187c478bd9Sstevel@tonic-gate 	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* miscellaneous control characters */
1217c478bd9Sstevel@tonic-gate 	{ '&', MACRODEXPAND },
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	{ '\0', '\0' }
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #define MACBINDING(name, mid) \
1277c478bd9Sstevel@tonic-gate 		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
1287c478bd9Sstevel@tonic-gate 		MacroName[mid] = name;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate void
initmacros(e)1317c478bd9Sstevel@tonic-gate initmacros(e)
132058561cbSjbeck 	ENVELOPE *e;
1337c478bd9Sstevel@tonic-gate {
134058561cbSjbeck 	struct metamac *m;
135058561cbSjbeck 	int c;
1367c478bd9Sstevel@tonic-gate 	char buf[5];
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	for (m = MetaMacros; m->metaname != '\0'; m++)
1397c478bd9Sstevel@tonic-gate 	{
1407c478bd9Sstevel@tonic-gate 		buf[0] = m->metaval;
1417c478bd9Sstevel@tonic-gate 		buf[1] = '\0';
1427c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, m->metaname, buf);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 	buf[0] = MATCHREPL;
1457c478bd9Sstevel@tonic-gate 	buf[2] = '\0';
1467c478bd9Sstevel@tonic-gate 	for (c = '0'; c <= '9'; c++)
1477c478bd9Sstevel@tonic-gate 	{
1487c478bd9Sstevel@tonic-gate 		buf[1] = c;
1497c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, c, buf);
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/* set defaults for some macros sendmail will use later */
1537c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'n', "MAILER-DAEMON");
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* set up external names for some internal macros */
1567c478bd9Sstevel@tonic-gate 	MACBINDING("opMode", MID_OPMODE);
1577c478bd9Sstevel@tonic-gate 	/*XXX should probably add equivalents for all short macros here XXX*/
1587c478bd9Sstevel@tonic-gate }
159058561cbSjbeck 
1607c478bd9Sstevel@tonic-gate /*
161058561cbSjbeck **  EXPAND/DOEXPAND -- macro expand a string using $x escapes.
162058561cbSjbeck **
163058561cbSjbeck **	After expansion, the expansion will be in external form (that is,
164058561cbSjbeck **	there will be no sendmail metacharacters and METAQUOTEs will have
165058561cbSjbeck **	been stripped out).
1667c478bd9Sstevel@tonic-gate **
1677c478bd9Sstevel@tonic-gate **	Parameters:
1687c478bd9Sstevel@tonic-gate **		s -- the string to expand.
1697c478bd9Sstevel@tonic-gate **		buf -- the place to put the expansion.
1707c478bd9Sstevel@tonic-gate **		bufsize -- the size of the buffer.
171058561cbSjbeck **		explevel -- the depth of expansion (doexpand only)
1727c478bd9Sstevel@tonic-gate **		e -- envelope in which to work.
1737c478bd9Sstevel@tonic-gate **
1747c478bd9Sstevel@tonic-gate **	Returns:
1757c478bd9Sstevel@tonic-gate **		none.
1767c478bd9Sstevel@tonic-gate **
1777c478bd9Sstevel@tonic-gate **	Side Effects:
1787c478bd9Sstevel@tonic-gate **		none.
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate 
181058561cbSjbeck static void doexpand __P(( char *, char *, size_t, int, ENVELOPE *));
182058561cbSjbeck 
183058561cbSjbeck static void
doexpand(s,buf,bufsize,explevel,e)184058561cbSjbeck doexpand(s, buf, bufsize, explevel, e)
185058561cbSjbeck 	char *s;
186058561cbSjbeck 	char *buf;
1877c478bd9Sstevel@tonic-gate 	size_t bufsize;
188058561cbSjbeck 	int explevel;
189058561cbSjbeck 	ENVELOPE *e;
1907c478bd9Sstevel@tonic-gate {
191058561cbSjbeck 	char *xp;
192058561cbSjbeck 	char *q;
1937c478bd9Sstevel@tonic-gate 	bool skipping;		/* set if conditionally skipping output */
1947c478bd9Sstevel@tonic-gate 	bool recurse;		/* set if recursion required */
1957c478bd9Sstevel@tonic-gate 	size_t i;
1967c478bd9Sstevel@tonic-gate 	int skiplev;		/* skipping nesting level */
1977c478bd9Sstevel@tonic-gate 	int iflev;		/* if nesting level */
198058561cbSjbeck 	bool quotenext;		/* quote the following character */
1997c478bd9Sstevel@tonic-gate 	char xbuf[MACBUFSIZE];
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (tTd(35, 24))
2027c478bd9Sstevel@tonic-gate 	{
2037c478bd9Sstevel@tonic-gate 		sm_dprintf("expand(");
2047c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), s);
2057c478bd9Sstevel@tonic-gate 		sm_dprintf(")\n");
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	recurse = false;
2097c478bd9Sstevel@tonic-gate 	skipping = false;
2107c478bd9Sstevel@tonic-gate 	skiplev = 0;
2117c478bd9Sstevel@tonic-gate 	iflev = 0;
212058561cbSjbeck 	quotenext = false;
2137c478bd9Sstevel@tonic-gate 	if (s == NULL)
2147c478bd9Sstevel@tonic-gate 		s = "";
2157c478bd9Sstevel@tonic-gate 	for (xp = xbuf; *s != '\0'; s++)
2167c478bd9Sstevel@tonic-gate 	{
2177c478bd9Sstevel@tonic-gate 		int c;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		/*
2207c478bd9Sstevel@tonic-gate 		**  Check for non-ordinary (special?) character.
2217c478bd9Sstevel@tonic-gate 		**	'q' will be the interpolated quantity.
2227c478bd9Sstevel@tonic-gate 		*/
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 		q = NULL;
225058561cbSjbeck 		c = *s & 0377;
226058561cbSjbeck 
227058561cbSjbeck 		if (quotenext)
228058561cbSjbeck 		{
229058561cbSjbeck 			quotenext = false;
230058561cbSjbeck 			goto simpleinterpolate;
231058561cbSjbeck 		}
232058561cbSjbeck 
233058561cbSjbeck 		switch (c)
2347c478bd9Sstevel@tonic-gate 		{
2357c478bd9Sstevel@tonic-gate 		  case CONDIF:		/* see if var set */
2367c478bd9Sstevel@tonic-gate 			iflev++;
237058561cbSjbeck 			c = *++s & 0377;
2387c478bd9Sstevel@tonic-gate 			if (skipping)
2397c478bd9Sstevel@tonic-gate 				skiplev++;
2407c478bd9Sstevel@tonic-gate 			else
2417c478bd9Sstevel@tonic-gate 			{
2427c478bd9Sstevel@tonic-gate 				char *mv;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 				mv = macvalue(c, e);
2457c478bd9Sstevel@tonic-gate 				skipping = (mv == NULL || *mv == '\0');
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 			continue;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		  case CONDELSE:	/* change state of skipping */
2507c478bd9Sstevel@tonic-gate 			if (iflev == 0)
2517c478bd9Sstevel@tonic-gate 				break;	/* XXX: error */
2527c478bd9Sstevel@tonic-gate 			if (skiplev == 0)
2537c478bd9Sstevel@tonic-gate 				skipping = !skipping;
2547c478bd9Sstevel@tonic-gate 			continue;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		  case CONDFI:		/* stop skipping */
2577c478bd9Sstevel@tonic-gate 			if (iflev == 0)
2587c478bd9Sstevel@tonic-gate 				break;	/* XXX: error */
2597c478bd9Sstevel@tonic-gate 			iflev--;
2607c478bd9Sstevel@tonic-gate 			if (skiplev == 0)
2617c478bd9Sstevel@tonic-gate 				skipping = false;
2627c478bd9Sstevel@tonic-gate 			if (skipping)
2637c478bd9Sstevel@tonic-gate 				skiplev--;
2647c478bd9Sstevel@tonic-gate 			continue;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		  case MACROEXPAND:	/* macro interpolation */
2677c478bd9Sstevel@tonic-gate 			c = bitidx(*++s);
2687c478bd9Sstevel@tonic-gate 			if (c != '\0')
2697c478bd9Sstevel@tonic-gate 				q = macvalue(c, e);
2707c478bd9Sstevel@tonic-gate 			else
2717c478bd9Sstevel@tonic-gate 			{
2727c478bd9Sstevel@tonic-gate 				s--;
2737c478bd9Sstevel@tonic-gate 				q = NULL;
2747c478bd9Sstevel@tonic-gate 			}
2757c478bd9Sstevel@tonic-gate 			if (q == NULL)
2767c478bd9Sstevel@tonic-gate 				continue;
2777c478bd9Sstevel@tonic-gate 			break;
278058561cbSjbeck 
279058561cbSjbeck 		  case METAQUOTE:
280058561cbSjbeck 			/* next octet completely quoted */
281058561cbSjbeck 			quotenext = true;
282058561cbSjbeck 			break;
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		/*
2867c478bd9Sstevel@tonic-gate 		**  Interpolate q or output one character
2877c478bd9Sstevel@tonic-gate 		*/
2887c478bd9Sstevel@tonic-gate 
289058561cbSjbeck   simpleinterpolate:
290058561cbSjbeck 		if (skipping || xp >= &xbuf[sizeof(xbuf) - 1])
2917c478bd9Sstevel@tonic-gate 			continue;
2927c478bd9Sstevel@tonic-gate 		if (q == NULL)
2937c478bd9Sstevel@tonic-gate 			*xp++ = c;
2947c478bd9Sstevel@tonic-gate 		else
2957c478bd9Sstevel@tonic-gate 		{
2967c478bd9Sstevel@tonic-gate 			/* copy to end of q or max space remaining in buf */
297058561cbSjbeck 			bool hiderecurse = false;
298058561cbSjbeck 
299058561cbSjbeck 			while ((c = *q++) != '\0' &&
300058561cbSjbeck 				xp < &xbuf[sizeof(xbuf) - 1])
3017c478bd9Sstevel@tonic-gate 			{
3027c478bd9Sstevel@tonic-gate 				/* check for any sendmail metacharacters */
303058561cbSjbeck 				if (!hiderecurse && (c & 0340) == 0200)
3047c478bd9Sstevel@tonic-gate 					recurse = true;
3057c478bd9Sstevel@tonic-gate 				*xp++ = c;
306058561cbSjbeck 
307058561cbSjbeck 				/* give quoted characters a free ride */
308058561cbSjbeck 				hiderecurse = (c & 0377) == METAQUOTE;
3097c478bd9Sstevel@tonic-gate 			}
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 	*xp = '\0';
3137c478bd9Sstevel@tonic-gate 
314058561cbSjbeck 	if (tTd(35, 28))
3157c478bd9Sstevel@tonic-gate 	{
316058561cbSjbeck 		sm_dprintf("expand(%d) ==> ", explevel);
3177c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), xbuf);
3187c478bd9Sstevel@tonic-gate 		sm_dprintf("\n");
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* recurse as appropriate */
3227c478bd9Sstevel@tonic-gate 	if (recurse)
3237c478bd9Sstevel@tonic-gate 	{
3247c478bd9Sstevel@tonic-gate 		if (explevel < MaxMacroRecursion)
3257c478bd9Sstevel@tonic-gate 		{
326058561cbSjbeck 			doexpand(xbuf, buf, bufsize, explevel + 1, e);
3277c478bd9Sstevel@tonic-gate 			return;
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 		syserr("expand: recursion too deep (%d max)",
3307c478bd9Sstevel@tonic-gate 			MaxMacroRecursion);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/* copy results out */
334058561cbSjbeck 	if (explevel == 0)
335058561cbSjbeck 		(void) sm_strlcpy(buf, xbuf, bufsize);
336058561cbSjbeck 	else
337058561cbSjbeck 	{
338058561cbSjbeck 		/* leave in internal form */
3397c478bd9Sstevel@tonic-gate 		i = xp - xbuf;
3407c478bd9Sstevel@tonic-gate 		if (i >= bufsize)
3417c478bd9Sstevel@tonic-gate 			i = bufsize - 1;
3427c478bd9Sstevel@tonic-gate 		memmove(buf, xbuf, i);
3437c478bd9Sstevel@tonic-gate 		buf[i] = '\0';
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
346058561cbSjbeck 	if (tTd(35, 24))
347058561cbSjbeck 	{
348058561cbSjbeck 		sm_dprintf("expand ==> ");
349058561cbSjbeck 		xputs(sm_debug_file(), buf);
350058561cbSjbeck 		sm_dprintf("\n");
351058561cbSjbeck 	}
352058561cbSjbeck }
353058561cbSjbeck 
354058561cbSjbeck void
expand(s,buf,bufsize,e)355058561cbSjbeck expand(s, buf, bufsize, e)
356058561cbSjbeck 	char *s;
357058561cbSjbeck 	char *buf;
358058561cbSjbeck 	size_t bufsize;
359058561cbSjbeck 	ENVELOPE *e;
360058561cbSjbeck {
361058561cbSjbeck 	doexpand(s, buf, bufsize, 0, e);
362058561cbSjbeck }
363058561cbSjbeck 
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate **  MACDEFINE -- bind a macro name to a value
3667c478bd9Sstevel@tonic-gate **
3677c478bd9Sstevel@tonic-gate **	Set a macro to a value, with fancy storage management.
3687c478bd9Sstevel@tonic-gate **	macdefine will make a copy of the value, if required,
3697c478bd9Sstevel@tonic-gate **	and will ensure that the storage for the previous value
3707c478bd9Sstevel@tonic-gate **	is not leaked.
3717c478bd9Sstevel@tonic-gate **
3727c478bd9Sstevel@tonic-gate **	Parameters:
3737c478bd9Sstevel@tonic-gate **		mac -- Macro table.
3747c478bd9Sstevel@tonic-gate **		vclass -- storage class of 'value', ignored if value==NULL.
3757c478bd9Sstevel@tonic-gate **			A_HEAP	means that the value was allocated by
3767c478bd9Sstevel@tonic-gate **				malloc, and that macdefine owns the storage.
3777c478bd9Sstevel@tonic-gate **			A_TEMP	means that value points to temporary storage,
3787c478bd9Sstevel@tonic-gate **				and thus macdefine needs to make a copy.
3797c478bd9Sstevel@tonic-gate **			A_PERM	means that value points to storage that
3807c478bd9Sstevel@tonic-gate **				will remain allocated and unchanged for
3817c478bd9Sstevel@tonic-gate **				at least the lifetime of mac.  Use A_PERM if:
3827c478bd9Sstevel@tonic-gate **				-- value == NULL,
3837c478bd9Sstevel@tonic-gate **				-- value points to a string literal,
3847c478bd9Sstevel@tonic-gate **				-- value was allocated from mac->mac_rpool
3857c478bd9Sstevel@tonic-gate **				   or (in the case of an envelope macro)
3867c478bd9Sstevel@tonic-gate **				   from e->e_rpool,
3877c478bd9Sstevel@tonic-gate **				-- in the case of an envelope macro,
3887c478bd9Sstevel@tonic-gate **				   value is a string member of the envelope
3897c478bd9Sstevel@tonic-gate **				   such as e->e_sender.
3907c478bd9Sstevel@tonic-gate **		id -- Macro id.  This is a single character macro name
3917c478bd9Sstevel@tonic-gate **			such as 'g', or a value returned by macid().
3927c478bd9Sstevel@tonic-gate **		value -- Macro value: either NULL, or a string.
3937c478bd9Sstevel@tonic-gate */
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate void
3967c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
macdefine_tagged(mac,vclass,id,value,file,line,grp)3977c478bd9Sstevel@tonic-gate macdefine_tagged(mac, vclass, id, value, file, line, grp)
3987c478bd9Sstevel@tonic-gate #else /* SM_HEAP_CHECK */
3997c478bd9Sstevel@tonic-gate macdefine(mac, vclass, id, value)
4007c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
4017c478bd9Sstevel@tonic-gate 	MACROS_T *mac;
4027c478bd9Sstevel@tonic-gate 	ARGCLASS_T vclass;
4037c478bd9Sstevel@tonic-gate 	int id;
4047c478bd9Sstevel@tonic-gate 	char *value;
4057c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
4067c478bd9Sstevel@tonic-gate 	char *file;
4077c478bd9Sstevel@tonic-gate 	int line;
4087c478bd9Sstevel@tonic-gate 	int grp;
4097c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	char *newvalue;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (id < 0 || id > MAXMACROID)
4147c478bd9Sstevel@tonic-gate 		return;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (tTd(35, 9))
4177c478bd9Sstevel@tonic-gate 	{
4187c478bd9Sstevel@tonic-gate 		sm_dprintf("%sdefine(%s as ",
4197c478bd9Sstevel@tonic-gate 			mac->mac_table[id] == NULL ? "" : "re", macname(id));
4207c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), value);
4217c478bd9Sstevel@tonic-gate 		sm_dprintf(")\n");
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (mac->mac_rpool == NULL)
4257c478bd9Sstevel@tonic-gate 	{
4267c478bd9Sstevel@tonic-gate 		char *freeit = NULL;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		if (mac->mac_table[id] != NULL &&
4297c478bd9Sstevel@tonic-gate 		    bitnset(id, mac->mac_allocated))
4307c478bd9Sstevel@tonic-gate 			freeit = mac->mac_table[id];
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 		if (value == NULL || vclass == A_HEAP)
4337c478bd9Sstevel@tonic-gate 		{
4347c478bd9Sstevel@tonic-gate 			sm_heap_checkptr_tagged(value, file, line);
4357c478bd9Sstevel@tonic-gate 			newvalue = value;
4367c478bd9Sstevel@tonic-gate 			clrbitn(id, mac->mac_allocated);
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 		else
4397c478bd9Sstevel@tonic-gate 		{
4407c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK
4417c478bd9Sstevel@tonic-gate 			newvalue = sm_strdup_tagged_x(value, file, line, 0);
4427c478bd9Sstevel@tonic-gate #else /* SM_HEAP_CHECK */
4437c478bd9Sstevel@tonic-gate 			newvalue = sm_strdup_x(value);
4447c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */
4457c478bd9Sstevel@tonic-gate 			setbitn(id, mac->mac_allocated);
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 		mac->mac_table[id] = newvalue;
4487c478bd9Sstevel@tonic-gate 		if (freeit != NULL)
4497c478bd9Sstevel@tonic-gate 			sm_free(freeit);
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 	else
4527c478bd9Sstevel@tonic-gate 	{
4537c478bd9Sstevel@tonic-gate 		if (value == NULL || vclass == A_PERM)
4547c478bd9Sstevel@tonic-gate 			newvalue = value;
4557c478bd9Sstevel@tonic-gate 		else
4567c478bd9Sstevel@tonic-gate 			newvalue = sm_rpool_strdup_x(mac->mac_rpool, value);
4577c478bd9Sstevel@tonic-gate 		mac->mac_table[id] = newvalue;
4587c478bd9Sstevel@tonic-gate 		if (vclass == A_HEAP)
4597c478bd9Sstevel@tonic-gate 			sm_free(value);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate #if _FFR_RESET_MACRO_GLOBALS
4637c478bd9Sstevel@tonic-gate 	switch (id)
4647c478bd9Sstevel@tonic-gate 	{
4657c478bd9Sstevel@tonic-gate 	  case 'j':
4667c478bd9Sstevel@tonic-gate 		PSTRSET(MyHostName, value);
4677c478bd9Sstevel@tonic-gate 		break;
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate #endif /* _FFR_RESET_MACRO_GLOBALS */
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate **  MACSET -- set a named macro to a value (low level)
4747c478bd9Sstevel@tonic-gate **
4757c478bd9Sstevel@tonic-gate **	No fancy storage management; the caller takes full responsibility.
4767c478bd9Sstevel@tonic-gate **	Often used with macget; see also macdefine.
4777c478bd9Sstevel@tonic-gate **
4787c478bd9Sstevel@tonic-gate **	Parameters:
4797c478bd9Sstevel@tonic-gate **		mac -- Macro table.
4807c478bd9Sstevel@tonic-gate **		i -- Macro name, specified as an integer offset.
4817c478bd9Sstevel@tonic-gate **		value -- Macro value: either NULL, or a string.
4827c478bd9Sstevel@tonic-gate */
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate void
macset(mac,i,value)4857c478bd9Sstevel@tonic-gate macset(mac, i, value)
4867c478bd9Sstevel@tonic-gate 	MACROS_T *mac;
4877c478bd9Sstevel@tonic-gate 	int i;
4887c478bd9Sstevel@tonic-gate 	char *value;
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate 	if (i < 0 || i > MAXMACROID)
4917c478bd9Sstevel@tonic-gate 		return;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (tTd(35, 9))
4947c478bd9Sstevel@tonic-gate 	{
4957c478bd9Sstevel@tonic-gate 		sm_dprintf("macset(%s as ", macname(i));
4967c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), value);
4977c478bd9Sstevel@tonic-gate 		sm_dprintf(")\n");
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 	mac->mac_table[i] = value;
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate **  MACVALUE -- return uninterpreted value of a macro.
5047c478bd9Sstevel@tonic-gate **
5057c478bd9Sstevel@tonic-gate **	Does fancy path searching.
5067c478bd9Sstevel@tonic-gate **	The low level counterpart is macget.
5077c478bd9Sstevel@tonic-gate **
5087c478bd9Sstevel@tonic-gate **	Parameters:
5097c478bd9Sstevel@tonic-gate **		n -- the name of the macro.
5107c478bd9Sstevel@tonic-gate **		e -- envelope in which to start looking for the macro.
5117c478bd9Sstevel@tonic-gate **
5127c478bd9Sstevel@tonic-gate **	Returns:
5137c478bd9Sstevel@tonic-gate **		The value of n.
5147c478bd9Sstevel@tonic-gate **
5157c478bd9Sstevel@tonic-gate **	Side Effects:
5167c478bd9Sstevel@tonic-gate **		none.
5177c478bd9Sstevel@tonic-gate */
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate char *
macvalue(n,e)5207c478bd9Sstevel@tonic-gate macvalue(n, e)
5217c478bd9Sstevel@tonic-gate 	int n;
522058561cbSjbeck 	ENVELOPE *e;
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	n = bitidx(n);
5257c478bd9Sstevel@tonic-gate 	if (e != NULL && e->e_mci != NULL)
5267c478bd9Sstevel@tonic-gate 	{
527058561cbSjbeck 		char *p = e->e_mci->mci_macro.mac_table[n];
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 		if (p != NULL)
5307c478bd9Sstevel@tonic-gate 			return p;
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 	while (e != NULL)
5337c478bd9Sstevel@tonic-gate 	{
534058561cbSjbeck 		char *p = e->e_macro.mac_table[n];
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 		if (p != NULL)
5377c478bd9Sstevel@tonic-gate 			return p;
5387c478bd9Sstevel@tonic-gate 		if (e == e->e_parent)
5397c478bd9Sstevel@tonic-gate 			break;
5407c478bd9Sstevel@tonic-gate 		e = e->e_parent;
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 	return GlobalMacros.mac_table[n];
5437c478bd9Sstevel@tonic-gate }
544058561cbSjbeck 
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate **  MACNAME -- return the name of a macro given its internal id
5477c478bd9Sstevel@tonic-gate **
5487c478bd9Sstevel@tonic-gate **	Parameter:
5497c478bd9Sstevel@tonic-gate **		n -- the id of the macro
5507c478bd9Sstevel@tonic-gate **
5517c478bd9Sstevel@tonic-gate **	Returns:
5527c478bd9Sstevel@tonic-gate **		The name of n.
5537c478bd9Sstevel@tonic-gate **
5547c478bd9Sstevel@tonic-gate **	Side Effects:
5557c478bd9Sstevel@tonic-gate **		none.
556058561cbSjbeck **
557058561cbSjbeck **	WARNING:
558058561cbSjbeck **		Not thread-safe.
5597c478bd9Sstevel@tonic-gate */
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate char *
macname(n)5627c478bd9Sstevel@tonic-gate macname(n)
5637c478bd9Sstevel@tonic-gate 	int n;
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	static char mbuf[2];
5667c478bd9Sstevel@tonic-gate 
567058561cbSjbeck 	n = (int)(unsigned char)n;
568058561cbSjbeck 	if (n > MAXMACROID)
569058561cbSjbeck 		return "***OUT OF RANGE MACRO***";
570058561cbSjbeck 
571058561cbSjbeck 	/* if not ASCII printable, look up the name */
572058561cbSjbeck 	if (n <= 0x20 || n > 0x7f)
5737c478bd9Sstevel@tonic-gate 	{
5747c478bd9Sstevel@tonic-gate 		char *p = MacroName[n];
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		if (p != NULL)
5777c478bd9Sstevel@tonic-gate 			return p;
5787c478bd9Sstevel@tonic-gate 		return "***UNDEFINED MACRO***";
5797c478bd9Sstevel@tonic-gate 	}
580058561cbSjbeck 
581058561cbSjbeck 	/* if in the ASCII graphic range, just return the id directly */
5827c478bd9Sstevel@tonic-gate 	mbuf[0] = n;
5837c478bd9Sstevel@tonic-gate 	mbuf[1] = '\0';
5847c478bd9Sstevel@tonic-gate 	return mbuf;
5857c478bd9Sstevel@tonic-gate }
586058561cbSjbeck 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate **  MACID_PARSE -- return id of macro identified by its name
5897c478bd9Sstevel@tonic-gate **
5907c478bd9Sstevel@tonic-gate **	Parameters:
5917c478bd9Sstevel@tonic-gate **		p -- pointer to name string -- either a single
5927c478bd9Sstevel@tonic-gate **			character or {name}.
5937c478bd9Sstevel@tonic-gate **		ep -- filled in with the pointer to the byte
5947c478bd9Sstevel@tonic-gate **			after the name.
5957c478bd9Sstevel@tonic-gate **
5967c478bd9Sstevel@tonic-gate **	Returns:
5977c478bd9Sstevel@tonic-gate **		0 -- An error was detected.
598058561cbSjbeck **		1..MAXMACROID -- The internal id code for this macro.
5997c478bd9Sstevel@tonic-gate **
6007c478bd9Sstevel@tonic-gate **	Side Effects:
6017c478bd9Sstevel@tonic-gate **		If this is a new macro name, a new id is allocated.
6027c478bd9Sstevel@tonic-gate **		On error, syserr is called.
6037c478bd9Sstevel@tonic-gate */
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate int
macid_parse(p,ep)6067c478bd9Sstevel@tonic-gate macid_parse(p, ep)
607058561cbSjbeck 	char *p;
6087c478bd9Sstevel@tonic-gate 	char **ep;
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int mid;
611058561cbSjbeck 	char *bp;
6127c478bd9Sstevel@tonic-gate 	char mbuf[MAXMACNAMELEN + 1];
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if (tTd(35, 14))
6157c478bd9Sstevel@tonic-gate 	{
6167c478bd9Sstevel@tonic-gate 		sm_dprintf("macid(");
6177c478bd9Sstevel@tonic-gate 		xputs(sm_debug_file(), p);
6187c478bd9Sstevel@tonic-gate 		sm_dprintf(") => ");
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
6227c478bd9Sstevel@tonic-gate 	{
6237c478bd9Sstevel@tonic-gate 		syserr("Name required for macro/class");
6247c478bd9Sstevel@tonic-gate 		if (ep != NULL)
6257c478bd9Sstevel@tonic-gate 			*ep = p;
6267c478bd9Sstevel@tonic-gate 		if (tTd(35, 14))
6277c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL\n");
6287c478bd9Sstevel@tonic-gate 		return 0;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 	if (*p != '{')
6317c478bd9Sstevel@tonic-gate 	{
6327c478bd9Sstevel@tonic-gate 		/* the macro is its own code */
6337c478bd9Sstevel@tonic-gate 		if (ep != NULL)
6347c478bd9Sstevel@tonic-gate 			*ep = p + 1;
6357c478bd9Sstevel@tonic-gate 		if (tTd(35, 14))
636058561cbSjbeck 		{
637058561cbSjbeck 			char buf[2];
638058561cbSjbeck 
639058561cbSjbeck 			buf[0] = *p;
640058561cbSjbeck 			buf[1] = '\0';
641058561cbSjbeck 			xputs(sm_debug_file(), buf);
642058561cbSjbeck 			sm_dprintf("\n");
643058561cbSjbeck 		}
6447c478bd9Sstevel@tonic-gate 		return bitidx(*p);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 	bp = mbuf;
647058561cbSjbeck 	while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof(mbuf) - 1])
6487c478bd9Sstevel@tonic-gate 	{
6497c478bd9Sstevel@tonic-gate 		if (isascii(*p) && (isalnum(*p) || *p == '_'))
6507c478bd9Sstevel@tonic-gate 			*bp++ = *p;
6517c478bd9Sstevel@tonic-gate 		else
6527c478bd9Sstevel@tonic-gate 			syserr("Invalid macro/class character %c", *p);
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	*bp = '\0';
6557c478bd9Sstevel@tonic-gate 	mid = -1;
6567c478bd9Sstevel@tonic-gate 	if (*p == '\0')
6577c478bd9Sstevel@tonic-gate 	{
6587c478bd9Sstevel@tonic-gate 		syserr("Unbalanced { on %s", mbuf);	/* missing } */
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 	else if (*p != '}')
6617c478bd9Sstevel@tonic-gate 	{
6627c478bd9Sstevel@tonic-gate 		syserr("Macro/class name ({%s}) too long (%d chars max)",
663058561cbSjbeck 			mbuf, (int) (sizeof(mbuf) - 1));
6647c478bd9Sstevel@tonic-gate 	}
665*7800901eSjbeck 	else if (mbuf[1] == '\0' && mbuf[0] >= 0x20)
6667c478bd9Sstevel@tonic-gate 	{
6677c478bd9Sstevel@tonic-gate 		/* ${x} == $x */
6687c478bd9Sstevel@tonic-gate 		mid = bitidx(mbuf[0]);
6697c478bd9Sstevel@tonic-gate 		p++;
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 	else
6727c478bd9Sstevel@tonic-gate 	{
673058561cbSjbeck 		STAB *s;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		s = stab(mbuf, ST_MACRO, ST_ENTER);
6767c478bd9Sstevel@tonic-gate 		if (s->s_macro != 0)
6777c478bd9Sstevel@tonic-gate 			mid = s->s_macro;
6787c478bd9Sstevel@tonic-gate 		else
6797c478bd9Sstevel@tonic-gate 		{
6807c478bd9Sstevel@tonic-gate 			if (NextMacroId > MAXMACROID)
6817c478bd9Sstevel@tonic-gate 			{
6827c478bd9Sstevel@tonic-gate 				syserr("Macro/class {%s}: too many long names",
6837c478bd9Sstevel@tonic-gate 					mbuf);
6847c478bd9Sstevel@tonic-gate 				s->s_macro = -1;
6857c478bd9Sstevel@tonic-gate 			}
6867c478bd9Sstevel@tonic-gate 			else
6877c478bd9Sstevel@tonic-gate 			{
6887c478bd9Sstevel@tonic-gate 				MacroName[NextMacroId] = s->s_name;
689*7800901eSjbeck 				s->s_macro = mid = NextMacroId;
690*7800901eSjbeck 				NextMacroId = NEXTMACROID(NextMacroId);
6917c478bd9Sstevel@tonic-gate 			}
6927c478bd9Sstevel@tonic-gate 		}
6937c478bd9Sstevel@tonic-gate 		p++;
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 	if (ep != NULL)
6967c478bd9Sstevel@tonic-gate 		*ep = p;
6977c478bd9Sstevel@tonic-gate 	if (mid < 0 || mid > MAXMACROID)
6987c478bd9Sstevel@tonic-gate 	{
6997c478bd9Sstevel@tonic-gate 		syserr("Unable to assign macro/class ID (mid = 0x%x)", mid);
7007c478bd9Sstevel@tonic-gate 		if (tTd(35, 14))
7017c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL\n");
7027c478bd9Sstevel@tonic-gate 		return 0;
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 	if (tTd(35, 14))
7057c478bd9Sstevel@tonic-gate 		sm_dprintf("0x%x\n", mid);
7067c478bd9Sstevel@tonic-gate 	return mid;
7077c478bd9Sstevel@tonic-gate }
708058561cbSjbeck 
7097c478bd9Sstevel@tonic-gate /*
7107c478bd9Sstevel@tonic-gate **  WORDINCLASS -- tell if a word is in a specific class
7117c478bd9Sstevel@tonic-gate **
7127c478bd9Sstevel@tonic-gate **	Parameters:
7137c478bd9Sstevel@tonic-gate **		str -- the name of the word to look up.
7147c478bd9Sstevel@tonic-gate **		cl -- the class name.
7157c478bd9Sstevel@tonic-gate **
7167c478bd9Sstevel@tonic-gate **	Returns:
7177c478bd9Sstevel@tonic-gate **		true if str can be found in cl.
7187c478bd9Sstevel@tonic-gate **		false otherwise.
7197c478bd9Sstevel@tonic-gate */
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate bool
wordinclass(str,cl)7227c478bd9Sstevel@tonic-gate wordinclass(str, cl)
7237c478bd9Sstevel@tonic-gate 	char *str;
7247c478bd9Sstevel@tonic-gate 	int cl;
7257c478bd9Sstevel@tonic-gate {
726058561cbSjbeck 	STAB *s;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	s = stab(str, ST_CLASS, ST_FIND);
7297c478bd9Sstevel@tonic-gate 	return s != NULL && bitnset(bitidx(cl), s->s_class);
7307c478bd9Sstevel@tonic-gate }
731