Coverage Report

Created: 2025-12-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/names.c
Line
Count
Source
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <ctype.h>
22
#include <libgen.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "tmux.h"
27
28
static void  name_time_callback(int, short, void *);
29
static int   name_time_expired(struct window *, struct timeval *);
30
31
static char *format_window_name(struct window *);
32
33
static void
34
name_time_callback(__unused int fd, __unused short events, void *arg)
35
0
{
36
0
  struct window *w = arg;
37
38
  /* The event loop will call check_window_name for us on the way out. */
39
0
  log_debug("@%u name timer expired", w->id);
40
0
}
41
42
static int
43
name_time_expired(struct window *w, struct timeval *tv)
44
0
{
45
0
  struct timeval  offset;
46
47
0
  timersub(tv, &w->name_time, &offset);
48
0
  if (offset.tv_sec != 0 || offset.tv_usec > NAME_INTERVAL)
49
0
    return (0);
50
0
  return (NAME_INTERVAL - offset.tv_usec);
51
0
}
52
53
void
54
check_window_name(struct window *w)
55
0
{
56
0
  struct timeval   tv, next;
57
0
  char    *name;
58
0
  int    left;
59
60
0
  if (w->active == NULL)
61
0
    return;
62
63
0
  if (!options_get_number(w->options, "automatic-rename"))
64
0
    return;
65
66
0
  if (~w->active->flags & PANE_CHANGED) {
67
0
    log_debug("@%u active pane not changed", w->id);
68
0
    return;
69
0
  }
70
0
  log_debug("@%u active pane changed", w->id);
71
72
0
  gettimeofday(&tv, NULL);
73
0
  left = name_time_expired(w, &tv);
74
0
  if (left != 0) {
75
0
    if (!event_initialized(&w->name_event))
76
0
      evtimer_set(&w->name_event, name_time_callback, w);
77
0
    if (!evtimer_pending(&w->name_event, NULL)) {
78
0
      log_debug("@%u name timer queued (%d left)", w->id,
79
0
          left);
80
0
      timerclear(&next);
81
0
      next.tv_usec = left;
82
0
      event_add(&w->name_event, &next);
83
0
    } else {
84
0
      log_debug("@%u name timer already queued (%d left)",
85
0
          w->id, left);
86
0
    }
87
0
    return;
88
0
  }
89
0
  memcpy(&w->name_time, &tv, sizeof w->name_time);
90
0
  if (event_initialized(&w->name_event))
91
0
    evtimer_del(&w->name_event);
92
93
0
  w->active->flags &= ~PANE_CHANGED;
94
95
0
  name = format_window_name(w);
96
0
  if (strcmp(name, w->name) != 0) {
97
0
    log_debug("@%u new name %s (was %s)", w->id, name, w->name);
98
0
    window_set_name(w, name);
99
0
    server_redraw_window_borders(w);
100
0
    server_status_window(w);
101
0
  } else
102
0
    log_debug("@%u name not changed (still %s)", w->id, w->name);
103
104
0
  free(name);
105
0
}
106
107
char *
108
default_window_name(struct window *w)
109
0
{
110
0
  char  *cmd, *s;
111
112
0
  if (w->active == NULL)
113
0
    return (xstrdup(""));
114
0
  cmd = cmd_stringify_argv(w->active->argc, w->active->argv);
115
0
  if (cmd != NULL && *cmd != '\0')
116
0
    s = parse_window_name(cmd);
117
0
  else
118
0
    s = parse_window_name(w->active->shell);
119
0
  free(cmd);
120
0
  return (s);
121
0
}
122
123
static char *
124
format_window_name(struct window *w)
125
0
{
126
0
  struct format_tree  *ft;
127
0
  const char    *fmt;
128
0
  char      *name;
129
130
0
  ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, 0);
131
0
  format_defaults_window(ft, w);
132
0
  format_defaults_pane(ft, w->active);
133
134
0
  fmt = options_get_string(w->options, "automatic-rename-format");
135
0
  name = format_expand(ft, fmt);
136
137
0
  format_free(ft);
138
0
  return (name);
139
0
}
140
141
char *
142
parse_window_name(const char *in)
143
0
{
144
0
  char  *copy, *name, *ptr;
145
146
0
  name = copy = xstrdup(in);
147
0
  if (*name == '"')
148
0
    name++;
149
0
  name[strcspn(name, "\"")] = '\0';
150
151
0
  if (strncmp(name, "exec ", (sizeof "exec ") - 1) == 0)
152
0
    name = name + (sizeof "exec ") - 1;
153
154
0
  while (*name == ' ' || *name == '-')
155
0
    name++;
156
0
  if ((ptr = strchr(name, ' ')) != NULL)
157
0
    *ptr = '\0';
158
159
0
  if (*name != '\0') {
160
0
    ptr = name + strlen(name) - 1;
161
0
    while (ptr > name &&
162
0
        !isalnum((u_char)*ptr) &&
163
0
        !ispunct((u_char)*ptr))
164
0
      *ptr-- = '\0';
165
0
  }
166
167
0
  if (*name == '/')
168
0
    name = basename(name);
169
0
  name = xstrdup(name);
170
0
  free(copy);
171
0
  return (name);
172
0
}