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