home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / forth / pfe-0.000 / pfe-0 / pfe-0.9.13 / src / 4ed.c next >
Encoding:
C/C++ Source or Header  |  1995-07-17  |  23.4 KB  |  1,411 lines

  1. /*
  2.  * This file is part of the portable Forth environment written in ANSI C.
  3.  * Copyright (C) 1995  Dirk Uwe Zoller
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Library General Public
  7.  * License as published by the Free Software Foundation; either
  8.  * version 2 of the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13.  * See the GNU Library General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Library General Public
  16.  * License along with this library; if not, write to the Free
  17.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  * This file is version 0.9.13 of 17-July-95
  20.  * Check for the latest version of this package via anonymous ftp at
  21.  *    roxi.rz.fht-mannheim.de:/pub/languages/forth/pfe-VERSION.tar.gz
  22.  * or    sunsite.unc.edu:/pub/languages/forth/pfe-VERSION.tar.gz
  23.  * or    ftp.cygnus.com:/pub/forth/pfe-VERSION.tar.gz
  24.  *
  25.  * Please direct any comments via internet to
  26.  *    duz@roxi.rz.fht-mannheim.de.
  27.  * Thank You.
  28.  */
  29. /*
  30.  * 4ed.c --- simple FORTH-screenfile editor
  31.  * (duz 28May93)
  32.  */
  33.  
  34. #include "forth.h"
  35. #include "support.h"
  36. #include "term.h"
  37. #include "lined.h"
  38.  
  39. #include <stdlib.h>
  40. #include <stdarg.h>
  41. #include <string.h>
  42. #include <ctype.h>
  43. #include <time.h>
  44. #include <signal.h>
  45.  
  46. #include "nonansi.h"
  47. #include "missing.h"
  48.  
  49.  
  50. typedef char line[64];
  51. typedef line blck[16];        /* block buffer */
  52.  
  53. static line            /* block buffers used for editing */
  54.   *buf, *blk,            /* and stacking source */
  55.   *linestk, *linetop, *linesp;
  56. static blck
  57.   *blkstk, *blktop, *blksp;
  58.  
  59. static int row, col;        /* cursor position */
  60. struct position { int row, col, scr; };
  61. static struct position mark = { 0 };
  62.  
  63. static char            /* mode flags: */
  64.   overtype = 0,            /*   overwrite mode */
  65.   caps = 1,            /*   simulate CAPS (for stupid DIN keyboard) */
  66.   stamp_changed = 1,        /*   shall changed screens be stamped? */
  67.   was_replacing = 0,        /*   action of ^L, repeat search or replace? */
  68.   readonly;            /*   file cannot be written */
  69.  
  70. static char log_name[16];    /* for stamp to screen */
  71.  
  72. static char search_str[32] = "";
  73. static char search_history[512];
  74. static struct lined search_lined =
  75. {
  76.   search_str, sizeof search_str,
  77.   search_history, sizeof search_history,
  78.   complete_dictionary, NULL
  79. };
  80.  
  81. static char replace_str[32] = "";
  82. static char replace_history[512];
  83. static struct lined replace_lined =
  84. {
  85.   replace_str, sizeof replace_str,
  86.   replace_history, sizeof replace_history,
  87.   complete_dictionary, NULL
  88. };
  89.  
  90. #define setcursor(R,C)    c_gotoxy ((C) + 16, (R))
  91.  
  92.  
  93. /*
  94.  * file-i/o
  95.  */
  96.  
  97. #define NOBLK UCELL_MAX
  98.  
  99. static int
  100. scr_changed (void)
  101. {
  102.   blk = (line *)block (BLOCK_FILE, SCR);
  103.   return memcmp (blk, buf, sizeof (blck)) != 0;
  104. }
  105.  
  106. static int
  107. block_empty (char *p)
  108. {
  109.   int n;
  110.  
  111.   for (n = 64; n < BPBUF; n++)
  112.     if (p[n] != ' ' && printable (p[n]))
  113.       return 0;
  114.   return 1;
  115. }
  116.  
  117. static int
  118. scr_empty (int n)
  119. {
  120.   return block_empty (block (BLOCK_FILE, n));
  121. }
  122.  
  123. static void
  124. scr_copy (int dst, int src)
  125. {
  126.   block (BLOCK_FILE, src);
  127.   BLOCK_FILE->n = dst;
  128.   update (BLOCK_FILE);
  129.   save_buffers (BLOCK_FILE);
  130. }
  131.  
  132. static void
  133. truncate_file (void)
  134. {
  135.   int n;
  136.  
  137.   for (n = BLOCK_FILE->size; n; n--)
  138.     if (!scr_empty (n - 1))
  139.       break;
  140.   resize_file (BLOCK_FILE, n * BPBUF);
  141. }
  142.  
  143. static void
  144. stamp_screen (void)
  145. {
  146.   time_t t;
  147.   struct tm *tm;
  148.   char stamp[65];
  149.   int n;
  150.  
  151.   time (&t);
  152.   tm = localtime (&t);
  153.   n = 64 - 3 - strlen (log_name) - 6 - 9;
  154.   sprintf (stamp, "\\ %.*s %s %02d:%02d %02d/%02d/%02d",
  155.        n, &buf[0][2], log_name, tm->tm_hour, tm->tm_min,
  156.        tm->tm_mon + 1, tm->tm_mday, tm->tm_year);
  157.   COPY (buf[0], stamp);
  158. }
  159.  
  160. static void
  161. writebuf (void)
  162. {
  163.   int dummy;
  164.  
  165.   if (SCR != NOBLK && scr_changed ())
  166.     {
  167.       if (stamp_changed)
  168.     stamp_screen ();
  169.       blk = (line *)buffer (BLOCK_FILE, SCR, &dummy);
  170.       memcpy (blk, buf, sizeof (blck));
  171.       update (BLOCK_FILE);
  172.       save_buffers (BLOCK_FILE);
  173.     }
  174. }
  175.  
  176. static void
  177. readbuf (int n)
  178. {
  179.   blk = (line *)block (BLOCK_FILE, n);
  180.   memcpy (buf, blk, sizeof (blck));
  181.   SCR = n;
  182. }
  183.  
  184. static void
  185. changescr (int n)
  186. {
  187.   writebuf ();
  188.   readbuf (n);
  189. }
  190.  
  191.  
  192. /*
  193.  * screen-i/o
  194.  */
  195.  
  196. static int
  197. getckey (void)
  198. {
  199.   char c = getwskey ();
  200.   return c < ' '
  201.     ? c + '@'
  202.     : toupper (c);
  203. }
  204.  
  205. static void
  206. c_printf (char *fmt,...)
  207. {
  208.   char buf[0x200];
  209.   va_list p;
  210.  
  211.   va_start (p, fmt);
  212.   vsprintf (buf, fmt, p);
  213.   va_end (p);
  214.   c_puts (buf);
  215. }
  216.  
  217. static void
  218. type_line (char *p, int n)
  219. {
  220.   int i;
  221.  
  222.   for (i = 0; i < n; i++)
  223.     if (!printable (p[i]))
  224.       break;
  225.   if (i < n)
  226.     while (n--)
  227.       c_putc_printable (*p++);
  228.   else
  229.     type (p, n);
  230. }
  231.  
  232.  
  233. /*
  234.  * show help
  235.  */
  236.  
  237. struct helpline
  238. {
  239.   char row, col;
  240.   char *str;
  241. };
  242.  
  243. static struct helpline *displayed_help = NULL;
  244. static struct helpline primary_help[] =
  245. {
  246.   {0, 0, "CURSOR MOVE"},
  247.   {1, 1, "^E up"},
  248.   {2, 1, "^X down"},
  249.   {3, 1, "^S left"},
  250.   {4, 1, "^D right"},
  251.   {5, 1, "^A word left"},
  252.   {6, 1, "^F word right"},
  253.  
  254.   {0, 20, "INSERT"},
  255.   {1, 21, "^W char"},
  256.   {2, 21, "^N line"},
  257.   {3, 21, "^P quotes ctl"},
  258.   {4, 21, "^V toggle overtype"},
  259.  
  260.   {0, 40, "DELETE"},
  261.   {1, 41, "^H char left"},
  262.   {2, 41, "^G char right"},
  263.   {3, 41, "^T word right"},
  264.   {4, 41, "^Y line"},
  265.  
  266.   {0, 60, "SCREEN CHANGE"},
  267.   {1, 61, "^R previous"},
  268.   {2, 61, "^C next"},
  269.  
  270.   {3, 60, "OTHER"},
  271.   {4, 61, "^L find string"},
  272.   {5, 61, "^Q... more"},
  273.   {6, 61, "^K... more"},
  274.   {7, 61, "^U exit editor"},
  275. };
  276. static struct helpline ctl_k_help[] =
  277. {
  278.   {0, 0, "LINE STACK"},
  279.   {1, 1, "X push line"},
  280.   {4, 1, "Y push&delete"},
  281.   {2, 1, "E pop line"},
  282.   {3, 1, "W pop&insert"},
  283.   {5, 1, "N push eol"},
  284.   {6, 1, "T pop eol"},
  285.  
  286.   {0, 20, "EVALUATE"},
  287.   {1, 21, "L this line"},
  288.   {2, 21, "B this block"},
  289.   {3, 21, "F block# 1"},
  290.  
  291.   {0, 40, "INSERT"},
  292.   {1, 41, "V insert block"},
  293.   {2, 40, "DELETE"},
  294.   {3, 41, "G delete block"},
  295.  
  296.   {0, 60, "OTHER"},
  297.   {1, 61, "M set mark"},
  298.   {2, 61, "R restore block"},
  299. };
  300. static struct helpline ctl_o_help[] =
  301. {
  302.   {0, 0, "OPTIONS"},
  303.   {1, 1, "C caps lock"},
  304.   {2, 1, "S stamp on/off"},
  305. };
  306. static struct helpline ctl_q_help[] =
  307. {
  308.   {0, 0, "CURSOR MOVE"},
  309.   {1, 1, "E top of block"},
  310.   {2, 1, "X bottom"},
  311.   {3, 1, "S begin line"},
  312.   {4, 1, "D end of line"},
  313.  
  314.   {0, 20, "FIND&REPLACE"},
  315.   {1, 21, "F find string"},
  316.   {2, 21, "A find and replace"},
  317.  
  318.   {0, 40, "INSERT"},
  319.   {1, 41, "N split line"},
  320.   {2, 40, "DELETE"},
  321.   {3, 41, "Y end of line"},
  322.  
  323.   {0, 60, "SCREEN CHANGE"},
  324.   {1, 61, "R first"},
  325.   {2, 61, "C last"},
  326.   {3, 60, "OTHER"},
  327.   {4, 61, "M goto mark"},
  328.   {5, 61, "L redraw screen"},
  329. };
  330.  
  331. static void
  332. show_help (int row, int col, int n, struct helpline *h)
  333. {
  334.   for (; n > 0; n--, h++)
  335.     {
  336.       setcursor (row + h->row, col + h->col);
  337.       c_puts (h->str);
  338.     }
  339. }
  340.  
  341. static void
  342. show_bottom_help (int n, struct helpline *h)
  343. {
  344.   if (displayed_help == h)
  345.     return;
  346.   setcursor (17, -16);
  347.   c_clrdown ();
  348.   show_help (17, -16, n, h);
  349.   displayed_help = h;
  350. }
  351.  
  352.  
  353. /*
  354.  * display blocks and lines on screen
  355.  */
  356.  
  357. static int
  358. coleol (int row)
  359. {
  360.   char *p = buf[row];
  361.   int col;
  362.  
  363.   col = 63;
  364.   if (p[col] == ' ')
  365.     while (col > 0 && p[col - 1] == ' ')
  366.       col--;
  367.   return col;
  368. }
  369.  
  370. static char *
  371. ptreol (int row)
  372. {
  373.   char *p, *q = buf[row];
  374.  
  375.   for (p = q + 64; p > q && p[-1] == ' '; p--);
  376.   return p;
  377. }
  378.  
  379. static void
  380. show_line (int i, int col)
  381. {
  382.   char *p;
  383.   int n;
  384.  
  385.   setcursor (i, col);
  386.   p = &buf[i][col];
  387.   n = ptreol (i) - p;
  388.   if (n > 0)
  389.     type_line (p, n);
  390.   if (col + n < 64)
  391.     c_clreol ();
  392. }
  393.  
  394. static void
  395. show_all_lines (int from)
  396. {
  397.   int i;
  398.  
  399.   for (i = from; i < 16; i++)
  400.     show_line (i, 0);
  401. }
  402.  
  403. static void
  404. show_screen (void)
  405. {
  406.   setcursor (0, -11);
  407.   c_printf ("%4u", (unsigned) SCR);
  408.   show_all_lines (0);
  409. }
  410.  
  411. static void
  412. show_status (void)
  413. {
  414.   setcursor (4, -16);
  415.   c_printf ("%3d  %3d", (int) row, (int) col);
  416.   setcursor (5, -12);
  417.   c_printf ("%02X", (unsigned char) buf[row][col]);
  418.   if (readonly)
  419.     {
  420.       if (scr_changed ())
  421.     {
  422.       memcpy (buf, blk, sizeof (blck));
  423.       c_bell ();
  424.       show_all_lines (0);
  425.     }
  426.     }
  427.   else
  428.     {
  429.       setcursor (0, -4);
  430.       c_putc (scr_changed () ? '*' : ' ');
  431.     }
  432. }
  433.  
  434. static void
  435. show_snr (void)
  436. {
  437.   c_underline_on ();
  438.   setcursor ( 8, -15), c_printf ("%-12.12s", search_str);
  439.   setcursor (10, -15), c_printf ("%-12.12s", replace_str);
  440.   c_underline_off ();
  441. }
  442.  
  443. static void
  444. show_options (void)
  445. {
  446.   setcursor (12, -15);
  447.   c_printf ("%c %c %c %c",
  448.         caps ? 'C' : ' ',
  449.         overtype ? 'O' : 'I',
  450.         was_replacing ? 'R' : 'F',
  451.         stamp_changed ? 'S' : ' ');
  452. }
  453.  
  454. static void
  455. show_line_stack (void)
  456. {
  457.   char buf[65];
  458.  
  459.   if (linesp == linetop)
  460.     memset (buf, '-', 64);
  461.   else
  462.     memcpy (buf, *linesp, 64);
  463.   buf[64] = '\0';
  464.   setcursor (16, -16);
  465.   c_reverse ();
  466.   c_printf ("line stack:  %2d %s", linetop - linesp, buf);
  467.   c_normal ();
  468. }
  469.  
  470. static void
  471. show_frame (void)
  472. {
  473.   int i;
  474.  
  475.   setcursor ( 0, -16), c_puts ("blk #");
  476.   setcursor ( 1, -16), c_printf ("%-10.10s", BLOCK_FILE->name);
  477.   setcursor ( 3, -16), c_puts ("row  col");
  478.   setcursor ( 5, -16), c_puts ("hex");
  479.   setcursor ( 7, -16), c_puts ("find:");
  480.   setcursor ( 9, -16), c_puts ("replace:");
  481.   setcursor (11, -16), c_puts ("options:");
  482.   if (readonly)
  483.     {
  484.       setcursor (0, -4);
  485.       c_putc ('%');
  486.     }
  487.   c_reverse ();
  488.   for (i = 0; i < 16; i++)
  489.     {
  490.       setcursor (i, -3);
  491.       c_printf ("%2d", i);
  492.     }
  493.   c_normal ();
  494. }
  495.  
  496. static void
  497. show_all (void)
  498. {
  499.   c_normal ();
  500.   c_clrscr ();
  501.   show_frame ();
  502.   show_snr ();
  503.   show_options ();
  504.   show_screen ();
  505.   show_line_stack ();
  506.   displayed_help = NULL;
  507.   show_bottom_help (DIM (primary_help), primary_help);
  508. }
  509.  
  510. static void
  511. show_ctl (char c)
  512. {
  513.   setcursor (15, -7);
  514.   if (c)
  515.     c_printf ("^%c", c);
  516.   else
  517.     c_puts ("  ");
  518. }
  519.  
  520. static int
  521. prompt_for (char *prompt, struct lined *l, char *dflt)
  522. {
  523.   setcursor (16, -16);
  524.   c_reverse ();
  525.   c_printf ("%15s[%*s]%*s", prompt,
  526.        l->max_length, "",
  527.        80 - 17 - l->max_length, "");
  528.   setcursor (16, 0);
  529.   lined (l, dflt);
  530.   c_normal ();
  531.   show_line_stack ();
  532.   return l->length;
  533. }
  534.  
  535. static int
  536. yesno (char *prompt)
  537. {
  538.   int c;
  539.  
  540.   setcursor (16, -16);
  541.   c_reverse ();
  542.   c_printf ("%15s?%*s", prompt, 64, "");
  543.   setcursor (16, 0);
  544.   do
  545.     c = toupper (c_getkey ());
  546.   while (c != 'N' && c != 'Y');
  547.   show_line_stack ();
  548.   return c == 'Y';
  549. }
  550.  
  551. static void
  552. word_from_cursor (char *p, int n)
  553. {
  554.   char *q = &buf[row][col];
  555.   while (q < buf[16] && q[0] == ' ')
  556.     q++;
  557.   while (q > buf[0] && q[-1] != ' ')
  558.     q--;
  559.   while (q < buf[16] && q[0] != ' ')
  560.     {
  561.       *p++ = *q++;
  562.       if (--n == 0)
  563.     break;
  564.     }
  565.   *p = '\0';
  566. }
  567.  
  568.  
  569. /*
  570.  * insert / delete character, word, line
  571.  */
  572.  
  573. static void
  574. insertc (char c)
  575. {
  576.   char *p = &buf[row][col], *q;
  577.  
  578.   for (q = &buf[row][coleol (row)] + 1; --q > p;)
  579.     q[0] = q[-1];
  580.   *p = c;
  581. }
  582.  
  583. static void
  584. deletec (void)
  585. {
  586.   char *p, *q = ptreol (row) - 1;
  587.  
  588.   for (p = &buf[row][col]; p < q; p++)
  589.     p[0] = p[1];
  590.   *p = ' ';
  591. }
  592.  
  593. static void
  594. insertl (int row)
  595. {
  596.   int i;
  597.  
  598.   for (i = 15; i > row; i--)
  599.     COPY (buf[i], buf[i - 1]);
  600.   memset (buf + i, ' ', sizeof buf[15]);
  601. }
  602.  
  603. static void
  604. deletel (int row)
  605. {
  606.   int i;
  607.  
  608.   for (i = row; i < 15; i++)
  609.     COPY (buf[i], buf[i + 1]);
  610.   memset (buf + 15, ' ', sizeof buf[15]);
  611. }
  612.  
  613. static void
  614. clear_endl (void)
  615. {
  616.   char *p = &buf[row][col], *q = ptreol (row);
  617.  
  618.   if (q > p)
  619.     memset (p, ' ', q - p);
  620. }
  621.  
  622. static void
  623. strip_blanks (char **p, int *n)
  624. {
  625.   while (*n && (*p)[*n - 1] == ' ')
  626.     --*n;
  627.   while (*n && **p == ' ')
  628.     --*n, ++*p;
  629. }
  630.  
  631. static int
  632. append_line (char *ln)
  633. {
  634.   char *q = ptreol (row);
  635.   int n = 64, j = q - buf[row];
  636.  
  637.   strip_blanks (&ln, &n);
  638.   if (j)
  639.     q++, j++;
  640.   if (64 - j < n)
  641.     return 0;
  642.   memcpy (q, ln, n);
  643.   return 1;
  644. }
  645.  
  646. static void
  647. split_line (void)
  648. {
  649.   if (row == 15)
  650.     clear_endl ();
  651.   else
  652.     {
  653.       insertl (row);
  654.       memcpy (buf[row], buf[row + 1], col);
  655.       memset (buf[row + 1], ' ', col);
  656.     }
  657. }
  658.  
  659. static void
  660. join_line (void)
  661. {
  662.   if (row < 15 && append_line (buf[row + 1]))
  663.     deletel (row + 1);
  664.   else
  665.     c_bell ();
  666. }
  667.  
  668. static void
  669. deletew (void)
  670. {
  671.   char *p = &buf[row][col];
  672.   int n = ptreol (row) - p;
  673.  
  674.   if (n <= 0)
  675.     {
  676.       join_line ();
  677.       show_all_lines (row);
  678.     }
  679.   else
  680.     {
  681.       while (n && *p != ' ')
  682.     deletec (), n--;
  683.       while (n && *p == ' ')
  684.     deletec (), n--;
  685.     }
  686. }
  687.  
  688. static void
  689. inserts (void)
  690. {
  691.   int n;
  692.  
  693.   writebuf ();
  694.   for (n = BLOCK_FILE->size; n > SCR; n--)
  695.     if (!scr_empty (n - 1))
  696.       break;
  697.   for (; n > SCR; n--)
  698.     scr_copy (n, n - 1);
  699.   memset (buf, ' ', sizeof (blck));
  700.   stamp_screen ();
  701.   writebuf ();
  702.   show_screen ();
  703. }
  704.  
  705. static int
  706. deletes (void)
  707. {
  708.   int n;
  709.  
  710.   if ((!scr_empty (SCR) || !block_empty (buf[0]))
  711.       && !yesno ("delete screen"))
  712.     return 0;
  713.   writebuf ();
  714.   for (n = SCR + 1; n < BLOCK_FILE->size; n++)
  715.     scr_copy (n - 1, n);
  716.   memset (buffer (BLOCK_FILE, BLOCK_FILE->size - 1, &n), ' ', BPBUF);
  717.   update_ ();
  718.   readbuf (SCR);
  719.   show_screen ();
  720.   return 1;
  721. }
  722.  
  723.  
  724. /*
  725.  * move cursor
  726.  */
  727.  
  728. static void
  729. fwd_word (void)
  730. {
  731.   char *p = &buf[row][col];
  732.   int n;
  733.  
  734.   while (p < buf[16] - 1)
  735.     if (*p != ' ')
  736.       p++;
  737.     else
  738.       break;
  739.   while (p < buf[16] - 1)
  740.     if (*p == ' ')
  741.       p++;
  742.     else
  743.       break;
  744.   n = p - buf[0];
  745.   row = n / 64;
  746.   col = n % 64;
  747. }
  748.  
  749. static void
  750. back_word (void)
  751. {
  752.   char *p = &buf[row][col];
  753.   int n;
  754.  
  755.   while (buf[0] < p)
  756.     if (p[-1] == ' ')
  757.       p--;
  758.     else
  759.       break;
  760.   while (buf[0] < p)
  761.     if (p[-1] != ' ')
  762.       p--;
  763.     else
  764.       break;
  765.   n = p - buf[0];
  766.   row = n / 64;
  767.   col = n % 64;
  768. }
  769.  
  770.  
  771. /*
  772.  * line- and block-stack
  773.  */
  774.  
  775. static int
  776. push_to_linestk (char *p, int n)
  777. {
  778.   if (linesp == linestk)
  779.     {
  780.       c_bell ();
  781.       return 0;
  782.     }
  783.   linesp--;
  784.   memcpy (*linesp, p, n);
  785.   memset (*linesp + n, ' ', 64 - n);
  786.   show_line_stack ();
  787.   return 1;
  788. }
  789.  
  790. static int
  791. pushln (int row)
  792. {
  793.   return push_to_linestk (buf[row], 64);
  794. }
  795.  
  796. static int
  797. popln (char *to)
  798. {
  799.   if (linesp == linetop)
  800.     {
  801.       c_bell ();
  802.       return 0;
  803.     }
  804.   memcpy (to, *linesp++, 64);
  805.   show_line_stack ();
  806.   return 1;
  807. }
  808.  
  809. void
  810. push_del_line (void)
  811. {
  812.   if (pushln (row))
  813.     {
  814.       deletel (row);
  815.       show_all_lines (row);
  816.     }
  817. }
  818.  
  819. void
  820. push_line (void)
  821. {
  822.   if (pushln (row) && row < 15)
  823.     row++;
  824. }
  825.  
  826. void
  827. pop_spread_line (void)
  828. {
  829.   if (linesp < linetop)
  830.     {
  831.       insertl (row);
  832.       popln (buf[row]);
  833.       show_all_lines (row);
  834.     }
  835.   else
  836.     c_bell ();
  837. }
  838.  
  839. void
  840. pop_line (void)
  841. {
  842.   if (popln (buf[row]))
  843.     {
  844.       show_line (row, 0);
  845.       if (row > 0)
  846.     row--;
  847.     }
  848. }
  849.  
  850. void
  851. push_line_end (void)
  852. {
  853.   if (push_to_linestk (&buf[row][col], 64 - col))
  854.     {
  855.       clear_endl ();
  856.       show_line (row, col);
  857.     }
  858. }
  859.  
  860. void
  861. pop_line_end (void)
  862. {
  863.   int c = coleol (row);
  864.  
  865.   if (c >= 63)
  866.     {
  867.       c_bell ();
  868.       return;
  869.     }
  870.   col = c ? c + 1 : 0;
  871.   if (linesp < linetop && append_line (*linesp))
  872.     {
  873.       linesp++;
  874.       show_line_stack ();
  875.       show_line (row, col);
  876.     }
  877.   else
  878.     c_bell ();
  879. }
  880.  
  881.  
  882. /*
  883.  * find and replace
  884.  */
  885.  
  886. static int
  887. search_string (int prompt)
  888. {
  889.   int i, n, l;
  890.   char *b, *p;
  891.  
  892.   l = strlen (search_str);
  893.   if (prompt || l == 0)
  894.     {
  895.       char buf[65];
  896.       word_from_cursor (buf, sizeof buf);
  897.       search_lined.overtype = overtype;
  898.       l = prompt_for ("Search: ", &search_lined, buf);
  899.       show_snr ();
  900.     }
  901.   if (l == 0)
  902.     return 0;
  903.   b = buf[0];
  904.   n = &buf[row][col] + 1 - b;
  905.   p = search (b + n, BPBUF - n, search_str, l);
  906.   if (!p)
  907.     for (i = SCR + 1; i < BLOCK_FILE->size; i++)
  908.       {
  909.     b = block (BLOCK_FILE, i);
  910.     p = search (b, BPBUF, search_str, l);
  911.     if (p)
  912.       {
  913.         changescr (i);
  914.         show_screen ();
  915.         break;
  916.       }
  917.       }
  918.   if (!p)
  919.     return 0;
  920.   n = p - b;
  921.   row = n / 64;
  922.   col = n % 64;
  923.   return 1;
  924. }
  925.  
  926. static int
  927. replace_string (int prompt)
  928. {
  929.   int i, lr, ls;
  930.  
  931.   if (!search_string (prompt))
  932.     return 0;
  933.   ls = strlen (search_str);
  934.   lr = strlen (replace_str);
  935.   if (prompt || lr == 0)
  936.     {
  937.       replace_lined.overtype = overtype;
  938.       lr = prompt_for ("Replace: ", &replace_lined, NULL);
  939.       show_snr ();
  940.     }
  941.   if (lr == 0)
  942.     return 0;
  943.   for (i = 0; i < ls; i++)
  944.     deletec ();
  945.   for (i = lr; --i >= 0;)
  946.     insertc (replace_str[i]);
  947.   show_line (row, col);
  948.   return 1;
  949. }
  950.  
  951.  
  952. /*
  953.  * keyboard input and dispatch
  954.  */
  955.  
  956. static struct helpline *sub_help = NULL;
  957. static int sub_help_len;
  958.  
  959. static void
  960. show_sub_help (int sig)
  961. {
  962. #if defined EMX || defined WC_OS2V2
  963.   signal (sig, SIG_ACK);
  964. #elif defined SIGALRM
  965.   signal (SIGALRM, SIG_IGN);
  966. #endif
  967.   show_bottom_help (sub_help_len, sub_help);
  968.   setcursor (row, col);
  969. }
  970.  
  971. static void
  972. submenu (char key, int n, struct helpline *h)
  973. {
  974.   show_ctl (key);
  975.   if (key)
  976.     {
  977.       sub_help_len = n;
  978.       sub_help = h;
  979. #if defined SIGALRM
  980.       signal (SIGALRM, show_sub_help);
  981.       alarm (1);
  982. #else
  983.       show_sub_help (0);
  984. #endif
  985.     }
  986.   else
  987.     {
  988. #if defined SIGALRM
  989.       signal (SIGALRM, SIG_IGN);
  990. #endif
  991.       show_bottom_help (DIM (primary_help), primary_help);
  992.     }
  993.   setcursor (row, col);
  994. }
  995.  
  996. static void
  997. do_ctlK (void)
  998. {
  999.   int c;
  1000.  
  1001.   submenu ('K', DIM (ctl_k_help), ctl_k_help);
  1002.   c = getckey ();
  1003.   submenu (0, 0, NULL);
  1004.   switch (c)
  1005.     {
  1006.     default:
  1007.       c_bell ();
  1008.     case ' ':
  1009.     case '\033':
  1010.       break;
  1011.     case 'Y':
  1012.     case 'Z':
  1013.       push_del_line ();
  1014.       break;
  1015.     case 'X':
  1016.       push_line ();
  1017.       break;
  1018.     case 'W':
  1019.       pop_spread_line ();
  1020.       break;
  1021.     case 'E':
  1022.       pop_line ();
  1023.       break;
  1024.     case 'N':
  1025.       push_line_end ();
  1026.       break;
  1027.     case 'T':
  1028.       pop_line_end ();
  1029.       break;
  1030.     case 'D':
  1031.       stamp_screen ();
  1032.       show_line (0, 0);
  1033.       row = 0;
  1034.       col = 2;
  1035.       overtype = 1;
  1036.     case 'L':
  1037.       show_bottom_help (0, NULL);
  1038.       writebuf ();
  1039.       evaluate (buf[row], 64);
  1040.       readbuf (SCR);
  1041.       show_all ();
  1042.       break;
  1043.     case 'B':
  1044.       show_bottom_help (0, NULL);
  1045.       writebuf ();
  1046.       load (BLOCK_FILE, SCR);
  1047.       readbuf (SCR);
  1048.       show_all ();
  1049.       break;
  1050.     case 'F':
  1051.       show_bottom_help (0, NULL);
  1052.       writebuf ();
  1053.       truncate_file ();
  1054.       load (BLOCK_FILE, 1);
  1055.       readbuf (SCR);
  1056.       show_all ();
  1057.       break;
  1058.     case 'M':
  1059.       mark.row = row;
  1060.       mark.col = col;
  1061.       mark.scr = SCR;
  1062.       break;
  1063.     case 'R':
  1064.       memcpy (buf, blk, sizeof (blck));
  1065.       show_screen ();
  1066.       break;
  1067.     case 'V':
  1068.       inserts ();
  1069.       break;
  1070.     case 'G':
  1071.       deletes ();
  1072.       break;
  1073.     }
  1074. }
  1075.  
  1076. static void
  1077. do_ctlO (void)
  1078. {
  1079.   int c;
  1080.  
  1081.   submenu ('O', DIM (ctl_o_help), ctl_o_help);
  1082.   c = getckey ();
  1083.   submenu (0, 0, NULL);
  1084.   switch (c)
  1085.     {
  1086.     default:
  1087.       c_bell ();
  1088.     case ' ':
  1089.     case '\033':
  1090.       break;
  1091.     case 'C':
  1092.       caps ^= 1;
  1093.       show_options ();
  1094.       break;
  1095.     case 'S':
  1096.       stamp_changed ^= 1;
  1097.       show_options ();
  1098.       break;
  1099.     }
  1100. }
  1101.  
  1102. static void
  1103. do_ctlQ (void)
  1104. {
  1105.   int c;
  1106.  
  1107.   submenu ('Q', DIM (ctl_q_help), ctl_q_help);
  1108.   c = getckey ();
  1109.   submenu (0, 0, NULL);
  1110.   switch (c)
  1111.     {
  1112.     default:
  1113.       c_bell ();
  1114.     case ' ':
  1115.     case '[':
  1116.       break;
  1117.     case 'E':
  1118.       row = 0;
  1119.       break;
  1120.     case 'X':
  1121.       row = 15;
  1122.       break;
  1123.     case 'S':
  1124.       col = 0;
  1125.       break;
  1126.     case 'D':
  1127.       col = coleol (row);
  1128.       break;
  1129.     case 'I':
  1130.       --col;
  1131.       col -= col % ED_TABW;
  1132.       break;
  1133.     case 'N':
  1134.       split_line ();
  1135.       show_all_lines (row);
  1136.       break;
  1137.     case 'Y':
  1138.       clear_endl ();
  1139.       show_line (row, col);
  1140.       break;
  1141.     case 'L':
  1142.       show_all ();
  1143.       break;
  1144.     case 'R':
  1145.       changescr (0);
  1146.       show_screen ();
  1147.       break;
  1148.     case 'C':
  1149.       changescr (BLOCK_FILE->size - 1);
  1150.       show_screen ();
  1151.       break;
  1152.     case 'M':
  1153.       changescr (mark.scr);
  1154.       row = mark.row;
  1155.       col = mark.col;
  1156.       show_screen ();
  1157.       break;
  1158.     case 'F':
  1159.       if (!search_string (1))
  1160.     c_bell ();
  1161.       was_replacing = 0;
  1162.       show_options ();
  1163.       break;
  1164.     case 'A':
  1165.       if (!replace_string (1))
  1166.     c_bell ();
  1167.       was_replacing = 1;
  1168.       show_options ();
  1169.       break;
  1170.     }
  1171. }
  1172.  
  1173. static int
  1174. do_key (char c)
  1175. /* interpretiert Zeichen erster Stufe */
  1176. {
  1177.   switch (c)
  1178.     {
  1179.     case '\033':        /* map Esc to ^Q, on Linux: Alt-F == ^Q-F */
  1180.     case 'Q' - '@':
  1181.       do_ctlQ ();
  1182.       break;
  1183.     case 'K' - '@':
  1184.       do_ctlK ();
  1185.       break;
  1186.     case 'O' - '@':
  1187.       do_ctlO ();
  1188.       break;
  1189.     case 'P' - '@':
  1190.       c = c_getkey ();
  1191.     default:
  1192.       if (overtype)
  1193.     {
  1194.       buf[row][col] = c;
  1195.       c_putc (c);
  1196.     }
  1197.       else
  1198.     {
  1199.       insertc (c);
  1200.       show_line (row, col);
  1201.     }
  1202.     case 'D' - '@':
  1203.       if (++col >= 64)
  1204.     {
  1205.       col -= 64;
  1206.     case 'X' - '@':
  1207.       if (row < 15)
  1208.         row++;
  1209.     }
  1210.       break;
  1211.     case 'S' - '@':
  1212.       if (--col < 0)
  1213.     {
  1214.       col += 64;
  1215.     case 'E' - '@':
  1216.       if (row > 0)
  1217.         row--;
  1218.     }
  1219.       break;
  1220.     case '\x7F':
  1221.     case 'H' - '@':
  1222.       if (col == 0)
  1223.     break;
  1224.       col--;
  1225.     case 'G' - '@':
  1226.       deletec ();
  1227.       show_line (row, col);
  1228.       break;
  1229.     case 'I' - '@':
  1230.       col += ED_TABW - col % ED_TABW;
  1231.       break;
  1232.     case 'W' - '@':
  1233.       insertc (' ');
  1234.       break;
  1235.     case 'A' - '@':
  1236.       back_word ();
  1237.       break;
  1238.     case 'F' - '@':
  1239.       fwd_word ();
  1240.       break;
  1241.     case 'T' - '@':
  1242.       deletew ();
  1243.       show_line (row, col);
  1244.       break;
  1245.     case 'M' - '@':
  1246.       col = 0;
  1247.       if (row < 15)
  1248.     row++;
  1249.       break;
  1250.     case 'N' - '@':
  1251.       insertl (row);
  1252.       show_all_lines (row);
  1253.       break;
  1254.     case 'Y' - '@':
  1255.       deletel (row);
  1256.       show_all_lines (row);
  1257.       break;
  1258.     case 'Z' - '@':
  1259.       memset (buf, ' ', sizeof (blck));
  1260.       show_screen ();
  1261.       break;
  1262.     case 'V' - '@':
  1263.       overtype ^= 1;
  1264.       show_options ();
  1265.       break;
  1266.     case 'L' - '@':
  1267.       if (was_replacing
  1268.       ? replace_string (0)
  1269.       : search_string (0))
  1270.     c_bell ();
  1271.       break;
  1272.     case 'R' - '@':
  1273.       if (SCR <= 0)
  1274.     {
  1275.       c_bell ();
  1276.       break;
  1277.     }
  1278.       changescr (SCR - 1);
  1279.       show_screen ();
  1280.       break;
  1281.     case 'C' - '@':
  1282.       if (SCR == BLOCK_FILE->size && !scr_changed ())
  1283.     {
  1284.       c_bell ();
  1285.       break;
  1286.     }
  1287.       changescr (SCR + 1);
  1288.       show_screen ();
  1289.       break;
  1290.     case 'U' - '@':
  1291.       writebuf ();
  1292.       truncate_file ();
  1293.       show_bottom_help (0, NULL);
  1294.       return 1;
  1295.     }
  1296.   return 0;
  1297. }
  1298.  
  1299. static void
  1300. free_bufs (void)
  1301. {
  1302.   if (buf)
  1303.     free (buf);
  1304.   if (linestk)
  1305.     free (linestk);
  1306.   if (blkstk)
  1307.     free (blkstk);
  1308. }
  1309.  
  1310. static int
  1311. alloc_bufs (int ls, int bs)
  1312. {
  1313.   buf = (line *) malloc (sizeof (blck));
  1314.   linestk = (line *) malloc (sizeof *linestk * ls);
  1315.   blkstk = (blck *) malloc (sizeof *blkstk * bs);
  1316.   if (!buf || !linestk || !blkstk)
  1317.     {
  1318.       free_bufs ();
  1319.       return 0;
  1320.     }
  1321.   linesp = linetop = linestk + ls;
  1322.   blksp = blktop = blkstk + bs;
  1323.   return 1;
  1324. }
  1325.  
  1326.  
  1327. /*
  1328.  * register additional actions for certain events:
  1329.  */
  1330.  
  1331. static void (*saved_on_stop) (void);
  1332. static void (*saved_on_continue) (void);
  1333. static void (*saved_on_winchg) (void);
  1334. jmp_buf after_stop;
  1335.  
  1336. static void
  1337. ed_on_stop (void)
  1338. {
  1339.   show_bottom_help (0, NULL);
  1340.   saved_on_stop ();
  1341. }
  1342.  
  1343. static void
  1344. ed_on_continue (void)
  1345. {
  1346.   saved_on_continue ();
  1347.   tty_interrupt_key (0);
  1348.   longjmp (after_stop, 1);
  1349. }
  1350.  
  1351. static void
  1352. ed_on_winchg (void)
  1353. {
  1354.   saved_on_winchg ();
  1355.   show_all ();
  1356. }
  1357.  
  1358. void
  1359. edit (int n, int r, int c)
  1360. {
  1361.   char *logn;
  1362.   volatile char intkey = tty_interrupt_key (0);
  1363.  
  1364.   logn = getenv ("LOGNAME");
  1365.   strncpy (log_name, logn ? logn : LOGNAME, sizeof log_name);
  1366.   switch (BLOCK_FILE->mode)
  1367.     {
  1368.     case FMODE_RO:
  1369.     case FMODE_ROB:
  1370.       readonly = 1;
  1371.       break;
  1372.     default:
  1373.       readonly = 0;
  1374.       break;
  1375.     }
  1376.   if (!alloc_bufs (32, 10))
  1377.     tHrow (THROW_OUT_OF_MEMORY);
  1378.   readbuf (n);
  1379.   row = r;
  1380.   col = c;
  1381.  
  1382.   saved_on_stop = on_stop;
  1383.   saved_on_continue = on_continue;
  1384.   saved_on_winchg = on_winchg;
  1385.   on_stop = ed_on_stop;
  1386.   on_continue = ed_on_continue;
  1387.   on_winchg = ed_on_winchg;
  1388.   setjmp (after_stop);
  1389.  
  1390.   displayed_help = NULL;
  1391.   show_all ();
  1392.   for (;;)
  1393.     {
  1394.       int key;
  1395.  
  1396.       setcursor (row, col);
  1397.       key = getwskey ();
  1398.       if (caps)
  1399.     key = change_case (key);
  1400.       if (do_key (key))
  1401.     break;
  1402.       show_status ();
  1403.     }
  1404.   free_bufs ();
  1405.   tty_interrupt_key (intkey);
  1406.  
  1407.   on_stop = saved_on_stop;
  1408.   on_continue = saved_on_continue;
  1409.   on_winchg = saved_on_winchg;
  1410. }
  1411.