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

Annotation of src/usr.bin/tmux/cmd.c, Revision 1.2

1.2     ! nicm        1: /* $OpenBSD: cmd.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
                      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: #include <sys/time.h>
                     21:
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24: #include <unistd.h>
                     25:
                     26: #include "tmux.h"
                     27:
                     28: const struct cmd_entry *cmd_table[] = {
                     29:        &cmd_attach_session_entry,
                     30:        &cmd_bind_key_entry,
                     31:        &cmd_break_pane_entry,
                     32:        &cmd_choose_session_entry,
                     33:        &cmd_choose_window_entry,
                     34:        &cmd_clear_history_entry,
                     35:        &cmd_clock_mode_entry,
                     36:        &cmd_command_prompt_entry,
                     37:        &cmd_confirm_before_entry,
                     38:        &cmd_copy_buffer_entry,
                     39:        &cmd_copy_mode_entry,
                     40:        &cmd_delete_buffer_entry,
                     41:        &cmd_detach_client_entry,
                     42:        &cmd_down_pane_entry,
                     43:        &cmd_find_window_entry,
                     44:        &cmd_has_session_entry,
                     45:        &cmd_kill_pane_entry,
                     46:        &cmd_kill_server_entry,
                     47:        &cmd_kill_session_entry,
                     48:        &cmd_kill_window_entry,
                     49:        &cmd_last_window_entry,
                     50:        &cmd_link_window_entry,
                     51:        &cmd_list_buffers_entry,
                     52:        &cmd_list_clients_entry,
                     53:        &cmd_list_commands_entry,
                     54:        &cmd_list_keys_entry,
                     55:        &cmd_list_sessions_entry,
                     56:        &cmd_list_windows_entry,
                     57:        &cmd_load_buffer_entry,
                     58:        &cmd_lock_server_entry,
                     59:        &cmd_move_window_entry,
                     60:        &cmd_new_session_entry,
                     61:        &cmd_new_window_entry,
                     62:        &cmd_next_layout_entry,
                     63:        &cmd_next_window_entry,
                     64:        &cmd_paste_buffer_entry,
                     65:        &cmd_previous_layout_entry,
                     66:        &cmd_previous_window_entry,
                     67:        &cmd_refresh_client_entry,
                     68:        &cmd_rename_session_entry,
                     69:        &cmd_rename_window_entry,
                     70:        &cmd_resize_pane_entry,
                     71:        &cmd_respawn_window_entry,
                     72:        &cmd_rotate_window_entry,
                     73:        &cmd_save_buffer_entry,
                     74:        &cmd_scroll_mode_entry,
                     75:        &cmd_select_layout_entry,
                     76:        &cmd_select_pane_entry,
                     77:        &cmd_select_prompt_entry,
                     78:        &cmd_select_window_entry,
                     79:        &cmd_send_keys_entry,
                     80:        &cmd_send_prefix_entry,
                     81:        &cmd_server_info_entry,
                     82:        &cmd_set_buffer_entry,
                     83:        &cmd_set_option_entry,
                     84:        &cmd_set_password_entry,
                     85:        &cmd_set_window_option_entry,
                     86:        &cmd_show_buffer_entry,
                     87:        &cmd_show_options_entry,
                     88:        &cmd_show_window_options_entry,
                     89:        &cmd_source_file_entry,
                     90:        &cmd_split_window_entry,
                     91:        &cmd_start_server_entry,
                     92:        &cmd_suspend_client_entry,
                     93:        &cmd_swap_pane_entry,
                     94:        &cmd_swap_window_entry,
                     95:        &cmd_switch_client_entry,
                     96:        &cmd_unbind_key_entry,
                     97:        &cmd_unlink_window_entry,
                     98:        &cmd_up_pane_entry,
                     99:        NULL
                    100: };
                    101:
                    102: struct cmd *
                    103: cmd_parse(int argc, char **argv, char **cause)
                    104: {
                    105:        const struct cmd_entry **entryp, *entry;
                    106:        struct cmd              *cmd;
                    107:        char                     s[BUFSIZ];
                    108:        int                      opt;
                    109:
                    110:        *cause = NULL;
1.2     ! nicm      111:        if (argc == 0) {
        !           112:                xasprintf(cause, "no command");
1.1       nicm      113:                return (NULL);
1.2     ! nicm      114:        }
1.1       nicm      115:
                    116:        entry = NULL;
                    117:        for (entryp = cmd_table; *entryp != NULL; entryp++) {
                    118:                if ((*entryp)->alias != NULL &&
                    119:                    strcmp((*entryp)->alias, argv[0]) == 0) {
                    120:                        entry = *entryp;
                    121:                        break;
                    122:                }
                    123:
                    124:                if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
                    125:                        continue;
                    126:                if (entry != NULL)
                    127:                        goto ambiguous;
                    128:                entry = *entryp;
                    129:
                    130:                /* Bail now if an exact match. */
                    131:                if (strcmp(entry->name, argv[0]) == 0)
                    132:                        break;
                    133:        }
                    134:        if (entry == NULL) {
                    135:                xasprintf(cause, "unknown command: %s", argv[0]);
                    136:                return (NULL);
                    137:        }
                    138:
                    139:        optreset = 1;
                    140:        optind = 1;
                    141:        if (entry->parse == NULL) {
                    142:                while ((opt = getopt(argc, argv, "")) != -1) {
                    143:                        switch (opt) {
                    144:                        default:
                    145:                                goto usage;
                    146:                        }
                    147:                }
                    148:                argc -= optind;
                    149:                argv += optind;
                    150:                if (argc != 0)
                    151:                        goto usage;
                    152:        }
                    153:
                    154:        cmd = xmalloc(sizeof *cmd);
                    155:        cmd->entry = entry;
                    156:        cmd->data = NULL;
                    157:        if (entry->parse != NULL) {
                    158:                if (entry->parse(cmd, argc, argv, cause) != 0) {
                    159:                        xfree(cmd);
                    160:                        return (NULL);
                    161:                }
                    162:        }
                    163:        return (cmd);
                    164:
                    165: ambiguous:
                    166:        *s = '\0';
                    167:        for (entryp = cmd_table; *entryp != NULL; entryp++) {
                    168:                if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0)
                    169:                        continue;
                    170:                if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s)
                    171:                        break;
                    172:                if (strlcat(s, ", ", sizeof s) >= sizeof s)
                    173:                        break;
                    174:        }
                    175:        s[strlen(s) - 2] = '\0';
                    176:        xasprintf(cause, "ambiguous command: %s, could be: %s", argv[0], s);
                    177:        return (NULL);
                    178:
                    179: usage:
                    180:        xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
                    181:        return (NULL);
                    182: }
                    183:
                    184: int
                    185: cmd_exec(struct cmd *cmd, struct cmd_ctx *ctx)
                    186: {
                    187:        if (server_locked) {
                    188:                ctx->error(ctx, "server is locked");
                    189:                return (-1);
                    190:        }
                    191:        return (cmd->entry->exec(cmd, ctx));
                    192: }
                    193:
                    194: void
                    195: cmd_send(struct cmd *cmd, struct buffer *b)
                    196: {
                    197:        const struct cmd_entry **entryp;
                    198:        u_int                    n;
                    199:
                    200:        n = 0;
                    201:        for (entryp = cmd_table; *entryp != NULL; entryp++) {
                    202:                if (*entryp == cmd->entry)
                    203:                        break;
                    204:                n++;
                    205:        }
                    206:        if (*entryp == NULL)
                    207:                fatalx("command not found");
                    208:
                    209:        buffer_write(b, &n, sizeof n);
                    210:
                    211:        if (cmd->entry->send != NULL)
                    212:                cmd->entry->send(cmd, b);
                    213: }
                    214:
                    215: struct cmd *
                    216: cmd_recv(struct buffer *b)
                    217: {
                    218:        const struct cmd_entry **entryp;
                    219:        struct cmd              *cmd;
                    220:        u_int                    m, n;
                    221:
                    222:        buffer_read(b, &m, sizeof m);
                    223:
                    224:        n = 0;
                    225:        for (entryp = cmd_table; *entryp != NULL; entryp++) {
                    226:                if (n == m)
                    227:                        break;
                    228:                n++;
                    229:        }
                    230:        if (*entryp == NULL)
                    231:                fatalx("command not found");
                    232:
                    233:        cmd = xmalloc(sizeof *cmd);
                    234:        cmd->entry = *entryp;
                    235:
                    236:        if (cmd->entry->recv != NULL)
                    237:                cmd->entry->recv(cmd, b);
                    238:        return (cmd);
                    239: }
                    240:
                    241: void
                    242: cmd_free(struct cmd *cmd)
                    243: {
                    244:        if (cmd->data != NULL && cmd->entry->free != NULL)
                    245:                cmd->entry->free(cmd);
                    246:        xfree(cmd);
                    247: }
                    248:
                    249: size_t
                    250: cmd_print(struct cmd *cmd, char *buf, size_t len)
                    251: {
                    252:        if (cmd->entry->print == NULL) {
                    253:                return (xsnprintf(buf, len, "%s", cmd->entry->name));
                    254:        }
                    255:        return (cmd->entry->print(cmd, buf, len));
                    256: }
                    257:
                    258: void
                    259: cmd_send_string(struct buffer *b, const char *s)
                    260: {
                    261:        size_t  n;
                    262:
                    263:        if (s == NULL) {
                    264:                n = 0;
                    265:                buffer_write(b, &n, sizeof n);
                    266:                return;
                    267:        }
                    268:
                    269:        n = strlen(s) + 1;
                    270:        buffer_write(b, &n, sizeof n);
                    271:
                    272:        buffer_write(b, s, n);
                    273: }
                    274:
                    275: char *
                    276: cmd_recv_string(struct buffer *b)
                    277: {
                    278:        char   *s;
                    279:        size_t  n;
                    280:
                    281:        buffer_read(b, &n, sizeof n);
                    282:
                    283:        if (n == 0)
                    284:                return (NULL);
                    285:
                    286:        s = xmalloc(n);
                    287:        buffer_read(b, s, n);
                    288:        s[n - 1] = '\0';
                    289:
                    290:        return (s);
                    291: }
                    292:
                    293: struct session *
                    294: cmd_current_session(struct cmd_ctx *ctx)
                    295: {
                    296:        struct msg_command_data *data = ctx->msgdata;
                    297:        struct timeval          *tv;
                    298:        struct session          *s, *newest = NULL;
                    299:        u_int                    i;
                    300:
                    301:        if (ctx->cursession != NULL)
                    302:                return (ctx->cursession);
                    303:
                    304:        if (data != NULL && data->pid != -1) {
                    305:                if (data->pid != getpid()) {
                    306:                        ctx->error(ctx, "wrong server: %ld", (long) data->pid);
                    307:                        return (NULL);
                    308:                }
                    309:                if (data->idx > ARRAY_LENGTH(&sessions)) {
                    310:                        ctx->error(ctx, "index out of range: %d", data->idx);
                    311:                        return (NULL);
                    312:                }
                    313:                if ((s = ARRAY_ITEM(&sessions, data->idx)) == NULL) {
                    314:                        ctx->error(ctx, "session doesn't exist: %u", data->idx);
                    315:                        return (NULL);
                    316:                }
                    317:                return (s);
                    318:        }
                    319:
                    320:        tv = NULL;
                    321:        for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
                    322:                s = ARRAY_ITEM(&sessions, i);
                    323:                if (s != NULL && (tv == NULL || timercmp(&s->tv, tv, >))) {
                    324:                        newest = ARRAY_ITEM(&sessions, i);
                    325:                        tv = &s->tv;
                    326:                }
                    327:        }
                    328:        return (newest);
                    329: }
                    330:
                    331: struct client *
                    332: cmd_find_client(struct cmd_ctx *ctx, const char *arg)
                    333: {
                    334:        struct client   *c;
                    335:
                    336:        if (arg == NULL)
                    337:                c = ctx->curclient;
                    338:        else {
                    339:                if ((c = arg_parse_client(arg)) == NULL) {
                    340:                        if (arg != NULL)
                    341:                                ctx->error(ctx, "client not found: %s", arg);
                    342:                        else
                    343:                                ctx->error(ctx, "no client found");
                    344:                }
                    345:        }
                    346:        return (c);
                    347: }
                    348:
                    349: struct session *
                    350: cmd_find_session(struct cmd_ctx *ctx, const char *arg)
                    351: {
                    352:        struct session  *s;
                    353:
                    354:        if (arg == NULL)
                    355:                s = cmd_current_session(ctx);
                    356:        else {
                    357:                if ((s = arg_parse_session(arg)) == NULL) {
                    358:                        if (arg != NULL)
                    359:                                ctx->error(ctx, "session not found: %s", arg);
                    360:                        else
                    361:                                ctx->error(ctx, "no session found");
                    362:                }
                    363:        }
                    364:        return (s);
                    365: }
                    366:
                    367: struct winlink *
                    368: cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp)
                    369: {
                    370:        struct session  *s;
                    371:        struct winlink  *wl;
                    372:        int              idx;
                    373:
                    374:        wl = NULL;
                    375:        if (arg_parse_window(arg, &s, &idx) != 0) {
                    376:                ctx->error(ctx, "bad window: %s", arg);
                    377:                return (NULL);
                    378:        }
                    379:        if (s == NULL)
                    380:                s = ctx->cursession;
                    381:        if (s == NULL)
                    382:                s = cmd_current_session(ctx);
                    383:        if (s == NULL)
                    384:                return (NULL);
                    385:        if (sp != NULL)
                    386:                *sp = s;
                    387:
                    388:        if (idx == -1)
                    389:                wl = s->curw;
                    390:        else
                    391:                wl = winlink_find_by_index(&s->windows, idx);
                    392:        if (wl == NULL)
                    393:                ctx->error(ctx, "window not found: %s:%d", s->name, idx);
                    394:        return (wl);
                    395: }