/* Copyright (C) Microsoft Corporation, 1998. All rights reserved. */ #include "precomp.h" #include "macro.h" CMacro:: CMacro ( BOOL *pfRetCode, LPSTR pszMacroName, UINT cbMaxBodySize ) : m_ArgList(8), // default 8 arguments m_MacroInstList(16), // default 16 instances of this macro m_cFormalArgs(0), m_cbBodySize(0), m_cbMaxBodySize(cbMaxBodySize), m_pszExpandBuffer(NULL), m_fArgExistsInBody(FALSE), m_fImported(FALSE) { m_pszMacroName = ::My_strdup(pszMacroName); m_pszBodyBuffer = new char[m_cbMaxBodySize]; m_pszCurr = m_pszBodyBuffer; *pfRetCode = (NULL != m_pszMacroName) && (NULL != m_pszBodyBuffer); } CMacro:: CMacro ( BOOL *pfRetCode, CMacro *pMacro ) : m_ArgList(pMacro->m_ArgList.GetCount()), // default 8 arguments m_MacroInstList(16), // default 16 instances of this macro m_cFormalArgs(pMacro->m_cFormalArgs), m_cbBodySize(pMacro->m_cbBodySize), m_cbMaxBodySize(pMacro->m_cbMaxBodySize), m_pszExpandBuffer(NULL), m_fArgExistsInBody(pMacro->m_fArgExistsInBody), m_fImported(TRUE) { m_pszMacroName = ::My_strdup(pMacro->m_pszMacroName); m_pszBodyBuffer = new char[m_cbMaxBodySize]; if (NULL != m_pszMacroName && NULL != m_pszBodyBuffer) { // copy the body ::memcpy(m_pszBodyBuffer, pMacro->m_pszBodyBuffer, pMacro->m_cbBodySize); // adjust the current buffer pointer m_pszCurr = m_pszBodyBuffer + m_cbBodySize; // null terminated the body *m_pszCurr++ = '\0'; // set up the expand buffer m_pszExpandBuffer = m_pszCurr; *pfRetCode = TRUE; } else { *pfRetCode = FALSE; } } CMacro:: ~CMacro ( void ) { delete m_pszBodyBuffer; Uninstance(); } void CMacro:: Uninstance ( void ) { m_ArgList.DeleteList(); m_MacroInstList.DeleteList(); } BOOL CMacro:: SetBodyPart ( LPSTR pszBodyPart ) { UINT cch = ::strlen(pszBodyPart); ASSERT(m_pszCurr + cch + 1 < m_pszBodyBuffer + m_cbMaxBodySize); if (m_pszCurr + cch + 1 < m_pszBodyBuffer + m_cbMaxBodySize) { LPSTR psz; m_ArgList.Reset(); for (UINT i = 0; NULL != (psz = m_ArgList.Iterate()); i++) { if (0 == ::strcmp(pszBodyPart, psz)) { // this is an argument m_fArgExistsInBody = TRUE; *m_pszCurr++ = ARG_ESCAPE_CHAR; *m_pszCurr++ = ARG_INDEX_BASE + i; return TRUE; } } // this is not an argument. ::memcpy(m_pszCurr, pszBodyPart, cch); m_pszCurr += cch; *m_pszCurr = '\0'; return TRUE; } return FALSE; } void CMacro:: EndMacro ( void ) { // save the count of arguments m_cFormalArgs = m_ArgList.GetCount(); // calculate the size of the body m_cbBodySize = m_pszCurr - m_pszBodyBuffer; // null terminated the body *m_pszCurr++ = '\0'; // set up the expand buffer m_pszExpandBuffer = m_pszCurr; // free the memory DeleteArgList(); } BOOL CMacro:: InstantiateMacro ( void ) { BOOL rc = FALSE; // assume failure LPSTR pszInstName, pszSrc, pszDst; UINT i, cch; CMacroInstance *pInst; if (! m_fArgExistsInBody) { // No need to instantiate because the body does not contain any argument. // We can take the body as the instance. rc = TRUE; goto MyExit; } ASSERT(m_ArgList.GetCount() == m_cFormalArgs); if (m_ArgList.GetCount() != m_cFormalArgs) { goto MyExit; } pszInstName = CreateInstanceName(); if (NULL == pszInstName) { goto MyExit; } m_MacroInstList.Reset(); while (NULL != (pInst = m_MacroInstList.Iterate())) { if (0 == ::strcmp(pszInstName, pInst->GetName())) { // same instance has been instantiated before. rc = TRUE; delete pszInstName; goto MyExit; } } // Let's instantiate a new instance... pszSrc = m_pszBodyBuffer; pszDst = m_pszExpandBuffer; // put in macro name first ::strcpy(pszDst, pszInstName); pszDst += ::strlen(pszDst); // put in macro body now. while (*pszSrc != '\0') { if (*pszSrc == ARG_ESCAPE_CHAR) { pszSrc++; i = *pszSrc++ - ARG_INDEX_BASE; ASSERT(i < m_ArgList.GetCount()); LPSTR pszArgName = m_ArgList.GetNthItem(i); cch = ::strlen(pszArgName); ::memcpy(pszDst, pszArgName, cch); pszDst += cch; } else { *pszDst++ = *pszSrc++; } } *pszDst++ = '\n'; *pszDst = '\0'; // create an instance pInst = new CMacroInstance(&rc, pszInstName, pszDst - m_pszExpandBuffer, m_pszExpandBuffer); if (NULL != pInst && rc) { m_MacroInstList.Append(pInst); } MyExit: // free up temporary argument names m_ArgList.DeleteList(); return rc; } BOOL CMacro:: OutputInstances ( COutput *pOutput ) { BOOL rc = TRUE; CMacroInstance *pInst; if (m_fArgExistsInBody) { m_MacroInstList.Reset(); while (NULL != (pInst = m_MacroInstList.Iterate())) { rc = pOutput->Write(pInst->GetBuffer(), pInst->GetBufSize()); ASSERT(rc); } } else { rc = pOutput->Write(m_pszMacroName, ::strlen(m_pszMacroName)); ASSERT(rc); rc = pOutput->Writeln(m_pszBodyBuffer, m_cbBodySize); ASSERT(rc); } return rc; } LPSTR CMacro:: CreateInstanceName ( void ) { UINT cch = ::strlen(m_pszMacroName) + 2; UINT i; LPSTR psz, pszArgName; if (m_fArgExistsInBody) { ASSERT(m_ArgList.GetCount() == m_cFormalArgs); m_ArgList.Reset(); while (NULL != (pszArgName = m_ArgList.Iterate())) { cch += ::strlen(pszArgName) + 1; } } LPSTR pszInstanceName = new char[cch]; if (NULL != pszInstanceName) { psz = pszInstanceName; ::strcpy(psz, m_pszMacroName); if (m_fArgExistsInBody) { psz += ::strlen(psz); m_ArgList.Reset(); while (NULL != (pszArgName = m_ArgList.Iterate())) { *psz++ = '-'; ::strcpy(psz, pszArgName); psz += ::strlen(psz); } } } return pszInstanceName; } CMacro * CMacroMgrList:: FindMacro ( LPSTR pszModuleName, LPSTR pszMacroName ) { CMacroMgr *pMacroMgr = FindMacroMgr(pszModuleName); return (NULL != pMacroMgr) ? pMacroMgr->FindMacro(pszMacroName) : NULL; } CMacroMgr * CMacroMgrList:: FindMacroMgr ( LPSTR pszModuleName ) { CMacroMgr *pMacroMgr; Reset(); while (NULL != (pMacroMgr = Iterate())) { if (0 == ::strcmp(pszModuleName, pMacroMgr->GetModuleName())) { return pMacroMgr; } } return NULL; } void CMacroMgrList:: Uninstance ( void ) { CMacroMgr *pMacroMgr; Reset(); while (NULL != (pMacroMgr = Iterate())) { pMacroMgr->Uninstance(); } } CMacroMgr:: CMacroMgr ( void ) : m_MacroList(16), // default 16 macros m_pszModuleName(NULL) { } CMacroMgr:: ~CMacroMgr ( void ) { m_MacroList.DeleteList(); delete m_pszModuleName; } BOOL CMacroMgr:: AddModuleName ( LPSTR pszModuleName ) { // can only be set once ASSERT(NULL == m_pszModuleName); m_pszModuleName = ::My_strdup(pszModuleName); ASSERT(NULL != m_pszModuleName); return (NULL != m_pszModuleName); } CMacro *CMacroMgr:: FindMacro ( LPSTR pszMacroName ) { CMacro *pMacro; m_MacroList.Reset(); while (NULL != (pMacro = m_MacroList.Iterate())) { if (0 == ::strcmp(pszMacroName, pMacro->GetName())) { return pMacro; } } return NULL; } BOOL CMacroMgr:: OutputImportedMacros ( COutput *pOutput ) { BOOL rc = TRUE; CMacro *pMacro; rc = pOutput->Write("\n\n", 2); m_MacroList.Reset(); while (NULL != (pMacro = m_MacroList.Iterate())) { if (pMacro->IsImported()) { rc = pMacro->OutputInstances(pOutput); if (! rc) { ASSERT(0); return FALSE; } } } return rc; } void CMacroMgr:: Uninstance ( void ) { CMacro *pMacro; m_MacroList.Reset(); while (NULL != (pMacro = m_MacroList.Iterate())) { pMacro->Uninstance(); } } CMacroInstance:: CMacroInstance ( BOOL *pfRetCode, LPSTR pszInstanceName, UINT cbBufSize, LPSTR pszInstBuf ) : m_pszInstanceName(pszInstanceName), m_cbBufSize(cbBufSize) { m_pszInstanceBuffer = new char[m_cbBufSize]; if (NULL != m_pszInstanceBuffer) { ::memcpy(m_pszInstanceBuffer, pszInstBuf, m_cbBufSize); } *pfRetCode = (NULL != m_pszInstanceName) && (NULL != m_pszInstanceBuffer); } CMacroInstance:: ~CMacroInstance ( void ) { delete m_pszInstanceName; delete m_pszInstanceBuffer; } void CMacroInstList:: DeleteList ( void ) { CMacroInstance *pInst; while (NULL != (pInst = Get())) { delete pInst; } } void CMacroList:: DeleteList ( void ) { CMacro *pMacro; while (NULL != (pMacro = Get())) { delete pMacro; } } void CMacroMgrList:: DeleteList ( void ) { CMacroMgr *pMacroMgr; while (NULL != (pMacroMgr = Get())) { delete pMacroMgr; } } BOOL CNameList:: AddName ( LPSTR pszName ) { pszName = ::My_strdup(pszName); if (NULL != pszName) { Append(pszName); return TRUE; } return FALSE; } LPSTR CNameList:: GetNthItem ( UINT nth ) { LPSTR psz; if (nth < GetCount()) { Reset(); do { psz = Iterate(); } while (nth--); } else { psz = NULL; } return psz; } void CNameList:: DeleteList ( void ) { LPSTR psz; while (NULL != (psz = Get())) { delete psz; } }