[BACK]Return to options.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Diff for /src/usr.bin/tmux/options.c between version 1.25 and 1.26

version 1.25, 2017/01/15 20:14:36 version 1.26, 2017/01/15 20:48:41
Line 18 
Line 18 
   
 #include <sys/types.h>  #include <sys/types.h>
   
   #include <ctype.h>
 #include <stdarg.h>  #include <stdarg.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
Line 29 
Line 30 
  * a red-black tree.   * a red-black tree.
  */   */
   
   struct option {
           struct options                           *owner;
   
           const char                               *name;
           const struct options_table_entry         *tableentry;
   
           union {
                   char                             *string;
                   long long                         number;
                   struct grid_cell                  style;
                   struct {
                           const char              **array;
                           u_int                     arraysize;
                   };
           };
   
           RB_ENTRY(option)                          entry;
   };
   
 struct options {  struct options {
         RB_HEAD(options_tree, options_entry) tree;          RB_HEAD(options_tree, option)            tree;
         struct options  *parent;          struct options                          *parent;
 };  };
   
 static int      options_cmp(struct options_entry *, struct options_entry *);  static struct option    *options_add(struct options *, const char *);
 RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp);  
   
   #define OPTIONS_ARRAY_LIMIT 1000
   
   #define OPTIONS_IS_STRING(o)                                            \
           ((o)->tableentry == NULL ||                                     \
               (o)->tableentry->type == OPTIONS_TABLE_STRING)
   #define OPTIONS_IS_NUMBER(o) \
           ((o)->tableentry != NULL &&                                     \
               ((o)->tableentry->type == OPTIONS_TABLE_NUMBER ||           \
               (o)->tableentry->type == OPTIONS_TABLE_KEY ||               \
               (o)->tableentry->type == OPTIONS_TABLE_COLOUR ||            \
               (o)->tableentry->type == OPTIONS_TABLE_ATTRIBUTES ||        \
               (o)->tableentry->type == OPTIONS_TABLE_FLAG ||              \
               (o)->tableentry->type == OPTIONS_TABLE_CHOICE))
   #define OPTIONS_IS_STYLE(o) \
           ((o)->tableentry != NULL &&                                     \
               (o)->tableentry->type == OPTIONS_TABLE_STYLE)
   #define OPTIONS_IS_ARRAY(o) \
           ((o)->tableentry != NULL &&                                     \
               (o)->tableentry->type == OPTIONS_TABLE_ARRAY)
   
   static int      options_cmp(struct option *, struct option *);
   RB_GENERATE_STATIC(options_tree, option, entry, options_cmp);
   
 static int  static int
 options_cmp(struct options_entry *o1, struct options_entry *o2)  options_cmp(struct option *lhs, struct option *rhs)
 {  {
         return (strcmp(o1->name, o2->name));          return (strcmp(lhs->name, rhs->name));
 }  }
   
   static const struct options_table_entry *
   options_parent_table_entry(struct options *oo, const char *s)
   {
           struct option   *o;
   
           if (oo->parent == NULL)
                   fatalx("no parent options for %s", s);
           o = options_get_only(oo->parent, s);
           if (o == NULL)
                   fatalx("%s not in parent options", s);
           return (o->tableentry);
   }
   
 struct options *  struct options *
 options_create(struct options *parent)  options_create(struct options *parent)
 {  {
Line 54 
Line 109 
         return (oo);          return (oo);
 }  }
   
 static void  
 options_free1(struct options *oo, struct options_entry *o)  
 {  
         RB_REMOVE(options_tree, &oo->tree, o);  
         free((char *)o->name);  
         if (o->type == OPTIONS_STRING)  
                 free(o->str);  
         free(o);  
 }  
   
 static struct options_entry *  
 options_new(struct options *oo, const char *name)  
 {  
         struct options_entry    *o;  
   
         if ((o = options_find1(oo, name)) == NULL) {  
                 o = xmalloc(sizeof *o);  
                 o->name = xstrdup(name);  
                 RB_INSERT(options_tree, &oo->tree, o);  
                 memcpy(&o->style, &grid_default_cell, sizeof o->style);  
         } else if (o->type == OPTIONS_STRING)  
                 free(o->str);  
         return (o);  
 }  
   
 void  void
 options_free(struct options *oo)  options_free(struct options *oo)
 {  {
         struct options_entry    *o, *o1;          struct option   *o, *tmp;
   
         RB_FOREACH_SAFE (o, options_tree, &oo->tree, o1)          RB_FOREACH_SAFE (o, options_tree, &oo->tree, tmp)
                 options_free1(oo, o);                  options_remove(o);
         free(oo);          free(oo);
 }  }
   
 struct options_entry *  struct option *
 options_first(struct options *oo)  options_first(struct options *oo)
 {  {
         return (RB_MIN(options_tree, &oo->tree));          return (RB_MIN(options_tree, &oo->tree));
 }  }
   
 struct options_entry *  struct option *
 options_next(struct options_entry *o)  options_next(struct option *o)
 {  {
         return (RB_NEXT(options_tree, &oo->tree, o));          return (RB_NEXT(options_tree, &oo->tree, o));
 }  }
   
 struct options_entry *  struct option *
 options_find1(struct options *oo, const char *name)  options_get_only(struct options *oo, const char *name)
 {  {
         struct options_entry    p;          struct option   o;
   
         p.name = (char *)name;          o.name = name;
         return (RB_FIND(options_tree, &oo->tree, &p));          return (RB_FIND(options_tree, &oo->tree, &o));
 }  }
   
 struct options_entry *  struct option *
 options_find(struct options *oo, const char *name)  options_get(struct options *oo, const char *name)
 {  {
         struct options_entry    *o, p;          struct option   *o;
   
         p.name = (char *)name;          o = options_get_only(oo, name);
         o = RB_FIND(options_tree, &oo->tree, &p);  
         while (o == NULL) {          while (o == NULL) {
                 oo = oo->parent;                  oo = oo->parent;
                 if (oo == NULL)                  if (oo == NULL)
                         break;                          break;
                 o = RB_FIND(options_tree, &oo->tree, &p);                  o = options_get_only(oo, name);
         }          }
         return (o);          return (o);
 }  }
   
 void  struct option *
 options_remove(struct options *oo, const char *name)  options_empty(struct options *oo, const struct options_table_entry *oe)
 {  {
         struct options_entry    *o;          struct option   *o;
   
         if ((o = options_find1(oo, name)) != NULL)          o = options_add(oo, oe->name);
                 options_free1(oo, o);          o->tableentry = oe;
   
           return (o);
 }  }
   
 struct options_entry *  struct option *
 options_set_string(struct options *oo, const char *name, int append,  options_default(struct options *oo, const struct options_table_entry *oe)
     const char *fmt, ...)  
 {  {
         struct options_entry    *o;          struct option   *o;
         va_list                  ap;          char            *cp, *copy, *next;
         char                    *s, *value;          u_int            idx = 0;
   
         va_start(ap, fmt);          o = options_empty(oo, oe);
         xvasprintf(&s, fmt, ap);  
         va_end(ap);  
   
         o = options_find1(oo, name);          if (oe->type == OPTIONS_TABLE_ARRAY) {
         if (o == NULL || !append)                  copy = cp = xstrdup(oe->default_str);
                 value = s;                  while ((next = strsep(&cp, ",")) != NULL) {
         else {                          options_array_set(o, idx, next);
                 xasprintf(&value, "%s%s", o->str, s);                          idx++;
                 free(s);                  }
                   free(copy);
                   return (o);
         }          }
   
         o = options_new(oo, name);          if (oe->type == OPTIONS_TABLE_STRING)
         o->type = OPTIONS_STRING;                  o->string = xstrdup(oe->default_str);
         o->str = value;          else if (oe->type == OPTIONS_TABLE_STYLE) {
                   memcpy(&o->style, &grid_default_cell, sizeof o->style);
                   style_parse(&grid_default_cell, &o->style, oe->default_str);
           } else
                   o->number = oe->default_num;
           return (o);
   }
   
   static struct option *
   options_add(struct options *oo, const char *name)
   {
           struct option   *o;
   
           o = options_get_only(oo, name);
           if (o != NULL)
                   options_remove(o);
   
           o = xcalloc(1, sizeof *o);
           o->owner = oo;
           o->name = xstrdup(name);
   
           RB_INSERT(options_tree, &oo->tree, o);
         return (o);          return (o);
 }  }
   
   void
   options_remove(struct option *o)
   {
           struct options  *oo = o->owner;
           u_int            i;
   
           if (OPTIONS_IS_STRING(o))
                   free((void *)o->string);
           else if (OPTIONS_IS_ARRAY(o)) {
                   for (i = 0; i < o->arraysize; i++)
                           free((void *)o->array[i]);
                   free(o->array);
           }
   
           RB_REMOVE(options_tree, &oo->tree, o);
           free(o);
   }
   
 const char *  const char *
 options_get_string(struct options *oo, const char *name)  options_name(struct option *o)
 {  {
         struct options_entry    *o;          return (o->name);
   }
   
         if ((o = options_find(oo, name)) == NULL)  const struct options_table_entry *
                 fatalx("missing option %s", name);  options_table_entry(struct option *o)
         if (o->type != OPTIONS_STRING)  {
                 fatalx("option %s not a string", name);          return (o->tableentry);
         return (o->str);  
 }  }
   
 struct options_entry *  const char *
 options_set_number(struct options *oo, const char *name, long long value)  options_array_get(struct option *o, u_int idx)
 {  {
         struct options_entry    *o;          if (!OPTIONS_IS_ARRAY(o))
                   return (NULL);
           if (idx >= o->arraysize)
                   return (NULL);
           return (o->array[idx]);
   }
   
         o = options_new(oo, name);  int
         o->type = OPTIONS_NUMBER;  options_array_set(struct option *o, u_int idx, const char *value)
         o->num = value;  {
           u_int   i;
   
         return (o);          if (!OPTIONS_IS_ARRAY(o))
                   return (-1);
   
           if (idx >= OPTIONS_ARRAY_LIMIT)
                   return (-1);
           if (idx >= o->arraysize) {
                   o->array = xreallocarray(o->array, idx + 1, sizeof *o->array);
                   for (i = o->arraysize; i < idx + 1; i++)
                           o->array[i] = NULL;
                   o->arraysize = idx + 1;
           }
           if (o->array[idx] != NULL)
                   free((void *)o->array[idx]);
           if (value != NULL)
                   o->array[idx] = xstrdup(value);
           else
                   o->array[idx] = NULL;
           return (0);
 }  }
   
 long long  int
 options_get_number(struct options *oo, const char *name)  options_array_size(struct option *o, u_int *size)
 {  {
         struct options_entry    *o;          if (!OPTIONS_IS_ARRAY(o))
                   return (-1);
           if (size != NULL)
                   *size = o->arraysize;
           return (0);
   }
   
         if ((o = options_find(oo, name)) == NULL)  int
                 fatalx("missing option %s", name);  options_isstring(struct option *o)
         if (o->type != OPTIONS_NUMBER)  {
                 fatalx("option %s not a number", name);          if (o->tableentry == NULL)
         return (o->num);                  return (1);
           return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o));
 }  }
   
 struct options_entry *  const char *
 options_set_style(struct options *oo, const char *name, int append,  options_tostring(struct option *o, int idx)
     const char *value)  
 {  {
         struct options_entry    *o;          static char      s[1024];
         struct grid_cell         tmpgc;          const char      *tmp;
   
         o = options_find1(oo, name);          if (OPTIONS_IS_ARRAY(o)) {
         if (o == NULL || !append)                  if (idx == -1)
                 memcpy(&tmpgc, &grid_default_cell, sizeof tmpgc);                          return (NULL);
                   if ((u_int)idx >= o->arraysize || o->array[idx] == NULL)
                           return ("");
                   return (o->array[idx]);
           }
           if (OPTIONS_IS_STYLE(o))
                   return (style_tostring(&o->style));
           if (OPTIONS_IS_NUMBER(o)) {
                   tmp = NULL;
                   switch (o->tableentry->type) {
                   case OPTIONS_TABLE_NUMBER:
                           xsnprintf(s, sizeof s, "%lld", o->number);
                           break;
                   case OPTIONS_TABLE_KEY:
                           tmp = key_string_lookup_key(o->number);
                           break;
                   case OPTIONS_TABLE_COLOUR:
                           tmp = colour_tostring(o->number);
                           break;
                   case OPTIONS_TABLE_ATTRIBUTES:
                           tmp = attributes_tostring(o->number);
                           break;
                   case OPTIONS_TABLE_FLAG:
                           tmp = (o->number ? "on" : "off");
                           break;
                   case OPTIONS_TABLE_CHOICE:
                           tmp = o->tableentry->choices[o->number];
                           break;
                   case OPTIONS_TABLE_STRING:
                   case OPTIONS_TABLE_STYLE:
                   case OPTIONS_TABLE_ARRAY:
                           break;
                   }
                   if (tmp != NULL)
                           xsnprintf(s, sizeof s, "%s", tmp);
                   return (s);
           }
           if (OPTIONS_IS_STRING(o))
                   return (o->string);
           return (NULL);
   }
   
   char *
   options_parse(const char *name, int *idx)
   {
           char    *copy, *cp, *end;
   
           if (*name == '\0')
                   return (NULL);
           copy = xstrdup(name);
           if ((cp = strchr(copy, '[')) == NULL) {
                   *idx = -1;
                   return (copy);
           }
           end = strchr(cp + 1, ']');
           if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) {
                   free(copy);
                   return (NULL);
           }
           if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) {
                   free(copy);
                   return (NULL);
           }
           *cp = '\0';
           return (copy);
   }
   
   struct option *
   options_parse_get(struct options *oo, const char *s, int *idx, int only)
   {
           struct option   *o;
           char            *name;
   
           name = options_parse(s, idx);
           if (name == NULL)
                   return (NULL);
           if (only)
                   o = options_get_only(oo, name);
         else          else
                 memcpy(&tmpgc, &o->style, sizeof tmpgc);                  o = options_get(oo, name);
           free(name);
           if (o != NULL) {
                   if (OPTIONS_IS_ARRAY(o) && *idx == -1)
                           return (NULL);
                   if (!OPTIONS_IS_ARRAY(o) && *idx != -1)
                           return (NULL);
           }
           return (o);
   }
   
         if (style_parse(&grid_default_cell, &tmpgc, value) == -1)  char *
   options_match(const char *s, int *idx, int* ambiguous)
   {
           const struct options_table_entry        *oe, *found;
           char                                    *name;
           size_t                                   namelen;
   
           name = options_parse(s, idx);
           namelen = strlen(name);
   
           found = NULL;
           for (oe = options_table; oe->name != NULL; oe++) {
                   if (strcmp(oe->name, name) == 0) {
                           found = oe;
                           break;
                   }
                   if (strncmp(oe->name, name, namelen) == 0) {
                           if (found != NULL) {
                                   *ambiguous = 1;
                                   free(name);
                                   return (NULL);
                           }
                           found = oe;
                   }
           }
           free(name);
           if (found == NULL) {
                   *ambiguous = 0;
                 return (NULL);                  return (NULL);
           }
           return (xstrdup(found->name));
   }
   
         o = options_new(oo, name);  struct option *
         o->type = OPTIONS_STYLE;  options_match_get(struct options *oo, const char *s, int *idx, int only,
         memcpy(&o->style, &tmpgc, sizeof o->style);      int* ambiguous)
   {
           char            *name;
           struct option   *o;
   
           name = options_match(s, idx, ambiguous);
           if (name == NULL)
                   return (NULL);
           *ambiguous = 0;
           if (only)
                   o = options_get_only(oo, name);
           else
                   o = options_get(oo, name);
           free(name);
           if (o != NULL) {
                   if (OPTIONS_IS_ARRAY(o) && *idx == -1)
                           return (NULL);
                   if (!OPTIONS_IS_ARRAY(o) && *idx != -1)
                           return (NULL);
           }
         return (o);          return (o);
 }  }
   
   
   const char *
   options_get_string(struct options *oo, const char *name)
   {
           struct option   *o;
   
           o = options_get(oo, name);
           if (o == NULL)
                   fatalx("missing option %s", name);
           if (!OPTIONS_IS_STRING(o))
                   fatalx("option %s is not a string", name);
           return (o->string);
   }
   
   long long
   options_get_number(struct options *oo, const char *name)
   {
           struct option   *o;
   
           o = options_get(oo, name);
           if (o == NULL)
                   fatalx("missing option %s", name);
           if (!OPTIONS_IS_NUMBER(o))
               fatalx("option %s is not a number", name);
           return (o->number);
   }
   
 const struct grid_cell *  const struct grid_cell *
 options_get_style(struct options *oo, const char *name)  options_get_style(struct options *oo, const char *name)
 {  {
         struct options_entry    *o;          struct option   *o;
   
         if ((o = options_find(oo, name)) == NULL)          o = options_get(oo, name);
           if (o == NULL)
                 fatalx("missing option %s", name);                  fatalx("missing option %s", name);
         if (o->type != OPTIONS_STYLE)          if (!OPTIONS_IS_STYLE(o))
                 fatalx("option %s not a style", name);                  fatalx("option %s is not a style", name);
         return (&o->style);          return (&o->style);
   }
   
   struct option *
   options_set_string(struct options *oo, const char *name, int append,
       const char *fmt, ...)
   {
           struct option   *o;
           va_list          ap;
           char            *s, *value;
   
           va_start(ap, fmt);
           xvasprintf(&s, fmt, ap);
           va_end(ap);
   
           o = options_get_only(oo, name);
           if (o != NULL && append && OPTIONS_IS_STRING(o)) {
                   xasprintf(&value, "%s%s", o->string, s);
                   free(s);
           } else
                   value = s;
           if (o == NULL && *name == '@')
                   o = options_add(oo, name);
           else if (o == NULL) {
                   o = options_default(oo, options_parent_table_entry(oo, name));
                   if (o == NULL)
                           return (NULL);
           }
   
           if (!OPTIONS_IS_STRING(o))
                   fatalx("option %s is not a string", name);
           free(o->string);
           o->string = value;
           return (o);
   }
   
   struct option *
   options_set_number(struct options *oo, const char *name, long long value)
   {
           struct option   *o;
   
           if (*name == '@')
                   fatalx("user option %s must be a string", name);
   
           o = options_get_only(oo, name);
           if (o == NULL) {
                   o = options_default(oo, options_parent_table_entry(oo, name));
                   if (o == NULL)
                           return (NULL);
           }
   
           if (!OPTIONS_IS_NUMBER(o))
                   fatalx("option %s is not a number", name);
           o->number = value;
           return (o);
   }
   
   struct option *
   options_set_style(struct options *oo, const char *name, int append,
       const char *value)
   {
           struct option           *o;
           struct grid_cell         gc;
   
           if (*name == '@')
                   fatalx("user option %s must be a string", name);
   
           o = options_get_only(oo, name);
           if (o != NULL && append && OPTIONS_IS_STYLE(o))
                   memcpy(&gc, &o->style, sizeof gc);
           else
                   memcpy(&gc, &grid_default_cell, sizeof gc);
           if (style_parse(&grid_default_cell, &gc, value) == -1)
                   return (NULL);
           if (o == NULL) {
                   o = options_default(oo, options_parent_table_entry(oo, name));
                   if (o == NULL)
                           return (NULL);
           }
   
           if (!OPTIONS_IS_STYLE(o))
                   fatalx("option %s is not a style", name);
           memcpy(&o->style, &gc, sizeof o->style);
           return (o);
   }
   
   enum options_table_scope
   options_scope_from_flags(struct args *args, int window,
       struct cmd_find_state *fs, struct options **oo, char **cause)
   {
           struct session  *s = fs->s;
           struct winlink  *wl = fs->wl;
           const char      *target= args_get(args, 't');
   
           if (args_has(args, 's')) {
                   *oo = global_options;
                   return (OPTIONS_TABLE_SERVER);
           }
   
           if (window || args_has(args, 'w')) {
                   if (args_has(args, 'g')) {
                           *oo = global_w_options;
                           return (OPTIONS_TABLE_WINDOW);
                   }
                   if (wl == NULL) {
                           if (target != NULL)
                                   xasprintf(cause, "no such window: %s", target);
                           else
                                   xasprintf(cause, "no current window");
                           return (OPTIONS_TABLE_NONE);
                   }
                   *oo = wl->window->options;
                   return (OPTIONS_TABLE_WINDOW);
           } else {
                   if (args_has(args, 'g')) {
                           *oo = global_s_options;
                           return (OPTIONS_TABLE_SESSION);
                   }
                   if (s == NULL) {
                           if (target != NULL)
                                   xasprintf(cause, "no such session: %s", target);
                           else
                                   xasprintf(cause, "no current session");
                           return (OPTIONS_TABLE_NONE);
                   }
                   *oo = s->options;
                   return (OPTIONS_TABLE_SESSION);
           }
   }
   
   void
   options_style_update_new(struct options *oo, struct option *o)
   {
           const char      *newname = o->tableentry->style;
           struct option   *new;
   
           if (newname == NULL)
                   return;
           new = options_get_only(oo, newname);
           if (new == NULL)
                   new = options_set_style(oo, newname, 0, "default");
   
           if (strstr(o->name, "-bg") != NULL)
                   new->style.bg = o->number;
           else if (strstr(o->name, "-fg") != NULL)
                   new->style.fg = o->number;
           else if (strstr(o->name, "-attr") != NULL)
                   new->style.attr = o->number;
   }
   
   void
   options_style_update_old(struct options *oo, struct option *o)
   {
           char    newname[128];
           int     size;
   
           size = strrchr(o->name, '-') - o->name;
   
           xsnprintf(newname, sizeof newname, "%.*s-bg", size, o->name);
           options_set_number(oo, newname, o->style.bg);
   
           xsnprintf(newname, sizeof newname, "%.*s-fg", size, o->name);
           options_set_number(oo, newname, o->style.fg);
   
           xsnprintf(newname, sizeof newname, "%.*s-attr", size, o->name);
           options_set_number(oo, newname, o->style.attr);
 }  }

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.26