macro.c revision 261363
138032Speter/* 2261363Sgshapiro * 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 16261363SgshapiroSM_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 2171345Sgshapiro#endif /* MAXMACROID != (BITMAPBITS - 1) */ 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/* 36590792Sgshapiro** MACDEFINE -- bind a macro name to a value 36638032Speter** 36790792Sgshapiro** Set a macro to a value, with fancy storage management. 36890792Sgshapiro** macdefine will make a copy of the value, if required, 36990792Sgshapiro** and will ensure that the storage for the previous value 37090792Sgshapiro** is not leaked. 37138032Speter** 37238032Speter** Parameters: 37390792Sgshapiro** mac -- Macro table. 37490792Sgshapiro** vclass -- storage class of 'value', ignored if value==NULL. 37590792Sgshapiro** A_HEAP means that the value was allocated by 37690792Sgshapiro** malloc, and that macdefine owns the storage. 37790792Sgshapiro** A_TEMP means that value points to temporary storage, 37890792Sgshapiro** and thus macdefine needs to make a copy. 37990792Sgshapiro** A_PERM means that value points to storage that 38090792Sgshapiro** will remain allocated and unchanged for 38190792Sgshapiro** at least the lifetime of mac. Use A_PERM if: 38290792Sgshapiro** -- value == NULL, 38390792Sgshapiro** -- value points to a string literal, 38490792Sgshapiro** -- value was allocated from mac->mac_rpool 38590792Sgshapiro** or (in the case of an envelope macro) 38690792Sgshapiro** from e->e_rpool, 38790792Sgshapiro** -- in the case of an envelope macro, 38890792Sgshapiro** value is a string member of the envelope 38990792Sgshapiro** such as e->e_sender. 39090792Sgshapiro** id -- Macro id. This is a single character macro name 39190792Sgshapiro** such as 'g', or a value returned by macid(). 39290792Sgshapiro** value -- Macro value: either NULL, or a string. 39338032Speter*/ 39438032Speter 39538032Spetervoid 39690792Sgshapiro#if SM_HEAP_CHECK 39790792Sgshapiromacdefine_tagged(mac, vclass, id, value, file, line, grp) 39890792Sgshapiro#else /* SM_HEAP_CHECK */ 39990792Sgshapiromacdefine(mac, vclass, id, value) 40090792Sgshapiro#endif /* SM_HEAP_CHECK */ 40190792Sgshapiro MACROS_T *mac; 40290792Sgshapiro ARGCLASS_T vclass; 40390792Sgshapiro int id; 40490792Sgshapiro char *value; 40590792Sgshapiro#if SM_HEAP_CHECK 40690792Sgshapiro char *file; 40790792Sgshapiro int line; 40890792Sgshapiro int grp; 40990792Sgshapiro#endif /* SM_HEAP_CHECK */ 41038032Speter{ 41190792Sgshapiro char *newvalue; 41264562Sgshapiro 41390792Sgshapiro if (id < 0 || id > MAXMACROID) 41490792Sgshapiro return; 41590792Sgshapiro 41638032Speter if (tTd(35, 9)) 41738032Speter { 41890792Sgshapiro sm_dprintf("%sdefine(%s as ", 41990792Sgshapiro mac->mac_table[id] == NULL ? "" : "re", macname(id)); 420132943Sgshapiro xputs(sm_debug_file(), value); 42190792Sgshapiro sm_dprintf(")\n"); 42238032Speter } 42364562Sgshapiro 42490792Sgshapiro if (mac->mac_rpool == NULL) 42590792Sgshapiro { 42690792Sgshapiro char *freeit = NULL; 42790792Sgshapiro 42890792Sgshapiro if (mac->mac_table[id] != NULL && 42990792Sgshapiro bitnset(id, mac->mac_allocated)) 43090792Sgshapiro freeit = mac->mac_table[id]; 43190792Sgshapiro 43290792Sgshapiro if (value == NULL || vclass == A_HEAP) 43390792Sgshapiro { 43490792Sgshapiro sm_heap_checkptr_tagged(value, file, line); 43590792Sgshapiro newvalue = value; 43690792Sgshapiro clrbitn(id, mac->mac_allocated); 43790792Sgshapiro } 43890792Sgshapiro else 43990792Sgshapiro { 440132943Sgshapiro#if SM_HEAP_CHECK 44190792Sgshapiro newvalue = sm_strdup_tagged_x(value, file, line, 0); 442132943Sgshapiro#else /* SM_HEAP_CHECK */ 443132943Sgshapiro newvalue = sm_strdup_x(value); 444132943Sgshapiro#endif /* SM_HEAP_CHECK */ 44590792Sgshapiro setbitn(id, mac->mac_allocated); 44690792Sgshapiro } 44790792Sgshapiro mac->mac_table[id] = newvalue; 44890792Sgshapiro if (freeit != NULL) 44990792Sgshapiro sm_free(freeit); 45090792Sgshapiro } 45190792Sgshapiro else 45290792Sgshapiro { 45390792Sgshapiro if (value == NULL || vclass == A_PERM) 45490792Sgshapiro newvalue = value; 45590792Sgshapiro else 45690792Sgshapiro newvalue = sm_rpool_strdup_x(mac->mac_rpool, value); 45790792Sgshapiro mac->mac_table[id] = newvalue; 45890792Sgshapiro if (vclass == A_HEAP) 45990792Sgshapiro sm_free(value); 46090792Sgshapiro } 46190792Sgshapiro 46264562Sgshapiro#if _FFR_RESET_MACRO_GLOBALS 46390792Sgshapiro switch (id) 46464562Sgshapiro { 46564562Sgshapiro case 'j': 46690792Sgshapiro PSTRSET(MyHostName, value); 46764562Sgshapiro break; 46864562Sgshapiro } 46964562Sgshapiro#endif /* _FFR_RESET_MACRO_GLOBALS */ 47038032Speter} 47190792Sgshapiro 47290792Sgshapiro/* 47390792Sgshapiro** MACSET -- set a named macro to a value (low level) 47490792Sgshapiro** 47590792Sgshapiro** No fancy storage management; the caller takes full responsibility. 47690792Sgshapiro** Often used with macget; see also macdefine. 47790792Sgshapiro** 47890792Sgshapiro** Parameters: 47990792Sgshapiro** mac -- Macro table. 48090792Sgshapiro** i -- Macro name, specified as an integer offset. 48190792Sgshapiro** value -- Macro value: either NULL, or a string. 48290792Sgshapiro*/ 48390792Sgshapiro 48490792Sgshapirovoid 48590792Sgshapiromacset(mac, i, value) 48690792Sgshapiro MACROS_T *mac; 48790792Sgshapiro int i; 48890792Sgshapiro char *value; 48990792Sgshapiro{ 49090792Sgshapiro if (i < 0 || i > MAXMACROID) 49190792Sgshapiro return; 49290792Sgshapiro 49390792Sgshapiro if (tTd(35, 9)) 49490792Sgshapiro { 49590792Sgshapiro sm_dprintf("macset(%s as ", macname(i)); 496132943Sgshapiro xputs(sm_debug_file(), value); 49790792Sgshapiro sm_dprintf(")\n"); 49890792Sgshapiro } 49990792Sgshapiro mac->mac_table[i] = value; 50090792Sgshapiro} 50190792Sgshapiro 50290792Sgshapiro/* 50338032Speter** MACVALUE -- return uninterpreted value of a macro. 50438032Speter** 50590792Sgshapiro** Does fancy path searching. 50690792Sgshapiro** The low level counterpart is macget. 50790792Sgshapiro** 50838032Speter** Parameters: 50938032Speter** n -- the name of the macro. 51090792Sgshapiro** e -- envelope in which to start looking for the macro. 51138032Speter** 51238032Speter** Returns: 51338032Speter** The value of n. 51438032Speter** 51538032Speter** Side Effects: 51638032Speter** none. 51738032Speter*/ 51838032Speter 51938032Speterchar * 52038032Spetermacvalue(n, e) 52138032Speter int n; 522168515Sgshapiro ENVELOPE *e; 52338032Speter{ 52471345Sgshapiro n = bitidx(n); 52590792Sgshapiro if (e != NULL && e->e_mci != NULL) 52690792Sgshapiro { 527168515Sgshapiro char *p = e->e_mci->mci_macro.mac_table[n]; 52890792Sgshapiro 52990792Sgshapiro if (p != NULL) 53090792Sgshapiro return p; 53190792Sgshapiro } 53238032Speter while (e != NULL) 53338032Speter { 534168515Sgshapiro char *p = e->e_macro.mac_table[n]; 53538032Speter 53638032Speter if (p != NULL) 53764562Sgshapiro return p; 53873188Sgshapiro if (e == e->e_parent) 53973188Sgshapiro break; 54038032Speter e = e->e_parent; 54138032Speter } 54290792Sgshapiro return GlobalMacros.mac_table[n]; 54338032Speter} 544168515Sgshapiro 54590792Sgshapiro/* 54638032Speter** MACNAME -- return the name of a macro given its internal id 54738032Speter** 54838032Speter** Parameter: 54938032Speter** n -- the id of the macro 55038032Speter** 55138032Speter** Returns: 55238032Speter** The name of n. 55338032Speter** 55438032Speter** Side Effects: 55538032Speter** none. 556168515Sgshapiro** 557168515Sgshapiro** WARNING: 558168515Sgshapiro** Not thread-safe. 55938032Speter*/ 56038032Speter 56138032Speterchar * 56238032Spetermacname(n) 56338032Speter int n; 56438032Speter{ 56538032Speter static char mbuf[2]; 56638032Speter 567168515Sgshapiro n = (int)(unsigned char)n; 568168515Sgshapiro if (n > MAXMACROID) 569168515Sgshapiro return "***OUT OF RANGE MACRO***"; 570168515Sgshapiro 571168515Sgshapiro /* if not ASCII printable, look up the name */ 572168515Sgshapiro if (n <= 0x20 || n > 0x7f) 57338032Speter { 57438032Speter char *p = MacroName[n]; 57538032Speter 57638032Speter if (p != NULL) 57738032Speter return p; 57838032Speter return "***UNDEFINED MACRO***"; 57938032Speter } 580168515Sgshapiro 581168515Sgshapiro /* if in the ASCII graphic range, just return the id directly */ 58238032Speter mbuf[0] = n; 58338032Speter mbuf[1] = '\0'; 58438032Speter return mbuf; 58538032Speter} 586168515Sgshapiro 58790792Sgshapiro/* 58890792Sgshapiro** MACID_PARSE -- return id of macro identified by its name 58938032Speter** 59038032Speter** Parameters: 59138032Speter** p -- pointer to name string -- either a single 59238032Speter** character or {name}. 59338032Speter** ep -- filled in with the pointer to the byte 59438032Speter** after the name. 59538032Speter** 59638032Speter** Returns: 59790792Sgshapiro** 0 -- An error was detected. 598168515Sgshapiro** 1..MAXMACROID -- The internal id code for this macro. 59938032Speter** 60038032Speter** Side Effects: 60138032Speter** If this is a new macro name, a new id is allocated. 60290792Sgshapiro** On error, syserr is called. 60338032Speter*/ 60438032Speter 60538032Speterint 60690792Sgshapiromacid_parse(p, ep) 607168515Sgshapiro char *p; 60838032Speter char **ep; 60938032Speter{ 61038032Speter int mid; 611168515Sgshapiro char *bp; 61242575Speter char mbuf[MAXMACNAMELEN + 1]; 61338032Speter 61438032Speter if (tTd(35, 14)) 61538032Speter { 61690792Sgshapiro sm_dprintf("macid("); 617132943Sgshapiro xputs(sm_debug_file(), p); 61890792Sgshapiro sm_dprintf(") => "); 61938032Speter } 62038032Speter 62138032Speter if (*p == '\0' || (p[0] == '{' && p[1] == '}')) 62238032Speter { 62338032Speter syserr("Name required for macro/class"); 62438032Speter if (ep != NULL) 62538032Speter *ep = p; 62638032Speter if (tTd(35, 14)) 62790792Sgshapiro sm_dprintf("NULL\n"); 62871345Sgshapiro return 0; 62938032Speter } 63038032Speter if (*p != '{') 63138032Speter { 63238032Speter /* the macro is its own code */ 63338032Speter if (ep != NULL) 63438032Speter *ep = p + 1; 63538032Speter if (tTd(35, 14)) 636168515Sgshapiro { 637168515Sgshapiro char buf[2]; 638168515Sgshapiro 639168515Sgshapiro buf[0] = *p; 640168515Sgshapiro buf[1] = '\0'; 641168515Sgshapiro xputs(sm_debug_file(), buf); 642168515Sgshapiro sm_dprintf("\n"); 643168515Sgshapiro } 64471345Sgshapiro return bitidx(*p); 64538032Speter } 64638032Speter bp = mbuf; 647168515Sgshapiro while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof(mbuf) - 1]) 64838032Speter { 64938032Speter if (isascii(*p) && (isalnum(*p) || *p == '_')) 65038032Speter *bp++ = *p; 65138032Speter else 65238032Speter syserr("Invalid macro/class character %c", *p); 65338032Speter } 65438032Speter *bp = '\0'; 65538032Speter mid = -1; 65638032Speter if (*p == '\0') 65738032Speter { 65838032Speter syserr("Unbalanced { on %s", mbuf); /* missing } */ 65938032Speter } 66038032Speter else if (*p != '}') 66138032Speter { 66238032Speter syserr("Macro/class name ({%s}) too long (%d chars max)", 663168515Sgshapiro mbuf, (int) (sizeof(mbuf) - 1)); 66438032Speter } 665173340Sgshapiro else if (mbuf[1] == '\0' && mbuf[0] >= 0x20) 66638032Speter { 66738032Speter /* ${x} == $x */ 66871345Sgshapiro mid = bitidx(mbuf[0]); 66938032Speter p++; 67038032Speter } 67138032Speter else 67238032Speter { 673168515Sgshapiro STAB *s; 67438032Speter 67538032Speter s = stab(mbuf, ST_MACRO, ST_ENTER); 67638032Speter if (s->s_macro != 0) 67738032Speter mid = s->s_macro; 67838032Speter else 67938032Speter { 68064562Sgshapiro if (NextMacroId > MAXMACROID) 68138032Speter { 68290792Sgshapiro syserr("Macro/class {%s}: too many long names", 68390792Sgshapiro mbuf); 68438032Speter s->s_macro = -1; 68538032Speter } 68638032Speter else 68738032Speter { 68838032Speter MacroName[NextMacroId] = s->s_name; 689173340Sgshapiro s->s_macro = mid = NextMacroId; 690173340Sgshapiro NextMacroId = NEXTMACROID(NextMacroId); 69138032Speter } 69238032Speter } 69338032Speter p++; 69438032Speter } 69538032Speter if (ep != NULL) 69638032Speter *ep = p; 69771345Sgshapiro if (mid < 0 || mid > MAXMACROID) 69871345Sgshapiro { 69971345Sgshapiro syserr("Unable to assign macro/class ID (mid = 0x%x)", mid); 70071345Sgshapiro if (tTd(35, 14)) 70190792Sgshapiro sm_dprintf("NULL\n"); 70271345Sgshapiro return 0; 70371345Sgshapiro } 70438032Speter if (tTd(35, 14)) 70590792Sgshapiro sm_dprintf("0x%x\n", mid); 70638032Speter return mid; 70738032Speter} 708168515Sgshapiro 70990792Sgshapiro/* 71038032Speter** WORDINCLASS -- tell if a word is in a specific class 71138032Speter** 71238032Speter** Parameters: 71338032Speter** str -- the name of the word to look up. 71438032Speter** cl -- the class name. 71538032Speter** 71638032Speter** Returns: 71790792Sgshapiro** true if str can be found in cl. 71890792Sgshapiro** false otherwise. 71938032Speter*/ 72038032Speter 72138032Speterbool 72238032Speterwordinclass(str, cl) 72338032Speter char *str; 72438032Speter int cl; 72538032Speter{ 726168515Sgshapiro STAB *s; 72738032Speter 72838032Speter s = stab(str, ST_CLASS, ST_FIND); 72971345Sgshapiro return s != NULL && bitnset(bitidx(cl), s->s_class); 73038032Speter} 731