summaryrefslogtreecommitdiffstats
path: root/src/ncmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ncmd.c')
-rw-r--r--src/ncmd.c351
1 files changed, 351 insertions, 0 deletions
diff --git a/src/ncmd.c b/src/ncmd.c
new file mode 100644
index 0000000..e1393a3
--- /dev/null
+++ b/src/ncmd.c
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright © 2020 rsiddharth <s@ricketyspace.net>
+ */
+
+#include <ncmd.h>
+
+int sanitize(char *cmd)
+{
+ check(cmd != NULL, "cmd is NULL");
+
+ int len = strlen(cmd);
+ check(len > 0, "cmd empty");
+
+ // replace newline character with NUL.
+ for (int i = 0; i < len; i++) {
+ if (cmd[i] == '\n') {
+ cmd[i] = '\0';
+
+ break;
+ }
+ }
+ return 0;
+ error:
+ return -1;
+}
+
+int check_cmd(char *cmd, char *err)
+{
+ check_mem(err);
+ check(cmd != NULL, "cmd is NULL");
+
+ int rc = sanitize(cmd);
+ check(rc != -1, "sanitize failed");
+
+ size_t len = strlen(cmd);
+ if (len >= CMD_MIN_SIZE && len <= CMD_MAX_SIZE) {
+ return 0;
+ }
+
+ if (len == 0) {
+ strncpy(err, "closing connection\n", RSP_SIZE);
+ return -1;
+ } else {
+ strncpy(err, "command size invalid\n", RSP_SIZE);
+ return -1;
+ }
+
+ return 0;
+ error:
+ strncpy(err, "internal error\n", RSP_SIZE);
+ return -1;
+}
+
+
+struct bstrList *cmd_parts(char *cmd)
+{
+ bstring bcmd = NULL;
+ struct bstrList *parts_tmp = NULL;
+
+ bcmd = bfromcstr(cmd);
+ check(bcmd != NULL, "bstring creation failed");
+
+ parts_tmp = bsplit(bcmd, ' ');
+ check(parts_tmp != NULL, "cmp split failed");
+ check(parts_tmp->qty > 0, "qty check failed");
+
+ struct bstrList *parts = bstrListCreate();
+ check(parts != NULL, "parts create failed");
+
+ int rc = bstrListAlloc(parts, parts_tmp->qty);
+ check(rc == BSTR_OK, "parts alloc failed");
+ check(parts->qty == 0, "qty check failed");
+
+ bstring part = NULL;
+ int index = 0;
+ for (int i = 0; i < parts_tmp->qty; i++) {
+ check(parts->qty <= parts->mlen, "parts capacity check failed");
+
+ part = parts_tmp->entry[i];
+
+ if (blength(part) == 0) {
+ continue;
+ }
+
+ parts->entry[index++] = bstrcpy(part);
+ parts->qty++;
+ }
+
+ // Clean up.
+ bdestroy(bcmd);
+ bstrListDestroy(parts_tmp);
+
+ return parts;
+ error:
+ // Clean up.
+ if (bcmd) {
+ bdestroy(bcmd);
+ }
+ if (parts_tmp) {
+ bstrListDestroy(parts_tmp);
+ }
+
+ return NULL;
+}
+
+int find_function(struct bstrList *cmd_parts)
+{
+ // functions.
+ struct tagbstring fcreate = bsStatic("/create");
+ struct tagbstring fsample = bsStatic("/sample");
+ struct tagbstring fmean = bsStatic("/mean");
+ struct tagbstring fdump = bsStatic("/dump");
+ struct tagbstring fdelete = bsStatic("/delete");
+ struct tagbstring flist = bsStatic("/list");
+ struct tagbstring fstore = bsStatic("/store");
+ struct tagbstring fload = bsStatic("/load");
+
+ check(cmd_parts != NULL, "cmd_parts is NULL");
+ check(cmd_parts->qty > 0, "qty check failed");
+
+ bstring cmd_name = cmd_parts->entry[0];
+ check(blength(cmd_name) > 0, "cmd_name check failed");
+
+ // trim cmd name
+ int rc = btrimws(cmd_name);
+ check(rc == BSTR_OK, "cmd name trim failed");
+
+ // find function for cmd_name
+ if (bstricmp(cmd_name, &fcreate) == 0) {
+ return NS_CREATE;
+ } else if (bstricmp(cmd_name, &fsample) == 0) {
+ return NS_SAMPLE;
+ } else if (bstricmp(cmd_name, &fmean) == 0) {
+ return NS_MEAN;
+ } else if (bstricmp(cmd_name, &fdump) == 0) {
+ return NS_DUMP;
+ } else if (bstricmp(cmd_name, &fdelete) == 0) {
+ return NS_DELETE;
+ } else if (bstricmp(cmd_name, &flist) == 0) {
+ return NS_LIST;
+ } else if (bstricmp(cmd_name, &fstore) == 0) {
+ return NS_STORE;
+ } else if (bstricmp(cmd_name, &fload) == 0) {
+ return NS_LOAD;
+ } else {
+ return NS_NOP;
+ }
+
+ error:
+ return NS_NOP;
+}
+
+int check_args(struct bstrList *cmd_parts, int argc)
+{
+ check(cmd_parts != NULL, "cmd_parts is NULL");
+ check(cmd_parts->qty == argc, "qty check failed");
+
+ bstring part = NULL;
+ for (int i = 0; i < argc; i++) {
+ part = cmd_parts->entry[i];
+
+ check(blength(part) > 0, "part %d empty", i);
+ }
+
+ return 0;
+ error:
+ return -1;
+}
+
+int call_function(int func, struct bstrList *cmd_parts, char *out)
+{
+ check(out != NULL, "out invalid");
+
+ if (func < 0 || cmd_parts == NULL || cmd_parts->qty < 1) {
+ strncpy(out, "error: args invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ double mean = 0.0;
+ switch (func) {
+ case NS_CREATE:
+ if(check_args(cmd_parts, 2) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+ if (sscreate(bdata(cmd_parts->entry[1])) < 0) {
+ strncpy(out, "error: create failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ strncpy(out, "OK\n", RSP_SIZE);
+
+ break;
+ case NS_SAMPLE:
+ if(check_args(cmd_parts, 3) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ double sample = strtod(bdata(cmd_parts->entry[2]), NULL);
+ mean = sssample(bdata(cmd_parts->entry[1]), sample);
+ if (mean < 0) {
+ strncpy(out, "error: sample failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ if (sprintf(out, "Mean: %.2f\n", mean) < 0) {
+ strncpy(out, "error: sample failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ break;
+ case NS_MEAN:
+ if(check_args(cmd_parts, 2) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ mean = ssmean(bdata(cmd_parts->entry[1]));
+ if (mean < 0) {
+ strncpy(out, "error: mean failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ if (sprintf(out, "Mean: %.2f\n", mean) < 0) {
+ strncpy(out, "error: mean failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ break;
+ case NS_DUMP:
+ if(check_args(cmd_parts, 2) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ char *dump = ssdump(bdata(cmd_parts->entry[1]));
+ if (dump == NULL) {
+ strncpy(out, "error: dump failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ strncpy(out, dump, RSP_SIZE);
+
+ // Clean up dump
+ free(dump);
+
+ break;
+ case NS_DELETE:
+ if(check_args(cmd_parts, 2) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ if (ssdelete(bdata(cmd_parts->entry[1])) != 0) {
+ strncpy(out, "error: delete failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ strncpy(out, "OK\n", RSP_SIZE);
+
+ break;
+ case NS_LIST:
+ if(check_args(cmd_parts, 1) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ char *list = sslist();
+ if (list == NULL) {
+ strncpy(out, "error: list failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ strncpy(out, list, RSP_SIZE);
+
+ // Clean up list.
+ free(list);
+
+ break;
+ case NS_STORE:
+ if(check_args(cmd_parts, 2) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+ if (ssstore(bdata(cmd_parts->entry[1])) < 0) {
+ strncpy(out, "error: store failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ strncpy(out, "OK\n", RSP_SIZE);
+ break;
+ case NS_LOAD:
+ if(check_args(cmd_parts, 3) != 0) {
+ strncpy(out, "error: command invalid\n", RSP_SIZE);
+
+ return -1;
+ }
+ if (ssload(bdata(cmd_parts->entry[1]),
+ bdata(cmd_parts->entry[2])) < 0) {
+ strncpy(out, "error: load failed\n", RSP_SIZE);
+
+ return -1;
+ }
+ strncpy(out, "OK\n", RSP_SIZE);
+ break;
+ default:
+ strncpy(out, "error: function not found\n", RSP_SIZE);
+
+ return -1;
+ }
+
+ return 0;
+ error:
+ return -1;
+}
+
+int process(char *cmd, char *out)
+{
+ check(out, "out invalid");
+
+ int rc = check_cmd(cmd, out);
+ check(rc == 0, "cmd check failed");
+
+ // split cmd into parts.
+ struct bstrList *parts = cmd_parts(cmd);
+ check(parts != NULL, "cmd_parts failed");
+ check(parts->qty > 0, "bstrList qty check failed");
+
+ // call find_function.
+ int FUNC = find_function(parts);
+ check(FUNC != -1, "find function failed");
+
+ // call call_function
+ rc = call_function(FUNC, parts, out);
+ check(rc != -1, "call function failed");
+
+ return 0;
+ error:
+ return -1;
+}
+