Merge branch 'obsd-master'
[tmux.git] / cmd-source-file.c
blob86c4b138cbe29afbc4e8c646bc5f9cc1c40ce98a
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
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.
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.
19 #include <sys/types.h>
21 #include <errno.h>
22 #include <glob.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "tmux.h"
29 * Sources a configuration file.
32 static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
34 const struct cmd_entry cmd_source_file_entry = {
35 .name = "source-file",
36 .alias = "source",
38 .args = { "t:Fnqv", 1, -1, NULL },
39 .usage = "[-Fnqv] " CMD_TARGET_PANE_USAGE " path ...",
41 .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
43 .flags = 0,
44 .exec = cmd_source_file_exec
47 struct cmd_source_file_data {
48 struct cmdq_item *item;
49 int flags;
51 struct cmdq_item *after;
52 enum cmd_retval retval;
54 u_int current;
55 char **files;
56 u_int nfiles;
59 static enum cmd_retval
60 cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
62 cfg_print_causes(item);
63 return (CMD_RETURN_NORMAL);
66 static void
67 cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
69 struct cmdq_item *new_item;
70 u_int i;
72 if (cfg_finished) {
73 if (cdata->retval == CMD_RETURN_ERROR &&
74 c != NULL &&
75 c->session == NULL)
76 c->retval = 1;
77 new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
78 cmdq_insert_after(cdata->after, new_item);
81 for (i = 0; i < cdata->nfiles; i++)
82 free(cdata->files[i]);
83 free(cdata->files);
84 free(cdata);
87 static void
88 cmd_source_file_done(struct client *c, const char *path, int error,
89 int closed, struct evbuffer *buffer, void *data)
91 struct cmd_source_file_data *cdata = data;
92 struct cmdq_item *item = cdata->item;
93 void *bdata = EVBUFFER_DATA(buffer);
94 size_t bsize = EVBUFFER_LENGTH(buffer);
95 u_int n;
96 struct cmdq_item *new_item;
97 struct cmd_find_state *target = cmdq_get_target(item);
99 if (!closed)
100 return;
102 if (error != 0)
103 cmdq_error(item, "%s: %s", path, strerror(error));
104 else if (bsize != 0) {
105 if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
106 target, cdata->flags, &new_item) < 0)
107 cdata->retval = CMD_RETURN_ERROR;
108 else if (new_item != NULL)
109 cdata->after = new_item;
112 n = ++cdata->current;
113 if (n < cdata->nfiles)
114 file_read(c, cdata->files[n], cmd_source_file_done, cdata);
115 else {
116 cmd_source_file_complete(c, cdata);
117 cmdq_continue(item);
121 static void
122 cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
124 char resolved[PATH_MAX];
126 if (realpath(path, resolved) == NULL) {
127 log_debug("%s: realpath(\"%s\") failed: %s", __func__,
128 path, strerror(errno));
129 } else
130 path = resolved;
132 log_debug("%s: %s", __func__, path);
133 cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
134 sizeof *cdata->files);
135 cdata->files[cdata->nfiles++] = xstrdup(path);
138 static enum cmd_retval
139 cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
141 struct args *args = cmd_get_args(self);
142 struct cmd_source_file_data *cdata;
143 struct client *c = cmdq_get_client(item);
144 enum cmd_retval retval = CMD_RETURN_NORMAL;
145 char *pattern, *cwd, *expanded = NULL;
146 const char *path, *error;
147 glob_t g;
148 int result;
149 u_int i, j;
151 cdata = xcalloc(1, sizeof *cdata);
152 cdata->item = item;
154 if (args_has(args, 'q'))
155 cdata->flags |= CMD_PARSE_QUIET;
156 if (args_has(args, 'n'))
157 cdata->flags |= CMD_PARSE_PARSEONLY;
158 if (args_has(args, 'v'))
159 cdata->flags |= CMD_PARSE_VERBOSE;
161 utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
163 for (i = 0; i < args_count(args); i++) {
164 path = args_string(args, i);
165 if (args_has(args, 'F')) {
166 free(expanded);
167 expanded = format_single_from_target(item, path);
168 path = expanded;
170 if (strcmp(path, "-") == 0) {
171 cmd_source_file_add(cdata, "-");
172 continue;
175 if (*path == '/')
176 pattern = xstrdup(path);
177 else
178 xasprintf(&pattern, "%s/%s", cwd, path);
179 log_debug("%s: %s", __func__, pattern);
181 if ((result = glob(pattern, 0, NULL, &g)) != 0) {
182 if (result != GLOB_NOMATCH ||
183 (~cdata->flags & CMD_PARSE_QUIET)) {
184 if (result == GLOB_NOMATCH)
185 error = strerror(ENOENT);
186 else if (result == GLOB_NOSPACE)
187 error = strerror(ENOMEM);
188 else
189 error = strerror(EINVAL);
190 cmdq_error(item, "%s: %s", path, error);
191 retval = CMD_RETURN_ERROR;
193 globfree(&g);
194 free(pattern);
195 continue;
197 free(pattern);
199 for (j = 0; j < g.gl_pathc; j++)
200 cmd_source_file_add(cdata, g.gl_pathv[j]);
201 globfree(&g);
203 free(expanded);
205 cdata->after = item;
206 cdata->retval = retval;
208 if (cdata->nfiles != 0) {
209 file_read(c, cdata->files[0], cmd_source_file_done, cdata);
210 retval = CMD_RETURN_WAIT;
211 } else
212 cmd_source_file_complete(c, cdata);
214 free(cwd);
215 return (retval);