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