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

Diff for /src/usr.bin/tmux/format.c between version 1.168 and 1.169

version 1.168, 2019/03/12 11:16:50 version 1.169, 2019/03/13 14:10:34
Line 92 
Line 92 
 #define FORMAT_TIMESTRING 0x1  #define FORMAT_TIMESTRING 0x1
 #define FORMAT_BASENAME 0x2  #define FORMAT_BASENAME 0x2
 #define FORMAT_DIRNAME 0x4  #define FORMAT_DIRNAME 0x4
 #define FORMAT_SUBSTITUTE 0x8  #define FORMAT_QUOTE 0x8
 #define FORMAT_QUOTE 0x10  #define FORMAT_LITERAL 0x10
   
 /* Entry in format tree. */  /* Entry in format tree. */
 struct format_entry {  struct format_entry {
Line 121 
Line 121 
 static int format_entry_cmp(struct format_entry *, struct format_entry *);  static int format_entry_cmp(struct format_entry *, struct format_entry *);
 RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);  RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
   
   /* Format modifiers. */
   struct format_modifier {
           char      modifier[3];
           u_int     size;
   
           char    **argv;
           int       argc;
   };
   
 /* Format entry tree comparison function. */  /* Format entry tree comparison function. */
 static int  static int
 format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)  format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)
Line 885 
Line 894 
   
 /* Skip until end. */  /* Skip until end. */
 static const char *  static const char *
 format_skip(const char *s, char end)  format_skip(const char *s, const char *end)
 {  {
         int     brackets = 0;          int     brackets = 0;
   
Line 898 
Line 907 
                 }                  }
                 if (*s == '}')                  if (*s == '}')
                         brackets--;                          brackets--;
                 if (*s == end && brackets == 0)                  if (strchr(end, *s) != NULL && brackets == 0)
                         break;                          break;
         }          }
         if (*s == '\0')          if (*s == '\0')
Line 908 
Line 917 
   
 /* Return left and right alternatives separated by commas. */  /* Return left and right alternatives separated by commas. */
 static int  static int
 format_choose(char *s, char **left, char **right)  format_choose(struct format_tree *ft, const char *s, char **left, char **right,
       int expand)
 {  {
         char    *cp;          const char      *cp;
           char            *left0, *right0;
   
         cp = (char *)format_skip(s, ',');          cp = format_skip(s, ",");
         if (cp == NULL)          if (cp == NULL)
                 return (-1);                  return (-1);
         *cp = '\0';          left0 = xstrndup(s, cp - s);
           right0 = xstrdup(cp + 1);
   
         *left = s;          if (expand) {
         *right = cp + 1;                  *left = format_expand(ft, left0);
                   *right = format_expand(ft, right0);
           } else {
                   *left = left0;
                   *right = right0;
           }
         return (0);          return (0);
 }  }
   
Line 931 
Line 948 
         return (0);          return (0);
 }  }
   
 /* Replace a key. */  /* Check if modifier end. */
 static int  static int
 format_replace(struct format_tree *ft, const char *key, size_t keylen,  format_is_end(char c)
     char **buf, size_t *len, size_t *off)  
 {  {
         struct window_pane      *wp = ft->wp;          return (c == ';' || c == ':');
         char                    *copy, *copy0, *endptr, *ptr, *found, *new, sep;  }
         char                    *value, *from = NULL, *to = NULL, *left, *right;  
         size_t                   valuelen, newlen, fromlen, tolen, used;  
         long                     limit = 0;  
         int                      modifiers = 0, compare = 0, search = 0;  
         int                      literal = 0;  
   
         /* Make a copy of the key. */  /* Add to modifier list. */
         copy0 = copy = xmalloc(keylen + 1);  static void
         memcpy(copy, key, keylen);  format_add_modifier(struct format_modifier **list, u_int *count,
         copy[keylen] = '\0';      const char *c, size_t n, char **argv, int argc)
   {
           struct format_modifier *fm;
   
         /* Is there a length limit or whatnot? */          *list = xreallocarray(*list, (*count) + 1, sizeof **list);
         switch (copy[0]) {          fm = &(*list)[(*count)++];
         case 'l':  
                 if (copy[1] != ':')          memcpy(fm->modifier, c, n);
                         break;          fm->modifier[n] = '\0';
                 literal = 1;          fm->size = n;
                 copy += 2;  
                 break;          fm->argv = argv;
         case 'm':          fm->argc = argc;
                 if (copy[1] != ':')  }
                         break;  
                 compare = -2;  /* Free modifier list. */
                 copy += 2;  static void
                 break;  format_free_modifiers(struct format_modifier *list, u_int count)
         case 'C':  {
                 if (copy[1] != ':')          u_int   i;
                         break;  
                 search = 1;          for (i = 0; i < count; i++)
                 copy += 2;                  cmd_free_argv(list[i].argc, list[i].argv);
                 break;          free(list);
         case '|':  }
                 if (copy[1] != '|' || copy[2] != ':')  
                         break;  /* Build modifier list. */
                 compare = -3;  static struct format_modifier *
                 copy += 3;  format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
                 break;  {
         case '&':          const char              *cp = *s, *end;
                 if (copy[1] != '&' || copy[2] != ':')          struct format_modifier  *list = NULL;
                         break;          char                     c, last[] = "X;:", **argv, *value;
                 compare = -4;          int                      argc;
                 copy += 3;  
                 break;          /*
         case '!':           * Modifiers are a ; separated list of the forms:
                 if (copy[1] == '=' && copy[2] == ':') {           *      l,m,C,b,d,t,q
                         compare = -1;           *      =a
                         copy += 3;           *      =/a
                         break;           *      =/a/
            *      s/a/b/
            *      s/a/b
            *      ||,&&,!=,==
            */
   
           *count = 0;
   
           while (*cp != '\0' && *cp != ':') {
                   /* Skip and separator character. */
                   if (*cp == ';')
                           cp++;
   
                   /* Check single character modifiers with no arguments. */
                   if (strchr("lmCbdtq", cp[0]) != NULL && format_is_end(cp[1])) {
                           format_add_modifier(&list, count, cp, 1, NULL, 0);
                           cp++;
                           continue;
                 }                  }
                 break;  
         case '=':                  /* Then try double character with no arguments. */
                 if (copy[1] == '=' && copy[2] == ':') {                  if ((memcmp("||", cp, 2) == 0 ||
                         compare = 1;                      memcmp("&&", cp, 2) == 0 ||
                         copy += 3;                      memcmp("!=", cp, 2) == 0 ||
                         break;                      memcmp("==", cp, 2) == 0) &&
                       format_is_end(cp[2])) {
                           format_add_modifier(&list, count, cp, 2, NULL, 0);
                           cp += 2;
                           continue;
                 }                  }
                 errno = 0;  
                 limit = strtol(copy + 1, &endptr, 10);                  /* Now try single character with arguments. */
                 if (errno == ERANGE && (limit == LONG_MIN || limit == LONG_MAX))                  if (strchr("s=", cp[0]) == NULL)
                         break;                          break;
                 if (*endptr != ':')                  c = cp[0];
                         break;  
                 copy = endptr + 1;                  /* No arguments provided. */
                 break;                  if (format_is_end(cp[1])) {
         case 'b':                          format_add_modifier(&list, count, cp, 1, NULL, 0);
                 if (copy[1] != ':')                          cp++;
                         break;                          continue;
                 modifiers |= FORMAT_BASENAME;  
                 copy += 2;  
                 break;  
         case 'd':  
                 if (copy[1] != ':')  
                         break;  
                 modifiers |= FORMAT_DIRNAME;  
                 copy += 2;  
                 break;  
         case 't':  
                 if (copy[1] != ':')  
                         break;  
                 modifiers |= FORMAT_TIMESTRING;  
                 copy += 2;  
                 break;  
         case 'q':  
                 if (copy[1] != ':')  
                         break;  
                 modifiers |= FORMAT_QUOTE;  
                 copy += 2;  
                 break;  
         case 's':  
                 sep = copy[1];  
                 if (sep == ':' || !ispunct((u_char)sep))  
                         break;  
                 from = copy + 2;  
                 for (copy = from; *copy != '\0' && *copy != sep; copy++)  
                         /* nothing */;  
                 if (copy[0] != sep || copy == from) {  
                         copy = copy0;  
                         break;  
                 }                  }
                 copy[0] = '\0';                  argv = NULL;
                 to = copy + 1;                  argc = 0;
                 for (copy = to; *copy != '\0' && *copy != sep; copy++)  
                         /* nothing */;                  /* Single argument with no wrapper character. */
                 if (copy[0] != sep || copy[1] != ':') {                  if (!ispunct(cp[1]) || cp[1] == '-') {
                         copy = copy0;                          end = format_skip(cp + 1, ":;");
                         break;                          if (end == NULL)
                                   break;
   
                           argv = xcalloc(1, sizeof *argv);
                           value = xstrndup(cp + 1, end - (cp + 1));
                           argv[0] = format_expand(ft, value);
                           free(value);
                           argc = 1;
   
                           format_add_modifier(&list, count, &c, 1, argv, argc);
                           cp = end;
                           continue;
                 }                  }
                 copy[0] = '\0';  
   
                 modifiers |= FORMAT_SUBSTITUTE;                  /* Multiple arguments with a wrapper character. */
                 copy += 2;                  last[0] = cp[1];
                 break;                  cp++;
                   do {
                           if (cp[0] == last[0] && format_is_end(cp[1])) {
                                   cp++;
                                   break;
                           }
                           end = format_skip(cp + 1, last);
                           if (end == NULL)
                                   break;
                           cp++;
   
                           argv = xreallocarray (argv, argc + 1, sizeof *argv);
                           value = xstrndup(cp, end - cp);
                           argv[argc++] = format_expand(ft, value);
                           free(value);
   
                           cp = end;
                   } while (!format_is_end(cp[0]));
                   format_add_modifier(&list, count, &c, 1, argv, argc);
         }          }
           if (*cp != ':') {
                   format_free_modifiers(list, *count);
                   *count = 0;
                   return (NULL);
           }
           *s = cp + 1;
           return list;
   }
   
   /* Perform substitution in string. */
   static char *
   format_substitute(const char *source, const char *from, const char *to)
   {
           char            *copy, *new;
           const char      *cp;
           size_t           fromlen, tolen, newlen, used;
   
           fromlen = strlen(from);
           tolen = strlen(to);
   
           newlen = strlen(source) + 1;
           copy = new = xmalloc(newlen);
   
           for (cp = source; *cp != '\0'; /* nothing */) {
                   if (strncmp(cp, from, fromlen) != 0) {
                           *new++ = *cp++;
                           continue;
                   }
                   used = new - copy;
   
                   newlen += tolen;
                   copy = xrealloc(copy, newlen);
   
                   new = copy + used;
                   memcpy(new, to, tolen);
   
                   new += tolen;
                   cp += fromlen;
           }
   
           *new = '\0';
           return (copy);
   }
   
   /* Replace a key. */
   static int
   format_replace(struct format_tree *ft, const char *key, size_t keylen,
       char **buf, size_t *len, size_t *off)
   {
           struct window_pane      *wp = ft->wp;
           const char              *errptr, *copy, *cp;
           char                    *copy0, *condition, *found, *new;
           char                    *value, *left, *right;
           char                     tmp[64];
           size_t                   valuelen;
           int                      modifiers = 0, limit = 0;
           struct format_modifier  *list, *fm, *cmp = NULL, *search = NULL;
           struct format_modifier  *sub = NULL;
           u_int                    i, count;
   
           /* Make a copy of the key. */
           copy = copy0 = xstrndup(key, keylen);
   
           /* Process modifier list. */
           list = format_build_modifiers(ft, &copy, &count);
           for (i = 0; i < count; i++) {
                   xsnprintf(tmp, sizeof tmp, "%s: modifier %u", __func__, i);
                   log_debug("%s = %s", tmp, list[i].modifier);
                   cmd_log_argv(list[i].argc, list[i].argv, tmp);
   
                   fm = &list[i];
                   if (fm->size == 1) {
                           switch (fm->modifier[0]) {
                           case 'm':
                                   cmp = fm;
                                   break;
                           case 'C':
                                   search = fm;
                                   break;
                           case 's':
                                   if (fm->argc != 2)
                                           break;
                                   sub = fm;
                                   break;
                           case '=':
                                   if (fm->argc != 1)
                                           break;
                                   limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
                                       &errptr);
                                   if (errptr != NULL)
                                           limit = 0;
                                   break;
                           case 'l':
                                   modifiers |= FORMAT_LITERAL;
                                   break;
                           case 'b':
                                   modifiers |= FORMAT_BASENAME;
                                   break;
                           case 'd':
                                   modifiers |= FORMAT_DIRNAME;
                                   break;
                           case 't':
                                   modifiers |= FORMAT_TIMESTRING;
                                   break;
                           case 'q':
                                   modifiers |= FORMAT_QUOTE;
                                   break;
                           }
                   } else if (fm->size == 2) {
                           if (strcmp(fm->modifier, "||") == 0 ||
                               strcmp(fm->modifier, "&&") == 0 ||
                               strcmp(fm->modifier, "==") == 0 ||
                               strcmp(fm->modifier, "!=") == 0)
                                   cmp = fm;
                   }
           }
           log_debug("%s: remaining = '%s'", __func__, copy);
   
         /* Is this a literal string? */          /* Is this a literal string? */
         if (literal) {          if (modifiers & FORMAT_LITERAL) {
                 value = xstrdup(copy);                  value = xstrdup(copy);
                 goto done;                  goto done;
         }          }
   
         /* Is this a comparison or a conditional? */          /* Is this a comparison or a conditional? */
         if (search) {          if (search != NULL) {
                 /* Search in pane. */                  /* Search in pane. */
                 if (wp == NULL)                  if (wp == NULL)
                         value = xstrdup("0");                          value = xstrdup("0");
                 else                  else
                         xasprintf(&value, "%u", window_pane_search(wp, copy));                          xasprintf(&value, "%u", window_pane_search(wp, copy));
         } else if (compare != 0) {          } else if (cmp != NULL) {
                 /* Comparison: compare comma-separated left and right. */                  /* Comparison of left and right. */
                 if (format_choose(copy, &left, &right) != 0)                  if (format_choose(ft, copy, &left, &right, 1) != 0)
                         goto fail;                          goto fail;
                 left = format_expand(ft, left);  
                 right = format_expand(ft, right);                  if (strcmp(cmp->modifier, "||") == 0) {
                 if (compare == -3 &&                          if (format_true(left) || format_true(right))
                     (format_true(left) || format_true(right)))                                  value = xstrdup("1");
                         value = xstrdup("1");                          else
                 else if (compare == -4 &&                                  value = xstrdup("0");
                     (format_true(left) && format_true(right)))                  } else if (strcmp(cmp->modifier, "&&") == 0) {
                         value = xstrdup("1");                          if (format_true(left) && format_true(right))
                 else if (compare == 1 && strcmp(left, right) == 0)                                  value = xstrdup("1");
                         value = xstrdup("1");                          else
                 else if (compare == -1 && strcmp(left, right) != 0)                                  value = xstrdup("0");
                         value = xstrdup("1");                  } else if (strcmp(cmp->modifier, "==") == 0) {
                 else if (compare == -2 && fnmatch(left, right, 0) == 0)                          if (strcmp(left, right) == 0)
                         value = xstrdup("1");                                  value = xstrdup("1");
                 else                          else
                         value = xstrdup("0");                                  value = xstrdup("0");
                   } else if (strcmp(cmp->modifier, "!=") == 0) {
                           if (strcmp(left, right) != 0)
                                   value = xstrdup("1");
                           else
                                   value = xstrdup("0");
                   }
                   else if (strcmp(cmp->modifier, "m") == 0) {
                           if (fnmatch(left, right, 0) == 0)
                                   value = xstrdup("1");
                           else
                                   value = xstrdup("0");
                   }
   
                 free(right);                  free(right);
                 free(left);                  free(left);
         } else if (*copy == '?') {          } else if (*copy == '?') {
                 /* Conditional: check first and choose second or third. */                  /* Conditional: check first and choose second or third. */
                 ptr = (char *)format_skip(copy, ',');                  cp = format_skip(copy + 1, ",");
                 if (ptr == NULL)                  if (cp == NULL)
                         goto fail;                          goto fail;
                 *ptr = '\0';                  condition = xstrndup(copy + 1, cp - (copy + 1));
   
                 found = format_find(ft, copy + 1, modifiers);                  found = format_find(ft, condition, modifiers);
                 if (found == NULL) {                  if (found == NULL) {
                         /*                          /*
                          * If the conditional not found, try to expand it. If                           * If the condition not found, try to expand it. If
                          * the expansion doesn't have any effect, then assume                           * the expansion doesn't have any effect, then assume
                          * false.                           * false.
                          */                           */
                         found = format_expand(ft, copy + 1);                          found = format_expand(ft, condition);
                         if (strcmp(found, copy + 1) == 0) {                          if (strcmp(found, condition) == 0) {
                                 free(found);                                  free(found);
                                 found = xstrdup("");                                  found = xstrdup("");
                         }                          }
                 }                  }
                 if (format_choose(ptr + 1, &left, &right) != 0) {                  free(condition);
   
                   if (format_choose(ft, cp + 1, &left, &right, 0) != 0) {
                         free(found);                          free(found);
                         goto fail;                          goto fail;
                 }                  }
   
                 if (format_true(found))                  if (format_true(found))
                         value = format_expand(ft, left);                          value = format_expand(ft, left);
                 else                  else
                         value = format_expand(ft, right);                          value = format_expand(ft, right);
                   free(right);
                   free(left);
   
                 free(found);                  free(found);
         } else {          } else {
                 /* Neither: look up directly. */                  /* Neither: look up directly. */
Line 1125 
Line 1290 
         }          }
   
         /* Perform substitution if any. */          /* Perform substitution if any. */
         if (modifiers & FORMAT_SUBSTITUTE) {          if (sub != NULL) {
                 fromlen = strlen(from);                  new = format_substitute(value, sub->argv[0], sub->argv[1]);
                 tolen = strlen(to);  
   
                 newlen = strlen(value) + 1;  
                 copy = new = xmalloc(newlen);  
                 for (ptr = value; *ptr != '\0'; /* nothing */) {  
                         if (strncmp(ptr, from, fromlen) != 0) {  
                                 *new++ = *ptr++;  
                                 continue;  
                         }  
                         used = new - copy;  
   
                         newlen += tolen;  
                         copy = xrealloc(copy, newlen);  
   
                         new = copy + used;  
                         memcpy(new, to, tolen);  
   
                         new += tolen;  
                         ptr += fromlen;  
                 }  
                 *new = '\0';  
                 free(value);                  free(value);
                 value = copy;                  value = new;
         }          }
   
         /* Truncate the value if needed. */          /* Truncate the value if needed. */
Line 1174 
Line 1318 
         *off += valuelen;          *off += valuelen;
   
         free(value);          free(value);
           format_free_modifiers(list, count);
         free(copy0);          free(copy0);
         return (0);          return (0);
   
 fail:  fail:
           format_free_modifiers(list, count);
         free(copy0);          free(copy0);
         return (-1);          return (-1);
 }  }
Line 1262 
Line 1408 
                         fmt += n + 1;                          fmt += n + 1;
                         continue;                          continue;
                 case '{':                  case '{':
                         ptr = format_skip(fmt - 2, '}');                          ptr = format_skip((char *)fmt - 2, "}");
                         if (ptr == NULL)                          if (ptr == NULL)
                                 break;                                  break;
                         n = ptr - fmt;                          n = ptr - fmt;
Line 1305 
Line 1451 
         }          }
         buf[off] = '\0';          buf[off] = '\0';
   
         log_debug("format '%s' -> '%s'", saved, buf);          log_debug("%s: '%s' -> '%s'", __func__, saved, buf);
         return (buf);          return (buf);
 }  }
   

Legend:
Removed from v.1.168  
changed lines
  Added in v.1.169