# $Id: evector.m,v 1.9 2010/09/16 18:35:40 ksb Exp $ # Like distrib's elist abstraction, but later in my skills (ksb) # require "util_ppm.m" %hi #if !defined(EVECTOR_H) /* A vector of these represents our macro defines, they are in the * order defined, because m4 macros are order dependent. Last name is NULL. * I know a lexical sort would make updates faster, that's not reason * enough to break the order semanitics here -- ksb. * We depend on ppm from mkcmd, of course. And we leak memory like we are * inside a CGI! This is not mean for a long running application. -- ksb */ typedef struct MDnode { const char *pcname, *pcvalue; /* name defined as value */ } MACRO_DEF; extern int ScanMacros(MACRO_DEF *, int (*)(const char *, const char *, void *), void *); extern void BindMacro(const char *, const char *); extern MACRO_DEF *CurrentMacros(); extern const char *MacroValue(const char *, MACRO_DEF *); extern void ResetMacros(); extern MACRO_DEF *MergeMacros(MACRO_DEF *, MACRO_DEF *); #define EVECTOR_H 1 #endif %% %i static char rcs_evector[] = "$Id: evector.m,v 1.9 2010/09/16 18:35:40 ksb Exp $"; static void MacroStart(); %% init 4 "MacroStart();" %c static PPM_BUF PPMCurMacros; static unsigned uMacroCount; /* retsart the macro list (ksb) */ static void MacroStart() { register MACRO_DEF *pMD; uMacroCount = 0; util_ppm_init(& PPMCurMacros, sizeof(MACRO_DEF), 128); pMD = (MACRO_DEF *)util_ppm_size(& PPMCurMacros, 128); pMD->pcname = (const char *)0; pMD->pcvalue = (const char *)0; } /* Process the list in order, return the first (ksb) * nonzero result from the Call function */ int ScanMacros(MACRO_DEF *pMDList, int (*pfiCall)(const char *, const char *, void *), void *pvData) { register int iRet; if ((MACRO_DEF *)0 == pMDList) { return 0; } for (iRet = 0; (const char *)0 != pMDList->pcname; ++pMDList) { if (0 != (iRet = pfiCall(pMDList->pcname, pMDList->pcvalue, pvData))) break; } return iRet; } /* Replace the value of the given macro in the current list (ksb) */ void BindMacro(const char *pcName, const char *pcValue) { register unsigned i; register MACRO_DEF *pMD; pMD = util_ppm_size(& PPMCurMacros, 1); for (i = 0; i < uMacroCount; ++i, ++pMD) { if (0 == strcmp(pMD->pcname, pcName)) break; } if (i != uMacroCount) { pMD->pcvalue = pcValue; return; } /* Resize and add the new one to the end */ pMD = util_ppm_size(& PPMCurMacros, ((uMacroCount+1)|31)+1); pMD[uMacroCount].pcname = pcName; pMD[uMacroCount].pcvalue = pcValue; ++uMacroCount; pMD[uMacroCount].pcname = (const char *)0; pMD[uMacroCount].pcvalue = (const char *)0; } /* Save the list as it is now, don't save the undefined ones (ksb) */ MACRO_DEF * CurrentMacros() { register unsigned i, iData; register MACRO_DEF *pMDCur, *pMDRet; pMDCur = util_ppm_size(& PPMCurMacros, 0); iData = 0; for (i = 0; i < uMacroCount; ++i) { if ((const char *)0 != pMDCur[i].pcvalue) ++iData; } if ((MACRO_DEF *)0 == (pMDRet = (MACRO_DEF *)calloc((iData|7)+1, sizeof(MACRO_DEF)))) { return (MACRO_DEF *)0; } iData = 0; for (i = 0; i < uMacroCount; ++i) { if ((const char *)0 == pMDCur[i].pcvalue) continue; pMDRet[iData].pcname = pMDCur[i].pcname; pMDRet[iData].pcvalue = pMDCur[i].pcvalue; ++iData; } pMDRet[iData].pcname = (const char *)0; pMDRet[iData].pcvalue = (const char *)0; return pMDRet; } /* return the current definition of a single macro from the tableau (ksb) */ const char * CurrentDef(const char *pcName, const char *pcDefValue) { register MACRO_DEF *pMDCur; register unsigned i; pMDCur = util_ppm_size(& PPMCurMacros, 0); for (i = 0; i++ < uMacroCount; ++pMDCur) if (0 == strcmp(pMDCur->pcname, pcName)) return pMDCur->pcvalue; return pcDefValue; } /* Merge two macro lists, the first wins in any overlap (ksb) * I know we N**2 when we could do better, but the order of the macros * is important to m4.dnl */ MACRO_DEF * MergeMacros(MACRO_DEF *pMDLeft, MACRO_DEF *pMDRight) { register MACRO_DEF *pMDCur, *pMDRet; register unsigned iLeft, iData, j; iData = 0; for (pMDCur = pMDLeft; (const char *)0 != pMDCur->pcname; ++pMDCur) { ++iData; } iLeft = iData; for (pMDCur = pMDRight; (const char *)0 != pMDCur->pcname; ++pMDCur) { ++iData; } if ((MACRO_DEF *)0 == (pMDRet = (MACRO_DEF *)calloc((iData|3)+1, sizeof(MACRO_DEF)))) { return (MACRO_DEF *)0; } iData = 0; for (pMDCur = pMDLeft; (const char *)0 != pMDCur->pcname; ++pMDCur) { pMDRet[iData].pcname = pMDCur->pcname; pMDRet[iData].pcvalue = pMDCur->pcvalue; ++iData; } for (pMDCur = pMDRight; (const char *)0 != pMDCur->pcname; ++pMDCur) { for (j = 0; j < iLeft; ++j) { if (0 == strcmp(pMDRet[j].pcname, pMDCur->pcname)) break; } if (j < iLeft) continue; pMDRet[iData].pcname = pMDCur->pcname; pMDRet[iData].pcvalue = pMDCur->pcvalue; ++iData; } return pMDRet; } /* Reset the list of bound macros at the top of the next config. (ksb) * Due to the many pointers refernecing the strings we can't free anything. */ void ResetMacros() { register unsigned i; register MACRO_DEF *pMDCur; pMDCur = util_ppm_size(& PPMCurMacros, 0); for (i = 0; i < uMacroCount; ++i) { pMDCur[i].pcvalue = (const char *)0; } } /* Recover the value from a fixed macro list for a given name (ksb) * We know the "fixed" list only has defined values, BTW. */ const char * MacroValue(const char *pcName, MACRO_DEF *pMDList) { for (/*param*/; (const char *)0 != pMDList->pcname; ++pMDList) { if (0 == strcmp(pMDList->pcname, pcName)) return pMDList->pcvalue; } return (const char *)0; } %%