306 lines
6.9 KiB
C
306 lines
6.9 KiB
C
/* $NetBSD: selection.c,v 1.2 2002/07/04 20:50:29 christos Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Julio Merino.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. The name authors may not be used to endorse or promote products
|
|
* derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: selection.c,v 1.2 2002/07/04 20:50:29 christos Exp $");
|
|
#endif /* not lint */
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/tty.h>
|
|
#include <dev/wscons/wsconsio.h>
|
|
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "pathnames.h"
|
|
#include "wsmoused.h"
|
|
|
|
/* This struct holds information about a sel. For now there is
|
|
* only one global instace, but using a structre gives us a place for
|
|
* maintaining all the variables together. Also, someone may want to
|
|
* allow multiple sels, so it is easier this way. */
|
|
static struct selection {
|
|
size_t start_row, start_col;
|
|
size_t end_row, end_col;
|
|
size_t abs_start, abs_end;
|
|
size_t text_size;
|
|
char *text;
|
|
} sel;
|
|
|
|
|
|
static void *
|
|
alloc_sel(size_t len)
|
|
{
|
|
void *ptr;
|
|
if ((ptr = malloc(len)) == NULL) {
|
|
warn("Cannot allocate memory for sel %lu",
|
|
(unsigned long)len);
|
|
return NULL;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/*
|
|
* Copies a region of a line inside the buffer pointed by ptr. We use
|
|
* a double pointer because we modify the pointer. When the function
|
|
* finishes, ptr points to the end of the buffer.
|
|
*/
|
|
static char *
|
|
fill_buf(char *ptr, struct mouse *m, size_t row, size_t col, size_t end)
|
|
{
|
|
struct wsdisplay_char ch;
|
|
ch.row = row;
|
|
for (ch.col = col; ch.col < end; ch.col++) {
|
|
if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1) {
|
|
warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
|
|
*ptr++ = ' ';
|
|
} else {
|
|
*ptr++ = ch.letter;
|
|
}
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
|
|
/*
|
|
* This function scans the specified line and checks its
|
|
* length. Characters at the end of it which match isspace() are not
|
|
* counted.
|
|
*/
|
|
static size_t
|
|
row_length(struct mouse *m, size_t row)
|
|
{
|
|
struct wsdisplay_char ch;
|
|
|
|
ch.col = m->max_col;
|
|
ch.row = row;
|
|
do {
|
|
if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1)
|
|
warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
|
|
ch.col--;
|
|
} while (isspace((unsigned char)ch.letter));
|
|
return ch.col + 2;
|
|
}
|
|
|
|
/*
|
|
* This (complex) function copies all the text englobed in the current
|
|
* sel to the sel buffer. It does space trimming at end of
|
|
* lines if it is selected.
|
|
*/
|
|
static void
|
|
sel_copy_text(struct mouse *m)
|
|
{
|
|
char *str, *ptr;
|
|
size_t r, l;
|
|
|
|
if (sel.start_row == sel.end_row) {
|
|
/* Selection is one row */
|
|
l = row_length(m, sel.start_row);
|
|
if (sel.start_col > l)
|
|
/* Selection is after last character,
|
|
* therefore it is empty */
|
|
str = NULL;
|
|
else {
|
|
if (sel.end_col > l)
|
|
sel.end_col = l;
|
|
ptr = str = alloc_sel(sel.end_col - sel.start_col + 1);
|
|
if (ptr == NULL)
|
|
return;
|
|
|
|
ptr = fill_buf(ptr, m, sel.start_row, sel.start_col,
|
|
sel.end_col);
|
|
*ptr = '\0';
|
|
}
|
|
} else {
|
|
/* Selection is multiple rows */
|
|
ptr = str = alloc_sel(sel.abs_end - sel.abs_start + 1);
|
|
if (ptr == NULL)
|
|
return;
|
|
|
|
/* Calculate and copy first line */
|
|
l = row_length(m, sel.start_row);
|
|
if (sel.start_col < l) {
|
|
ptr = fill_buf(ptr, m, sel.start_row, sel.start_col, l);
|
|
*ptr++ = '\r';
|
|
}
|
|
|
|
/* Copy mid lines if there are any */
|
|
if ((sel.end_row - sel.start_row) > 1) {
|
|
for (r = sel.start_row + 1; r <= sel.end_row - 1; r++) {
|
|
ptr = fill_buf(ptr, m, r, 0, row_length(m, r));
|
|
*ptr++ = '\r';
|
|
}
|
|
}
|
|
|
|
/* Calculate and copy end line */
|
|
l = row_length(m, sel.end_row);
|
|
if (sel.end_col < l)
|
|
l = sel.end_col;
|
|
ptr = fill_buf(ptr, m, sel.end_row, 0, l);
|
|
*ptr = '\0';
|
|
}
|
|
|
|
if (sel.text != NULL) {
|
|
free(sel.text);
|
|
sel.text = NULL;
|
|
}
|
|
|
|
if (str != NULL) {
|
|
sel.text = str;
|
|
sel.text_size = ptr - str;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes sel data. It should be called only once, at
|
|
* wsmoused startup to initialize pointers.
|
|
*/
|
|
void
|
|
mouse_sel_init()
|
|
{
|
|
memset(&sel, 0, sizeof(struct selection));
|
|
}
|
|
|
|
/*
|
|
* Starts a sel (when mouse is pressed).
|
|
*/
|
|
void
|
|
mouse_sel_start(struct mouse *m)
|
|
{
|
|
if (sel.text != NULL) {
|
|
free(sel.text);
|
|
sel.text = NULL;
|
|
}
|
|
|
|
sel.start_row = m->row;
|
|
sel.start_col = m->col;
|
|
mouse_sel_calculate(m);
|
|
m->selecting = 1;
|
|
}
|
|
|
|
/*
|
|
* Ends a sel. Text is copied to memory for future pasting and
|
|
* highlighted region is returned to normal state.
|
|
*/
|
|
void
|
|
mouse_sel_end(struct mouse *m)
|
|
{
|
|
size_t i;
|
|
|
|
mouse_sel_calculate(m);
|
|
|
|
/* Invert sel coordinates if needed */
|
|
if (sel.start_col > sel.end_col) {
|
|
i = sel.end_col;
|
|
sel.end_col = sel.start_col;
|
|
sel.start_col = i;
|
|
}
|
|
if (sel.start_row > sel.end_row) {
|
|
i = sel.end_row;
|
|
sel.end_row = sel.start_row;
|
|
sel.start_row = i;
|
|
}
|
|
|
|
sel_copy_text(m);
|
|
m->selecting = 0;
|
|
}
|
|
|
|
/*
|
|
* Calculates sel absolute postitions.
|
|
*/
|
|
void
|
|
mouse_sel_calculate(struct mouse *m)
|
|
{
|
|
size_t i = m->max_col + 1;
|
|
|
|
sel.end_row = m->row;
|
|
sel.end_col = m->col;
|
|
sel.abs_start = sel.start_row * i + sel.start_col;
|
|
sel.abs_end = sel.end_row * i + sel.end_col;
|
|
|
|
if (sel.abs_start > sel.abs_end) {
|
|
i = sel.abs_end;
|
|
sel.abs_end = sel.abs_start;
|
|
sel.abs_start = i;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hides highlighted region, returning it to normal colors.
|
|
*/
|
|
void
|
|
mouse_sel_hide(struct mouse *m)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = sel.abs_start; i <= sel.abs_end; i++)
|
|
char_invert(m, 0, i);
|
|
}
|
|
|
|
/*
|
|
* Highlights selected region.
|
|
*/
|
|
void
|
|
mouse_sel_show(struct mouse *m)
|
|
{
|
|
size_t i;
|
|
|
|
mouse_sel_calculate(m);
|
|
for (i = sel.abs_start; i <= sel.abs_end; i++)
|
|
char_invert(m, 0, i);
|
|
}
|
|
|
|
|
|
/*
|
|
* Pastes selected text into the active console.
|
|
*/
|
|
void
|
|
mouse_sel_paste(struct mouse *m)
|
|
{
|
|
size_t i;
|
|
|
|
if (sel.text == NULL)
|
|
return;
|
|
for (i = 0; i < sel.text_size; i++)
|
|
if (ioctl(m->tty_fd, TIOCSTI, &sel.text[i]) == -1)
|
|
warn("ioctl(TIOCSTI)");
|
|
}
|