cmd-save-buffer.c revision 1.20
1/* $OpenBSD: cmd-save-buffer.c,v 1.20 2013/10/10 12:00:22 nicm Exp $ */
2
3/*
4 * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
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/stat.h>
21
22#include <errno.h>
23#include <stdlib.h>
24#include <string.h>
25#include <vis.h>
26
27#include "tmux.h"
28
29/*
30 * Saves a paste buffer to a file.
31 */
32
33enum cmd_retval	 cmd_save_buffer_exec(struct cmd *, struct cmd_q *);
34
35const struct cmd_entry cmd_save_buffer_entry = {
36	"save-buffer", "saveb",
37	"ab:", 1, 1,
38	"[-a] " CMD_BUFFER_USAGE " path",
39	0,
40	NULL,
41	cmd_save_buffer_exec
42};
43
44const struct cmd_entry cmd_show_buffer_entry = {
45	"show-buffer", "showb",
46	"b:", 0, 0,
47	CMD_BUFFER_USAGE,
48	0,
49	NULL,
50	cmd_save_buffer_exec
51};
52
53enum cmd_retval
54cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
55{
56	struct args		*args = self->args;
57	struct client		*c;
58	struct session          *s;
59	struct paste_buffer	*pb;
60	const char		*path, *newpath, *wd;
61	char			*cause, *start, *end;
62	size_t			 size, used;
63	int			 buffer;
64	mode_t			 mask;
65	FILE			*f;
66	char			*msg;
67	size_t			 msglen;
68
69	if (!args_has(args, 'b')) {
70		if ((pb = paste_get_top(&global_buffers)) == NULL) {
71			cmdq_error(cmdq, "no buffers");
72			return (CMD_RETURN_ERROR);
73		}
74	} else {
75		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
76		if (cause != NULL) {
77			cmdq_error(cmdq, "buffer %s", cause);
78			free(cause);
79			return (CMD_RETURN_ERROR);
80		}
81
82		pb = paste_get_index(&global_buffers, buffer);
83		if (pb == NULL) {
84			cmdq_error(cmdq, "no buffer %d", buffer);
85			return (CMD_RETURN_ERROR);
86		}
87	}
88
89	if (self->entry == &cmd_show_buffer_entry)
90		path = "-";
91	else
92		path = args->argv[0];
93	if (strcmp(path, "-") == 0) {
94		c = cmdq->client;
95		if (c == NULL) {
96			cmdq_error(cmdq, "can't write to stdout");
97			return (CMD_RETURN_ERROR);
98		}
99		if (c->session == NULL || (c->flags & CLIENT_CONTROL))
100			goto do_stdout;
101		goto do_print;
102	}
103
104	c = cmdq->client;
105	if (c != NULL)
106		wd = c->cwd;
107	else if ((s = cmd_current_session(cmdq, 0)) != NULL) {
108		wd = options_get_string(&s->options, "default-path");
109		if (*wd == '\0')
110			wd = s->cwd;
111	} else
112		wd = NULL;
113	if (wd != NULL && *wd != '\0') {
114		newpath = get_full_path(wd, path);
115		if (newpath != NULL)
116			path = newpath;
117	}
118
119	mask = umask(S_IRWXG | S_IRWXO);
120	if (args_has(self->args, 'a'))
121		f = fopen(path, "ab");
122	else
123		f = fopen(path, "wb");
124	umask(mask);
125	if (f == NULL) {
126		cmdq_error(cmdq, "%s: %s", path, strerror(errno));
127		return (CMD_RETURN_ERROR);
128	}
129	if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
130		cmdq_error(cmdq, "%s: fwrite error", path);
131		fclose(f);
132		return (CMD_RETURN_ERROR);
133	}
134	fclose(f);
135
136	return (CMD_RETURN_NORMAL);
137
138do_stdout:
139	evbuffer_add(c->stdout_data, pb->data, pb->size);
140	server_push_stdout(c);
141	return (CMD_RETURN_NORMAL);
142
143do_print:
144	if (pb->size > (INT_MAX / 4) - 1) {
145		cmdq_error(cmdq, "buffer too big");
146		return (CMD_RETURN_ERROR);
147	}
148	msg = NULL;
149	msglen = 0;
150
151	used = 0;
152	while (used != pb->size) {
153		start = pb->data + used;
154		end = memchr(start, '\n', pb->size - used);
155		if (end != NULL)
156			size = end - start;
157		else
158			size = pb->size - used;
159
160		msglen = size * 4 + 1;
161		msg = xrealloc(msg, 1, msglen);
162
163		strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
164		cmdq_print(cmdq, "%s", msg);
165
166		used += size + (end != NULL);
167	}
168
169	free(msg);
170	return (CMD_RETURN_NORMAL);
171}
172