📄 vxi.cpp
字号:
if (nodeName == NODE_FIELD || nodeName == NODE_RECORD ||
nodeName == NODE_TRANSFER || nodeName == NODE_OBJECT ||
nodeName == NODE_SUBDIALOG || nodeName == NODE_MENU)
return true;
return false;
}
// Finds the named form item within the dialog. If the name is empty, the
// first non-filled item is returned.
//
void VXI::DoInnerJump(const VXMLElement & elem, const vxistring & item)
{
if (elem == 0) return;
if (log->IsLogging(2)) {
log->StartDiagnostic(2) << L"VXI::DoInnerJump(" << item << L")";
log->EndDiagnostic();
}
// find form.
VXMLElement current = elem;
while (1) {
VXMLElementType nodeName = current.GetName();
if (nodeName == NODE_MENU)
throw JumpItem(current); // Menu is a special case.
if (nodeName == NODE_FORM)
break;
const VXMLElement & parent = current.GetParent();
if (parent == 0) {
log->LogError(999, SimpleLogger::MESSAGE,
L"could not locate form on local jump");
throw VXIException::Fatal();
}
current = parent;
};
// (2) If the next item is specified (such as from a previous <goto>, look
// for an exact match.
if (!item.empty()) {
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;
vxistring name;
if (!elem.GetAttribute(ATTRIBUTE__ITEMNAME, name)) continue;
if (item == name) throw JumpItem(elem);
}
}
// (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) {
VXM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -