Home | History | Annotate | Download | only in lib
      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