1 /* commas.c - Deal with comma separated lists 2 * 3 * Copyright 2018 Rob Landley <rob (at) landley.net> 4 */ 5 6 #include "toys.h" 7 8 // Traverse arg_list of csv, calling callback on each value 9 void comma_args(struct arg_list *al, void *data, char *err, 10 char *(*callback)(void *data, char *str, int len)) 11 { 12 char *next, *arg; 13 int len; 14 15 if (CFG_TOYBOX_DEBUG && !err) err = "INTERNAL"; 16 17 while (al) { 18 arg = al->arg; 19 while ((next = comma_iterate(&arg, &len))) 20 if ((next = callback(data, next, len))) 21 error_exit("%s '%s'\n%*c", err, al->arg, 22 (int)(5+strlen(toys.which->name)+strlen(err)+next-al->arg), '^'); 23 al = al->next; 24 } 25 } 26 27 // Realloc *old with oldstring,newstring 28 29 void comma_collate(char **old, char *new) 30 { 31 char *temp, *atold = *old; 32 33 // Only add a comma if old string didn't end with one 34 if (atold && *atold) { 35 char *comma = ","; 36 37 if (atold[strlen(atold)-1] == ',') comma = ""; 38 temp = xmprintf("%s%s%s", atold, comma, new); 39 } else temp = xstrdup(new); 40 free (atold); 41 *old = temp; 42 } 43 44 // iterate through strings in a comma separated list. 45 // returns start of next entry or NULL if none 46 // sets *len to length of entry (not including comma) 47 // advances *list to start of next entry 48 char *comma_iterate(char **list, int *len) 49 { 50 char *start = *list, *end; 51 52 if (!*list || !**list) return 0; 53 54 if (!(end = strchr(*list, ','))) { 55 *len = strlen(*list); 56 *list = 0; 57 } else *list += (*len = end-start)+1; 58 59 return start; 60 } 61 62 // check all instances of opt and "no"opt in optlist, return true if opt 63 // found and last instance wasn't no. If clean, remove each instance from list. 64 int comma_scan(char *optlist, char *opt, int clean) 65 { 66 int optlen = strlen(opt), len, no, got = 0; 67 68 if (optlist) for (;;) { 69 char *s = comma_iterate(&optlist, &len); 70 71 if (!s) break; 72 no = 2*(*s == 'n' && s[1] == 'o'); 73 if (optlen == len-no && !strncmp(opt, s+no, optlen)) { 74 got = !no; 75 if (clean) { 76 if (optlist) memmove(s, optlist, strlen(optlist)+1); 77 else *s = 0; 78 } 79 } 80 } 81 82 return got; 83 } 84 85 // return true if all scanlist options enabled in optlist 86 int comma_scanall(char *optlist, char *scanlist) 87 { 88 int i = 1; 89 90 while (scanlist && *scanlist) { 91 char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i); 92 93 i = comma_scan(optlist, s, 0); 94 free(s); 95 if (!i) break; 96 } 97 98 return i; 99 } 100