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

Annotation of src/usr.bin/tmux/cfg.c, Revision 1.87

1.87    ! nicm        1: /* $OpenBSD: cfg.c,v 1.86 2022/06/20 07:59:37 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.44      nicm        4:  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        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:
1.21      nicm       21: #include <ctype.h>
1.1       nicm       22: #include <errno.h>
                     23: #include <stdio.h>
1.15      nicm       24: #include <stdlib.h>
1.1       nicm       25: #include <string.h>
1.32      tobias     26: #include <util.h>
1.1       nicm       27:
                     28: #include "tmux.h"
                     29:
1.63      nicm       30: struct client           *cfg_client;
1.58      nicm       31: int                      cfg_finished;
                     32: static char            **cfg_causes;
                     33: static u_int             cfg_ncauses;
                     34: static struct cmdq_item         *cfg_item;
                     35:
1.82      nicm       36: int                       cfg_quiet = 1;
                     37: char                    **cfg_files;
                     38: u_int                     cfg_nfiles;
                     39:
1.58      nicm       40: static enum cmd_retval
                     41: cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
                     42: {
                     43:        if (!cfg_finished)
                     44:                return (CMD_RETURN_WAIT);
                     45:        return (CMD_RETURN_NORMAL);
                     46: }
1.40      nicm       47:
1.49      nicm       48: static enum cmd_retval
1.50      nicm       49: cfg_done(__unused struct cmdq_item *item, __unused void *data)
1.49      nicm       50: {
                     51:        if (cfg_finished)
                     52:                return (CMD_RETURN_NORMAL);
                     53:        cfg_finished = 1;
                     54:
1.86      nicm       55:        cfg_show_causes(NULL);
1.57      nicm       56:
1.58      nicm       57:        if (cfg_item != NULL)
1.74      nicm       58:                cmdq_continue(cfg_item);
1.58      nicm       59:
1.57      nicm       60:        status_prompt_load_history();
1.49      nicm       61:
                     62:        return (CMD_RETURN_NORMAL);
                     63: }
1.40      nicm       64:
                     65: void
                     66: start_cfg(void)
                     67: {
1.81      nicm       68:        struct client    *c;
1.82      nicm       69:        u_int             i;
1.87    ! nicm       70:        int               flags = 0;
1.40      nicm       71:
1.56      nicm       72:        /*
1.71      nicm       73:         * Configuration files are loaded without a client, so commands are run
                     74:         * in the global queue with item->client NULL.
1.58      nicm       75:         *
                     76:         * However, we must block the initial client (but just the initial
                     77:         * client) so that its command runs after the configuration is loaded.
                     78:         * Because start_cfg() is called so early, we can be sure the client's
                     79:         * command queue is currently empty and our callback will be at the
                     80:         * front - we need to get in before MSG_COMMAND.
1.56      nicm       81:         */
1.63      nicm       82:        cfg_client = c = TAILQ_FIRST(&clients);
1.58      nicm       83:        if (c != NULL) {
                     84:                cfg_item = cmdq_get_callback(cfg_client_done, NULL);
                     85:                cmdq_append(c, cfg_item);
                     86:        }
1.40      nicm       87:
1.87    ! nicm       88:        if (cfg_quiet)
        !            89:                flags = CMD_PARSE_QUIET;
        !            90:        for (i = 0; i < cfg_nfiles; i++)
        !            91:                load_cfg(cfg_files[i], c, NULL, NULL, flags, NULL);
1.40      nicm       92:
1.56      nicm       93:        cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
1.40      nicm       94: }
1.1       nicm       95:
1.28      nicm       96: int
1.87    ! nicm       97: load_cfg(const char *path, struct client *c, struct cmdq_item *item,
        !            98:     struct cmd_find_state *current, int flags, struct cmdq_item **new_item)
