+/* Copyright (c) 1991
+ * 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 1, 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, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ * Wayne Davison (davison@borland.com)
+ * Patrick Wolfe (pat@kai.com, kailand!pat)
+ * Bart Schaefer (schaefer@cse.ogi.edu)
+ * Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ * Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ * Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ * Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ * Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ */
+
+#ifndef lint
+ static char rcs_id[] = "$Id: mark.c,v 1.2 1992/05/18 03:49:28 rich Exp $ FAU";
+#endif
+
+#include <sys/types.h>
+
+#ifdef BSDI
+# include <sys/signal.h>
+#endif /* BSDI */
+
+#include "config.h"
+#include "screen.h"
+#include "ansi.h" /* here we find A_SO, ASCII, EXPENSIVE */
+#include "extern.h"
+
+static int is_letter __P((int));
+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 void revto __P((int, int));
+static void revto_line __P((int, int, int));
+static void MarkRedisplayLine __P((int, int, int, int));
+static int MarkRewrite __P((int, int, int, int));
+static void process_mark_input __P((char **, int *));
+static void AbortMarkRoutine __P((void));
+static int MarkScrollDownDisplay __P((int));
+static int MarkScrollUpDisplay __P((int));
+
+int join_with_cr = 0;
+extern struct win *fore, *wtab[];
+extern int screenwidth, screenheight;
+extern int screentop, screenbot;
+extern char GlobalAttr, GlobalCharset;
+extern int in_ovl;
+extern int HS;
+extern int LP;
+extern char *null, *blank;
+
+#ifdef NETHACK
+extern nethackflag;
+#endif
+
+char *copybuffer = NULL;
+int copylen = 0;
+char mark_key_tab[256]; /* this array must be initialised first! */
+
+static int in_mark; /* mark routine active */
+static int left_mar, right_mar, nonl;
+static int x1, y1, second; /* y1 is in terms of WIN coordinates, not DISPLAY */
+static int cx, cy; /* Cursor Position in WIN coords*/
+static rep_cnt; /* no. of repeats are rep_cnt+1. jw. */
+static int append_mode; /* shall we overwrite or append to copybuffer */
+static write_buffer; /* shall we do a KEY_WRITE_EXCHANGE right away? */
+static hist_offset;
+
+static int is_letter(c)
+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;
+}
+
+/*
+ * iWIN gives us a reference to line y of the *whole* image
+ * where line 0 is the oldest line in our history.
+ * y must be in WIN coordinate system, not in display.
+ */
+#define iWIN(y) ((y < fore->histheight) ? fore->ihist[(fore->histidx + y)\
+ % fore->histheight] : fore->image[y - fore->histheight])
+#define aWIN(y) ((y < fore->histheight) ? fore->ahist[(fore->histidx + y)\
+ % fore->histheight] : fore->attr[y - fore->histheight])
+#define fWIN(y) ((y < fore->histheight) ? fore->fhist[(fore->histidx + y)\
+ % fore->histheight] : fore->font[y - fore->histheight])
+/*
+ * hist_offset tells us, how many lines there are on top of the
+ * visible screen.
+ */
+
+#define W2D(y) ((y)-hist_offset)
+#define D2W(y) ((y)+hist_offset)
+
+static int
+linestart(y)
+int y;
+{
+ register int x;
+ register char *i;
+
+ for (x = left_mar, i = iWIN(y) + x; x < screenwidth-1; x++)
+ if (*i++ != ' ')
+ break;
+ if (x == screenwidth-1)
+ x = left_mar;
+ return(x);
+}
+
+static int
+lineend(y)
+int y;
+{
+ register int x;
+ register char *i;
+
+ for (x = right_mar, i = iWIN(y) + x; x >= 0; x--)
+ if (*i-- != ' ')
+ break;
+ if (x < 0)
+ x = left_mar;
+ return(x);
+}
+
+
+/*
+ * 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 even if the position is correct.
+ */
+
+#define NW_BACK 1
+#define NW_ENDOFWORD 2
+#define NW_MUSTMOVE 4
+
+static void
+nextword(xp, yp, flags, num)
+int *xp, *yp, flags, num;
+{
+ int xx = screenwidth, yy = fore->histheight + screenheight;
+ register int sx, oq, q, x, y;
+
+ x = *xp;
+ y = *yp;
+ sx = (flags & NW_BACK) ? -1 : 1;
+ if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
+ x += sx;
+ for (oq = -1; ; x += sx, oq = q)
+ {
+ if (x >= xx || x < 0)
+ q = 0;
+ else
+ q = is_letter(iWIN(y)[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;
+ }
+ else if (x < 0)
+ {
+ x = xx;
+ if (--y < 0)
+ return;
+ }
+ }
+}
+
+
+/*
+ * y1, y2 are WIN coordinates
+ *
+ * redisplay: 0 - just copy
+ * 1 - redisplay + copy
+ * 2 - count + copy, don't redisplay
+ */
+
+static int rem(x1, y1, x2, y2, redisplay, pt, yend)
+int x1, y1, x2, y2, redisplay, yend;
+char *pt;
+{
+ int i, j, from, to, ry;
+ int l = 0;
+ char *im;
+
+ second = 0;
+ if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
+ {
+ i = y2;
+ y2 = y1;
+ y1 = i;
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ ry = y1 - 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;
+ from = (i == y1) ? x1 : 0;
+ if (from < left_mar)
+ from = left_mar;
+ for (to = screenwidth-1, im = iWIN(i)+to; to>=0; to--)
+ if (*im-- != ' ')
+ break;
+ if (i == y2 && x2 < to)
+ to = x2;
+ if (to > right_mar)
+ to = 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;
+ for (j = from, im = iWIN(i)+from; j <= to; j++)
+ {
+ if (pt)
+ *pt++ = *im++;
+ l++;
+ }
+ if (i != y2)
+ {
+ /*
+ * this code defines, what glues lines together
+ */
+ switch (nonl)
+ {
+ case 0: /* lines separated by newlines */
+ if (join_with_cr)
+ {
+ if (pt)
+ *pt++ = '\r';
+ l++;
+ }
+ if (pt)
+ *pt++ = '\n';
+ l++;
+ break;
+ case 1: /* nothing to separate lines */
+ break;
+ case 2: /* lines separated by blanks */
+ if (pt)
+ *pt++ = ' ';
+ l++;
+ break;
+ }
+ }
+ }
+ return(l);
+}
+
+static int eq(a, b)
+int a, 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;
+}
+
+static int crazychar = 0;
+static int crazy_y = -1;
+static int crazy_x = -1;
+
+int MarkRoutine(flag) /* return value 1 when copybuffer changed; */
+int flag;
+{
+ int x, y, i;
+
+ hist_offset = fore->histheight;
+
+ if (!fore->active)
+ {
+ Msg(0, "Fore window is not active !!!");
+ return 0;
+ }
+
+ second = 0;
+ rep_cnt = 0;
+ append_mode = 0;
+ write_buffer = 0;
+ nonl = left_mar = 0;
+ right_mar = screenwidth-1;
+ x = fore->x;
+ y = D2W(fore->y);
+ if (x >= screenwidth)
+ x = screenwidth-1;
+
+ if (flag == CRAZY && crazychar != 0 && crazy_x != -1 && crazy_y != -1)
+ {
+ Msg(0, "CRAZY mode not impl.\n");
+ }
+ crazychar = 0;
+ crazy_y = -1;
+ crazy_x = -1;
+ if (flag == TRICKY)
+ {
+ int f, q = 0, xx, yy;
+ char *linep;
+
+ debug2("cursor is at x=%d, y=%d\n", fore->x, D2W(fore->y));
+ for (xx = fore->x - 1, linep = iWIN(y) + xx; xx >= 0; xx--)
+ if ((q = *linep--) != ' ' )
+ break;
+ debug3("%c at (%d,%d)\n", q, xx, y);
+ for (yy = D2W(fore->y) - 1; yy >= 0; yy--)
+ if (xx < 0 || eq(iWIN(yy)[xx], q))
+ { /* line is matching... */
+ f = 0;
+ for (i = fore->x; i < screenwidth-1; i++)
+ {
+ if (iWIN(yy)[i] != ' ')
+ {
+ f = 1;
+ break;
+ }
+ }
+ if (f)
+ break;
+ }
+ if (yy < 0)
+ return 0;
+ xx = 0;
+ for (i = screenwidth-1, linep = iWIN(yy)+i; i>0; i--)
+ if (*linep-- != ' ')
+ break;
+ if (i < x)
+ i = x;
+ if (copybuffer != NULL)
+ Free(copybuffer);
+ if ((copybuffer = malloc((unsigned) (i - x + 2))) == NULL)
+ {
+ Msg(0, "Not enough memoooh!... Sorry.");
+ return 0;
+ }
+ rem(x, yy, i, yy, 0, copybuffer, 0);
+ copylen = i - x + 1;
+ return 1;
+ }
+ InitOverlayPage(process_mark_input, MarkRedisplayLine, MarkRewrite, 1);
+ GotoPos(x, W2D(y));
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "Welcome to hacker's treasure zoo - Column %d Line %d(+%d) (%d,%d)",
+ x+1, W2D(y+1), fore->histheight, fore->width, fore->height);
+ else
+#endif
+ Msg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
+ x+1, W2D(y+1), fore->histheight, fore->width, fore->height);
+ fflush(stdout);
+ cx = x1 = x;
+ cy = y1 = y;
+ in_mark = 1;
+ return 0;
+}
+
+static void process_mark_input(inbufp,inlenp)
+char **inbufp;
+int *inlenp;
+{
+ char *inbuf, *pt;
+ int inlen;
+ int x2, y2, i, j, yend;
+ int newcopylen = 0, od;
+/*
+ char *extrap = 0, extrabuf[100];
+*/
+
+ if (inbufp == 0)
+ {
+ AbortMarkRoutine();
+ return;
+ }
+
+ inbuf= *inbufp;
+ inlen= *inlenp;
+ pt = inbuf;
+ while (in_mark && (inlen /* || extrap */))
+ {
+ if (!HS)
+ RemoveStatus();
+/*
+ if (extrap)
+ {
+ od = *extrap++;
+ if (*extrap == 0)
+ extrap = 0;
+ }
+ else
+*/
+ {
+ od = mark_key_tab[*pt++];
+ inlen--;
+ }
+ if (od >= '0' && od <= '9')
+ {
+ if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
+ {
+ 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.
+ */
+ }
+ }
+ switch (od)
+ {
+ case '\014': /* CTRL-L Redisplay */
+ Redisplay(0);
+ GotoPos(cx, W2D(cy));
+ break;
+ case '\010': /* CTRL-H Backspace */
+ case 'h':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx - rep_cnt, cy);
+ break;
+ 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->histheight + screenheight - 1)
+ j = fore->histheight + screenheight - 1;
+ revto(linestart(j), j);
+ break;
+ case '-':
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ j = cy - rep_cnt;
+ if (j < 0)
+ j = 0;
+ revto(linestart(j), j);
+ break;
+ case '^':
+ revto(linestart(cy), cy);
+ break;
+ case '\n':
+ revto(left_mar, cy + 1);
+ break;
+ case 'k':
+ case '\020': /* CTRL-P */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ revto(cx, cy - rep_cnt);
+ break;
+ 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(left_mar, cy);
+ break;
+ case '\004': /* CTRL-D down half screen */
+ if (rep_cnt == 0)
+ rep_cnt = (screenheight+1) >> 1;
+ revto_line(cx, cy + rep_cnt, W2D(cy));
+ break;
+ case '$':
+ revto(lineend(cy), cy);
+ break;
+ case '\025': /* CTRL-U up half screen */
+ if (rep_cnt == 0)
+ rep_cnt = (screenheight+1) >> 1;
+ revto_line(cx, cy - rep_cnt, W2D(cy));
+ break;
+ case '?':
+ if (left_mar == 0 && right_mar == screenwidth - 1)
+ Msg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
+ hist_offset);
+ else
+ Msg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
+ left_mar+1, right_mar+1, W2D(cy)+1, hist_offset);
+ break;
+ case '\002': /* CTRL-B back one page */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt *= (screenheight-1);
+ revto(cx, cy - rep_cnt);
+ break;
+ case '\006': /* CTRL-F forward one page */
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ rep_cnt *= (screenheight-1);
+ 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
+ GotoPos(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(screenheight-1))
+ revto(cx, D2W(screenheight-1));
+ else
+ GotoPos(cx, W2D(cy));
+ break;
+ case '@':
+ /* it may be usefull to have a key that does nothing */
+ break;
+ case '%':
+ rep_cnt--;
+ /* 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(left_mar, (rep_cnt * (fore->histheight + screenheight)) / 100, (screenheight-1)/2);
+ break;
+ case 'g':
+ rep_cnt = 1;
+ /* FALLTHROUGH */
+ case 'G':
+ /* rep_cnt is here the WIN line number */
+ if (rep_cnt == 0)
+ rep_cnt = fore->histheight + screenheight;
+ revto_line(left_mar, --rep_cnt, (screenheight-1)/2);
+ break;
+ case 'H':
+ revto(left_mar, D2W(0));
+ break;
+ case 'M':
+ revto(left_mar, D2W((screenheight-1) / 2));
+ break;
+ case 'L':
+ revto(left_mar, D2W(screenheight-1));
+ break;
+ case '|':
+ revto(--rep_cnt, cy);
+ break;
+ case 'w':
+ i = cx;
+ j = cy;
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&i, &j, NW_MUSTMOVE, rep_cnt);
+ revto(i, j);
+ break;
+ case 'e':
+ i = cx;
+ j = cy;
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&i, &j, NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
+ revto(i, j);
+ break;
+ case 'b':
+ i = cx;
+ j = cy;
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ nextword(&i, &j, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
+ revto(i, j);
+ break;
+ case 'a':
+ append_mode = 1 - append_mode;
+ debug1("append mode %d--\n", append_mode);
+ Msg(0, (append_mode) ? ":set append" : ":set noappend");
+ break;
+ case 'v':
+ case 'V':
+ /* this sets start column to column 9 for VI :set nu users */
+ if (left_mar == 8)
+ rep_cnt = 1;
+ else
+ rep_cnt = 9;
+ /* FALLTHROUGH */
+ case 'c':
+ case 'C':
+ /* set start column (c) and end column (C) */
+ if (second)
+ {
+ rem(x1, y1, cx, cy, 1, (char *)0, screenheight-1); /* Hack */
+ second = 1; /* rem turns off second */
+ }
+ rep_cnt--;
+ if (rep_cnt < 0)
+ rep_cnt = cx;
+ if (od != 'C')
+ {
+ left_mar = rep_cnt;
+ if (left_mar > right_mar)
+ left_mar = right_mar;
+ }
+ else
+ {
+ right_mar = rep_cnt;
+ if (left_mar > right_mar)
+ right_mar = left_mar;
+ }
+ if (second)
+ {
+ int x = cx, y = cy;
+ cx = x1; cy = y1;
+ revto(x, y);
+ }
+ if (od == 'v' || od == 'V')
+ Msg(0, (left_mar != 8) ? ":set nonu" : ":set nu");
+ break;
+ case 'J':
+ /* how do you join lines in VI ? */
+ nonl = (nonl + 1) % 3;
+ switch (nonl)
+ {
+ case 0:
+ if (join_with_cr)
+ Msg(0, "Multiple lines (CR/LF)");
+ else
+ Msg(0, "Multiple lines (LF)");
+ break;
+ case 1:
+ Msg(0, "Lines joined");
+ break;
+ case 2:
+ Msg(0, "Lines joined with blanks");
+ break;
+ }
+ break;
+ case 'y':
+ case 'Y':
+ if (!second)
+ {
+ revto(linestart(cy), cy);
+ second++;
+ x1 = cx;
+ y1 = cy;
+ }
+ if (--rep_cnt > 0)
+ revto(cx, cy + rep_cnt);
+ revto(lineend(cy), cy);
+ if (od == 'y')
+ break;
+ /* FALLTHROUGH */
+ case 'W':
+ if (od == 'W')
+ {
+ if (rep_cnt == 0)
+ rep_cnt = 1;
+ if (!second)
+ {
+ i = cx;
+ j = cy;
+ nextword(&i, &j, NW_BACK|NW_ENDOFWORD, 1);
+ revto(i, j);
+ second++;
+ x1 = cx;
+ y1 = cy;
+ }
+ i = cx;
+ j = cy;
+ nextword(&i, &j, NW_ENDOFWORD, rep_cnt);
+ revto(i, j);
+ }
+ /* FALLTHROUGH */
+ case 'A':
+ if (od == 'A')
+ append_mode = 1;
+ /* FALLTHROUGH */
+ case '>':
+ if (od == '>')
+ write_buffer = 1;
+ /* FALLTHROUGH */
+ case ' ':
+ case '\r':
+ if (!second)
+ {
+ second++;
+ x1 = cx;
+ y1 = cy;
+ revto(x1, y1);
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You drop a magic marker - Column %d Line %d",
+ cx+1, W2D(cy)+1, hist_offset);
+ else
+#endif
+ Msg(0, "First mark set - Column %d Line %d", cx+1, cy+1);
+ break;
+ }
+ else
+ {
+ x2 = cx;
+ y2 = cy;
+ newcopylen = rem(x1, y1, x2, y2, 2, (char *)0, 0); /* count */
+ if (copybuffer != NULL && !append_mode)
+ {
+ copylen = 0;
+ Free(copybuffer);
+ }
+ if (newcopylen > 0)
+ {
+ /* the +3 below is for : cr + lf + \0 */
+ if (copybuffer != NULL)
+ copybuffer = realloc(copybuffer,
+ (unsigned) (copylen + newcopylen + 3));
+ else
+ {
+ copylen = 0;
+ copybuffer = malloc((unsigned) (newcopylen + 3));
+ }
+ if (copybuffer == NULL)
+ {
+ AbortMarkRoutine();
+ Msg(0, "Not enough memoooh!... Sorry.");
+ copylen = 0;
+ copybuffer = NULL;
+ break;
+ }
+ if (append_mode)
+ {
+ switch (nonl)
+ /*
+ * this code defines, what glues lines together
+ */
+ {
+ case 0:
+ if (join_with_cr)
+ {
+ copybuffer[copylen] = '\r';
+ copylen++;
+ }
+ copybuffer[copylen] = '\n';
+ copylen++;
+ break;
+ case 1:
+ break;
+ case 2:
+ copybuffer[copylen] = ' ';
+ copylen++;
+ break;
+ }
+ }
+ yend = screenheight - 1;
+ if (fore->histheight - hist_offset < screenheight)
+ {
+ second = 0;
+ yend -= MarkScrollUpDisplay(fore->histheight - hist_offset);
+ }
+ copylen += rem(x1, y1, x2, y2, hist_offset == fore->histheight, copybuffer + copylen, yend);
+ }
+ if (hist_offset != fore->histheight)
+ {
+ in_ovl = 0; /* So we can use Activate() */
+ Activate(0);
+ }
+ ExitOverlayPage();
+ if (append_mode)
+ Msg(0, "Appended %d characters to buffer",
+ newcopylen);
+ else
+ Msg(0, "Copied %d characters into buffer", copylen);
+ if (write_buffer)
+ WriteFile(DUMP_EXCHANGE);
+ in_mark = 0;
+ break;
+ }
+ default:
+ AbortMarkRoutine();
+#ifdef NETHACK
+ if (nethackflag)
+ Msg(0, "You escaped the dungeon.");
+ else
+#endif
+ Msg(0, "Copy mode aborted");
+ break;
+ }
+ rep_cnt = 0;
+ }
+ fflush(stdout);
+ *inbufp = pt;
+ *inlenp = inlen;
+}
+
+static void revto(tx, ty)
+int tx, ty;
+{
+ revto_line(tx, ty, -1);
+}
+
+/* tx, ty: WINDOW, line: DISPLAY */
+static void revto_line(tx, ty, line)
+int tx, ty, line;
+{
+ int fx, fy;
+ int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
+ int ystart = 0, yend = screenheight-1;
+ int i, ry;
+
+ if (tx < 0)
+ tx = 0;
+ else if (tx > screenwidth - 1)
+ tx = screenwidth -1;
+ if (ty < 0)
+ ty = 0;
+ else if (ty > fore->histheight + screenheight - 1)
+ ty = fore->histheight + screenheight - 1;
+
+ fx = cx; fy = cy;
+ cx = tx; cy = ty;
+/*debug2("revto(%d, %d, ", x1, y1);
+ debug2("%d, %d, ", fx, fy);
+ debug2("%d, %d)\n", tx, ty);*/
+
+ /*
+ * if we go to a position that is currently offscreen
+ * then scroll the screen
+ */
+ i = 0;
+ if (line >= 0 && line < screenheight)
+ i = W2D(ty) - line;
+ else if (ty < hist_offset)
+ i = ty - hist_offset;
+ else if (ty > hist_offset + (screenheight-1))
+ i = ty-hist_offset-(screenheight-1);
+ if (i > 0)
+ yend -= MarkScrollUpDisplay(i);
+ else if (i < 0)
+ ystart += MarkScrollDownDisplay(-i);
+
+ if (second == 0)
+ {
+ GotoPos(tx, W2D(cy));
+ return;
+ }
+
+ qq = x1 + y1 * screenwidth;
+ ff = fx + fy * screenwidth; /* "from" offset in WIN coords */
+ tt = tx + ty * screenwidth; /* "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 - hist_offset;
+ if (ry < ystart)
+ {
+ y += (ystart - ry);
+ x = 0;
+ st = y * screenwidth;
+ ry = ystart;
+ }
+ for (t = st; t <= en; t++, x++)
+ {
+ if (x >= screenwidth)
+ {
+ x = 0;
+ y++, ry++;
+ }
+ if (ry > yend)
+ break;
+ if (t == st || x == 0)
+ {
+ for (ce = screenwidth-1; ce >= 0; ce--)
+ if (iWIN(y)[ce] != ' ')
+ break;
+ }
+ if (x <= ce && x >= left_mar && x <= right_mar
+ && (LP || x < screenwidth-1 || ry < screenbot))
+ {
+ GotoPos(x, W2D(y));
+ if (t >= revst && t <= reven)
+ SaveSetAttr(A_SO, ASCII);
+ else
+ SaveSetAttr(aWIN(y)[x], fWIN(y)[x]);
+ PUTCHAR(iWIN(y)[x]);
+ }
+ }
+ GotoPos(tx, W2D(cy));
+}
+
+static void AbortMarkRoutine()
+{
+ int yend, redisp;
+
+ yend = screenheight - 1;
+ redisp = second;
+ if (fore->histheight - hist_offset < screenheight)
+ {
+ second = 0;
+ yend -= MarkScrollUpDisplay(fore->histheight - hist_offset);
+ }
+ if (hist_offset != fore->histheight)
+ {
+ in_ovl = 0; /* So we can use Activate() */
+ Activate(0); /* to do a complete redisplay */
+ }
+ else
+ {
+ rem(x1, y1, cx, cy, redisp, (char *)0, yend);
+ }
+ ExitOverlayPage();
+ in_mark = 0;
+}
+
+
+static void MarkRedisplayLine(y, xs, xe, isblank)
+int y; /* NOTE: y is in DISPLAY coords system! */
+int xs, xe;
+int isblank;
+{
+ int x, i, rm;
+ int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
+ char *wi, *wa, *wf, *oldi;
+
+ InsertMode(0); /* Not done in DisplayLine() */
+
+ wi = iWIN(D2W(y));
+ wa = aWIN(D2W(y));
+ wf = fWIN(D2W(y));
+ oldi = isblank ? blank : null;
+
+ if (second == 0)
+ {
+ DisplayLine(oldi, null, null, wi, wa, wf, y, xs, xe);
+ return;
+ }
+
+ sta = y1 * screenwidth + x1;
+ sto = cy * screenwidth + cx;
+ if (sta > sto)
+ {
+ i=sta; sta=sto; sto=i;
+ }
+ cp = D2W(y) * screenwidth + xs;
+
+ rm = right_mar;
+ for (x = screenwidth - 1; x >= 0; x--)
+ if (wi[x] != ' ')
+ break;
+ if (x < rm)
+ rm = x;
+
+ for (x = xs; x <= xe; x++, cp++)
+ if (cp >= sta && x >= left_mar)
+ break;
+ if (x > xs)
+ DisplayLine(oldi, null, null, wi, wa, wf, y, xs, x-1);
+ for (; x <= xe; x++, cp++)
+ {
+ if (cp > sto || x > rm || (!LP && x >= screenwidth-1 && y == screenbot))
+ break;
+ GotoPos(x, y);
+ SaveSetAttr(A_SO, ASCII);
+ PUTCHAR(wi[x]);
+ }
+ if (x<=xe)
+ DisplayLine(oldi, null, null, wi, wa, wf, y, x, xe);
+}
+
+
+static int
+MarkRewrite(ry, xs, xe, doit)
+int ry, xs, xe, doit;
+{
+ int dx, x, y, st, en, t, rm;
+ char *a, *f, *i;
+
+ y = D2W(ry);
+ dx = xe - xs;
+ if (doit)
+ {
+ i = iWIN(y) + xs;
+ while (dx--)
+ PUTCHAR(*i++);
+ return(0);
+ }
+
+ a = aWIN(y) + xs,
+ f = fWIN(y) + xs;
+ if (second == 0)
+ st = en = -1;
+ else
+ {
+ st = y1 * screenwidth + x1;
+ en = cy * screenwidth + cx;
+ if (st > en)
+ {
+ t = st; st = en; en = t;
+ }
+ }
+ t = y * screenwidth + xs;
+ for (rm=screenwidth-1, i=iWIN(y) + screenwidth-1; rm>=0; rm--)
+ if (*i-- != ' ')
+ break;
+ if (rm > right_mar)
+ rm = right_mar;
+ x = xs;
+ while (dx--)
+ {
+ if (t >= st && t <= en && x >= left_mar && x <= rm)
+ {
+ if (GlobalAttr != A_SO || GlobalCharset != ASCII)
+ return(EXPENSIVE);
+ }
+ else
+ {
+ if (GlobalAttr != *a || GlobalCharset != *f)
+ return(EXPENSIVE);
+ }
+ a++, f++, t++, x++;
+ }
+ return(xe - xs);
+}
+
+
+/*
+ * scroll the screen contents up/down.
+ */
+static int MarkScrollUpDisplay(n)
+int n;
+{
+ int i;
+
+ debug1("MarkScrollUpDisplay(%d)\n", n);
+ if (n <= 0)
+ return 0;
+ if (n > fore->histheight - hist_offset)
+ n = fore->histheight - hist_offset;
+ i = (n < screenheight) ? n : (screenheight);
+ ScrollRegion(0, screenheight - 1, i);
+ hist_offset += n;
+ while (i-- > 0)
+ MarkRedisplayLine(screenheight-i-1, 0, screenwidth-1, 1);
+ return n;
+}
+
+static int MarkScrollDownDisplay(n)
+int n;
+{
+ int i;
+
+ debug1("MarkScrollDownDisplay(%d)\n", n);
+ if (n <= 0)
+ return 0;
+ if (n > hist_offset)
+ n = hist_offset;
+ i = (n < screenheight) ? n : (screenheight);
+ ScrollRegion(0, screenheight - 1, -i);
+ hist_offset -= n;
+ while (i-- > 0)
+ MarkRedisplayLine(i, 0, screenwidth-1, 1);
+ return n;
+}
+