mirror of
https://github.com/tmux/tmux.git
synced 2025-09-02 05:21:10 +00:00
Move the jobs output cache into the formats code so that #() work more
generally (for example, again working in set-titles-string).
This commit is contained in:
192
format.c
192
format.c
@ -35,6 +35,9 @@
|
||||
* string.
|
||||
*/
|
||||
|
||||
void format_job_callback(struct job *);
|
||||
const char *format_job_get(struct format_tree *, const char *);
|
||||
|
||||
int format_replace(struct format_tree *, const char *, size_t, char **,
|
||||
size_t *, size_t *);
|
||||
char *format_time_string(time_t);
|
||||
@ -46,6 +49,32 @@ void format_defaults_client(struct format_tree *, struct client *);
|
||||
void format_defaults_winlink(struct format_tree *, struct session *,
|
||||
struct winlink *);
|
||||
|
||||
/* Entry in format job tree. */
|
||||
struct format_job {
|
||||
const char *cmd;
|
||||
|
||||
time_t last;
|
||||
char *out;
|
||||
|
||||
struct job *job;
|
||||
int status;
|
||||
|
||||
RB_ENTRY(format_job) entry;
|
||||
};
|
||||
|
||||
/* Format job tree. */
|
||||
int format_job_cmp(struct format_job *, struct format_job *);
|
||||
RB_HEAD(format_job_tree, format_job) format_jobs = RB_INITIALIZER();
|
||||
RB_PROTOTYPE(format_job_tree, format_job, entry, format_job_cmp);
|
||||
RB_GENERATE(format_job_tree, format_job, entry, format_job_cmp);
|
||||
|
||||
/* Format job tree comparison function. */
|
||||
int
|
||||
format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
{
|
||||
return (strcmp(fj1->cmd, fj2->cmd));
|
||||
}
|
||||
|
||||
/* Entry in format tree. */
|
||||
struct format_entry {
|
||||
char *key;
|
||||
@ -54,22 +83,22 @@ struct format_entry {
|
||||
RB_ENTRY(format_entry) entry;
|
||||
};
|
||||
|
||||
/* Tree of format entries. */
|
||||
/* Format entry tree. */
|
||||
struct format_tree {
|
||||
struct window *w;
|
||||
struct session *s;
|
||||
|
||||
RB_HEAD(format_rb_tree, format_entry) tree;
|
||||
int status;
|
||||
|
||||
RB_HEAD(format_entry_tree, format_entry) tree;
|
||||
};
|
||||
int format_entry_cmp(struct format_entry *, struct format_entry *);
|
||||
RB_PROTOTYPE(format_entry_tree, format_entry, entry, format_entry_cmp);
|
||||
RB_GENERATE(format_entry_tree, format_entry, entry, format_entry_cmp);
|
||||
|
||||
/* Format key-value replacement entry. */
|
||||
int format_cmp(struct format_entry *, struct format_entry *);
|
||||
RB_PROTOTYPE(format_rb_tree, format_entry, entry, format_cmp);
|
||||
RB_GENERATE(format_rb_tree, format_entry, entry, format_cmp);
|
||||
|
||||
/* Format tree comparison function. */
|
||||
/* Format entry tree comparison function. */
|
||||
int
|
||||
format_cmp(struct format_entry *fe1, struct format_entry *fe2)
|
||||
format_entry_cmp(struct format_entry *fe1, struct format_entry *fe2)
|
||||
{
|
||||
return (strcmp(fe1->key, fe2->key));
|
||||
}
|
||||
@ -134,15 +163,118 @@ const char *format_lower[] = {
|
||||
NULL /* z */
|
||||
};
|
||||
|
||||
/* Format job callback. */
|
||||
void
|
||||
format_job_callback(struct job *job)
|
||||
{
|
||||
struct format_job *fj = job->data;
|
||||
char *line, *buf;
|
||||
size_t len;
|
||||
struct client *c;
|
||||
|
||||
fj->job = NULL;
|
||||
free(fj->out);
|
||||
|
||||
if (WIFEXITED(job->status) && WEXITSTATUS(job->status) != 0) {
|
||||
xasprintf(&fj->out, "<'%s' exited with %d>", fj->cmd,
|
||||
WEXITSTATUS(job->status));
|
||||
return;
|
||||
}
|
||||
if (WIFSIGNALED(job->status)) {
|
||||
xasprintf(&fj->out, "<'%s' got signal %d>", fj->cmd,
|
||||
WTERMSIG(job->status));
|
||||
return;
|
||||
}
|
||||
|
||||
buf = NULL;
|
||||
if ((line = evbuffer_readline(job->event->input)) == NULL) {
|
||||
len = EVBUFFER_LENGTH(job->event->input);
|
||||
buf = xmalloc(len + 1);
|
||||
if (len != 0)
|
||||
memcpy(buf, EVBUFFER_DATA(job->event->input), len);
|
||||
buf[len] = '\0';
|
||||
} else
|
||||
buf = line;
|
||||
fj->out = buf;
|
||||
|
||||
if (fj->status) {
|
||||
TAILQ_FOREACH(c, &clients, entry)
|
||||
server_status_client(c);
|
||||
fj->status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find a job. */
|
||||
const char *
|
||||
format_job_get(struct format_tree *ft, const char *cmd)
|
||||
{
|
||||
struct format_job fj0, *fj;
|
||||
|
||||
fj0.cmd = cmd;
|
||||
if ((fj = RB_FIND(format_job_tree, &format_jobs, &fj0)) == NULL)
|
||||
{
|
||||
fj = xcalloc(1, sizeof *fj);
|
||||
fj->cmd = xstrdup(cmd);
|
||||
fj->status = ft->status;
|
||||
|
||||
xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
|
||||
|
||||
RB_INSERT(format_job_tree, &format_jobs, fj);
|
||||
}
|
||||
|
||||
if (fj->job == NULL && fj->last != time(NULL)) {
|
||||
fj->job = job_run(fj->cmd, NULL, -1, format_job_callback,
|
||||
NULL, fj);
|
||||
if (fj->job == NULL) {
|
||||
free(fj->out);
|
||||
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
|
||||
}
|
||||
}
|
||||
fj->last = time(NULL);
|
||||
|
||||
return (fj->out);
|
||||
}
|
||||
|
||||
/* Remove old jobs. */
|
||||
void
|
||||
format_clean(void)
|
||||
{
|
||||
struct format_job *fj, *fj1;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
RB_FOREACH_SAFE(fj, format_job_tree, &format_jobs, fj1) {
|
||||
if (fj->last > now || now - fj->last < 3600)
|
||||
continue;
|
||||
RB_REMOVE(format_job_tree, &format_jobs, fj);
|
||||
|
||||
if (fj->job != NULL)
|
||||
job_free(fj->job);
|
||||
|
||||
free((void*)fj->cmd);
|
||||
free(fj->out);
|
||||
|
||||
free(fj);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new tree. */
|
||||
struct format_tree *
|
||||
format_create(void)
|
||||
{
|
||||
return (format_create_status(0));
|
||||
}
|
||||
|
||||
/* Create a new tree for the status line. */
|
||||
struct format_tree *
|
||||
format_create_status(int status)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char host[HOST_NAME_MAX+1], *ptr;
|
||||
char host[HOST_NAME_MAX + 1], *ptr;
|
||||
|
||||
ft = xcalloc(1, sizeof *ft);
|
||||
RB_INIT(&ft->tree);
|
||||
ft->status = status;
|
||||
|
||||
if (gethostname(host, sizeof host) == 0) {
|
||||
format_add(ft, "host", "%s", host);
|
||||
@ -160,8 +292,8 @@ format_free(struct format_tree *ft)
|
||||
{
|
||||
struct format_entry *fe, *fe1;
|
||||
|
||||
RB_FOREACH_SAFE(fe, format_rb_tree, &ft->tree, fe1) {
|
||||
RB_REMOVE(format_rb_tree, &ft->tree, fe);
|
||||
RB_FOREACH_SAFE(fe, format_entry_tree, &ft->tree, fe1) {
|
||||
RB_REMOVE(format_entry_tree, &ft->tree, fe);
|
||||
free(fe->value);
|
||||
free(fe->key);
|
||||
free(fe);
|
||||
@ -185,7 +317,7 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
|
||||
xvasprintf(&fe->value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fe_now = RB_INSERT(format_rb_tree, &ft->tree, fe);
|
||||
fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
|
||||
if (fe_now != NULL) {
|
||||
free(fe_now->value);
|
||||
fe_now->value = fe->value;
|
||||
@ -224,7 +356,7 @@ format_find(struct format_tree *ft, const char *key)
|
||||
}
|
||||
|
||||
fe_find.key = (char *) key;
|
||||
fe = RB_FIND(format_rb_tree, &ft->tree, &fe_find);
|
||||
fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
|
||||
if (fe == NULL)
|
||||
return (NULL);
|
||||
return (fe->value);
|
||||
@ -358,9 +490,9 @@ format_expand_time(struct format_tree *ft, const char *fmt, time_t t)
|
||||
char *
|
||||
format_expand(struct format_tree *ft, const char *fmt)
|
||||
{
|
||||
char *buf;
|
||||
char *buf, *tmp;
|
||||
const char *ptr, *s;
|
||||
size_t off, len, n;
|
||||
size_t off, len, n, slen;
|
||||
int ch, brackets;
|
||||
|
||||
if (fmt == NULL)
|
||||
@ -383,6 +515,34 @@ format_expand(struct format_tree *ft, const char *fmt)
|
||||
|
||||
ch = (u_char) *fmt++;
|
||||
switch (ch) {
|
||||
case '(':
|
||||
brackets = 1;
|
||||
for (ptr = fmt; *ptr != '\0'; ptr++) {
|
||||
if (*ptr == '(')
|
||||
brackets++;
|
||||
if (*ptr == ')' && --brackets == 0)
|
||||
break;
|
||||
}
|
||||
if (*ptr != ')' || brackets != 0)
|
||||
break;
|
||||
n = ptr - fmt;
|
||||
|
||||
tmp = xmalloc(n + 1);
|
||||
memcpy(tmp, fmt, n);
|
||||
tmp[n] = '\0';
|
||||
|
||||
s = format_job_get(ft, tmp);
|
||||
slen = strlen(s);
|
||||
|
||||
while (len - off < slen + 1) {
|
||||
buf = xreallocarray(buf, 2, len);
|
||||
len *= 2;
|
||||
}
|
||||
memcpy(buf + off, s, slen);
|
||||
off += slen;
|
||||
|
||||
fmt += n + 1;
|
||||
continue;
|
||||
case '{':
|
||||
brackets = 1;
|
||||
for (ptr = fmt; *ptr != '\0'; ptr++) {
|
||||
|
Reference in New Issue
Block a user