From 965572705beb4a0789970a44e11fce94654ad4b9 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Tue, 24 Aug 2021 07:50:32 -0400 Subject: [PATCH] plugin lib/arg_helper parse 'command line' args add a helper function to allow plugins to parse the parameter string passed into plugins support included for bool, char, string and numbers+decimals Change-Id: I39f35c8bd3c21b83097a538c19f46d362c468fa4 --- apps/plugins/lib/SOURCES | 1 + apps/plugins/lib/arg_helper.c | 287 ++++++++++++++++++++++++++++++++++ apps/plugins/lib/arg_helper.h | 53 +++++++ 3 files changed, 341 insertions(+) create mode 100644 apps/plugins/lib/arg_helper.c create mode 100644 apps/plugins/lib/arg_helper.h diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES index 6d5fe6cb5f..bdea07315e 100644 --- a/apps/plugins/lib/SOURCES +++ b/apps/plugins/lib/SOURCES @@ -3,6 +3,7 @@ gcc-support.c pluginlib_actions.c helper.c icon_helper.c +arg_helper.c md5.c jhash.c configfile.c diff --git a/apps/plugins/lib/arg_helper.c b/apps/plugins/lib/arg_helper.c new file mode 100644 index 0000000000..dcf3e31834 --- /dev/null +++ b/apps/plugins/lib/arg_helper.c @@ -0,0 +1,287 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 William Wilgus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "arg_helper.h" + +#ifndef logf +#define logf(...) {} +#endif + +#define SWCHAR '-' +#define DECSEPCHAR '.' + +int string_parse(const char **parameter, char* buf, size_t buf_sz) +{ +/* fills buf with a string upto buf_sz, null terminates the buffer + * strings break on WS by default but can be enclosed in single or double quotes + * opening and closing quotes will not be included in the buffer but will be counted + * use alternating quotes if you really want them included '"text"' or "'text'" + * failure to close the string will result in eating all remaining args till \0 + * If buffer full remaining chars are discarded till stopchar or \0 is reached */ + + char stopchar = ' '; + char stopchars[] = "\'\""; + int skipped = 0; + int found = 0; + const char* start = *parameter; + + if (strchr(stopchars, *start)) + { + logf("stop char %c\n", *start); + stopchar = *start; + skipped++; + start++; + } + while (*start && *start != stopchar) + { + if (buf_sz > 1) + { + *buf++ = *start; + buf_sz--; + } + found++; + start++; + } + if (*start == stopchar && skipped) + { + start++; + skipped++; + } + + *buf = '\0'; + + if (found > 0) + *parameter = start; + else + skipped = 0; + + return found + skipped; +} + +int char_parse(const char **parameter, char* character) +{ +/* passes *character a single character eats remaining non-WS characters */ + char buf[2]; + int ret = string_parse(parameter, buf, sizeof(buf)); + if (ret && character) + *character = buf[0]; + return ret; + +} + + +int bool_parse(const char **parameter, bool *choice) +{ +/* determine true false using the first character the rest are skipped/ignored */ + int found = 0; + const char tf_val[]="fn0ty1";/* false chars on left f/t should be balanced fffttt */ + const char* start = *parameter; + + + char c = tolower(*start); + const char *tfval = strchr(tf_val, c); + while(isalnum(*++start)) {;} + + if (tfval) + { + found = start - (*parameter); + *parameter = start; + } + + if (choice) + *choice = (tfval - tf_val) > (signed int) (sizeof(tf_val) / 2) - 1; + + return found; +} + + +int longnum_parse(const char **parameter, long *number, long *decimal) +{ +/* passes number and or decimal portion of number base 10 only.. */ + long num = 0; + long dec = 0; + int found = 0; + int neg = 0; + logf ("n: %s\n", *parameter); + const char *start = *parameter; + + if (*start == '-') + { + neg = 1; + start++; + } + while (isdigit(*start)) + { + found++; + num = num *10 + *start - '0'; + start++; + } + + if (*start == DECSEPCHAR) + { + start++; + while (isdigit(*start)) + { + dec = dec *10 + *start - '0'; + start++; + } + } + + if (found > 0) + { + found = start - (*parameter); + *parameter = start; + } + + if(number) + *number = neg ? -num : num; + + if (decimal) + *decimal = dec; + + return found; +} + +int num_parse(const char **parameter, int *number, int *decimal) +{ + long num, dec; + int ret = longnum_parse(parameter, &num, &dec); + + if(number) + *number = num; + + if (decimal) + *decimal = dec; + + return ret; +} + +/* +*argparse(const char *parameter, int parameter_len, +* int (*arg_callback)(char argchar, const char **parameter)) +* parameter : constant char string of arguments +* parameter_len : may be set to -1 if your parameter string is NULL (\0) terminated +* arg_callback : function gets called for each SWCHAR found in the parameter string +* Note: WS at beginning is stripped, **parameter starts at the first NON WS char +* return 0 for arg_callback to quit parsing immediately +*/ +void argparse(const char *parameter, int parameter_len, int (*arg_callback)(char argchar, const char **parameter)) +{ + bool lastchr; + char argchar; + const char *start = parameter; + while (parameter_len < 0 || (parameter - start) < parameter_len) + { + switch (*parameter++) + { + case SWCHAR: + { + if ((*parameter) == '\0') + return; + logf ("%s\n",parameter); + argchar = *parameter; + lastchr = (*(parameter + 1) == '\0'); + while (*++parameter || lastchr) + { + lastchr = false; + if (isspace(*parameter)) + continue; /* eat spaces at beginning */ + if (!arg_callback(argchar, ¶meter)) + return; + break; + } + break; + } + case '\0': + { + if (parameter_len <= 0) + return; + } + } + } +} + +/* EXAMPLE USAGE +argparse("-n 42 -N 9.9 -n -78.9009 -f -P /rockbox/path/f -s 'Yestest' -B false -B 0 -B true -b n -by -b 1-c ops -c s -k", -1, &arg_callback); + +int arg_callback(char argchar, const char **parameter) +{ + int ret; + int num, dec; + char c; + char buf[32]; + bool bret; + logf ("Arg: %c\n", argchar); + switch (tolower(argchar)) + { + case 'k' : + logf("Option K!"); + break; + case 'c' : + ret = char_parse(parameter, &c); + if (ret) + { + logf ("Val: %c\n", c); + logf("ate %d chars\n", ret); + } + break; + + case 'n' : + ret = num_parse(parameter, &num, &dec); + if (ret) + { + logf ("Val: %d.%d\n", num, dec); + logf("ate %d chars\n", ret); + } + break; + case 's' : + ret = string_parse(parameter, buf, sizeof(buf)); + if (ret) + { + logf ("Val: %s\n", buf); + logf("ate %d chars\n", ret); + } + break; + case 'p' : + ret = string_parse(parameter, buf, sizeof(buf)); + if (ret) + { + logf ("Path: %s\n", buf); + logf("ate %d chars\n", ret); + } + break; + case 'b' : + ret = bool_parse(parameter, &bret); + if (ret) + { + logf ("Val: %s\n", bret ? "true" : "false"); + logf("ate %d chars\n", ret); + } + break; + default : + logf ("Unknown switch '%c'\n",argchar); + //return 0; + } + return 1; +} +*/ + diff --git a/apps/plugins/lib/arg_helper.h b/apps/plugins/lib/arg_helper.h new file mode 100644 index 0000000000..7c770e0162 --- /dev/null +++ b/apps/plugins/lib/arg_helper.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 William Wilgus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _LIB_ARG_HELPER_H_ +#define _LIB_ARG_HELPER_H_ + +#include "plugin.h" + +/* fills buf with a string upto buf_sz, null terminates the buffer + * strings break on WS by default but can be enclosed in single or double quotes + * opening and closing quotes will not be included in the buffer but will be counted + * use alternating quotes if you really want them included '"text"' or "'text'" + * failure to close the string will result in eating all remaining args till \0 + * If buffer full remaining chars are discarded till stopchar or \0 is reached */ +int string_parse(const char **parameter, char* buf, size_t buf_sz); +/* passes *character a single character eats remaining non-WS characters */ +int char_parse(const char **parameter, char* character); +/* determine true false using the first character the rest are skipped/ignored */ +int bool_parse(const char **parameter, bool *choice); +/* passes number and or decimal portion of number base 10 only.. */ +int longnum_parse(const char **parameter, long *number, long *decimal); +int num_parse(const char **parameter, int *number, int *decimal); + +/* +*argparse(const char *parameter, int parameter_len, +* int (*arg_callback)(char argchar, const char **parameter)) +* parameter : constant char string of arguments +* parameter_len : may be set to -1 if your parameter string is NULL (\0) terminated +* arg_callback : function gets called for each SWCHAR found in the parameter string +* Note: WS at beginning is stripped, **parameter starts at the first NON WS char +* return 0 for arg_callback to quit parsing immediately +*/ +void argparse(const char *parameter, int parameter_len, + int (*arg_callback)(char argchar, const char **parameter)); + +#endif /* _LIB_ARG_HELPER_H_ */