diff options
Diffstat (limited to 'src/ncmd.c')
-rw-r--r-- | src/ncmd.c | 351 |
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; +} + |