1.1       nicm       99: {
1.50      nicm      100:        FILE                    *f;
1.71      nicm      101:        struct cmd_parse_input   pi;
                    102:        struct cmd_parse_result *pr;
1.70      nicm      103:        struct cmdq_item        *new_item0;
1.83      nicm      104:        struct cmdq_state       *state;
1.61      nicm      105:
1.71      nicm      106:        if (new_item != NULL)
                    107:                *new_item = NULL;
1.1       nicm      108:
1.29      nicm      109:        log_debug("loading %s", path);
1.1       nicm      110:        if ((f = fopen(path, "rb")) == NULL) {
1.71      nicm      111:                if (errno == ENOENT && (flags & CMD_PARSE_QUIET))
1.45      tim       112:                        return (0);
                    113:                cfg_add_cause("%s: %s", path, strerror(errno));
1.28      nicm      114:                return (-1);
1.25      nicm      115:        }
                    116:
1.71      nicm      117:        memset(&pi, 0, sizeof pi);
                    118:        pi.flags = flags;
                    119:        pi.file = path;
1.72      nicm      120:        pi.line = 1;
1.73      nicm      121:        pi.item = item;
1.75      nicm      122:        pi.c = c;
1.13      nicm      123:
1.71      nicm      124:        pr = cmd_parse_from_file(f, &pi);
                    125:        fclose(f);
1.77      nicm      126:        if (pr->status == CMD_PARSE_ERROR) {
                    127:                cfg_add_cause("%s", pr->error);
                    128:                free(pr->error);
                    129:                return (-1);
                    130:        }
                    131:        if (flags & CMD_PARSE_PARSEONLY) {
                    132:                cmd_list_free(pr->cmdlist);
                    133:                return (0);
                    134:        }
                    135:
1.83      nicm      136:        if (item != NULL)
1.87    ! nicm      137:                state = cmdq_copy_state(cmdq_get_state(item), current);
1.83      nicm      138:        else
                    139:                state = cmdq_new_state(NULL, NULL, 0);
                    140:        cmdq_add_format(state, "current_file", "%s", pi.file);
                    141:
                    142:        new_item0 = cmdq_get_command(pr->cmdlist, state);
1.77      nicm      143:        if (item != NULL)
1.78      nicm      144:                new_item0 = cmdq_insert_after(item, new_item0);
1.77      nicm      145:        else
1.78      nicm      146:                new_item0 = cmdq_append(NULL, new_item0);
1.77      nicm      147:        cmd_list_free(pr->cmdlist);
1.83      nicm      148:        cmdq_free_state(state);
1.77      nicm      149:
                    150:        if (new_item != NULL)
                    151:                *new_item = new_item0;
                    152:        return (0);
                    153: }
                    154:
                    155: int
                    156: load_cfg_from_buffer(const void *buf, size_t len, const char *path,
1.87    ! nicm      157:     struct client *c, struct cmdq_item *item, struct cmd_find_state *current,
        !           158:     int flags, struct cmdq_item **new_item)
1.77      nicm      159: {
                    160:        struct cmd_parse_input   pi;
                    161:        struct cmd_parse_result *pr;
                    162:        struct cmdq_item        *new_item0;
1.83      nicm      163:        struct cmdq_state       *state;
1.77      nicm      164:
                    165:        if (new_item != NULL)
                    166:                *new_item = NULL;
                    167:
                    168:        log_debug("loading %s", path);
                    169:
                    170:        memset(&pi, 0, sizeof pi);
                    171:        pi.flags = flags;
                    172:        pi.file = path;
                    173:        pi.line = 1;
                    174:        pi.item = item;
                    175:        pi.c = c;
                    176:
                    177:        pr = cmd_parse_from_buffer(buf, len, &pi);
1.71      nicm      178:        if (pr->status == CMD_PARSE_ERROR) {
                    179:                cfg_add_cause("%s", pr->error);
                    180:                free(pr->error);
                    181:                return (-1);
                    182:        }
                    183:        if (flags & CMD_PARSE_PARSEONLY) {
                    184:                cmd_list_free(pr->cmdlist);
                    185:                return (0);
1.1       nicm      186:        }
1.61      nicm      187:
1.83      nicm      188:        if (item != NULL)
1.87    ! nicm      189:                state = cmdq_copy_state(cmdq_get_state(item), current);
1.83      nicm      190:        else
                    191:                state = cmdq_new_state(NULL, NULL, 0);
                    192:        cmdq_add_format(state, "current_file", "%s", pi.file);
                    193:
                    194:        new_item0 = cmdq_get_command(pr->cmdlist, state);
1.71      nicm      195:        if (item != NULL)
1.78      nicm      196:                new_item0 = cmdq_insert_after(item, new_item0);
1.71      nicm      197:        else
1.78      nicm      198:                new_item0 = cmdq_append(NULL, new_item0);
1.71      nicm      199:        cmd_list_free(pr->cmdlist);
1.83      nicm      200:        cmdq_free_state(state);
1.25      nicm      201:
1.70      nicm      202:        if (new_item != NULL)
1.71      nicm      203:                *new_item = new_item0;
                    204:        return (0);
1.33      nicm      205: }
                    206:
                    207: void
