aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/config/commandParser.c
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/config/commandParser.c')
-rwxr-xr-xhicn-light/src/config/commandParser.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/hicn-light/src/config/commandParser.c b/hicn-light/src/config/commandParser.c
new file mode 100755
index 000000000..84d273c9d
--- /dev/null
+++ b/hicn-light/src/config/commandParser.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+#include <src/config/commandParser.h>
+
+#ifndef __ANDROID__
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+extern int errno;
+#endif
+#endif
+
+struct command_parser {
+ // key = command, value = CommandOps
+ PARCTreeRedBlack *commandTree;
+ bool debugFlag;
+};
+
+static int _stringCompare(const void *key1, const void *key2) {
+ return strcasecmp((const char *)key1, (const char *)key2);
+}
+
+CommandParser *commandParser_Create(void) {
+ CommandParser *state = parcMemory_AllocateAndClear(sizeof(CommandParser));
+ parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ sizeof(CommandParser));
+
+ state->commandTree = parcTreeRedBlack_Create(_stringCompare, // key compare
+ NULL, // key free
+ NULL, // key copy
+ NULL, // value equals
+ NULL, // value free
+ NULL // value copy
+ );
+ state->debugFlag = false;
+ return state;
+}
+
+void commandParser_Destroy(CommandParser **parserPtr) {
+ CommandParser *parser = *parserPtr;
+
+ // destroy every element if it has a destroyer
+ PARCArrayList *values = parcTreeRedBlack_Values(parser->commandTree);
+ if (values) {
+ for (int i = 0; i < parcArrayList_Size(values); i++) {
+ CommandOps *ops = parcArrayList_Get(values, i);
+ parcTreeRedBlack_Remove(parser->commandTree, ops->command);
+ if (ops->destroyer) {
+ ops->destroyer(&ops);
+ }
+ }
+ parcArrayList_Destroy(&values);
+ }
+
+ parcTreeRedBlack_Destroy(&parser->commandTree);
+
+ parcMemory_Deallocate((void **)&parser);
+ *parserPtr = NULL;
+}
+
+void commandParser_SetDebug(CommandParser *state, bool debugFlag) {
+ state->debugFlag = debugFlag;
+}
+
+bool commandParser_GetDebug(CommandParser *state) { return state->debugFlag; }
+
+void commandParser_RegisterCommand(CommandParser *state, CommandOps *ops) {
+ parcAssertNotNull(state, "Parameter state must be non-null");
+ parcAssertNotNull(ops, "Parameter ops must be non-null");
+ parcAssertNotNull(ops->command, "Operation command string must be non-null");
+
+ void *exists = parcTreeRedBlack_Get(state->commandTree, ops->command);
+ parcAssertNull(exists, "Command '%s' already exists in the tree %p\n",
+ ops->command, (void *)exists);
+
+ parcTreeRedBlack_Insert(state->commandTree, (void *)ops->command,
+ (void *)ops);
+
+ // if the command being registered asked for an init function to be called,
+ // call it
+ if (ops->init != NULL) {
+ ops->init(state, ops);
+ }
+}
+
+static PARCList *parseStringIntoTokens(const char *originalString) {
+ PARCList *list =
+ parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction),
+ PARCArrayListAsPARCList);
+
+ char *token;
+
+ char *tofree =
+ parcMemory_StringDuplicate(originalString, strlen(originalString) + 1);
+ char *string = tofree;
+
+ while ((token = strsep(&string, " \t\n")) != NULL) {
+ if (strlen(token) > 0) {
+ parcList_Add(list, strdup(token));
+ }
+ }
+
+ parcMemory_Deallocate((void **)&tofree);
+
+ return list;
+}
+
+/**
+ * Matches the user arguments to available commands, returning the command or
+ * NULL if not found
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static CommandOps *commandParser_MatchCommand(CommandParser *state,
+ PARCList *args) {
+ // Find the longest matching prefix command.
+ // Pretty wildly inefficient
+
+ size_t longest_token_count = 0;
+ char *longest_command = NULL;
+
+ PARCArrayList *commands = parcTreeRedBlack_Keys(state->commandTree);
+ for (int i = 0; i < parcArrayList_Size(commands); i++) {
+ char *command = parcArrayList_Get(commands, i);
+ PARCList *command_tokens = parseStringIntoTokens(command);
+
+ // is it a prefix match?
+ if (parcList_Size(args) >= parcList_Size(command_tokens)) {
+ bool possible_match = true;
+ for (int i = 0; i < parcList_Size(command_tokens) && possible_match;
+ i++) {
+ const char *a = parcList_GetAtIndex(command_tokens, i);
+ const char *b = parcList_GetAtIndex(args, i);
+ if (strncasecmp(a, b, strlen(a) + 1) != 0) {
+ possible_match = false;
+ }
+ }
+
+ if (possible_match &&
+ parcList_Size(command_tokens) > longest_token_count) {
+ longest_token_count = parcList_Size(command_tokens);
+ longest_command = command;
+ }
+ }
+
+ parcList_Release(&command_tokens);
+ }
+
+ parcArrayList_Destroy(&commands);
+
+ if (longest_token_count == 0) {
+ return NULL;
+ } else {
+ CommandOps *ops = parcTreeRedBlack_Get(state->commandTree, longest_command);
+ parcAssertNotNull(ops, "Got null operations for command '%s'\n",
+ longest_command);
+ return ops;
+ }
+}
+
+CommandReturn commandParser_DispatchCommand(CommandParser *state,
+ PARCList *args) {
+ CommandOps *ops = commandParser_MatchCommand(state, args);
+
+ if (ops == NULL) {
+ printf("Command not found.\n");
+ return CommandReturn_Failure;
+ } else {
+ return ops->execute(state, ops, args);
+ }
+}
+
+bool commandParser_ContainsCommand(CommandParser *parser, const char *command) {
+ CommandOps *ops = parcTreeRedBlack_Get(parser->commandTree, command);
+ return (ops != NULL);
+}