home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / screen-3.5 / part04 / mark.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-25  |  25.0 KB  |  1,144 lines

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