GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/paste.c Lines: 0 117 0.0 %
Date: 2017-11-13 Branches: 0 380 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: paste.c,v 1.39 2017/01/24 13:28:33 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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
#include <time.h>
24
#include <vis.h>
25
26
#include "tmux.h"
27
28
/*
29
 * Set of paste buffers. Note that paste buffer data is not necessarily a C
30
 * string!
31
 */
32
33
struct paste_buffer {
34
	char		*data;
35
	size_t		 size;
36
37
	char		*name;
38
	time_t		 created;
39
	int		 automatic;
40
	u_int		 order;
41
42
	RB_ENTRY(paste_buffer) name_entry;
43
	RB_ENTRY(paste_buffer) time_entry;
44
};
45
46
static u_int	paste_next_index;
47
static u_int	paste_next_order;
48
static u_int	paste_num_automatic;
49
static RB_HEAD(paste_name_tree, paste_buffer) paste_by_name;
50
static RB_HEAD(paste_time_tree, paste_buffer) paste_by_time;
51
52
static int	paste_cmp_names(const struct paste_buffer *,
53
		    const struct paste_buffer *);
54
RB_GENERATE_STATIC(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
55
56
static int	paste_cmp_times(const struct paste_buffer *,
57
		    const struct paste_buffer *);
58
RB_GENERATE_STATIC(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
59
60
static int
61
paste_cmp_names(const struct paste_buffer *a, const struct paste_buffer *b)
62
{
63
	return (strcmp(a->name, b->name));
64
}
65
66
static int
67
paste_cmp_times(const struct paste_buffer *a, const struct paste_buffer *b)
68
{
69
	if (a->order > b->order)
70
		return (-1);
71
	if (a->order < b->order)
72
		return (1);
73
	return (0);
74
}
75
76
/* Get paste buffer name. */
77
const char *
78
paste_buffer_name(struct paste_buffer *pb)
79
{
80
	return (pb->name);
81
}
82
83
/* Get paste buffer order. */
84
u_int
85
paste_buffer_order(struct paste_buffer *pb)
86
{
87
	return (pb->order);
88
}
89
90
/* Get paste buffer created. */
91
time_t
92
paste_buffer_created(struct paste_buffer *pb)
93
{
94
	return (pb->created);
95
}
96
97
/* Get paste buffer data. */
98
const char *
99
paste_buffer_data(struct paste_buffer *pb, size_t *size)
100
{
101
	if (size != NULL)
102
		*size = pb->size;
103
	return (pb->data);
104
}
105
106
/* Walk paste buffers by time. */
107
struct paste_buffer *
108
paste_walk(struct paste_buffer *pb)
109
{
110
	if (pb == NULL)
111
		return (RB_MIN(paste_time_tree, &paste_by_time));
112
	return (RB_NEXT(paste_time_tree, &paste_by_time, pb));
113
}
114
115
/* Get the most recent automatic buffer. */
116
struct paste_buffer *
117
paste_get_top(const char **name)
118
{
119
	struct paste_buffer	*pb;
120
121
	pb = RB_MIN(paste_time_tree, &paste_by_time);
122
	if (pb == NULL)
123
		return (NULL);
124
	if (name != NULL)
125
		*name = pb->name;
126
	return (pb);
127
}
128
129
/* Get a paste buffer by name. */
130
struct paste_buffer *
131
paste_get_name(const char *name)
132
{
133
	struct paste_buffer	pbfind;
134
135
	if (name == NULL || *name == '\0')
136
		return (NULL);
137
138
	pbfind.name = (char *)name;
139
	return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind));
140
}
141
142
/* Free a paste buffer. */
143
void
144
paste_free(struct paste_buffer *pb)
145
{
146
	RB_REMOVE(paste_name_tree, &paste_by_name, pb);
147
	RB_REMOVE(paste_time_tree, &paste_by_time, pb);
148
	if (pb->automatic)
149
		paste_num_automatic--;
150
151
	free(pb->data);
152
	free(pb->name);
153
	free(pb);
154
}
155
156
/*
157
 * Add an automatic buffer, freeing the oldest automatic item if at limit. Note
158
 * that the caller is responsible for allocating data.
159
 */
160
void
161
paste_add(char *data, size_t size)
162
{
163
	struct paste_buffer	*pb, *pb1;
164
	u_int			 limit;
165
166
	if (size == 0) {
167
		free(data);
168
		return;
169
	}
170
171
	limit = options_get_number(global_options, "buffer-limit");
172
	RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) {
173
		if (paste_num_automatic < limit)
174
			break;
175
		if (pb->automatic)
176
			paste_free(pb);
177
	}
178
179
	pb = xmalloc(sizeof *pb);
180
181
	pb->name = NULL;
182
	do {
183
		free(pb->name);
184
		xasprintf(&pb->name, "buffer%04u", paste_next_index);
185
		paste_next_index++;
186
	} while (paste_get_name(pb->name) != NULL);
187
188
	pb->data = data;
189
	pb->size = size;
190
191
	pb->automatic = 1;
192
	paste_num_automatic++;
193
194
	pb->created = time(NULL);
195
196
	pb->order = paste_next_order++;
197
	RB_INSERT(paste_name_tree, &paste_by_name, pb);
198
	RB_INSERT(paste_time_tree, &paste_by_time, pb);
199
}
200
201
/* Rename a paste buffer. */
202
int
203
paste_rename(const char *oldname, const char *newname, char **cause)
204
{
205
	struct paste_buffer	*pb, *pb_new;
206
207
	if (cause != NULL)
208
		*cause = NULL;
209
210
	if (oldname == NULL || *oldname == '\0') {
211
		if (cause != NULL)
212
			*cause = xstrdup("no buffer");
213
		return (-1);
214
	}
215
	if (newname == NULL || *newname == '\0') {
216
		if (cause != NULL)
217
			*cause = xstrdup("new name is empty");
218
		return (-1);
219
	}
220
221
	pb = paste_get_name(oldname);
222
	if (pb == NULL) {
223
		if (cause != NULL)
224
			xasprintf(cause, "no buffer %s", oldname);
225
		return (-1);
226
	}
227
228
	pb_new = paste_get_name(newname);
229
	if (pb_new != NULL) {
230
		if (cause != NULL)
231
			xasprintf(cause, "buffer %s already exists", newname);
232
		return (-1);
233
	}
234
235
	RB_REMOVE(paste_name_tree, &paste_by_name, pb);
236
237
	free(pb->name);
238
	pb->name = xstrdup(newname);
239
240
	if (pb->automatic)
241
		paste_num_automatic--;
242
	pb->automatic = 0;
243
244
	RB_INSERT(paste_name_tree, &paste_by_name, pb);
245
246
	return (0);
247
}
248
249
/*
250
 * Add or replace an item in the store. Note that the caller is responsible for
251
 * allocating data.
252
 */
253
int
254
paste_set(char *data, size_t size, const char *name, char **cause)
255
{
256
	struct paste_buffer	*pb, *old;
257
258
	if (cause != NULL)
259
		*cause = NULL;
260
261
	if (size == 0) {
262
		free(data);
263
		return (0);
264
	}
265
	if (name == NULL) {
266
		paste_add(data, size);
267
		return (0);
268
	}
269
270
	if (*name == '\0') {
271
		if (cause != NULL)
272
			*cause = xstrdup("empty buffer name");
273
		return (-1);
274
	}
275
276
	pb = xmalloc(sizeof *pb);
277
278
	pb->name = xstrdup(name);
279
280
	pb->data = data;
281
	pb->size = size;
282
283
	pb->automatic = 0;
284
	pb->order = paste_next_order++;
285
286
	pb->created = time(NULL);
287
288
	if ((old = paste_get_name(name)) != NULL)
289
		paste_free(old);
290
291
	RB_INSERT(paste_name_tree, &paste_by_name, pb);
292
	RB_INSERT(paste_time_tree, &paste_by_time, pb);
293
294
	return (0);
295
}
296
297
/* Convert start of buffer into a nice string. */
298
char *
299
paste_make_sample(struct paste_buffer *pb)
300
{
301
	char		*buf;
302
	size_t		 len, used;
303
	const int	 flags = VIS_OCTAL|VIS_TAB|VIS_NL;
304
	const size_t	 width = 200;
305
306
	len = pb->size;
307
	if (len > width)
308
		len = width;
309
	buf = xreallocarray(NULL, len, 4 + 4);
310
311
	used = utf8_strvis(buf, pb->data, len, flags);
312
	if (pb->size > width || used > width)
313
		strlcpy(buf + width, "...", 4);
314
	return (buf);
315
}