summaryrefslogtreecommitdiffstats
path: root/mark.c
diff options
context:
space:
mode:
Diffstat (limited to 'mark.c')
-rw-r--r--mark.c1449
1 files changed, 1449 insertions, 0 deletions
diff --git a/mark.c b/mark.c
new file mode 100644
index 0000000..1e40fcb
--- /dev/null
+++ b/mark.c
@@ -0,0 +1,1449 @@
+/* Copyright (c) 2008, 2009
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Micah Cowan (micah@cowan.name)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, see
+ * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "screen.h"
+#include "mark.h"
+#include "extern.h"
+
+#ifdef COPY_PASTE
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * WARNING: these routines use the global variables "fore" and
+ * "flayer" to make things easier.
+ *
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+static int is_letter __P((char));
+static void nextword __P((int *, int *, int, int));
+static int linestart __P((int));
+static int lineend __P((int));
+static int rem __P((int, int, int, int, int, char *, int));
+static int eq __P((int, int));
+static int MarkScrollDownDisplay __P((int));
+static int MarkScrollUpDisplay __P((int));
+
+static void MarkProcess __P((char **, int *));
+static void MarkAbort __P((void));
+static void MarkRedisplayLine __P((int, int, int, int));
+static int MarkRewrite __P((int, int, int, struct mchar *, int));
+
+extern struct layer *flayer;
+extern struct display *display, *displays;
+extern struct win *fore;
+extern struct mline mline_blank, mline_null;
+extern struct mchar mchar_so;
+
+#ifdef FONT
+int pastefont = 1;
+#endif
+
+struct LayFuncs MarkLf = {
+ MarkProcess,
+ MarkAbort,
+ MarkRedisplayLine,
+ DefClearLine,
+ MarkRewrite,
+ DefResize,
+ DefRestore,
+ 0
+};
+
+int join_with_cr = 0;
+int compacthist = 0;
+
+unsigned char mark_key_tab[256]; /* this array must be initialised first! */
+
+static struct markdata *markdata;
+
+/*
+ * VI like is_letter: 0 - whitespace
+ * 1 - letter
+ * 2 - other
+ */
+static int
+is_letter(char c)
+{
+ if ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '.' ||
+ c == '@' || c == ':' ||
+ c == '%' || c == '!' ||
+ c == '-' || c == '+')
+ /* thus we can catch email-addresses as a word :-) */
+ return 1;
+ else if (c != ' ')
+ return 2;
+ return 0;
+}
+
+static int
+linestart(int y)
+{
+ register int x;
+ register unsigned char *i;
+
+ for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
+ if (*i++ != ' ')
+ break;
+ if (x == fore->w_width - 1)
+ x = markdata->left_mar;
+ return x;
+}
+
+static int
+lineend(int y)
+{
+ register int x;
+ register unsigned char *i;
+
+ for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
+ if (*i-- != ' ')
+ break;
+ if (x < 0)
+ x = markdata->left_mar;
+ return x;
+}
+
+/*
+ * nextchar sets *xp to the num-th occurrence of the target in the line.
+ *
+ * Returns -1 if the target doesn't appear num times, 0 otherwise.
+ */
+static int
+nextchar(int *xp, int *yp, int direction, char target, int num)
+{
+ int width; /* width of the current window. */
+ int x; /* x coordinate of the current cursor position. */
+ int step; /* amount to increment x (+1 or -1) */
+ int adjust; /* Final adjustment of cursor position. */
+ char *displayed_line; /* Line in which search takes place. */
+
+ debug("nextchar\n");
+
+ x = *xp;
+ step = 1;
+ adjust = 0;
+ width = fore->w_width;
+ displayed_line = (char *)WIN(*yp)->image;
+
+ switch (direction) {
+ case 't':
+ adjust = -1; /* fall through */
+ case 'f':
+ step = 1;
+ break;
+ case 'T':
+ adjust = 1; /* fall through */
+ case 'F':
+ step = -1;
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ x += step;
+
+ debug1("ml->image = %s\n", displayed_line);
+ debug2("num = %d, width = %d\n", num, width);
+ debug2("x = %d target = %c\n", x, target);
+
+ for (; x >= 0 && x <= width; x += step) {
+ if (displayed_line[x] == target) {
+ if (--num == 0) {
+ *xp = x + adjust;
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * nextword calculates the cursor position of the num'th word.
+ * If the cursor is on a word, it counts as the first.
+ * NW_BACK: search backward
+ * NW_ENDOFWORD: find the end of the word
+ * NW_MUSTMOVE: move at least one char
+ * NW_BIG: match WORDs not words
+ */
+
+#define NW_BACK (1<<0)
+#define NW_ENDOFWORD (1<<1)
+#define NW_MUSTMOVE (1<<2)
+#define NW_BIG (1<<3)
+
+static void
+nextword(int *xp, int *yp, int flags, int num)
+{
+ int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
+ register int sx, oq, q, x, y;
+ struct mline *ml;
+
+ x = *xp;
+ y = *yp;
+ sx = (flags & NW_BACK) ? -1 : 1;
+ if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
+ x += sx;
+ ml = WIN(y);
+ for (oq = -1;; x += sx, oq = q) {
+ if (x >= xx || x < 0)
+ q = 0;
+ else if (flags & NW_BIG)
+ q = ml->image[x] == ' ';
+ else
+ q = is_letter(ml->image[x]);
+
+ if (oq >= 0 && oq != q) {
+ if (oq == 0 || !(flags & NW_ENDOFWORD))
+ *xp = x;
+ else
+ *xp = x - sx;
+ *yp = y;
+
+ if ((!(flags & NW_ENDOFWORD) && q) || ((flags & NW_ENDOFWORD) && oq)) {
+ if (--num <= 0)
+ return;
+ }
+ }
+
+ if (x == xx) {
+ x = -1;
+ if (++y >= yy)
+ return;
+ ml = WIN(y);
+ } else if (x < 0) {
+ x = xx;
+ if (--y < 0)
+ return;
+ ml = WIN(y);
+ }
+ }
+}
+
+/*
+ * y1, y2 are WIN coordinates
+ *
+ * redisplay: 0 - just copy
+ * 1 - redisplay + copy
+ * 2 - count + copy, don't redisplay
+ */
+
+static int
+rem(int x1, int y1, int x2, int y2, int redisplay, char *pt, int yend)
+{
+ int i, j, from, to, ry, c;
+ int l = 0;
+ unsigned char *im;
+ struct mline *ml;
+#ifdef FONT
+ int cf, cfx, font;
+ unsigned char *fo, *fox;
+#endif
+
+ markdata->second = 0;
+ if (y2 < y1 || ((y2 == y1) && (x2 < x1))) {
+ i = y2;
+ y2 = y1;
+ y1 = i;
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ ry = y1 - markdata->hist_offset;
+
+ i = y1;
+ if (redisplay != 2 && pt == 0 && ry < 0) {
+ i -= ry;
+ ry = 0;
+ }
+ for (; i <= y2; i++, ry++) {
+ if (redisplay != 2 && pt == 0 && ry > yend)
+ break;
+ ml = WIN(i);
+ from = (i == y1) ? x1 : 0;
+
+ if (from < markdata->left_mar)
+ from = markdata->left_mar;
+ for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
+ if (*im-- != ' ')
+ break;
+ if (i == y2 && x2 < to)
+ to = x2;
+ if (to > markdata->right_mar)
+ to = markdata->right_mar;
+ if (redisplay == 1 && from <= to && ry >= 0 && ry <= yend)
+ MarkRedisplayLine(ry, from, to, 0);
+ if (redisplay != 2 && pt == 0) /* don't count/copy */
+ continue;
+ j = from;
+#ifdef DW_CHARS
+ if (dw_right(ml, j, fore->w_encoding))
+ j--;
+#endif
+ im = ml->image + j;
+#ifdef FONT
+ fo = ml->font + j;
+ fox = ml->fontx + j;
+ font = ASCII;
+#endif
+ for (; j <= to; j++) {
+ c = (unsigned char)*im++;
+#ifdef FONT
+ cf = (unsigned char)*fo++;
+ cfx = (unsigned char)*fox++;
+# ifdef UTF8
+ if (fore->w_encoding == UTF8) {
+ c |= cf << 8 | cfx << 16;
+ if (c == UCS_HIDDEN)
+ continue;
+ c = ToUtf8_comb(pt, c);
+ l += c;
+ if (pt)
+ pt += c;
+ continue;
+ }
+# endif
+# ifdef DW_CHARS
+ if (is_dw_font(cf)) {
+ c = c << 8 | (unsigned char)*im++;
+ fo++;
+ j++;
+ }
+# endif
+ if (pastefont) {
+ c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
+ l += c;
+ if (pt)
+ pt += c;
+ continue;
+ }
+#endif /* FONT */
+ if (pt)
+ *pt++ = c;
+ l++;
+ }
+#ifdef FONT
+ if (pastefont && font != ASCII) {
+ if (pt) {
+ strcpy(pt, "\033(B");
+ pt += 3;
+ }
+ l += 3;
+ }
+#endif
+ if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' ')) {
+ /*
+ * this code defines, what glues lines together
+ */
+ switch (markdata->nonl) {
+ case 0: /* lines separated by newlines */
+ if (pt)
+ *pt++ = '\r';
+ l++;
+ if (join_with_cr) {
+ if (pt)
+ *pt++ = '\n';
+ l++;
+ }
+ break;
+ case 1: /* nothing to separate lines */
+ break;
+ case 2: /* lines separated by blanks */
+ if (pt)
+ *pt++ = ' ';
+ l++;
+ break;
+ case 3: /* seperate by comma, for csh junkies */
+ if (pt)
+ *pt++ = ',';
+ l++;
+ break;
+ }
+ }
+ }
+ return l;
+}
+
+/* Check if two chars are identical. All digits are treated
+ * as same. Used for GetHistory()
+ */
+
+static int
+eq(int a, int b)
+{
+ if (a == b)
+ return 1;
+ if (a == 0 || b == 0)
+ return 1;
+ if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
+ return 1;
+ return 0;
+}
+
+/**********************************************************************/
+
+int
+GetHistory() /* return value 1 if copybuffer changed */
+{
+ int i = 0, q = 0, xx, yy, x, y;
+ unsigned char *linep;
+ struct mline *ml;
+
+ ASSERT(display && fore);
+ x = fore->w_x;
+ if (x >= fore->w_width)
+ x = fore->w_width - 1;
+ y = fore->w_y + fore->w_histheight;
+ debug2("cursor is at x=%d, y=%d\n", x, y);
+ ml = WIN(y);
+ for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
+ if ((q = *linep--) != ' ')
+ break;
+ debug3("%c at (%d,%d)\n", q, xx, y);
+ for (yy = y - 1; yy >= 0; yy--) {
+ ml = WIN(yy);
+ linep = ml->image;
+ if (xx < 0 || eq(linep[xx], q)) { /* line is matching... */
+ for (i = fore->w_width - 1, linep += i; i >= x; i--)
+ if (*linep-- != ' ')
+ break;
+ if (i >= x)
+ break;
+ }
+ }
+ if (yy < 0)
+ return 0;
+ if (D_user->u_plop.buf)
+ UserFreeCopyBuffer(D_user);
+ if ((D_user->u_plop.buf = (char *)malloc((unsigned)(i - x + 2))) ==
+ NULL) {
+ LMsg(0, "Not enough memory... Sorry.");
+ return 0;
+ }
+ bcopy((char *)linep - i + x + 1, D_user->u_plop.buf, i - x + 1);
+ D_user->u_plop.len = i - x + 1;
+#ifdef ENCODINGS
+ D_user->u_plop.enc = fore->w_encoding;
+#endif
+ return 1;
+}
+
+/**********************************************************************/
+
+
+void
+MarkRoutine()
+{
+ int x, y;
+
+ ASSERT(fore && display && D_user);
+
+ debug2("MarkRoutine called: fore nr %d, display %s\n", fore->w_number, D_usertty);
+
+ if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
+ return;
+ flayer->l_encoding = fore->w_encoding;
+ flayer->l_mode = 1;
+ markdata = (struct markdata *)flayer->l_data;
+ markdata->md_user = D_user; /* XXX: Correct? */
+ markdata->md_window = fore;
+ markdata->second = 0;
+ markdata->rep_cnt = 0;
+ markdata->append_mode = 0;
+ markdata->write_buffer = 0;
+ markdata->nonl = 0;
+ markdata->left_mar = 0;
+ markdata->right_mar = fore->w_width - 1;
+ markdata->hist_offset = fore->w_histheight;
+ x = fore->w_x;
+ y = D2W(fore->w_y);
+ if (x >= fore->w_width)
+ x = fore->w_width - 1;
+
+ LGotoPos(flayer, x, W2D(y));
+ LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)", x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
+ markdata->cx = markdata->x1 = x;
+ markdata->cy = markdata->y1 = y;
+ flayer->l_x = x;
+ flayer->l_y = W2D(y);
+}
+
+static void
+MarkProcess(char **inbufp, int *inlenp)
+{
+ char *inbuf, *pt;
+ int inlen;
+ int cx, cy, x2, y2, j, yend;
+ int newcopylen = 0, od;
+ int in_mark;
+ int rep_cnt;
+ struct acluser *md_user;
+
+/*
+ char *extrap = 0, extrabuf[100];
+*/
+
+ markdata = (struct markdata *)flayer->l_data;
+ fore = markdata->md_window;
+ md_user = markdata->md_user;
+ if (inbufp == 0) {
+ MarkAbort();
+ return;
+ }
+
+ LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
+ inbuf = *inbufp;
+ inlen = *inlenp;
+ pt = inbuf;
+ in_mark = 1;
+ while (in_mark && (inlen /* || extrap */)) {
+ unsigned char ch = (unsigned char)*pt++;
+ inlen--;
+ if (flayer->l_mouseevent.start) {
+ int r = LayProcessMouse(flayer, ch);
+ if (r == -1)
+ LayProcessMouseSwitch(flayer, 0);
+ else {
+ if (r)
+ ch = 0222;
+ else
+ continue;
+ }
+ }
+ od = mark_key_tab[(int)ch];
+ rep_cnt = markdata->rep_cnt;
+ if (od >= '0' && od <= '9' && !markdata->f_cmd.flag) {
+ if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0)) {
+ markdata->rep_cnt = 10 * rep_cnt + od - '0';
+ continue;
+ /*
+ * Now what is that 1001 here? Well, we have a screen with
+ * 25 * 80 = 2000 characters. Movement is at most across the full
+ * screen. This we do with word by word movement, as character by
+ * character movement never steps over line boundaries. The most words
+ * we can place on the screen are 1000 single letter words. Thus 1001
+ * is sufficient. Users with bigger screens never write in single letter
+ * words, as they should be more advanced. jw.
+ * Oh, wrong. We still give even the experienced user a factor of ten.
+ */
+ }
+ }
+ cx = markdata->cx;
+ cy = markdata->cy;
+
+ if (markdata->f_cmd.flag) {
+ debug2("searching for %c:%d\n", od, rep_cnt);
+ markdata->f_cmd.flag = 0;
+ markdata->rep_cnt = 0;
+
+ if (isgraph(od)) {
+ markdata->f_cmd.target = od;
+ rep_cnt = (rep_cnt) ? rep_cnt : 1;
+ nextchar(&cx, &cy, markdata->f_cmd.direction, od, rep_cnt);
+ revto(cx, cy);
+ continue;
+ }
+ }
+
+processchar:
+ switch (od) {
+ case 'f': /* fall through */
+ case 'F': /* fall through */
+ case 't': /* fall through */
+ case 'T': /* fall through */
+ /*
+ * Set f_cmd to do a search on the next key stroke.
+ * If we break, rep_cnt will be reset, so we
+ * continue instead. It might be cleaner to
+ * store the rep_count in f_cmd and
+ * break here so later followon code will be
+ * hit.
+ */
+ markdata->f_cmd.flag = 1;
+ markdata->f_cmd.direction = od;
+ debug("entering char search\n");
+ continue;
+ case ';':
+ case ',':
+ if (!markdata->f_cmd.target)
+ break;
+ if (!rep_cnt)
+ rep_cnt = 1;
+ nextchar(&cx,
+ &cy,
+ od == ';' ? markdata->f_cmd.direction : (markdata->f_cmd.direction ^ 0x20),
+ markdata->f_cmd.target,
+ rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'o':
+ case 'x':
+ if (!markdata->second)
+ break;
+ markdata->cx = markdata->x1;
+ markdata->cy = markdata->y1;
+ markdata->x1 = cx;
+ markdata->y1 = cy;
+ revto(markdata->cx, markdata->cy);
+ break;
+ case '\014': /* CTRL-L Redisplay */
+ Redisplay(0);
+ LGotoPos(flayer, cx, W2D(cy));
+ break;
+ case 0202: /* M-C-b */
+ case '\010': /* CTRL-H Backspace */
+ case 'h':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx - rep_cnt, cy);
+ break;
+ case 0216: /* M-C-p */
+ case '\016': /* CTRL-N */
+ case 'j':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx, cy + rep_cnt);
+ break;
+ case '+':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ j = cy + rep_cnt;
+ if (j > fore->w_histheight + fore->w_height - 1)
+ j = fore->w_histheight + fore->w_height - 1;
+ revto(linestart(j), j);
+ break;
+ case '-':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ cy -= rep_cnt;
+ if (cy < 0)
+ cy = 0;
+ revto(linestart(cy), cy);
+ break;
+ case '^':
+ revto(linestart(cy), cy);
+ break;
+ case '\n':
+ revto(markdata->left_mar, cy + 1);
+ break;
+ case 0220: /* M-C-p */
+ case '\020': /* CTRL-P */
+ case 'k':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx, cy - rep_cnt);
+ break;
+ case 0206: /* M-C-f */
+ case 'l':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx + rep_cnt, cy);
+ break;
+ case '\001': /* CTRL-A from tcsh/emacs */
+ case '0':
+ revto(markdata->left_mar, cy);
+ break;
+ case '\004': /* CTRL-D down half screen */
+ if (rep_cnt == 0)
+ rep_cnt = (fore->w_height + 1) >> 1;
+ revto_line(cx, cy + rep_cnt, W2D(cy));
+ break;
+ case '$':
+ revto(lineend(cy), cy);
+ break;
+ case '\022': /* CTRL-R emacs style backwards search */
+ ISearch(-1);
+ in_mark = 0;
+ break;
+ case '\023': /* CTRL-S emacs style search */
+ ISearch(1);
+ in_mark = 0;
+ break;
+ case '\025': /* CTRL-U up half screen */
+ if (rep_cnt == 0)
+ rep_cnt = (fore->w_height + 1) >> 1;
+ revto_line(cx, cy - rep_cnt, W2D(cy));
+ break;
+ case '\007': /* CTRL-G show cursorpos */
+ if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
+ LMsg(0, "Column %d Line %d(+%d)", cx + 1, W2D(cy) + 1, markdata->hist_offset);
+ else
+ LMsg(0, "Column %d(%d..%d) Line %d(+%d)",
+ cx + 1, markdata->left_mar + 1,
+ markdata->right_mar + 1, W2D(cy) + 1,
+ markdata->hist_offset);
+ break;
+ case '\002': /* CTRL-B back one page */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt *= fore->w_height;
+ revto(cx, cy - rep_cnt);
+ break;
+ case '\006': /* CTRL-F forward one page */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt *= fore->w_height;
+ revto(cx, cy + rep_cnt);
+ break;
+ case '\005': /* CTRL-E scroll up */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt = MarkScrollUpDisplay(rep_cnt);
+ if (cy < D2W(0))
+ revto(cx, D2W(0));
+ else
+ LGotoPos(flayer, cx, W2D(cy));
+ break;
+ case '\031': /* CTRL-Y scroll down */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt = MarkScrollDownDisplay(rep_cnt);
+ if (cy > D2W(fore->w_height - 1))
+ revto(cx, D2W(fore->w_height - 1));
+ else
+ LGotoPos(flayer, cx, W2D(cy));
+ break;
+ case '@':
+ /* it may be useful to have a key that does nothing */
+ break;
+ case '%':
+ /* rep_cnt is a percentage for the history buffer */
+ if (rep_cnt < 0)
+ rep_cnt = 0;
+ if (rep_cnt > 100)
+ rep_cnt = 100;
+
+ revto_line(markdata->left_mar,
+ fore->w_histheight - fore->w_scrollback_height +
+ (int)(rep_cnt * (fore->w_scrollback_height +
+ fore->w_height) / 100.0), (fore->w_height - 1) / 2);
+ break;
+ case 0201:
+ case 'g':
+ rep_cnt = 1;
+ /* FALLTHROUGH */
+ case 0205:
+ case 'G':
+ /* rep_cnt is here the WIN line number */
+ if (rep_cnt == 0)
+ rep_cnt = fore->w_histheight + fore->w_height;
+ revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
+ break;
+ case 'H':
+ revto(markdata->left_mar, D2W(0));
+ break;
+ case 'M':
+ revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
+ break;
+ case 'L':
+ revto(markdata->left_mar, D2W(fore->w_height - 1));
+ break;
+ case '|':
+ revto(--rep_cnt, cy);
+ break;
+ case 'w':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'e':
+ case 'E':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'b':
+ case 'B':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
+ revto(cx, cy);
+ break;
+ case 'a':
+ markdata->append_mode = 1 - markdata->append_mode;
+ debug1("append mode %d--\n", markdata->append_mode);
+ LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
+ break;
+ case 'v':
+ case 'V':
+ /* this sets start column to column 9 for VI :set nu users */
+ if (markdata->left_mar == 8)
+ rep_cnt = 1;
+ else
+ rep_cnt = 9;
+ /* FALLTHROUGH */
+ case 'c':
+ case 'C':
+ /* set start column (c) and end column (C) */
+ if (markdata->second) {
+ rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, fore->w_height - 1); /* Hack */
+ markdata->second = 1; /* rem turns off second */
+ }
+ rep_cnt--;
+ if (rep_cnt < 0)
+ rep_cnt = cx;
+ if (od != 'C') {
+ markdata->left_mar = rep_cnt;
+ if (markdata->left_mar > markdata->right_mar)
+ markdata->left_mar = markdata->right_mar;
+ } else {
+ markdata->right_mar = rep_cnt;
+ if (markdata->left_mar > markdata->right_mar)
+ markdata->right_mar = markdata->left_mar;
+ }
+ if (markdata->second) {
+ markdata->cx = markdata->x1;
+ markdata->cy = markdata->y1;
+ revto(cx, cy);
+ }
+ if (od == 'v' || od == 'V')
+ LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
+ break;
+ case 'J':
+ /* how do you join lines in VI ? */
+ markdata->nonl = (markdata->nonl + 1) % 4;
+ switch (markdata->nonl) {
+ case 0:
+ if (join_with_cr)
+ LMsg(0, "Multiple lines (CR/LF)");
+ else
+ LMsg(0, "Multiple lines (LF)");
+ break;
+ case 1:
+ LMsg(0, "Lines joined");
+ break;
+ case 2:
+ LMsg(0, "Lines joined with blanks");
+ break;
+ case 3:
+ LMsg(0, "Lines joined with comma");
+ break;
+ }
+ break;
+ case '/':
+ Search(1);
+ in_mark = 0;
+ break;
+ case '?':
+ Search(-1);
+ in_mark = 0;
+ break;
+ case 'n':
+ Search(0);
+ break;
+ case 'N':
+ markdata->isdir = -markdata->isdir;
+ Search(0);
+ markdata->isdir = -markdata->isdir;
+ break;
+ case 'y':
+ case 'Y':
+ if (markdata->second == 0) {
+ revto(linestart(cy), cy);
+ markdata->second++;
+ cx = markdata->x1 = markdata->cx;
+ cy = markdata->y1 = markdata->cy;
+ }
+ if (--rep_cnt > 0)
+ revto(cx, cy + rep_cnt);
+ revto(lineend(markdata->cy), markdata->cy);
+ if (od == 'y')
+ break;
+ /* FALLTHROUGH */
+ case 'W':
+ if (od == 'W') {
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ if (!markdata->second) {
+ nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
+ revto(cx, cy);
+ markdata->second++;
+ cx = markdata->x1 = markdata->cx;
+ cy = markdata->y1 = markdata->cy;
+ }
+ nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
+ revto(cx, cy);
+ }
+ cx = markdata->cx;
+ cy = markdata->cy;
+ /* FALLTHROUGH */
+ case 'A':
+ if (od == 'A')
+ markdata->append_mode = 1;
+ /* FALLTHROUGH */
+ case '>':
+ if (od == '>')
+ markdata->write_buffer = 1;
+ /* FALLTHROUGH */
+ case ' ':
+ case '\r':
+ if (!markdata->second) {
+ markdata->second++;
+ markdata->x1 = cx;
+ markdata->y1 = cy;
+ revto(cx, cy);
+ LMsg(0, "First mark set - Column %d Line %d", cx + 1, W2D(cy) + 1);
+ break;
+ } else {
+ int append_mode = markdata->append_mode;
+ int write_buffer = markdata->write_buffer;
+
+ x2 = cx;
+ y2 = cy;
+ newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
+ if (md_user->u_plop.buf && !append_mode)
+ UserFreeCopyBuffer(md_user);
+ yend = fore->w_height - 1;
+ if (fore->w_histheight - markdata->hist_offset < fore->w_height) {
+ markdata->second = 0;
+ yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
+ }
+ if (newcopylen > 0) {
+ /* the +3 below is for : cr + lf + \0 */
+ if (md_user->u_plop.buf)
+ md_user->u_plop.buf = realloc(md_user->u_plop.buf, (unsigned)(md_user->u_plop.len + newcopylen + 3));
+ else {
+ md_user->u_plop.len = 0;
+ md_user->u_plop.buf = malloc((unsigned)(newcopylen + 3));
+ }
+ if (!md_user->u_plop.buf) {
+ MarkAbort();
+ in_mark = 0;
+ LMsg(0, "Not enough memory... Sorry.");
+ md_user->u_plop.len = 0;
+ md_user->u_plop.buf = 0;
+ break;
+ }
+ if (append_mode) {
+ switch (markdata->nonl) {
+ /*
+ * this code defines, what glues lines together
+ */
+ case 0:
+ if (join_with_cr) {
+ md_user->u_plop.buf[md_user->u_plop.len] = '\r';
+ md_user->u_plop.len++;
+ }
+ md_user->u_plop.buf[md_user->u_plop.len] = '\n';
+ md_user->u_plop.len++;
+ break;
+ case 1:
+ break;
+ case 2:
+ md_user->u_plop.buf[md_user->u_plop.len] = ' ';
+ md_user->u_plop.len++;
+ break;
+ case 3:
+ md_user->u_plop.buf[md_user->u_plop.len] = ',';
+ md_user->u_plop.len++;
+ break;
+ }
+ }
+ md_user->u_plop.len += rem(markdata->x1,
+ markdata->y1,
+ x2,
+ y2,
+ markdata->hist_offset == fore->w_histheight,
+ md_user->u_plop.buf + md_user->u_plop.len,
+ yend);
+#ifdef ENCODINGS
+ md_user->u_plop.enc = fore->w_encoding;
+#endif
+ }
+ if (markdata->hist_offset != fore->w_histheight) {
+ LAY_CALL_UP(LRefreshAll(flayer, 0));
+ }
+ ExitOverlayPage();
+ WindowChanged(fore, 'P');
+
+ if (append_mode)
+ LMsg(0, "Appended %d characters to buffer", newcopylen);
+ else
+ LMsg(0, "Copied %d characters into buffer", md_user->u_plop.len);
+
+ if (write_buffer)
+ WriteFile(md_user, (char *)0, DUMP_EXCHANGE);
+ in_mark = 0;
+ break;
+ }
+
+ case 0222:
+ if (flayer->l_mouseevent.start) {
+ int button = flayer->l_mouseevent.buffer[0];
+ if (button == 'a') {
+ /* Scroll down */
+ od = 'j';
+ } else if (button == '`') {
+ /* Scroll up */
+ od = 'k';
+ } else if (button == ' ') {
+ /* Left click */
+ cx = flayer->l_mouseevent.buffer[1];
+ cy = D2W(flayer->l_mouseevent.buffer[2]);
+ revto(cx, cy);
+ od = ' ';
+ } else
+ od = 0;
+ LayProcessMouseSwitch(flayer, 0);
+ if (od)
+ goto processchar;
+ } else
+ LayProcessMouseSwitch(flayer, 1);
+ break;
+
+ default:
+ MarkAbort();
+ LMsg(0, "Copy mode aborted");
+ in_mark = 0;
+ break;
+ }
+ if (in_mark) /* markdata may be freed */
+ markdata->rep_cnt = 0;
+ }
+ if (in_mark) {
+ flayer->l_x = markdata->cx;
+ flayer->l_y = W2D(markdata->cy);
+ }
+ *inbufp = pt;
+ *inlenp = inlen;
+}
+
+void
+revto(int tx, int ty)
+{
+ revto_line(tx, ty, -1);
+}
+
+/* tx, ty: WINDOW, line: DISPLAY */
+void
+revto_line(int tx, int ty, int line)
+{
+ int fx, fy;
+ int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
+ int ystart = 0, yend = fore->w_height - 1;
+ int i, ry;
+ unsigned char *wi;
+ struct mline *ml;
+ struct mchar mc;
+
+ if (tx < 0)
+ tx = 0;
+ else if (tx > fore->w_width - 1)
+ tx = fore->w_width - 1;
+ if (ty < fore->w_histheight - fore->w_scrollback_height)
+ ty = fore->w_histheight - fore->w_scrollback_height;
+ else if (ty > fore->w_histheight + fore->w_height - 1)
+ ty = fore->w_histheight + fore->w_height - 1;
+
+ fx = markdata->cx;
+ fy = markdata->cy;
+
+#ifdef DW_CHARS
+ /* don't just move inside of a kanji, the user wants to see something */
+ ml = WIN(ty);
+ if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
+ tx++;
+ if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
+ tx--;
+#endif
+
+ markdata->cx = tx;
+ markdata->cy = ty;
+
+ /*
+ * if we go to a position that is currently offscreen
+ * then scroll the screen
+ */
+ i = 0;
+
+ if (line >= 0 && line < fore->w_height)
+ i = W2D(ty) - line;
+ else if (ty < markdata->hist_offset)
+ i = ty - markdata->hist_offset;
+ else if (ty > markdata->hist_offset + (fore->w_height - 1))
+ i = ty - markdata->hist_offset - (fore->w_height - 1);
+
+ if (i > 0)
+ yend -= MarkScrollUpDisplay(i);
+ else if (i < 0)
+ ystart += MarkScrollDownDisplay(-i);
+
+ if (markdata->second == 0) {
+ flayer->l_x = tx;
+ flayer->l_y = W2D(ty);
+ LGotoPos(flayer, tx, W2D(ty));
+ return;
+ }
+
+ qq = markdata->x1 + markdata->y1 * fore->w_width;
+ ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
+ tt = tx + ty * fore->w_width; /* "to" offset in WIN coords*/
+
+ if (ff > tt) {
+ st = tt;
+ en = ff;
+ x = tx;
+ y = ty;
+ } else {
+ st = ff;
+ en = tt;
+ x = fx;
+ y = fy;
+ }
+
+ if (st > qq) {
+ st++;
+ x++;
+ }
+
+ if (en < qq)
+ en--;
+
+ if (tt > qq) {
+ revst = qq;
+ reven = tt;
+ } else {
+ revst = tt;
+ reven = qq;
+ }
+ ry = y - markdata->hist_offset;
+
+ if (ry < ystart) {
+ y += (ystart - ry);
+ x = 0;
+ st = y * fore->w_width;
+ ry = ystart;
+ }
+ ml = WIN(y);
+
+ for (t = st; t <= en; t++, x++) {
+ if (x >= fore->w_width) {
+ x = 0;
+ y++, ry++;
+ ml = WIN(y);
+ }
+ if (ry > yend)
+ break;
+ if (t == st || x == 0) {
+ wi = ml->image + fore->w_width;
+ for (ce = fore->w_width; ce >= 0; ce--, wi--)
+ if (*wi != ' ')
+ break;
+ }
+
+ if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar) {
+#ifdef DW_CHARS
+ if (dw_right(ml, x, fore->w_encoding)) {
+ if (t == revst)
+ revst--;
+ t--;
+ x--;
+ }
+#endif
+ if (t >= revst && t <= reven) {
+ mc = mchar_so;
+#ifdef FONT
+ if (pastefont) {
+ mc.font = ml->font[x];
+ mc.fontx = ml->fontx[x];
+ }
+#endif
+ mc.image = ml->image[x];
+ } else
+ copy_mline2mchar(&mc, ml, x);
+#ifdef DW_CHARS
+ if (dw_left(ml, x, fore->w_encoding)) {
+ mc.mbcs = ml->image[x + 1];
+ LPutChar(flayer, &mc, x, W2D(y));
+ t++;
+ }
+#endif
+ LPutChar(flayer, &mc, x, W2D(y));
+#ifdef DW_CHARS
+ if (dw_left(ml, x, fore->w_encoding))
+ x++;
+#endif
+ }
+ }
+ flayer->l_x = tx;
+ flayer->l_y = W2D(ty);
+ LGotoPos(flayer, tx, W2D(ty));
+}
+
+static void
+MarkAbort()
+{
+ int yend, redisp;
+
+ debug("MarkAbort\n");
+ markdata = (struct markdata *)flayer->l_data;
+ fore = markdata->md_window;
+ yend = fore->w_height - 1;
+ redisp = markdata->second;
+ if (fore->w_histheight - markdata->hist_offset < fore->w_height) {
+ markdata->second = 0;
+ yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
+ }
+ if (markdata->hist_offset != fore->w_histheight) {
+ LAY_CALL_UP(LRefreshAll(flayer, 0));
+ } else {
+ rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
+ }
+ ExitOverlayPage();
+ WindowChanged(fore, 'P');
+}
+
+static void
+MarkRedisplayLine(int y, int xs, int xe, int isblank) /* NOTE: y is in DISPLAY coords system! */
+{
+ int wy, x, i, rm;
+ int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
+ unsigned char *wi;
+ struct mline *ml;
+ struct mchar mchar_marked;
+
+ if (y < 0) /* No special full page handling */
+ return;
+
+ markdata = (struct markdata *)flayer->l_data;
+ fore = markdata->md_window;
+
+ mchar_marked = mchar_so;
+
+ wy = D2W(y);
+ ml = WIN(wy);
+
+ if (markdata->second == 0) {
+ if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
+ xs--;
+ if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
+ xe++;
+ if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
+ LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
+ else
+ LCDisplayLine(flayer, ml, y, xs, xe, isblank);
+ return;
+ }
+
+ sta = markdata->y1 * fore->w_width + markdata->x1;
+ sto = markdata->cy * fore->w_width + markdata->cx;
+ if (sta > sto) {
+ i = sta;
+ sta = sto;
+ sto = i;
+ }
+ cp = wy * fore->w_width + xs;
+
+ rm = markdata->right_mar;
+ for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
+ if (*wi != ' ')
+ break;
+ if (x < rm)
+ rm = x;
+
+ for (x = xs; x <= xe; x++, cp++)
+ if (cp >= sta && x >= markdata->left_mar)
+ break;
+#ifdef DW_CHARS
+ if (dw_right(ml, x, fore->w_encoding))
+ x--;
+#endif
+ if (x > xs)
+ LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
+ for (; x <= xe; x++, cp++) {
+ if (cp > sto || x > rm)
+ break;
+#ifdef FONT
+ if (pastefont) {
+ mchar_marked.font = ml->font[x];
+ mchar_marked.fontx = ml->fontx[x];
+ }
+#endif
+ mchar_marked.image = ml->image[x];
+#ifdef DW_CHARS
+ mchar_marked.mbcs = 0;
+ if (dw_left(ml, x, fore->w_encoding)) {
+ mchar_marked.mbcs = ml->image[x + 1];
+ cp++;
+ }
+#endif
+ LPutChar(flayer, &mchar_marked, x, y);
+#ifdef DW_CHARS
+ if (dw_left(ml, x, fore->w_encoding))
+ x++;
+#endif
+ }
+ if (x <= xe)
+ LCDisplayLine(flayer, ml, y, x, xe, isblank);
+}
+
+/*
+ * This ugly routine is to speed up GotoPos()
+ */
+static int
+MarkRewrite(int ry, int xs, int xe, struct mchar *rend, int doit)
+{
+ int dx, x, y, st, en, t, rm;
+ unsigned char *i;
+ struct mline *ml;
+ struct mchar mchar_marked;
+
+ mchar_marked = mchar_so;
+
+ debug3("MarkRewrite %d, %d-%d\n", ry, xs, xe);
+ markdata = (struct markdata *)flayer->l_data;
+ fore = markdata->md_window;
+ y = D2W(ry);
+ ml = WIN(y);
+#ifdef UTF8
+ if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(ml, xs, xe, fore->w_encoding))
+ return EXPENSIVE;
+#endif
+ dx = xe - xs + 1;
+ if (doit) {
+ i = ml->image + xs;
+ while (dx--)
+ PUTCHAR(*i++);
+ return 0;
+ }
+
+ if (markdata->second == 0)
+ st = en = -1;
+ else {
+ st = markdata->y1 * fore->w_width + markdata->x1;
+ en = markdata->cy * fore->w_width + markdata->cx;
+ if (st > en) {
+ t = st;
+ st = en;
+ en = t;
+ }
+ }
+ t = y * fore->w_width + xs;
+ for (rm = fore->w_width, i = ml->image + fore->w_width; rm >= 0; rm--)
+ if (*i-- != ' ')
+ break;
+ if (rm > markdata->right_mar)
+ rm = markdata->right_mar;
+ x = xs;
+ while (dx--) {
+ if (t >= st && t <= en && x >= markdata->left_mar && x <= rm) {
+#ifdef FONT
+ if (pastefont) {
+ mchar_marked.font = ml->font[x];
+ mchar_marked.fontx = ml->fontx[x];
+ }
+#endif
+ rend->image = mchar_marked.image;
+ if (!cmp_mchar(rend, &mchar_marked))
+ return EXPENSIVE;
+ } else {
+ rend->image = ml->image[x];
+ if (!cmp_mchar_mline(rend, ml, x))
+ return EXPENSIVE;
+ }
+ x++;
+ }
+ return xe - xs + 1;
+}
+
+/*
+ * scroll the screen contents up/down.
+ */
+static int
+MarkScrollUpDisplay(int n)
+{
+ int i;
+
+ debug1("MarkScrollUpDisplay(%d)\n", n);
+ if (n <= 0)
+ return 0;
+ if (n > fore->w_histheight - markdata->hist_offset)
+ n = fore->w_histheight - markdata->hist_offset;
+
+ markdata->hist_offset += n;
+ i = (n < flayer->l_height) ? n : (flayer->l_height);
+ LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
+ while (i-- > 0)
+ MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
+ return n;
+}
+
+static int
+MarkScrollDownDisplay(int n)
+{
+ int i;
+
+ debug1("MarkScrollDownDisplay(%d)\n", n);
+ if (n <= 0)
+ return 0;
+ if (n > markdata->hist_offset)
+ n = markdata->hist_offset;
+ markdata->hist_offset -= n;
+ i = (n < flayer->l_height) ? n : (flayer->l_height);
+ LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
+ while (i-- > 0)
+ MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
+ return n;
+}
+
+void
+MakePaster(struct paster *pa, char *buf, int len, int bufiscopy)
+{
+ FreePaster(pa);
+ pa->pa_pasteptr = buf;
+ pa->pa_pastelen = len;
+ if (bufiscopy)
+ pa->pa_pastebuf = buf;
+ pa->pa_pastelayer = flayer;
+ DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
+}
+
+void
+FreePaster(struct paster *pa)
+{
+ if (pa->pa_pastebuf)
+ free(pa->pa_pastebuf);
+ pa->pa_pastebuf = 0;
+ pa->pa_pasteptr = 0;
+ pa->pa_pastelen = 0;
+ pa->pa_pastelayer = 0;
+ evdeq(&pa->pa_slowev);
+}
+
+#endif /* COPY_PASTE */
+