diff options
Diffstat (limited to 'apps/plugins/lib/arg_helper.c')
-rw-r--r-- | apps/plugins/lib/arg_helper.c | 287 |
1 files changed, 287 insertions, 0 deletions
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 @@ | |||
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 | |||
32 | int string_parse(const char **parameter, char* buf, size_t buf_sz) | ||
33 | { | ||
34 | /* fills buf with a string upto buf_sz, null terminates the buffer | ||
35 | * strings break on WS by default but can be enclosed in single or double quotes | ||
36 | * opening and closing quotes will not be included in the buffer but will be counted | ||
37 | * use alternating quotes if you really want them included '"text"' or "'text'" | ||
38 | * failure to close the string will result in eating all remaining args till \0 | ||
39 | * If buffer full remaining chars are discarded till stopchar or \0 is reached */ | ||
40 | |||
41 | char stopchar = ' '; | ||
42 | char stopchars[] = "\'\""; | ||
43 | int skipped = 0; | ||
44 | int found = 0; | ||
45 | const char* start = *parameter; | ||
46 | |||
47 | if (strchr(stopchars, *start)) | ||
48 | { | ||
49 | logf("stop char %c\n", *start); | ||
50 | stopchar = *start; | ||
51 | skipped++; | ||
52 | start++; | ||
53 | } | ||
54 | while (*start && *start != stopchar) | ||
55 | { | ||
56 | if (buf_sz > 1) | ||
57 | { | ||
58 | *buf++ = *start; | ||
59 | buf_sz--; | ||
60 | } | ||
61 | found++; | ||
62 | start++; | ||
63 | } | ||
64 | if (*start == stopchar && skipped) | ||
65 | { | ||
66 | start++; | ||
67 | skipped++; | ||
68 | } | ||
69 | |||
70 | *buf = '\0'; | ||
71 | |||
72 | if (found > 0) | ||
73 | *parameter = start; | ||
74 | else | ||
75 | skipped = 0; | ||
76 | |||
77 | return found + skipped; | ||
78 | } | ||
79 | |||
80 | int char_parse(const char **parameter, char* character) | ||
81 | { | ||
82 | /* passes *character a single character eats remaining non-WS characters */ | ||
83 | char buf[2]; | ||
84 | int ret = string_parse(parameter, buf, sizeof(buf)); | ||
85 | if (ret && character) | ||
86 | *character = buf[0]; | ||
87 | return ret; | ||
88 | |||
89 | } | ||
90 | |||
91 | |||
92 | int bool_parse(const char **parameter, bool *choice) | ||
93 | { | ||
94 | /* determine true false using the first character the rest are skipped/ignored */ | ||
95 | int found = 0; | ||
96 | const char tf_val[]="fn0ty1";/* false chars on left f/t should be balanced fffttt */ | ||
97 | const char* start = *parameter; | ||
98 | |||
99 | |||
100 | char c = tolower(*start); | ||
101 | const char *tfval = strchr(tf_val, c); | ||
102 | while(isalnum(*++start)) {;} | ||
103 | |||
104 | if (tfval) | ||
105 | { | ||
106 | found = start - (*parameter); | ||
107 | *parameter = start; | ||
108 | } | ||
109 | |||
110 | if (choice) | ||
111 | *choice = (tfval - tf_val) > (signed int) (sizeof(tf_val) / 2) - 1; | ||
112 | |||
113 | return found; | ||
114 | } | ||
115 | |||
116 | |||
117 | int longnum_parse(const char **parameter, long *number, long *decimal) | ||
118 | { | ||
119 | /* passes number and or decimal portion of number base 10 only.. */ | ||
120 | long num = 0; | ||
121 | long dec = 0; | ||
122 | int found = 0; | ||
123 | int neg = 0; | ||
124 | logf ("n: %s\n", *parameter); | ||
125 | const char *start = *parameter; | ||
126 | |||
127 | if (*start == '-') | ||
128 | { | ||
129 | neg = 1; | ||
130 | start++; | ||
131 | } | ||
132 | while (isdigit(*start)) | ||
133 | { | ||
134 | found++; | ||
135 | num = num *10 + *start - '0'; | ||
136 | start++; | ||
137 | } | ||
138 | |||
139 | if (*start == DECSEPCHAR) | ||
140 | { | ||
141 | start++; | ||
142 | while (isdigit(*start)) | ||
143 | { | ||
144 | dec = dec *10 + *start - '0'; | ||
145 | start++; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (found > 0) | ||
150 | { | ||
151 | found = start - (*parameter); | ||
152 | *parameter = start; | ||
153 | } | ||
154 | |||
155 | if(number) | ||
156 | *number = neg ? -num : num; | ||
157 | |||
158 | if (decimal) | ||
159 | *decimal = dec; | ||
160 | |||
161 | return found; | ||
162 | } | ||
163 | |||
164 | int num_parse(const char **parameter, int *number, int *decimal) | ||
165 | { | ||
166 | long num, dec; | ||
167 | int ret = longnum_parse(parameter, &num, &dec); | ||
168 | |||
169 | if(number) | ||
170 | *number = num; | ||
171 | |||
172 | if (decimal) | ||
173 | *decimal = dec; | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | *argparse(const char *parameter, int parameter_len, | ||
180 | * int (*arg_callback)(char argchar, const char **parameter)) | ||
181 | * parameter : constant char string of arguments | ||
182 | * parameter_len : may be set to -1 if your parameter string is NULL (\0) terminated | ||
183 | * arg_callback : function gets called for each SWCHAR found in the parameter string | ||
184 | * Note: WS at beginning is stripped, **parameter starts at the first NON WS char | ||
185 | * return 0 for arg_callback to quit parsing immediately | ||
186 | */ | ||
187 | void argparse(const char *parameter, int parameter_len, int (*arg_callback)(char argchar, const char **parameter)) | ||
188 | { | ||
189 | bool lastchr; | ||
190 | char argchar; | ||
191 | const char *start = parameter; | ||
192 | while (parameter_len < 0 || (parameter - start) < parameter_len) | ||
193 | { | ||
194 | switch (*parameter++) | ||
195 | { | ||
196 | case SWCHAR: | ||
197 | { | ||
198 | if ((*parameter) == '\0') | ||
199 | return; | ||
200 | logf ("%s\n",parameter); | ||
201 | argchar = *parameter; | ||
202 | lastchr = (*(parameter + 1) == '\0'); | ||
203 | while (*++parameter || lastchr) | ||
204 | { | ||
205 | lastchr = false; | ||
206 | if (isspace(*parameter)) | ||
207 | continue; /* eat spaces at beginning */ | ||
208 | if (!arg_callback(argchar, ¶meter)) | ||
209 | return; | ||
210 | break; | ||
211 | } | ||
212 | break; | ||
213 | } | ||
214 | case '\0': | ||
215 | { | ||
216 | if (parameter_len <= 0) | ||
217 | return; | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* EXAMPLE USAGE | ||
224 | 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); | ||
225 | |||
226 | int arg_callback(char argchar, const char **parameter) | ||
227 | { | ||
228 | int ret; | ||
229 | int num, dec; | ||
230 | char c; | ||
231 | char buf[32]; | ||
232 | bool bret; | ||
233 | logf ("Arg: %c\n", argchar); | ||
234 | switch (tolower(argchar)) | ||
235 | { | ||
236 | case 'k' : | ||
237 | logf("Option K!"); | ||
238 | break; | ||
239 | case 'c' : | ||
240 | ret = char_parse(parameter, &c); | ||
241 | if (ret) | ||
242 | { | ||
243 | logf ("Val: %c\n", c); | ||
244 | logf("ate %d chars\n", ret); | ||
245 | } | ||
246 | break; | ||
247 | |||
248 | case 'n' : | ||
249 | ret = num_parse(parameter, &num, &dec); | ||
250 | if (ret) | ||
251 | { | ||
252 | logf ("Val: %d.%d\n", num, dec); | ||
253 | logf("ate %d chars\n", ret); | ||
254 | } | ||
255 | break; | ||
256 | case 's' : | ||
257 | ret = string_parse(parameter, buf, sizeof(buf)); | ||
258 | if (ret) | ||
259 | { | ||
260 | logf ("Val: %s\n", buf); | ||
261 | logf("ate %d chars\n", ret); | ||
262 | } | ||
263 | break; | ||
264 | case 'p' : | ||
265 | ret = string_parse(parameter, buf, sizeof(buf)); | ||
266 | if (ret) | ||
267 | { | ||
268 | logf ("Path: %s\n", buf); | ||
269 | logf("ate %d chars\n", ret); | ||
270 | } | ||
271 | break; | ||
272 | case 'b' : | ||
273 | ret = bool_parse(parameter, &bret); | ||
274 | if (ret) | ||
275 | { | ||
276 | logf ("Val: %s\n", bret ? "true" : "false"); | ||
277 | logf("ate %d chars\n", ret); | ||
278 | } | ||
279 | break; | ||
280 | default : | ||
281 | logf ("Unknown switch '%c'\n",argchar); | ||
282 | //return 0; | ||
283 | } | ||
284 | return 1; | ||
285 | } | ||
286 | */ | ||
287 | |||