xref: /openbsd-src/usr.bin/tmux/paste.c (revision 1ac29a775d849917840d63aef99eb2f74bd51d40)
1 /* $OpenBSD: paste.c,v 1.15 2014/02/17 23:07:03 nicm 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 #include <sys/time.h>
21 
22 #include <stdlib.h>
23 #include <string.h>
24 #include <vis.h>
25 
26 #include "tmux.h"
27 
28 /*
29  * Stack of paste buffers. Note that paste buffer data is not necessarily a C
30  * string!
31  */
32 
33 /* Return each item of the stack in turn. */
34 struct paste_buffer *
35 paste_walk_stack(struct paste_stack *ps, u_int *idx)
36 {
37 	struct paste_buffer	*pb;
38 
39 	pb = paste_get_index(ps, *idx);
40 	(*idx)++;
41 	return (pb);
42 }
43 
44 /* Get the top item on the stack. */
45 struct paste_buffer *
46 paste_get_top(struct paste_stack *ps)
47 {
48 	if (ARRAY_LENGTH(ps) == 0)
49 		return (NULL);
50 	return (ARRAY_FIRST(ps));
51 }
52 
53 /* Get an item by its index. */
54 struct paste_buffer *
55 paste_get_index(struct paste_stack *ps, u_int idx)
56 {
57 	if (idx >= ARRAY_LENGTH(ps))
58 		return (NULL);
59 	return (ARRAY_ITEM(ps, idx));
60 }
61 
62 /* Free the top item on the stack. */
63 int
64 paste_free_top(struct paste_stack *ps)
65 {
66 	struct paste_buffer	*pb;
67 
68 	if (ARRAY_LENGTH(ps) == 0)
69 		return (-1);
70 
71 	pb = ARRAY_FIRST(ps);
72 	ARRAY_REMOVE(ps, 0);
73 
74 	free(pb->data);
75 	free(pb);
76 
77 	return (0);
78 }
79 
80 /* Free an item by index. */
81 int
82 paste_free_index(struct paste_stack *ps, u_int idx)
83 {
84 	struct paste_buffer	*pb;
85 
86 	if (idx >= ARRAY_LENGTH(ps))
87 		return (-1);
88 
89 	pb = ARRAY_ITEM(ps, idx);
90 	ARRAY_REMOVE(ps, idx);
91 
92 	free(pb->data);
93 	free(pb);
94 
95 	return (0);
96 }
97 
98 /*
99  * Add an item onto the top of the stack, freeing the bottom if at limit. Note
100  * that the caller is responsible for allocating data.
101  */
102 void
103 paste_add(struct paste_stack *ps, char *data, size_t size, u_int limit)
104 {
105 	struct paste_buffer	*pb;
106 
107 	if (size == 0)
108 		return;
109 
110 	while (ARRAY_LENGTH(ps) >= limit) {
111 		pb = ARRAY_LAST(ps);
112 		free(pb->data);
113 		free(pb);
114 		ARRAY_TRUNC(ps, 1);
115 	}
116 
117 	pb = xmalloc(sizeof *pb);
118 	ARRAY_INSERT(ps, 0, pb);
119 
120 	pb->data = data;
121 	pb->size = size;
122 }
123 
124 
125 /*
126  * Replace an item on the stack. Note that the caller is responsible for
127  * allocating data.
128  */
129 int
130 paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size)
131 {
132 	struct paste_buffer	*pb;
133 
134 	if (size == 0) {
135 		free(data);
136 		return (0);
137 	}
138 
139 	if (idx >= ARRAY_LENGTH(ps))
140 		return (-1);
141 
142 	pb = ARRAY_ITEM(ps, idx);
143 	free(pb->data);
144 
145 	pb->data = data;
146 	pb->size = size;
147 
148 	return (0);
149 }
150 
151 /* Convert a buffer into a visible string. */
152 char *
153 paste_print(struct paste_buffer *pb, size_t width)
154 {
155 	char	*buf;
156 	size_t	 len, used;
157 
158 	if (width < 3)
159 		width = 3;
160 	buf = xmalloc(width * 4 + 1);
161 
162 	len = pb->size;
163 	if (len > width)
164 		len = width;
165 
166 	used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL);
167 	if (pb->size > width || used > width)
168 		strlcpy(buf + width - 3, "...", 4);
169 
170 	return (buf);
171 }
172 
173 /* Paste into a window pane, filtering '\n' according to separator. */
174 void
175 paste_send_pane (struct paste_buffer *pb, struct window_pane *wp,
176     const char *sep, int bracket)
177 {
178 	const char	*data = pb->data, *end = data + pb->size, *lf;
179 	size_t		 seplen;
180 
181 	if (bracket)
182 		bufferevent_write(wp->event, "\033[200~", 6);
183 
184 	seplen = strlen(sep);
185 	while ((lf = memchr(data, '\n', end - data)) != NULL) {
186 		if (lf != data)
187 			bufferevent_write(wp->event, data, lf - data);
188 		bufferevent_write(wp->event, sep, seplen);
189 		data = lf + 1;
190 	}
191 
192 	if (end != data)
193 		bufferevent_write(wp->event, data, end - data);
194 
195 	if (bracket)
196 		bufferevent_write(wp->event, "\033[201~", 6);
197 }
198