A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 325 lines 8.7 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2021 William Wilgus 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "plugin.h" 23#include "arg_helper.h" 24 25#ifndef logf 26#define logf(...) {} 27#endif 28 29#define SWCHAR '-' 30#define DECSEPCHAR '.' 31#ifdef PLUGIN 32 #define strchr rb->strchr 33#endif 34int string_parse(const char **parameter, char *buf, size_t buf_sz) 35{ 36/* fills buf with a string upto buf_sz, null terminates the buffer 37 * strings break on WS by default but can be enclosed in single or double quotes 38 * opening and closing quotes will not be included in the buffer but will be counted 39 * use alternating quotes if you really want them included '"text"' or "'text'" 40 * failure to close the string will result in eating all remaining args till \0 41 * If buffer full remaining chars are discarded till stopchar or \0 is reached */ 42 43 char stopchar = ' '; 44 char stopchars[] = "\'\""; 45 int skipped = 0; 46 int found = 0; 47 if (!parameter || !*parameter) 48 { 49 *buf = '\0'; 50 return 0; 51 } 52 const char* start = *parameter; 53 54 if (strchr(stopchars, *start)) 55 { 56 logf("stop char %c\n", *start); 57 stopchar = *start; 58 skipped++; 59 start++; 60 } 61 while (*start && *start != stopchar) 62 { 63 if (buf_sz > 1) 64 { 65 *buf++ = *start; 66 buf_sz--; 67 } 68 found++; 69 start++; 70 } 71 if (*start == stopchar && skipped) 72 { 73 start++; 74 skipped++; 75 } 76 77 *buf = '\0'; 78 79 if (found > 0) 80 *parameter = start; 81 else 82 skipped = 0; 83 84 return found + skipped; 85} 86 87int char_parse(const char **parameter, char *character) 88{ 89/* passes *character a single character eats remaining non-WS characters */ 90 char buf[2]; 91 int ret = string_parse(parameter, buf, sizeof(buf)); 92 if (ret && character) 93 *character = buf[0]; 94 return ret; 95 96} 97 98int bool_parse(const char **parameter, bool *choice) 99{ 100/* determine true false using the first character the rest are skipped/ignored */ 101 int found = 0; 102 const char tf_val[]="fn0ty1";/* false chars on left f/t should be balanced fffttt */ 103 if (!parameter || !*parameter) 104 return 0; 105 const char* start = *parameter; 106 107 108 char c = tolower(*start); 109 const char *tfval = strchr(tf_val, c); 110 while(isalnum(*++start)) {;} 111 112 if (tfval) 113 { 114 found = start - (*parameter); 115 *parameter = start; 116 } 117 118 if (choice) 119 *choice = (tfval - tf_val) > (signed int) (sizeof(tf_val) / 2) - 1; 120 121 return found; 122} 123 124int longnum_parse(const char **parameter, long *number, long *decimal) 125{ 126/* passes number and or decimal portion of number base 10 only.. 127 fractional portion is scaled by ARGPARSE_FRAC_DEC_MULTIPLIER 128 Example (if ARGPARSE_FRAC_DEC_MULTIPLIER = 10 000) 129 meaning .0009 returns 9 , 9 / 10000 = .0009 130 .009 returns 90 131 .099 returns 990 132 .09 returns 900 133 .9 returns 9000 134 .9999 returns 9999 135*/ 136 137 long num = 0; 138 long dec = 0; 139 int found = 0; 140 int neg = 0; 141 int digits = 0; 142 //logf ("n: %s\n", *parameter); 143 if (!parameter || !*parameter) 144 return 0; 145 const char* start = *parameter; 146 147 if (*start == '-') 148 { 149 neg = 1; 150 start++; 151 } 152 while (isdigit(*start)) 153 { 154 found++; 155 num = num *10 + *start - '0'; 156 start++; 157 } 158 159 if (*start == DECSEPCHAR) 160 { 161 start++; 162 while(*start == '0') 163 { 164 digits++; 165 start++; 166 } 167 while (isdigit(*start)) 168 { 169 dec = dec *10 + *start - '0'; 170 digits++; 171 start++; 172 } 173 if (decimal && digits <= ARGPARSE_MAX_FRAC_DIGITS) 174 { 175 if(digits < ARGPARSE_MAX_FRAC_DIGITS) 176 { 177 digits = ARGPARSE_MAX_FRAC_DIGITS - digits; 178 while (digits--) 179 dec *= 10; 180 } 181 } 182 else 183 dec = -1; /* error */ 184 } 185 186 if (found > 0) 187 { 188 found = start - (*parameter); 189 *parameter = start; 190 } 191 192 if(number) 193 *number = neg ? -num : num; 194 195 if (decimal) 196 *decimal = dec; 197 198 return found; 199} 200 201int num_parse(const char **parameter, int *number, int *decimal) 202{ 203 long num, dec; 204 int ret = longnum_parse(parameter, &num, &dec); 205 if(number) 206 *number = num; 207 if (decimal) 208 *decimal = dec; 209 return ret; 210} 211 212/* 213*argparse(const char *parameter, int parameter_len, 214* int (*arg_callback)(char argchar, const char **parameter)) 215* parameter : constant char string of arguments 216* parameter_len : may be set to -1 if your parameter string is NULL (\0) terminated 217* arg_callback : function gets called for each SWCHAR found in the parameter string 218* Note: WS at beginning is stripped, **parameter starts at the first NON WS char 219* return 0 for arg_callback to quit parsing immediately 220*/ 221void argparse(const char *parameter, int parameter_len, void *userdata, 222 int (*arg_callback)(char argchar, const char **parameter, void *userdata)) 223{ 224 bool lastchr; 225 char argchar; 226 const char *start = parameter; 227 while (parameter_len < 0 || (parameter - start) < parameter_len) 228 { 229 switch (*parameter++) 230 { 231 case SWCHAR: 232 { 233 if ((*parameter) == '\0') 234 return; 235 236 if (parameter_len < 0) { logf ("%s\n", parameter); } 237 else { logf ("%.*s\n", plen, parameter); } 238 239 argchar = *parameter; 240 lastchr = (*(parameter + 1) == '\0'); 241 while (*++parameter || lastchr) 242 { 243 lastchr = false; 244 if (isspace(*parameter)) 245 continue; /* eat spaces at beginning */ 246 if (!arg_callback(argchar, &parameter, userdata)) 247 return; 248 break; 249 } 250 break; 251 } 252 case '\0': 253 { 254 if (parameter_len <= 0) 255 return; 256 } 257 } 258 } 259} 260 261/* EXAMPLE USAGE 262argparse("-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); 263 264int arg_callback(char argchar, const char **parameter) 265{ 266 int ret; 267 int num, dec; 268 char c; 269 char buf[32]; 270 bool bret; 271 logf ("Arg: %c\n", argchar); 272 switch (tolower(argchar)) 273 { 274 case 'k' : 275 logf("Option K!"); 276 break; 277 case 'c' : 278 ret = char_parse(parameter, &c); 279 if (ret) 280 { 281 logf ("Val: %c\n", c); 282 logf("ate %d chars\n", ret); 283 } 284 break; 285 286 case 'n' : 287 ret = num_parse(parameter, &num, &dec); 288 if (ret) 289 { 290 logf ("Val: %d.%d\n", num, dec); 291 logf("ate %d chars\n", ret); 292 } 293 break; 294 case 's' : 295 ret = string_parse(parameter, buf, sizeof(buf)); 296 if (ret) 297 { 298 logf ("Val: %s\n", buf); 299 logf("ate %d chars\n", ret); 300 } 301 break; 302 case 'p' : 303 ret = string_parse(parameter, buf, sizeof(buf)); 304 if (ret) 305 { 306 logf ("Path: %s\n", buf); 307 logf("ate %d chars\n", ret); 308 } 309 break; 310 case 'b' : 311 ret = bool_parse(parameter, &bret); 312 if (ret) 313 { 314 logf ("Val: %s\n", bret ? "true" : "false"); 315 logf("ate %d chars\n", ret); 316 } 317 break; 318 default : 319 logf ("Unknown switch '%c'\n",argchar); 320 //return 0; 321 } 322 return 1; 323} 324*/ 325