filters

formula.cc

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;  // really 0 - pCnt +1
00055 
00056    if( pCnt > 0 && (cIdx-lFirstIdx) >=0 )
00057    {
00058       int lSepLen = strlen(pSeparator);
00059       int lLen    = lSepLen * (pCnt-1) +1;  // +1 for null terminator
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 // {7, default ??? don't know what this is ???
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 // {25, Halt ??? don't know what this is ???
00167 // {26, dll ??? don't know what this is ???
00168 // {27, extended no operands ??? don't know what this is ???
00169 // {28, extended operands ??? don't know what this is ???
00170 // {29, Reserved
00171 // {30, Reserved
00172 // {31, NA
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("},  // would have expected func4 ???
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("},  // would have expected func4 ???
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 //   {114, QpFormula::func1,         "@call("},
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          // search through override list for this function/operand
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       // if no override then find the default
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*/*pOper*/)
00396 {
00397    // kspread doesn't (yet) have the abs function so do it ourselves
00398    // using 'if( (arg) < 0, -(arg), arg )'
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];  // ??? hard coded length
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 
KDE Home | KDE Accessibility Home | Description of Access Keys