Merge branch 'obsd-master'
[tmux.git] / cmd-source-file.c
blobb390ed633644983fa0d4dfed1aafc1d39286b40c
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 log_debug("%s: %s", __func__, path);
125 cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
126 sizeof *cdata->files);
127 cdata->files[cdata->nfiles++] = xstrdup(path);
130 static enum cmd_retval
131 cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
133 struct args *args = cmd_get_args(self);
134 struct cmd_source_file_data *cdata;
135 struct client *c = cmdq_get_client(item);
136 enum cmd_retval retval = CMD_RETURN_NORMAL;
137 char *pattern, *cwd, *expanded = NULL;
138 const char *path, *error;
139 glob_t g;
140 int result;
141 u_int i, j;
143 cdata = xcalloc(1, sizeof *cdata);
144 cdata->item = item;
146 if (args_has(args, 'q'))
147 cdata->flags |= CMD_PARSE_QUIET;
148 if (args_has(args, 'n'))
149 cdata->flags |= CMD_PARSE_PARSEONLY;
150 if (args_has(args, 'v'))
151 cdata->flags |= CMD_PARSE_VERBOSE;
153 utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
155 for (i = 0; i < args_count(args); i++) {
156 path = args_string(args, i);
157 if (args_has(args, 'F')) {
158 free(expanded);
159 expanded = format_single_from_target(item, path);
160 path = expanded;
162 if (strcmp(path, "-") == 0) {
163 cmd_source_file_add(cdata, "-");
164 continue;
167 if (*path == '/')
168 pattern = xstrdup(path);
169 else
170 xasprintf(&pattern, "%s/%s", cwd, path);
171 log_debug("%s: %s", __func__, pattern);
173 if ((result = glob(pattern, 0, NULL, &g)) != 0) {
174 if (result != GLOB_NOMATCH ||
175 (~cdata->flags & CMD_PARSE_QUIET)) {
176 if (result == GLOB_NOMATCH)
177 error = strerror(ENOENT);
178 else if (result == GLOB_NOSPACE)
179 error = strerror(ENOMEM);
180 else
181 error = strerror(EINVAL);
182 cmdq_error(item, "%s: %s", path, error);
183 retval = CMD_RETURN_ERROR;
185 globfree(&g);
186 free(pattern);
187 continue;
189 free(pattern);
191 for (j = 0; j < g.gl_pathc; j++)
192 cmd_source_file_add(cdata, g.gl_pathv[j]);
193 globfree(&g);
195 free(expanded);
197 cdata->after = item;
198 cdata->retval = retval;
200 if (cdata->nfiles != 0) {
201 file_read(c, cdata->files[0], cmd_source_file_done, cdata);
202 retval = CMD_RETURN_WAIT;
203 } else
204 cmd_source_file_complete(c, cdata);
206 free(cwd);
207 return (retval);