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