xref: /netbsd-src/external/bsd/tmux/dist/cmd-paste-buffer.c (revision cb861154c176d3dcc8ff846f449e3c16a5f5edb5)
1 /* $Id: cmd-paste-buffer.c,v 1.2 2011/03/12 03:02:58 christos Exp $ */
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 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Paste paste buffer if present.
28  */
29 
30 struct cmd_paste_buffer_data {
31 	char	*target;
32 	int	 buffer;
33 
34 	int	 flag_delete;
35 	char	*sepstr;
36 };
37 
38 void	cmd_paste_buffer_init(struct cmd *, int);
39 int	cmd_paste_buffer_parse(struct cmd *, int, char **, char **);
40 int	cmd_paste_buffer_exec(struct cmd *, struct cmd_ctx *);
41 void	cmd_paste_buffer_filter(
42 	    struct window_pane *, const char *, size_t, char *);
43 void	cmd_paste_buffer_free(struct cmd *);
44 size_t	cmd_paste_buffer_print(struct cmd *, char *, size_t);
45 
46 const struct cmd_entry cmd_paste_buffer_entry = {
47 	"paste-buffer", "pasteb",
48 	"[-dr] [-s separator] [-b buffer-index] [-t target-pane]",
49 	0, "",
50 	cmd_paste_buffer_init,
51 	cmd_paste_buffer_parse,
52 	cmd_paste_buffer_exec,
53 	cmd_paste_buffer_free,
54 	cmd_paste_buffer_print
55 };
56 
57 /* ARGSUSED */
58 void
59 cmd_paste_buffer_init(struct cmd *self, unused int arg)
60 {
61 	struct cmd_paste_buffer_data	*data;
62 
63 	self->data = data = xmalloc(sizeof *data);
64 	data->target = NULL;
65 	data->buffer = -1;
66 	data->flag_delete = 0;
67 	data->sepstr = xstrdup("\r");
68 }
69 
70 int
71 cmd_paste_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
72 {
73 	struct cmd_paste_buffer_data	*data;
74 	int			 opt, n;
75 	const char		*errstr;
76 
77 	cmd_paste_buffer_init(self, 0);
78 	data = self->data;
79 
80 	while ((opt = getopt(argc, argv, "b:ds:t:r")) != -1) {
81 		switch (opt) {
82 		case 'b':
83 			if (data->buffer == -1) {
84 				n = strtonum(optarg, 0, INT_MAX, &errstr);
85 				if (errstr != NULL) {
86 					xasprintf(cause, "buffer %s", errstr);
87 					goto error;
88 				}
89 				data->buffer = n;
90 			}
91 			break;
92 		case 'd':
93 			data->flag_delete = 1;
94 			break;
95 		case 's':
96 			if (data->sepstr != NULL)
97 				xfree(data->sepstr);
98 			data->sepstr = xstrdup(optarg);
99 			break;
100 		case 't':
101 			if (data->target == NULL)
102 				data->target = xstrdup(optarg);
103 			break;
104 		case 'r':
105 			if (data->sepstr != NULL)
106 				xfree(data->sepstr);
107 			data->sepstr = xstrdup("\n");
108 			break;
109 		default:
110 			goto usage;
111 		}
112 	}
113 	argc -= optind;
114 	argv += optind;
115 
116 	return (0);
117 
118 usage:
119 	xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
120 
121 error:
122 	self->entry->free(self);
123 	return (-1);
124 }
125 
126 int
127 cmd_paste_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
128 {
129 	struct cmd_paste_buffer_data	*data = self->data;
130 	struct window_pane		*wp;
131 	struct session			*s;
132 	struct paste_buffer		*pb;
133 
134 	if (cmd_find_pane(ctx, data->target, &s, &wp) == NULL)
135 		return (-1);
136 
137 	if (data->buffer == -1)
138 		pb = paste_get_top(&s->buffers);
139 	else {
140 		if ((pb = paste_get_index(&s->buffers, data->buffer)) == NULL) {
141 			ctx->error(ctx, "no buffer %d", data->buffer);
142 			return (-1);
143 		}
144 	}
145 
146 	if (pb != NULL)
147 		cmd_paste_buffer_filter(wp, pb->data, pb->size, data->sepstr);
148 
149 	/* Delete the buffer if -d. */
150 	if (data->flag_delete) {
151 		if (data->buffer == -1)
152 			paste_free_top(&s->buffers);
153 		else
154 			paste_free_index(&s->buffers, data->buffer);
155 	}
156 
157 	return (0);
158 }
159 
160 /* Add bytes to a buffer and filter '\n' according to separator. */
161 void
162 cmd_paste_buffer_filter(
163     struct window_pane *wp, const char *data, size_t size, char *sep)
164 {
165 	const char	*end = data + size;
166 	const char	*lf;
167 	size_t		 seplen;
168 
169 	seplen = strlen(sep);
170 	while ((lf = memchr(data, '\n', end - data)) != NULL) {
171 		if (lf != data)
172 			bufferevent_write(wp->event, data, lf - data);
173 		bufferevent_write(wp->event, sep, seplen);
174 		data = lf + 1;
175 	}
176 
177 	if (end != data)
178 		bufferevent_write(wp->event, data, end - data);
179 }
180 
181 void
182 cmd_paste_buffer_free(struct cmd *self)
183 {
184 	struct cmd_paste_buffer_data	*data = self->data;
185 
186 	if (data->target != NULL)
187 		xfree(data->target);
188 	if (data->sepstr != NULL)
189 		xfree(data->sepstr);
190 	xfree(data);
191 }
192 
193 size_t
194 cmd_paste_buffer_print(struct cmd *self, char *buf, size_t len)
195 {
196 	struct cmd_paste_buffer_data	*data = self->data;
197 	size_t				 off = 0;
198 	int				 r_flag;
199 
200 	r_flag = 0;
201 	if (data->sepstr != NULL)
202 		r_flag = (data->sepstr[0] == '\n' && data->sepstr[1] == '\0');
203 
204 	off += xsnprintf(buf, len, "%s", self->entry->name);
205 	if (data == NULL)
206 		return (off);
207 	if (off < len && data->flag_delete)
208 		off += xsnprintf(buf + off, len - off, " -d");
209 	if (off < len && r_flag)
210 		off += xsnprintf(buf + off, len - off, " -r");
211 	if (off < len && data->buffer != -1)
212 		off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
213 	if (off < len && data->sepstr != NULL && !r_flag) {
214 		size_t slen = strlen(data->sepstr);
215 		char tmp[slen * 4 + 1];
216 		strvisx(tmp, data->sepstr, slen, VIS_OCTAL|VIS_TAB|VIS_NL);
217 		off += cmd_prarg(buf + off, len - off, " -s ", tmp);
218 	}
219 	if (off < len && data->target != NULL)
220 		off += cmd_prarg(buf + off, len - off, " -t ", data->target);
221 	return (off);
222 }
223