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

Annotation of src/usr.bin/tmux/control.c, Revision 1.32

1.32    ! nicm        1: /* $OpenBSD: control.c,v 1.31 2020/05/21 07:24:13 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.17      nicm        4:  * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        5:  * Copyright (c) 2012 George Nachman <tmux@georgester.com>
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software for any
                      8:  * purpose with or without fee is hereby granted, provided that the above
                      9:  * copyright notice and this permission notice appear in all copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     15:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     16:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     17:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19:
                     20: #include <sys/types.h>
                     21:
                     22: #include <event.h>
1.2       nicm       23: #include <stdlib.h>
1.1       nicm       24: #include <string.h>
1.10      nicm       25: #include <time.h>
1.1       nicm       26:
                     27: #include "tmux.h"
                     28:
1.32    ! nicm       29: /* Control offsets. */
        !            30: struct control_offset {
        !            31:        u_int                           pane;
        !            32:
        !            33:        struct window_pane_offset       offset;
        !            34:        int                             flags;
        !            35: #define CONTROL_OFFSET_OFF 0x1
        !            36:
        !            37:        RB_ENTRY(control_offset)                entry;
        !            38: };
        !            39: RB_HEAD(control_offsets, control_offset);
        !            40:
        !            41: /* Compare client offsets. */
        !            42: static int
        !            43: control_offset_cmp(struct control_offset *co1, struct control_offset *co2)
        !            44: {
        !            45:        if (co1->pane < co2->pane)
        !            46:                return (-1);
        !            47:        if (co1->pane > co2->pane)
        !            48:                return (1);
        !            49:        return (0);
        !            50: }
        !            51: RB_GENERATE_STATIC(control_offsets, control_offset, entry, control_offset_cmp);
        !            52:
        !            53: /* Get pane offsets for this client. */
        !            54: static struct control_offset *
        !            55: control_get_offset(struct client *c, struct window_pane *wp)
        !            56: {
        !            57:        struct control_offset   co = { .pane = wp->id };
        !            58:
        !            59:        if (c->offsets == NULL)
        !            60:                return (NULL);
        !            61:        return (RB_FIND(control_offsets, c->offsets, &co));
        !            62: }
        !            63:
        !            64: /* Add pane offsets for this client. */
        !            65: static struct control_offset *
        !            66: control_add_offset(struct client *c, struct window_pane *wp)
        !            67: {
        !            68:        struct control_offset   *co;
        !            69:
        !            70:        co = control_get_offset(c, wp);
        !            71:        if (co != NULL)
        !            72:                return (co);
        !            73:
        !            74:        if (c->offsets == NULL) {
        !            75:                c->offsets = xmalloc(sizeof *c->offsets);
        !            76:                RB_INIT(c->offsets);
        !            77:        }
        !            78:
        !            79:        co = xcalloc(1, sizeof *co);
        !            80:        co->pane = wp->id;
        !            81:        RB_INSERT(control_offsets, c->offsets, co);
        !            82:        memcpy(&co->offset, &wp->offset, sizeof co->offset);
        !            83:        return (co);
        !            84: }
        !            85:
        !            86: /* Free control offsets. */
        !            87: void
        !            88: control_free_offsets(struct client *c)
        !            89: {
        !            90:        struct control_offset   *co, *co1;
        !            91:
        !            92:        if (c->offsets == NULL)
        !            93:                return;
        !            94:        RB_FOREACH_SAFE(co, control_offsets, c->offsets, co1) {
        !            95:                RB_REMOVE(control_offsets, c->offsets, co);
        !            96:                free(co);
        !            97:        }
        !            98:        free(c->offsets);
        !            99: }
        !           100:
        !           101: /* Get offsets for client. */
        !           102: struct window_pane_offset *
        !           103: control_pane_offset(struct client *c, struct window_pane *wp, int *off)
        !           104: {
        !           105:        struct control_offset   *co;
        !           106:
        !           107:        if (c->flags & CLIENT_CONTROL_NOOUTPUT) {
        !           108:                *off = 0;
        !           109:                return (NULL);
        !           110:        }
        !           111:
        !           112:        co = control_get_offset(c, wp);
        !           113:        if (co == NULL) {
        !           114:                *off = 0;
        !           115:                return (NULL);
        !           116:        }
        !           117:        if (co->flags & CONTROL_OFFSET_OFF) {
        !           118:                *off = 1;
        !           119:                return (NULL);
        !           120:        }
        !           121:        return (&co->offset);
        !           122: }
        !           123:
        !           124: /* Set pane as on. */
        !           125: void
        !           126: control_set_pane_on(struct client *c, struct window_pane *wp)
        !           127: {
        !           128:        struct control_offset   *co;
        !           129:
        !           130:        co = control_get_offset(c, wp);
        !           131:        if (co != NULL) {
        !           132:                co->flags &= ~CONTROL_OFFSET_OFF;
        !           133:                memcpy(&co->offset, &wp->offset, sizeof co->offset);
        !           134:        }
        !           135: }
        !           136:
        !           137: /* Set pane as off. */
        !           138: void
        !           139: control_set_pane_off(struct client *c, struct window_pane *wp)
        !           140: {
        !           141:        struct control_offset   *co;
        !           142:
        !           143:        co = control_add_offset(c, wp);
        !           144:        co->flags |= CONTROL_OFFSET_OFF;
        !           145: }
        !           146:
