File less-429-mouse.patch of Package less

---
 Makefile.in  |    3 
 cmd.h        |    8 +
 command.c    |  237 +++++++++++++++++++++++++++++++++++++++++++++++++++
 decode.c     |   33 +++++++
 defines.h.in |    6 -
 funcs.h      |   10 ++
 less.hlp     |    2 
 less.nro     |   18 +++
 main.c       |    1 
 optfunc.c    |   24 +++++
 opttbl.c     |   11 ++
 output.c     |   22 ++++
 screen.c     |   42 +++++++++
 selection.c  |  271 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 14 files changed, 680 insertions(+), 8 deletions(-)

Index: Makefile.in
===================================================================
--- Makefile.in.orig	2009-06-30 21:27:08.000000000 +0200
+++ Makefile.in	2009-07-07 15:46:59.000000000 +0200
@@ -49,7 +49,8 @@ OBJ = \
 	help.${O} ifile.${O} input.${O} jump.${O} line.${O} linenum.${O} \
 	lsystem.${O} mark.${O} optfunc.${O} option.${O} opttbl.${O} os.${O} \
 	output.${O} pattern.${O} position.${O} prompt.${O} search.${O} signal.${O} \
-	tags.${O} ttyin.${O} version.${O}  @REGEX_O@
+	tags.${O} ttyin.${O} version.${O}  @REGEX_O@ \
+	selection.${O}
 
 all: less$(EXEEXT) lesskey$(EXEEXT) lessecho$(EXEEXT)
 
Index: cmd.h
===================================================================
--- cmd.h.orig	2009-06-30 21:27:09.000000000 +0200
+++ cmd.h	2009-07-07 15:46:59.000000000 +0200
@@ -67,6 +67,10 @@
 #define	A_PREV_TAG		54
 #define	A_FILTER		55
 
+#define A_MOUSE			60
+#define A_MOUSE_END_SEL_IN		61
+#define A_MOUSE_END_SEL_OUT		62
+
 #define	A_INVALID		100
 #define	A_NOACTION		101
 #define	A_UINVALID		102
@@ -130,3 +134,7 @@
 #define SK_BACKTAB		15
 #define SK_CTL_BACKSPACE	16
 #define SK_CONTROL_K		40
+
+/* less input command mode */
+#define M_NORMAL		1
+#define M_MULTICHAR_COMMAND	2
Index: command.c
===================================================================
--- command.c.orig	2009-06-30 21:27:09.000000000 +0200
+++ command.c	2009-07-07 15:46:59.000000000 +0200
@@ -56,7 +56,7 @@ extern int oldbot;
 extern int forw_prompt;
 
 static char ungot[UNGOT_SIZE];
-static char *ungotp = NULL;
+public char *ungotp = NULL;
 #if SHELL_ESCAPE
 static char *shellcmd = NULL;	/* For holding last shell command for "!!" */
 #endif
@@ -72,6 +72,10 @@ static int save_hshift;
 #if PIPEC
 static char pipec;
 #endif
+int mouse_x1, mouse_y1; 	/* mouse coordinates on left mouse button press */
+extern char *selection;	/* buffer with selection */
+extern int selection_size;	/* current selection size */
+extern int xselection;		/* is xselection available */
 
 static void multi_search();
 
