xref: /aosp_15_r20/external/toybox/lib/commas.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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