1.1       nicm      147: /* Write a line. */
1.13      nicm      148: void
1.1       nicm      149: control_write(struct client *c, const char *fmt, ...)
                    150: {
1.25      nicm      151:        va_list ap;
1.1       nicm      152:
                    153:        va_start(ap, fmt);
1.25      nicm      154:        file_vprint(c, fmt, ap);
                    155:        file_print(c, "\n");
1.1       nicm      156:        va_end(ap);
1.31      nicm      157: }
                    158:
                    159: /* Write output from a pane. */
                    160: void
                    161: control_write_output(struct client *c, struct window_pane *wp)
                    162: {
1.32    ! nicm      163:        struct control_offset   *co;
1.31      nicm      164:        struct evbuffer         *message;
                    165:        u_char                  *new_data;
                    166:        size_t                   new_size, i;
                    167:
                    168:        if (c->flags & CLIENT_CONTROL_NOOUTPUT)
                    169:                return;
                    170:
                    171:        /*
                    172:         * Only write input if the window pane is linked to a window belonging
                    173:         * to the client's session.
                    174:         */
                    175:        if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
                    176:                return;
                    177:
1.32    ! nicm      178:        co = control_add_offset(c, wp);
        !           179:        if (co->flags & CONTROL_OFFSET_OFF) {
1.31      nicm      180:                window_pane_update_used_data(wp, &co->offset, SIZE_MAX, 1);
                    181:                return;
                    182:        }
                    183:        new_data = window_pane_get_new_data(wp, &co->offset, &new_size);
                    184:        if (new_size == 0)
                    185:                return;
                    186:
                    187:        message = evbuffer_new();
                    188:        if (message == NULL)
                    189:                fatalx("out of memory");
                    190:        evbuffer_add_printf(message, "%%output %%%u ", wp->id);
                    191:
                    192:        for (i = 0; i < new_size; i++) {
                    193:                if (new_data[i] < ' ' || new_data[i] == '\\')
                    194:                        evbuffer_add_printf(message, "\\%03o", new_data[i]);
                    195:                else
                    196:                        evbuffer_add_printf(message, "%c", new_data[i]);
                    197:        }
                    198:        evbuffer_add(message, "", 1);
                    199:
                    200:        control_write(c, "%s", EVBUFFER_DATA(message));
                    201:        evbuffer_free(message);
                    202:
                    203:        window_pane_update_used_data(wp, &co->offset, new_size, 1);
1.1       nicm      204: }
                    205:
1.18      nicm      206: /* Control error callback. */
                    207: static enum cmd_retval
1.19      nicm      208: control_error(struct cmdq_item *item, void *data)
1.18      nicm      209: {
1.26      nicm      210:        struct client   *c = cmdq_get_client(item);
1.18      nicm      211:        char            *error = data;
                    212:
1.19      nicm      213:        cmdq_guard(item, "begin", 1);
1.18      nicm      214:        control_write(c, "parse error: %s", error);
1.19      nicm      215:        cmdq_guard(item, "error", 1);
1.18      nicm      216:
                    217:        free(error);
                    218:        return (CMD_RETURN_NORMAL);
                    219: }
                    220:
1.1       nicm      221: /* Control input callback. Read lines and fire commands. */
1.25      nicm      222: static void
                    223: control_callback(__unused struct client *c, __unused const char *path,
1.30      nicm      224:     int read_error, int closed, struct evbuffer *buffer, __unused void *data)
1.1       nicm      225: {
1.30      nicm      226:        char                    *line, *error;
1.29      nicm      227:        struct cmdq_state       *state;
1.30      nicm      228:        enum cmd_parse_status    status;
1.1       nicm      229:
1.30      nicm      230:        if (closed || read_error != 0)
1.1       nicm      231:                c->flags |= CLIENT_EXIT;
                    232:
                    233:        for (;;) {
1.25      nicm      234:                line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
1.1       nicm      235:                if (line == NULL)
                    236:                        break;
1.25      nicm      237:                log_debug("%s: %s", __func__, line);
1.1       nicm      238:                if (*line == '\0') { /* empty line exit */
1.24      nicm      239:                        free(line);
1.1       nicm      240:                        c->flags |= CLIENT_EXIT;
                    241:                        break;
                    242:                }
                    243:
1.30      nicm      244:                state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL);
                    245:                status = cmd_parse_and_append(line, NULL, c, state, &error);
                    246:                if (status == CMD_PARSE_ERROR)
                    247:                        cmdq_append(c, cmdq_get_callback(control_error, error));
                    248:                cmdq_free_state(state);
1.1       nicm      249:
1.2       nicm      250:                free(line);
1.1       nicm      251:        }
1.25      nicm      252: }
                    253:
1.32    ! nicm      254: /* Initialize for control mode. */
1.25      nicm      255: void
                    256: control_start(struct client *c)
                    257: {
                    258:        file_read(c, "-", control_callback, c);
                    259:
                    260:        if (c->flags & CLIENT_CONTROLCONTROL)
                    261:                file_print(c, "\033P1000p");
1.1       nicm      262: }