macro.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1998-2001, 2003 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sendmail.h>
#endif /* MAXMACROID != (BITMAPBITS - 1) */
/*
** INITMACROS -- initialize the macro system
**
** This just involves defining some macros that are actually
** used internally as metasymbols to be themselves.
**
** Parameters:
** none.
**
** Returns:
** none.
**
** Side Effects:
** initializes several macros to be themselves.
*/
struct metamac MetaMacros[] =
{
/* LHS pattern matching characters */
/* these are RHS metasymbols */
{ '>', CALLSUBR },
/* the conditional operations */
/* the hostname lookup characters */
/* miscellaneous control characters */
{ '&', MACRODEXPAND },
{ '\0', '\0' }
};
void
initmacros(e)
register ENVELOPE *e;
{
register struct metamac *m;
register int c;
char buf[5];
{
}
for (c = '0'; c <= '9'; c++)
{
buf[1] = c;
}
/* set defaults for some macros sendmail will use later */
/* set up external names for some internal macros */
/*XXX should probably add equivalents for all short macros here XXX*/
}
/*
** EXPAND -- macro expand a string using $x escapes.
**
** Parameters:
** s -- the string to expand.
** buf -- the place to put the expansion.
** bufsize -- the size of the buffer.
** e -- envelope in which to work.
**
** Returns:
** none.
**
** Side Effects:
** none.
*/
void
register char *s;
register char *buf;
register ENVELOPE *e;
{
register char *xp;
register char *q;
bool skipping; /* set if conditionally skipping output */
bool recurse; /* set if recursion required */
size_t i;
int skiplev; /* skipping nesting level */
int iflev; /* if nesting level */
char xbuf[MACBUFSIZE];
static int explevel = 0;
{
sm_dprintf("expand(");
xputs(sm_debug_file(), s);
sm_dprintf(")\n");
}
recurse = false;
skipping = false;
skiplev = 0;
iflev = 0;
if (s == NULL)
s = "";
{
int c;
/*
** Check for non-ordinary (special?) character.
** 'q' will be the interpolated quantity.
*/
q = NULL;
c = *s;
switch (c & 0377)
{
case CONDIF: /* see if var set */
iflev++;
c = *++s;
if (skipping)
skiplev++;
else
{
char *mv;
}
continue;
case CONDELSE: /* change state of skipping */
if (iflev == 0)
break; /* XXX: error */
if (skiplev == 0)
continue;
case CONDFI: /* stop skipping */
if (iflev == 0)
break; /* XXX: error */
iflev--;
if (skiplev == 0)
skipping = false;
if (skipping)
skiplev--;
continue;
case MACROEXPAND: /* macro interpolation */
c = bitidx(*++s);
if (c != '\0')
q = macvalue(c, e);
else
{
s--;
q = NULL;
}
if (q == NULL)
continue;
break;
}
/*
** Interpolate q or output one character
*/
continue;
if (q == NULL)
*xp++ = c;
else
{
/* copy to end of q or max space remaining in buf */
{
/* check for any sendmail metacharacters */
if ((c & 0340) == 0200)
recurse = true;
*xp++ = c;
}
}
}
*xp = '\0';
{
sm_dprintf("expand ==> ");
sm_dprintf("\n");
}
/* recurse as appropriate */
if (recurse)
{
if (explevel < MaxMacroRecursion)
{
explevel++;
explevel--;
return;
}
syserr("expand: recursion too deep (%d max)",
}
/* copy results out */
if (i >= bufsize)
i = bufsize - 1;
buf[i] = '\0';
}
/*
** MACDEFINE -- bind a macro name to a value
**
** Set a macro to a value, with fancy storage management.
** macdefine will make a copy of the value, if required,
** and will ensure that the storage for the previous value
** is not leaked.
**
** Parameters:
** mac -- Macro table.
** vclass -- storage class of 'value', ignored if value==NULL.
** A_HEAP means that the value was allocated by
** malloc, and that macdefine owns the storage.
** A_TEMP means that value points to temporary storage,
** and thus macdefine needs to make a copy.
** A_PERM means that value points to storage that
** will remain allocated and unchanged for
** at least the lifetime of mac. Use A_PERM if:
** -- value == NULL,
** -- value points to a string literal,
** -- value was allocated from mac->mac_rpool
** or (in the case of an envelope macro)
** from e->e_rpool,
** -- in the case of an envelope macro,
** value is a string member of the envelope
** such as e->e_sender.
** id -- Macro id. This is a single character macro name
** such as 'g', or a value returned by macid().
** value -- Macro value: either NULL, or a string.
*/
void
#if SM_HEAP_CHECK
#else /* SM_HEAP_CHECK */
#endif /* SM_HEAP_CHECK */
int id;
char *value;
#if SM_HEAP_CHECK
char *file;
int line;
int grp;
#endif /* SM_HEAP_CHECK */
{
char *newvalue;
return;
{
sm_dprintf("%sdefine(%s as ",
sm_dprintf(")\n");
}
{
{
}
else
{
#if SM_HEAP_CHECK
#else /* SM_HEAP_CHECK */
#endif /* SM_HEAP_CHECK */
}
}
else
{
else
}
switch (id)
{
case 'j':
break;
}
#endif /* _FFR_RESET_MACRO_GLOBALS */
}
/*
** MACSET -- set a named macro to a value (low level)
**
** No fancy storage management; the caller takes full responsibility.
** Often used with macget; see also macdefine.
**
** Parameters:
** mac -- Macro table.
** i -- Macro name, specified as an integer offset.
** value -- Macro value: either NULL, or a string.
*/
void
int i;
char *value;
{
if (i < 0 || i > MAXMACROID)
return;
{
sm_dprintf(")\n");
}
}
/*
** MACVALUE -- return uninterpreted value of a macro.
**
** Does fancy path searching.
** The low level counterpart is macget.
**
** Parameters:
** n -- the name of the macro.
** e -- envelope in which to start looking for the macro.
**
** Returns:
** The value of n.
**
** Side Effects:
** none.
*/
char *
macvalue(n, e)
int n;
register ENVELOPE *e;
{
n = bitidx(n);
{
if (p != NULL)
return p;
}
while (e != NULL)
{
if (p != NULL)
return p;
if (e == e->e_parent)
break;
e = e->e_parent;
}
return GlobalMacros.mac_table[n];
}
/*
** MACNAME -- return the name of a macro given its internal id
**
** Parameter:
** n -- the id of the macro
**
** Returns:
** The name of n.
**
** Side Effects:
** none.
*/
char *
macname(n)
int n;
{
static char mbuf[2];
n = bitidx(n);
if (bitset(0200, n))
{
char *p = MacroName[n];
if (p != NULL)
return p;
return "***UNDEFINED MACRO***";
}
mbuf[0] = n;
return mbuf;
}
/*
** MACID_PARSE -- return id of macro identified by its name
**
** Parameters:
** p -- pointer to name string -- either a single
** character or {name}.
** ep -- filled in with the pointer to the byte
** after the name.
**
** Returns:
** 0 -- An error was detected.
** 1..255 -- The internal id code for this macro.
**
** Side Effects:
** If this is a new macro name, a new id is allocated.
** On error, syserr is called.
*/
int
macid_parse(p, ep)
register char *p;
char **ep;
{
int mid;
register char *bp;
{
sm_dprintf("macid(");
xputs(sm_debug_file(), p);
sm_dprintf(") => ");
}
if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
{
*ep = p;
sm_dprintf("NULL\n");
return 0;
}
if (*p != '{')
{
/* the macro is its own code */
*ep = p + 1;
return bitidx(*p);
}
{
*bp++ = *p;
else
}
*bp = '\0';
mid = -1;
if (*p == '\0')
{
}
else if (*p != '}')
{
}
{
/* ${x} == $x */
p++;
}
else
{
register STAB *s;
if (s->s_macro != 0)
else
{
if (NextMacroId > MAXMACROID)
{
mbuf);
s->s_macro = -1;
}
else
{
}
}
p++;
}
*ep = p;
{
sm_dprintf("NULL\n");
return 0;
}
return mid;
}
/*
** WORDINCLASS -- tell if a word is in a specific class
**
** Parameters:
** str -- the name of the word to look up.
** cl -- the class name.
**
** Returns:
** true if str can be found in cl.
** false otherwise.
*/
bool
char *str;
int cl;
{
register STAB *s;
}