138032Speter/*
2261194Sgshapiro * Copyright (c) 1998-2001, 2003, 2006, 2007 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16266527SgshapiroSM_RCSID("@(#)$Id: macro.c,v 8.108 2013-11-22 20:51:55 ca Exp $")
1790792Sgshapiro
18168515Sgshapiro#include <sm/sendmail.h>
1971345Sgshapiro#if MAXMACROID != (BITMAPBITS - 1)
2071345Sgshapiro	ERROR Read the comment in conf.h
21363466Sgshapiro#endif
2238032Speter
2390792Sgshapirostatic char	*MacroName[MAXMACROID + 1];	/* macro id to name table */
24173340Sgshapiro
25173340Sgshapiro/*
26173340Sgshapiro**  Codes for long named macros.
27173340Sgshapiro**  See also macname():
28173340Sgshapiro	* if not ASCII printable, look up the name *
29173340Sgshapiro	if (n <= 0x20 || n > 0x7f)
30173340Sgshapiro**  First use 1 to NEXTMACROID_L, then use NEXTMACROID_H to MAXMACROID.
31173340Sgshapiro*/
32173340Sgshapiro
33173340Sgshapiro#define NEXTMACROID_L 037
34173340Sgshapiro#define NEXTMACROID_H 0240
35173340Sgshapiro
36173340Sgshapiro#if _FFR_MORE_MACROS
37173340Sgshapiro/* table for next id in non-printable ASCII range: disallow some value */
38173340Sgshapirostatic int NextMIdTable[] =
39173340Sgshapiro{
40173340Sgshapiro	/*  0  nul */	 1,
41173340Sgshapiro	/*  1  soh */	 2,
42173340Sgshapiro	/*  2  stx */	 3,
43173340Sgshapiro	/*  3  etx */	 4,
44173340Sgshapiro	/*  4  eot */	 5,
45173340Sgshapiro	/*  5  enq */	 6,
46173340Sgshapiro	/*  6  ack */	 7,
47173340Sgshapiro	/*  7  bel */	 8,
48173340Sgshapiro	/*  8  bs  */	14,
49173340Sgshapiro	/*  9  ht  */	-1,
50173340Sgshapiro	/* 10  nl  */	-1,
51173340Sgshapiro	/* 11  vt  */	-1,
52173340Sgshapiro	/* 12  np  */	-1,
53173340Sgshapiro	/* 13  cr  */	-1,
54173340Sgshapiro	/* 14  so  */	15,
55173340Sgshapiro	/* 15  si  */	16,
56173340Sgshapiro	/* 16  dle */	17,
57173340Sgshapiro	/* 17  dc1 */	18,
58173340Sgshapiro	/* 18  dc2 */	19,
59173340Sgshapiro	/* 19  dc3 */	20,
60173340Sgshapiro	/* 20  dc4 */	21,
61173340Sgshapiro	/* 21  nak */	22,
62173340Sgshapiro	/* 22  syn */	23,
63173340Sgshapiro	/* 23  etb */	24,
64173340Sgshapiro	/* 24  can */	25,
65173340Sgshapiro	/* 25  em  */	26,
66173340Sgshapiro	/* 26  sub */	27,
67173340Sgshapiro	/* 27  esc */	28,
68173340Sgshapiro	/* 28  fs  */	29,
69173340Sgshapiro	/* 29  gs  */	30,
70173340Sgshapiro	/* 30  rs  */	31,
71173340Sgshapiro	/* 31  us  */	32,
72173340Sgshapiro	/* 32  sp  */	-1,
73173340Sgshapiro};
74173340Sgshapiro
75173340Sgshapiro#define NEXTMACROID(mid)	(		\
76173340Sgshapiro	(mid < NEXTMACROID_L) ? (NextMIdTable[mid]) :	\
77173340Sgshapiro	((mid < NEXTMACROID_H) ? NEXTMACROID_H : (mid + 1)))
78173340Sgshapiro
79173340Sgshapiroint		NextMacroId = 1;	/* codes for long named macros */
80173340Sgshapiro/* see sendmail.h: Special characters in rewriting rules. */
81173340Sgshapiro#else /* _FFR_MORE_MACROS */
8290792Sgshapiroint		NextMacroId = 0240;	/* codes for long named macros */
83173340Sgshapiro#define NEXTMACROID(mid)	((mid) + 1)
84173340Sgshapiro#endif /* _FFR_MORE_MACROS */
8538032Speter
86168515Sgshapiro
8738032Speter/*
8890792Sgshapiro**  INITMACROS -- initialize the macro system
8990792Sgshapiro**
9090792Sgshapiro**	This just involves defining some macros that are actually
9190792Sgshapiro**	used internally as metasymbols to be themselves.
9290792Sgshapiro**
9390792Sgshapiro**	Parameters:
9490792Sgshapiro**		none.
9590792Sgshapiro**
9690792Sgshapiro**	Returns:
9790792Sgshapiro**		none.
9890792Sgshapiro**
9990792Sgshapiro**	Side Effects:
10090792Sgshapiro**		initializes several macros to be themselves.
10190792Sgshapiro*/
10290792Sgshapiro
10390792Sgshapirostruct metamac	MetaMacros[] =
10490792Sgshapiro{
10590792Sgshapiro	/* LHS pattern matching characters */
10690792Sgshapiro	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
10790792Sgshapiro	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
10890792Sgshapiro
10990792Sgshapiro	/* these are RHS metasymbols */
11090792Sgshapiro	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
11190792Sgshapiro	{ '>', CALLSUBR },
11290792Sgshapiro
11390792Sgshapiro	/* the conditional operations */
11490792Sgshapiro	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
11590792Sgshapiro
11690792Sgshapiro	/* the hostname lookup characters */
11790792Sgshapiro	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
11890792Sgshapiro	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
11990792Sgshapiro
12090792Sgshapiro	/* miscellaneous control characters */
12190792Sgshapiro	{ '&', MACRODEXPAND },
12290792Sgshapiro
12390792Sgshapiro	{ '\0', '\0' }
12490792Sgshapiro};
12590792Sgshapiro
12690792Sgshapiro#define MACBINDING(name, mid) \
12790792Sgshapiro		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
12890792Sgshapiro		MacroName[mid] = name;
12990792Sgshapiro
13090792Sgshapirovoid
13190792Sgshapiroinitmacros(e)
132168515Sgshapiro	ENVELOPE *e;
13390792Sgshapiro{
134168515Sgshapiro	struct metamac *m;
135168515Sgshapiro	int c;
13690792Sgshapiro	char buf[5];
13790792Sgshapiro
13890792Sgshapiro	for (m = MetaMacros; m->metaname != '\0'; m++)
13990792Sgshapiro	{
14090792Sgshapiro		buf[0] = m->metaval;
14190792Sgshapiro		buf[1] = '\0';
14290792Sgshapiro		macdefine(&e->e_macro, A_TEMP, m->metaname, buf);
14390792Sgshapiro	}
14490792Sgshapiro	buf[0] = MATCHREPL;
14590792Sgshapiro	buf[2] = '\0';
14690792Sgshapiro	for (c = '0'; c <= '9'; c++)
14790792Sgshapiro	{
14890792Sgshapiro		buf[1] = c;
14990792Sgshapiro		macdefine(&e->e_macro, A_TEMP, c, buf);
15090792Sgshapiro	}
15190792Sgshapiro
15290792Sgshapiro	/* set defaults for some macros sendmail will use later */
15390792Sgshapiro	macdefine(&e->e_macro, A_PERM, 'n', "MAILER-DAEMON");
15490792Sgshapiro
15590792Sgshapiro	/* set up external names for some internal macros */
15690792Sgshapiro	MACBINDING("opMode", MID_OPMODE);
15790792Sgshapiro	/*XXX should probably add equivalents for all short macros here XXX*/
15890792Sgshapiro}
159168515Sgshapiro
16090792Sgshapiro/*
161168515Sgshapiro**  EXPAND/DOEXPAND -- macro expand a string using $x escapes.
16238032Speter**
163168515Sgshapiro**	After expansion, the expansion will be in external form (that is,
164168515Sgshapiro**	there will be no sendmail metacharacters and METAQUOTEs will have
165168515Sgshapiro**	been stripped out).
166168515Sgshapiro**
16738032Speter**	Parameters:
16838032Speter**		s -- the string to expand.
16938032Speter**		buf -- the place to put the expansion.
17038032Speter**		bufsize -- the size of the buffer.
171168515Sgshapiro**		explevel -- the depth of expansion (doexpand only)
17238032Speter**		e -- envelope in which to work.
17338032Speter**
17438032Speter**	Returns:
17538032Speter**		none.
17638032Speter**
17738032Speter**	Side Effects:
17838032Speter**		none.
17938032Speter*/
18038032Speter
181168515Sgshapirostatic void doexpand __P(( char *, char *, size_t, int, ENVELOPE *));
182168515Sgshapiro
183168515Sgshapirostatic void
184168515Sgshapirodoexpand(s, buf, bufsize, explevel, e)
185168515Sgshapiro	char *s;
186168515Sgshapiro	char *buf;
18738032Speter	size_t bufsize;
188168515Sgshapiro	int explevel;
189168515Sgshapiro	ENVELOPE *e;
19038032Speter{
191168515Sgshapiro	char *xp;
192168515Sgshapiro	char *q;
19338032Speter	bool skipping;		/* set if conditionally skipping output */
19490792Sgshapiro	bool recurse;		/* set if recursion required */
19590792Sgshapiro	size_t i;
19638032Speter	int skiplev;		/* skipping nesting level */
19738032Speter	int iflev;		/* if nesting level */
198168515Sgshapiro	bool quotenext;		/* quote the following character */
19938032Speter	char xbuf[MACBUFSIZE];
20038032Speter
20138032Speter	if (tTd(35, 24))
20238032Speter	{
20390792Sgshapiro		sm_dprintf("expand(");
204132943Sgshapiro		xputs(sm_debug_file(), s);
20590792Sgshapiro		sm_dprintf(")\n");
20638032Speter	}
20738032Speter
20890792Sgshapiro	recurse = false;
20990792Sgshapiro	skipping = false;
21038032Speter	skiplev = 0;
21138032Speter	iflev = 0;
212168515Sgshapiro	quotenext = false;
21338032Speter	if (s == NULL)
21438032Speter		s = "";
21538032Speter	for (xp = xbuf; *s != '\0'; s++)
21638032Speter	{
21738032Speter		int c;
21838032Speter
21938032Speter		/*
22038032Speter		**  Check for non-ordinary (special?) character.
22138032Speter		**	'q' will be the interpolated quantity.
22238032Speter		*/
22338032Speter
22438032Speter		q = NULL;
225168515Sgshapiro		c = *s & 0377;
226168515Sgshapiro
227168515Sgshapiro		if (quotenext)
22838032Speter		{
229168515Sgshapiro			quotenext = false;
230168515Sgshapiro			goto simpleinterpolate;
231168515Sgshapiro		}
232168515Sgshapiro
233168515Sgshapiro		switch (c)
234168515Sgshapiro		{
23538032Speter		  case CONDIF:		/* see if var set */
23638032Speter			iflev++;
237168515Sgshapiro			c = *++s & 0377;
23838032Speter			if (skipping)
23938032Speter				skiplev++;
24038032Speter			else
24164562Sgshapiro			{
24264562Sgshapiro				char *mv;
24364562Sgshapiro
24464562Sgshapiro				mv = macvalue(c, e);
24564562Sgshapiro				skipping = (mv == NULL || *mv == '\0');
24664562Sgshapiro			}
24738032Speter			continue;
24838032Speter
24938032Speter		  case CONDELSE:	/* change state of skipping */
25038032Speter			if (iflev == 0)
25190792Sgshapiro				break;	/* XXX: error */
25238032Speter			if (skiplev == 0)
25338032Speter				skipping = !skipping;
25438032Speter			continue;
25538032Speter
25638032Speter		  case CONDFI:		/* stop skipping */
25738032Speter			if (iflev == 0)
25890792Sgshapiro				break;	/* XXX: error */
25938032Speter			iflev--;
26038032Speter			if (skiplev == 0)
26190792Sgshapiro				skipping = false;
26238032Speter			if (skipping)
26338032Speter				skiplev--;
26438032Speter			continue;
26538032Speter
26638032Speter		  case MACROEXPAND:	/* macro interpolation */
26771345Sgshapiro			c = bitidx(*++s);
26838032Speter			if (c != '\0')
26938032Speter				q = macvalue(c, e);
27038032Speter			else
27138032Speter			{
27238032Speter				s--;
27338032Speter				q = NULL;
27438032Speter			}
27538032Speter			if (q == NULL)
27638032Speter				continue;
27738032Speter			break;
278168515Sgshapiro
279168515Sgshapiro		  case METAQUOTE:
280168515Sgshapiro			/* next octet completely quoted */
281168515Sgshapiro			quotenext = true;
282168515Sgshapiro			break;
28338032Speter		}
28438032Speter
28538032Speter		/*
28638032Speter		**  Interpolate q or output one character
28738032Speter		*/
28838032Speter
289168515Sgshapiro  simpleinterpolate:
290168515Sgshapiro		if (skipping || xp >= &xbuf[sizeof(xbuf) - 1])
29138032Speter			continue;
29238032Speter		if (q == NULL)
29338032Speter			*xp++ = c;
29438032Speter		else
29538032Speter		{
29638032Speter			/* copy to end of q or max space remaining in buf */
297168515Sgshapiro			bool hiderecurse = false;
298168515Sgshapiro
299168515Sgshapiro			while ((c = *q++) != '\0' &&
300168515Sgshapiro				xp < &xbuf[sizeof(xbuf) - 1])
30138032Speter			{
30238032Speter				/* check for any sendmail metacharacters */
303168515Sgshapiro				if (!hiderecurse && (c & 0340) == 0200)
30490792Sgshapiro					recurse = true;
30538032Speter				*xp++ = c;
306168515Sgshapiro
307168515Sgshapiro				/* give quoted characters a free ride */
308168515Sgshapiro				hiderecurse = (c & 0377) == METAQUOTE;
30938032Speter			}
31038032Speter		}
31138032Speter	}
31238032Speter	*xp = '\0';
31338032Speter
314168515Sgshapiro	if (tTd(35, 28))
31538032Speter	{
316168515Sgshapiro		sm_dprintf("expand(%d) ==> ", explevel);
317132943Sgshapiro		xputs(sm_debug_file(), xbuf);
31890792Sgshapiro		sm_dprintf("\n");
31938032Speter	}
32038032Speter
32138032Speter	/* recurse as appropriate */
32238032Speter	if (recurse)
32338032Speter	{
32438032Speter		if (explevel < MaxMacroRecursion)
32538032Speter		{
326168515Sgshapiro			doexpand(xbuf, buf, bufsize, explevel + 1, e);
32738032Speter			return;
32838032Speter		}
32938032Speter		syserr("expand: recursion too deep (%d max)",
33038032Speter			MaxMacroRecursion);
33138032Speter	}
33238032Speter
33338032Speter	/* copy results out */
334168515Sgshapiro	if (explevel == 0)
335168515Sgshapiro		(void) sm_strlcpy(buf, xbuf, bufsize);
336168515Sgshapiro	else
337168515Sgshapiro	{
338168515Sgshapiro		/* leave in internal form */
339168515Sgshapiro		i = xp - xbuf;
340168515Sgshapiro		if (i >= bufsize)
341168515Sgshapiro			i = bufsize - 1;
342168515Sgshapiro		memmove(buf, xbuf, i);
343168515Sgshapiro		buf[i] = '\0';
344168515Sgshapiro	}
345168515Sgshapiro
346168515Sgshapiro	if (tTd(35, 24))
347168515Sgshapiro	{
348168515Sgshapiro		sm_dprintf("expand ==> ");
349168515Sgshapiro		xputs(sm_debug_file(), buf);
350168515Sgshapiro		sm_dprintf("\n");
351168515Sgshapiro	}
35238032Speter}
35390792Sgshapiro
354168515Sgshapirovoid
355168515Sgshapiroexpand(s, buf, bufsize, e)
356168515Sgshapiro	char *s;
357168515Sgshapiro	char *buf;
358168515Sgshapiro	size_t bufsize;
359168515Sgshapiro	ENVELOPE *e;
360168515Sgshapiro{
361168515Sgshapiro	doexpand(s, buf, bufsize, 0, e);
362168515Sgshapiro}
363168515Sgshapiro
36490792Sgshapiro/*
365363466Sgshapiro**  MACTABCLEAR -- clear entire macro table
366363466Sgshapiro**
367363466Sgshapiro**	Parameters:
368363466Sgshapiro**		mac -- Macro table.
369363466Sgshapiro**
370363466Sgshapiro**	Returns:
371363466Sgshapiro**		none.
372363466Sgshapiro**
373363466Sgshapiro**	Side Effects:
374363466Sgshapiro**		clears entire mac structure including rpool pointer!
375363466Sgshapiro*/
376363466Sgshapiro
377363466Sgshapirovoid
378363466Sgshapiromactabclear(mac)
379363466Sgshapiro	MACROS_T *mac;
380363466Sgshapiro{
381363466Sgshapiro	int i;
382363466Sgshapiro
383363466Sgshapiro	if (mac->mac_rpool == NULL)
384363466Sgshapiro	{
385363466Sgshapiro		for (i = 0; i < MAXMACROID; i++)
386363466Sgshapiro			SM_FREE(mac->mac_table[i]);
387363466Sgshapiro	}
388363466Sgshapiro	memset((char *) mac, '\0', sizeof(*mac));
389363466Sgshapiro}
390363466Sgshapiro
391363466Sgshapiro/*
39290792Sgshapiro**  MACDEFINE -- bind a macro name to a value
39338032Speter**
39490792Sgshapiro**	Set a macro to a value, with fancy storage management.
39590792Sgshapiro**	macdefine will make a copy of the value, if required,
39690792Sgshapiro**	and will ensure that the storage for the previous value
39790792Sgshapiro**	is not leaked.
39838032Speter**
39938032Speter**	Parameters:
40090792Sgshapiro**		mac -- Macro table.
40190792Sgshapiro**		vclass -- storage class of 'value', ignored if value==NULL.
40290792Sgshapiro**			A_HEAP	means that the value was allocated by
40390792Sgshapiro**				malloc, and that macdefine owns the storage.
40490792Sgshapiro**			A_TEMP	means that value points to temporary storage,
40590792Sgshapiro**				and thus macdefine needs to make a copy.
40690792Sgshapiro**			A_PERM	means that value points to storage that
40790792Sgshapiro**				will remain allocated and unchanged for
40890792Sgshapiro**				at least the lifetime of mac.  Use A_PERM if:
40990792Sgshapiro**				-- value == NULL,
41090792Sgshapiro**				-- value points to a string literal,
41190792Sgshapiro**				-- value was allocated from mac->mac_rpool
41290792Sgshapiro**				   or (in the case of an envelope macro)
41390792Sgshapiro**				   from e->e_rpool,
41490792Sgshapiro**				-- in the case of an envelope macro,
41590792Sgshapiro**				   value is a string member of the envelope
41690792Sgshapiro**				   such as e->e_sender.
41790792Sgshapiro**		id -- Macro id.  This is a single character macro name
41890792Sgshapiro**			such as 'g', or a value returned by macid().
41990792Sgshapiro**		value -- Macro value: either NULL, or a string.
42038032Speter*/
42138032Speter
42238032Spetervoid
42390792Sgshapiro#if SM_HEAP_CHECK
42490792Sgshapiromacdefine_tagged(mac, vclass, id, value, file, line, grp)
42590792Sgshapiro#else /* SM_HEAP_CHECK */
42690792Sgshapiromacdefine(mac, vclass, id, value)
42790792Sgshapiro#endif /* SM_HEAP_CHECK */
42890792Sgshapiro	MACROS_T *mac;
42990792Sgshapiro	ARGCLASS_T vclass;
43090792Sgshapiro	int id;
43190792Sgshapiro	char *value;
43290792Sgshapiro#if SM_HEAP_CHECK
43390792Sgshapiro	char *file;
43490792Sgshapiro	int line;
43590792Sgshapiro	int grp;
43690792Sgshapiro#endif /* SM_HEAP_CHECK */
43738032Speter{
43890792Sgshapiro	char *newvalue;
43964562Sgshapiro
44090792Sgshapiro	if (id < 0 || id > MAXMACROID)
44190792Sgshapiro		return;
44290792Sgshapiro
44338032Speter	if (tTd(35, 9))
44438032Speter	{
44590792Sgshapiro		sm_dprintf("%sdefine(%s as ",
44690792Sgshapiro			mac->mac_table[id] == NULL ? "" : "re", macname(id));
447132943Sgshapiro		xputs(sm_debug_file(), value);
44890792Sgshapiro		sm_dprintf(")\n");
44938032Speter	}
45064562Sgshapiro
45190792Sgshapiro	if (mac->mac_rpool == NULL)
45290792Sgshapiro	{
45390792Sgshapiro		char *freeit = NULL;
45490792Sgshapiro
45590792Sgshapiro		if (mac->mac_table[id] != NULL &&
45690792Sgshapiro		    bitnset(id, mac->mac_allocated))
45790792Sgshapiro			freeit = mac->mac_table[id];
45890792Sgshapiro
45990792Sgshapiro		if (value == NULL || vclass == A_HEAP)
46090792Sgshapiro		{
46190792Sgshapiro			sm_heap_checkptr_tagged(value, file, line);
46290792Sgshapiro			newvalue = value;
46390792Sgshapiro			clrbitn(id, mac->mac_allocated);
46490792Sgshapiro		}
46590792Sgshapiro		else
46690792Sgshapiro		{
467132943Sgshapiro#if SM_HEAP_CHECK
46890792Sgshapiro			newvalue = sm_strdup_tagged_x(value, file, line, 0);
469363466Sgshapiro#else
470132943Sgshapiro			newvalue = sm_strdup_x(value);
471363466Sgshapiro#endif
47290792Sgshapiro			setbitn(id, mac->mac_allocated);
47390792Sgshapiro		}
47490792Sgshapiro		mac->mac_table[id] = newvalue;
47590792Sgshapiro		if (freeit != NULL)
47690792Sgshapiro			sm_free(freeit);
47790792Sgshapiro	}
47890792Sgshapiro	else
47990792Sgshapiro	{
48090792Sgshapiro		if (value == NULL || vclass == A_PERM)
48190792Sgshapiro			newvalue = value;
48290792Sgshapiro		else
48390792Sgshapiro			newvalue = sm_rpool_strdup_x(mac->mac_rpool, value);
48490792Sgshapiro		mac->mac_table[id] = newvalue;
48590792Sgshapiro		if (vclass == A_HEAP)
48690792Sgshapiro			sm_free(value);
48790792Sgshapiro	}
48890792Sgshapiro
48964562Sgshapiro#if _FFR_RESET_MACRO_GLOBALS
49090792Sgshapiro	switch (id)
49164562Sgshapiro	{
49264562Sgshapiro	  case 'j':
49390792Sgshapiro		PSTRSET(MyHostName, value);
49464562Sgshapiro		break;
49564562Sgshapiro	}
49664562Sgshapiro#endif /* _FFR_RESET_MACRO_GLOBALS */
49738032Speter}
49890792Sgshapiro
49990792Sgshapiro/*
50090792Sgshapiro**  MACSET -- set a named macro to a value (low level)
50190792Sgshapiro**
50290792Sgshapiro**	No fancy storage management; the caller takes full responsibility.
50390792Sgshapiro**	Often used with macget; see also macdefine.
50490792Sgshapiro**
50590792Sgshapiro**	Parameters:
50690792Sgshapiro**		mac -- Macro table.
50790792Sgshapiro**		i -- Macro name, specified as an integer offset.
50890792Sgshapiro**		value -- Macro value: either NULL, or a string.
50990792Sgshapiro*/
51090792Sgshapiro
51190792Sgshapirovoid
51290792Sgshapiromacset(mac, i, value)
51390792Sgshapiro	MACROS_T *mac;
51490792Sgshapiro	int i;
51590792Sgshapiro	char *value;
51690792Sgshapiro{
51790792Sgshapiro	if (i < 0 || i > MAXMACROID)
51890792Sgshapiro		return;
51990792Sgshapiro
52090792Sgshapiro	if (tTd(35, 9))
52190792Sgshapiro	{
52290792Sgshapiro		sm_dprintf("macset(%s as ", macname(i));
523132943Sgshapiro		xputs(sm_debug_file(), value);
52490792Sgshapiro		sm_dprintf(")\n");
52590792Sgshapiro	}
52690792Sgshapiro	mac->mac_table[i] = value;
52790792Sgshapiro}
52890792Sgshapiro
52990792Sgshapiro/*
53038032Speter**  MACVALUE -- return uninterpreted value of a macro.
53138032Speter**
53290792Sgshapiro**	Does fancy path searching.
53390792Sgshapiro**	The low level counterpart is macget.
53490792Sgshapiro**
53538032Speter**	Parameters:
53638032Speter**		n -- the name of the macro.
53790792Sgshapiro**		e -- envelope in which to start looking for the macro.
53838032Speter**
53938032Speter**	Returns:
54038032Speter**		The value of n.
54138032Speter**
54238032Speter**	Side Effects:
54338032Speter**		none.
54438032Speter*/
54538032Speter
54638032Speterchar *
54738032Spetermacvalue(n, e)
54838032Speter	int n;
549168515Sgshapiro	ENVELOPE *e;
55038032Speter{
55171345Sgshapiro	n = bitidx(n);
55290792Sgshapiro	if (e != NULL && e->e_mci != NULL)
55390792Sgshapiro	{
554168515Sgshapiro		char *p = e->e_mci->mci_macro.mac_table[n];
55590792Sgshapiro
55690792Sgshapiro		if (p != NULL)
55790792Sgshapiro			return p;
55890792Sgshapiro	}
55938032Speter	while (e != NULL)
56038032Speter	{
561168515Sgshapiro		char *p = e->e_macro.mac_table[n];
56238032Speter
56338032Speter		if (p != NULL)
56464562Sgshapiro			return p;
56573188Sgshapiro		if (e == e->e_parent)
56673188Sgshapiro			break;
56738032Speter		e = e->e_parent;
56838032Speter	}
569363466Sgshapiro#if _FFR_BLANKENV_MACV
570363466Sgshapiro	if (LOOKUP_MACRO_IN_BLANKENV && e != &BlankEnvelope)
571363466Sgshapiro	{
572363466Sgshapiro		char *p = BlankEnvelope.e_macro.mac_table[n];
573363466Sgshapiro
574363466Sgshapiro		if (p != NULL)
575363466Sgshapiro			return p;
576363466Sgshapiro	}
577363466Sgshapiro#endif
57890792Sgshapiro	return GlobalMacros.mac_table[n];
57938032Speter}
580168515Sgshapiro
58190792Sgshapiro/*
58238032Speter**  MACNAME -- return the name of a macro given its internal id
58338032Speter**
58438032Speter**	Parameter:
58538032Speter**		n -- the id of the macro
58638032Speter**
58738032Speter**	Returns:
58838032Speter**		The name of n.
58938032Speter**
59038032Speter**	Side Effects:
59138032Speter**		none.
592168515Sgshapiro**
593168515Sgshapiro**	WARNING:
594168515Sgshapiro**		Not thread-safe.
59538032Speter*/
59638032Speter
59738032Speterchar *
59838032Spetermacname(n)
59938032Speter	int n;
60038032Speter{
60138032Speter	static char mbuf[2];
60238032Speter
603168515Sgshapiro	n = (int)(unsigned char)n;
604168515Sgshapiro	if (n > MAXMACROID)
605168515Sgshapiro		return "***OUT OF RANGE MACRO***";
606168515Sgshapiro
607168515Sgshapiro	/* if not ASCII printable, look up the name */
608168515Sgshapiro	if (n <= 0x20 || n > 0x7f)
60938032Speter	{
61038032Speter		char *p = MacroName[n];
61138032Speter
61238032Speter		if (p != NULL)
61338032Speter			return p;
61438032Speter		return "***UNDEFINED MACRO***";
61538032Speter	}
616168515Sgshapiro
617168515Sgshapiro	/* if in the ASCII graphic range, just return the id directly */
61838032Speter	mbuf[0] = n;
61938032Speter	mbuf[1] = '\0';
62038032Speter	return mbuf;
62138032Speter}
622168515Sgshapiro
62390792Sgshapiro/*
62490792Sgshapiro**  MACID_PARSE -- return id of macro identified by its name
62538032Speter**
62638032Speter**	Parameters:
62738032Speter**		p -- pointer to name string -- either a single
62838032Speter**			character or {name}.
62938032Speter**		ep -- filled in with the pointer to the byte
63038032Speter**			after the name.
63138032Speter**
63238032Speter**	Returns:
63390792Sgshapiro**		0 -- An error was detected.
634168515Sgshapiro**		1..MAXMACROID -- The internal id code for this macro.
63538032Speter**
63638032Speter**	Side Effects:
63738032Speter**		If this is a new macro name, a new id is allocated.
63890792Sgshapiro**		On error, syserr is called.
63938032Speter*/
64038032Speter
64138032Speterint
64290792Sgshapiromacid_parse(p, ep)
643168515Sgshapiro	char *p;
64438032Speter	char **ep;
64538032Speter{
64638032Speter	int mid;
647168515Sgshapiro	char *bp;
64842575Speter	char mbuf[MAXMACNAMELEN + 1];
64938032Speter
65038032Speter	if (tTd(35, 14))
65138032Speter	{
65290792Sgshapiro		sm_dprintf("macid(");
653132943Sgshapiro		xputs(sm_debug_file(), p);
65490792Sgshapiro		sm_dprintf(") => ");
65538032Speter	}
65638032Speter
65738032Speter	if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
65838032Speter	{
65938032Speter		syserr("Name required for macro/class");
66038032Speter		if (ep != NULL)
66138032Speter			*ep = p;
66238032Speter		if (tTd(35, 14))
66390792Sgshapiro			sm_dprintf("NULL\n");
66471345Sgshapiro		return 0;
66538032Speter	}
66638032Speter	if (*p != '{')
66738032Speter	{
66838032Speter		/* the macro is its own code */
66938032Speter		if (ep != NULL)
67038032Speter			*ep = p + 1;
67138032Speter		if (tTd(35, 14))
672168515Sgshapiro		{
673168515Sgshapiro			char buf[2];
674168515Sgshapiro
675168515Sgshapiro			buf[0] = *p;
676168515Sgshapiro			buf[1] = '\0';
677168515Sgshapiro			xputs(sm_debug_file(), buf);
678168515Sgshapiro			sm_dprintf("\n");
679168515Sgshapiro		}
68071345Sgshapiro		return bitidx(*p);
68138032Speter	}
68238032Speter	bp = mbuf;
683168515Sgshapiro	while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof(mbuf) - 1])
68438032Speter	{
68538032Speter		if (isascii(*p) && (isalnum(*p) || *p == '_'))
68638032Speter			*bp++ = *p;
68738032Speter		else
68838032Speter			syserr("Invalid macro/class character %c", *p);
68938032Speter	}
69038032Speter	*bp = '\0';
69138032Speter	mid = -1;
69238032Speter	if (*p == '\0')
69338032Speter	{
69438032Speter		syserr("Unbalanced { on %s", mbuf);	/* missing } */
69538032Speter	}
69638032Speter	else if (*p != '}')
69738032Speter	{
69838032Speter		syserr("Macro/class name ({%s}) too long (%d chars max)",
699168515Sgshapiro			mbuf, (int) (sizeof(mbuf) - 1));
70038032Speter	}
701173340Sgshapiro	else if (mbuf[1] == '\0' && mbuf[0] >= 0x20)
70238032Speter	{
70338032Speter		/* ${x} == $x */
70471345Sgshapiro		mid = bitidx(mbuf[0]);
70538032Speter		p++;
70638032Speter	}
70738032Speter	else
70838032Speter	{
709168515Sgshapiro		STAB *s;
71038032Speter
71138032Speter		s = stab(mbuf, ST_MACRO, ST_ENTER);
71238032Speter		if (s->s_macro != 0)
71338032Speter			mid = s->s_macro;
71438032Speter		else
71538032Speter		{
71664562Sgshapiro			if (NextMacroId > MAXMACROID)
71738032Speter			{
71890792Sgshapiro				syserr("Macro/class {%s}: too many long names",
71990792Sgshapiro					mbuf);
72038032Speter				s->s_macro = -1;
72138032Speter			}
72238032Speter			else
72338032Speter			{
72438032Speter				MacroName[NextMacroId] = s->s_name;
725173340Sgshapiro				s->s_macro = mid = NextMacroId;
726173340Sgshapiro				NextMacroId = NEXTMACROID(NextMacroId);
72738032Speter			}
72838032Speter		}
72938032Speter		p++;
73038032Speter	}
73138032Speter	if (ep != NULL)
73238032Speter		*ep = p;
73371345Sgshapiro	if (mid < 0 || mid > MAXMACROID)
73471345Sgshapiro	{
73571345Sgshapiro		syserr("Unable to assign macro/class ID (mid = 0x%x)", mid);
73671345Sgshapiro		if (tTd(35, 14))
73790792Sgshapiro			sm_dprintf("NULL\n");
73871345Sgshapiro		return 0;
73971345Sgshapiro	}
74038032Speter	if (tTd(35, 14))
74190792Sgshapiro		sm_dprintf("0x%x\n", mid);
74238032Speter	return mid;
74338032Speter}
744168515Sgshapiro
74590792Sgshapiro/*
74638032Speter**  WORDINCLASS -- tell if a word is in a specific class
74738032Speter**
74838032Speter**	Parameters:
74938032Speter**		str -- the name of the word to look up.
75038032Speter**		cl -- the class name.
75138032Speter**
75238032Speter**	Returns:
75390792Sgshapiro**		true if str can be found in cl.
75490792Sgshapiro**		false otherwise.
75538032Speter*/
75638032Speter
75738032Speterbool
75838032Speterwordinclass(str, cl)
75938032Speter	char *str;
76038032Speter	int cl;
76138032Speter{
762168515Sgshapiro	STAB *s;
76338032Speter
76438032Speter	s = stab(str, ST_CLASS, ST_FIND);
76571345Sgshapiro	return s != NULL && bitnset(bitidx(cl), s->s_class);
76638032Speter}
767