📄 vxi.cpp
字号:
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; unsigned int count = 0; VXIException::InterpreterEvent event = e; do { try { // (2) Increments counts associated with this event. exe->eventcounts.Increment(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 (++count < MAX_LOOP_ITERATIONS); // (6) Probable loop - catch X throws X? Quit handling after a while. 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; vxistring::size_type bestMatchLength = 0; VXMLElement bestMatch; enum { DOCUMENT, APPLICATION, DEFAULTS } stage = DOCUMENT; bool done = false; // Start from current item in document. VXMLElement currentNode = item; do { // (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 && nodeName != NODE_ERROR && nodeName != NODE_HELP && nodeName != NODE_NOINPUT && nodeName != NODE_NOMATCH) continue; // (2.2) If it is not a catch, is this an active match? int eventCount; vxistring catchEvent; if (nodeName != NODE_CATCH) { // Map back to strings. if (nodeName == NODE_ERROR) catchEvent = L"error"; else if (nodeName == NODE_HELP) catchEvent = L"help"; else if (nodeName == NODE_NOINPUT) catchEvent = L"noinput"; else if (nodeName == NODE_NOMATCH) catchEvent = L"nomatch"; eventCount = exe->eventcounts.GetCount(event, catchEvent); if (eventCount == 0) continue; } // (2.3) If it is a catch, we need to examine the list. else { elem.GetAttribute(ATTRIBUTE_EVENT, catchEvent); // Find the best match in the event list. STRINGDEQUE catchList; ProcessNameList(catchEvent, catchList); catchEvent.erase(); if (catchList.empty()) eventCount = exe->eventcounts.GetCount(event, catchEvent); else { STRINGDEQUE::iterator i; for (i = catchList.begin(); i != catchList.end(); ++i) { int temp = exe->eventcounts.GetCount(event, *i); if (temp != 0 && (*i).length() > catchEvent.length()) { catchEvent = (*i); eventCount = temp; } } if (catchEvent.empty()) continue; } } // (2.4) Matching catch element found. Evaluate its 'cond' attribute. vxistring attr; elem.GetAttribute(ATTRIBUTE_COND, attr); if (!attr.empty() && !exe->script.TestCondition(attr)) continue; // (2.5) Condition okay. Check the count against the eventCount. int catchCount = 1; if (elem.GetAttribute(ATTRIBUTE_COUNT, attr)) {#if defined(__GNUC__) && (__GNUC__ <= 2 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)) // The G++ 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 (catchCount < 1 || catchCount > eventCount) continue; // (2.6) We now have a candidate. vxistring::size_type catchEventLength = catchEvent.length(); if (catchEventLength < bestMatchLength) continue; // Name isn't as good. if (catchEventLength == bestMatchLength && catchCount <= bestCount) continue; // Names match, but count isn't better. // (2.7) Update best match. bestCount = catchCount; bestMatchLength = catchEventLength; 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); 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); 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){ 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); exe->script.SetValue(key, value); while (VXIMapGetNextProperty(i, &key, &value) == VXIvalue_RESULT_SUCCESS) exe->script.SetValue(key, value); VXIMapIteratorDestroy(&i); } // (3) Walk through the children and execute each node. for (VXMLNodeIterator it(doc); it; ++it) { VXMLNode child = *it; switch (child.GetType()) { case VXMLNode::Type_VXMLContent: executable_prompt(child); break; case VXMLNode::Type_VXMLElement: { const VXMLElement & elem = reinterpret_cast<VXMLElement &>(child); executable_element(elem); break; } default: // do nothing break; } }}// Executable element dispatch//void VXI::executable_element(const VXMLElement & elem){ 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 || nodeName == NODE_AUDIO || nodeName == NODE_VALUE || nodeName == NODE_ENUMERATE) executable_prompt(elem); else if (nodeName == NODE_REPROMPT) reprompt_element(elem); 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 & doc){ vxistring name; vxistring expr; doc.GetAttribute(ATTRIBUTE_NAME, name); doc.GetAttribute(ATTRIBUTE_EXPR, expr); if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::var_element(name=\"" << name << L"\" expr = \"" << expr << L"\")"; log->EndDiagnostic(); } if (name.empty()) return; exe->script.MakeVar(name, expr);} // Process <assign> elements in current interpreter context//void VXI::assign_element(const VXMLElement & doc){ vxistring name; doc.GetAttribute(ATTRIBUTE_NAME, name); if (name.empty()) return; vxistring expr; doc.GetAttribute(ATTRIBUTE_EXPR, expr); if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::assign_element(name=\"" << name << L"\" expr = \"" << expr << L"\""; log->EndDiagnostic(); } exe->script.SetVar(name, expr);}// Handler for meta elements. Do nothing for now.//void VXI::meta_element(const VXMLElement & doc){ // vxistring & name = doc.GetAttribute("name"); // vxistring & name = doc.GetAttribute("content"); // vxistring & name = doc.GetAttribute("http-equiv");}// Handler for clear elements. This may resets all form items or a user// specified subset.//void VXI::clear_element(const VXMLElement & doc){ log->LogDiagnostic(2, L"VXI::clear_element()"); // (1) Get the namelist. vxistring namelist; doc.GetAttribute(ATTRIBUTE_NAMELIST, namelist); // (2) Handle the easy case: empty namelist --> clear all if (namelist.empty()) { // (2.1) Clear prompt and event counts. exe->promptcounts.Clear(); exe->eventcounts.Clear(); // (2.2) The list of form items resides in the slot map. ExecutionContext::STRINGDEQUE::iterator i; ExecutionContext::STRINGDEQUE & formitems = exe->formitems; for (i = formitems.begin(); i != formitems.end(); ++i) exe->script.ClearVar(*i); return; } // (3) Handle case where user specifies form items. STRINGDEQUE names; ProcessNameList(namelist, names); for (STRINGDEQUE::const_iterator i = names.begin(); i != names.end(); ++i) { // (3.1) Check that the name is a real form item. A linear search should
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -