00001 #include <qpro/common.h>
00002
00003 #include <iostream>
00004 #include <strstream>
00005
00006 #include <string.h>
00007
00008 #include <qpro/formula.h>
00009 #include <qpro/stream.h>
00010
00011
00012
00013
00014 QpFormulaStack::QpFormulaStack()
00015 : cIdx(-1)
00016 , cMax(3)
00017 {
00018 cStack = new char*[cMax];
00019 }
00020
00021 QpFormulaStack::~QpFormulaStack()
00022 {
00023 }
00024
00025 void
00026 QpFormulaStack::bracket(const char* pBefore, const char* pAfter)
00027 {
00028 if( cIdx >= 0 )
00029 {
00030 int lLen = strlen(cStack[cIdx]) + 1;
00031
00032 if( pBefore ) lLen += strlen(pBefore);
00033
00034 if( pAfter ) lLen += strlen(pAfter);
00035
00036 char* lNew = new char[ lLen ];
00037
00038 lNew[0] = '\0';
00039
00040 if( pBefore ) strcpy( lNew, pBefore );
00041
00042 strcat( lNew, cStack[cIdx] );
00043
00044 if( pAfter ) strcat( lNew, pAfter );
00045
00046 delete [] cStack[cIdx];
00047 cStack[cIdx] = lNew;
00048 }
00049 }
00050
00051 void
00052 QpFormulaStack::join(int pCnt, const char* pSeparator)
00053 {
00054 int lFirstIdx = 1 - pCnt;
00055
00056 if( pCnt > 0 && (cIdx-lFirstIdx) >=0 )
00057 {
00058 int lSepLen = strlen(pSeparator);
00059 int lLen = lSepLen * (pCnt-1) +1;
00060
00061 for(int lIdx=lFirstIdx; lIdx <= 0; ++lIdx)
00062 {
00063 lLen += strlen( cStack[cIdx + lIdx] );
00064 }
00065
00066 char* lNew = new char[lLen];
00067
00068 lNew[0] = '\0';
00069
00070 for(int lIdx=lFirstIdx; lIdx <= 0; ++lIdx)
00071 {
00072 strcat( lNew, cStack[cIdx + lIdx] );
00073 if( lIdx != 0 )
00074 {
00075 strcat( lNew, pSeparator );
00076 }
00077 }
00078
00079 pop(pCnt);
00080
00081 push(lNew);
00082
00083 delete [] lNew;
00084 }
00085 }
00086
00087 void
00088 QpFormulaStack::pop(int pCnt)
00089 {
00090 while( cIdx >= 0 && pCnt-- )
00091 {
00092 delete [] cStack[cIdx--];
00093 }
00094 }
00095
00096 void
00097 QpFormulaStack::push(const char* pString)
00098 {
00099 ++cIdx;
00100
00101 if(cIdx == cMax)
00102 {
00103 cMax += 10;
00104
00105 char** cTemp = new char*[cMax];
00106
00107 for(int lIdx=0; lIdx<cIdx; ++lIdx)
00108 {
00109 cTemp[lIdx] = cStack[lIdx];
00110 }
00111
00112 delete [] cStack;
00113 cStack = cTemp;
00114 }
00115
00116 cStack[cIdx] = strcpy(new char[strlen(pString)+1], pString);
00117 }
00118
00119 const char*
00120 QpFormulaStack::top()
00121 {
00122 return (cIdx >=0 ? cStack[cIdx] : 0);
00123 }
00124
00125 const char*
00126 QpFormulaStack::operator [] (int pIdx)
00127 {
00128 char* lResult = 0;
00129
00130 if( pIdx <= 0 && (cIdx + pIdx) >= 0 )
00131 {
00132 lResult = cStack[cIdx + pIdx];
00133 }
00134
00135 return lResult;
00136 }
00137
00138
00139
00140 static const QpFormulaConv gConv[] =
00141 {
00142 {0, QpFormula::floatFunc, 0},
00143 {1, QpFormula::ref, 0},
00144 {2, QpFormula::ref, 0},
00145 {4, QpFormula::func1, "("},
00146 {5, QpFormula::intFunc, 0},
00147 {6, QpFormula::stringFunc, 0},
00148
00149 {8, QpFormula::unaryOperand, "-"},
00150 {9, QpFormula::binaryOperand, "+"},
00151 {10, QpFormula::binaryOperand, "-"},
00152 {11, QpFormula::binaryOperand, "*"},
00153 {12, QpFormula::binaryOperand, "/"},
00154 {13, QpFormula::binaryOperand, "^"},
00155 {14, QpFormula::binaryOperand, "="},
00156 {15, QpFormula::binaryOperand, "<>"},
00157 {16, QpFormula::binaryOperand, "<="},
00158 {17, QpFormula::binaryOperand, ">="},
00159 {18, QpFormula::binaryOperand, "<"},
00160 {19, QpFormula::binaryOperand, ">"},
00161 {20, QpFormula::binaryOperand, "#AND#"},
00162 {21, QpFormula::binaryOperand, "#OR#"},
00163 {22, QpFormula::unaryOperand, "#NOT#"},
00164 {23, QpFormula::unaryOperand, "+"},
00165 {24, QpFormula::binaryOperand, "&"},
00166
00167
00168
00169
00170
00171
00172
00173 {32, QpFormula::func0, "@err"},
00174 {33, QpFormula::func1, "@abs("},
00175 {34, QpFormula::func1, "@int("},
00176 {35, QpFormula::func1, "@sqrt("},
00177 {36, QpFormula::func1, "@log("},
00178 {37, QpFormula::func1, "@ln("},
00179 {38, QpFormula::func0, "@pi"},
00180 {39, QpFormula::func1, "@sin("},
00181 {40, QpFormula::func1, "@cos("},
00182 {41, QpFormula::func1, "@tan("},
00183 {42, QpFormula::func2, "@atan2("},
00184 {43, QpFormula::func1, "@atan("},
00185 {44, QpFormula::func1, "@asin("},
00186 {45, QpFormula::func1, "@acos("},
00187 {46, QpFormula::func1, "@exp("},
00188 {47, QpFormula::func2, "@mod("},
00189 {48, QpFormula::funcV, "@choose("},
00190 {49, QpFormula::func1, "@isna("},
00191 {50, QpFormula::func1, "@iserr("},
00192 {51, QpFormula::func0, "@false"},
00193 {52, QpFormula::func0, "@true"},
00194 {53, QpFormula::func0, "@rand"},
00195 {54, QpFormula::func3, "@date("},
00196 {55, QpFormula::func0, "@now"},
00197 {56, QpFormula::func3, "@pmt("},
00198 {57, QpFormula::func3, "@pv("},
00199 {58, QpFormula::func3, "@fv("},
00200 {59, QpFormula::func3, "@if("},
00201 {60, QpFormula::func1, "@day("},
00202 {61, QpFormula::func1, "@month("},
00203 {62, QpFormula::func1, "@year("},
00204 {63, QpFormula::func2, "@round("},
00205 {64, QpFormula::func3, "@time("},
00206 {65, QpFormula::func1, "@hour("},
00207 {66, QpFormula::func1, "@minute("},
00208 {67, QpFormula::func1, "@second("},
00209 {68, QpFormula::func1, "@isnumber("},
00210 {69, QpFormula::func1, "@isstring("},
00211 {70, QpFormula::func1, "@length("},
00212 {71, QpFormula::func1, "@value("},
00213 {72, QpFormula::func2, "@string("},
00214 {73, QpFormula::func3, "@mid("},
00215 {74, QpFormula::func1, "@char("},
00216 {75, QpFormula::func1, "@code("},
00217 {76, QpFormula::func3, "@find("},
00218 {77, QpFormula::func1, "@dateVal("},
00219 {78, QpFormula::func1, "@timeVal("},
00220 {79, QpFormula::func1, "@cellPtr("},
00221 {80, QpFormula::funcV, "@sum("},
00222 {81, QpFormula::funcV, "@avg("},
00223 {82, QpFormula::funcV, "@count("},
00224 {83, QpFormula::funcV, "@min("},
00225 {84, QpFormula::funcV, "@max("},
00226 {85, QpFormula::func3, "@vlookup("},
00227 {86, QpFormula::func2, "@npv("},
00228 {87, QpFormula::funcV, "@var("},
00229 {88, QpFormula::funcV, "@std("},
00230 {89, QpFormula::func2, "@irr("},
00231 {90, QpFormula::func3, "@hlookup("},
00232 {91, QpFormula::func3, "@dsum("},
00233 {92, QpFormula::func3, "@davg("},
00234 {93, QpFormula::func3, "@dcount("},
00235 {94, QpFormula::func3, "@dmin("},
00236 {95, QpFormula::func3, "@dmax("},
00237 {96, QpFormula::func3, "@dvar("},
00238 {97, QpFormula::func3, "@dstd("},
00239 {98, QpFormula::func3, "@index("},
00240 {99, QpFormula::func1, "@cols("},
00241 {100, QpFormula::func1, "@rows("},
00242 {101, QpFormula::func2, "@repeat("},
00243 {102, QpFormula::func1, "@upper("},
00244 {103, QpFormula::func1, "@lower("},
00245 {104, QpFormula::func2, "@left("},
00246 {105, QpFormula::func2, "@right("},
00247 {106, QpFormula::func4, "@replace("},
00248 {107, QpFormula::func1, "@proper("},
00249 {108, QpFormula::func2, "@cell("},
00250 {109, QpFormula::func1, "@trim("},
00251 {110, QpFormula::func1, "@clean("},
00252 {111, QpFormula::func1, "@s("},
00253 {112, QpFormula::func1, "@n("},
00254 {113, QpFormula::func1, "@exact("},
00255
00256 {115, QpFormula::func1, "@@("},
00257 {116, QpFormula::func3, "@rate("},
00258 {117, QpFormula::func3, "@term("},
00259 {118, QpFormula::func3, "@cterm("},
00260 {119, QpFormula::func3, "@sln("},
00261 {120, QpFormula::func4, "@syd("},
00262 {121, QpFormula::func4, "@ddb("},
00263 {122, QpFormula::funcV, "@stds("},
00264 {123, QpFormula::funcV, "@vars("},
00265 {124, QpFormula::func1, "@dstds("},
00266 {125, QpFormula::func1, "@dvars("},
00267 {126, QpFormula::func1, "@pval("},
00268 {127, QpFormula::func1, "@paymt("},
00269 {128, QpFormula::func1, "@fval("},
00270 {129, QpFormula::func1, "@nper("},
00271 {130, QpFormula::func1, "@irate("},
00272 {131, QpFormula::func1, "@ipaymt("},
00273 {132, QpFormula::func1, "@ppaymt("},
00274 {133, QpFormula::func1, "@sumproduct("},
00275 {134, QpFormula::func1, "@memavail("},
00276 {135, QpFormula::func1, "@mememsavail("},
00277 {136, QpFormula::func1, "@fileexists("},
00278 {137, QpFormula::func1, "@curval("},
00279 {138, QpFormula::func1, "@degrees("},
00280 {139, QpFormula::func1, "@radians("},
00281 {140, QpFormula::func1, "@hextonum("},
00282 {141, QpFormula::func1, "@numtohex("},
00283 {142, QpFormula::func1, "@today("},
00284 {143, QpFormula::func3, "@npv("},
00285 {144, QpFormula::func1, "@cellindex2d("},
00286 {145, QpFormula::func1, "@version("},
00287 {154, QpFormula::func1, "@sheets("},
00288 {157, QpFormula::func1, "@index3d("},
00289 {158, QpFormula::func1, "@cellindex3d("},
00290 {159, QpFormula::func1, "@property("},
00291 {160, QpFormula::func1, "@ddelink("},
00292 {161, QpFormula::func1, "@command("},
00293 {0, 0, 0}
00294 };
00295
00296 QpFormula::QpFormula(QpRecFormulaCell& pCell, QpTableNames& pTable)
00297 : cArgSeparator(strcpy(new char[2],","))
00298 , cCell(pCell)
00299 , cFormula( (unsigned char*)pCell.formula(), (unsigned int)pCell.formulaLen() )
00300 , cFormulaRefs( (unsigned char*)&pCell.formula()[pCell.formulaReferences()]
00301 , (unsigned)(pCell.formulaLen()-pCell.formulaReferences())
00302 )
00303 , cReplaceFunc(0)
00304 , cFormulaStart(strcpy(new char[2],"+"))
00305 , cIdx(0)
00306 , cDropLeadingAt(0)
00307 , cTable(pTable)
00308 {
00309 }
00310
00311 QpFormula::~QpFormula()
00312 {
00313 delete [] cArgSeparator;
00314 cArgSeparator = 0;
00315
00316 delete [] cFormulaStart;
00317 cFormulaStart = 0;
00318
00319 cReplaceFunc = 0;
00320 }
00321
00322 void
00323 QpFormula::argSeparator(const char* pArg)
00324 {
00325 delete [] cArgSeparator;
00326 cArgSeparator = strcpy(new char[strlen(pArg)+1], pArg);
00327 }
00328
00329 char*
00330 QpFormula::formula()
00331 {
00332 QP_INT8 lOperand;
00333
00334 cStack.push(cFormulaStart);
00335
00336 while( cFormula >> lOperand, cFormula && lOperand != 3 )
00337 {
00338 int lFound = 0;
00339 int lIdx;
00340
00341 if(cReplaceFunc != 0)
00342 {
00343
00344 for( lIdx=0
00345 ; !lFound && cReplaceFunc[lIdx].cFunc != 0
00346 ; ++lIdx
00347 )
00348 {
00349 if( cReplaceFunc[lIdx].cOperand == lOperand )
00350 {
00351 lFound = -1;
00352 QP_DEBUG("Processing " << (int)lOperand << endl);
00353 (*cReplaceFunc[lIdx].cFunc)(*this, cReplaceFunc[lIdx].cArg);
00354 }
00355 }
00356 }
00357
00358
00359 for( lIdx=0
00360 ; !lFound && gConv[lIdx].cFunc != 0
00361 ; ++lIdx
00362 )
00363 {
00364 if( gConv[lIdx].cOperand == lOperand )
00365 {
00366 lFound = -1;
00367 QP_DEBUG("Processing " << (int)lOperand << endl);
00368 (*gConv[lIdx].cFunc)(*this, gConv[lIdx].cArg);
00369 }
00370 }
00371
00372 QP_DEBUG("Top = " << cStack.top() << endl);
00373 }
00374
00375 cStack.join(2, "");
00376
00377 QP_DEBUG("Formula = " << cStack.top() << endl);
00378 return strcpy(new char[strlen(cStack.top())+1], cStack.top());
00379 }
00380
00381 void
00382 QpFormula::formulaStart(const char* pFirstChar)
00383 {
00384 delete [] cFormulaStart;
00385 cFormulaStart = strcpy(new char[strlen(pFirstChar)+1], pFirstChar);
00386 }
00387
00388 void
00389 QpFormula::binaryOperandReal(const char* pOper)
00390 {
00391 cStack.join( 2, pOper );
00392 }
00393
00394 void
00395 QpFormula::absKludgeReal(const char*)
00396 {
00397
00398
00399
00400 cStack.bracket();
00401
00402 char* lArg = strcpy(new char[strlen(cStack.top())+1], cStack.top());
00403
00404 cStack.bracket("", "<0");
00405
00406 cStack.push(lArg);
00407 cStack.bracket("-", "");
00408
00409 cStack.push(lArg);
00410
00411 cStack.join(3, cArgSeparator);
00412
00413 cStack.bracket("if(");
00414
00415 delete [] lArg;
00416 }
00417
00418 void
00419 QpFormula::func0Real(const char* pFunc)
00420 {
00421 const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
00422
00423 cStack.push( lFunc );
00424 }
00425
00426 void
00427 QpFormula::func1Real(const char* pFunc)
00428 {
00429 const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
00430
00431 cStack.bracket( lFunc );
00432 }
00433
00434 void
00435 QpFormula::func2Real(const char* pFunc)
00436 {
00437 const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
00438
00439 cStack.join( 2, cArgSeparator );
00440 cStack.bracket( lFunc );
00441 }
00442
00443 void
00444 QpFormula::func3Real(const char* pFunc)
00445 {
00446 const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
00447
00448 cStack.join( 3, cArgSeparator );
00449 cStack.bracket( lFunc );
00450 }
00451
00452 void
00453 QpFormula::func4Real(const char* pFunc)
00454 {
00455 const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
00456
00457 cStack.join( 4, cArgSeparator );
00458 cStack.bracket( lFunc );
00459 }
00460
00461 void
00462 QpFormula::funcVReal(const char* pFunc)
00463 {
00464 QP_INT8 lCnt;
00465 const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
00466
00467 cFormula >> lCnt;
00468
00469 cStack.join( lCnt, cArgSeparator );
00470 cStack.bracket( lFunc );
00471 }
00472
00473 void
00474 QpFormula::floatFuncReal(const char*)
00475 {
00476 QP_INT64 lFloat;
00477 std::ostrstream lNum;
00478
00479 cFormula >> lFloat;
00480
00481 lNum << lFloat << ends;
00482
00483 cStack.push( lNum.str() );
00484
00485 lNum.rdbuf()->freeze(0);
00486 }
00487
00488 void
00489 QpFormula::intFuncReal(const char*)
00490 {
00491 QP_INT16 lInt;
00492 std::ostrstream lNum;
00493
00494 cFormula >> lInt;
00495
00496 lNum << lInt << ends;
00497
00498 cStack.push( lNum.str() );
00499
00500 lNum.rdbuf()->freeze(0);
00501 }
00502
00503 void
00504 QpFormula::dropLeadingAt(int pBool)
00505 {
00506 cDropLeadingAt = pBool;
00507 }
00508
00509 void
00510 QpFormula::refReal(const char*)
00511 {
00512 char lRef[100];
00513
00514 cCell.cellRef( lRef, cTable, cFormulaRefs );
00515
00516 cStack.push( lRef );
00517 }
00518
00519 void
00520 QpFormula::replaceFunc(QpFormulaConv* pFuncEntry)
00521 {
00522 cReplaceFunc = pFuncEntry;
00523 }
00524
00525 void
00526 QpFormula::stringFuncReal(const char*)
00527 {
00528 char* lString = 0;
00529
00530 cFormula >> lString;
00531
00532 char* lQuoteString = new char[strlen(lString)+3];
00533
00534 lQuoteString[0] = '"';
00535 strcpy(&lQuoteString[1], lString);
00536 strcat(lQuoteString, "\"");
00537
00538 cStack.push( lQuoteString );
00539
00540 delete [] lString;
00541 delete [] lQuoteString;
00542 }
00543
00544 void
00545 QpFormula::unaryOperandReal(const char* pOper)
00546 {
00547 cStack.bracket( pOper, "" );
00548 }
00549
00550