home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / screen3 / part04 / mark.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  24.5 KB  |  1,131 lines

  1. /* Copyright (c) 1991
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * Noteworthy contributors to screen's design and implementation:
  21.  *    Wayne Davison (davison@borland.com)
  22.  *    Patrick Wolfe (pat@kai.com, kailand!pat)
  23.  *    Bart Schaefer (schaefer@cse.ogi.edu)
  24.  *    Nathan Glasser (nathan@brokaw.lcs.mit.edu)
  25.  *    Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
  26.  *    Howard Chu (hyc@hanauma.jpl.nasa.gov)
  27.  *    Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  28.  *    Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
  29.  *    Marc Boucher (marc@CAM.ORG)
  30.  *
  31.  ****************************************************************
  32.  */
  33.  
  34. #ifndef lint
  35.   static char rcs_id[] = "$Id: mark.c,v 1.38 91/10/11 11:46:04 jnweiger Exp $ FAU";
  36. #endif
  37.  
  38. #include <sys/types.h>
  39. #if defined(BSD) || defined(sequent)
  40. # include <strings.h>
  41. #else
  42. # include <string.h>
  43. #endif
  44.  
  45. #include "config.h"
  46. #include "screen.h"
  47. #include "ansi.h"    /* here we find A_SO, ASCII, EXPENSIVE */
  48. #include "extern.h"
  49.  
  50. static int is_letter __P((int));
  51. static void nextword __P((int *, int *, int, int));
  52. static int linestart __P((int));
  53. static int lineend __P((int));
  54. static int rem __P((int, int , int , int , int , char *, int));
  55. static int eq __P((int, int ));
  56. static void revto __P((int, int));
  57. static void revto_line __P((int, int, int));
  58. static void MarkRedisplayLine __P((int, int, int, int));
  59. static int MarkRewrite __P((int, int, int, int));
  60. static void process_mark_input __P((char **, int *));
  61. static void AbortMarkRoutine __P((void));
  62. static int MarkScrollDownDisplay __P((int));
  63. static int MarkScrollUpDisplay __P((int));
  64.  
  65. int join_with_cr =  0;
  66. extern struct win *fore, *wtab[];
  67. extern int screenwidth, screenheight;
  68. extern int screentop, screenbot;
  69. extern char GlobalAttr, GlobalCharset;
  70. extern int in_ovl;
  71. extern int HS;
  72. extern int LP;
  73. extern char *null, *blank;
  74.  
  75. #ifdef NETHACK
  76. extern nethackflag;
  77. #endif
  78.  
  79. char *copybuffer = NULL;
  80. int copylen = 0;
  81. char mark_key_tab[256]; /* this array must be initialised first! */
  82.  
  83. static int in_mark;    /* mark routine active */
  84. static int left_mar, right_mar, nonl;
  85. static int x1, y1, second; /* y1 is in terms of WIN coordinates, not DISPLAY */
  86. static int cx, cy;    /* Cursor Position in WIN coords*/
  87. static rep_cnt;        /* no. of repeats are rep_cnt+1. jw. */
  88. static int append_mode;    /* shall we overwrite or append to copybuffer */
  89. static write_buffer;    /* shall we do a KEY_WRITE_EXCHANGE right away? */
  90. static hist_offset;
  91.  
  92. static int is_letter(c)
  93. char c;
  94. {
  95.   if (c >= 'a' && c <= 'z' ||
  96.       c >= 'A' && c <= 'Z' ||
  97.       c >= '0' && c <= '9' ||
  98.       c == '_' || c == '.' ||
  99.       c == '@' || c == ':' ||
  100.       c == '%' || c == '!' ||
  101.       c == '-' || c == '+')
  102.     /* thus we can catch email-addresses as a word :-) */
  103.     return 1;
  104.   else if (c != ' ')
  105.     return 2;
  106.   return 0;
  107. }
  108.  
  109. /*
  110.  * iWIN gives us a reference to line y of the *whole* image 
  111.  * where line 0 is the oldest line in our history.
  112.  * y must be in WIN coordinate system, not in display.
  113.  */
  114. #define iWIN(y) ((y < fore->histheight) ? fore->ihist[(fore->histidx + y)\
  115.         % fore->histheight] : fore->image[y - fore->histheight])
  116. #define aWIN(y) ((y < fore->histheight) ? fore->ahist[(fore->histidx + y)\
  117.         % fore->histheight] : fore->attr[y - fore->histheight])
  118. #define fWIN(y) ((y < fore->histheight) ? fore->fhist[(fore->histidx + y)\
  119.         % fore->histheight] : fore->font[y - fore->histheight])
  120. /*
  121.  * hist_offset tells us, how many lines there are on top of the
  122.  * visible screen.
  123.  */
  124.  
  125. #define W2D(y) ((y)-hist_offset)
  126. #define D2W(y) ((y)+hist_offset)
  127.  
  128. static int
  129. linestart(y)
  130. int y;
  131. {
  132.   register int x;
  133.   register char *i;
  134.  
  135.   for (x = left_mar, i = iWIN(y) + x; x < screenwidth-1; x++)
  136.     if (*i++ != ' ')
  137.       break;
  138.   if (x == screenwidth-1)
  139.     x = left_mar;
  140.   return(x);
  141. }
  142.  
  143. static int
  144. lineend(y)
  145. int y;
  146. {
  147.   register int x;
  148.   register char *i;
  149.  
  150.   for (x = right_mar, i = iWIN(y) + x; x >= 0; x--)
  151.     if (*i-- != ' ')
  152.       break;
  153.   if (x < 0)
  154.     x = left_mar;
  155.   return(x);
  156. }
  157.  
  158. /*
  159.  * nextword returnes 1 if x,y altered. dir== -1 means backwards search
  160.  * beginning of a word, +1 means forward search beginning of a word, +2
  161.  * means search forward end of word.
  162.  */
  163.  
  164. #define NW_BACK        1
  165. #define NW_ENDOFWORD    2
  166. #define NW_MUSTMOVE    4
  167.  
  168. static void nextword(xp, yp, dir, num)
  169. int *xp, *yp, dir, num;
  170. {
  171.   int xx = screenwidth, yy = fore->histheight + screenheight;
  172.   register int sx, oq, q, x, y;
  173.  
  174.   x = *xp;
  175.   y = *yp;
  176.   sx = (dir & NW_BACK) ? -1 : 1;
  177.   if ((dir & NW_ENDOFWORD) && (dir & NW_MUSTMOVE))
  178.     x += sx;
  179.   for (oq = -1; ; x += sx, oq = q)
  180.     {
  181.       if (x >= xx || x < 0)
  182.     q = 0;
  183.       else
  184.         q = is_letter(iWIN(y)[x]);
  185.       if (oq >= 0 && oq != q)
  186.     {
  187.       if (oq == 0 || !(dir & NW_ENDOFWORD))
  188.         *xp = x;
  189.       else
  190.         *xp = x-sx;
  191.       *yp = y;
  192.       if ((!(dir & NW_ENDOFWORD) && q) ||
  193.           ((dir & NW_ENDOFWORD) && oq))
  194.         {
  195.           if (--num <= 0)
  196.             return;
  197.         }
  198.     }
  199.       if (x == xx)
  200.     {
  201.       x = -1;
  202.       if (++y >= yy)
  203.         return;
  204.     }
  205.       else if (x < 0)
  206.     {
  207.       x = xx;
  208.       if (--y < 0)
  209.         return;
  210.     }
  211.     }
  212. }
  213.  
  214.  
  215. /*
  216.  * y1, y2 are WIN coordinates
  217.  *
  218.  * redisplay:    0  -  just copy
  219.  *         1  -  redisplay + copy
  220.  *        2  -  count + copy, don't redisplay
  221.  */
  222.  
  223. static int rem(x1, y1, x2, y2, redisplay, pt, yend)
  224. int x1, y1, x2, y2, redisplay, yend;
  225. char *pt;
  226. {
  227.   int i, j, from, to, ry;
  228.   int l = 0;
  229.   char *im;
  230.  
  231.   second = 0;
  232.   if (y2 < y1 || y2 == y1 && x2 < x1)
  233.     {
  234.       i = y2;
  235.       y2 = y1;
  236.       y1 = i;
  237.       i = x2;
  238.       x2 = x1;
  239.       x1 = i;
  240.     }
  241.   ry = y1 - hist_offset;
  242.   
  243.   i = y1;
  244.   if (redisplay != 2 && pt == 0 && ry <0)
  245.     {
  246.       i -= ry;
  247.       ry = 0;
  248.     }
  249.   for (; i <= y2; i++, ry++)
  250.     {
  251.       if (redisplay != 2 && pt == 0 && ry > yend)
  252.     break;
  253.       from = (i == y1) ? x1 : 0;
  254.       if (from < left_mar)
  255.     from = left_mar;
  256.       for (to = screenwidth-1, im = iWIN(i)+to; to>=0; to--)
  257.         if (*im-- != ' ')
  258.       break;
  259.       if (i == y2 && x2 < to)
  260.     to = x2;
  261.       if (to > right_mar)
  262.     to = right_mar;
  263.       if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
  264.     MarkRedisplayLine(ry, from, to, 0);
  265.       if (redisplay != 2 && pt == 0)    /* don't count/copy */
  266.     continue;
  267.       for (j = from, im = iWIN(i)+from; j <= to; j++)
  268.     {
  269.       if (pt)
  270.         *pt++ = *im++;
  271.       l++;
  272.     }
  273.       if (i != y2)
  274.     {
  275.       /* 
  276.        * this code defines, what glues lines together
  277.        */
  278.       switch (nonl)
  279.         {
  280.         case 0:        /* lines separated by newlines */
  281.           if (join_with_cr)
  282.         {
  283.           if (pt)
  284.             *pt++ = '\r';
  285.           l++;
  286.         }
  287.           if (pt)
  288.         *pt++ = '\n';
  289.           l++;
  290.           break;
  291.         case 1:        /* nothing to separate lines */
  292.           break;
  293.         case 2:        /* lines separated by blanks */
  294.           if (pt)
  295.         *pt++ = ' ';
  296.           l++;
  297.           break;
  298.         }
  299.     }
  300.     }
  301.   return(l);
  302. }
  303.  
  304. static int eq(a, b)
  305. int a, b;
  306. {
  307.   if (a == b)
  308.     return 1;
  309.   if (a == 0 || b == 0)
  310.     return 1;
  311.   if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
  312.     return 1;
  313.   return 0;
  314. }
  315.  
  316. int MarkRoutine(flag)    /* return value 1 when copybuffer changed; */
  317. int flag;
  318. {
  319.   int x, y, i;
  320.  
  321.   hist_offset = fore->histheight;
  322.  
  323.   if (!fore->active)
  324.     {
  325.       Msg(0, "Fore window is not active !!!");
  326.       return 0;
  327.     }
  328.  
  329.   second = 0;
  330.   rep_cnt = 0;
  331.   append_mode = 0;
  332.   write_buffer = 0;
  333.   nonl = left_mar = 0;
  334.   right_mar = screenwidth-1;
  335.   x = fore->x;
  336.   y = D2W(fore->y);
  337.   if (x >= screenwidth)
  338.     x = screenwidth-1;
  339.  
  340.   if (flag == TRICKY)
  341.     {
  342.       int f, q = 0, xx, yy;
  343.       char *linep;
  344.  
  345.       debug2("cursor is at x=%d, y=%d\n", fore->x, D2W(fore->y));
  346.       for (xx = fore->x - 1, linep = iWIN(y)+xx; xx >= 0; xx--)
  347.     if ((q = *linep--) != ' ' )
  348.       break;
  349.       debug3("%c at (%d,%d)\n", q, xx, y);
  350.       for (yy = D2W(fore->y) - 1; yy >= 0; yy--)
  351.     if (xx < 0 || eq(iWIN(yy)[xx], q))
  352.       {        /* line is matching... */
  353.         f = 0;
  354.         for (i = fore->x; i < screenwidth-1; i++)
  355.           {
  356.         if (iWIN(yy)[i] != ' ')
  357.           {
  358.             f = 1;
  359.             break;
  360.           }
  361.           }
  362.         if (f)
  363.           break;
  364.       }
  365.       if (yy < 0)
  366.     return 0;
  367.       xx = 0;
  368.       for (i = screenwidth-1, linep = iWIN(yy)+i; i>0; i--)
  369.     if (*linep-- != ' ')
  370.       break;
  371.       if (i < x)
  372.     i = x;
  373.       if (copybuffer != NULL)
  374.     Free(copybuffer);
  375.       if ((copybuffer = malloc((unsigned) (i - x + 2))) == NULL)
  376.     {
  377.       Msg(0, "Not enough memoooh!... Sorry.");
  378.       return 0;
  379.     }
  380.       rem(x, yy, i, yy, 0, copybuffer, 0);
  381.       copylen = i - x + 1;
  382.       return 1;
  383.     }
  384.   InitOverlayPage(process_mark_input, MarkRedisplayLine, MarkRewrite, 1);
  385.   GotoPos(x, W2D(y));
  386. #ifdef NETHACK
  387.   if (nethackflag)
  388.     Msg(0, "Welcome to hacker's treasure zoo - Column %d Line %d(+%d) (%d,%d)",
  389.     x+1, W2D(y+1), fore->histheight, fore->width, fore->height);
  390.   else
  391. #endif
  392.   Msg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
  393.       x+1, W2D(y+1), fore->histheight, fore->width, fore->height);
  394.   fflush(stdout);
  395.   cx = x1 = x;
  396.   cy = y1 = y;
  397.   in_mark = 1;
  398.   return 0;
  399. }
  400.  
  401. static void process_mark_input(inbufp,inlenp)
  402. char **inbufp;
  403. int *inlenp;
  404. {
  405.   char *inbuf, *pt;
  406.   int inlen;
  407.   int x2, y2, i, j, yend;
  408.   int newcopylen = 0, od;
  409. /*
  410.   char *extrap = 0, extrabuf[100];
  411. */
  412.       
  413.   if (inbufp == 0)
  414.     {
  415.       AbortMarkRoutine();
  416.       return;
  417.     }
  418.  
  419.   inbuf= *inbufp;
  420.   inlen= *inlenp;
  421.   pt = inbuf;
  422.   while (in_mark && (inlen /* || extrap */))
  423.     {
  424.       if (!HS)
  425.     RemoveStatus();
  426. /*
  427.       if (extrap)
  428.     {
  429.       od = *extrap++;
  430.       if (*extrap == 0)
  431.         extrap = 0;
  432.     }
  433.       else
  434. */
  435.     {
  436.           od = mark_key_tab[*pt++];
  437.           inlen--;
  438.     }
  439.       if (od >= '0' && od <= '9')
  440.         {
  441.       if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
  442.         {
  443.           rep_cnt = 10 * rep_cnt + od - '0';
  444.           continue;
  445.            /*
  446.            * Now what is that 1001 here? Well, we have a screen with
  447.            * 25 * 80 = 2000 characters. Movement is at most across the full
  448.            * screen. This we do with word by word movement, as character by
  449.            * character movement never steps over line boundaries. The most words
  450.            * we can place on the screen are 1000 single letter words. Thus 1001
  451.            * is sufficient. Users with bigger screens never write in single letter
  452.            * words, as they should be more advanced. jw.
  453.            * Oh, wrong. We still give even the experienced user a factor of ten.
  454.            */
  455.         }
  456.     }
  457.       switch (od)
  458.     {
  459.     case '\014':    /* CTRL-L Redisplay */
  460.       Redisplay();
  461.       GotoPos(cx, W2D(cy));
  462.       break;
  463.     case '\010':    /* CTRL-H Backspace */
  464.     case 'h':
  465.       if (rep_cnt == 0)
  466.         rep_cnt = 1;
  467.       revto(cx - rep_cnt, cy);
  468.       break;
  469.     case '\016':    /* CTRL-N */
  470.     case 'j':
  471.       if (rep_cnt == 0)
  472.         rep_cnt = 1;
  473.       revto(cx, cy + rep_cnt);
  474.       break;
  475.     case '+':
  476.       if (rep_cnt == 0)
  477.         rep_cnt = 1;
  478.       j = cy + rep_cnt;
  479.       if (j > fore->histheight + screenheight - 1)
  480.         j = fore->histheight + screenheight - 1;
  481.       revto(linestart(j), j);
  482.       break;
  483.     case '-':
  484.       if (rep_cnt == 0)
  485.         rep_cnt = 1;
  486.       j = cy - rep_cnt;
  487.       if (j < 0)
  488.         j = 0;
  489.       revto(linestart(j), j);
  490.       break;
  491.     case '^':
  492.       revto(linestart(cy), cy);
  493.       break;
  494.     case '\n':
  495.       revto(left_mar, cy + 1);
  496.       break;
  497.     case 'k':
  498.     case '\020':    /* CTRL-P */
  499.       if (rep_cnt == 0)
  500.         rep_cnt = 1;
  501.       revto(cx, cy - rep_cnt);
  502.       break;
  503.     case 'l':
  504.       if (rep_cnt == 0)
  505.         rep_cnt = 1;
  506.       revto(cx + rep_cnt, cy);
  507.       break;
  508.     case '\001':    /* CTRL-A from tcsh/emacs */
  509.     case '0':
  510.       revto(left_mar, cy);
  511.       break;
  512.     case '\004':    /* CTRL-D down half screen */
  513.       if (rep_cnt == 0)
  514.         rep_cnt = (screenheight+1) >> 1;
  515.       revto_line(cx, cy + rep_cnt, W2D(cy));
  516.       break;
  517.     case '$':
  518.       revto(lineend(cy), cy);
  519.       break;
  520.     case '\025':    /* CTRL-U up half screen */
  521.       if (rep_cnt == 0)
  522.         rep_cnt = (screenheight+1) >> 1;
  523.       revto_line(cx, cy - rep_cnt, W2D(cy));
  524.       break;
  525.     case '?':
  526.       if (left_mar == 0 && right_mar == screenwidth - 1)
  527.         Msg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
  528.         hist_offset);
  529.       else
  530.         Msg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
  531.         left_mar+1, right_mar+1, W2D(cy)+1, hist_offset);
  532.       break;
  533.     case '\002':    /* CTRL-B  back one page */
  534.       if (rep_cnt == 0)
  535.         rep_cnt = 1;
  536.       rep_cnt *= (screenheight-1);
  537.       revto(cx, cy - rep_cnt);
  538.       break;
  539.     case '\006':    /* CTRL-F  forward one page */
  540.       if (rep_cnt == 0)
  541.         rep_cnt = 1;
  542.       rep_cnt *= (screenheight-1);
  543.       revto(cx, cy + rep_cnt);
  544.       break;
  545.     case '\005':    /* CTRL-E  scroll up */
  546.       if (rep_cnt == 0)
  547.         rep_cnt = 1;
  548.       rep_cnt = MarkScrollUpDisplay(rep_cnt);
  549.       if (cy < D2W(0))
  550.             revto(cx, D2W(0));
  551.       else
  552.             GotoPos(cx, W2D(cy));
  553.       break;
  554.     case '\031': /* CTRL-Y  scroll down */
  555.       if (rep_cnt == 0)
  556.         rep_cnt = 1;
  557.       rep_cnt = MarkScrollDownDisplay(rep_cnt);
  558.       if (cy > D2W(screenheight-1))
  559.             revto(cx, D2W(screenheight-1));
  560.       else
  561.             GotoPos(cx, W2D(cy));
  562.       break;
  563.     case '@':
  564.       /* it may be usefull to have a key that does nothing */
  565.       break;
  566.     case '%':
  567.       rep_cnt--;
  568.       /* rep_cnt is a percentage for the history buffer */
  569.       if (rep_cnt < 0)
  570.         rep_cnt = 0;
  571.       if (rep_cnt > 100)
  572.         rep_cnt = 100;
  573.       revto_line(left_mar, (rep_cnt * (fore->histheight + screenheight)) / 100, (screenheight-1)/2);
  574.       break;
  575.     case 'g':
  576.       rep_cnt = 1;
  577.       /* FALLTHROUGH */
  578.     case 'G':
  579.       /* rep_cnt is here the WIN line number */
  580.       if (rep_cnt == 0)
  581.         rep_cnt = fore->histheight + screenheight;
  582.       revto_line(left_mar, --rep_cnt, (screenheight-1)/2);
  583.       break;
  584.     case 'H':
  585.       revto(left_mar, D2W(0));
  586.       break;
  587.     case 'M':
  588.       revto(left_mar, D2W((screenheight-1) / 2));
  589.       break;
  590.     case 'L':
  591.       revto(left_mar, D2W(screenheight-1));
  592.       break;
  593.     case '|':
  594.       revto(--rep_cnt, cy);
  595.       break;
  596.     case 'w':
  597.       i = cx;
  598.       j = cy;
  599.       if (rep_cnt == 0)
  600.         rep_cnt = 1;
  601.       nextword(&i, &j, NW_MUSTMOVE, rep_cnt);
  602.       revto(i, j);
  603.       break;
  604.     case 'e':
  605.       i = cx;
  606.       j = cy;
  607.       if (rep_cnt == 0)
  608.         rep_cnt = 1;
  609.       nextword(&i, &j, NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
  610.       revto(i, j);
  611.       break;
  612.     case 'b':
  613.       i = cx;
  614.       j = cy;
  615.       if (rep_cnt == 0)
  616.         rep_cnt = 1;
  617.       nextword(&i, &j, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
  618.       revto(i, j);
  619.       break;
  620.     case 'a':
  621.       append_mode = 1 - append_mode;
  622.       debug1("append mode %d--\n", append_mode);
  623.       Msg(0, (append_mode) ? ":set append" : ":set noappend");
  624.       break;
  625.     case 'v':
  626.     case 'V':
  627.       /* this sets start column to column 9 for VI :set nu users */
  628.       if (left_mar == 8)
  629.         rep_cnt = 1;
  630.       else
  631.         rep_cnt = 9;
  632.       /* FALLTHROUGH */
  633.     case 'c':
  634.     case 'C':
  635.       /* set start column (c) and end column (C) */
  636.       if (second)
  637.         {
  638.           rem(x1, y1, cx, cy, 1, 0, screenheight-1); /* Hack */
  639.           second = 1;    /* rem turns off second */
  640.         }
  641.       rep_cnt--;
  642.       if (rep_cnt < 0)
  643.         rep_cnt = cx;
  644.       if (od != 'C')
  645.         {
  646.           left_mar = rep_cnt;
  647.           if (left_mar > right_mar)
  648.         left_mar = right_mar;
  649.         }
  650.       else
  651.         {
  652.           right_mar = rep_cnt;
  653.           if (left_mar > right_mar)
  654.         right_mar = left_mar;
  655.         }
  656.       if (second)
  657.         {
  658.           int x = cx, y = cy;
  659.           cx = x1; cy = y1;
  660.           revto(x, y);
  661.         }
  662.       if (od == 'v' || od == 'V')
  663.         Msg(0, (left_mar != 8) ? ":set nonu" : ":set nu");
  664.       break;
  665.     case 'J':
  666.       /* how do you join lines in VI ? */
  667.       nonl = (nonl + 1) % 3;
  668.       switch (nonl)
  669.         {
  670.         case 0:
  671.           if (join_with_cr)
  672.         Msg(0, "Multiple lines (CR/LF)");
  673.           else
  674.         Msg(0, "Multiple lines (LF)");
  675.           break;
  676.         case 1:
  677.           Msg(0, "Lines joined");
  678.           break;
  679.         case 2:
  680.           Msg(0, "Lines joined with blanks");
  681.           break;
  682.         }
  683.       break;
  684.     case 'y':
  685.     case 'Y':
  686.       if (!second)
  687.         {
  688.           revto(linestart(cy), cy);
  689.           second++;
  690.           x1 = cx;
  691.           y1 = cy;
  692.         }
  693.       if (--rep_cnt > 0)
  694.         revto(cx, cy + rep_cnt);
  695.       revto(lineend(cy), cy);
  696.       if (od == 'y')
  697.         break;
  698.       /* FALLTHROUGH */
  699.     case 'W':
  700.       if (od == 'W')
  701.         {
  702.           if (rep_cnt == 0)
  703.         rep_cnt = 1;
  704.           if (!second)
  705.         {
  706.           i = cx;
  707.           j = cy;
  708.           nextword(&i, &j, NW_BACK|NW_ENDOFWORD, 1);
  709.           revto(i, j);
  710.           second++;
  711.           x1 = cx;
  712.           y1 = cy;
  713.         }
  714.           i = cx;
  715.           j = cy;
  716.           nextword(&i, &j, NW_ENDOFWORD, rep_cnt);
  717.           revto(i, j);
  718.         }
  719.       /* FALLTHROUGH */
  720.     case 'A':
  721.       if (od == 'A')
  722.         append_mode = 1;
  723.       /* FALLTHROUGH */
  724.     case '>':
  725.       if (od == '>')
  726.         write_buffer = 1;
  727.       /* FALLTHROUGH */
  728.     case ' ':
  729.     case '\r':
  730.       if (!second)
  731.         {
  732.           second++;
  733.           x1 = cx;
  734.           y1 = cy;
  735.           revto(x1, y1);
  736. #ifdef NETHACK
  737.           if (nethackflag)
  738.         Msg(0, "You drop a magic marker - Column %d Line %d",
  739.                 cx+1, W2D(cy)+1, hist_offset);
  740.           else
  741. #endif
  742.           Msg(0, "First mark set - Column %d Line %d", cx+1, cy+1);
  743.           break;
  744.         }
  745.       else
  746.         {
  747.           x2 = cx;
  748.           y2 = cy;
  749.           newcopylen = rem(x1, y1, x2, y2, 2, 0, 0); /* count */
  750.           if (copybuffer != NULL && !append_mode)
  751.         {
  752.           copylen = 0;
  753.           Free(copybuffer);
  754.         }
  755.           if (newcopylen > 0)
  756.         {
  757.           /* the +3 below is for : cr + lf + \0 */
  758.           if (copybuffer != NULL)
  759.             copybuffer = realloc(copybuffer,
  760.             (unsigned) (copylen + newcopylen + 3));
  761.           else
  762.             {
  763.             copylen = 0;
  764.             copybuffer = malloc((unsigned) (newcopylen + 3));
  765.             }
  766.           if (copybuffer == NULL)
  767.             {
  768.               AbortMarkRoutine();
  769.               Msg(0, "Not enough memoooh!... Sorry.");
  770.               copylen = 0;
  771.               copybuffer = NULL;
  772.               break;
  773.             }
  774.           if (append_mode)
  775.             {
  776.               switch (nonl)
  777.             /* 
  778.              * this code defines, what glues lines together
  779.              */
  780.             {
  781.             case 0:
  782.               if (join_with_cr)
  783.                 {
  784.                   copybuffer[copylen] = '\r';
  785.                   copylen++;
  786.                 }
  787.               copybuffer[copylen] = '\n';
  788.               copylen++;
  789.               break;
  790.             case 1:
  791.               break;
  792.             case 2:
  793.               copybuffer[copylen] = ' ';
  794.               copylen++;
  795.               break;
  796.             }
  797.             }
  798.           yend = screenheight - 1;
  799.           if (fore->histheight - hist_offset < screenheight)
  800.             {
  801.               second = 0;
  802.               yend -= MarkScrollUpDisplay(fore->histheight - hist_offset);
  803.             }
  804.           copylen += rem(x1, y1, x2, y2, hist_offset == fore->histheight, copybuffer + copylen, yend);
  805.         }
  806.           if (hist_offset != fore->histheight)
  807.         {
  808.           in_ovl = 0;    /* So we can use Activate() */
  809.           Activate();
  810.         }
  811.           ExitOverlayPage();
  812.           if (append_mode)
  813.         Msg(0, "Appended %d characters to buffer",
  814.             newcopylen);
  815.           else
  816.         Msg(0, "Copied %d characters into buffer", copylen);
  817.           if (write_buffer)
  818.         WriteFile(DUMP_EXCHANGE);
  819.           in_mark = 0;
  820.           break;
  821.         }
  822.     default:
  823.       AbortMarkRoutine();
  824. #ifdef NETHACK
  825.       if (nethackflag)
  826.         Msg(0, "You escaped the dungeon.");
  827.       else
  828. #endif
  829.       Msg(0, "Copy mode aborted");
  830.       break;
  831.     }
  832.       rep_cnt = 0;
  833.     }
  834.   fflush(stdout);
  835.   *inbufp = pt;
  836.   *inlenp = inlen;
  837. }
  838.  
  839. static void revto(tx, ty)
  840. int tx, ty;
  841. {
  842.   revto_line(tx, ty, -1);
  843. }
  844.  
  845. /* tx, ty: WINDOW,  line: DISPLAY */
  846. static void revto_line(tx, ty, line)
  847. int tx, ty, line;
  848. {
  849.   int fx, fy;
  850.   int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
  851.   int ystart = 0, yend = screenheight-1;
  852.   int i, ry;
  853.  
  854.   if (tx < 0)
  855.     tx = 0;
  856.   else if (tx > screenwidth - 1)
  857.     tx = screenwidth -1;
  858.   if (ty < 0)
  859.     ty = 0;
  860.   else if (ty > fore->histheight + screenheight - 1)
  861.     ty = fore->histheight + screenheight - 1;
  862.   
  863.   fx = cx; fy = cy;
  864.   cx = tx; cy = ty;
  865. /*debug2("revto(%d, %d, ", x1, y1);
  866.   debug2("%d, %d, ", fx, fy);
  867.   debug2("%d, %d)\n", tx, ty);*/
  868.  
  869.   /*
  870.    * if we go to a position that is currently offscreen 
  871.    * then scroll the screen
  872.    */
  873.   i = 0;
  874.   if (line >= 0 && line < screenheight)
  875.     i = W2D(ty) - line;
  876.   else if (ty < hist_offset)
  877.     i = ty - hist_offset;
  878.   else if (ty > hist_offset + (screenheight-1))
  879.     i = ty-hist_offset-(screenheight-1);
  880.   if (i > 0)
  881.     yend -= MarkScrollUpDisplay(i);
  882.   else if (i < 0)
  883.     ystart += MarkScrollDownDisplay(-i);
  884.  
  885.   if (second == 0)
  886.     {
  887.       GotoPos(tx, W2D(cy));
  888.       return;
  889.     }
  890.   
  891.   qq = x1 + y1 * screenwidth;
  892.   ff = fx + fy * screenwidth; /* "from" offset in WIN coords */
  893.   tt = tx + ty * screenwidth; /* "to" offset  in WIN coords*/
  894.  
  895.   if (ff > tt)
  896.     {
  897.       st = tt; en = ff;
  898.       x = tx; y = ty;
  899.     }
  900.   else
  901.     {
  902.       st = ff; en = tt;
  903.       x = fx; y = fy;
  904.     }
  905.   if (st > qq)
  906.     {
  907.       st++;
  908.       x++;
  909.     }
  910.   if (en < qq)
  911.     en--;
  912.   if (tt > qq)
  913.     {
  914.       revst = qq; reven = tt;
  915.     }
  916.   else
  917.     {
  918.       revst = tt; reven = qq;
  919.     }
  920.   ry = y - hist_offset;
  921.   if (ry < ystart)
  922.     {
  923.       y += (ystart - ry);
  924.       x = 0;
  925.       st = y * screenwidth;
  926.       ry = ystart;
  927.     }
  928.   for (t = st; t <= en; t++, x++)
  929.     {
  930.       if (x >= screenwidth)
  931.     {
  932.       x = 0;
  933.       y++, ry++;
  934.     }
  935.       if (ry > yend)
  936.     break;
  937.       if (t == st || x == 0)
  938.     {
  939.       for (ce = screenwidth-1; ce >= 0; ce--)
  940.         if (iWIN(y)[ce] != ' ')
  941.           break;
  942.     }
  943.       if (x <= ce && x >= left_mar && x <= right_mar
  944.           && (LP || x < screenwidth-1 || ry < screenbot))
  945.     {
  946.       GotoPos(x, W2D(y));
  947.       if (t >= revst && t <= reven)
  948.         SaveSetAttr(A_SO, ASCII);
  949.       else
  950.         SaveSetAttr(aWIN(y)[x], fWIN(y)[x]);
  951.       PUTCHAR(iWIN(y)[x]);
  952.     }
  953.     }
  954.   GotoPos(tx, W2D(cy));
  955. }
  956.  
  957. static void AbortMarkRoutine()
  958. {
  959.   int yend, redisp;
  960.  
  961.   yend = screenheight - 1;
  962.   redisp = second;
  963.   if (fore->histheight - hist_offset < screenheight)
  964.     {
  965.       second = 0;
  966.       yend -= MarkScrollUpDisplay(fore->histheight - hist_offset);
  967.     }
  968.   if (hist_offset != fore->histheight)
  969.     {
  970.       in_ovl = 0;    /* So we can use Activate() */
  971.       Activate();    /* to do a complete redisplay */
  972.     }
  973.   else
  974.     {
  975.       rem(x1, y1, cx, cy, redisp, 0, yend);
  976.     }
  977.   ExitOverlayPage();
  978.   in_mark = 0;
  979. }
  980.  
  981.  
  982. static void MarkRedisplayLine(y, xs, xe, isblank)
  983. int y; /* NOTE: y is in DISPLAY coords system! */
  984. int xs, xe;
  985. int isblank;
  986. {
  987.   int x, i, rm;
  988.   int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
  989.   char *wi, *wa, *wf, *oldi;
  990.  
  991.   InsertMode(0); /* Not done in DisplayLine() */
  992.  
  993.   wi = iWIN(D2W(y));
  994.   wa = aWIN(D2W(y));
  995.   wf = fWIN(D2W(y));
  996.   oldi = isblank ? blank : null;
  997.  
  998.   if (second == 0)
  999.     {
  1000.       DisplayLine(oldi, null, null, wi, wa, wf, y, xs, xe);
  1001.       return;
  1002.     }
  1003.  
  1004.   sta = y1 * screenwidth + x1;
  1005.   sto = cy * screenwidth + cx;
  1006.   if (sta > sto)
  1007.     {
  1008.       i=sta; sta=sto; sto=i;
  1009.     }
  1010.   cp = D2W(y) * screenwidth + xs;
  1011.  
  1012.   rm = right_mar;
  1013.   for (x=screenwidth-1; x>=0; x--)
  1014.     if (wi[x] != ' ')
  1015.       break;
  1016.   if (x < rm)
  1017.     rm = x;
  1018.  
  1019.   for (x=xs; x<=xe; x++, cp++)
  1020.     if (cp>=sta && x>= left_mar)
  1021.       break;
  1022.   if (x>xs)
  1023.     DisplayLine(oldi, null, null, wi, wa, wf, y, xs, x-1);
  1024.   for (; x<=xe; x++, cp++)
  1025.     {
  1026.       if (cp > sto || x > rm || (!LP && x >= screenwidth-1 && y == screenbot))
  1027.     break;
  1028.       GotoPos(x, y);
  1029.       SaveSetAttr(A_SO, ASCII);
  1030.       PUTCHAR(wi[x]);
  1031.     }
  1032.   if (x<=xe)
  1033.     DisplayLine(oldi, null, null, wi, wa, wf, y, x, xe);
  1034. }
  1035.  
  1036.  
  1037. static int
  1038. MarkRewrite(ry, xs, xe, doit)
  1039. int ry, xs, xe, doit;
  1040. {
  1041.   int dx, x, y, st, en, t, rm;
  1042.   char *a, *f, *i;
  1043.  
  1044.   y = D2W(ry);
  1045.   dx = xe - xs;
  1046.   if (doit)
  1047.     {
  1048.       i = iWIN(y) + xs;
  1049.       while (dx--)
  1050.         PUTCHAR(*i++);
  1051.       return(0);
  1052.     }
  1053.   
  1054.   a = aWIN(y) + xs,
  1055.   f = fWIN(y) + xs;
  1056.   if (second == 0)
  1057.     st = en = -1;
  1058.   else
  1059.     {
  1060.       st = y1 * screenwidth + x1;
  1061.       en = cy * screenwidth + cx;
  1062.       if (st > en)
  1063.         {
  1064.           t = st; st = en; en = t;
  1065.         }
  1066.     }
  1067.   t = y * screenwidth + xs;
  1068.   for (rm=screenwidth-1, i=iWIN(y) + screenwidth-1; rm>=0; rm--)
  1069.     if (*i-- != ' ')
  1070.       break;
  1071.   if (rm > right_mar)
  1072.     rm = right_mar;
  1073.   x = xs;
  1074.   while (dx--)
  1075.     {
  1076.       if (t >= st && t <= en && x >= left_mar && x <= rm)
  1077.         {
  1078.       if (GlobalAttr != A_SO || GlobalCharset != ASCII)
  1079.         return(EXPENSIVE);
  1080.         }
  1081.       else
  1082.         {
  1083.       if (GlobalAttr != *a || GlobalCharset != *f)
  1084.         return(EXPENSIVE);
  1085.         }
  1086.       a++, f++, t++, x++;
  1087.     }
  1088.   return(xe - xs);
  1089. }
  1090.  
  1091.  
  1092. /*
  1093.  * scroll the screen contents up/down.
  1094.  */
  1095. static int MarkScrollUpDisplay(n)
  1096. int n;
  1097. {
  1098.   int i;
  1099.  
  1100.   debug1("MarkScrollUpDisplay(%d)\n", n);
  1101.   if (n <= 0)
  1102.     return 0;
  1103.   if (n > fore->histheight - hist_offset)
  1104.     n = fore->histheight - hist_offset;
  1105.   i = (n < screenheight) ? n : (screenheight);
  1106.   ScrollRegion(0, screenheight - 1, i);
  1107.   hist_offset += n;
  1108.   while (i-- > 0)
  1109.     MarkRedisplayLine(screenheight-i-1, 0, screenwidth-1, 1);
  1110.   return n;
  1111. }
  1112.  
  1113. static int MarkScrollDownDisplay(n)
  1114. int n;
  1115. {
  1116.   int i;
  1117.  
  1118.   debug1("MarkScrollDownDisplay(%d)\n", n);
  1119.   if (n <= 0)
  1120.     return 0;
  1121.   if (n > hist_offset)
  1122.     n = hist_offset;
  1123.   i = (n < screenheight) ? n : (screenheight);
  1124.   ScrollRegion(0, screenheight - 1, -i);
  1125.   hist_offset -= n;
  1126.   while (i-- > 0)
  1127.     MarkRedisplayLine(i, 0, screenwidth-1, 1);
  1128.   return n;
  1129. }
  1130.  
  1131.