int repeat_min;
int repeat_max;
const char *weight;
- char *tag;
+ int tag;
};
/**
/** rule names mapped to node */
switch_hash_t *rules;
/** possible matching tags */
- const char *tags[MAX_TAGS];
+ const char *tags[MAX_TAGS + 1];
/** number of tags */
int tag_count;
/** grammar encoding */
{
struct srgs_node *item = grammar->cur->parent;
if (item && item->type == SNT_ITEM) {
- item->value.item.tag = switch_core_alloc(grammar->pool, sizeof(char) * (len + 1));
- item->value.item.tag[len] = '\0';
- strncpy(item->value.item.tag, data, len);
if (grammar->tag_count < MAX_TAGS) {
- grammar->tags[grammar->tag_count++] = item->value.item.tag;
+ /* grammar gets the tag name, item gets the unique tag number */
+ char *tag = switch_core_alloc(grammar->pool, sizeof(char) * (len + 1));
+ tag[len] = '\0';
+ strncpy(tag, data, len);
+ grammar->tags[++grammar->tag_count] = tag;
+ item->value.item.tag = grammar->tag_count;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "too many <tag>s\n");
return IKS_BADXML;
case SNT_ITEM:
if (node->child) {
struct srgs_node *item = node->child;
- if (node->value.item.repeat_min != 1 || node->value.item.repeat_max != 1 || !zstr(node->value.item.tag)) {
- if (zstr(node->value.item.tag)) {
- stream->write_function(stream, "%s", "(?:");
+ if (node->value.item.repeat_min != 1 || node->value.item.repeat_max != 1 || node->value.item.tag) {
+ if (node->value.item.tag) {
+ stream->write_function(stream, "(?P<%d>", node->value.item.tag);
} else {
- stream->write_function(stream, "(?P<%s>", node->value.item.tag);
+ stream->write_function(stream, "%s", "(?:");
}
}
for(; item; item = item->next) {
} else {
stream->write_function(stream, "){%i}", node->value.item.repeat_min);
}
- } else if (!zstr(node->value.item.tag)) {
+ } else if (node->value.item.tag) {
stream->write_function(stream, "%s", ")");
}
}
buffer[MAX_INPUT_SIZE] = '\0';
/* find matching instance... */
- for (i = 0; i < grammar->tag_count; i++) {
+ for (i = 1; i <= grammar->tag_count; i++) {
+ char substring_name[16] = { 0 };
buffer[0] = '\0';
- if (pcre_copy_named_substring(compiled_regex, input, ovector, result, grammar->tags[i], buffer, MAX_INPUT_SIZE) != PCRE_ERROR_NOSUBSTRING && !zstr_buf(buffer)) {
+ snprintf(substring_name, 16, "%d", i);
+ if (pcre_copy_named_substring(compiled_regex, input, ovector, result, substring_name, buffer, MAX_INPUT_SIZE) != PCRE_ERROR_NOSUBSTRING && !zstr_buf(buffer)) {
*interpretation = grammar->tags[i];
break;
}
srgs_parser_destroy(parser);
}
+static const char *duplicate_tag_grammar =
+ "<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" version=\"1.0\" xml:lang=\"en-US\" mode=\"dtmf\" root=\"options\" tag-format=\"semantics/1.0-literals\">"
+ " <rule id=\"options\" scope=\"public\">\n"
+ " <one-of>\n"
+ " <item><tag>2</tag>1</item>\n"
+ " <item><tag>2</tag>5</item>\n"
+ " <item><tag>4</tag>7</item>\n"
+ " <item><tag>4</tag>9</item>\n"
+ " </one-of>\n"
+ " </rule>\n"
+ "</grammar>\n";
+
+/**
+ * Test matching with duplicate tags
+ */
+static void test_match_duplicate_tag_grammar(void)
+{
+ struct srgs_parser *parser;
+ struct srgs_grammar *grammar;
+ const char *interpretation;
+
+ parser = srgs_parser_new("1234");
+ ASSERT_NOT_NULL((grammar = srgs_parse(parser, duplicate_tag_grammar)));
+
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "1", &interpretation));
+ ASSERT_STRING_EQUALS("2", interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "2", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "3", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "4", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "5", &interpretation));
+ ASSERT_STRING_EQUALS("2", interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "6", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "7", &interpretation));
+ ASSERT_STRING_EQUALS("4", interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "8", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_MATCH_END, srgs_grammar_match(grammar, "9", &interpretation));
+ ASSERT_STRING_EQUALS("4", interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "#", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "*", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "A", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "27", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "223", &interpretation));
+ ASSERT_NULL(interpretation);
+ ASSERT_EQUALS(SMT_NO_MATCH, srgs_grammar_match(grammar, "0123456789*#", &interpretation));
+ ASSERT_NULL(interpretation);
+
+ srgs_parser_destroy(parser);
+}
+
static const char *adhearsion_ask_grammar =
"<grammar xmlns=\"http://www.w3.org/2001/06/grammar\" version=\"1.0\" xml:lang=\"en-US\" mode=\"dtmf\" root=\"inputdigits\">"
srgs_init();
TEST(test_parse_grammar);
TEST(test_match_adhearsion_menu_grammar);
+ TEST(test_match_duplicate_tag_grammar);
TEST(test_match_adhearsion_ask_grammar);
TEST(test_match_multi_digit_grammar);
TEST(test_match_multi_rule_grammar);