//metaparser.cpp
#include "StdAfx.h"
#include "metaparser.h"
#include "valuework.hpp"
struct parsingData
{
parsingData(CString& str) : text(str)
{
// ,
// ,
pWrite = str.GetBufferSetLength(str.GetLength());
pStartAll = pWrite;
pRead = pStartAll;
pStartOfRead = pStartAll;
extraLen = 0;
modCount = 0;
}
void insertSubst(const CString& param)
{
// , .
if(pStartOfRead > pWrite)
{
DWORD lenOfBlock = pStartOfParam - pStartOfRead;
memmove(pWrite, pStartOfRead, lenOfBlock);
pWrite += lenOfBlock;
}
else
pWrite = (LPSTR)pStartOfParam;
// ,
DWORD freeSpace = pRead - pWrite, paramLen = param.GetLength();
if(paramLen <= freeSpace)
{
memcpy(pWrite, (LPCSTR)param, paramLen);
pWrite += paramLen;
}
else
{
extraLen += paramLen;
subsStrings.Add(param);
subsOffsets.Add(pWrite - pStartAll);
}
pStartOfRead = pRead;
}
void makeInserts()
{
if(pStartOfRead > pWrite)
{
memmove(pWrite, pStartOfRead, pRead - pStartOfRead);
pRead -= pStartOfRead - pWrite;
}
int newLen = pRead - pStartAll + extraLen;
if(newLen != text.GetLength())
text.GetBufferSetLength(newLen);
if(extraLen)
{
LPSTR pNewWrite = (LPSTR)(LPCSTR)text;
LPSTR pBlockEnd = pNewWrite + (pRead - pStartAll);
DWORD el = extraLen;
for(DWORD idx = subsStrings.GetSize(); idx--; )
{
LPSTR pStartOfBlock = pNewWrite + subsOffsets[idx];
const CString& param = subsStrings[idx];
memmove(pStartOfBlock + el, pStartOfBlock, pBlockEnd - pStartOfBlock);
DWORD len = param.GetLength();
el -= len;
memcpy(pStartOfBlock + el, (LPCSTR)param, len);
pBlockEnd = pStartOfBlock;
}
}
}
CString& text;
LPCSTR pStartAll, pStartOfParam, pEndOfParam, pRead, pStartOfRead;
LPSTR pWrite;
CStringArray subsStrings;
CDWordArray subsOffsets;
DWORD extraLen;
int modCount;
};
struct bindTextParam
{
const CString& paramName;
CString result;
MetaParser& mp;
bindTextParam(const CString& pn, MetaParser& _mp) : paramName(pn), mp(_mp){}
void error(LPCSTR text)
{
CString err;
err.Format(" %s - %s", (LPCSTR)paramName, text);
CBLModule::RaiseExtRuntimeError(err, FALSE);
}
void bindText(const CString& text)
{
CString tmp(text);
tmp.Replace("'", "''");
DWORD len = tmp.GetLength();
LPSTR ptr = result.GetBufferSetLength(len + 2);
*ptr = '\'';
memcpy(ptr + 1, (LPCSTR)tmp, len);
ptr[len + 1] = '\'';
}
void bindNumeric(const CValue* pValue)
{
result = pValue->GetString();
}
void bindNull()
{
result = "NULL";
}
void bindFragment(const CString& str)
{
result = str;
mp.processSql(result);
}
void bindMDID36(CMetaDataObj* pObj, int mod)
{
if(!pObj)
error(" ");
switch(mod)
{
case 0:
{
BYTE* ptr = (BYTE*)result.GetBufferSetLength(6);
ptr[0] = '\'';
*(DWORD*)(ptr + 1) = ' ';
id2str(pObj->m_ID, ptr + 1, 4);
ptr[5] = '\'';
}
break;
case 1:
result.Format("%i", pObj->m_ID);
break;
default:
error(" ");
}
}
};
CMetaDataObj* findConstant(const CString& name) {return pMetaDataCont->GetConstDef(name);}
CMetaDataObj* findReference(const CString& name) {return pMetaDataCont->GetSTypeDef(name);}
CMetaDataObj* findDocument(const CString& name) {return pMetaDataCont->GetDocDef(name);}
CMetaDataObj* findEnum(const CString& name) {return pMetaDataCont->GetEnumDef(name);}
CMetaDataObj* findJournal(const CString& name) {return pMetaDataCont->GetJournalDef(name);}
CMetaDataObj* findSelCol(const CString& name) {return pMetaDataCont->GenDocSelRefs()->GetItem(name);}
CMetaDataObj* findCalendar(const CString& name) {return pMetaDataCont->GetCalendarTypeDef(name);}
CMetaDataObj* findCalcJournal(const CString& name) {return pMetaDataCont->GetCJDef(name);}
CMetaDataObj* findAlgorithm(const CString& name) {return pMetaDataCont->GetAlgorithmDef(name);}
CMetaDataObj* findSbcntKind(const CString& name)
{
CBuhDef* pBuh = pMetaDataCont->GetBuhDef();
if(pBuh)
return pBuh->GetSbKindDefs()->GetItem(name);
return NULL;
}
CMetaDataObj* findChartOfAccs(const CString& name)
{
CBuhDef* pBuh = pMetaDataCont->GetBuhDef();
if(pBuh)
return pBuh->GetPlanDef(name);
return NULL;
}
template<typename Op>
void bindMetaNameObj(bindTextParam& binder, int mod, CStringArray& parts, Op op)
{
if(parts.GetSize() == 2)
binder.bindMDID36(op(parts[1]), mod);
}
inline static void bindHistoryProp(bindTextParam& binder, int mod, CStringArray& parts)
{
if(parts.GetSize() == 3)
{
CSbCntTypeDef* pRef = pMetaDataCont->GetSTypeDef(parts[1]);
if(pRef)
{
CSbCntParamDef* pProp = pRef->GetParamDef(parts[2]);
if(pProp && pProp->IsDateDep())
binder.bindMDID36(pProp, mod);
}
}
}
void isMetaName(bindTextParam& binder, int mod)
{
static struct prefix_finder
{
enum{
mnConst, mnRefKind, mnDocKind, mnEnumKind, mnPeriodic,
mnJournal, mnSelCol, mnCalendar, mnHolidays, mnCalcJournal, mnAlgorithm,
mnEmptyID, mnEmptyID13, mnEnum, mnSubcKind, mnChartOfAccs,
};
prefix_finder()
{
static struct {LPCSTR name1, name2; int idx;} prefixes[] = {
{"", "Constant", mnConst},
{"", "ReferenceKind", mnRefKind},
{"", "DocumentKind", mnDocKind},
{"", "EnumKind", mnEnumKind},
{"", "PropertyHistory", mnPeriodic},
{"", "DocsJournal", mnJournal},
{"", "SelectionColumn", mnSelCol},
{"", "Calendar", mnCalendar},
{"", "Holidays", mnHolidays},
{"", "CalcJournalKind", mnCalcJournal},
{"", "Algorithm", mnAlgorithm},
{"", "EmptyID", mnEmptyID},
{"13", "EmptyID13", mnEmptyID13},
{"", "Enumeration", mnEnum},
{"", "SubcKind", mnSubcKind},
{"", "ChartOfAccounts", mnChartOfAccs},
};
for(DWORD i = 0; i < sizeof(prefixes) / sizeof(prefixes[0]); i++)
{
prefMap[prefixes[i].name1] = prefixes[i].idx;
prefMap[prefixes[i].name2] = prefixes[i].idx;
}
}
int find(const CString& name)
{
int idx = -1;
prefMap.Lookup(name, idx);
return idx;
}
CNoCaseMap<int> prefMap;
}finder;
CStringArray parts;
SplitStr2Array(binder.paramName, parts, '.');
int countOfParts = parts.GetSize();
if(!countOfParts)
binder.error(" ");
switch(finder.find(parts[0]))
{
case prefix_finder::mnConst:
bindMetaNameObj(binder, mod, parts, findConstant);
break;
case prefix_finder::mnRefKind:
bindMetaNameObj(binder, mod, parts, findReference);
break;
case prefix_finder::mnDocKind:
bindMetaNameObj(binder, mod, parts, findDocument);
break;
case prefix_finder::mnEnumKind:
bindMetaNameObj(binder, mod, parts, findEnum);
break;
case prefix_finder::mnPeriodic:
bindHistoryProp(binder, mod, parts);
break;
case prefix_finder::mnJournal:
bindMetaNameObj(binder, mod, parts, findJournal);
break;
case prefix_finder::mnSelCol:
bindMetaNameObj(binder, mod, parts, findSelCol);
break;
case prefix_finder::mnCalendar:
bindMetaNameObj(binder, mod, parts, findCalendar);
break;
case prefix_finder::mnHolidays:
if(countOfParts == 1)
binder.bindMDID36(pMetaDataCont->GetHolidaysDef(), mod);
break;
case prefix_finder::mnCalcJournal:
bindMetaNameObj(binder, mod, parts, findCalcJournal);
break;
case prefix_finder::mnAlgorithm:
bindMetaNameObj(binder, mod, parts, findAlgorithm);
break;
case prefix_finder::mnEmptyID:
if(countOfParts == 1)
binder.result = "' 0 '";
break;
case prefix_finder::mnEmptyID13:
if(countOfParts == 1)
binder.result = "' 0 0 '";
break;
case prefix_finder::mnEnum:
if(countOfParts == 3)
{
CEnumDef* pDef = pMetaDataCont->GetEnumDef(parts[1]);
if(pDef)
{
CEnumValDef* pVal = pDef->GetValDef(parts[2]);
if(pVal)
{
unsigned char* ptr = (unsigned char*)binder.result.GetBufferSetLength(11);
*ptr = '\'';
*(DWORD*)(ptr + 1) = ' ';
*(DWORD*)(ptr + 5) = ' ';
*(WORD*)(ptr + 9) = '\' ';
id2str(pVal->m_ID, ptr + 1, 6);
}
}
}
break;
case prefix_finder::mnSubcKind:
bindMetaNameObj(binder, mod, parts, findSbcntKind);
break;
case prefix_finder::mnChartOfAccs:
bindMetaNameObj(binder, mod, parts, findChartOfAccs);
break;
}
if(binder.result.IsEmpty())
binder.error(" ");
}
void MetaParser::processParam(parsingData& pd)
{
CString paramName(pd.pStartOfParam + 1, pd.pEndOfParam - pd.pStartOfParam - 1);
bindTextParam bt(paramName, *this);
if(textParams.IsExist(paramName))
bindValue(bt, &textParams[paramName], pd.modCount);
else
isMetaName(bt, pd.modCount);
pd.insertSubst(bt.result);
}
void MetaParser::processSql(CString& sql)
{
enum States{
stNone,
stMinus,
stLineRemark,
stDiv,
stMultiRemark,
stMultiRemarkMult,
stQuote,
stBraket,
stParam,
stParamMod,
};
// ,
// --, /**/
// '' []
// :
// ,
// , -, .
parsingData pd(sql);
States state = stNone;
for(;;)
{
DWORD s = (DWORD)(BYTE)*pd.pRead;
switch(state)
{
case stNone:
if('-' == s)
state = stMinus;
else if('/' == s)
state = stDiv;
else if('\'' == s)
state = stQuote;
else if('[' == s)
state = stBraket;
else if(':' == s)
{
pd.pStartOfParam = pd.pRead;
state = stParam;
}
break;
case stMinus:
if('-' == s)
state = stLineRemark;
else if('/' == s)
state = stDiv;
else if('\'' == s)
state = stQuote;
else if('[' == s)
state = stBraket;
else if(':' == s)
{
pd.pStartOfParam = pd.pRead;
state = stParam;
}
else
state = stNone;
break;
case stLineRemark:
if('\n' == s)
state = stNone;
break;
case stDiv:
if('*' == s)
state = stMultiRemark;
else if('\'' == s)
state = stQuote;
else if('[' == s)
state = stBraket;
else if(':' == s)
{
pd.pStartOfParam = pd.pRead;
state = stParam;
}
else if('-' == s)
state = stMinus;
else if('/' != s)
state = stNone;
break;
case stMultiRemark:
if('*' == s)
state = stMultiRemarkMult;
break;
case stMultiRemarkMult:
if('/' == s)
state = stNone;
else if('*' != s)
state = stMultiRemark;
break;
case stQuote:
if('\'' == s)
state = stNone;
break;
case stBraket:
if(']' == s)
state = stNone;
break;
case stParam:
if('~' == s)
{
pd.pEndOfParam = pd.pRead;
pd.modCount = 1;
state = stParamMod;
}
else if('*' == s)
{
pd.pEndOfParam = pd.pRead;
pd.modCount = -1;
pd.pRead++;
processParam(pd);
pd.pRead--;
state = stNone;
}
else if(! (s >= 129 || (s >= '0' && s <= '9') || s == '.' || s == '_' || (s >= 'A' && s <= 'Z') ||
(s >= 'a' && s <= 'z')))
{
pd.pEndOfParam = pd.pRead;
pd.modCount = 0;
processParam(pd);
state = stNone;
}
break;
case stParamMod:
if('~' == s)
pd.modCount++;
else
{
processParam(pd);
state = stNone;
}
break;
}
if(!s)
break;
pd.pRead++;
}
pd.makeInserts();
}