selection.c revision 1.1
1/* $NetBSD: selection.c,v 1.1 2002/06/26 23:13:08 christos Exp $ */ 2 3/* 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julio Merino. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. The name authors may not be used to endorse or promote products 16 * derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33 34#ifndef lint 35__RCSID("$NetBSD: selection.c,v 1.1 2002/06/26 23:13:08 christos Exp $"); 36#endif /* not lint */ 37 38#include <sys/ioctl.h> 39#include <sys/time.h> 40#include <sys/types.h> 41#include <sys/tty.h> 42#include <dev/wscons/wsconsio.h> 43 44#include <ctype.h> 45#include <fcntl.h> 46#include <err.h> 47#include <errno.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <unistd.h> 52 53#include "pathnames.h" 54#include "wsmoused.h" 55 56/* This struct holds information about a sel. For now there is 57 * only one global instace, but using a structre gives us a place for 58 * maintaining all the variables together. Also, someone may want to 59 * allow multiple sels, so it is easier this way. */ 60static struct selection { 61 size_t start_row, start_col; 62 size_t end_row, end_col; 63 size_t abs_start, abs_end; 64 size_t text_size; 65 char *text; 66} sel; 67 68 69static void * 70alloc_sel(size_t len) 71{ 72 void *ptr; 73 if ((ptr = malloc(len)) == NULL) { 74 warn("Cannot allocate memory for sel %lu", 75 (unsigned long)len); 76 return NULL; 77 } 78 return ptr; 79} 80 81static void 82fill_buf(char *ptr, struct mouse *m, size_t row, size_t col, size_t end) 83{ 84 struct wsdisplay_char ch; 85 ch.row = sel.start_row; 86 for (ch.col = col; ch.col < end; ch.col++) { 87 if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1) { 88 warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed"); 89 *ptr++ = ' '; 90 } else { 91 *ptr++ = ch.letter; 92 } 93 } 94} 95 96 97/* 98 * This function scans the specified line and checks its 99 * length. Characters at the end of it which match isspace() are not 100 * counted. 101 */ 102static size_t 103row_length(struct mouse *m, size_t row) 104{ 105 struct wsdisplay_char ch; 106 107 ch.col = m->max_col; 108 ch.row = row; 109 do { 110 if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1) 111 warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed"); 112 ch.col--; 113 } while (isspace((unsigned char)ch.letter)); 114 return ch.col + 2; 115} 116 117/* 118 * This (complex) function copies all the text englobed in the current 119 * sel to the sel buffer. It does space trimming at end of 120 * lines if it is selected. 121 */ 122static void 123sel_copy_text(struct mouse *m) 124{ 125 char *str, *ptr; 126 size_t r, l; 127 128 if (sel.start_row == sel.end_row) { 129 /* Selection is one row */ 130 l = row_length(m, sel.start_row); 131 if (sel.start_col > l) 132 /* Selection is after last character, 133 * therefore it is empty */ 134 str = NULL; 135 else { 136 if (sel.end_col > l) 137 sel.end_col = l; 138 ptr = str = alloc_sel( sel.end_col - sel.start_col + 1); 139 if (ptr == NULL) 140 return; 141 142 fill_buf(ptr, m, sel.start_row, sel.start_col, 143 sel.end_col); 144 *ptr = '\0'; 145 } 146 } else { 147 /* Selection is multiple rows */ 148 ptr = str = alloc_sel(sel.abs_end - sel.abs_start + 1); 149 if (ptr == NULL) 150 return; 151 152 /* Calculate and copy first line */ 153 l = row_length(m, sel.start_row); 154 if (sel.start_col < l) { 155 fill_buf(ptr, m, sel.start_row, sel.start_col, l); 156 *ptr++ = '\r'; 157 } 158 159 /* Copy mid lines if there are any */ 160 if ((sel.end_row - sel.start_row) > 1) { 161 for (r = sel.start_row + 1; r <= sel.end_row - 1; r++) { 162 fill_buf(ptr, m, r, 0, row_length(m, r)); 163 *ptr++ = '\r'; 164 } 165 } 166 167 /* Calculate and copy end line */ 168 l = row_length(m, sel.end_row); 169 if (sel.end_col < l) 170 l = sel.end_col; 171 fill_buf(ptr, m, sel.end_row, 0, l); 172 *ptr = '\0'; 173 } 174 175 if (sel.text != NULL) { 176 free(sel.text); 177 sel.text = NULL; 178 } 179 180 if (str != NULL) { 181 sel.text = str; 182 sel.text_size = ptr - str; 183 } 184} 185 186/* 187 * Initializes sel data. It should be called only once, at 188 * wsmoused startup to initialize pointers. 189 */ 190void 191mouse_sel_init() 192{ 193 memset(&sel, 0, sizeof(struct selection)); 194} 195 196/* 197 * Starts a sel (when mouse is pressed). 198 */ 199void 200mouse_sel_start(struct mouse *m) 201{ 202 if (sel.text != NULL) { 203 free(sel.text); 204 sel.text = NULL; 205 } 206 207 sel.start_row = m->row; 208 sel.start_col = m->col; 209 mouse_sel_calculate(m); 210 m->selecting = 1; 211} 212 213/* 214 * Ends a sel. Text is copied to memory for future pasting and 215 * highlighted region is returned to normal state. 216 */ 217void 218mouse_sel_end(struct mouse *m) 219{ 220 size_t i; 221 222 mouse_sel_calculate(m); 223 224 /* Invert sel coordinates if needed */ 225 if (sel.start_col > sel.end_col) { 226 i = sel.end_col; 227 sel.end_col = sel.start_col; 228 sel.start_col = i; 229 } 230 if (sel.start_row > sel.end_row) { 231 i = sel.end_row; 232 sel.end_row = sel.start_row; 233 sel.start_row = i; 234 } 235 236 sel_copy_text(m); 237 m->selecting = 0; 238} 239 240/* 241 * Calculates sel absolute postitions. 242 */ 243void 244mouse_sel_calculate(struct mouse *m) 245{ 246 size_t i = m->max_col + 1; 247 248 sel.end_row = m->row; 249 sel.end_col = m->col; 250 sel.abs_start = sel.start_row * i + sel.start_col; 251 sel.abs_end = sel.end_row * i + sel.end_col; 252 253 if (sel.abs_start > sel.abs_end) { 254 i = sel.abs_end; 255 sel.abs_end = sel.abs_start; 256 sel.abs_start = i; 257 } 258} 259 260/* 261 * Hides highlighted region, returning it to normal colors. 262 */ 263void 264mouse_sel_hide(struct mouse *m) 265{ 266 size_t i; 267 268 for (i = sel.abs_start; i <= sel.abs_end; i++) 269 char_invert(m, 0, i); 270} 271 272/* 273 * Highlights selected region. 274 */ 275void 276mouse_sel_show(struct mouse *m) 277{ 278 size_t i; 279 280 mouse_sel_calculate(m); 281 for (i = sel.abs_start; i <= sel.abs_end; i++) 282 char_invert(m, 0, i); 283} 284 285 286/* 287 * Pastes selected text into the active console. 288 */ 289void 290mouse_sel_paste(struct mouse *m) 291{ 292 size_t i; 293 294 if (sel.text == NULL) 295 return; 296 for (i = 0; i < sel.text_size; i++) 297 if (ioctl(m->tty_fd, TIOCSTI, &sel.text[i]) == -1) 298 warn("ioctl(TIOCSTI)"); 299} 300