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