=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/status.c,v retrieving revision 1.45 retrieving revision 1.46 diff -u -r1.45 -r1.46 --- src/usr.bin/tmux/status.c 2009/11/19 10:22:07 1.45 +++ src/usr.bin/tmux/status.c 2009/11/19 11:38:54 1.46 @@ -1,4 +1,4 @@ -/* $OpenBSD: status.c,v 1.45 2009/11/19 10:22:07 nicm Exp $ */ +/* $OpenBSD: status.c,v 1.46 2009/11/19 11:38:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -33,6 +33,8 @@ void status_job_callback(struct job *); size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); +void status_replace1( + struct client *, char **, char **, char *, size_t, int); void status_message_callback(int, short, void *); void status_prompt_add_history(struct client *); @@ -318,139 +320,133 @@ return (1); } -char * -status_replace(struct client *c, const char *fmt, time_t t, int run_jobs) +/* Replace a single special sequence (prefixed by #). */ +void +status_replace1(struct client *c, + char **iptr, char **optr, char *out, size_t outsize, int jobsflag) { struct session *s = c->session; struct winlink *wl = s->curw; + char ch, tmp[256], *ptr, *endptr, *freeptr; + size_t ptrlen; + long limit; + + errno = 0; + limit = strtol(*iptr, &endptr, 10); + if ((limit == 0 && errno != EINVAL) || + (limit == LONG_MIN && errno != ERANGE) || + (limit == LONG_MAX && errno != ERANGE) || + limit != 0) + *iptr = endptr; + if (limit <= 0) + limit = LONG_MAX; + + freeptr = NULL; + + switch (*(*iptr)++) { + case '(': + if (!jobsflag) { + ch = ')'; + goto skip_to; + } + if ((ptr = status_job(c, iptr)) == NULL) + return; + freeptr = ptr; + goto do_replace; + case 'H': + if (gethostname(tmp, sizeof tmp) != 0) + fatal("gethostname failed"); + ptr = tmp; + goto do_replace; + case 'I': + xsnprintf(tmp, sizeof tmp, "%d", wl->idx); + ptr = tmp; + goto do_replace; + case 'P': + xsnprintf(tmp, sizeof tmp, "%u", + window_pane_index(wl->window, wl->window->active)); + ptr = tmp; + goto do_replace; + case 'S': + ptr = s->name; + goto do_replace; + case 'T': + ptr = wl->window->active->base.title; + goto do_replace; + case 'W': + ptr = wl->window->name; + goto do_replace; + case '[': + /* + * Embedded style, handled at display time. Leave present and + * skip input until ]. + */ + ch = ']'; + goto skip_to; + case '#': + *(*optr++) = '#'; + break; + } + + return; + +do_replace: + ptrlen = strlen(ptr); + if ((size_t) limit < ptrlen) + ptrlen = limit; + + if (*optr + ptrlen >= out + outsize - 1) + return; + while (ptrlen > 0 && *ptr != '\0') { + *(*optr)++ = *ptr++; + ptrlen--; + } + + if (freeptr != NULL) + xfree(freeptr); + return; + +skip_to: + *(*optr)++ = '#'; + + (*iptr)--; /* include ch */ + while (**iptr != ch && **iptr != '\0') { + if (*optr >= out + outsize - 1) + break; + *(*optr)++ = *(*iptr)++; + } +} + +/* Replace special sequences in fmt. */ +char * +status_replace(struct client *c, const char *fmt, time_t t, int jobsflag) +{ static char out[BUFSIZ]; - char in[BUFSIZ], tmp[256], ch, *iptr, *optr, *ptr, *endptr; - char *savedptr; /* freed at end of each loop */ - size_t len; - long n; + char in[BUFSIZ], ch, *iptr, *optr; - strftime(in, sizeof in, fmt, localtime(&t)); in[(sizeof in) - 1] = '\0'; iptr = in; optr = out; - savedptr = NULL; while (*iptr != '\0') { if (optr >= out + (sizeof out) - 1) break; - switch (ch = *iptr++) { - case '#': - errno = 0; - n = strtol(iptr, &endptr, 10); - if ((n == 0 && errno != EINVAL) || - (n == LONG_MIN && errno != ERANGE) || - (n == LONG_MAX && errno != ERANGE) || - n != 0) - iptr = endptr; - if (n <= 0) - n = LONG_MAX; + ch = *iptr++; - ptr = NULL; - switch (*iptr++) { - case '(': - if (run_jobs) { - if (ptr == NULL) { - ptr = status_job(c, &iptr); - if (ptr == NULL) - break; - savedptr = ptr; - } - } else { - /* Don't run jobs. Copy to ). */ - *optr++ = '#'; - - iptr--; /* include [ */ - while (*iptr != ')' && *iptr != '\0') { - if (optr >= - out + (sizeof out) - 1) - break; - *optr++ = *iptr++; - } - break; - } - /* FALLTHROUGH */ - case 'H': - if (ptr == NULL) { - if (gethostname(tmp, sizeof tmp) != 0) - fatal("gethostname failed"); - ptr = tmp; - } - /* FALLTHROUGH */ - case 'I': - if (ptr == NULL) { - xsnprintf(tmp, sizeof tmp, "%d", wl->idx); - ptr = tmp; - } - /* FALLTHROUGH */ - case 'P': - if (ptr == NULL) { - xsnprintf(tmp, sizeof tmp, "%u", - window_pane_index(wl->window, - wl->window->active)); - ptr = tmp; - } - /* FALLTHROUGH */ - case 'S': - if (ptr == NULL) - ptr = s->name; - /* FALLTHROUGH */ - case 'T': - if (ptr == NULL) - ptr = wl->window->active->base.title; - /* FALLTHROUGH */ - case 'W': - if (ptr == NULL) - ptr = wl->window->name; - len = strlen(ptr); - if ((size_t) n < len) - len = n; - if (optr + len >= out + (sizeof out) - 1) - break; - while (len > 0 && *ptr != '\0') { - *optr++ = *ptr++; - len--; - } - break; - case '[': - /* - * Embedded style, handled at display time. - * Leave present and skip input until ]. - */ - *optr++ = '#'; - - iptr--; /* include [ */ - while (*iptr != ']' && *iptr != '\0') { - if (optr >= out + (sizeof out) - 1) - break; - *optr++ = *iptr++; - } - break; - case '#': - *optr++ = '#'; - break; - } - if (savedptr != NULL) { - xfree(savedptr); - savedptr = NULL; - } - break; - default: + if (ch != '#') { *optr++ = ch; - break; + continue; } + status_replace1(c, &iptr, &optr, out, sizeof out, jobsflag); } *optr = '\0'; return (xstrdup(out)); } +/* Figure out job name and get its result, starting it off if necessary. */ char * status_job(struct client *c, char **iptr) { @@ -498,6 +494,7 @@ return (xstrdup(job->data)); } +/* Job has finished: save its result. */ void status_job_callback(struct job *job) { @@ -523,12 +520,14 @@ xfree(buf); } +/* Calculate winlink status line entry width. */ size_t status_width(struct winlink *wl) { return (xsnprintf(NULL, 0, "%d:%s ", wl->idx, wl->window->name)); } +/* Return winlink status line entry and adjust gc as necessary. */ char * status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) { @@ -577,6 +576,7 @@ return (text); } +/* Set a status line message. */ void printflike2 status_message_set(struct client *c, const char *fmt, ...) { @@ -621,6 +621,7 @@ c->flags |= CLIENT_STATUS; } +/* Clear status line message. */ void status_message_clear(struct client *c) { @@ -636,6 +637,7 @@ screen_reinit(&c->status); } +/* Clear status line message after timer expires. */ void status_message_callback(unused int fd, unused short event, void *data) { @@ -685,6 +687,7 @@ return (1); } +/* Enable status line prompt. */ void status_prompt_set(struct client *c, const char *msg, int (*callbackfn)(void *, const char *), void (*freefn)(void *), @@ -718,6 +721,7 @@ c->flags |= CLIENT_STATUS; } +/* Remove status line prompt. */ void status_prompt_clear(struct client *c) { @@ -739,6 +743,7 @@ screen_reinit(&c->status); } +/* Update status line prompt with a new prompt string. */ void status_prompt_update(struct client *c, const char *msg) {