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