toybox/lib/commas.c
<<
>>
Prefs
   1/* commas.c - Deal with comma separated lists
   2 *
   3 * Copyright 2018 Rob Landley <rob@landley.net>
   4 */
   5
   6#include "toys.h"
   7
   8// Traverse arg_list of csv, calling callback on each value
   9void 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
  29void 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
  48char *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.
  64int 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
  86int 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
 101// Returns true and removes `opt` from `optlist` if present, false otherwise.
 102// Doesn't have the magic "no" behavior of comma_scan.
 103int comma_remove(char *optlist, char *opt)
 104{
 105  int optlen = strlen(opt), len, got = 0;
 106
 107  if (optlist) for (;;) {
 108    char *s = comma_iterate(&optlist, &len);
 109
 110    if (!s) break;
 111    if (optlen == len && !strncmp(opt, s, optlen)) {
 112      got = 1;
 113      if (optlist) memmove(s, optlist, strlen(optlist)+1);
 114      else *s = 0;
 115    }
 116  }
 117
 118  return got;
 119}
 120