MythTV  0.26-pre
Variables.cpp
Go to the documentation of this file.
00001 /* Variables.cpp
00002 
00003    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU General Public License
00007    as published by the Free Software Foundation; either version 2
00008    of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018    Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00019 
00020 */
00021 #include "compat.h"
00022 
00023 #include "Variables.h"
00024 #include "Ingredients.h"
00025 #include "Root.h"
00026 #include "BaseClasses.h"
00027 #include "ParseNode.h"
00028 #include "ASN1Codes.h"
00029 #include "Engine.h"
00030 #include "Logging.h"
00031 
00032 enum TestCodes { TC_Equal = 1, TC_NotEqual, TC_Less, TC_LessOrEqual, TC_Greater, TC_GreaterOrEqual };
00033 
00034 static const char *TestToText(int tc)
00035 {
00036     switch (tc)
00037     {
00038         case TC_Equal:
00039             return "Equal";
00040         case TC_NotEqual:
00041             return "NotEqual";
00042         case TC_Less:
00043             return "Less";
00044         case TC_LessOrEqual:
00045             return "LessOrEqual";
00046         case TC_Greater:
00047             return "Greater";
00048         case TC_GreaterOrEqual:
00049             return "GreaterOrEqual";
00050     }
00051 
00052     return NULL; // To keep the compiler happy
00053 }
00054 
00055 // Normal activation behaviour.
00056 void MHVariable::Activation(MHEngine *engine)
00057 {
00058     if (m_fRunning)
00059     {
00060         return;
00061     }
00062 
00063     MHIngredient::Activation(engine);
00064     m_fRunning = true;
00065     engine->EventTriggered(this, EventIsRunning);
00066 }
00067 
00068 void MHBooleanVar::Initialise(MHParseNode *p, MHEngine *engine)
00069 {
00070     MHVariable::Initialise(p, engine);
00071     // Original value should be a bool.
00072     MHParseNode *pInitial = p->GetNamedArg(C_ORIGINAL_VALUE);
00073 
00074     if (pInitial)
00075     {
00076         m_fOriginalValue = pInitial->GetArgN(0)->GetBoolValue();
00077     }
00078 }
00079 
00080 void MHBooleanVar::PrintMe(FILE *fd, int nTabs) const
00081 {
00082     PrintTabs(fd, nTabs);
00083     fprintf(fd, "{:BooleanVar");
00084     MHVariable::PrintMe(fd, nTabs + 1);
00085     PrintTabs(fd, nTabs + 1);
00086     fprintf(fd, ":OrigValue %s\n", m_fOriginalValue ? "true" : "false");
00087     PrintTabs(fd, nTabs);
00088     fprintf(fd, "}\n");
00089 }
00090 
00091 void MHBooleanVar::Preparation(MHEngine *engine)
00092 {
00093     if (m_fAvailable)
00094     {
00095         return;
00096     }
00097 
00098     m_fValue = m_fOriginalValue;
00099     MHVariable::Preparation(engine);
00100 }
00101 
00102 // Implement the TestVariable action.  Triggers a TestEvent event on the result.
00103 void MHBooleanVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
00104 {
00105     parm.CheckType(MHUnion::U_Bool);
00106     bool fRes = false;
00107 
00108     switch (nOp)
00109     {
00110         case TC_Equal:
00111             fRes = m_fValue == parm.m_fBoolVal;
00112             break;
00113         case TC_NotEqual:
00114             fRes = m_fValue != parm.m_fBoolVal;
00115             break;
00116         default:
00117             MHERROR("Invalid comparison for bool");
00118     }
00119 
00120     MHLOG(MHLogDetail, QString("Comparison %1 between %2 and %3 => %4").arg(TestToText(nOp))
00121           .arg(m_fValue ? "true" : "false").arg(parm.m_fBoolVal ? "true" : "false").arg(fRes ? "true" : "false"));
00122     engine->EventTriggered(this, EventTestEvent, fRes);
00123 }
00124 
00125 // Get the variable value.  Used in IndirectRef.
00126 void MHBooleanVar::GetVariableValue(MHUnion &value, MHEngine *)
00127 {
00128     value.m_Type = MHUnion::U_Bool;
00129     value.m_fBoolVal = m_fValue;
00130 }
00131 
00132 // Implement the SetVariable action.
00133 void MHBooleanVar::SetVariableValue(const MHUnion &value)
00134 {
00135     value.CheckType(MHUnion::U_Bool);
00136     m_fValue = value.m_fBoolVal;
00137     MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_fValue ? "true" : "false"));
00138 }
00139 
00140 
00141 void MHIntegerVar::Initialise(MHParseNode *p, MHEngine *engine)
00142 {
00143     MHVariable::Initialise(p, engine);
00144     // Original value should be an int.
00145     MHParseNode *pInitial = p->GetNamedArg(C_ORIGINAL_VALUE);
00146 
00147     if (pInitial)
00148     {
00149         m_nOriginalValue = pInitial->GetArgN(0)->GetIntValue();
00150     }
00151 }
00152 
00153 void MHIntegerVar::PrintMe(FILE *fd, int nTabs) const
00154 {
00155     PrintTabs(fd, nTabs);
00156     fprintf(fd, "{:IntegerVar");
00157     MHVariable::PrintMe(fd, nTabs + 1);
00158     PrintTabs(fd, nTabs + 1);
00159     fprintf(fd, ":OrigValue %d\n", m_nOriginalValue);
00160     PrintTabs(fd, nTabs);
00161     fprintf(fd, "}\n");
00162 }
00163 
00164 void MHIntegerVar::Preparation(MHEngine *engine)
00165 {
00166     if (m_fAvailable)
00167     {
00168         return;
00169     }
00170 
00171     m_nValue = m_nOriginalValue;
00172     MHVariable::Preparation(engine);
00173 }
00174 
00175 // Implement the TestVariable action.  Triggers a TestEvent event on the result.
00176 void MHIntegerVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
00177 {
00178     parm.CheckType(MHUnion::U_Int);
00179     bool fRes = false;
00180 
00181     switch (nOp)
00182     {
00183         case TC_Equal:
00184             fRes = m_nValue == parm.m_nIntVal;
00185             break;
00186         case TC_NotEqual:
00187             fRes = m_nValue != parm.m_nIntVal;
00188             break;
00189         case TC_Less:
00190             fRes = m_nValue < parm.m_nIntVal;
00191             break;
00192         case TC_LessOrEqual:
00193             fRes = m_nValue <= parm.m_nIntVal;
00194             break;
00195         case TC_Greater:
00196             fRes = m_nValue > parm.m_nIntVal;
00197             break;
00198         case TC_GreaterOrEqual:
00199             fRes = m_nValue >= parm.m_nIntVal;
00200             break;
00201         default:
00202             MHERROR("Invalid comparison for int"); // Shouldn't ever happen
00203     }
00204 
00205     MHLOG(MHLogDetail, QString("Comparison %1 between %2 and %3 => %4").arg(TestToText(nOp))
00206           .arg(m_nValue).arg(parm.m_nIntVal).arg(fRes ? "true" : "false"));
00207     engine->EventTriggered(this, EventTestEvent, fRes);
00208 }
00209 
00210 // Get the variable value.  Used in IndirectRef.
00211 void MHIntegerVar::GetVariableValue(MHUnion &value, MHEngine *)
00212 {
00213     value.m_Type = MHUnion::U_Int;
00214     value.m_nIntVal = m_nValue;
00215 }
00216 
00217 // Implement the SetVariable action.  Also used as part of Add, Subtract etc
00218 void MHIntegerVar::SetVariableValue(const MHUnion &value)
00219 {
00220     if (value.m_Type == MHUnion::U_String)
00221     {
00222         // Implicit conversion of string to integer.
00223         int v = 0;
00224         int p = 0;
00225         bool fNegative = false;
00226 
00227         if (value.m_StrVal.Size() > 0 && value.m_StrVal.GetAt(0) == '-')
00228         {
00229             p++;
00230             fNegative = true;
00231         }
00232 
00233         for (; p < value.m_StrVal.Size(); p++)
00234         {
00235             unsigned char ch =  value.m_StrVal.GetAt(p);
00236 
00237             if (ch < '0' || ch > '9')
00238             {
00239                 break;
00240             }
00241 
00242             v = v * 10 + ch - '0';
00243         }
00244 
00245         if (fNegative)
00246         {
00247             m_nValue = -v;
00248         }
00249         else
00250         {
00251             m_nValue = v;
00252         }
00253     }
00254     else
00255     {
00256         value.CheckType(MHUnion::U_Int);
00257         m_nValue = value.m_nIntVal;
00258     }
00259 
00260     MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_nValue));
00261 }
00262 
00263 
00264 
00265 void MHOctetStrVar::Initialise(MHParseNode *p, MHEngine *engine)
00266 {
00267     MHVariable::Initialise(p, engine);
00268     // Original value should be a string.
00269     MHParseNode *pInitial = p->GetNamedArg(C_ORIGINAL_VALUE);
00270 
00271     if (pInitial)
00272     {
00273         pInitial->GetArgN(0)->GetStringValue(m_OriginalValue);
00274     }
00275 }
00276 
00277 void MHOctetStrVar::PrintMe(FILE *fd, int nTabs) const
00278 {
00279     PrintTabs(fd, nTabs);
00280     fprintf(fd, "{:OStringVar");
00281     MHVariable::PrintMe(fd, nTabs + 1);
00282     PrintTabs(fd, nTabs + 1);
00283     fprintf(fd, ":OrigValue ");
00284     m_OriginalValue.PrintMe(fd, nTabs + 1);
00285     fprintf(fd, "\n");
00286     PrintTabs(fd, nTabs);
00287     fprintf(fd, "}\n");
00288 }
00289 
00290 void MHOctetStrVar::Preparation(MHEngine *engine)
00291 {
00292     if (m_fAvailable)
00293     {
00294         return;
00295     }
00296 
00297     m_Value.Copy(m_OriginalValue);
00298     MHVariable::Preparation(engine);
00299 }
00300 
00301 // Implement the TestVariable action.  Triggers a TestEvent event on the result.
00302 void MHOctetStrVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
00303 {
00304     parm.CheckType(MHUnion::U_String);
00305     int nRes = m_Value.Compare(parm.m_StrVal);
00306     bool fRes = false;
00307 
00308     switch (nOp)
00309     {
00310         case TC_Equal:
00311             fRes = nRes == 0;
00312             break;
00313         case TC_NotEqual:
00314             fRes = nRes != 0;
00315             break;
00316             /*  case TC_Less: fRes = nRes < 0; break;
00317                 case TC_LessOrEqual: fRes = nRes <= 0; break;
00318                 case TC_Greater: fRes = nRes > 0; break;
00319                 case TC_GreaterOrEqual: fRes = nRes >= 0; break;*/
00320         default:
00321             MHERROR("Invalid comparison for string"); // Shouldn't ever happen
00322     }
00323 
00324     MHOctetString sample1(m_Value, 0, 10);
00325     MHOctetString sample2(parm.m_StrVal, 0, 10);
00326     MHLOG(MHLogDetail, QString("Comparison %1 %2 and %3 => %4").arg(TestToText(nOp))
00327           .arg(sample1.Printable()).arg(sample2.Printable()).arg(fRes ? "true" : "false"));
00328     engine->EventTriggered(this, EventTestEvent, fRes);
00329 }
00330 
00331 // Get the variable value.  Used in IndirectRef.
00332 void MHOctetStrVar::GetVariableValue(MHUnion &value, MHEngine *)
00333 {
00334     value.m_Type = MHUnion::U_String;
00335     value.m_StrVal.Copy(m_Value);
00336 }
00337 
00338 // Implement the SetVariable action.
00339 void MHOctetStrVar::SetVariableValue(const MHUnion &value)
00340 {
00341     if (value.m_Type == MHUnion::U_Int)
00342     {
00343         // Implicit conversion of int to string.
00344         char buff[30]; // 30 chars is more than enough.
00345         snprintf(buff, sizeof(buff), "%0d", value.m_nIntVal);
00346         m_Value.Copy(buff);
00347     }
00348     else
00349     {
00350         value.CheckType(MHUnion::U_String);
00351         m_Value.Copy(value.m_StrVal);
00352     }
00353 
00354     // Debug
00355     MHOctetString sample(m_Value, 0, 60);
00356     MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable())
00357           .arg(sample.Printable()));
00358 }
00359 
00360 
00361 void MHObjectRefVar::Initialise(MHParseNode *p, MHEngine *engine)
00362 {
00363     MHVariable::Initialise(p, engine);
00364     // Original value should be an object reference.
00365     MHParseNode *pInitial = p->GetNamedArg(C_ORIGINAL_VALUE);
00366 
00367     // and this should be a ObjRef node.
00368     if (pInitial)
00369     {
00370         MHParseNode *pArg = pInitial->GetNamedArg(C_OBJECT_REFERENCE);
00371 
00372         if (pArg)
00373         {
00374             m_OriginalValue.Initialise(pArg->GetArgN(0), engine);
00375         }
00376     }
00377 }
00378 
00379 void MHObjectRefVar::PrintMe(FILE *fd, int nTabs) const
00380 {
00381     PrintTabs(fd, nTabs);
00382     fprintf(fd, "{:ObjectRefVar");
00383     MHVariable::PrintMe(fd, nTabs + 1);
00384     PrintTabs(fd, nTabs + 1);
00385     fprintf(fd, ":OrigValue ");
00386     m_OriginalValue.PrintMe(fd, nTabs + 1);
00387     fprintf(fd, "\n");
00388     PrintTabs(fd, nTabs);
00389     fprintf(fd, "}\n");
00390 }
00391 
00392 void MHObjectRefVar::Preparation(MHEngine *engine)
00393 {
00394     if (m_fAvailable)
00395     {
00396         return;
00397     }
00398 
00399     m_Value.Copy(m_OriginalValue);
00400     MHVariable::Preparation(engine);
00401 }
00402 
00403 // Implement the TestVariable action.  Triggers a TestEvent event on the result.
00404 void MHObjectRefVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
00405 {
00406     parm.CheckType(MHUnion::U_ObjRef);
00407     bool fRes = false;
00408 
00409     switch (nOp)
00410     {
00411         case TC_Equal:
00412             fRes = m_Value.Equal(parm.m_ObjRefVal, engine);
00413             break;
00414         case TC_NotEqual:
00415             fRes = ! m_Value.Equal(parm.m_ObjRefVal, engine);
00416             break;
00417         default:
00418             MHERROR("Invalid comparison for object ref");
00419     }
00420 
00421     engine->EventTriggered(this, EventTestEvent, fRes);
00422 }
00423 
00424 // Get the variable value.  Used in IndirectRef.
00425 void MHObjectRefVar::GetVariableValue(MHUnion &value, MHEngine *)
00426 {
00427     value.m_Type = MHUnion::U_ObjRef;
00428     value.m_ObjRefVal.Copy(m_Value);
00429 }
00430 
00431 // Implement the SetVariable action.
00432 void MHObjectRefVar::SetVariableValue(const MHUnion &value)
00433 {
00434     value.CheckType(MHUnion::U_ObjRef);
00435     m_Value.Copy(value.m_ObjRefVal);
00436     MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_Value.Printable()));
00437 }
00438 
00439 
00440 void MHContentRefVar::Initialise(MHParseNode *p, MHEngine *engine)
00441 {
00442     MHVariable::Initialise(p, engine);
00443     // Original value should be a content reference.
00444     MHParseNode *pInitial = p->GetNamedArg(C_ORIGINAL_VALUE);
00445 
00446     // and this should be a ContentRef node.
00447     if (pInitial)
00448     {
00449         MHParseNode *pArg = pInitial->GetNamedArg(C_CONTENT_REFERENCE);
00450 
00451         if (pArg)
00452         {
00453             m_OriginalValue.Initialise(pArg->GetArgN(0), engine);
00454         }
00455     }
00456 }
00457 
00458 void MHContentRefVar::PrintMe(FILE *fd, int nTabs) const
00459 {
00460     PrintTabs(fd, nTabs);
00461     fprintf(fd, "{:ContentRefVar");
00462     MHVariable::PrintMe(fd, nTabs + 1);
00463     PrintTabs(fd, nTabs + 1);
00464     fprintf(fd, ":OrigValue ");
00465     m_OriginalValue.PrintMe(fd, nTabs + 1);
00466     fprintf(fd, "\n");
00467     PrintTabs(fd, nTabs);
00468     fprintf(fd, "}\n");
00469 }
00470 
00471 void MHContentRefVar::Preparation(MHEngine *engine)
00472 {
00473     if (m_fAvailable)
00474     {
00475         return;
00476     }
00477 
00478     m_Value.Copy(m_OriginalValue);
00479     MHVariable::Preparation(engine);
00480 }
00481 
00482 // Implement the TestVariable action.  Triggers a TestEvent event on the result.
00483 void MHContentRefVar::TestVariable(int nOp, const MHUnion &parm, MHEngine *engine)
00484 {
00485     parm.CheckType(MHUnion::U_ContentRef);
00486     bool fRes = false;
00487 
00488     switch (nOp)
00489     {
00490         case TC_Equal:
00491             fRes = m_Value.Equal(parm.m_ContentRefVal, engine);
00492             break;
00493         case TC_NotEqual:
00494             fRes = !m_Value.Equal(parm.m_ContentRefVal, engine);
00495             break;
00496         default:
00497             MHERROR("Invalid comparison for content ref");
00498     }
00499 
00500     engine->EventTriggered(this, EventTestEvent, fRes);
00501 }
00502 
00503 // Get the variable value.  Used in IndirectRef.
00504 void MHContentRefVar::GetVariableValue(MHUnion &value, MHEngine *)
00505 {
00506     value.m_Type = MHUnion::U_ContentRef;
00507     value.m_ContentRefVal.Copy(m_Value);
00508 }
00509 
00510 // Implement the SetVariable action.
00511 void MHContentRefVar::SetVariableValue(const MHUnion &value)
00512 {
00513     value.CheckType(MHUnion::U_ContentRef);
00514     m_Value.Copy(value.m_ContentRefVal);
00515     MHLOG(MHLogDetail, QString("Update %1 := %2").arg(m_ObjectReference.Printable()).arg(m_Value.Printable()));
00516 }
00517 
00518 // Actions
00519 void MHSetVariable::Initialise(MHParseNode *p, MHEngine *engine)
00520 {
00521     MHElemAction::Initialise(p, engine); // Target
00522     m_NewValue.Initialise(p->GetArgN(1), engine); // Value to store
00523 }
00524 
00525 void MHSetVariable::Perform(MHEngine *engine)
00526 {
00527     MHObjectRef target;
00528     m_Target.GetValue(target, engine); // Get the target
00529     MHUnion newValue;
00530     newValue.GetValueFrom(m_NewValue, engine); // Get the actual value to set.
00531     engine->FindObject(target)->SetVariableValue(newValue); // Set the value.
00532 }
00533 
00534 
00535 void MHTestVariable::Initialise(MHParseNode *p, MHEngine *engine)
00536 {
00537     MHElemAction::Initialise(p, engine); // Target
00538     m_nOperator = p->GetArgN(1)->GetIntValue(); // Test to perform
00539     m_Comparison.Initialise(p->GetArgN(2), engine); // Value to compare against
00540 }
00541 
00542 void MHTestVariable::PrintArgs(FILE *fd, int /*nTabs*/) const
00543 {
00544     fprintf(fd, " %d ", m_nOperator);
00545     m_Comparison.PrintMe(fd, 0);
00546 }
00547 
00548 void MHTestVariable::Perform(MHEngine *engine)
00549 {
00550     MHObjectRef target;
00551     m_Target.GetValue(target, engine); // Get the target
00552     MHUnion testValue;
00553     testValue.GetValueFrom(m_Comparison, engine); // Get the actual value to compare.
00554     engine->FindObject(target)->TestVariable(m_nOperator, testValue, engine); // Do the test.
00555 }
00556 
00557 void MHIntegerAction::Initialise(MHParseNode *p, MHEngine *engine)
00558 {
00559     MHElemAction::Initialise(p, engine); // Target
00560     MHParseNode *pOp = p->GetArgN(1);
00561     m_Operand.Initialise(pOp, engine); // Operand to add, subtract etc.
00562 }
00563 
00564 void MHIntegerAction::Perform(MHEngine *engine)
00565 {
00566     MHUnion targetVal;
00567     // Find the target and get its current value.  The target can be an indirect reference.
00568     MHObjectRef parm;
00569     m_Target.GetValue(parm, engine);
00570     MHRoot *pTarget = engine->FindObject(parm);
00571     pTarget->GetVariableValue(targetVal, engine);
00572     targetVal.CheckType(MHUnion::U_Int);
00573     // Get the value of the operand.
00574     int nOperand = m_Operand.GetValue(engine);
00575     // Set the value of targetVal to the new value and store it.
00576     targetVal.m_nIntVal = DoOp(targetVal.m_nIntVal, nOperand);
00577     pTarget->SetVariableValue(targetVal);
00578 }
00579 
00580 void MHAppend::Initialise(MHParseNode *p, MHEngine *engine)
00581 {
00582     MHElemAction::Initialise(p, engine); // Target
00583     m_Operand.Initialise(p->GetArgN(1), engine); // Operand to append
00584 }
00585 
00586 void MHAppend::Perform(MHEngine *engine)
00587 {
00588     MHUnion targetVal;
00589     // Find the target and get its current value.  The target can be an indirect reference.
00590     MHObjectRef parm;
00591     m_Target.GetValue(parm, engine);
00592     MHRoot *pTarget = engine->FindObject(parm);
00593     pTarget->GetVariableValue(targetVal, engine);
00594     targetVal.CheckType(MHUnion::U_String);
00595     // Get the string to append.
00596     MHOctetString toAppend;
00597     m_Operand.GetValue(toAppend, engine);
00598     targetVal.m_StrVal.Append(toAppend); // Add it on the end
00599     pTarget->SetVariableValue(targetVal); // Set the target to the result.
00600 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends