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