📄 vxi.cpp
字号:
// (3) Otherwise, find the first non-filled item with a valid condition. else { for (VXMLNodeIterator it(current); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); if (!IsFormItemNode(elem)) continue; // Must use itemname here, as could be implicit name vxistring itemname; if (!elem.GetAttribute(ATTRIBUTE__ITEMNAME, itemname)) { log->LogError(999, SimpleLogger::MESSAGE, L"unnamed item found on local jump"); throw VXIException::Fatal(); } if (exe->script.IsVarDefined(itemname)) continue; // OK if var is undefined, check condition vxistring cond; elem.GetAttribute(ATTRIBUTE_COND, cond); if (cond.empty() || exe->script.TestCondition(cond)) throw JumpItem(elem); } } // log->LogDiagnostic(2, L"VXI::DoInnerJump - no match found."); } //############################################################################# // Utility functions //############################################################################# // do_event() - top level call into event handler; deals with // event counts and defaults. // void VXI::DoEvent(const VXMLElement & item, const VXIException::InterpreterEvent & e) { // (0) Initial logging if (item == 0) { log->LogDiagnostic(0, L"VXI::DoEvent - invalid argument, ignoring event"); return; } else if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::DoEvent(" << e.GetValue() << L")"; log->EndDiagnostic(); } // (1) Disable queuing of prompts outside of event handler. exe->playingPrompts = false; VXIint32 numRethrows = 0; VXIException::InterpreterEvent event = e; // retrieve field name vxistring fieldName; item.GetAttribute(ATTRIBUTE__ITEMNAME, fieldName); do { try { // (2) Increments counts associated with this event. exe->eventcounts.Increment(fieldName, event.GetValue()); // (3) Process the current event. exe->eventSource = item; bool handled = do_event(item, event); exe->eventSource = VXMLElement(); if (handled) { if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::DoEvent - event processed."; log->EndDiagnostic(); } return; } // (4) No one willing to handle this event. Exit. vxistring exitmessage(L"Unhandled exception: "); exitmessage += event.GetValue(); VXIString * val = VXIStringCreate(exitmessage.c_str()); if (val == NULL) throw VXIException::OutOfMemory(); throw VXIException::Exit(reinterpret_cast<VXIValue*>(val)); } // (5) The catch had a <throw> element inside. Must process the new event. catch (const VXIException::InterpreterEvent & e) { event = e; } } while (++numRethrows < DEFAULT_MAX_EVENT_RETHROWS); // (6) Probable loop - catch X throws X? Quit handling after a while. log->LogError(216); vxistring exitmessage(L"Unhandled exception (suspected infinite loop)"); VXIString * val = VXIStringCreate(exitmessage.c_str()); if (val == NULL) throw VXIException::OutOfMemory(); throw VXIException::Exit(reinterpret_cast<VXIValue*>(val)); } bool VXI::do_event(const VXMLElement & item, const VXIException::InterpreterEvent & e) { const vxistring & event = e.GetValue(); // (1) Define the variables for the best match. int bestCount = 0; VXMLElement bestMatch; enum { DOCUMENT, APPLICATION, DEFAULTS } stage = DOCUMENT; bool done = false; // Start from current item in document. VXMLElement currentNode = item; vxistring oldFieldName, fieldName; item.GetAttribute(ATTRIBUTE__ITEMNAME, oldFieldName); do { // Retrieve the field name for the current node for event counter currentNode.GetAttribute(ATTRIBUTE__ITEMNAME, fieldName); // If we move to the next level, we must initialize the event counter // because the event may have not been initialized yet! if( oldFieldName != fieldName ) exe->eventcounts.Increment(fieldName, event); // (2) Walk through all nodes at this level looking for catch elements. for (VXMLNodeIterator it(currentNode); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); // (2.1) Can this node catch events? VXMLElementType nodeName = elem.GetName(); if (nodeName != NODE_CATCH) continue; // (2.2) Is this an active match? int eventCount; vxistring catchEvent; // Treat <catch> and <catch event=""> and <catch event="."> // identically. if (!elem.GetAttribute(ATTRIBUTE_EVENT, catchEvent)) catchEvent.erase(); if (catchEvent == L".") catchEvent.erase(); // Find the best match in the event list. bool goNext = false; /// JC STRINGDEQUE catchList; ProcessNameList(catchEvent, catchList); catchEvent.erase(); // Find field name if (catchList.empty()) { eventCount = exe->eventcounts.GetCount(fieldName, event, catchEvent); } else { STRINGDEQUE::iterator i; for (i = catchList.begin(); i != catchList.end(); ++i) { int temp = exe->eventcounts.GetCount(fieldName, event, *i); if (temp != 0 && (*i).length() > catchEvent.length()) { catchEvent = (*i); eventCount = temp; } } if (catchEvent.empty()) continue; } // sanity check event count if (eventCount > DEFAULT_MAX_EVENT_COUNT) { log->LogError(216); vxistring exitmessage(L"Unhandled exception (suspected infinite loop)"); VXIString * val = VXIStringCreate(exitmessage.c_str()); if (val == NULL) throw VXIException::OutOfMemory(); throw VXIException::Exit(reinterpret_cast<VXIValue*>(val)); } // (2.3) Matching catch element found. Evaluate its 'cond' attribute. vxistring attr; elem.GetAttribute(ATTRIBUTE_COND, attr); if (!attr.empty() && !exe->script.TestCondition(attr)) continue; // (2.4) Condition okay. Check the count against the eventCount. int catchCount = 1; if (elem.GetAttribute(ATTRIBUTE_COUNT, attr)) { #if (defined(__GNUC__) || defined(_decunix_)) // The G++ 2.95 and 3.0.2 implementation of basic_stringstream is faulty. VXIchar * temp; catchCount = int(wcstol(attr.c_str(), &temp, 10)); #else std::basic_stringstream<VXIchar> attrStream(attr); attrStream >> catchCount; #endif } if( catchList.empty() && bestCount > 0) if( catchCount == eventCount ) continue; if (catchCount < 1 || catchCount > eventCount) continue; // (2.5) We now have a candidate. if (catchCount <= bestCount) continue; // Names match, but count isn't better. // (2.6) Update best match. bestCount = catchCount; bestMatch = elem; } // (3) Decide where to search next. const VXMLElement & parent = currentNode.GetParent(); if (parent != 0) currentNode = parent; else { if (stage == DOCUMENT) { stage = APPLICATION; currentNode = exe->application.GetRoot(); if (currentNode != 0) continue; // Otherwise, fall through to application level. } if (stage == APPLICATION) { stage = DEFAULTS; // We resort to this level _only_ if no match has been found. if (bestCount < 1) { vxistring language = toString(exe->properties.GetProperty(PropertyList::Language)); // We clear the current node. It will be set either to the global // language (*) or to an exact match. currentNode = VXMLElement(); VXMLElement defaultsRoot = domDefaultDoc.GetRoot(); for (VXMLNodeIterator it(defaultsRoot); it; ++it) { VXMLNode child = *it; // Look for a language node. if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); if (elem.GetName() != DEFAULTS_LANGUAGE) continue; vxistring id; elem.GetAttribute(ATTRIBUTE_ID, id); if (id == language || (id == GENERIC_DEFAULTS && currentNode == 0)) currentNode = elem; } if (currentNode != 0) continue; } } done = true; } } while (!done); if (bestCount == 0) return false; // Compliance Note: // // Because of the 'as-if-by-copy' semantic, we now execute the catch content, // including relative URIs, in the local scope. So nothing special needs to // be done. VXIMapHolder vars; VXIValue * temp = NULL; temp = reinterpret_cast<VXIValue *>(VXIStringCreate(e.GetValue().c_str())); if (temp == NULL) throw VXIException::OutOfMemory(); VXIMapSetProperty(vars.GetValue(), L"_event", temp); if (e.GetMessage().empty()) temp = reinterpret_cast<VXIValue *>(VXIPtrCreate(NULL)); else temp =reinterpret_cast<VXIValue*>(VXIStringCreate(e.GetMessage().c_str())); if (temp == NULL) throw VXIException::OutOfMemory(); VXIMapSetProperty(vars.GetValue(), L"_message", temp); execute_content(bestMatch, vars, e.GetActiveDialog()); return true; } // Top level call into executable content section. // Called from <block>,<catch>, and <filled> // void VXI::execute_content(const VXMLElement& doc, const VXIMapHolder & vars, const VXMLElement& activeDialog) { log->LogDiagnostic(2, L"VXI::execute_content()"); // (1) Add a new scope. The allows anonymous variables to be defined. if (exe->script.CurrentScope(SCOPE_Anonymous)) exe->script.PopScope(); exe->script.PushScope(SCOPE_Anonymous); // (2) Set externally specified variables (if necessary). if (vars.GetValue() != NULL) { const VXIchar * key; const VXIValue * value; VXIMapIterator * i = VXIMapGetFirstProperty(vars.GetValue(), &key, &value); if (VXIValueGetType(value) == VALUE_PTR) exe->script.MakeVar(key, L""); // Set to ECMAScript undefined else exe->script.MakeVar(key, value); while (VXIMapGetNextProperty(i, &key, &value) == VXIvalue_RESULT_SUCCESS) { if (VXIValueGetType(value) == VALUE_PTR) exe->script.MakeVar(key, L""); // Set to ECMAScript undefined else exe->script.MakeVar(key, value); } VXIMapIteratorDestroy(&i); } // (3) Walk through the children and execute each node. for (VXMLNodeIterator it(doc); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<VXMLElement &>(child); executable_element(elem, activeDialog); } } // Executable element dispatch // void VXI::executable_element(const VXMLElement & elem, const VXMLElement & activeDialog) { if (elem == 0) { log->LogError(999, SimpleLogger::MESSAGE, L"empty executable element"); return; } VXMLElementType nodeName = elem.GetName(); if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::executable_element - " << nodeName; log->EndDiagnostic(); } if (nodeName == NODE_VAR) var_element(elem); else if (nodeName == NODE_ASSIGN) assign_element(elem); else if (nodeName == NODE_CLEAR) clear_element(elem); else if (nodeName == NODE_DISCONNECT) disconnect_element(elem); else if (nodeName == NODE_EXIT) exit_element(elem); else if (nodeName == NODE_GOTO) goto_element(elem); else if (nodeName == NODE_IF) if_element(elem); else if (nodeName == NODE_LOG) log_element(elem); else if (nodeName == NODE_PROMPT) executable_prompt(elem); else if (nodeName == NODE_REPROMPT) reprompt_element(elem, activeDialog); else if (nodeName == NODE_RETURN) return_element(elem); else if (nodeName == NODE_SCRIPT) script_element(elem); else if (nodeName == NODE_SUBMIT) submit_element(elem); else if (nodeName == NODE_THROW) throw_element(elem); else log->LogError(999, SimpleLogger::MESSAGE,L"unexpected executable element"); } /* * Process <var> elements in current interp context. * * This differs from assign in that it makes new var in current scope * assign follows scope chain lookup for var name (and throws * error if fails) * * This is also used for initialiation of guard vars in field items * * <var> processing is compliated by the need to check for <param> values * from subdialog calls. */ void VXI::var_element(const VXMLElement &
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -