xref: /freebsd/contrib/sendmail/src/macro.c (revision 40266059)
1c2aa98e2SPeter Wemm /*
2602a2b1bSGregory Neil Shapiro  * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
15c2aa98e2SPeter Wemm 
1640266059SGregory Neil Shapiro SM_RCSID("@(#)$Id: macro.c,v 8.86 2001/09/11 04:05:14 gshapiro Exp $")
1740266059SGregory Neil Shapiro 
18193538b7SGregory Neil Shapiro #if MAXMACROID != (BITMAPBITS - 1)
19193538b7SGregory Neil Shapiro 	ERROR Read the comment in conf.h
20193538b7SGregory Neil Shapiro #endif /* MAXMACROID != (BITMAPBITS - 1) */
21c2aa98e2SPeter Wemm 
2240266059SGregory Neil Shapiro static char	*MacroName[MAXMACROID + 1];	/* macro id to name table */
23193538b7SGregory Neil Shapiro int		NextMacroId = 0240;	/* codes for long named macros */
24c2aa98e2SPeter Wemm 
25c2aa98e2SPeter Wemm /*
2640266059SGregory Neil Shapiro **  INITMACROS -- initialize the macro system
2740266059SGregory Neil Shapiro **
2840266059SGregory Neil Shapiro **	This just involves defining some macros that are actually
2940266059SGregory Neil Shapiro **	used internally as metasymbols to be themselves.
3040266059SGregory Neil Shapiro **
3140266059SGregory Neil Shapiro **	Parameters:
3240266059SGregory Neil Shapiro **		none.
3340266059SGregory Neil Shapiro **
3440266059SGregory Neil Shapiro **	Returns:
3540266059SGregory Neil Shapiro **		none.
3640266059SGregory Neil Shapiro **
3740266059SGregory Neil Shapiro **	Side Effects:
3840266059SGregory Neil Shapiro **		initializes several macros to be themselves.
3940266059SGregory Neil Shapiro */
4040266059SGregory Neil Shapiro 
4140266059SGregory Neil Shapiro struct metamac	MetaMacros[] =
4240266059SGregory Neil Shapiro {
4340266059SGregory Neil Shapiro 	/* LHS pattern matching characters */
4440266059SGregory Neil Shapiro 	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
4540266059SGregory Neil Shapiro 	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
4640266059SGregory Neil Shapiro 
4740266059SGregory Neil Shapiro 	/* these are RHS metasymbols */
4840266059SGregory Neil Shapiro 	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
4940266059SGregory Neil Shapiro 	{ '>', CALLSUBR },
5040266059SGregory Neil Shapiro 
5140266059SGregory Neil Shapiro 	/* the conditional operations */
5240266059SGregory Neil Shapiro 	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
5340266059SGregory Neil Shapiro 
5440266059SGregory Neil Shapiro 	/* the hostname lookup characters */
5540266059SGregory Neil Shapiro 	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
5640266059SGregory Neil Shapiro 	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
5740266059SGregory Neil Shapiro 
5840266059SGregory Neil Shapiro 	/* miscellaneous control characters */
5940266059SGregory Neil Shapiro 	{ '&', MACRODEXPAND },
6040266059SGregory Neil Shapiro 
6140266059SGregory Neil Shapiro 	{ '\0', '\0' }
6240266059SGregory Neil Shapiro };
6340266059SGregory Neil Shapiro 
6440266059SGregory Neil Shapiro #define MACBINDING(name, mid) \
6540266059SGregory Neil Shapiro 		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
6640266059SGregory Neil Shapiro 		MacroName[mid] = name;
6740266059SGregory Neil Shapiro 
6840266059SGregory Neil Shapiro void
6940266059SGregory Neil Shapiro initmacros(e)
7040266059SGregory Neil Shapiro 	register ENVELOPE *e;
7140266059SGregory Neil Shapiro {
7240266059SGregory Neil Shapiro 	register struct metamac *m;
7340266059SGregory Neil Shapiro 	register int c;
7440266059SGregory Neil Shapiro 	char buf[5];
7540266059SGregory Neil Shapiro 
7640266059SGregory Neil Shapiro 	for (m = MetaMacros; m->metaname != '\0'; m++)
7740266059SGregory Neil Shapiro 	{
7840266059SGregory Neil Shapiro 		buf[0] = m->metaval;
7940266059SGregory Neil Shapiro 		buf[1] = '\0';
8040266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, m->metaname, buf);
8140266059SGregory Neil Shapiro 	}
8240266059SGregory Neil Shapiro 	buf[0] = MATCHREPL;
8340266059SGregory Neil Shapiro 	buf[2] = '\0';
8440266059SGregory Neil Shapiro 	for (c = '0'; c <= '9'; c++)
8540266059SGregory Neil Shapiro 	{
8640266059SGregory Neil Shapiro 		buf[1] = c;
8740266059SGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, c, buf);
8840266059SGregory Neil Shapiro 	}
8940266059SGregory Neil Shapiro 
9040266059SGregory Neil Shapiro 	/* set defaults for some macros sendmail will use later */
9140266059SGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'n', "MAILER-DAEMON");
9240266059SGregory Neil Shapiro 
9340266059SGregory Neil Shapiro 	/* set up external names for some internal macros */
9440266059SGregory Neil Shapiro 	MACBINDING("opMode", MID_OPMODE);
9540266059SGregory Neil Shapiro 	/*XXX should probably add equivalents for all short macros here XXX*/
9640266059SGregory Neil Shapiro }
9740266059SGregory Neil Shapiro /*
98c2aa98e2SPeter Wemm **  EXPAND -- macro expand a string using $x escapes.
99c2aa98e2SPeter Wemm **
100c2aa98e2SPeter Wemm **	Parameters:
101c2aa98e2SPeter Wemm **		s -- the string to expand.
102c2aa98e2SPeter Wemm **		buf -- the place to put the expansion.
103c2aa98e2SPeter Wemm **		bufsize -- the size of the buffer.
104c2aa98e2SPeter Wemm **		e -- envelope in which to work.
105c2aa98e2SPeter Wemm **
106c2aa98e2SPeter Wemm **	Returns:
107c2aa98e2SPeter Wemm **		none.
108c2aa98e2SPeter Wemm **
109c2aa98e2SPeter Wemm **	Side Effects:
110c2aa98e2SPeter Wemm **		none.
111c2aa98e2SPeter Wemm */
112c2aa98e2SPeter Wemm 
113c2aa98e2SPeter Wemm void
114c2aa98e2SPeter Wemm expand(s, buf, bufsize, e)
115c2aa98e2SPeter Wemm 	register char *s;
116c2aa98e2SPeter Wemm 	register char *buf;
117c2aa98e2SPeter Wemm 	size_t bufsize;
118c2aa98e2SPeter Wemm 	register ENVELOPE *e;
119c2aa98e2SPeter Wemm {
120c2aa98e2SPeter Wemm 	register char *xp;
121c2aa98e2SPeter Wemm 	register char *q;
122c2aa98e2SPeter Wemm 	bool skipping;		/* set if conditionally skipping output */
12340266059SGregory Neil Shapiro 	bool recurse;		/* set if recursion required */
12440266059SGregory Neil Shapiro 	size_t i;
125c2aa98e2SPeter Wemm 	int skiplev;		/* skipping nesting level */
126c2aa98e2SPeter Wemm 	int iflev;		/* if nesting level */
127c2aa98e2SPeter Wemm 	char xbuf[MACBUFSIZE];
128c2aa98e2SPeter Wemm 	static int explevel = 0;
129c2aa98e2SPeter Wemm 
130c2aa98e2SPeter Wemm 	if (tTd(35, 24))
131c2aa98e2SPeter Wemm 	{
13240266059SGregory Neil Shapiro 		sm_dprintf("expand(");
133c2aa98e2SPeter Wemm 		xputs(s);
13440266059SGregory Neil Shapiro 		sm_dprintf(")\n");
135c2aa98e2SPeter Wemm 	}
136c2aa98e2SPeter Wemm 
13740266059SGregory Neil Shapiro 	recurse = false;
13840266059SGregory Neil Shapiro 	skipping = false;
139c2aa98e2SPeter Wemm 	skiplev = 0;
140c2aa98e2SPeter Wemm 	iflev = 0;
141c2aa98e2SPeter Wemm 	if (s == NULL)
142c2aa98e2SPeter Wemm 		s = "";
143c2aa98e2SPeter Wemm 	for (xp = xbuf; *s != '\0'; s++)
144c2aa98e2SPeter Wemm 	{
145c2aa98e2SPeter Wemm 		int c;
146c2aa98e2SPeter Wemm 
147c2aa98e2SPeter Wemm 		/*
148c2aa98e2SPeter Wemm 		**  Check for non-ordinary (special?) character.
149c2aa98e2SPeter Wemm 		**	'q' will be the interpolated quantity.
150c2aa98e2SPeter Wemm 		*/
151c2aa98e2SPeter Wemm 
152c2aa98e2SPeter Wemm 		q = NULL;
153c2aa98e2SPeter Wemm 		c = *s;
154c2aa98e2SPeter Wemm 		switch (c & 0377)
155c2aa98e2SPeter Wemm 		{
156c2aa98e2SPeter Wemm 		  case CONDIF:		/* see if var set */
157c2aa98e2SPeter Wemm 			iflev++;
158c2aa98e2SPeter Wemm 			c = *++s;
159c2aa98e2SPeter Wemm 			if (skipping)
160c2aa98e2SPeter Wemm 				skiplev++;
161c2aa98e2SPeter Wemm 			else
16206f25ae9SGregory Neil Shapiro 			{
16306f25ae9SGregory Neil Shapiro 				char *mv;
16406f25ae9SGregory Neil Shapiro 
16506f25ae9SGregory Neil Shapiro 				mv = macvalue(c, e);
16606f25ae9SGregory Neil Shapiro 				skipping = (mv == NULL || *mv == '\0');
16706f25ae9SGregory Neil Shapiro 			}
168c2aa98e2SPeter Wemm 			continue;
169c2aa98e2SPeter Wemm 
170c2aa98e2SPeter Wemm 		  case CONDELSE:	/* change state of skipping */
171c2aa98e2SPeter Wemm 			if (iflev == 0)
17240266059SGregory Neil Shapiro 				break;	/* XXX: error */
173c2aa98e2SPeter Wemm 			if (skiplev == 0)
174c2aa98e2SPeter Wemm 				skipping = !skipping;
175c2aa98e2SPeter Wemm 			continue;
176c2aa98e2SPeter Wemm 
177c2aa98e2SPeter Wemm 		  case CONDFI:		/* stop skipping */
178c2aa98e2SPeter Wemm 			if (iflev == 0)
17940266059SGregory Neil Shapiro 				break;	/* XXX: error */
180c2aa98e2SPeter Wemm 			iflev--;
181c2aa98e2SPeter Wemm 			if (skiplev == 0)
18240266059SGregory Neil Shapiro 				skipping = false;
183c2aa98e2SPeter Wemm 			if (skipping)
184c2aa98e2SPeter Wemm 				skiplev--;
185c2aa98e2SPeter Wemm 			continue;
186c2aa98e2SPeter Wemm 
187c2aa98e2SPeter Wemm 		  case MACROEXPAND:	/* macro interpolation */
188193538b7SGregory Neil Shapiro 			c = bitidx(*++s);
189c2aa98e2SPeter Wemm 			if (c != '\0')
190c2aa98e2SPeter Wemm 				q = macvalue(c, e);
191c2aa98e2SPeter Wemm 			else
192c2aa98e2SPeter Wemm 			{
193c2aa98e2SPeter Wemm 				s--;
194c2aa98e2SPeter Wemm 				q = NULL;
195c2aa98e2SPeter Wemm 			}
196c2aa98e2SPeter Wemm 			if (q == NULL)
197c2aa98e2SPeter Wemm 				continue;
198c2aa98e2SPeter Wemm 			break;
199c2aa98e2SPeter Wemm 		}
200c2aa98e2SPeter Wemm 
201c2aa98e2SPeter Wemm 		/*
202c2aa98e2SPeter Wemm 		**  Interpolate q or output one character
203c2aa98e2SPeter Wemm 		*/
204c2aa98e2SPeter Wemm 
205c2aa98e2SPeter Wemm 		if (skipping || xp >= &xbuf[sizeof xbuf - 1])
206c2aa98e2SPeter Wemm 			continue;
207c2aa98e2SPeter Wemm 		if (q == NULL)
208c2aa98e2SPeter Wemm 			*xp++ = c;
209c2aa98e2SPeter Wemm 		else
210c2aa98e2SPeter Wemm 		{
211c2aa98e2SPeter Wemm 			/* copy to end of q or max space remaining in buf */
212c2aa98e2SPeter Wemm 			while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
213c2aa98e2SPeter Wemm 			{
214c2aa98e2SPeter Wemm 				/* check for any sendmail metacharacters */
215c2aa98e2SPeter Wemm 				if ((c & 0340) == 0200)
21640266059SGregory Neil Shapiro 					recurse = true;
217c2aa98e2SPeter Wemm 				*xp++ = c;
218c2aa98e2SPeter Wemm 			}
219c2aa98e2SPeter Wemm 		}
220c2aa98e2SPeter Wemm 	}
221c2aa98e2SPeter Wemm 	*xp = '\0';
222c2aa98e2SPeter Wemm 
223c2aa98e2SPeter Wemm 	if (tTd(35, 24))
224c2aa98e2SPeter Wemm 	{
22540266059SGregory Neil Shapiro 		sm_dprintf("expand ==> ");
226c2aa98e2SPeter Wemm 		xputs(xbuf);
22740266059SGregory Neil Shapiro 		sm_dprintf("\n");
228c2aa98e2SPeter Wemm 	}
229c2aa98e2SPeter Wemm 
230c2aa98e2SPeter Wemm 	/* recurse as appropriate */
231c2aa98e2SPeter Wemm 	if (recurse)
232c2aa98e2SPeter Wemm 	{
233c2aa98e2SPeter Wemm 		if (explevel < MaxMacroRecursion)
234c2aa98e2SPeter Wemm 		{
235c2aa98e2SPeter Wemm 			explevel++;
236c2aa98e2SPeter Wemm 			expand(xbuf, buf, bufsize, e);
237c2aa98e2SPeter Wemm 			explevel--;
238c2aa98e2SPeter Wemm 			return;
239c2aa98e2SPeter Wemm 		}
240c2aa98e2SPeter Wemm 		syserr("expand: recursion too deep (%d max)",
241c2aa98e2SPeter Wemm 			MaxMacroRecursion);
242c2aa98e2SPeter Wemm 	}
243c2aa98e2SPeter Wemm 
244c2aa98e2SPeter Wemm 	/* copy results out */
245c2aa98e2SPeter Wemm 	i = xp - xbuf;
24640266059SGregory Neil Shapiro 	if (i >= bufsize)
247c2aa98e2SPeter Wemm 		i = bufsize - 1;
24806f25ae9SGregory Neil Shapiro 	memmove(buf, xbuf, i);
249c2aa98e2SPeter Wemm 	buf[i] = '\0';
250c2aa98e2SPeter Wemm }
25140266059SGregory Neil Shapiro 
25240266059SGregory Neil Shapiro /*
25340266059SGregory Neil Shapiro **  MACDEFINE -- bind a macro name to a value
254c2aa98e2SPeter Wemm **
25540266059SGregory Neil Shapiro **	Set a macro to a value, with fancy storage management.
25640266059SGregory Neil Shapiro **	macdefine will make a copy of the value, if required,
25740266059SGregory Neil Shapiro **	and will ensure that the storage for the previous value
25840266059SGregory Neil Shapiro **	is not leaked.
259c2aa98e2SPeter Wemm **
260c2aa98e2SPeter Wemm **	Parameters:
26140266059SGregory Neil Shapiro **		mac -- Macro table.
26240266059SGregory Neil Shapiro **		vclass -- storage class of 'value', ignored if value==NULL.
26340266059SGregory Neil Shapiro **			A_HEAP	means that the value was allocated by
26440266059SGregory Neil Shapiro **				malloc, and that macdefine owns the storage.
26540266059SGregory Neil Shapiro **			A_TEMP	means that value points to temporary storage,
26640266059SGregory Neil Shapiro **				and thus macdefine needs to make a copy.
26740266059SGregory Neil Shapiro **			A_PERM	means that value points to storage that
26840266059SGregory Neil Shapiro **				will remain allocated and unchanged for
26940266059SGregory Neil Shapiro **				at least the lifetime of mac.  Use A_PERM if:
27040266059SGregory Neil Shapiro **				-- value == NULL,
27140266059SGregory Neil Shapiro **				-- value points to a string literal,
27240266059SGregory Neil Shapiro **				-- value was allocated from mac->mac_rpool
27340266059SGregory Neil Shapiro **				   or (in the case of an envelope macro)
27440266059SGregory Neil Shapiro **				   from e->e_rpool,
27540266059SGregory Neil Shapiro **				-- in the case of an envelope macro,
27640266059SGregory Neil Shapiro **				   value is a string member of the envelope
27740266059SGregory Neil Shapiro **				   such as e->e_sender.
27840266059SGregory Neil Shapiro **		id -- Macro id.  This is a single character macro name
27940266059SGregory Neil Shapiro **			such as 'g', or a value returned by macid().
28040266059SGregory Neil Shapiro **		value -- Macro value: either NULL, or a string.
281c2aa98e2SPeter Wemm */
282c2aa98e2SPeter Wemm 
283c2aa98e2SPeter Wemm void
28440266059SGregory Neil Shapiro #if SM_HEAP_CHECK
28540266059SGregory Neil Shapiro macdefine_tagged(mac, vclass, id, value, file, line, grp)
28640266059SGregory Neil Shapiro #else /* SM_HEAP_CHECK */
28740266059SGregory Neil Shapiro macdefine(mac, vclass, id, value)
28840266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
28940266059SGregory Neil Shapiro 	MACROS_T *mac;
29040266059SGregory Neil Shapiro 	ARGCLASS_T vclass;
29140266059SGregory Neil Shapiro 	int id;
29240266059SGregory Neil Shapiro 	char *value;
29340266059SGregory Neil Shapiro #if SM_HEAP_CHECK
29440266059SGregory Neil Shapiro 	char *file;
29540266059SGregory Neil Shapiro 	int line;
29640266059SGregory Neil Shapiro 	int grp;
29740266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
298c2aa98e2SPeter Wemm {
29940266059SGregory Neil Shapiro 	char *newvalue;
30006f25ae9SGregory Neil Shapiro 
30140266059SGregory Neil Shapiro 	if (id < 0 || id > MAXMACROID)
30240266059SGregory Neil Shapiro 		return;
30340266059SGregory Neil Shapiro 
304c2aa98e2SPeter Wemm 	if (tTd(35, 9))
305c2aa98e2SPeter Wemm 	{
30640266059SGregory Neil Shapiro 		sm_dprintf("%sdefine(%s as ",
30740266059SGregory Neil Shapiro 			mac->mac_table[id] == NULL ? "" : "re", macname(id));
30840266059SGregory Neil Shapiro 		xputs(value);
30940266059SGregory Neil Shapiro 		sm_dprintf(")\n");
310c2aa98e2SPeter Wemm 	}
31140266059SGregory Neil Shapiro 
31240266059SGregory Neil Shapiro 	if (mac->mac_rpool == NULL)
31340266059SGregory Neil Shapiro 	{
31440266059SGregory Neil Shapiro 		char *freeit = NULL;
31540266059SGregory Neil Shapiro 
31640266059SGregory Neil Shapiro 		if (mac->mac_table[id] != NULL &&
31740266059SGregory Neil Shapiro 		    bitnset(id, mac->mac_allocated))
31840266059SGregory Neil Shapiro 			freeit = mac->mac_table[id];
31940266059SGregory Neil Shapiro 
32040266059SGregory Neil Shapiro 		if (value == NULL || vclass == A_HEAP)
32140266059SGregory Neil Shapiro 		{
32240266059SGregory Neil Shapiro 			sm_heap_checkptr_tagged(value, file, line);
32340266059SGregory Neil Shapiro 			newvalue = value;
32440266059SGregory Neil Shapiro 			clrbitn(id, mac->mac_allocated);
32540266059SGregory Neil Shapiro 		}
32640266059SGregory Neil Shapiro 		else
32740266059SGregory Neil Shapiro 		{
32840266059SGregory Neil Shapiro 			newvalue = sm_strdup_tagged_x(value, file, line, 0);
32940266059SGregory Neil Shapiro 			setbitn(id, mac->mac_allocated);
33040266059SGregory Neil Shapiro 		}
33140266059SGregory Neil Shapiro 		mac->mac_table[id] = newvalue;
33240266059SGregory Neil Shapiro 		if (freeit != NULL)
33340266059SGregory Neil Shapiro 			sm_free(freeit);
33440266059SGregory Neil Shapiro 	}
33540266059SGregory Neil Shapiro 	else
33640266059SGregory Neil Shapiro 	{
33740266059SGregory Neil Shapiro 		if (value == NULL || vclass == A_PERM)
33840266059SGregory Neil Shapiro 			newvalue = value;
33940266059SGregory Neil Shapiro 		else
34040266059SGregory Neil Shapiro 			newvalue = sm_rpool_strdup_x(mac->mac_rpool, value);
34140266059SGregory Neil Shapiro 		mac->mac_table[id] = newvalue;
34240266059SGregory Neil Shapiro 		if (vclass == A_HEAP)
34340266059SGregory Neil Shapiro 			sm_free(value);
34440266059SGregory Neil Shapiro 	}
34506f25ae9SGregory Neil Shapiro 
34606f25ae9SGregory Neil Shapiro #if _FFR_RESET_MACRO_GLOBALS
34740266059SGregory Neil Shapiro 	switch (id)
34806f25ae9SGregory Neil Shapiro 	{
34906f25ae9SGregory Neil Shapiro 	  case 'j':
35040266059SGregory Neil Shapiro 		PSTRSET(MyHostName, value);
35106f25ae9SGregory Neil Shapiro 		break;
35206f25ae9SGregory Neil Shapiro 	}
35306f25ae9SGregory Neil Shapiro #endif /* _FFR_RESET_MACRO_GLOBALS */
354c2aa98e2SPeter Wemm }
35540266059SGregory Neil Shapiro 
35640266059SGregory Neil Shapiro /*
35740266059SGregory Neil Shapiro **  MACSET -- set a named macro to a value (low level)
35840266059SGregory Neil Shapiro **
35940266059SGregory Neil Shapiro **	No fancy storage management; the caller takes full responsibility.
36040266059SGregory Neil Shapiro **	Often used with macget; see also macdefine.
36140266059SGregory Neil Shapiro **
36240266059SGregory Neil Shapiro **	Parameters:
36340266059SGregory Neil Shapiro **		mac -- Macro table.
36440266059SGregory Neil Shapiro **		i -- Macro name, specified as an integer offset.
36540266059SGregory Neil Shapiro **		value -- Macro value: either NULL, or a string.
36640266059SGregory Neil Shapiro */
36740266059SGregory Neil Shapiro 
36840266059SGregory Neil Shapiro void
36940266059SGregory Neil Shapiro macset(mac, i, value)
37040266059SGregory Neil Shapiro 	MACROS_T *mac;
37140266059SGregory Neil Shapiro 	int i;
37240266059SGregory Neil Shapiro 	char *value;
37340266059SGregory Neil Shapiro {
37440266059SGregory Neil Shapiro 	if (i < 0 || i > MAXMACROID)
37540266059SGregory Neil Shapiro 		return;
37640266059SGregory Neil Shapiro 
37740266059SGregory Neil Shapiro 	if (tTd(35, 9))
37840266059SGregory Neil Shapiro 	{
37940266059SGregory Neil Shapiro 		sm_dprintf("macset(%s as ", macname(i));
38040266059SGregory Neil Shapiro 		xputs(value);
38140266059SGregory Neil Shapiro 		sm_dprintf(")\n");
38240266059SGregory Neil Shapiro 	}
38340266059SGregory Neil Shapiro 	mac->mac_table[i] = value;
38440266059SGregory Neil Shapiro }
38540266059SGregory Neil Shapiro 
38640266059SGregory Neil Shapiro /*
387c2aa98e2SPeter Wemm **  MACVALUE -- return uninterpreted value of a macro.
388c2aa98e2SPeter Wemm **
38940266059SGregory Neil Shapiro **	Does fancy path searching.
39040266059SGregory Neil Shapiro **	The low level counterpart is macget.
39140266059SGregory Neil Shapiro **
392c2aa98e2SPeter Wemm **	Parameters:
393c2aa98e2SPeter Wemm **		n -- the name of the macro.
39440266059SGregory Neil Shapiro **		e -- envelope in which to start looking for the macro.
395c2aa98e2SPeter Wemm **
396c2aa98e2SPeter Wemm **	Returns:
397c2aa98e2SPeter Wemm **		The value of n.
398c2aa98e2SPeter Wemm **
399c2aa98e2SPeter Wemm **	Side Effects:
400c2aa98e2SPeter Wemm **		none.
401c2aa98e2SPeter Wemm */
402c2aa98e2SPeter Wemm 
403c2aa98e2SPeter Wemm char *
404c2aa98e2SPeter Wemm macvalue(n, e)
405c2aa98e2SPeter Wemm 	int n;
406c2aa98e2SPeter Wemm 	register ENVELOPE *e;
407c2aa98e2SPeter Wemm {
408193538b7SGregory Neil Shapiro 	n = bitidx(n);
40940266059SGregory Neil Shapiro 	if (e != NULL && e->e_mci != NULL)
41040266059SGregory Neil Shapiro 	{
41140266059SGregory Neil Shapiro 		register char *p = e->e_mci->mci_macro.mac_table[n];
41240266059SGregory Neil Shapiro 
41340266059SGregory Neil Shapiro 		if (p != NULL)
41440266059SGregory Neil Shapiro 			return p;
41540266059SGregory Neil Shapiro 	}
416c2aa98e2SPeter Wemm 	while (e != NULL)
417c2aa98e2SPeter Wemm 	{
41840266059SGregory Neil Shapiro 		register char *p = e->e_macro.mac_table[n];
419c2aa98e2SPeter Wemm 
420c2aa98e2SPeter Wemm 		if (p != NULL)
42106f25ae9SGregory Neil Shapiro 			return p;
422602a2b1bSGregory Neil Shapiro 		if (e == e->e_parent)
423602a2b1bSGregory Neil Shapiro 			break;
424c2aa98e2SPeter Wemm 		e = e->e_parent;
425c2aa98e2SPeter Wemm 	}
42640266059SGregory Neil Shapiro 	return GlobalMacros.mac_table[n];
427c2aa98e2SPeter Wemm }
42840266059SGregory Neil Shapiro /*
429c2aa98e2SPeter Wemm **  MACNAME -- return the name of a macro given its internal id
430c2aa98e2SPeter Wemm **
431c2aa98e2SPeter Wemm **	Parameter:
432c2aa98e2SPeter Wemm **		n -- the id of the macro
433c2aa98e2SPeter Wemm **
434c2aa98e2SPeter Wemm **	Returns:
435c2aa98e2SPeter Wemm **		The name of n.
436c2aa98e2SPeter Wemm **
437c2aa98e2SPeter Wemm **	Side Effects:
438c2aa98e2SPeter Wemm **		none.
439c2aa98e2SPeter Wemm */
440c2aa98e2SPeter Wemm 
441c2aa98e2SPeter Wemm char *
442c2aa98e2SPeter Wemm macname(n)
443c2aa98e2SPeter Wemm 	int n;
444c2aa98e2SPeter Wemm {
445c2aa98e2SPeter Wemm 	static char mbuf[2];
446c2aa98e2SPeter Wemm 
447193538b7SGregory Neil Shapiro 	n = bitidx(n);
448c2aa98e2SPeter Wemm 	if (bitset(0200, n))
449c2aa98e2SPeter Wemm 	{
450c2aa98e2SPeter Wemm 		char *p = MacroName[n];
451c2aa98e2SPeter Wemm 
452c2aa98e2SPeter Wemm 		if (p != NULL)
453c2aa98e2SPeter Wemm 			return p;
454c2aa98e2SPeter Wemm 		return "***UNDEFINED MACRO***";
455c2aa98e2SPeter Wemm 	}
456c2aa98e2SPeter Wemm 	mbuf[0] = n;
457c2aa98e2SPeter Wemm 	mbuf[1] = '\0';
458c2aa98e2SPeter Wemm 	return mbuf;
459c2aa98e2SPeter Wemm }
46040266059SGregory Neil Shapiro /*
46140266059SGregory Neil Shapiro **  MACID_PARSE -- return id of macro identified by its name
462c2aa98e2SPeter Wemm **
463c2aa98e2SPeter Wemm **	Parameters:
464c2aa98e2SPeter Wemm **		p -- pointer to name string -- either a single
465c2aa98e2SPeter Wemm **			character or {name}.
466c2aa98e2SPeter Wemm **		ep -- filled in with the pointer to the byte
467c2aa98e2SPeter Wemm **			after the name.
468c2aa98e2SPeter Wemm **
469c2aa98e2SPeter Wemm **	Returns:
47040266059SGregory Neil Shapiro **		0 -- An error was detected.
47140266059SGregory Neil Shapiro **		1..255 -- The internal id code for this macro.
472c2aa98e2SPeter Wemm **
473c2aa98e2SPeter Wemm **	Side Effects:
474c2aa98e2SPeter Wemm **		If this is a new macro name, a new id is allocated.
47540266059SGregory Neil Shapiro **		On error, syserr is called.
476c2aa98e2SPeter Wemm */
477c2aa98e2SPeter Wemm 
478c2aa98e2SPeter Wemm int
47940266059SGregory Neil Shapiro macid_parse(p, ep)
480c2aa98e2SPeter Wemm 	register char *p;
481c2aa98e2SPeter Wemm 	char **ep;
482c2aa98e2SPeter Wemm {
483c2aa98e2SPeter Wemm 	int mid;
484c2aa98e2SPeter Wemm 	register char *bp;
485065a643dSPeter Wemm 	char mbuf[MAXMACNAMELEN + 1];
486c2aa98e2SPeter Wemm 
487c2aa98e2SPeter Wemm 	if (tTd(35, 14))
488c2aa98e2SPeter Wemm 	{
48940266059SGregory Neil Shapiro 		sm_dprintf("macid(");
490c2aa98e2SPeter Wemm 		xputs(p);
49140266059SGregory Neil Shapiro 		sm_dprintf(") => ");
492c2aa98e2SPeter Wemm 	}
493c2aa98e2SPeter Wemm 
494c2aa98e2SPeter Wemm 	if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
495c2aa98e2SPeter Wemm 	{
496c2aa98e2SPeter Wemm 		syserr("Name required for macro/class");
497c2aa98e2SPeter Wemm 		if (ep != NULL)
498c2aa98e2SPeter Wemm 			*ep = p;
499c2aa98e2SPeter Wemm 		if (tTd(35, 14))
50040266059SGregory Neil Shapiro 			sm_dprintf("NULL\n");
501193538b7SGregory Neil Shapiro 		return 0;
502c2aa98e2SPeter Wemm 	}
503c2aa98e2SPeter Wemm 	if (*p != '{')
504c2aa98e2SPeter Wemm 	{
505c2aa98e2SPeter Wemm 		/* the macro is its own code */
506c2aa98e2SPeter Wemm 		if (ep != NULL)
507c2aa98e2SPeter Wemm 			*ep = p + 1;
508c2aa98e2SPeter Wemm 		if (tTd(35, 14))
50940266059SGregory Neil Shapiro 			sm_dprintf("%c\n", bitidx(*p));
510193538b7SGregory Neil Shapiro 		return bitidx(*p);
511c2aa98e2SPeter Wemm 	}
512c2aa98e2SPeter Wemm 	bp = mbuf;
513065a643dSPeter Wemm 	while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf - 1])
514c2aa98e2SPeter Wemm 	{
515c2aa98e2SPeter Wemm 		if (isascii(*p) && (isalnum(*p) || *p == '_'))
516c2aa98e2SPeter Wemm 			*bp++ = *p;
517c2aa98e2SPeter Wemm 		else
518c2aa98e2SPeter Wemm 			syserr("Invalid macro/class character %c", *p);
519c2aa98e2SPeter Wemm 	}
520c2aa98e2SPeter Wemm 	*bp = '\0';
521c2aa98e2SPeter Wemm 	mid = -1;
522c2aa98e2SPeter Wemm 	if (*p == '\0')
523c2aa98e2SPeter Wemm 	{
524c2aa98e2SPeter Wemm 		syserr("Unbalanced { on %s", mbuf);	/* missing } */
525c2aa98e2SPeter Wemm 	}
526c2aa98e2SPeter Wemm 	else if (*p != '}')
527c2aa98e2SPeter Wemm 	{
528c2aa98e2SPeter Wemm 		syserr("Macro/class name ({%s}) too long (%d chars max)",
52940266059SGregory Neil Shapiro 			mbuf, (int) (sizeof mbuf - 1));
530c2aa98e2SPeter Wemm 	}
531c2aa98e2SPeter Wemm 	else if (mbuf[1] == '\0')
532c2aa98e2SPeter Wemm 	{
533c2aa98e2SPeter Wemm 		/* ${x} == $x */
534193538b7SGregory Neil Shapiro 		mid = bitidx(mbuf[0]);
535c2aa98e2SPeter Wemm 		p++;
536c2aa98e2SPeter Wemm 	}
537c2aa98e2SPeter Wemm 	else
538c2aa98e2SPeter Wemm 	{
539c2aa98e2SPeter Wemm 		register STAB *s;
540c2aa98e2SPeter Wemm 
541c2aa98e2SPeter Wemm 		s = stab(mbuf, ST_MACRO, ST_ENTER);
542c2aa98e2SPeter Wemm 		if (s->s_macro != 0)
543c2aa98e2SPeter Wemm 			mid = s->s_macro;
544c2aa98e2SPeter Wemm 		else
545c2aa98e2SPeter Wemm 		{
54606f25ae9SGregory Neil Shapiro 			if (NextMacroId > MAXMACROID)
547c2aa98e2SPeter Wemm 			{
54840266059SGregory Neil Shapiro 				syserr("Macro/class {%s}: too many long names",
54940266059SGregory Neil Shapiro 					mbuf);
550c2aa98e2SPeter Wemm 				s->s_macro = -1;
551c2aa98e2SPeter Wemm 			}
552c2aa98e2SPeter Wemm 			else
553c2aa98e2SPeter Wemm 			{
554c2aa98e2SPeter Wemm 				MacroName[NextMacroId] = s->s_name;
555c2aa98e2SPeter Wemm 				s->s_macro = mid = NextMacroId++;
556c2aa98e2SPeter Wemm 			}
557c2aa98e2SPeter Wemm 		}
558c2aa98e2SPeter Wemm 		p++;
559c2aa98e2SPeter Wemm 	}
560c2aa98e2SPeter Wemm 	if (ep != NULL)
561c2aa98e2SPeter Wemm 		*ep = p;
562193538b7SGregory Neil Shapiro 	if (mid < 0 || mid > MAXMACROID)
563193538b7SGregory Neil Shapiro 	{
564193538b7SGregory Neil Shapiro 		syserr("Unable to assign macro/class ID (mid = 0x%x)", mid);
565193538b7SGregory Neil Shapiro 		if (tTd(35, 14))
56640266059SGregory Neil Shapiro 			sm_dprintf("NULL\n");
567193538b7SGregory Neil Shapiro 		return 0;
568193538b7SGregory Neil Shapiro 	}
569c2aa98e2SPeter Wemm 	if (tTd(35, 14))
57040266059SGregory Neil Shapiro 		sm_dprintf("0x%x\n", mid);
571c2aa98e2SPeter Wemm 	return mid;
572c2aa98e2SPeter Wemm }
57340266059SGregory Neil Shapiro /*
574c2aa98e2SPeter Wemm **  WORDINCLASS -- tell if a word is in a specific class
575c2aa98e2SPeter Wemm **
576c2aa98e2SPeter Wemm **	Parameters:
577c2aa98e2SPeter Wemm **		str -- the name of the word to look up.
578c2aa98e2SPeter Wemm **		cl -- the class name.
579c2aa98e2SPeter Wemm **
580c2aa98e2SPeter Wemm **	Returns:
58140266059SGregory Neil Shapiro **		true if str can be found in cl.
58240266059SGregory Neil Shapiro **		false otherwise.
583c2aa98e2SPeter Wemm */
584c2aa98e2SPeter Wemm 
585c2aa98e2SPeter Wemm bool
586c2aa98e2SPeter Wemm wordinclass(str, cl)
587c2aa98e2SPeter Wemm 	char *str;
588c2aa98e2SPeter Wemm 	int cl;
589c2aa98e2SPeter Wemm {
590c2aa98e2SPeter Wemm 	register STAB *s;
591c2aa98e2SPeter Wemm 
592c2aa98e2SPeter Wemm 	s = stab(str, ST_CLASS, ST_FIND);
593193538b7SGregory Neil Shapiro 	return s != NULL && bitnset(bitidx(cl), s->s_class);
594c2aa98e2SPeter Wemm }
595