@@ -900,13 +904,218 @@ multi_search(pattern, n)
 }
 
 /*
+ * process escape sequence with mouse button action
+ * Note: action on mouse wheel depends on current less input command  mode
+ */
+	static void
+process_mouse_button(mode)
+	int mode;		/* normal mode or multicharacter command mode */
+{
+	int button, mouse_x, mouse_y;
+	int counter;
+
+	button  = getcc() - 32;
+	mouse_x = getcc() - 32;
+	mouse_y = getcc() - 32;
+
+	if (button & 64)
+	{
+		/* mouse wheel used */
+		if (button & 1)
+		{
+			/* mouse wheel down */
+			switch (mode)
+			{
+			case M_NORMAL:
+				/* forward N (default 3) line. */
+				if (number <= 0)
+					number = 3;
+				cmd_exec();
+				if (show_attn == OPT_ONPLUS && number > 1)
+					set_attnpos(bottompos);
+				forward(number, 0, 0);
+				break;
+			case M_MULTICHAR_COMMAND:
+				/* the same behaviour as for down arrow */
+				ungetcc('k');
+				ungetcc('\033');
+				break;
+			default:
+				error("Warnning: Internal error, bad mode for process_mouse_button()", NULL_PARG);
+				break;
+			}
+		} else
+		{
+			/* mouse wheel up */
+			switch (mode)
+			{
+			case M_NORMAL:
+				/* backward N (default 3) line. */
+				if (number <= 0)
+					number = 3;
+				cmd_exec();
+				backward(number, 0, 0);
+				break;
+			case M_MULTICHAR_COMMAND:
+				/* the same behaviour as for up arrow */
+    				ungetcc('j');
+				ungetcc('\033');
+				break;
+			default:
+				error("Warnning: Internal error, bad mode for process_mouse_button()", NULL_PARG);
+				break;
+			}
+		}
+	} else
+	{
+		/* 1-3 mouse button used */
+		switch (button & 3)
+		{
+		case 0:
+			/*
+			 * left button pressed
+			 * xterm is waiting for mouse tracking information
+			 */
+			printf("\033[1;%d;%d;1;%dT",
+				mouse_x, mouse_y, get_swindow() + 1);
+			fflush(stdout);
+			/* save coordinates of selection */
+			mouse_x1 = mouse_x;
+			mouse_y1 = mouse_y;
+			break;
+		case 1:
+			/*
+			 * middle button pressed
+			 * paste selection
+			 */
+			if (xselection)
+				read_xselection();
+			for (counter = selection_size; --counter >= 0;)
+			  ungetcc(selection[counter]);
+			break;
+		case 3:
+			/* any button released */
+			break;
+		}
+	}
+	return;
+}
+
+/*
+ * process escape sequence with mouse action (end of selection)
+ * left mouse button was released inside of given area
+ */
+	static void
+process_mouse_end_selection_in()
+{
+	int button, mouse_x, mouse_y;
+
+	mouse_x = getcc() - 32;
+	mouse_y = getcc() - 32;
+	create_selection(mouse_x1 - 1, mouse_y1 - 1,
+	                 mouse_x - 1, mouse_y - 1);
+	if (xselection)
+		write_xselection();
+	return;
+}
+
+/*
+ * process escape sequence with mouse action (end of selection)
+ * left mouse button was released outside of given area
+ */
+	static void
+process_mouse_end_selection_out()
+{
+	int mouse_x, mouse_y;
+	int mouse_x2, mouse_y2;
+
+	mouse_x1 = getcc() - 32;	/* startx */
+	mouse_y1 = getcc() - 32;	/* starty */
+	mouse_x2 = getcc() - 32;	/* endx - inside of given area */
+	mouse_y2 = getcc() - 32;	/* endy - inside of given area */
+	mouse_x = getcc() - 32;		/* current mouse x coordinate */
+	mouse_y = getcc() - 32;		/* current mouse y coordinate */
+	create_selection(mouse_x1 - 1, mouse_y1 - 1,
+			 mouse_x2 - 1, mouse_y2 - 1);
+	if (xselection)
+		write_xselection();
+	return;
+}
+
+/*
+ * process possible escape sequention with mouse action
+ * in multicharacter command mode
+ */
+	static int
+save_mouse_action(int *c)
+{
+	unsigned char mouse_cbuf[CMDBUF_SIZE + 1]; /* buffer for current input */
+	char *mouse_extra = NULL;
+	int mouse_cbuf_pos;		  /* current position in mouse_cbuf */
+	int mouse_action;		  /* what action is in current input ? */
+
+	mouse_cbuf[0] = *c;
+	mouse_cbuf[1] = '\0';
+	mouse_cbuf_pos = 1;
+
+	while (((mouse_action = mcmd_decode(mouse_cbuf, &mouse_extra)) == A_PREFIX) &&
+	       (mouse_cbuf_pos < CMDBUF_SIZE))
+	{
+		/*
+		 * current input contains prefix for an action
+		 * read next char
+		 */
+		mouse_cbuf[mouse_cbuf_pos++] = getcc();
+		mouse_cbuf[mouse_cbuf_pos] = '\0';
+		mouse_extra = NULL;
+	}
+
+	switch (mouse_action)
+	{
+	case A_MOUSE:
+		/*
+		 * a mouse button pressed or released
+		 */
+		process_mouse_button(M_MULTICHAR_COMMAND);
+		*c = getcc();
+		return 1;
+	case A_MOUSE_END_SEL_IN:
+		/*
+		 * end of mouse selection
+		 * left mouse button was released inside of given area
+		 */
+		process_mouse_end_selection_in();
+		*c = getcc();
+		return 1;
+	case A_MOUSE_END_SEL_OUT:
+		/*
+		 * end of mouse selection
+		 * left mouse button was released outside of given area
+		 */
+		process_mouse_end_selection_out();
+		*c = getcc();
+		return 1;
+	default:
+		/*
+		 * no mouse action
+		 * unget all characters
+		 */
+		while (--mouse_cbuf_pos > 0)
+			ungetcc(mouse_cbuf[mouse_cbuf_pos]);
+		*c = mouse_cbuf[0];
+		return 0;
+	}
+	return 0;
+}
+
+/*
  * Main command processor.
  * Accept and execute commands until a quit command.
  */
 	public void
 commands()
 {
-	register int c;
+	int c;
 	register int action;
 	register char *cbuf;
 	int newaction;
@@ -971,6 +1180,7 @@ commands()
 			 * action to be performed.
 			 */
 			if (mca)
+				while (save_mouse_action(&c)); /* process all escape sequences with mouse actions */
 				switch (mca_char(c))
 				{
 				case MCA_MORE:
@@ -1041,6 +1251,29 @@ commands()
 
 		switch (action)
 		{
+		case A_MOUSE:
+			/*
+			 * a mouse button pressed or released
+			 */
+			process_mouse_button(M_NORMAL);
+			break;
+
+		case A_MOUSE_END_SEL_IN:
+			/*
+			 * end of mouse selection
+			 * left mouse button was released inside of given area
+			 */
+			process_mouse_end_selection_in();
+			break;
+
+		case A_MOUSE_END_SEL_OUT:
+			/*
+			 * end of mouse selection
+			 * left mouse button was released outside of given area
+			 */
+			process_mouse_end_selection_out();
+			break;
+
 		case A_DIGIT:
 			/*
 			 * First digit of a number.
Index: decode.c
===================================================================
--- decode.c.orig	2009-06-30 21:27:09.000000000 +0200
+++ decode.c	2009-07-07 15:46:59.000000000 +0200
@@ -166,6 +166,13 @@ static unsigned char cmdtable[] =
 	'Z','Z',0,			A_QUIT
 };
 
+static unsigned char mousetable[] =
+{
+	ESC,'[','M',0,			A_MOUSE,
+	ESC,'[','t',0,			A_MOUSE_END_SEL_IN,
+	ESC,'[','T',0,			A_MOUSE_END_SEL_OUT
+};
+
 static unsigned char edittable[] =
 {
 	'\t',0,	    			EC_F_COMPLETE,	/* TAB */
@@ -218,6 +225,7 @@ struct tablelist
  * List of command tables and list of line-edit tables.
  */
 static struct tablelist *list_fcmd_tables = NULL;
+static struct tablelist *list_mcmd_tables = NULL;
 static struct tablelist *list_ecmd_tables = NULL;
 static struct tablelist *list_var_tables = NULL;
 static struct tablelist *list_sysvar_tables = NULL;
@@ -293,8 +301,10 @@ init_cmds()
 	/*
 	 * Add the default command tables.
 	 */
+	add_fcmd_table((char*)mousetable, sizeof(mousetable));
 	add_fcmd_table((char*)cmdtable, sizeof(cmdtable));
 	add_ecmd_table((char*)edittable, sizeof(edittable));
+	add_mcmd_table((char*)mousetable, sizeof(mousetable));
 #if USERFILE
 	/*
 	 * For backwards compatibility,
@@ -369,6 +379,18 @@ add_ecmd_table(buf, len)
 }
 
 /*
+ * Add an mouse command table.
+ */
+	public void
+add_mcmd_table(buf, len)
+	char *buf;
+	int len;
+{
+	if (add_cmd_table(&list_mcmd_tables, buf, len) < 0)
+		error("Warning: some mouse commands disabled", NULL_PARG);
+}
+
+/*
  * Add an environment variable table.
  */
 	static void
@@ -523,6 +545,17 @@ ecmd_decode(cmd, sp)
 }
 
 /*
+ * Decode a command from the mousetables list.
+ */
+	public int
+mcmd_decode(cmd, sp)
+	char *cmd;
+	char **sp;
+{
+	return (cmd_decode(list_mcmd_tables, cmd, sp));
+}
+
+/*
  * Get the value of an environment variable.
  * Looks first in the lesskey file, then in the real environment.
  */
Index: defines.h.in
===================================================================
--- defines.h.in.orig	2009-07-07 15:46:58.000000000 +0200
+++ defines.h.in	2009-07-07 15:47:17.000000000 +0200
@@ -219,9 +219,6 @@
 /* Define HAVE_FILENO if you have the fileno() macro. */
 #undef HAVE_FILENO
 
-/* Define to 1 if you have the `tcdrain' function. */
-#undef HAVE_TCDRAIN
-
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
@@ -321,6 +318,9 @@
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define to 1 if you have the `tcdrain' function. */
+#undef HAVE_TCDRAIN
+
 /* Define to 1 if you have the <termcap.h> header file. */
 #undef HAVE_TERMCAP_H
 
Index: funcs.h
===================================================================
--- funcs.h.orig	2009-06-30 21:27:31.000000000 +0200
+++ funcs.h	2009-07-07 15:58:03.000000000 +0200
@@ -89,8 +89,10 @@
 	public void init_cmds ();
 	public void add_fcmd_table ();
 	public void add_ecmd_table ();
+	public void add_mcmd_table ();
 	public int fcmd_decode ();
 	public int ecmd_decode ();
+	public int mcmd_decode ();
 	public char * lgetenv ();
 	public int lesskey ();
 	public void add_hometable ();
@@ -191,6 +193,7 @@
 	public void gomark ();
 	public POSITION markpos ();
 	public void unmark ();
+	public void opt_A ();
 	public void opt_o ();
 	public void opt__O ();
 	public void opt_l ();
@@ -288,3 +291,10 @@
 	public void open_getchr ();
 	public void close_getchr ();
 	public int getchr ();
+	public void clear_selection();
+	public int create_selection(int, int, int, int);
+	public int write_xselection();
+	public int read_xselection();
+	public int is_xselection_available();
+	public void init_mouse_support();
+	public void deinit_mouse_support();
Index: less.hlp
===================================================================
--- less.hlp.orig	2009-06-30 21:27:30.000000000 +0200
+++ less.hlp	2009-07-07 15:58:01.000000000 +0200
@@ -112,6 +112,8 @@
                   Display help (from command line).
   -a  ........  --search-skip-screen
                   Forward search skips current screen.
+  -A  ........  --mouse-support
+		  Use less mouse support (works only in xterm)
   -b [_N]  ....  --buffers=[_N]
                   Number of buffers.
   -B  ........  --auto-buffers
Index: less.nro
===================================================================
--- less.nro.orig	2009-06-30 21:29:16.000000000 +0200
+++ less.nro	2009-07-07 15:58:01.000000000 +0200
@@ -10,7 +10,7 @@ less \- opposite of more
 .br
 .B "less \-\-version"
 .br
-.B "less [\-[+]aBcCdeEfFgGiIJKLmMnNqQrRsSuUVwWX~]"
+.B "less [\-[+]aABcCdeEfFgGiIJKLmMnNqQrRsSuUVwWX~]"
 .br
 .B "     [\-b \fIspace\fP] [\-h \fIlines\fP] [\-j \fIline\fP] [\-k \fIkeyfile\fP]"
 .br
@@ -470,6 +470,22 @@ displayed on the screen,
 thus skipping all lines displayed on the screen.
 By default, searches start at the second line on the screen
 (or after the last found line; see the \-j option).
+.IP "-A or --mouse-support"
+Causes less to process mouse actions itself. Currently
+it works only in xterm. The inspiration comes from vim-6.0.
+.sp
+Cut&Paste function works only internally by default. To access
+X selection you must hold SHIFT key to process the mouse actions
+by xterm. Or you can install
+.I xselection
+utility by which less
+is able to access X selection itself.
+.sp
+Also scrolling by mouse wheel button is supported. You must map
+wheel mouse action on the 4th and 5th mouse button. This is done
+in XF86Config in Section "InputDevice" by option:
+.sp
+	Option	"ZAxisMapping" "4 5"
 .IP "\-b\fIn\fP or \-\-buffers=\fIn\fP"
 Specifies the amount of buffer space
 .I less
Index: main.c
===================================================================
--- main.c.orig	2009-06-30 21:27:09.000000000 +0200
+++ main.c	2009-07-07 15:46:59.000000000 +0200
@@ -32,6 +32,7 @@ public char *	progname;
 public int	quitting;
 public int	secure;
 public int	dohelp;
+public int	xselection = 0;		/* is xselection utility available ? */
 public int	less_is_more;
 
 #if LOGFILE
Index: optfunc.c
===================================================================
--- optfunc.c.orig	2009-06-30 21:27:09.000000000 +0200
+++ optfunc.c	2009-07-07 15:46:59.000000000 +0200
@@ -67,7 +67,31 @@ extern int ul_fg_color, ul_bg_color;
 extern int so_fg_color, so_bg_color;
 extern int bl_fg_color, bl_bg_color;
 #endif
+extern int opt_mouse_support;
 
+/*
+ * Handler for the -A option.
+ */
+	/*ARGSUSED*/
+	public void
+opt_A(type, s)
+	int type;
+	char *s;
+{
+	switch (type)
+	{
+	case TOGGLE:
+		if (opt_mouse_support)
+			init_mouse_support();
+		else
+			deinit_mouse_support();
+		break;
+	case QUERY:
+	case INIT:
+		break;
+	}
+	return;
+}
 
 #if LOGFILE
 /*
Index: opttbl.c
===================================================================
--- opttbl.c.orig	2009-06-30 21:27:09.000000000 +0200
+++ opttbl.c	2009-07-07 15:46:59.000000000 +0200
@@ -56,6 +56,7 @@ public int oldbot;		/* Old bottom of scr
 #if HILITE_SEARCH
 public int hilite_search;	/* Highlight matched search patterns? */
 #endif
+public int opt_mouse_support;	/* Less mouse support (works only with xterm) */
 
 public int less_is_more = 0;	/* Make compatible with POSIX more */
 
@@ -63,6 +64,7 @@ public int less_is_more = 0;	/* Make com
  * Long option names.
  */
 static struct optname a_optname      = { "search-skip-screen",   NULL };
+static struct optname A_optname      = { "mouse-support",   	 NULL };
 static struct optname b_optname      = { "buffers",              NULL };
 static struct optname B__optname     = { "auto-buffers",         NULL };
 static struct optname c_optname      = { "clear-screen",         NULL };
@@ -140,7 +142,14 @@ static struct loption option[] =
 			NULL
 		}
 	},
-
+	{ 'A', &A_optname,
+		BOOL, OPT_OFF, &opt_mouse_support, opt_A,
+		{
+			"Do not use less mouse support",
+			"Use less mouse support (works only in xterm)",
+			NULL
+		}
+	},
 	{ 'b', &b_optname,
 		NUMBER|INIT_HANDLER, 64, &bufspace, opt_b, 
 		{
Index: output.c
===================================================================
--- output.c.orig	2009-06-30 21:27:09.000000000 +0200
+++ output.c	2009-07-07 15:46:59.000000000 +0200
@@ -40,6 +40,8 @@ extern int so_fg_color, so_bg_color;
 extern int bl_fg_color, bl_bg_color;
 #endif
 
+extern char *ungotp;
+
 /*
  * Display the line which is in the line buffer.
  */
@@ -490,7 +492,27 @@ get_return()
 #else
 	c = getchr();
 	if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
+	{
+		/*
+		 * on the standard input can be a sequence (not only one char)
+		 * we have read first char of the potential sequence and
+		 * we want to unget it to internal less buffer but there
+		 * can be older ungotten chracters
+		 *
+		 * we must not to put old ungotten chars inside this sequence
+		 *
+		 * 1. solution is to put this char at the begin of internal
+		 * less buffer (LIFO) to use this character after all older
+		 * ungotten chars. But the user can be mixed that the current
+		 * command is done later
+		 *
+		 * 2. soluton is to discard all old ungotten chars
+		 *
+		 * I prefer the 2. solution
+		 */
+		ungotp = NULL;
 		ungetcc(c);
+	}
 #endif
 }
 
Index: screen.c
===================================================================
--- screen.c.orig	2009-07-07 15:46:59.000000000 +0200
+++ screen.c	2009-07-07 15:46:59.000000000 +0200
@@ -241,6 +241,9 @@ extern int hilite_search;
 extern char *tgetstr();
 extern char *tgoto();
 
+extern int xselection;		/* is xselection available */
+extern int opt_mouse_support;	/* is less mouse support enabled (option -A ) */
+int mouse_support = 0;		/* is less mouse support initialized ? */
 
 /*
  * Change terminal to "raw mode", or restore to "normal" mode.
@@ -1527,6 +1530,42 @@ win32_deinit_term()
 
 #endif
 
+public void
+init_mouse_support()
+{
+	if (mouse_support)
+		/* nothing to do (less mouse support is already inicialized */
+		return;
+
+	/* save old highlight mouse tracking */
+	printf("\033[?1001s");
+	/* enable mouse tracking */
+	printf("\033[?1001h");
+	fflush(stdout);
+	mouse_support = 1;
+
+	/* check if the xselection utility is available and is usable */
+	xselection = is_xselection_available();
+
+	return;
+}
+
+public void
+deinit_mouse_support()
+{
+	if (!mouse_support)
+		/* nothing to do (mouse support was not inicialized) */
+		return;
+
+	/* disable mouse tracking */
+	printf("\033[?1001l");
+	/* restore old highlight mouse tracking */
+	printf("\033[?1001r");
+	fflush(stdout);
+	mouse_support = 0;
+	return;
+}
+
 /*
  * Initialize terminal
  */
@@ -1538,6 +1577,8 @@ init()
 		tputs(sc_init, sc_height, putchr);
 	if (!no_keypad)
 		tputs(sc_s_keypad, sc_height, putchr);
+	if (opt_mouse_support)
+		init_mouse_support();
 	if (top_scroll) 
 	{
 		int i;
@@ -1576,6 +1617,7 @@ deinit()
 		tputs(sc_e_keypad, sc_height, putchr);
 	if (!no_init)
 		tputs(sc_deinit, sc_height, putchr);
+	deinit_mouse_support();
 #else
 	/* Restore system colors. */
 	SETCOLORS(sy_fg_color, sy_bg_color);
Index: selection.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ selection.c	2009-07-07 15:46:59.000000000 +0200
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 1984-2000  Mark Nudelman
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Less License, as specified in the README file.
+ *
+ * For more information about less, or for information on how to
+ * contact the author, see the README file.
+ */
+/*
+ * Copyright (c) 1997-2000  Kazushi (Jam) Marukawa
+ * All rights of japanized routines are reserved.
+ *
+ * You may distribute under the terms of the Less License.
+ */
+
+
+/*
+ * User-level command processor.
+ */
+
+#include <stdio.h>
+#include "less.h"
+#include "position.h"
+#include "option.h"
+#include "cmd.h"
+
+#define IS_CONT(c)  (((c) & 0xC0) == 0x80)
+#define SELECTION_SIZE_STEP 1000
+
+char *selection=NULL;		/* buffer for less internal selection */
+int max_selection_size=0;	/* current size of the buffer for less */
+				/* internal selection */
+int selection_size=0;		/* current size of less internal selection */
+
+extern int utf_mode;
+
+/*
+ * clear less internal selection
+ */
+	public void
+clear_selection()
+{
+	if (selection)
+	{
+		free(selection);
+		selection=NULL;
+		max_selection_size=0;
+		selection_size=0;
+	}
+	return;
+}
+
+/*
+ * expand the size of less internal selection buffer
+ */
+	static int
+expand_selection_buffer(size)
+	int size;	/* new size will be: max_selection_size + size */
+{
+	char *new_selection;
+
+	if (!selection)
+	{
+		/* buffer for selection isn't allocated */
+		selection = (char*)malloc((size + 1) * sizeof(char));
+		if (!selection)
+		{
+			error("WARNING: Not enough memory for selection", NULL_PARG);
+			clear_selection();
+			return 0;
+		}
+	max_selection_size = size;
+	selection_size = 0;
+	*selection = '\0';
+	return 1;
+	}
+
+	if (size > 0)
+	{
+		new_selection = (char*)malloc((max_selection_size + size + 1) * sizeof(char));
+		if (!new_selection)
+		{
+			error("WARNING: Not enough memory for selection", NULL_PARG);
+			clear_selection();
+			return 0;
+		}
+		memcpy(new_selection, selection, max_selection_size + 1);
+		free(selection);
+		selection = new_selection;
+		max_selection_size += size;
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * add a char into less internal selection
+ */
+	static int
+add_char_to_selection(c)
+	int c;
+{
+	if (selection_size >= max_selection_size)
+		if (!(expand_selection_buffer(SELECTION_SIZE_STEP)))
+			return 0;
+
+	/* finally add new char */
+	selection[selection_size++] = c;
+	selection[selection_size] = '\0';
+	return 1;
+}
+
+/*
+ * add more chars into less internal selection
+ */
+	static int
+add_buf_to_selection(buf, size)
+	char *buf;
+	int size;
+{
+	if ((selection_size + size) > max_selection_size)
+		if (!(expand_selection_buffer(size)))
+			return 0;
+
+	/* finally add buf to selection */
+	memcpy(selection + selection_size, buf, size);
+	selection_size += size;
+	selection[selection_size] = '\0';
+	return 1;
+}
+
+
+/*
+ * create less internal selection
+ * x1, y1, x2, y2 - are coordinates of begin and end of selection
+ */
+	public int
+create_selection(x1, y1, x2, y2)
+	int x1;
+	int y1;
+	int x2;
+	int y2;
+{
+	int x, y;
+	int c, csp, ap;
+	POSITION pos;
+
+	if ((x1 == x2) && (y1 == y2))
+		/* no new selection */
+		return 1;
+
+	if (((y1 == y2) && (x1 > x2)) || (y1 > y2))
+	{
+		/* we want to have x1,y1 as begin of selection */
+		x  = x1; y  = y1;
+		x1 = x2; y1 = y2;
+		x2 = x;  y2 = y;
+	}
+
+	clear_selection();
+	for (y = y1; y <= y2; y++)
+	{
+		pos = position(y);
+		forw_line(pos);
+		for (x = (y == y1) ? x1 : 0;
+		     (((c = gline(x, &csp, &ap)) != '\0') && !((y == y2) && (x >= x2)));
+		     x++)
+		{
+			if (!add_char_to_selection(c))
+				/* something wrong */
+				return 0;
+			if ((utf_mode) && (IS_CONT(c)) && (y == y2))
+				/* it is multichar */
+				++x2;
+		}
+	}
+	return 2;
+}
+
+/*
+ * write less internal selection to xselection
+ * it use the xselection utility because less isn't linked against Xlib
+ */
+	public int
+write_xselection()
+{
+	FILE *xsel;
+
+	if ((xsel = popen("xselection PRIMARY -", "w")) == NULL)
+		/* can't open xselection */
+		return 0;
+
+	if (selection)
+		if (fwrite(selection, 1, selection_size, xsel) != selection_size)
+		{
+			error("WARNING: Can not write the whole selection to the xselection", NULL_PARG);
+			pclose(xsel);
+			return 0;
+		}
+
+	if (pclose(xsel) != 0)
+		/* xselection didn't work correctly */
+		return 0;
+
+	/* everything OK */
+	return 1;
+}
+
+
+/*
+ * read xselection to less internal selection
+ * it use the xselection utility because less isn't linked against Xlib
+ */
+	public int
+read_xselection()
+{
+	FILE *xsel;
+	char buf[SELECTION_SIZE_STEP];
+	int read;
+
+	if ((xsel = popen("xselection PRIMARY", "r")) == NULL)
+		/* can't open xselection */
+		return 0;
+
+	clear_selection();
+	while ((read = fread(buf, 1, SELECTION_SIZE_STEP, xsel)) != 0)
+	{
+		if (!add_buf_to_selection(buf, read))
+		{
+			/* something wrong */
+			pclose(xsel);
+			return 0;
+		}
+	}
+
+	if (pclose(xsel) != 0)
+	{
+		/* xselection didn't work correctly */
+		clear_selection();
+		return 0;
+	}
+
+	/* everything OK */
+	return 1;
+}
+
+/*
+ * test if xselection utility is available
+ */
+	public int
+is_xselection_available()
+{
+	FILE *xsel;
+	char buf[SELECTION_SIZE_STEP];
+	int read;
+
+	if ((xsel = popen("xselection -help 2>/dev/null", "r")) == NULL)
+		/* can't open xselection */
+		return 0;
+
+	while ((read = fread(buf, 1, SELECTION_SIZE_STEP, xsel)) != 0);
+
+	if (pclose(xsel) != 0)
+		/* xselection doesn't work correctly */
+		return 0;
+
+	/* everything OK */
+	return 1;
+}
openSUSE Build Service is sponsored by