1.36      nicm      208: cfg_add_cause(const char *fmt, ...)
1.33      nicm      209: {
1.36      nicm      210:        va_list  ap;
                    211:        char    *msg;
1.33      nicm      212:
                    213:        va_start(ap, fmt);
                    214:        xvasprintf(&msg, fmt, ap);
1.38      nicm      215:        va_end(ap);
1.33      nicm      216:
1.35      nicm      217:        cfg_ncauses++;
                    218:        cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes);
                    219:        cfg_causes[cfg_ncauses - 1] = msg;
1.33      nicm      220: }
                    221:
                    222: void
1.50      nicm      223: cfg_print_causes(struct cmdq_item *item)
1.33      nicm      224: {
                    225:        u_int    i;
                    226:
1.35      nicm      227:        for (i = 0; i < cfg_ncauses; i++) {
1.50      nicm      228:                cmdq_print(item, "%s", cfg_causes[i]);
1.35      nicm      229:                free(cfg_causes[i]);
1.33      nicm      230:        }
1.35      nicm      231:
                    232:        free(cfg_causes);
                    233:        cfg_causes = NULL;
1.37      nicm      234:        cfg_ncauses = 0;
1.17      nicm      235: }
                    236:
                    237: void
1.28      nicm      238: cfg_show_causes(struct session *s)
1.17      nicm      239: {
1.86      nicm      240:        struct client                   *c = TAILQ_FIRST(&clients);
1.66      nicm      241:        struct window_pane              *wp;
                    242:        struct window_mode_entry        *wme;
                    243:        u_int                            i;
1.17      nicm      244:
1.86      nicm      245:        if (cfg_ncauses == 0)
                    246:                return;
                    247:
                    248:        if (c != NULL && (c->flags & CLIENT_CONTROL)) {
                    249:                for (i = 0; i < cfg_ncauses; i++) {
                    250:                        control_write(c, "%%config-error %s", cfg_causes[i]);
                    251:                        free(cfg_causes[i]);
                    252:                }
                    253:                goto out;
                    254:        }
                    255:
                    256:        if (s == NULL) {
                    257:                if (c != NULL && c->session != NULL)
                    258:                        s = c->session;
                    259:                else
                    260:                        s = RB_MIN(sessions, &sessions);
                    261:        }
                    262:        if (s == NULL || s->attached == 0) /* wait for an attached session */
1.17      nicm      263:                return;
                    264:        wp = s->curw->window->active;
                    265:
1.66      nicm      266:        wme = TAILQ_FIRST(&wp->modes);
                    267:        if (wme == NULL || wme->mode != &window_view_mode)
1.79      nicm      268:                window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
1.35      nicm      269:        for (i = 0; i < cfg_ncauses; i++) {
1.85      nicm      270:                window_copy_add(wp, 0, "%s", cfg_causes[i]);
1.35      nicm      271:                free(cfg_causes[i]);
1.17      nicm      272:        }
1.35      nicm      273:
1.86      nicm      274: out:
1.35      nicm      275:        free(cfg_causes);
                    276:        cfg_causes = NULL;
1.37      nicm      277:        cfg_ncauses = 0;
1.1       nicm      278: }