--- /dev/null
+/*
+* Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the License);
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an AS IS BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+#include "ctype.h"
+
+#include "vc_main.h"
+#include "vc_command_util.h"
+#include "vc_command.h"
+
+#include <voice_control_command_expand.h>
+
+vc_cmd_list_h ret_list = NULL;
+GList *split_list = NULL;
+int ret_cnt = -1;
+
+void __tolower(char *str)
+{
+ while (0 != *str) {
+ *str = tolower(*str);
+ ++str;
+ }
+}
+
+int vc_cmd_get_partially_matched_cmd_list(const char *command, vc_cmd_list_h src_list, vc_cmd_list_h dst_list, int search_level)
+{
+ SLOG(LOG_DEBUG, TAG_VCCMD, "@@@ vc_cmd_find_similar_commands");
+ if (NULL == command || NULL == src_list || NULL == dst_list || VC_SEARCH_TEXT_LEVEL > search_level || VC_SEARCH_PRON_LEVEL < search_level) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Invalid parameter");
+ return VC_ERROR_INVALID_PARAMETER;
+ }
+
+ char *temp_cmd = NULL;
+ char *split = NULL;
+ char *tok_ptr = NULL;
+
+ ret_list = dst_list;
+ split_list = NULL;
+ ret_cnt = 0;
+
+ temp_cmd = strdup(command);
+ if (NULL == temp_cmd) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Out of memory");
+ return VC_ERROR_OUT_OF_MEMORY;
+ }
+
+ __tolower(temp_cmd);
+ split = strtok_r(temp_cmd, " ", &tok_ptr);
+ while (NULL != split) {
+ char *temp = strdup(split);
+
+ if (NULL == temp) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Out of memory");
+ free(temp_cmd);
+ temp_cmd = NULL;
+
+ g_list_free_full(split_list, free);
+ split_list = NULL;
+
+ return VC_ERROR_OUT_OF_MEMORY;
+ }
+
+ SLOG(LOG_DEBUG, TAG_VCCMD, "(%s)", split);
+ split_list = g_list_append(split_list, temp);
+
+ split = strtok_r(NULL, " ", &tok_ptr);
+ }
+
+ free(temp_cmd);
+ temp_cmd = NULL;
+
+ int ret = 0;
+ ret = vc_search_text(src_list, search_level);
+
+ g_list_free_full(split_list, free);
+ split_list = NULL;
+ if (0 != ret) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to search similar commands (%d)", ret);
+ }
+
+ SLOG(LOG_DEBUG, TAG_VCCMD, "@@@");
+ return ret;
+}
+
+int vc_search_text(vc_cmd_list_h list, int search_level)
+{
+ SLOG(LOG_DEBUG, TAG_VCCMD, "@@@ Full Text level matching");
+ vc_cmd_h vc_cmd = NULL;
+ int ret = VC_ERROR_NONE;
+
+ ret = vc_cmd_list_first(list);
+ if (0 != ret) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to make list first (%d)", ret);
+ return ret;
+ }
+ ret = vc_cmd_list_get_current(list, &vc_cmd);
+ if (0 != ret) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to get voice command handle (%d)", ret);
+ return ret;
+ }
+
+ while (NULL != vc_cmd) {
+ GList *item = NULL;
+ char *cmd_text = NULL;
+
+ if (0 != vc_cmd_get_command(vc_cmd, &cmd_text) || NULL == cmd_text) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to get command");
+ return VC_ERROR_OPERATION_FAILED;
+ }
+
+ __tolower(cmd_text);
+ item = g_list_first(split_list);
+ while (NULL != item) {
+ char *word = (char*)item->data;
+ if (NULL != word && NULL == strstr(cmd_text, word)) {
+ break;
+ }
+
+ item = item->next;
+ }
+
+ free(cmd_text);
+
+ if (NULL == item) {
+ if (0 == vc_cmd_list_add(ret_list, vc_cmd)) {
+ ret_cnt++;
+ }
+ }
+
+ if (VC_ERROR_ITERATION_END == vc_cmd_list_next(list)) {
+ /* Move commands from list to ret_list */
+ if (0 != vc_cmd_list_first(ret_list) || 0 != vc_cmd_list_get_current(ret_list, &vc_cmd)) {
+ break;
+ }
+
+ while (NULL != vc_cmd) {
+ if (0 != vc_cmd_list_remove(list, vc_cmd)) {
+ break;
+ }
+
+ if (0 != vc_cmd_list_next(ret_list)) {
+ break;
+ }
+
+ if (0 != vc_cmd_list_get_current(ret_list, &vc_cmd)) {
+ break;
+ }
+ }
+
+ break;
+ }
+
+ vc_cmd_list_get_current(list, &vc_cmd);
+ }
+
+ SLOG(LOG_DEBUG, TAG_VCCMD, "Number of matched text : (%d)", ret_cnt);
+
+ if (ret_cnt >= 1) {
+ return VC_ERROR_NONE;
+ }
+
+ if (VC_SEARCH_WORD_LEVEL > search_level) {
+ SLOG(LOG_DEBUG, TAG_VCCMD, "Text matching ends by search level (%d)", search_level);
+ return VC_ERROR_NONE;
+ }
+
+ return vc_search_word(list, search_level);
+}
+
+int vc_search_word(vc_cmd_list_h list, int search_level)
+{
+ SLOG(LOG_DEBUG, TAG_VCCMD, "@@@ Partial Word level matching");
+ vc_cmd_h vc_cmd = NULL;
+ vc_cmd_h ret_cmd = NULL;
+ int ret = VC_ERROR_NONE;
+ int max = -1; // This is also threshold value
+
+ max = g_list_length(split_list) * VC_WORD_MATCHING_RATE;
+
+ ret = vc_cmd_list_first(list);
+ if (0 != ret) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to make list first (%d)", ret);
+ return ret;
+ }
+ ret = vc_cmd_list_get_current(list, &vc_cmd);
+ if (0 != ret) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to get voice command handle (%d)", ret);
+ return ret;
+ }
+
+ while (NULL != vc_cmd) {
+ GList *item = NULL;
+ char *cmd_text = NULL;
+ int cnt = 0;
+
+ if (0 != vc_cmd_get_command(vc_cmd, &cmd_text) || NULL == cmd_text) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to get command");
+ return VC_ERROR_OPERATION_FAILED;
+ }
+
+ __tolower(cmd_text);
+ item = g_list_first(split_list);
+ while (NULL != item) {
+ char *word = (char*)item->data;
+
+ if (NULL != word && NULL != strstr(cmd_text, word)) {
+ cnt++;
+ }
+
+ item = item->next;
+ }
+
+ free(cmd_text);
+
+ SLOG(LOG_DEBUG, TAG_VCCMD, "The number of matched word in the text : (%d)", cnt);
+ if (cnt > max) {
+ ret_cmd = vc_cmd;
+ max = cnt;
+ }
+
+ if (VC_ERROR_ITERATION_END == vc_cmd_list_next(list)) {
+ break;
+ }
+
+ vc_cmd_list_get_current(list, &vc_cmd);
+ }
+
+ if (NULL != ret_cmd) {
+ if (0 != vc_cmd_list_remove(list, ret_cmd)) {
+ return VC_ERROR_OPERATION_FAILED;
+ }
+ if (0 != vc_cmd_list_add(ret_list, ret_cmd)) {
+ return VC_ERROR_OPERATION_FAILED;
+ }
+
+ ret_cnt++;
+
+ return VC_ERROR_NONE;
+ }
+
+ if (VC_SEARCH_CHAR_LEVEL > search_level) {
+ SLOG(LOG_DEBUG, TAG_VCCMD, "Text matching end by search level (%d)", search_level);
+ return VC_ERROR_NONE;
+ }
+
+ return vc_search_char(list, search_level);
+}
+
+/* check the behavior */
+int vc_search_char(vc_cmd_list_h list, int search_level)
+{
+ SLOG(LOG_DEBUG, TAG_VCCMD, "@@@ Partial Character level matching");
+ vc_cmd_h vc_cmd = NULL;
+ vc_cmd_h ret_cmd = NULL;
+ int threshold = 0;
+ GList *item = NULL;
+
+ int result_score = 2147483647;
+
+ vc_cmd_list_first(list);
+ vc_cmd_list_get_current(list, &vc_cmd);
+
+ while (NULL != vc_cmd) {
+ int score = 0;
+ char *split = NULL;
+ char *cmd_text = NULL;
+ char *tok_ptr = NULL;
+
+ if (0 != vc_cmd_get_command(vc_cmd, &cmd_text) || NULL == cmd_text) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Fail to get command");
+ return VC_ERROR_OPERATION_FAILED;
+ }
+
+ __tolower(cmd_text);
+ item = g_list_first(split_list);
+ while (NULL != item) {
+ char *word = (char*)item->data;
+ int min_score = -1;
+
+ if (NULL == word || 3 > strlen(word)) {
+ item = item->next;
+ continue;
+ }
+
+ min_score = strlen(word) * VC_CHAR_MATCHING_RATE; // This is also threshold
+
+ split = strtok_r(cmd_text, " ", &tok_ptr);
+ while (NULL != split) {
+ SLOG(LOG_DEBUG, TAG_VCCMD, "(%s)", split);
+ if (3 > strlen(split)) {
+ split = strtok_r(NULL, " ", &tok_ptr);
+ continue;
+ }
+
+ char *long_str = NULL;
+ char *short_str = NULL;
+
+ if (strlen(split) > strlen(word)) {
+ long_str = split;
+ short_str = word;
+ } else {
+ long_str = word;
+ short_str = split;
+ }
+
+ int long_str_len = strlen(long_str);
+ int short_str_len = strlen(short_str);
+
+ int *cost = (int*)calloc(long_str_len + 1, sizeof(int));
+ int *ncost = (int*)calloc(long_str_len + 1, sizeof(int));
+
+ if (NULL == cost || NULL == ncost) {
+ SLOG(LOG_ERROR, TAG_VCCMD, "[ERROR] Out of memory");
+
+ free(cmd_text);
+ return VC_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (int l = 0; l <= long_str_len; l++) {
+ cost[l] = l;
+ }
+
+ for (int s = 1; s <= short_str_len; s++) {
+ ncost[0] = s;
+
+ for (int l = 1; l <= long_str_len; l++) {
+ int match = (short_str[s - 1] == long_str[l - 1] ? 0 : 1);
+
+ int rep = cost[l - 1] + match;
+ int ins = cost[l] + 1;
+ int del = ncost[l - 1] + 1;
+
+ int min = (rep < ins ? rep : ins);
+ ncost[l] = (min < del ? min : del);
+ }
+
+ int *temp = cost;
+ cost = ncost;
+ ncost = temp;
+ }
+
+ if (min_score > cost[long_str_len]) {
+ min_score = cost[long_str_len];
+ }
+
+ free(cost);
+ free(ncost);
+
+ split = strtok_r(NULL, " ", &tok_ptr);
+ }
+
+ if (min_score < strlen(word) * VC_CHAR_MATCHING_RATE) {
+ score = score + min_score;
+ } else {
+ score = score + strlen(word);
+ }
+
+ item = item->next;
+ }
+
+ free(cmd_text);
+ cmd_text = NULL;
+
+ if (result_score > score) {
+ result_score = score;
+ ret_cmd = vc_cmd;
+ }
+
+ if (VC_ERROR_ITERATION_END == vc_cmd_list_next(list)) {
+ break;
+ }
+
+ vc_cmd_list_get_current(list, &vc_cmd);
+ }
+
+ item = g_list_first(split_list);
+ while (NULL != item) {
+ char *word = (char*)item->data;
+
+ if (NULL != word && 3 <= strlen(word)) {
+ threshold += strlen(word);
+ }
+
+ item = item->next;
+ }
+
+ if (threshold > result_score) {
+ vc_cmd_list_remove(list, ret_cmd);
+ vc_cmd_list_add(ret_list, ret_cmd);
+ ret_cnt++;
+
+ return VC_ERROR_NONE;
+ }
+
+ if (VC_SEARCH_PRON_LEVEL > search_level) {
+ SLOG(LOG_DEBUG, TAG_VCCMD, "Text matching ends by search level (%d)", search_level);
+ return VC_ERROR_NONE;
+ }
+
+ return vc_search_pron(list, search_level);
+}
+
+int vc_search_pron(vc_cmd_list_h list, int search_level)
+{
+ SLOG(LOG_DEBUG, TAG_VCCMD, "@@@ Partial Pronunciation level matching");
+ return VC_ERROR_NONE;
+}
\ No newline at end of file