📄 vxi.cpp
字号:
if (val != NULL && VXIValueGetType(val) == VALUE_STRING)
diagUri = VXIStringCStr(reinterpret_cast<const VXIString *>(val));
vxistring temp(L"URL");
temp += L": ";
temp += diagUri.c_str();
temp += L", ";
temp += VXIStringCStr(key);
temp += L": ";
temp += VXIStringCStr(value);
log->LogDiagnostic(SimpleLogger::DOC_DUMPS, temp.c_str());
}
delete [] cbuffer;
cbuffer = NULL;
if (key) VXIStringDestroy(&key);
if (value) VXIStringDestroy(&value);
}
// (3) Handle error conditions.
switch (result) {
case -1: // Out of memory
throw VXIException::OutOfMemory();
case 0: // Success
break;
case 1: // Invalid parameter
case 2: // Unable to open URI
log->LogError(203);
// now look at the http status code to throw the
// compiliant error.badfetch.http.<response code>
if (docProperties.GetValue()) {
// retrieve response code
VXIint iv = 0;
const VXIValue *v =
VXIMapGetProperty(docProperties.GetValue(), INET_INFO_HTTP_STATUS);
if( v && VXIValueGetType(v) == VALUE_INTEGER &&
((iv = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(v))) > 0)
)
{
std::basic_stringstream<VXIchar> respStream;
respStream << EV_ERROR_BADFETCH << L".http.";
respStream << iv;
throw VXIException::InterpreterEvent(respStream.str().c_str());
}
}
throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH);
case 3: // Unable to read from URI
log->LogError(204);
throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH);
case 4: // Unable to parse contents of URI
{
VXIString *key = NULL, *value = NULL;
if ((cbuffer) &&
((log->IsLogging(SimpleLogger::DOC_PARSE_ERROR_DUMPS)) ||
(log->IsLogging(SimpleLogger::DOC_DUMPS))) &&
(log->LogContent(VXI_MIME_XML, cbuffer, bufferSize, &key, &value)))
log->LogError(205, VXIStringCStr(key), VXIStringCStr(value));
else
log->LogError(205);
if (cbuffer) delete [] cbuffer;
if (key) VXIStringDestroy(&key);
if (value) VXIStringDestroy(&value);
throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH);
}
default:
log->LogError(206);
throw VXIException::Fatal();
}
if (doc.GetRoot() == 0) {
log->LogError(999, SimpleLogger::MESSAGE,
L"able to fetch initial document but node empty");
throw VXIException::Fatal();
}
}
void VXI::ProcessRootScripts(VXMLElement& doc)
{
if (doc == 0) return;
log->LogDiagnostic(2, L"VXI::ProcessRootScripts()");
// Do <var> <script> and <meta> <property> elements
for (VXMLNodeIterator it(doc); it; ++it) {
VXMLNode child = *it;
if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child);
VXMLElementType nodeName = elem.GetName();
if (nodeName == NODE_VAR)
var_element(elem);
else if (nodeName == NODE_META)
meta_element(elem);
else if (nodeName == NODE_SCRIPT)
script_element(elem);
}
log->LogDiagnostic(2, L"VXI::ProcessRootScripts - done");
}
//#############################################################################
// Dialog Loop
//#############################################################################
// There are two cases in which this routine may be entered.
// A. After a new document is loaded (lastItem == 0)
// B. After a return from <subdialog>
// and three ways in which the loop may be re-entered.
// 1. Jump to new dialog.
// 2. Jump to new form item in the existing dialog.
// 3. Jump to new dialog after recognizing a document scope grammar.
//
// The ECMA script scopes are reset accordingly:
// anonymous: A B 1 2 3
// local: A 1 2 3
// dialog: A 1 3
void VXI::RunInnerLoop()
{
log->LogDiagnostic(2, L"VXI::RunInnerLoop()");
if (exe->currentDialog == 0) {
log->LogError(999, SimpleLogger::MESSAGE, L"no current active document");
return;
}
exe->currentFormItem = exe->lastItem; // next item to process; <goto> etc.
exe->lastItem = VXMLElement(); // reset after <subdialog>
bool newDialog = (exe->currentFormItem == 0);
exe->playingPrompts = true; // flag for prompting after events
// Are we re-entering after a recognition?
bool unprocessedAnswer = false;
while (1) {
if (stopRequested) throw VXIException::StopRequest();
try {
try {
// (1) Adjust scope if necessary
if (exe->script.CurrentScope(SCOPE_Anonymous)) exe->script.PopScope();
if (exe->script.CurrentScope(SCOPE_Local)) exe->script.PopScope();
// (2) Initialize dialog (if necessary)
if (newDialog) {
newDialog = false;
exe->playingPrompts = true;
// (2.1) Reset ECMA script scope.
if (exe->script.CurrentScope(SCOPE_Dialog)) exe->script.PopScope();
exe->script.PushScope(SCOPE_Dialog);
// (2.2) Do 'initialization phase' from FIA.
VXIMapHolder params(sdParams);
sdParams = NULL;
FormInit(exe->currentDialog, params);
// (2.3) Do 'select phase' from FIA if the item is not already known
if (exe->currentFormItem == 0) {
DoInnerJump(exe->currentDialog, L"");
break;
}
}
// (3) The loop cases.
// (3.1) Re-entering loop with an unprocessed recognition result.
if (unprocessedAnswer == true) {
unprocessedAnswer = false;
HandleRemoteMatch(exe->currentDialog, exe->currentFormItem);
}
// (3.2) Re-entering loop after returning from a <subdialog>.
else if (sdResult != NULL) {
VXIMapHolder temp(sdResult);
sdResult = NULL;
ProcessReturn(exe->currentDialog, exe->currentFormItem, temp);
}
else if (sdEvent != NULL) {
// The sdEvent is deallocated in the catch (below).
throw VXIException::InterpreterEvent(*sdEvent);
}
// (3.3) Each time we enter collect phase, we get fresh local scope.
// All filled and catched triggered form here will execute in this
// scope. The final local scope is popped with we leave.
else {
if (exe->script.CurrentScope(SCOPE_Local)) exe->script.PopScope();
exe->script.PushScope(SCOPE_Local);
mutex.Lock();
if (haveExternalEvents) {
vxistring event, message;
if (externalEvents.size() > 0) {
event = externalEvents.front();
externalEvents.pop_front();
message = externalMessages.front();
externalMessages.pop_front();
}
if (externalEvents.empty()) haveExternalEvents = false;
mutex.Unlock();
throw VXIException::InterpreterEvent(event, message,
exe->currentDialog);
}
mutex.Unlock();
// Do the 'collect phase & process phase' from the FIA.
CollectPhase(exe->currentDialog, exe->currentFormItem);
}
}
catch (const VXIException::InterpreterEvent & e) {
// Cleanup sdEvent (if necessary).
if (sdEvent != NULL) {
delete sdEvent;
sdEvent = NULL;
}
// Handles document events.
if (log->IsLogging(2)) {
log->StartDiagnostic(2) << L"VXI::RunInnerLoop - got exception: "
<< e.GetValue();
log->EndDiagnostic();
}
if (exe->currentFormItem != 0)
DoEvent(exe->currentFormItem, e);
else
DoEvent(exe->currentDialog, e);
}
DoInnerJump(exe->currentDialog, L"");
break;
}
catch (JumpDialog & e) { // Handle <goto> events
exe->currentDialog = e.dialog;
exe->currentFormItem = VXMLElement();
newDialog = true;
}
catch (const JumpItem & e) { // This handles local <goto>s.
exe->currentFormItem = e.item;
}
catch (AnswerInformation & e) {
if (exe->currentDialog != e.dialog) {
exe->currentDialog = e.dialog;
newDialog = true;
}
exe->currentFormItem = e.element;
unprocessedAnswer = true;
}
} // while (1)
log->LogDiagnostic(2, L"VXI::RunInnerLoop - done");
}
void VXI::ProcessReturn(const VXMLElement& form, const VXMLElement & item,
VXIMapHolder & result)
{
log->LogDiagnostic(2, L"VXI::ProcessReturn()");
vxistring filled;
item.GetAttribute(ATTRIBUTE__ITEMNAME, filled);
exe->script.SetValue(filled, reinterpret_cast<VXIValue*>(result.GetValue()));
ProcessFilledElements(filled, form);
}
// Perform initialization associated with property tags and form level
// variables. Reset the event and prompts counts.
//
void VXI::FormInit(const VXMLElement & form, VXIMapHolder & params)
{
log->LogDiagnostic(2, L"VXI::FormInit()");
// (1) Set the form properties.
exe->properties.SetProperties(form, DIALOG_PROP, VXIMapHolder());
// (2) Clear the prompt & event counts when the form is entered.
exe->promptcounts.Clear();
exe->eventcounts.Clear();
exe->formitems.clear();
vxistring itemname;
form.GetAttribute(ATTRIBUTE__ITEMNAME, itemname);
// (3) Walk through the form nodes. Set up variables as necessary.
for (VXMLNodeIterator it(form); it; ++it) {
VXMLNode child = *it;
if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child);
// (3.1) Handle <var> and <script> elements.
VXMLElementType nodeName = elem.GetName();
if (nodeName == NODE_VAR) {
if (params.GetValue() != NULL) {
// (3.1.1) Set matching variables to the value in the param list.
// Each located parameter gets removed from the map.
vxistring name;
elem.GetAttribute(ATTRIBUTE_NAME, name);
if (!name.empty()) {
const VXIValue * value = VXIMapGetProperty(params.GetValue(),
name.c_str());
if (value != NULL) {
exe->script.MakeVar(name, value);
VXIMapDeleteProperty(params.GetValue(), name.c_str());
continue;
}
}
}
// (3.1.2) Otherwise, follow the normal proceedure.
var_element(elem);
continue;
}
else if (nodeName == NODE_SCRIPT)
script_element(elem);
// (3.2) Ignore anything which is not a form item.
if (!IsFormItemNode(elem)) continue;
// (3.3) Initialize variables for each form item.
vxistring name;
vxistring expr;
elem.GetAttribute(ATTRIBUTE__ITEMNAME, name);
if (exe->script.IsVarDeclared(name)) {
throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH,
L"input item variable name conflict");
}
elem.GetAttribute(ATTRIBUTE_EXPR, expr);
exe->script.MakeVar(name, expr);
nodeName = elem.GetName();
if (nodeName == NODE_FIELD || nodeName == NODE_RECORD ||
nodeName == NODE_TRANSFER)
exe->script.EvalScript(vxistring(L"var ") + name + L"$ = new Object();");
exe->formitems.push_back(name);
}
// (4) Did all incoming parameters get used?
if (params.GetValue() != NULL &&
VXIMapNumProperties(params.GetValue()) != 0) {
if (log->IsLogging(2)) {
const VXIchar *key;
const VXIValue *value;
VXIMapIterator *vi = VXIMapGetFirstProperty(params.GetValue(), &key,
&value);
while (vi) {
vxistring text(L"VXI::FormInit - unused parameter ");
text += key;
log->LogDiagnostic(2, text.c_str());
if (VXIMapGetNextProperty(vi, &key, &value) !=VXIvalue_RESULT_SUCCESS){
VXIMapIteratorDestroy(&vi);
vi = NULL;
}
}
}
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC);
}
log->LogDiagnostic(2, L"VXI::FormInit - Done");
}
// Returns true iff the element is a form item.
//
// This is the list from section 6.2 of the VXML 1.0 specification with one
// addition - <menu>.
//
bool VXI::IsFormItemNode(const VXMLElement & doc)
{
VXMLElementType nodeName = doc.GetName();
if (nodeName == NODE_FIELD || nodeName == NODE_INITIAL ||
nodeName == NODE_RECORD || nodeName == NODE_TRANSFER ||
nodeName == NODE_OBJECT || nodeName == NODE_SUBDIALOG ||
nodeName == NODE_MENU || nodeName == NODE_BLOCK)
return true;
return false;
}
bool VXI::IsInputItemNode(const VXMLElement & doc)
{
VXMLElementType nodeName = doc.GetName();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -