[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.262 and 1.263

version 1.262, 2020/09/16 18:37:55 version 1.263, 2020/10/06 07:36:05
Line 38 
Line 38 
  * string.   * string.
  */   */
   
 static char     *format_job_get(struct format_tree *, const char *);  struct format_expand_state;
 static void      format_job_timer(int, short, void *);  
   
 static int       format_replace(struct format_tree *, const char *, size_t,  static char     *format_job_get(struct format_expand_state *, const char *);
                      char **, size_t *, size_t *);  static void      format_job_timer(int, short, void *);
   static char     *format_expand1(struct format_expand_state *, const char *);
   static int       format_replace(struct format_expand_state *, const char *,
                        size_t, char **, size_t *, size_t *);
 static void      format_defaults_session(struct format_tree *,  static void      format_defaults_session(struct format_tree *,
                      struct session *);                       struct session *);
 static void      format_defaults_client(struct format_tree *, struct client *);  static void      format_defaults_client(struct format_tree *, struct client *);
 static void      format_defaults_winlink(struct format_tree *, struct winlink *);  static void      format_defaults_winlink(struct format_tree *,
                        struct winlink *);
   
 /* Entry in format job tree. */  /* Entry in format job tree. */
 struct format_job {  struct format_job {
Line 99 
Line 102 
 /* Limit on recursion. */  /* Limit on recursion. */
 #define FORMAT_LOOP_LIMIT 10  #define FORMAT_LOOP_LIMIT 10
   
   /* Format expand flags. */
   #define FORMAT_EXPAND_TIME 0x1
   #define FORMAT_EXPAND_NOJOBS 0x2
   
 /* Entry in format tree. */  /* Entry in format tree. */
 struct format_entry {  struct format_entry {
         char                    *key;          char                    *key;
         char                    *value;          char                    *value;
         time_t                   t;          time_t                   time;
         format_cb                cb;          format_cb                cb;
         RB_ENTRY(format_entry)   entry;          RB_ENTRY(format_entry)   entry;
 };  };
Line 120 
Line 127 
         struct client           *client;          struct client           *client;
         int                      flags;          int                      flags;
         u_int                    tag;          u_int                    tag;
         time_t                   time;  
         u_int                    loop;  
   
         struct mouse_event       m;          struct mouse_event       m;
   
Line 130 
Line 135 
 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 expand state. */
   struct format_expand_state {
           struct format_tree      *ft;
           u_int                    loop;
           time_t                   time;
           int                      flags;
   };
   
 /* Format modifier. */  /* Format modifier. */
 struct format_modifier {  struct format_modifier {
         char      modifier[3];          char      modifier[3];
Line 215 
Line 228 
   
 /* Log a message if verbose. */  /* Log a message if verbose. */
 static void printflike(3, 4)  static void printflike(3, 4)
 format_log1(struct format_tree *ft, const char *from, const char *fmt, ...)  format_log1(struct format_expand_state *es, const char *from, const char *fmt,
       ...)
 {  {
           struct format_tree      *ft = es->ft;
         va_list                  ap;          va_list                  ap;
         char                    *s;          char                    *s;
         static const char        spaces[] = "          ";          static const char        spaces[] = "          ";
Line 230 
Line 245 
   
         log_debug("%s: %s", from, s);          log_debug("%s: %s", from, s);
         if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE))          if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE))
                 cmdq_print(ft->item, "#%.*s%s", ft->loop, spaces, s);                  cmdq_print(ft->item, "#%.*s%s", es->loop, spaces, s);
   
         free(s);          free(s);
 }  }
 #define format_log(ft, fmt, ...) format_log1(ft, __func__, fmt, ##__VA_ARGS__)  #define format_log(es, fmt, ...) format_log1(es, __func__, fmt, ##__VA_ARGS__)
   
   /* Copy expand state. */
   static void
   format_copy_state(struct format_expand_state *to,
       struct format_expand_state *from, int flags)
   {
           to->ft = from->ft;
           to->loop = from->loop;
           to->time = from->time;
           to->flags = from->flags|flag;
   }
   
 /* Format job update callback. */  /* Format job update callback. */
 static void  static void
 format_job_update(struct job *job)  format_job_update(struct job *job)
Line 304 
Line 330 
   
 /* Find a job. */  /* Find a job. */
 static char *  static char *
 format_job_get(struct format_tree *ft, const char *cmd)  format_job_get(struct format_expand_state *es, const char *cmd)
 {  {
         struct format_job_tree  *jobs;          struct format_tree              *ft = es->ft;
         struct format_job        fj0, *fj;          struct format_job_tree          *jobs;
         time_t                   t;          struct format_job                fj0, *fj;
         char                    *expanded;          time_t                           t;
         int                      force;          char                            *expanded;
           int                              force;
           struct format_expand_state       next;
   
         if (ft->client == NULL)          if (ft->client == NULL)
                 jobs = &format_jobs;                  jobs = &format_jobs;
Line 335 
Line 363 
                 RB_INSERT(format_job_tree, jobs, fj);                  RB_INSERT(format_job_tree, jobs, fj);
         }          }
   
         expanded = format_expand(ft, cmd);          expanded = format_expand1(es, cmd);
         if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) {          if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) {
                 free((void *)fj->expanded);                  free((void *)fj->expanded);
                 fj->expanded = xstrdup(expanded);                  fj->expanded = xstrdup(expanded);
Line 357 
Line 385 
                 fj->last = t;                  fj->last = t;
                 fj->updated = 0;                  fj->updated = 0;
         }          }
           free(expanded);
   
         if (ft->flags & FORMAT_STATUS)          if (ft->flags & FORMAT_STATUS)
                 fj->status = 1;                  fj->status = 1;
           format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS);
         free(expanded);          return (format_expand1(&next, fj->out));
         return (format_expand(ft, fj->out));  
 }  }
   
 /* Remove old jobs. */  /* Remove old jobs. */
Line 1211 
Line 1239 
   
         ft->tag = tag;          ft->tag = tag;
         ft->flags = flags;          ft->flags = flags;
         ft->time = time(NULL);  
   
         format_add(ft, "version", "%s", getversion());          format_add(ft, "version", "%s", getversion());
         format_add_cb(ft, "host", format_cb_host);          format_add_cb(ft, "host", format_cb_host);
Line 1261 
Line 1288 
         char                     s[64];          char                     s[64];
   
         RB_FOREACH(fe, format_entry_tree, &ft->tree) {          RB_FOREACH(fe, format_entry_tree, &ft->tree) {
                 if (fe->t != 0) {                  if (fe->time != 0) {
                         xsnprintf(s, sizeof s, "%lld", (long long)fe->t);                          xsnprintf(s, sizeof s, "%lld", (long long)fe->time);
                         cb(fe->key, s, arg);                          cb(fe->key, s, arg);
                 } else {                  } else {
                         if (fe->value == NULL && fe->cb != NULL) {                          if (fe->value == NULL && fe->cb != NULL) {
Line 1295 
Line 1322 
         }          }
   
         fe->cb = NULL;          fe->cb = NULL;
         fe->t = 0;          fe->time = 0;
   
         va_start(ap, fmt);          va_start(ap, fmt);
         xvasprintf(&fe->value, fmt, ap);          xvasprintf(&fe->value, fmt, ap);
Line 1320 
Line 1347 
         }          }
   
         fe->cb = NULL;          fe->cb = NULL;
         fe->t = tv->tv_sec;          fe->time = tv->tv_sec;
   
         fe->value = NULL;          fe->value = NULL;
 }  }
Line 1344 
Line 1371 
         }          }
   
         fe->cb = cb;          fe->cb = cb;
         fe->t = 0;          fe->time = 0;
   
         fe->value = NULL;          fe->value = NULL;
 }  }
