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