|
MythTV
0.26-pre
|
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 }
1.7.6.1