Line 1440 
Line 1467 
         fe_find.key = (char *)key;          fe_find.key = (char *)key;
         fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);          fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
         if (fe != NULL) {          if (fe != NULL) {
                 if (fe->t != 0) {                  if (fe->time != 0) {
                         t = fe->t;                          t = fe->time;
                         goto found;                          goto found;
                 }                  }
                 if (fe->value == NULL && fe->cb != NULL) {                  if (fe->value == NULL && fe->cb != NULL) {
Line 1563 
Line 1590 
   
 /* Return left and right alternatives separated by commas. */  /* Return left and right alternatives separated by commas. */
 static int  static int
 format_choose(struct format_tree *ft, const char *s, char **left, char **right,  format_choose(struct format_expand_state *es, const char *s, char **left,
     int expand)      char **right, int expand)
 {  {
         const char      *cp;          const char      *cp;
         char            *left0, *right0;          char            *left0, *right0;
Line 1576 
Line 1603 
         right0 = xstrdup(cp + 1);          right0 = xstrdup(cp + 1);
   
         if (expand) {          if (expand) {
                 *left = format_expand(ft, left0);                  *left = format_expand1(es, left0);
                 free(left0);                  free(left0);
                 *right = format_expand(ft, right0);                  *right = format_expand1(es, right0);
                 free(right0);                  free(right0);
         } else {          } else {
                 *left = left0;                  *left = left0;
Line 1634 
Line 1661 
   
 /* Build modifier list. */  /* Build modifier list. */
 static struct format_modifier *  static struct format_modifier *
 format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)  format_build_modifiers(struct format_expand_state *es, const char **s,
       u_int *count)
 {  {
         const char              *cp = *s, *end;          const char              *cp = *s, *end;
         struct format_modifier  *list = NULL;          struct format_modifier  *list = NULL;
Line 1702 
Line 1730 
   
                         argv = xcalloc(1, sizeof *argv);                          argv = xcalloc(1, sizeof *argv);
                         value = xstrndup(cp + 1, end - (cp + 1));                          value = xstrndup(cp + 1, end - (cp + 1));
                         argv[0] = format_expand(ft, value);                          argv[0] = format_expand1(es, value);
                         free(value);                          free(value);
                         argc = 1;                          argc = 1;
   
Line 1726 
Line 1754 
   
                         argv = xreallocarray (argv, argc + 1, sizeof *argv);                          argv = xreallocarray (argv, argc + 1, sizeof *argv);
                         value = xstrndup(cp, end - cp);                          value = xstrndup(cp, end - cp);
                         argv[argc++] = format_expand(ft, value);                          argv[argc++] = format_expand1(es, value);
                         free(value);                          free(value);
   
                         cp = end;                          cp = end;
Line 1807 
Line 1835 
   
 /* Loop over sessions. */  /* Loop over sessions. */
 static char *  static char *
 format_loop_sessions(struct format_tree *ft, const char *fmt)  format_loop_sessions(struct format_expand_state *es, const char *fmt)
 {  {
         struct client           *c = ft->client;          struct format_tree              *ft = es->ft;
         struct cmdq_item        *item = ft->item;          struct client                   *c = ft->client;
         struct format_tree      *nft;          struct cmdq_item                *item = ft->item;
         char                    *expanded, *value;          struct format_tree              *nft;
         size_t                   valuelen;          struct format_expand_state       next;
         struct session          *s;          char                            *expanded, *value;
           size_t                           valuelen;
           struct session                  *s;
   
         value = xcalloc(1, 1);          value = xcalloc(1, 1);
         valuelen = 1;          valuelen = 1;
   
         RB_FOREACH(s, sessions, &sessions) {          RB_FOREACH(s, sessions, &sessions) {
                 format_log(ft, "session loop: $%u", s->id);                  format_log(es, "session loop: $%u", s->id);
                 nft = format_create(c, item, FORMAT_NONE, ft->flags);                  nft = format_create(c, item, FORMAT_NONE, ft->flags);
                 nft->loop = ft->loop;                  format_defaults(next.ft, ft->c, s, NULL, NULL);
                 format_defaults(nft, ft->c, s, NULL, NULL);                  format_copy_state(&next, es, 0);
                 expanded = format_expand(nft, fmt);                  next.ft = nft;
                 format_free(nft);                  expanded = format_expand1(&next, fmt);
                   format_free(next.ft);
   
                 valuelen += strlen(expanded);                  valuelen += strlen(expanded);
                 value = xrealloc(value, valuelen);                  value = xrealloc(value, valuelen);
Line 1839 
Line 1870 
   
 /* Loop over windows. */  /* Loop over windows. */
 static char *  static char *
 format_loop_windows(struct format_tree *ft, const char *fmt)  format_loop_windows(struct format_expand_state *es, const char *fmt)
 {  {
         struct client           *c = ft->client;          struct format_tree              *ft = es->ft;
         struct cmdq_item        *item = ft->item;          struct client                   *c = ft->client;
         struct format_tree      *nft;          struct cmdq_item                *item = ft->item;
         char                    *all, *active, *use, *expanded, *value;          struct format_tree              *nft;
         size_t                   valuelen;          struct format_expand_state       next;
         struct winlink          *wl;          char                            *all, *active, *use, *expanded, *value;
         struct window           *w;          size_t                           valuelen;
           struct winlink                  *wl;
           struct window                   *w;
   
         if (ft->s == NULL) {          if (ft->s == NULL) {
                 format_log(ft, "window loop but no session");                  format_log(es, "window loop but no session");
                 return (NULL);                  return (NULL);
         }          }
   
         if (format_choose(ft, fmt, &all, &active, 0) != 0) {          if (format_choose(es, fmt, &all, &active, 0) != 0) {
                 all = xstrdup(fmt);                  all = xstrdup(fmt);
                 active = NULL;                  active = NULL;
         }          }
Line 1864 
Line 1897 
   
         RB_FOREACH(wl, winlinks, &ft->s->windows) {          RB_FOREACH(wl, winlinks, &ft->s->windows) {
                 w = wl->window;                  w = wl->window;
                 format_log(ft, "window loop: %u @%u", wl->idx, w->id);                  format_log(es, "window loop: %u @%u", wl->idx, w->id);
                 if (active != NULL && wl == ft->s->curw)                  if (active != NULL && wl == ft->s->curw)
                         use = active;                          use = active;
                 else                  else
                         use = all;                          use = all;
                 nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);                  nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
                 nft->loop = ft->loop;  
                 format_defaults(nft, ft->c, ft->s, wl, NULL);                  format_defaults(nft, ft->c, ft->s, wl, NULL);
                 expanded = format_expand(nft, use);                  format_copy_state(&next, es, 0);
                   next.ft = nft;
                   expanded = format_expand1(&next, use);
                 format_free(nft);                  format_free(nft);
   
                 valuelen += strlen(expanded);                  valuelen += strlen(expanded);
Line 1890 
Line 1924 
   
 /* Loop over panes. */  /* Loop over panes. */
 static char *  static char *
 format_loop_panes(struct format_tree *ft, const char *fmt)  format_loop_panes(struct format_expand_state *es, const char *fmt)
 {  {
         struct client           *c = ft->client;          struct format_tree              *ft = es->ft;
         struct cmdq_item        *item = ft->item;          struct client                   *c = ft->client;
         struct format_tree      *nft;          struct cmdq_item                *item = ft->item;
         char                    *all, *active, *use, *expanded, *value;          struct format_tree              *nft;
         size_t                   valuelen;          struct format_expand_state       next;
         struct window_pane      *wp;          char                            *all, *active, *use, *expanded, *value;
           size_t                           valuelen;
           struct window_pane              *wp;
   
         if (ft->w == NULL) {          if (ft->w == NULL) {
                 format_log(ft, "pane loop but no window");                  format_log(es, "pane loop but no window");
                 return (NULL);                  return (NULL);
         }          }
   
         if (format_choose(ft, fmt, &all, &active, 0) != 0) {          if (format_choose(es, fmt, &all, &active, 0) != 0) {
                 all = xstrdup(fmt);                  all = xstrdup(fmt);
                 active = NULL;                  active = NULL;
         }          }
Line 1913 
Line 1949 
         valuelen = 1;          valuelen = 1;
   
         TAILQ_FOREACH(wp, &ft->w->panes, entry) {          TAILQ_FOREACH(wp, &ft->w->panes, entry) {
                 format_log(ft, "pane loop: %%%u", wp->id);                  format_log(es, "pane loop: %%%u", wp->id);
                 if (active != NULL && wp == ft->w->active)                  if (active != NULL && wp == ft->w->active)
                         use = active;                          use = active;
                 else                  else
                         use = all;                          use = all;
                 nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);                  nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
                 nft->loop = ft->loop;  
                 format_defaults(nft, ft->c, ft->s, ft->wl, wp);                  format_defaults(nft, ft->c, ft->s, ft->wl, wp);
                 expanded = format_expand(nft, use);                  format_copy_state(&next, es, 0);
                   next.ft = nft;
                   expanded = format_expand1(&next, use);
                 format_free(nft);                  format_free(nft);
   
                 valuelen += strlen(expanded);                  valuelen += strlen(expanded);
Line 1938 
Line 1975 
 }  }
   
 static char *  static char *
 format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,  format_replace_expression(struct format_modifier *mexp,
     const char *copy)      struct format_expand_state *es, const char *copy)
 {  {
         int              argc = mexp->argc;          int                      argc = mexp->argc;
         const char      *errstr;          const char              *errstr;
         char            *endch, *value, *left = NULL, *right = NULL;          char                    *endch, *value, *left = NULL, *right = NULL;
         int              use_fp = 0;          int                      use_fp = 0;
         u_int            prec = 0;          u_int                    prec = 0;
         double           mleft, mright, result;          double                   mleft, mright, result;
         enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;          enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;
   
         if (strcmp(mexp->argv[0], "+") == 0)          if (strcmp(mexp->argv[0], "+") == 0)
Line 1961 
Line 1998 
             strcmp(mexp->argv[0], "m") == 0)              strcmp(mexp->argv[0], "m") == 0)
                 operator = MODULUS;                  operator = MODULUS;
         else {          else {
                 format_log(ft, "expression has no valid operator: '%s'",                  format_log(es, "expression has no valid operator: '%s'",
                     mexp->argv[0]);                      mexp->argv[0]);
                 goto fail;                  goto fail;
         }          }
Line 1976 
Line 2013 
         if (argc >= 3) {          if (argc >= 3) {
                 prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);                  prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
                 if (errstr != NULL) {                  if (errstr != NULL) {
                         format_log (ft, "expression precision %s: %s", errstr,                          format_log(es, "expression precision %s: %s", errstr,
                             mexp->argv[2]);                              mexp->argv[2]);
                         goto fail;                          goto fail;
                 }                  }
         }          }
   
         if (format_choose(ft, copy, &left, &right, 1) != 0) {          if (format_choose(es, copy, &left, &right, 1) != 0) {
                 format_log(ft, "expression syntax error");                  format_log(es, "expression syntax error");
                 goto fail;                  goto fail;
         }          }
   
         mleft = strtod(left, &endch);          mleft = strtod(left, &endch);
         if (*endch != '\0') {          if (*endch != '\0') {
                 format_log(ft, "expression left side is invalid: %s", left);                  format_log(es, "expression left side is invalid: %s", left);
                 goto fail;                  goto fail;
         }          }
   
         mright = strtod(right, &endch);          mright = strtod(right, &endch);
         if (*endch != '\0') {          if (*endch != '\0') {
                 format_log(ft, "expression right side is invalid: %s", right);                  format_log(es, "expression right side is invalid: %s", right);
                 goto fail;                  goto fail;
         }          }
   
Line 2003 
Line 2040 
                 mleft = (long long)mleft;                  mleft = (long long)mleft;
                 mright = (long long)mright;                  mright = (long long)mright;
         }          }
         format_log(ft, "expression left side is: %.*f", prec, mleft);          format_log(es, "expression left side is: %.*f", prec, mleft);
         format_log(ft, "expression right side is:  %.*f", prec, mright);          format_log(es, "expression right side is:  %.*f", prec, mright);
   
         switch (operator) {          switch (operator) {
         case ADD:          case ADD:
Line 2027 
Line 2064 
                 xasprintf(&value, "%.*f", prec, result);                  xasprintf(&value, "%.*f", prec, result);
         else          else
                 xasprintf(&value, "%.*f", prec, (double)(long long)result);                  xasprintf(&value, "%.*f", prec, (double)(long long)result);
         format_log(ft, "expression result is %s", value);          format_log(es, "expression result is %s", value);
   
         free(right);          free(right);
         free(left);          free(left);
Line 2041 
Line 2078 
   
 /* Replace a key. */  /* Replace a key. */
 static int  static int
 format_replace(struct format_tree *ft, const char *key, size_t keylen,  format_replace(struct format_expand_state *es, const char *key, size_t keylen,
     char **buf, size_t *len, size_t *off)      char **buf, size_t *len, size_t *off)
 {  {
         struct window_pane       *wp = ft->wp;          struct format_tree               *ft = es->ft;
         const char               *errptr, *copy, *cp, *marker = NULL;          struct window_pane               *wp = ft->wp;
         const char               *time_format = NULL;          const char                       *errptr, *copy, *cp, *marker = NULL;
         char                     *copy0, *condition, *found, *new;          const char                       *time_format = NULL;
         char                     *value, *left, *right;          char                             *copy0, *condition, *found, *new;
         size_t                    valuelen;          char                             *value, *left, *right;
         int                       modifiers = 0, limit = 0, width = 0, j;          size_t                            valuelen;
         struct format_modifier   *list, *fm, *cmp = NULL, *search = NULL;          int                               modifiers = 0, limit = 0, width = 0;
         struct format_modifier  **sub = NULL, *mexp = NULL;          int                               j;
         u_int                     i, count, nsub = 0;          struct format_modifier           *list, *cmp = NULL, *search = NULL;
           struct format_modifier          **sub = NULL, *mexp = NULL, *fm;
           u_int                             i, count, nsub = 0;
           struct format_expand_state        next;
   
         /* Make a copy of the key. */          /* Make a copy of the key. */
         copy = copy0 = xstrndup(key, keylen);          copy = copy0 = xstrndup(key, keylen);
   
         /* Process modifier list. */          /* Process modifier list. */
         list = format_build_modifiers(ft, &copy, &count);          list = format_build_modifiers(es, &copy, &count);
         for (i = 0; i < count; i++) {          for (i = 0; i < count; i++) {
                 fm = &list[i];                  fm = &list[i];
                 if (format_logging(ft)) {                  if (format_logging(ft)) {
                         format_log(ft, "modifier %u is %s", i, fm->modifier);                          format_log(es, "modifier %u is %s", i, fm->modifier);
                         for (j = 0; j < fm->argc; j++) {                          for (j = 0; j < fm->argc; j++) {
                                 format_log(ft, "modifier %u argument %d: %s", i,                                  format_log(es, "modifier %u argument %d: %s", i,
                                     j, fm->argv[j]);                                      j, fm->argv[j]);
                         }                          }
                 }                  }
Line 2169 
Line 2209 
   
         /* Is this a loop, comparison or condition? */          /* Is this a loop, comparison or condition? */
         if (modifiers & FORMAT_SESSIONS) {          if (modifiers & FORMAT_SESSIONS) {
                 value = format_loop_sessions(ft, copy);                  value = format_loop_sessions(es, copy);
                 if (value == NULL)                  if (value == NULL)
                         goto fail;                          goto fail;
         } else if (modifiers & FORMAT_WINDOWS) {          } else if (modifiers & FORMAT_WINDOWS) {
                 value = format_loop_windows(ft, copy);                  value = format_loop_windows(es, copy);
                 if (value == NULL)                  if (value == NULL)
                         goto fail;                          goto fail;
         } else if (modifiers & FORMAT_PANES) {          } else if (modifiers & FORMAT_PANES) {
                 value = format_loop_panes(ft, copy);                  value = format_loop_panes(es, copy);
                 if (value == NULL)                  if (value == NULL)
                         goto fail;                          goto fail;
         } else if (search != NULL) {          } else if (search != NULL) {
                 /* Search in pane. */                  /* Search in pane. */
                 new = format_expand(ft, copy);                  new = format_expand1(es, copy);
                 if (wp == NULL) {                  if (wp == NULL) {
                         format_log(ft, "search '%s' but no pane", new);                          format_log(es, "search '%s' but no pane", new);
                         value = xstrdup("0");                          value = xstrdup("0");
                 } else {                  } else {
                         format_log(ft, "search '%s' pane %%%u", new,  wp->id);                          format_log(es, "search '%s' pane %%%u", new, wp->id);
                         value = format_search(fm, wp, new);                          value = format_search(fm, wp, new);
                 }                  }
                 free(new);                  free(new);
         } else if (cmp != NULL) {          } else if (cmp != NULL) {
                 /* Comparison of left and right. */                  /* Comparison of left and right. */
                 if (format_choose(ft, copy, &left, &right, 1) != 0) {                  if (format_choose(es, copy, &left, &right, 1) != 0) {
                         format_log(ft, "compare %s syntax error: %s",                          format_log(es, "compare %s syntax error: %s",
                             cmp->modifier, copy);                              cmp->modifier, copy);
                         goto fail;                          goto fail;
                 }                  }
                 format_log(ft, "compare %s left is: %s", cmp->modifier, left);                  format_log(es, "compare %s left is: %s", cmp->modifier, left);
                 format_log(ft, "compare %s right is: %s", cmp->modifier, right);                  format_log(es, "compare %s right is: %s", cmp->modifier, right);
   
                 if (strcmp(cmp->modifier, "||") == 0) {                  if (strcmp(cmp->modifier, "||") == 0) {
                         if (format_true(left) || format_true(right))                          if (format_true(left) || format_true(right))
Line 2250 
Line 2290 
                 /* Conditional: check first and choose second or third. */                  /* Conditional: check first and choose second or third. */
                 cp = format_skip(copy + 1, ",");                  cp = format_skip(copy + 1, ",");
                 if (cp == NULL) {                  if (cp == NULL) {
                         format_log(ft, "condition syntax error: %s", copy + 1);                          format_log(es, "condition syntax error: %s", copy + 1);
                         goto fail;                          goto fail;
                 }                  }
                 condition = xstrndup(copy + 1, cp - (copy + 1));                  condition = xstrndup(copy + 1, cp - (copy + 1));
                 format_log(ft, "condition is: %s", condition);                  format_log(es, "condition is: %s", condition);
   
                 found = format_find(ft, condition, modifiers, time_format);                  found = format_find(ft, condition, modifiers, time_format);
                 if (found == NULL) {                  if (found == NULL) {
Line 2263 
Line 2303 
                          * the expansion doesn't have any effect, then assume                           * the expansion doesn't have any effect, then assume
                          * false.                           * false.
                          */                           */
                         found = format_expand(ft, condition);                          found = format_expand1(es, condition);
                         if (strcmp(found, condition) == 0) {                          if (strcmp(found, condition) == 0) {
                                 free(found);                                  free(found);
                                 found = xstrdup("");                                  found = xstrdup("");
                                 format_log(ft, "condition '%s' found: %s",                                  format_log(es, "condition '%s' found: %s",
                                     condition, found);                                      condition, found);
                         } else {                          } else {
                                 format_log(ft,                                  format_log(es,
                                     "condition '%s' not found; assuming false",                                      "condition '%s' not found; assuming false",
                                     condition);                                      condition);
                         }                          }
                 } else                  } else
                         format_log(ft, "condition '%s' found", condition);                          format_log(es, "condition '%s' found", condition);
   
                 if (format_choose(ft, cp + 1, &left, &right, 0) != 0) {                  if (format_choose(es, cp + 1, &left, &right, 0) != 0) {
                         format_log(ft, "condition '%s' syntax error: %s",                          format_log(es, "condition '%s' syntax error: %s",
                             condition, cp + 1);                              condition, cp + 1);
                         free(found);                          free(found);
                         goto fail;                          goto fail;
                 }                  }
                 if (format_true(found)) {                  if (format_true(found)) {
                         format_log(ft, "condition '%s' is true", condition);                          format_log(es, "condition '%s' is true", condition);
                         value = format_expand(ft, left);                          value = format_expand1(es, left);
                 } else {                  } else {
                         format_log(ft, "condition '%s' is false", condition);                          format_log(es, "condition '%s' is false", condition);
                         value = format_expand(ft, right);                          value = format_expand1(es, right);
                 }                  }
                 free(right);                  free(right);
                 free(left);                  free(left);
Line 2296 
Line 2336 
                 free(condition);                  free(condition);
                 free(found);                  free(found);
         } else if (mexp != NULL) {          } else if (mexp != NULL) {
                 value = format_replace_expression(mexp, ft, copy);                  value = format_replace_expression(mexp, es, copy);
                 if (value == NULL)                  if (value == NULL)
                         value = xstrdup("");                          value = xstrdup("");
         } else {          } else {
                 if (strstr(copy, "#{") != 0) {                  if (strstr(copy, "#{") != 0) {
                         format_log(ft, "expanding inner format '%s'", copy);                          format_log(es, "expanding inner format '%s'", copy);
                         value = format_expand(ft, copy);                          value = format_expand1(es, copy);
                 } else {                  } else {
                         value = format_find(ft, copy, modifiers, time_format);                          value = format_find(ft, copy, modifiers, time_format);
                         if (value == NULL) {                          if (value == NULL) {
                                 format_log(ft, "format '%s' not found", copy);                                  format_log(es, "format '%s' not found", copy);
                                 value = xstrdup("");                                  value = xstrdup("");
                         } else                          } else {
                                 format_log(ft, "format '%s' found: %s", copy, value);                                  format_log(es, "format '%s' found: %s", copy,
                                       value);
                           }
                 }                  }
         }          }
   
 done:  done:
         /* Expand again if required. */          /* Expand again if required. */
         if (modifiers & FORMAT_EXPAND) {          if (modifiers & FORMAT_EXPAND) {
                 new = format_expand(ft, value);                  new = format_expand1(es, value);
                 free(value);                  free(value);
                 value = new;                  value = new;
         } else if (modifiers & FORMAT_EXPANDTIME) {          } else if (modifiers & FORMAT_EXPANDTIME) {
                 new = format_expand_time(ft, value);                  format_copy_state(&next, es, FORMAT_EXPAND_TIME);
                   new = format_expand1(&next, value);
                 free(value);                  free(value);
                 value = new;                  value = new;
         }          }
   
         /* Perform substitution if any. */          /* Perform substitution if any. */
         for (i = 0; i < nsub; i++) {          for (i = 0; i < nsub; i++) {
                 left = format_expand(ft, sub[i]->argv[0]);                  left = format_expand1(es, sub[i]->argv[0]);
                 right = format_expand(ft, sub[i]->argv[1]);                  right = format_expand1(es, sub[i]->argv[1]);
                 new = format_sub(sub[i], value, left, right);                  new = format_sub(sub[i], value, left, right);
                 format_log(ft, "substitute '%s' to '%s': %s", left, right, new);                  format_log(es, "substitute '%s' to '%s': %s", left, right, new);
                 free(value);                  free(value);
                 value = new;                  value = new;
                 free(right);                  free(right);
Line 2347 
Line 2390 
                         free(value);                          free(value);
                         value = new;                          value = new;
                 }                  }
                 format_log(ft, "applied length limit %d: %s", limit, value);                  format_log(es, "applied length limit %d: %s", limit, value);
         } else if (limit < 0) {          } else if (limit < 0) {
                 new = format_trim_right(value, -limit);                  new = format_trim_right(value, -limit);
                 if (marker != NULL && strcmp(new, value) != 0) {                  if (marker != NULL && strcmp(new, value) != 0) {
Line 2357 
Line 2400 
                         free(value);                          free(value);
                         value = new;                          value = new;
                 }                  }
                 format_log(ft, "applied length limit %d: %s", limit, value);                  format_log(es, "applied length limit %d: %s", limit, value);
         }          }
   
         /* Pad the value if needed. */          /* Pad the value if needed. */
Line 2365 
Line 2408 
                 new = utf8_padcstr(value, width);                  new = utf8_padcstr(value, width);
                 free(value);                  free(value);
                 value = new;                  value = new;
                 format_log(ft, "applied padding width %d: %s", width, value);                  format_log(es, "applied padding width %d: %s", width, value);
         } else if (width < 0) {          } else if (width < 0) {
                 new = utf8_rpadcstr(value, -width);                  new = utf8_rpadcstr(value, -width);
                 free(value);                  free(value);
                 value = new;                  value = new;
                 format_log(ft, "applied padding width %d: %s", width, value);                  format_log(es, "applied padding width %d: %s", width, value);
         }          }
   
         /* Replace with the length if needed. */          /* Replace with the length if needed. */
Line 2378 
Line 2421 
                 xasprintf(&new, "%zu", strlen(value));                  xasprintf(&new, "%zu", strlen(value));
                 free(value);                  free(value);
                 value = new;                  value = new;
                 format_log(ft, "replacing with length: %s", new);                  format_log(es, "replacing with length: %s", new);
         }          }
   
         /* Expand the buffer and copy in the value. */          /* Expand the buffer and copy in the value. */
Line 2390 
Line 2433 
         memcpy(*buf + *off, value, valuelen);          memcpy(*buf + *off, value, valuelen);
         *off += valuelen;          *off += valuelen;
   
         format_log(ft, "replaced '%s' with '%s'", copy0, value);          format_log(es, "replaced '%s' with '%s'", copy0, value);
         free(value);          free(value);
   
         free(sub);          free(sub);
Line 2399 
Line 2442 
         return (0);          return (0);
   
 fail:  fail:
         format_log(ft, "failed %s", copy0);          format_log(es, "failed %s", copy0);
   
         free(sub);          free(sub);
         format_free_modifiers(list, count);          format_free_modifiers(list, count);
Line 2409 
Line 2452 
   
 /* Expand keys in a template. */  /* Expand keys in a template. */
 static char *  static char *
 format_expand1(struct format_tree *ft, const char *fmt, int time)  format_expand1(struct format_expand_state *es, const char *fmt)
 {  {
         char            *buf, *out, *name;          struct format_tree      *ft = es->ft;
         const char      *ptr, *s;          char                    *buf, *out, *name;
         size_t           off, len, n, outlen;          const char              *ptr, *s;
         int              ch, brackets;          size_t                   off, len, n, outlen;
         struct tm       *tm;          int                      ch, brackets;
         char             expanded[8192];          struct tm               *tm;
           char                     expanded[8192];
   
         if (fmt == NULL || *fmt == '\0')          if (fmt == NULL || *fmt == '\0')
                 return (xstrdup(""));                  return (xstrdup(""));
   
         if (ft->loop == FORMAT_LOOP_LIMIT)          if (es->loop == FORMAT_LOOP_LIMIT)
                 return (xstrdup(""));                  return (xstrdup(""));
         ft->loop++;          es->loop++;
   
         format_log(ft, "expanding format: %s", fmt);          format_log(es, "expanding format: %s", fmt);
   
         if (time) {          if (es->flags & FORMAT_EXPAND_TIME) {
                 tm = localtime(&ft->time);                  if (es->time == 0)
                           es->time = time(NULL);
                   tm = localtime(&es->time);
                 if (strftime(expanded, sizeof expanded, fmt, tm) == 0) {                  if (strftime(expanded, sizeof expanded, fmt, tm) == 0) {
                         format_log(ft, "format is too long");                          format_log(es, "format is too long");
                         return (xstrdup(""));                          return (xstrdup(""));
                 }                  }
                 if (format_logging(ft) && strcmp(expanded, fmt) != 0)                  if (format_logging(ft) && strcmp(expanded, fmt) != 0)
                         format_log(ft, "after time expanded: %s", expanded);                          format_log(es, "after time expanded: %s", expanded);
                 fmt = expanded;                  fmt = expanded;
         }          }
   
Line 2468 
Line 2514 
                         n = ptr - fmt;                          n = ptr - fmt;
   
                         name = xstrndup(fmt, n);                          name = xstrndup(fmt, n);
                         format_log(ft, "found #(): %s", name);                          format_log(es, "found #(): %s", name);
   
                         if (ft->flags & FORMAT_NOJOBS) {                          if ((ft->flags & FORMAT_NOJOBS) ||
                               (es->flags & FORMAT_EXPAND_NOJOBS)) {
                                 out = xstrdup("");                                  out = xstrdup("");
                                 format_log(ft, "#() is disabled");                                  format_log(es, "#() is disabled");
                         } else {                          } else {
                                 out = format_job_get(ft, name);                                  out = format_job_get(es, name);
                                 format_log(ft, "#() result: %s", out);                                  format_log(es, "#() result: %s", out);
                         }                          }
                         free(name);                          free(name);
   
Line 2497 
Line 2544 
                                 break;                                  break;
                         n = ptr - fmt;                          n = ptr - fmt;
   
                         format_log(ft, "found #{}: %.*s", (int)n, fmt);                          format_log(es, "found #{}: %.*s", (int)n, fmt);
                         if (format_replace(ft, fmt, n, &buf, &len, &off) != 0)                          if (format_replace(es, fmt, n, &buf, &len, &off) != 0)
                                 break;                                  break;
                         fmt += n + 1;                          fmt += n + 1;
                         continue;                          continue;
                 case '}':                  case '}':
                 case '#':                  case '#':
                 case ',':                  case ',':
                         format_log(ft, "found #%c", ch);                          format_log(es, "found #%c", ch);
                         while (len - off < 2) {                          while (len - off < 2) {
                                 buf = xreallocarray(buf, 2, len);                                  buf = xreallocarray(buf, 2, len);
                                 len *= 2;                                  len *= 2;
Line 2528 
Line 2575 
                                 continue;                                  continue;
                         }                          }
                         n = strlen(s);                          n = strlen(s);
                         format_log(ft, "found #%c: %s", ch, s);                          format_log(es, "found #%c: %s", ch, s);
                         if (format_replace(ft, s, n, &buf, &len, &off) != 0)                          if (format_replace(es, s, n, &buf, &len, &off) != 0)
                                 break;                                  break;
                         continue;                          continue;
                 }                  }
Line 2538 
Line 2585 
         }          }
         buf[off] = '\0';          buf[off] = '\0';
   
         format_log(ft, "result is: %s", buf);          format_log(es, "result is: %s", buf);
         ft->loop--;          es->loop--;
   
         return (buf);          return (buf);
 }  }
Line 2548 
Line 2595 
 char *  char *
 format_expand_time(struct format_tree *ft, const char *fmt)  format_expand_time(struct format_tree *ft, const char *fmt)
 {  {
         return (format_expand1(ft, fmt, 1));          struct format_expand_state      es;
   
           memset(&es, 0, sizeof es);
           es.ft = ft;
           es.flags = FORMAT_EXPAND_TIME;
           return (format_expand1(&es, fmt));
 }  }
   
 /* Expand keys in a template. */  /* Expand keys in a template. */
 char *  char *
 format_expand(struct format_tree *ft, const char *fmt)  format_expand(struct format_tree *ft, const char *fmt)
 {  {
         return (format_expand1(ft, fmt, 0));          struct format_expand_state      es;
   
           memset(&es, 0, sizeof es);
           es.ft = ft;
           es.flags = 0;
           return (format_expand1(&es, fmt));
 }  }
   
 /* Expand a single string. */  /* Expand a single string. */

Legend:
Removed from v.1.262  
changed lines
  Added in v.1.263