summaryrefslogtreecommitdiff
path: root/Radio/HW/BladeRF/common/src/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'Radio/HW/BladeRF/common/src/parse.c')
-rw-r--r--Radio/HW/BladeRF/common/src/parse.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/Radio/HW/BladeRF/common/src/parse.c b/Radio/HW/BladeRF/common/src/parse.c
new file mode 100644
index 0000000..dd6abe1
--- /dev/null
+++ b/Radio/HW/BladeRF/common/src/parse.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2017 Nuand LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "parse.h"
+#include "conversions.h"
+#include "log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static char **add_arg(
+ char **argv, int argc, const char *buf, int start, int end, int quote_count)
+{
+ char **rv;
+ char *d_ptr;
+ int i;
+ int len;
+
+ char c;
+ char quote_char;
+
+ quote_char = 0;
+
+ rv = (char **)realloc(argv, sizeof(char *) * (argc + 1));
+ if (rv == NULL) {
+ return NULL;
+ }
+
+ rv[argc] = NULL;
+
+ len = end - start + 1;
+
+ d_ptr = (char *)malloc(len + 1 - quote_count * 2);
+ if (d_ptr == NULL) {
+ free(rv);
+ return NULL;
+ }
+
+ rv[argc - 1] = d_ptr;
+
+ for (i = 0; i < len; i++) {
+ c = buf[start + i];
+
+ if (!quote_char) {
+ /* We are not in a quote, copy everything but quote chars */
+ if (c == '"' || c == '\'') {
+ quote_char = c;
+ } else {
+ *d_ptr++ = c;
+ }
+ } else {
+ /* We are in a quote, copy everything but the current quote char */
+ if (c == quote_char) {
+ quote_char = 0;
+ } else {
+ *d_ptr++ = c;
+ }
+ }
+ }
+ *d_ptr = '\0';
+
+ return rv;
+}
+
+int str2args(const char *line, char comment_char, char ***argv)
+{
+ char **rv;
+ int argc;
+
+ unsigned i;
+ size_t len;
+
+ bool in_arg;
+ char c;
+ char quote_char;
+
+ int arg_start;
+ int quote_count;
+
+ rv = NULL;
+ argc = 0;
+
+ quote_char = 0;
+
+ arg_start = 0;
+ quote_count = 0;
+
+ len = strlen(line);
+
+ in_arg = false;
+
+ for (i = 0; i < len; i++) {
+ c = line[i];
+
+ if (in_arg) {
+ /* Found the end of a quote! */
+ if (quote_char) {
+ if (quote_char == c) {
+ quote_char = 0;
+ }
+ continue;
+ }
+
+ /* Found the beginning of a quote! */
+ if (c == '\'' || c == '"') {
+ quote_count++;
+ quote_char = c;
+ continue;
+ }
+
+ /* Found whitespace outside of quote */
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ in_arg = false;
+ argc++;
+ rv = add_arg(rv, argc, line, arg_start, i - 1, quote_count);
+ if (rv == NULL)
+ return -1;
+ }
+ } else {
+ if (c == comment_char) {
+ break;
+ }
+ /* Enter a new argument */
+ if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
+ /* If first argument is a tick it means we're in a quote */
+ if (c == '\'' || c == '"') {
+ quote_char = c;
+ } else {
+ quote_char = 0;
+ }
+ quote_count = 0;
+ arg_start = i;
+ in_arg = true;
+ }
+ /* else this is still whitespace */
+ }
+ }
+
+ /* reached the end of the line, check to see if current arg needs to
+ * be closed */
+ if (in_arg) {
+ if (quote_char) {
+ free_args(argc, rv);
+ return -2;
+ } else {
+ argc++;
+ rv = add_arg(rv, argc, line, arg_start, i - 1, quote_count);
+ if (rv == NULL) {
+ return -1;
+ }
+ }
+ }
+
+ *argv = rv;
+
+ return argc;
+}
+
+void free_args(int argc, char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++) {
+ free(argv[i]);
+ }
+ free(argv);
+}
+
+static struct config_options *add_opt(
+ struct config_options *optv, int optc, char *key, char *val, int lineno)
+{
+ struct config_options *rv;
+ char *ptr1, *ptr2;
+ rv = (struct config_options *)realloc(optv,
+ sizeof(struct config_options) * optc);
+ if (rv == NULL) {
+ return NULL;
+ }
+
+ ptr1 = (char *)malloc(strlen(key) + 1);
+ if (ptr1 == NULL) {
+ free(rv);
+ return NULL;
+ }
+ strcpy(ptr1, key);
+ rv[optc - 1].key = ptr1;
+
+ ptr2 = (char *)malloc(strlen(val) + 1);
+ if (ptr2 == NULL) {
+ free(ptr1);
+ free(rv);
+ return NULL;
+ }
+ strcpy(ptr2, val);
+ rv[optc - 1].value = ptr2;
+
+ rv[optc - 1].lineno = lineno;
+
+ return rv;
+}
+
+bool update_match(struct bladerf *dev, char *str)
+{
+ size_t len;
+ int status;
+ struct bladerf_devinfo info;
+ bladerf_fpga_size fpga_size;
+
+ status = bladerf_get_devinfo(dev, &info);
+ if (status < 0)
+ return false;
+
+ bladerf_get_fpga_size(dev, &fpga_size);
+ if (status < 0)
+ return false;
+
+ str++;
+ len = strlen(str);
+ if (str[len - 1] == ']')
+ str[len - 1] = '\0';
+
+ if (!strcmp(str, "x40")) {
+ return fpga_size == BLADERF_FPGA_40KLE;
+ } else if (!strcmp(str, "x115")) {
+ return fpga_size == BLADERF_FPGA_115KLE;
+ }
+
+ status = bladerf_devstr_matches(str, &info);
+
+ return status == 1;
+}
+
+int str2options(struct bladerf *dev,
+ const char *buf,
+ size_t buf_sz,
+ struct config_options **opts)
+{
+ char *line;
+ char *d_ptr;
+ int line_num;
+ char c;
+ unsigned i;
+
+ struct config_options *optv;
+ int optc;
+
+ char **line_argv;
+ int line_argc;
+
+ bool match;
+
+ match = true;
+
+ optv = NULL;
+ optc = 0;
+
+ line_num = 1;
+
+ line = malloc(buf_sz + 1);
+ if (!line)
+ return BLADERF_ERR_MEM;
+
+ d_ptr = line;
+
+ for (i = 0; i < buf_sz; i++) {
+ c = buf[i];
+ if (c == '\n') {
+ /* deal with the old line */
+ *d_ptr = 0;
+ line_argc = str2args(line, '#', &line_argv);
+ if (line_argc < 0)
+ goto out;
+
+ /* handle line */
+ if (line_argc > 3) {
+ log_error("Too many arguments in bladeRF.conf on line %d\n",
+ line_num);
+ goto out;
+ } else if (match && line_argc == 2) {
+ optc++;
+ optv =
+ add_opt(optv, optc, line_argv[0], line_argv[1], line_num);
+ if (!optv) {
+ optc = -1;
+ goto out;
+ }
+ } else if (line_argc == 1) {
+ if (*line_argv[0] != '[') {
+ log_error("Expecting scoping line (requires [ and ]) on "
+ "line %d\n",
+ line_num);
+ }
+ match = update_match(dev, line_argv[0]);
+ }
+
+ /* free line */
+ free_args(line_argc, line_argv);
+
+ /* setup to capture the next line */
+ line_num++;
+ d_ptr = line;
+ } else {
+ *d_ptr++ = c;
+ }
+ }
+
+ if (opts)
+ *opts = optv;
+
+out:
+ free(line);
+ return optc;
+}
+
+void free_opts(struct config_options *optv, int optc)
+{
+ int i;
+
+ for (i = 0; i < optc; i++) {
+ free(optv[i].key);
+ free(optv[i].value);
+ }
+ free(optv);
+}
+
+int csv2int(const char *line, int ***args)
+{
+ const char delim[] = " \r\n\t,.:"; /* supported delimiters */
+ const size_t MAXLEN = 128; /* max line length (with newline and null) */
+ static size_t arglen = 2; /* tunable: initial expected column count */
+ char *myline = NULL; /* local copy of 'line' */
+ char *parsestr = NULL; /* ptr to 'myline' on first strtok_r */
+ char *saveptr = NULL; /* strtok_r state pointer */
+ int **argout = NULL; /* array of output values */
+ size_t count = 0; /* count of tokens extracted */
+ size_t i;
+
+ // Validity check
+ if (NULL == line) {
+ log_debug("line is null\n");
+ return 0;
+ }
+
+ if (NULL == args) {
+ log_error("args is null\n");
+ goto fail;
+ }
+
+ // strtok_r doesn't respect const, so make a copy of 'line'
+ myline = calloc(MAXLEN, 1);
+ if (NULL == myline) {
+ log_error("could not calloc myline\n");
+ goto fail;
+ }
+
+ myline = strncpy(myline, line, MAXLEN - 1);
+
+ // Initial allocation of argout
+ argout = malloc(arglen * sizeof(int *));
+ if (NULL == argout) {
+ log_error("could not malloc argout\n");
+ goto fail;
+ }
+
+ // Loop over input until strtok_r returns a NULL
+ for (i = 0, parsestr = myline; true; ++i, parsestr = NULL) {
+ char *token = NULL; /* return token from strtok_r */
+ bool ok;
+
+ token = strtok_r(parsestr, delim, &saveptr);
+ if (NULL == token) {
+ break;
+ }
+
+ // Expand argout if necessary
+ if (i >= arglen) {
+ arglen *= 2;
+ log_verbose("expanding allocation to %zu column(s)\n", arglen);
+ int **newargout = realloc(argout, arglen * sizeof(int *));
+ if (NULL == newargout) {
+ log_error("could not realloc(argout,%zu)\n", arglen);
+ goto fail;
+ }
+ argout = newargout;
+ }
+
+ // Allocate memory for this value
+ argout[i] = malloc(sizeof(int));
+ if (NULL == argout[i]) {
+ log_error("could not malloc argout[%zu]\n", i);
+ goto fail;
+ }
+
+ // Update the count now, in case str2int fails and we need to dealloc
+ ++count;
+
+ // Parse token into an integer value
+ *argout[i] = str2int(token, INT32_MIN, INT32_MAX, &ok);
+ if (!ok) {
+ log_error("str2int failed on '%s'\n", token);
+ goto fail;
+ }
+ }
+
+ // Success!
+ *args = argout;
+ free(myline);
+
+ // If arglen is too big, cut it in half next time...
+ if (count <= (arglen / 2)) {
+ arglen /= 2;
+ log_verbose("decreasing future arglen to %zu\n", arglen);
+ }
+
+ return (int)count;
+
+fail:
+ // Deallocate everything...
+ free(myline);
+ free_csv2int((int)count, argout);
+ return -1;
+}
+
+void free_csv2int(int argc, int **args)
+{
+ int i;
+
+ if (NULL == args) {
+ return;
+ }
+
+ for (i = 0; i < argc; ++i) {
+ free(args[i]);
+ }
+
+ free(args);
+}