home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / eel / ep_remap.zip / KEY-RE.MAP
Internet Message Format  |  1988-09-17  |  177KB

  1. Date: 13 Sep 1988 2311-EDT
  2. From: LISKOV@XX.LCS.MIT.EDU
  3. Subject: key re-mapping
  4. To: info-ibmpc@walker-emh.arpa
  5.  
  6. to:infoibmpc
  7. subject: remapping keys
  8.  
  9. Using NANSI.SYS or ANSI.SYS is the poor man's approach to key remapping.
  10. It is done by using ansi escape sequences such as the following that I
  11. use in my autoexec.bat to remap the function keys:
  12.  
  13. echo 9;"swap"13p0;"cls"13p2;"ls -au";13p
  14. echo 3;"lf";13p4;"copy ";p
  15. echo 5;"sdl d:/w";13p7;"sdl a:/w";13p8;"sdl c:/w";13p
  16. echo 6;"sdl e:/w";13p
  17.  
  18. The 13p appends a carriage return to the remapped sequence. The  character 
  19. is the escape character.  If you cannot input an escape character in your 
  20. editor the prompt command can be used, for example:
  21.  
  22. echo on
  23. prompt $e[0;59;"swap";13p
  24. prompt $e[0;60;"cls";13p
  25. prompt $e[0;61;"ls -au";13p
  26. prompt $e[0;63;"lf ";13p
  27. prompt $e[0;64;"copy "p
  28. prompt $e[0;65;"sdl d:/w";13p
  29. prompt $e[0;110;"sd d:/e";13p
  30. prompt $e[0;66;"sdl c:/w";13p
  31. prompt $e[0;111;"sd c:/e";13p
  32. prompt $e[0;67;"sdl a:/w";13p
  33. prompt $e[0;112;"sd a:/e";13p
  34. prompt $e[0;68;"dir /w ";13p
  35. prompt $d $t$h$h$h $p$g
  36.  
  37. I do not know if one can map meta keys using this approach, but it can
  38. be done in Epsilon.  In Epsilon one can define a key binding and then
  39. make it permanent by saving the state, epsilon.sta.  Or one can define
  40. eel code for epsilon, compile it, and then load it in as needed or
  41. load it in and make it permanent by saving the state with the eel
  42. code loaded.
  43.  
  44. I am enclosing examples of eel code, most of which came from the old
  45. info-ibmpc librady at c.isi.edu.  These are all appended to this
  46. note.  To use an *.e file, use eel to compile it to an *.b file, then
  47. within epsilon, load it by typing the f-3 key and following the prompt.
  48. Type write-state to make those commands a permanent part of your key
  49. definitions.  Of course, the eel code is for use only by legitimate
  50. epsilon licensees.
  51.  
  52. The nate.e file contains some the most useful generic features of the
  53. .e files that appear to work well and I use these extensions in my
  54. .sta file.  Note that the nate.e contains some initial loading
  55. defaults and key bindings... see end of file.  Also the epsilon.sta
  56. contains my normal alternate key bindings.  View the *.e files for
  57. specific documentation.  
  58.  
  59. To  right  justify  a paragraph type ctrl-u, esc-q and then wait.  It
  60. works  a  little  slowly  and  requires  that  the  paragraph  not be
  61. indented.  This is an example of the result.
  62.  
  63. Narrow.e works as advertized, but is not included in nate.e.
  64.  
  65. The for-mode and the pas-mode in FOR_mode and PAS_mode appear very
  66. useful in that they help with language syntax and insert all keywords
  67. automatically.  But they will take some getting used to.  I would
  68. suggest you load them when needed.  I have modified them so that the
  69. appropriate *.b files must be in the local directory when loaded.
  70. You can change the appropriate #define statements to any specific
  71. directory you desire to avoid this inconvenience.  One might still
  72. want to experiment with for_load (etc) or fortran.e for fortran
  73. specific applications and pas_load (etc) for pascal applications.
  74.  
  75. Krypt works but is very slow.
  76.  
  77. Most of kmode appears to work and some appears very useful.
  78.  
  79. Happy computing
  80.  
  81.     Nate Liskov % liskov.xx.mit.edu
  82.  
  83.  
  84. ******************************************************************
  85. nate.e follows:
  86. ******************************************************************
  87. /************************************************************************
  88. This is a compliation of .eel commands from various .e sources on
  89. info-ibmpc at c.isi.edu on the arpa net.  These are ones that I think
  90. will be useful and that appear to work as advertised.  I have taken
  91. liberty to modify key-bindings, etc. to my taste.
  92.  
  93. This material may be used and distributed freely, provided that it is not
  94. used as part of a product to be sold for profit.
  95.  
  96. The ideas for most of the commands implemented here come primarily
  97. from TOPS-20 EMACS, by Richard M. Stallman and others.
  98. ************************************************************************/
  99.  
  100. /************************************************************************
  101. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  102. *                                    *
  103. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  104. *                                    *
  105. * Limited permission is hereby granted to reproduce and modify this    *
  106. * copyrighted material provided that the resulting code is used only in    *
  107. * conjunction with Lugaru products and that this notice is retained in    *
  108. * any such reproduction or modification.                *
  109. ************************************************************************/
  110.  
  111. /*
  112. This file contains the following commands:
  113.  
  114. ****************************************************************
  115. Written by Nate Liskov:
  116.  
  117. insert_file - bound to C-X C-I   - From Epsilon Manual EEL Example
  118.  
  119. ****************************************************************
  120. Written by Bob Knight copyright (C) 1986:
  121.  
  122. lowercase_region - lowercases the current region, bound to C-X C-L
  123. uppercase_region - uppercases the current region, bound to C-X C-U
  124. revert_file - restore the current buffer from the associated disk file, bound
  125.              to C-X C-R
  126. connect_to_directory - connect to a named directory
  127. count_lines_region - count the number of lines in the current region, bound to
  128.             M-=
  129. ****************************************************************
  130. Modifications and extensions by Bruce K. Hillyer:
  131.      
  132. Fill-indented (<esc><tab>) fills the region, making the indentation equal to
  133. that of the first line.  This is useful, for instance, when editing a
  134. quotation that is indented from the left margin.  Mark fist line and then
  135. go to end of paragraph and type esc followed by tab
  136.  
  137. Display-matching-parens is a command to toggle the behavior of the closing
  138. delimiters  )  ]  }  to control whether Epsilon automatically shows the
  139. matching open delimiter.
  140.  
  141. split_and_find -bound to C-X S , splits screen and prompts for find_file
  142.  
  143. Insert-time inserts the current date and time into the buffer at point.
  144.  
  145. Show-time (C-X t) shows the current date and time in the echo area.
  146.  
  147. The next few commands are for scrolling when using two windows.
  148.    Next-page-lower (C-PgDn) is like next-page (C-V), but it controls
  149.        the window below the current one.
  150.    Previous-page-lower (C-PgUp) is like previous-page (A-V), but for 
  151.        the window below the current one.
  152.    Next-page-both (C-keypad key 5) shows the next page in both 
  153.        the current window and the one below.
  154.  
  155. Goto-beginning (A-<) and goto-end (A->) leave a mark behind.
  156.  
  157. Show-point (C-X =) also shows the decimal and octal values of the character
  158. at point. 
  159.  
  160. Next-page (C-V) and Previous-page (A-V) leave just one line of overlap.
  161.  
  162. ********************************************************************
  163. Copyright (C) 1985 George D. Hadden on right justify feature:
  164.  
  165. Right-justify paragraph: Ctrl-u ,ESC, Q    
  166.  
  167. Right-justify region: Ctrl-u, fill_region 
  168.  
  169. ***************************************************************
  170.  
  171. */
  172.  
  173. #include "eel.h"
  174.  
  175. /* lowercase the region */
  176. command lowercase_region() on cx_tab[CTRL('l')]
  177. {
  178.     do_region_case(1);
  179. }
  180.  
  181. /* capitalize the region */
  182. command uppercase_region() on cx_tab[CTRL('u')]
  183. {
  184.     do_region_case(0);
  185. }
  186.  
  187. /* Routine for region case converts */
  188. do_region_case(do_lower)
  189. {
  190.     int c, from = point, to = mark, temp;
  191.     char resp[80];
  192.  
  193.     if (from > to)
  194.         temp = from, from = to, to = temp;
  195.  
  196.     if ((to-from)>250)
  197.         get_string(resp, "Do you really want to case convert such a large region? [y]");
  198.     else *resp = 'Y';
  199.  
  200.     if (toupper(*resp) != 'N') {
  201.         for (; from <= to; from++) {
  202.             check_abort();
  203.             c = character(from);
  204.             replace(from, do_lower ? tolower(c) : toupper(c));
  205.         }
  206.     }
  207. }
  208.  
  209. /* Revert file - restore the current buffer from its associated disk file */
  210. command revert_file() on cx_tab[CTRL('R')]
  211. {
  212.     char resp[80];
  213.     int old_point;
  214.     
  215.     if(!strcmp(bufname,"process"))
  216.         say("Can't revert process");
  217.     else {
  218.         get_string(resp, "Restore file from disk? [n]");
  219.  
  220.         if (toupper(*resp) == 'Y') {
  221.             old_point = point;
  222.             read_file(filename);
  223.             point = old_point;
  224.         }
  225.     }
  226. }
  227.  
  228. /* connect_to_directory */
  229. command connect_to_directory()
  230. {
  231.     char dir[80];
  232.     
  233.     get_string(dir,"Connect to directory [\\]:  ");
  234.     if (!*dir)
  235.         strcpy(dir,"\\");
  236.     if (chdir(dir))
  237.         say("Unable to connect to %s",dir);
  238.     else {
  239.         if (another) {
  240.             to_buffer("process");
  241.             point = size();
  242.             insert('\n');
  243.             to_buffer(previous_buffer);
  244.         }
  245.     }
  246. }
  247.  
  248. /* count_lines_region */
  249. command count_lines_region() on reg_tab[ALT('=')]
  250. {
  251.     int curpoint = point, nlines = 1, temp;
  252.     
  253.     if (point > mark)
  254.         temp = point, point = mark, mark = temp;
  255.     for (;point <= mark;) {
  256.         check_abort();
  257.         if (!nl_forward())
  258.             break;
  259.         if (point <= mark)
  260.             nlines++;
  261.     }
  262.     say("%d",nlines);
  263.     point = curpoint;
  264. }
  265.  
  266.  
  267.  
  268. /************************************************
  269.  *                        *
  270.  *    new functions by Bruce Hillyer        *
  271.  *                        *
  272.  ************************************************/
  273.  
  274.  
  275. /* fill region making indentation equal to that of the first line
  276.  *
  277.  * The use of this routine is as follows.  If you are writing a paragraph
  278.  * that is indented, as in a quotation, put a mark at the beginning of the
  279.  * first line, go past the last line, and press <escape> followed by <tab>.
  280.  * The entire paragraph will be filled, but all lines will be indented to
  281.  * match the first line.
  282.  */
  283. command fill_indented() on reg_tab[ALT(CTRL('I'))]
  284. {
  285.     fill_region_indent(1);
  286. }
  287.  
  288.  
  289. /* automatically display matching delimiters (toggle)
  290.  */
  291.  
  292. command display_matching_parens()
  293. {
  294.  
  295.     int display_matching_mode =
  296.        (has_arg ? (iter != 0)
  297.             : !(mode_keys[')'] == (short) show_matching_delimiter
  298.             && mode_keys[']'] == (short) show_matching_delimiter
  299.             && mode_keys['}'] == (short) show_matching_delimiter
  300.                )
  301.        );
  302.     if (display_matching_mode) {
  303.         say("Display matching )]}");
  304.         mode_keys[')'] =
  305.           mode_keys[']'] =
  306.             mode_keys['}'] = (short) show_matching_delimiter;
  307.     }
  308.     else {
  309.         say("No display matching )]}");
  310.         mode_keys[')'] =
  311.           mode_keys[']'] =
  312.             mode_keys['}'] = 0;
  313.     }
  314.     iter = 1;
  315. }
  316.  
  317.  
  318.  
  319. /* Modifications and extensions to the Epsilon editor.  Bruce K. Hillyer.
  320.  * Portions of this code are covered by the following notice:
  321.  */
  322.  
  323. /************************************************************************
  324. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  325. *                                    *
  326. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  327. *                                    *
  328. * Limited permission is hereby granted to reproduce and modify this    *
  329. * copyrighted material provided that the resulting code is used only in    *
  330. * conjunction with Lugaru products and that this notice is retained in    *
  331. * any such reproduction or modification.                *
  332. ************************************************************************/
  333.  
  334.  
  335. /* split this window and find a file in the one below this
  336.  */
  337. command split_and_find() on cx_tab['s'], cx_tab['S']
  338. {
  339.     window_split();
  340.     find_file();
  341. }
  342.  
  343.  
  344. /* insert the current date and time in the buffer
  345.  */
  346. command insert_time()
  347. {
  348.     struct time_info b;
  349.  
  350.     time_and_day(&b);
  351.     mark = point;
  352.     bprintf("%d-%02d-%d  %d:%02d:%02d.%02d", 
  353.         b.month, b.day, b.year, b.hour, b.minute, b.second, b.hundredth);
  354. }
  355.  
  356.  
  357. /* insert the current date and time in the buffer
  358.  */
  359. command insert_time()
  360. {
  361.     struct time_info b;
  362.  
  363.     time_and_day(&b);
  364.     mark = point;
  365.     bprintf("%d-%02d-%d  %d:%02d:%02d.%02d", 
  366.         b.month, b.day, b.year, b.hour, b.minute, b.second, b.hundredth);
  367. }
  368.  
  369.  
  370. /* show the current date and time in the echo area
  371.  */
  372. command show_time() on cx_tab['t']
  373. {
  374.     struct time_info b;
  375.  
  376.     time_and_day(&b);
  377.     say("%d-%02d-%d  %d:%02d:%02d.%02d", 
  378.     b.month, b.day, b.year, b.hour, b.minute, b.second, b.hundredth);
  379. }
  380.  
  381.  
  382. /* the next few commands are for scrolling when using two windows.  C-PgUp
  383.  * is like A-V, but for the window below the current one.  C-PgDn is like
  384.  * C-V, but for the window below.  C-(keypad key 5) scrolls both the current
  385.  * window and the one below.
  386.  */
  387.  
  388. /* show the previous page in the window below this one
  389.  */
  390. command previous_page_lower() on reg_tab[NUMCTRL(NUMDIGIT(9))]
  391. {
  392.     window_number++;
  393.     previous_page();
  394.     window_number--;
  395. }
  396.  
  397.  
  398. /* show the next page in the window below this one
  399.  */
  400. command next_page_lower() on reg_tab[NUMCTRL(NUMDIGIT(3))]
  401. {
  402.     window_number++;
  403.     next_page();
  404.     window_number--;
  405. }
  406.  
  407.  
  408. /* show the next page both in this window and the one below this
  409.  */
  410. command next_page_both() on reg_tab[NUMCTRL(NUMDIGIT(5))]
  411. {
  412.     window_number++;
  413.     next_page();
  414.     window_number--;
  415.     next_page();
  416. }
  417.  
  418.  
  419. /************************************************
  420.  *                        *
  421.  *    local modifications of functions    *
  422.  *                        *
  423.  ************************************************/
  424.  
  425. command show_point() on cx_tab['=']
  426. {
  427. /***/    say("Column=%d, point=%d, size=%d, chr=0x%x (%d)",
  428. /***/        current_column(), point, size(), curchar(), curchar());
  429. }
  430.  
  431.  
  432. /* prog.e */
  433. show_line()        /* display point for a moment, then restore */
  434. {
  435.   /* delay a bit longer when showing a matching delimiter.
  436.    */
  437.     int oldstart = window_start;
  438.     int time;
  439.  
  440.     maybe_refresh();
  441. /***/    time = (window_start == oldstart) ? 8 : 25;
  442.     if (has_arg && iter > 0)
  443.         time = iter;
  444.     pause(time);
  445.     window_start = oldstart;
  446.     build_first = 1;
  447. }
  448.  
  449.  
  450. /* window.e */
  451. int move_by()
  452. {
  453.   /* leave just one line of overlap on C-V
  454.    */
  455. /***/    int n = window_size - 1;
  456. /***/    if (n < 1)
  457. /***/        n = 1;
  458.     return n;
  459. }
  460.  
  461. fill_region_indent(indented)
  462.     int indented;
  463. {
  464.     int start, *end = alloc_spot();
  465.     int indentation;
  466.  
  467.     if (point > (*end = mark))
  468.         *end = point, point = mark;
  469.  
  470. /***/    to_begin_line();
  471. /***/    re_search(1, "[ \t\n]*");    /* determine indentation */
  472. /***/    indentation = (indented ? current_column() : 0);
  473.     while (point < *end) {
  474.         start = point;
  475.         if (search(1, "\n\n"))
  476.             point--;
  477.         if (point > *end)
  478.             point = *end;
  479. /***/        if (character(point-1) == '\n')
  480. /***/                point--;
  481. /***/        region_fill_ind(start, point, indentation);
  482.         re_search(1, "[ \t\n]*");    /* skip paragraph indent */
  483.     }
  484.     free_spot(end);
  485. }
  486.  
  487.  
  488.  
  489. command fill_paragraph() on reg_tab[ALT('q')], reg_tab[CTRL(']')]
  490. {
  491.     int end, start=point;
  492.  
  493.     iter = 0;
  494.     forward_paragraph();
  495.     end = point - 1;
  496.     backward_paragraph(); 
  497.     re_search(1, "[ \t\n]*");    /* leave leading whitespace intact */
  498. /***/   region_fill_ind(point, end, 0);
  499.     if (start > size()) start = size();
  500.     point = start;
  501. }
  502.  
  503.  
  504.  
  505. region_fill_ind(a, b, lmargin)
  506.     int a, b, lmargin;
  507. {
  508.   /* leave two spaces after ':' when filling, and indent each line by the
  509.    * amount specified as lmargin
  510.    */
  511.     int start, *end = alloc_spot();
  512.     char line[160];
  513.     int startcol;
  514.  
  515.     point = a, *end = b;
  516.     if (a > b)
  517.         point = b, *end = a;
  518.     startcol = current_column();
  519.     while (point < *end) {
  520.         start = point;
  521. /***/        if (line_fill(line, *end, margin_right, startcol, ".?:!",
  522.                     ")]'\""))
  523.             break;
  524.         while (point < *end && isspace(curchar()))
  525.             point++;
  526.         delete(start, point);
  527. /***/        to_column(startcol);
  528.         stuff(line);
  529. /***/        startcol = lmargin;
  530.     }
  531.     free_spot(end);
  532.     build_first = 1;        /* redisplay hint */
  533. }
  534.  
  535.  
  536. command goto_beginning() on reg_tab[ALT('<')], reg_tab[NUMCTRL(NUMDIGIT(7))]
  537. {
  538. /***/    mark = point;
  539.     point = 0;
  540. }
  541.  
  542. command goto_end() on reg_tab[ALT('>')], reg_tab[NUMCTRL(NUMDIGIT(1))]
  543. {
  544. /***/    mark = point;
  545.     point = size();
  546. }
  547.  
  548. /* the following function has been modified by George D Hadden such 
  549.    that when given a numeric argument, it will right justify as well as 
  550.    fill the region */
  551.  
  552. command fill_region()
  553. {
  554.           int start, *end = alloc_spot();
  555.  
  556.           if (point > (*end = mark))
  557.                     *end = point, point = mark;
  558.           while (point < *end) {
  559.                     start = point;
  560.                     if (search(1, "\n\n"))
  561.                               point--;
  562.                     if (point > *end)
  563.                               point = *end;
  564.                     region_fill(start, point);
  565.                     re_search(1, "[ \t\n]*");     /* skip paragraph indent */
  566.           }
  567.           free_spot(end);
  568. }
  569.  
  570. command fill_paragraph() on reg_tab[ALT('q')], reg_tab[CTRL(']')]
  571. {
  572.           int end, start=point;
  573.  
  574.           iter = 0;
  575.           forward_paragraph();
  576.           end = point - 1;
  577.           backward_paragraph();
  578.           re_search(1, "[ \t\n]*");     /* leave leading whitespace intact */
  579.           region_fill(point, end);
  580.           if (start > size()) start = size();
  581.           point = start;
  582. }
  583.  
  584. region_fill(a, b)
  585.           int a, b;
  586. {
  587.           int start, *end = alloc_spot();
  588.           char line[160], startcol;
  589.  
  590.           point = a, *end = b;
  591.           if (a > b)
  592.                     point = b, *end = a;
  593.           startcol = current_column();
  594.           while (point < *end) {
  595.                     start = point;
  596.                     if (line_fill(line, *end, margin_right, startcol, ".?!",
  597.                                                             ")]'\""))
  598.                               break;
  599.  
  600.                     while (point < *end && isspace(curchar()))
  601.                               point++;
  602.                     delete(start, point);
  603.                     /* geo's additions */
  604.                     if (has_arg && /* numeric arg was provided */
  605.                         index(line, '\n')) /* if end reached, no linefeed (?) */
  606.                               justify(line, margin_right);
  607.                     /* eventually, we'll do a left margin, too */
  608.                     stuff(line);        /* change these two lines to do left */
  609.                     startcol = 0;       /* margin.  also add set-left-margin  */
  610.           }
  611.           free_spot(end);
  612.           build_first = 1;              /* redisplay hint */
  613. }
  614.  
  615. justify (line, margin)
  616. char *line, margin;
  617.  
  618. /* we can assume that line[0] is non-space */
  619.  
  620. {
  621.           char *line_ptr;
  622.  
  623.           line_ptr = line;
  624.           while (strlen(line) < margin) {
  625.                     /* returns immediately if longer than margin */
  626.                     while (!isspace(*line_ptr))
  627.                               line_ptr++;
  628.                     while (isspace(*line_ptr) && *line_ptr != '\n')
  629.                               line_ptr++;
  630.                     if (*line_ptr == '\n')
  631.                               line_ptr = line;
  632.                     else
  633.                               one_to_right(line_ptr++);
  634.           }
  635. }
  636.  
  637.  
  638. one_to_right(ptr)
  639. char *ptr;
  640.  
  641. /* move characters in string one character to the right replacing *ptr
  642.    with a space */
  643.  
  644. {
  645.           char *end_ptr;
  646.  
  647.           end_ptr = ptr;
  648.           while (*end_ptr)
  649.                     end_ptr++;
  650.           while (end_ptr >= ptr)        {
  651.                     end_ptr[1] = *end_ptr;
  652.                     end_ptr--;
  653.           }
  654.           *ptr = ' ';
  655. }
  656.  
  657.  
  658. command insert_file() on cx_tab[CTRL('I')]
  659. {
  660.     char inserted_file[FNAMELEN];
  661.     char *original_buffer = bufname;
  662.     
  663.     get_file(inserted_file, "Insert file: ");
  664.     zap("tempbuf");        /* make an empty buffer */
  665.     bufname = "tempbuf";    /* use that buffer */
  666.     filename = inserted_file;
  667.     if (file_read(inserted_file,1) > 0)
  668.         error("Read error: %s", inserted_file);
  669.             /* copy the characters */
  670.     xfer(original_buffer, 0 , size());
  671.             /* move back to buffer */
  672.     bufname = original_buffer;
  673.     delete_buffer("tempbuf");
  674. }
  675.  
  676.  
  677. /* declare routines that are defined elsewhere */
  678. command goto_line();
  679. command compare_windows();
  680.  
  681. when_loading()
  682. {
  683.     /* set desired defaults */
  684.     use_default = 1;
  685.     margin_right = 70;
  686.     num_kbufs = 6;
  687.     use_default = 0;
  688.  
  689.     /* supply desired bindings */
  690.     cx_tab['g']        = (short) goto_line;
  691.     reg_tab[ALT(CTRL('C'))] = (short) compare_windows;
  692.  
  693.     /* for IBM-AT, swap the <esc> and <backquote> keys */
  694. /*    keytran[NUMCTRL(GREYESC)] = keytran[GREYESC] = '`';
  695.     keytran[NUMALT(GREYESC)] = ALT('`');
  696.     keytran['`'] = ESC;    */
  697. }
  698. ******************************************************************
  699. narrow.e follows
  700. ******************************************************************
  701.  
  702. /********** Documentation to be inserted in file "edoc" ***********
  703.  
  704. narrow-bounds-to-region         Narrow portion of buffer to edit to region.
  705.         Make region the only portion of the buffer that your commands
  706.         affect.  Return to editting of the entire buffer with widen-bounds.
  707.  
  708. widen-bounds    Widen bounds to entire buffer.
  709.         Use this command when you have finished editting a portion of the
  710.         buffer selected previously with narrow-bounds-to-region.
  711.  
  712. ***********             End of documentation            **********/
  713.  
  714. /*-----  Gary R. Smith  (smith#gary@b.mfenet@nmfecc.arpa) */
  715.  
  716. /****************** Beginning of file "narrow.e" ******************/
  717.  
  718. /* EEL commands to customize Epsilon 3.05 written by Gary R. Smith,
  719.    Aug. 9, 1986. */
  720.  
  721. #include "eel.h"
  722.  
  723. buffer int narrow_mode = 0;     /* Are we in narrow mode? */
  724.  
  725. char *bef_reg;
  726. char *aft_reg;
  727. /*****************************************************************************
  728. *                                                                            *
  729. *     Save parts of buffer before and after region in temporary buffers,     *
  730. *     and leave only region in the current buffer.                           *
  731. *                                                                            *
  732. *****************************************************************************/
  733. command narrow_bounds_to_region() on cx_tab['n']
  734. {
  735.         int mod = modified;
  736.         int beg_reg = point;
  737.         int end_reg = mark;
  738.         
  739.         if (narrow_mode) error("Already in Narrow mode");
  740.         
  741.         if (point > mark) {     /* beginning and end of region */
  742.                 beg_reg = mark;
  743.                 end_reg = point;
  744.         }
  745.         
  746.         aft_reg = temp_buf();
  747.         xfer(aft_reg, end_reg, size()); /* save part after region */
  748.         delete(end_reg, size());
  749.  
  750.         bef_reg = temp_buf();
  751.         xfer(bef_reg, 0, beg_reg);      /* save part before region */
  752.         delete(0, beg_reg);
  753.  
  754.         modified = mod;
  755.         narrow_mode = 1;        /* now in Narrow mode */
  756.         make_mode();
  757. }
  758.  
  759. /*****************************************************************************
  760. *                                                                            *
  761. *     Restore parts of buffer saved by narrow_bounds_to_region.              *
  762. *     Keep point, mark, and window_start in same places.                     *
  763. *                                                                            *
  764. *****************************************************************************/
  765. command widen_bounds() on cx_tab['w']
  766. {
  767.         int mod = modified;
  768.         char *current_buffer;
  769.         int oldstart = window_start;    /* save start of window */
  770.         int oldpos = point;             /*   and point and mark */
  771.         int oldmark = mark;
  772.         int size_bef;
  773.  
  774.         if (!narrow_mode) error("Cannot widen when not in Narrow mode");
  775.         
  776.         point = 0;              /* insert at beginning of current buffer */
  777.         current_buffer = bufname;
  778.         bufname = bef_reg;      /*   from 'before-region' temp buf */
  779.         xfer(current_buffer, 0, size());
  780.         size_bef = size();
  781.         
  782.         bufname = current_buffer;
  783.         point = size();         /* insert at end of current buffer */
  784.         bufname = aft_reg;      /*   from 'after-region' temp buf */
  785.         xfer(current_buffer, 0, size());
  786.         bufname = current_buffer;
  787.         
  788.         mark = oldmark + size_bef;      /* restore point and mark */
  789.         point = oldpos + size_bef;
  790.         window_start = oldstart + size_bef;     /* same start of window */
  791.         
  792.         modified = mod;
  793.         narrow_mode = 0;        /* no longer in Narrow mode */
  794.         make_mode();
  795. }
  796.  
  797. /* make_mode() from disp.e is enhanced here to show Narrow mode */
  798.  
  799. make_mode()
  800. {
  801. strcpy(mode, major_mode);
  802. if (fill_mode)
  803.         strcat(mode, " Fill");
  804. if (over_mode)
  805.         strcat(mode, " Over");
  806. if (!strip_returns)
  807.         strcat(mode, " NoTrans");
  808. if (narrow_mode)
  809.         strcat(mode, " Narrow");
  810. }
  811.  
  812. /****************** End of file "narrow.e" ******************/
  813. ******************************************************************
  814. nuformat.e follows
  815. ******************************************************************
  816. /************************************************************************
  817. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  818. *                                                                                         *
  819. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.   *
  820. *                                                                                         *
  821. * Limited permission is hereby granted to reproduce and modify this   *
  822. * copyrighted material provided that the resulting code is used only in         *
  823. * conjunction with Lugaru products and that this notice is retained in          *
  824. * any such reproduction or modification.                                        *
  825. ************************************************************************/
  826.  
  827. /************************************************************************
  828. * Portions of this file                                                 *
  829. *    Copyright (C) 1985 George D. Hadden                                *
  830. * Permission is granted to reproduce and use this copyrighted material  *
  831. * for any purpose whatsoever.                                           *
  832. ************************************************************************/
  833.  
  834. #include "eel.h"
  835.  
  836. #define WORD_PAT    "[a-zA-Z0-9_]+"
  837.  
  838. /* position point after the next word */
  839. command forward_word() on reg_tab[ALT('f')], reg_tab[NUMCTRL(NUMDIGIT(6))]
  840. {
  841. if (iter < 0) {
  842.           iter = -iter;
  843.           backward_word();
  844. }
  845. while (iter-- > 0)
  846.           re_search(1, WORD_PAT);
  847. }
  848.  
  849. /* position point before the previous word */
  850. command backward_word() on reg_tab[ALT('b')], reg_tab[NUMCTRL(NUMDIGIT(4))]
  851. {
  852. if (iter < 0) {
  853.           iter = -iter;
  854.           forward_word();
  855. }
  856. while (iter-- > 0)
  857.           re_search(-1, WORD_PAT);
  858. }
  859.  
  860. #define tolow 0
  861. #define toup 1
  862. #define tocap 2
  863.  
  864. /* make the current word all lower case */
  865. command lowercase_word() on reg_tab[ALT('l')]
  866. {
  867. int start = point;
  868.  
  869. forward_word();
  870. mkcase(tolow, start, point);
  871. }
  872.  
  873. /* make the current word all lower case */
  874. command uppercase_word() on reg_tab[ALT('u')]
  875. {
  876. int start = point;
  877.  
  878. forward_word();
  879. mkcase(toup, start, point);
  880. }
  881.  
  882. /* capitalize the current word */
  883. command capitalize_word() on reg_tab[ALT('c')]
  884. {
  885. int start = point;
  886.  
  887. forward_word();
  888. mkcase(tocap, start, point);
  889. }
  890.  
  891.  
  892. /* fiddle with the case of the region */
  893. mkcase(cs, from, to)
  894. int cs;
  895. int from, to;
  896. {
  897. int first = 1, new, c, newfirst;
  898. int temp;
  899.  
  900. if (from > to)
  901.           temp = from, from = to, to = temp;
  902. for (; from < to; from++) {
  903.           c = character(from), new = -1, newfirst = 0;
  904.           if (c >= 'A' && c <= 'Z') {
  905.                     if (cs == tolow || cs == tocap && !first)
  906.                               new = c + 'a' - 'A';
  907.           } else if (c >= 'a' && c <= 'z') {
  908.                     if (cs == toup || cs == tocap && first)
  909.                               new = c + 'A' - 'a';
  910.           } else
  911.                     newfirst = 1;
  912.           first = newfirst;
  913.           if (new != -1)
  914.                     replace(from, new);
  915. }
  916. }
  917.  
  918.  
  919. /* transpose characters before and after point */
  920. command transpose_characters() on reg_tab[CTRL('T')]
  921. {
  922. int p = point;
  923. char c, d;
  924.  
  925. if (p == size() || curchar() == '\n')   /* switch last two at end of line */
  926.           p--;
  927. else if (p == 0 || character(point - 1) == '\n')
  928.           p++;
  929. c = character(p);                                 /* store away current */
  930. d = character(p - 1);
  931. if (p > 0 && p < size() && c != '\n' && d != '\n') {
  932.           replace(p, d);
  933.           replace(p - 1, c);
  934. }
  935. }
  936.  
  937. save_away(from, to)
  938. int from, to;
  939. {
  940. zap("temp_buffer");
  941. xfer("temp_buffer", from, to);
  942. delete(from, to);
  943. }
  944.  
  945. grab_back()
  946. {
  947. char *cur = bufname;
  948.  
  949. bufname = "temp_buffer";
  950. xfer(cur, 0, size());
  951. bufname = cur;
  952. }
  953.  
  954. command transpose_words() on reg_tab[ALT('t')]
  955. {
  956.           int first, second;
  957.  
  958.           create("temp_buffer");
  959.           re_search(1, WORD_PAT);
  960.           re_search(-1, WORD_PAT);
  961.           re_search(-1, WORD_PAT);
  962.           first = point;
  963.           re_search(1, WORD_PAT);
  964.           save_away(first, point);
  965.           re_search(1, WORD_PAT);
  966.           second = point;
  967.           grab_back();
  968.           point = second;
  969.           re_search(-1, WORD_PAT);
  970.           save_away(point, second);
  971.           point = first;
  972.           grab_back();
  973.           delete_buffer("temp_buffer");
  974.           iter = 0;
  975. }
  976.  
  977. command transpose_lines() on cx_tab[CTRL('T')]
  978. {
  979.           int first;
  980.  
  981.           create("temp_buffer");
  982.           nl_reverse();
  983.           to_begin_line();
  984.           first = point;
  985.           nl_forward();
  986.           save_away(first, point);
  987.           nl_forward();
  988.           grab_back();
  989.           nl_reverse();
  990.           to_begin_line();
  991.           delete_buffer("temp_buffer");
  992. }
  993.  
  994. command set_fill_column() on cx_tab['f']
  995. {
  996.           margin_right = (iter > 1) ? iter : (current_column() + 1);
  997.           iter = 1;
  998.           say("Fill column is %d", margin_right);
  999. }
  1000.  
  1001.  
  1002. command mark_paragraph() on reg_tab[ALT('h')]
  1003. {
  1004.           backward_paragraph();
  1005.           mark = point;
  1006.           forward_paragraph();
  1007. }
  1008.  
  1009. command forward_paragraph() on reg_tab[ALT(']')], reg_tab[NUMALT(NUMDIGIT(2))]
  1010. {
  1011.           to_begin_line();
  1012.           re_search(1, "([@.].*\n)*");
  1013.           re_search(1, "[^ \t\n@.]");
  1014.           if (re_search(1, "\n[ \t\n]")) {
  1015.                     point--;
  1016.                     re_search(-1, "^([@.].*\n)*");
  1017.           } else
  1018.                     point = size();
  1019. }
  1020.  
  1021. command backward_paragraph() on reg_tab[ALT('[')],
  1022.                                         reg_tab[NUMALT(NUMDIGIT(8))]
  1023. {
  1024.           if (character(point - 1) == '\n')
  1025.                     re_search(-1, "^([@.].*\n)*");
  1026.           re_search(-1, "[^ \t\n]");
  1027.           if (re_search(-1, "\n[ \t\n]"))
  1028.                     re_search(1, "\n*");
  1029.           re_search(1, "^([@.].*\n)*");
  1030. }
  1031.  
  1032.  
  1033. #define SENTEND     "([.?!][])'\"]*[ \t\n]*([ \t][ \t]|\n))|(\n[ \t\n.])"
  1034.  
  1035. command forward_sentence() on reg_tab[ALT('e')],
  1036.                                         reg_tab[NUMCTRL(NUMDIGIT(2))]
  1037. {
  1038.           if (iter < 0) {
  1039.                     iter = -iter;
  1040.                     backward_sentence();
  1041.           }
  1042.           while (iter-- > 0) {
  1043.                     re_search(1, "[^ \t\n]");     /* don't find same sentence */
  1044.                     if (re_search(1, SENTEND))    /* go to end of sentence */
  1045.                               re_search(-1, "[ \n\t]*(.|\n)");
  1046.           }
  1047. }
  1048.  
  1049. command backward_sentence() on reg_tab[ALT('a')],
  1050.                                         reg_tab[NUMCTRL(NUMDIGIT(8))]
  1051. {
  1052.           if (iter < 0) {
  1053.                     iter = -iter;
  1054.                     forward_sentence();
  1055.           }
  1056.           while (iter-- > 0) {
  1057.                     re_search(-1, "[^ \t\n]");    /* don't find same sentence */
  1058.                     if (re_search(-1, SENTEND))
  1059.                               re_search(1, "[ \n\t]+"); /* go to start of sent. */
  1060.           }
  1061. }
  1062.  
  1063. command center_line() on reg_tab[ALT('s')]        /* center current line */
  1064. {
  1065.           int linelen;                            /* length of line */
  1066.  
  1067.           to_begin_line();              /* first remove extra space */
  1068.           delete_horizontal_space();
  1069.           to_end_line();
  1070.           delete_horizontal_space();
  1071.           linelen = current_column();   /* column at end is length */
  1072.           to_begin_line();
  1073.           to_column((margin_right - linelen) / 2);          /* indent to here */
  1074. }
  1075.  
  1076. /* make space break line or not */
  1077. command auto_fill_mode()
  1078. {
  1079.           fill_mode = (has_arg? (iter != 0) : !fill_mode);
  1080.           make_mode();
  1081.           iter = 1;
  1082. }
  1083.  
  1084. /* determine where to break current line given right margin */
  1085. pick_break(col)
  1086. int col;
  1087. {
  1088.           int orig = point, start;
  1089.  
  1090.           to_begin_line();
  1091.           start = point;
  1092.           move_to_column(col);          /* find first space before col */
  1093.           if (!re_search(-1, "[ \t]") || point < start) {   /* if none */
  1094.                     point = orig;
  1095.                     return 0;
  1096.           }
  1097.           point++;
  1098.           return 1;
  1099. }
  1100.  
  1101. command maybe_break_line() on reg_tab[' '], reg_tab['\n']
  1102. {
  1103.           int h, both, origkey = key;
  1104.           int *spot;
  1105.  
  1106.           if (fill_mode) {
  1107.                     spot = alloc_spot();
  1108.                     h = current_column() + 1;
  1109.                     both = (h > margin_right && pick_break(margin_right));
  1110.                     if (h >= margin_right) {
  1111.                               delete_horizontal_space();
  1112.                               key = '\n';
  1113.                     }
  1114.                     if (both) {
  1115.                               normal_character();
  1116.                               key = origkey;
  1117.                               point = *spot;
  1118.                     }
  1119.                     free_spot(spot);
  1120.           }
  1121.           normal_character();
  1122. }
  1123.  
  1124. command fill_region()
  1125. {
  1126.           int start, *end = alloc_spot();
  1127.  
  1128.           if (point > (*end = mark))
  1129.                     *end = point, point = mark;
  1130.           while (point < *end) {
  1131.                     start = point;
  1132.                     if (search(1, "\n\n"))
  1133.                               point--;
  1134.                     if (point > *end)
  1135.                               point = *end;
  1136.                     region_fill(start, point);
  1137.                     re_search(1, "[ \t\n]*");     /* skip paragraph indent */
  1138.           }
  1139.           free_spot(end);
  1140. }
  1141.  
  1142. command fill_paragraph() on reg_tab[ALT('q')]
  1143. {
  1144.           int end, start=point;
  1145.  
  1146.           iter = 0;
  1147.           forward_paragraph();
  1148.           end = point - 1;
  1149.           backward_paragraph();
  1150.           re_search(1, "[ \t\n]*");     /* leave leading whitespace intact */
  1151.           region_fill(point, end);
  1152.           if (start > size()) start = size();
  1153.           point = start;
  1154. }
  1155.  
  1156. /* the following function has been modified such that when given a 
  1157.    numeric argument, it will right justify as well as fill the region */
  1158.  
  1159. region_fill(a, b)
  1160.           int a, b;
  1161. {
  1162.           int start, *end = alloc_spot();
  1163.           char line[160], startcol;
  1164.  
  1165.           point = a, *end = b;
  1166.           if (a > b)
  1167.                     point = b, *end = a;
  1168.           startcol = current_column();
  1169.           while (point < *end) {
  1170.                     start = point;
  1171.                     if (line_fill(line, *end, margin_right, startcol, ".?!",
  1172.                                                             ")]'\""))
  1173.                               break;
  1174.  
  1175.                     while (point < *end && isspace(curchar()))
  1176.                               point++;
  1177.                     delete(start, point);
  1178.                     /* geo's additions */
  1179.                     if (has_arg && /* numeric arg was provided */
  1180.                         index(line, '\n')) /* if end reached, no linefeed (?) */
  1181.                               justify(line, margin_right);
  1182.                     /* eventually, we'll do a left margin, too */
  1183.                     stuff(line);        /* change these two lines to do left */
  1184.                     startcol = 0;       /* margin.  also add set-left-margin  */
  1185.           }
  1186.           free_spot(end);
  1187.           build_first = 1;              /* redisplay hint */
  1188. }
  1189.  
  1190. justify (line, margin)
  1191. char *line, margin;
  1192.  
  1193. /* we can assume that line[0] is non-space */
  1194.  
  1195. {
  1196.           char *line_ptr;
  1197.  
  1198.           line_ptr = line;
  1199.           while (strlen(line) < margin) {
  1200.                     /* returns immediately if longer than margin */
  1201.                     while (!isspace(*line_ptr))
  1202.                               line_ptr++;
  1203.                     while (isspace(*line_ptr) && *line_ptr != '\n')
  1204.                               line_ptr++;
  1205.                     if (*line_ptr == '\n')
  1206.                               line_ptr = line;
  1207.                     else
  1208.                               one_to_right(line_ptr++);
  1209.           }
  1210. }
  1211.  
  1212.  
  1213. one_to_right(ptr)
  1214. char *ptr;
  1215.  
  1216. /* move characters in string one character to the right replacing *ptr
  1217.    with a space */
  1218.  
  1219. {
  1220.           char *end_ptr;
  1221.  
  1222.           end_ptr = ptr;
  1223.           while (*end_ptr)
  1224.                     end_ptr++;
  1225.           while (end_ptr >= ptr)        {
  1226.                     end_ptr[1] = *end_ptr;
  1227.                     end_ptr--;
  1228.           }
  1229.           *ptr = ' ';
  1230. }
  1231. ******************************************************************
  1232. local.e follows
  1233. ******************************************************************
  1234.  
  1235. /* Modifications and extensions to the Epsilon editor.  Bruce K. Hillyer.
  1236.  * Portions of this code are covered by the following notice:
  1237.  */
  1238.  
  1239. /************************************************************************
  1240. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  1241. *                                    *
  1242. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  1243. *                                    *
  1244. * Limited permission is hereby granted to reproduce and modify this    *
  1245. * copyrighted material provided that the resulting code is used only in    *
  1246. * conjunction with Lugaru products and that this notice is retained in    *
  1247. * any such reproduction or modification.                *
  1248. ************************************************************************/
  1249.  
  1250.  
  1251.  
  1252. #include "eel.h"
  1253.  
  1254.  
  1255. /************************************************
  1256.  *                        *
  1257.  *        new functions            *
  1258.  *                        *
  1259.  ************************************************/
  1260.  
  1261.  
  1262. /* fill region making indentation equal to that of the first line
  1263.  *
  1264.  * The use of this routine is as follows.  If you are writing a paragraph
  1265.  * that is indented, as in a quotation, put a mark at the beginning of the
  1266.  * first line, go past the last line, and press <escape> followed by <tab>.
  1267.  * The entire paragraph will be filled, but all lines will be indented to
  1268.  * match the first line.
  1269.  */
  1270. command fill_indented() on reg_tab[ALT(CTRL('I'))]
  1271. {
  1272.     fill_region_indent(1);
  1273. }
  1274.  
  1275.  
  1276.  
  1277. /* find a line before this one that is less indented, line up with it.
  1278.  *
  1279.  * The use of this routine is as follows.  After typing a line of, say,
  1280.  * Pascal, press C-M to start a new line indented under the previous
  1281.  * line (see command indent_next() below).  Then you can press A-M to
  1282.  * unindent one nesting level. 
  1283.  */
  1284.  
  1285. command indent_less() on reg_tab[ALT('m')] {
  1286.  
  1287.     int orig_column;    /* indentation of original line           */
  1288.     int prev_indent;    /* indentation of some previous line       */
  1289.     int orig;        /* point of original indentation       */
  1290.     int prev_try;    /* to guarantee the loop keeps progressing */
  1291.  
  1292.     to_indentation();
  1293.     orig = point;
  1294.     orig_column = current_column();
  1295.  
  1296.     /* scan backwards for a line that is indented less */
  1297.     do {
  1298.         prev_try = point;
  1299.     to_begin_line();
  1300.     re_search(-1, "[^ \t\n]");    /* find previous non-blank line */
  1301.     to_indentation();
  1302.     prev_indent = current_column();
  1303.     } while (point < prev_try && prev_indent >= orig_column);
  1304.  
  1305.     point = orig;
  1306.     to_column((prev_indent < orig_column) ? prev_indent : 0);
  1307. }
  1308.  
  1309.  
  1310. /*  Go to the next line and then indent under
  1311.  */
  1312. command indent_next() on reg_tab[CTRL('M')]
  1313. {
  1314.     insert('\n');
  1315.     indent_under();
  1316. }
  1317.  
  1318.  
  1319. /* automatically display matching delimiters (toggle)
  1320.  */
  1321.  
  1322. command display_matching_parens()
  1323. {
  1324.  
  1325.     int display_matching_mode =
  1326.        (has_arg ? (iter != 0)
  1327.             : !(mode_keys[')'] == (short) show_matching_delimiter
  1328.             && mode_keys[']'] == (short) show_matching_delimiter
  1329.             && mode_keys['}'] == (short) show_matching_delimiter
  1330.                )
  1331.        );
  1332.     if (display_matching_mode) {
  1333.         say("Display matching )]}");
  1334.         mode_keys[')'] =
  1335.           mode_keys[']'] =
  1336.             mode_keys['}'] = (short) show_matching_delimiter;
  1337.     }
  1338.     else {
  1339.         say("No display matching )]}");
  1340.         mode_keys[')'] =
  1341.           mode_keys[']'] =
  1342.             mode_keys['}'] = 0;
  1343.     }
  1344.     iter = 1;
  1345. }
  1346.  
  1347.  
  1348. /* remember the parameters to a query replace so it can be reissued
  1349.  *
  1350.  * After leaving a query replace, give C-X %  to start query replacing again,
  1351.  * with the same arguments.
  1352.  */
  1353. char query_str[80], query_with[80];
  1354. int did_query = 0;
  1355.  
  1356. command query_replace_again() on cx_tab['%']
  1357. {
  1358.     if (did_query)
  1359.         string_replace(query_str, query_with, 1, has_arg, 0);
  1360.     else
  1361.         say("No previous query-replace.");
  1362. }
  1363.  
  1364.  
  1365.  
  1366. /* insert the current date and time in the buffer
  1367.  */
  1368. command insert_time()
  1369. {
  1370.     struct time_info b;
  1371.  
  1372.     time_and_day(&b);
  1373.     mark = point;
  1374.     bprintf("%d-%02d-%d  %d:%02d:%02d.%02d", 
  1375.         b.month, b.day, b.year, b.hour, b.minute, b.second, b.hundredth);
  1376. }
  1377.  
  1378.  
  1379. /* show the current date and time in the echo area
  1380.  */
  1381. command show_time() on cx_tab['t']
  1382. {
  1383.     struct time_info b;
  1384.  
  1385.     time_and_day(&b);
  1386.     say("%d-%02d-%d  %d:%02d:%02d.%02d", 
  1387.     b.month, b.day, b.year, b.hour, b.minute, b.second, b.hundredth);
  1388. }
  1389.  
  1390.  
  1391. /* the next few commands are for scrolling when using two windows.  A-Z
  1392.  * is like A-V, but for the window below the current one.  C-Z is like
  1393.  * C-V, but for the window below.  C-A-Z scrolls both the current window
  1394.  * and the one below.
  1395.  */
  1396.  
  1397. /* show the previous page in the window below this one
  1398.  */
  1399. command previous_page_lower() on reg_tab[ALT('z')]
  1400. {
  1401.     window_number++;
  1402.     previous_page();
  1403.     window_number--;
  1404. }
  1405.  
  1406.  
  1407. /* show the next page in the window below this one
  1408.  */
  1409. command next_page_lower() on reg_tab[CTRL('Z')]
  1410. {
  1411.     window_number++;
  1412.     next_page();
  1413.     window_number--;
  1414. }
  1415.  
  1416.  
  1417. /* show the next page both in this window and the one below this
  1418.  */
  1419. command next_page_both() on reg_tab[ALT(CTRL('Z'))]
  1420. {
  1421.     window_number++;
  1422.     next_page();
  1423.     window_number--;
  1424.     next_page();
  1425. }
  1426.  
  1427.  
  1428. /* split this window and find a file in the one below this
  1429.  */
  1430. command split_and_find() on cx_tab['4']
  1431. {
  1432.     window_split();
  1433.     find_file();
  1434. }
  1435.  
  1436.  
  1437.  
  1438. /* allocate some K for process.  if there is an argument, reserve that
  1439.  * percent of the remaining memory for process.  if no argument, split memory
  1440.  * in the default way. 
  1441.  *
  1442.  * The point of this command is as follows.  I normally have the Epsilon
  1443.  * environment variable set as:  set epsilon=-m1, so that all of memory is
  1444.  * reserved for editing.  (I.e., so that Epsilon doesn't start swapping
  1445.  * sooner than absolutely necessary.)  If I want to see how much memory
  1446.  * Epsilon is using, I give C-U 0 F2 process-mem <cr>.  If I want to reserve
  1447.  * 200K for the process buffer, I give C-U 200 F2 process-mem <cr>.
  1448.  */
  1449. command process_mem()
  1450. {
  1451.     if (has_arg) {
  1452.     if (iter < 1 || iter > 500)
  1453.         say("use argument from 1 to 500 (Kbytes for process)");
  1454.     else {
  1455.         maxmem = minmem = availmem - 1024 * iter;
  1456.         if (maxmem < mem_in_use + 30000)
  1457.             maxmem = minmem = mem_in_use + 30000;
  1458.     }
  1459.     } else {
  1460.     minmem = availmem - 200000;  /* Epsilon uses remaining memory */
  1461.     if (minmem < mem_in_use + 30000)    /* make sure we have */
  1462.         minmem = mem_in_use + 30000;    /* 30k left for buffers */
  1463.     if (availmem > 300000)    /* if plenty, save some memory for process */
  1464.         maxmem = minmem;
  1465.     }
  1466.  
  1467.     say("in-use %d   avail %d   epsilon %d   process %d",
  1468.          mem_in_use, availmem, maxmem, availmem - maxmem);
  1469.     iter = 1;
  1470. }
  1471.  
  1472.  
  1473. /* put mark at the beginning of the buffer, and point at the end.  Useful for
  1474.  * killing the entire buffer, (say for inclusion in another).
  1475.  */
  1476. command mark_whole_buffer() on cx_tab['h']
  1477. {
  1478.     mark = 0;
  1479.     point = size();
  1480. }
  1481.  
  1482.  
  1483.  
  1484.  
  1485. /************************************************
  1486.  *                        *
  1487.  *    local modifications of functions    *
  1488.  *                        *
  1489.  ************************************************/
  1490.  
  1491. /* basic.e */
  1492.  
  1493.  
  1494. command goto_beginning() on reg_tab[ALT('<')], reg_tab[NUMCTRL(NUMDIGIT(7))]
  1495. {
  1496. /***/    mark = point;
  1497.     point = 0;
  1498. }
  1499.  
  1500. command goto_end() on reg_tab[ALT('>')], reg_tab[NUMCTRL(NUMDIGIT(1))]
  1501. {
  1502. /***/    mark = point;
  1503.     point = size();
  1504. }
  1505.  
  1506.  
  1507. /* files.e */
  1508. command visit_file() on cx_tab[CTRL('V')]
  1509.   /* if no file name is given, try to visit a file with the same name as
  1510.    * the buffer name.
  1511.    */
  1512. {
  1513.     char tmp[FNAMELEN];
  1514.     char resp[80];
  1515.     
  1516.     iter = 0;
  1517.     get_file(tmp, "Visit file: ");
  1518.     if (tmp[0] == '\0')
  1519. /***/        if (!filename || *filename == '\0') {
  1520. /***/            strcpy(tmp, bufname);
  1521. /***/        }
  1522.         else
  1523.             strcpy(tmp, filename);
  1524.     if (!has_arg && modified) {        /* buffer need to be saved? */
  1525.         get_string(resp, "Save buffer? [y]");
  1526.         if (toupper(*resp) != 'N')
  1527.             save_file();
  1528.         }
  1529.     read_file(tmp);
  1530. }
  1531.  
  1532. command show_point() on cx_tab['=']
  1533. {
  1534. /***/    say("Column=%d, point=%d, size=%d, chr=0x%x (%d)",
  1535. /***/        current_column(), point, size(), curchar(), curchar());
  1536. }
  1537.  
  1538.  
  1539. /* format.e */
  1540.  
  1541. command maybe_break_line() on reg_tab[' '], reg_tab['\n']
  1542. {
  1543.     int h;
  1544.     int *spot;
  1545.  
  1546.     if (fill_mode)
  1547.         if ((h = current_column() + 1) > margin_right) {
  1548.             spot = alloc_spot();
  1549.             pick_break(margin_right);
  1550.             delete_horizontal_space();
  1551.             insert('\n');
  1552.             point = *spot;
  1553.             free_spot(spot);
  1554. /***/            if (key == '\n') return;
  1555.         } else if (h == margin_right && isspace(key)) {
  1556.             delete_horizontal_space();
  1557.             key = '\n';            /* right at break */
  1558.         }
  1559.     normal_character();
  1560. }
  1561.  
  1562.  
  1563. /* fill region with no indentation (except whatever is on first line
  1564.  */
  1565. command fill_region()
  1566. {
  1567. /***/    fill_region_indent(0);
  1568. }
  1569.  
  1570.  
  1571.  
  1572. fill_region_indent(indented)
  1573.     int indented;
  1574. {
  1575.     int start, *end = alloc_spot();
  1576.     int indentation;
  1577.  
  1578.     if (point > (*end = mark))
  1579.         *end = point, point = mark;
  1580.  
  1581. /***/    to_begin_line();
  1582. /***/    re_search(1, "[ \t\n]*");    /* determine indentation */
  1583. /***/    indentation = (indented ? current_column() : 0);
  1584.     while (point < *end) {
  1585.         start = point;
  1586.         if (search(1, "\n\n"))
  1587.             point--;
  1588.         if (point > *end)
  1589.             point = *end;
  1590. /***/        if (character(point-1) == '\n')
  1591. /***/                point--;
  1592. /***/        region_fill_ind(start, point, indentation);
  1593.         re_search(1, "[ \t\n]*");    /* skip paragraph indent */
  1594.     }
  1595.     free_spot(end);
  1596. }
  1597.  
  1598.  
  1599.  
  1600. command fill_paragraph() on reg_tab[ALT('q')]
  1601. {
  1602.     int end, start=point;
  1603.  
  1604.     iter = 0;
  1605.     forward_paragraph();
  1606.     end = point - 1;
  1607.     backward_paragraph(); 
  1608.     re_search(1, "[ \t\n]*");    /* leave leading whitespace intact */
  1609. /***/   region_fill_ind(point, end, 0);
  1610.     if (start > size()) start = size();
  1611.     point = start;
  1612. }
  1613.  
  1614.  
  1615.  
  1616. region_fill_ind(a, b, lmargin)
  1617.     int a, b, lmargin;
  1618. {
  1619.   /* leave two spaces after ':' when filling, and indent each line by the
  1620.    * amount specified as lmargin
  1621.    */
  1622.     int start, *end = alloc_spot();
  1623.     char line[160];
  1624.     int startcol;
  1625.  
  1626.     point = a, *end = b;
  1627.     if (a > b)
  1628.         point = b, *end = a;
  1629.     startcol = current_column();
  1630.     while (point < *end) {
  1631.         start = point;
  1632. /***/        if (line_fill(line, *end, margin_right, startcol, ".?:!",
  1633.                     ")]'\""))
  1634.             break;
  1635.         while (point < *end && isspace(curchar()))
  1636.             point++;
  1637.         delete(start, point);
  1638. /***/        to_column(startcol);
  1639.         stuff(line);
  1640. /***/        startcol = lmargin;
  1641.     }
  1642.     free_spot(end);
  1643.     build_first = 1;        /* redisplay hint */
  1644. }
  1645.  
  1646.  
  1647.  
  1648.  
  1649. /* proc.e */
  1650. command start_process_split() on cx_tab[CTRL('M')]
  1651. {
  1652.     window_split();
  1653.     start_process();
  1654. }
  1655.  
  1656.  
  1657.  
  1658. /* prog.e */
  1659. show_line()        /* display point for a moment, then restore */
  1660. {
  1661.   /* delay a bit longer when showing a matching delimiter.
  1662.    */
  1663.     int oldstart = window_start;
  1664.     int time;
  1665.  
  1666.     maybe_refresh();
  1667. /***/    time = (window_start == oldstart) ? 8 : 25;
  1668.     if (has_arg && iter > 0)
  1669.         time = iter;
  1670.     pause(time);
  1671.     window_start = oldstart;
  1672.     build_first = 1;
  1673. }
  1674.  
  1675.  
  1676. /* search.e */
  1677. /* general replace routine */
  1678. gen_replace(query, regex)
  1679. int query;
  1680. {
  1681.   /* save query replace arguments for use by query_replace_again()
  1682.    */
  1683.     char msg[80], str[80], with[80];
  1684.     
  1685.     iter = 0;
  1686.     sprintf(msg, "%s%seplace string: ",
  1687.             regex ? "R-E " : has_arg ? "Word " : "",
  1688.             query? "Query r": "R");
  1689.     get_string(str, msg);
  1690.     if (*str) {
  1691.         get_string(with, "with: ");
  1692. /***/        if (query) {
  1693. /***/            did_query = 1;
  1694. /***/            strcpy(query_str, str);
  1695. /***/            strcpy(query_with, with);
  1696. /***/        }
  1697.         string_replace(str, with, query, has_arg, regex);
  1698.     }
  1699. }
  1700.  
  1701.  
  1702.  
  1703. /* window.e */
  1704. int move_by()
  1705. {
  1706.   /* leave just one line of overlap on C-V
  1707.    */
  1708. /***/    int n = window_size - 1;
  1709. /***/    if (n < 1)
  1710. /***/        n = 1;
  1711.     return n;
  1712. }
  1713.  
  1714. #define BUFSIZE 100
  1715.  
  1716. command compare_windows()
  1717. {
  1718.   /* if one buffer has more characters than the other, leave the cursor
  1719.    * in the window with the extra characters.
  1720.    */
  1721.     char buf1[BUFSIZE], buf2[BUFSIZE];
  1722.     int max, end, i;
  1723.  
  1724.     for (;;) {
  1725.         check_abort();
  1726.         max = BUFSIZE - 1;
  1727.         if (point + max > size())
  1728.             max = size() - point;
  1729.         grab(point, point + max, buf1);
  1730.         window_number++;
  1731.         if (point + max > size())
  1732.             max = size() - point;
  1733.         grab(point, point + max, buf2);
  1734.         if (strncmp(buf1, buf2, max) || strlen(buf1) < max) {
  1735.             for (i = 0; i < max; i++)    /* find difference */
  1736.                 if (buf1[i] != buf2[i]) {
  1737.                     say("Difference found.");
  1738.                     point += i;
  1739.                     window_number--;
  1740.                     point += i;
  1741.                     return;
  1742.                 }
  1743.         }
  1744.         point += max;
  1745.         end = point >= size();
  1746.         window_number--;
  1747.         point += max;
  1748.         if (end && point >= size()) {
  1749.             say("No difference.");
  1750.             return;
  1751.         } else if (end || point >= size()) {
  1752.             say("Extra characters.");
  1753. /***/            if (point >= size())
  1754.                 window_number++;  /* show the longer one */
  1755.             return;
  1756.         }
  1757.     }
  1758. }
  1759.  
  1760.  
  1761. /************************************************
  1762.  *                        *
  1763.  *   set local default values and bindings       *
  1764.  *                        *
  1765.  ************************************************/
  1766.  
  1767. /* .mss .txt and .to files should start in auto-fill mode
  1768.  */
  1769. suffix_mss() { do_fill(); }
  1770. suffix_txt() { do_fill(); }
  1771. suffix_to()  { do_fill(); }
  1772.  
  1773. do_fill()
  1774. {
  1775.     fill_mode = 1;
  1776.     make_mode();
  1777. }
  1778.  
  1779.  
  1780. /* this should probably be replaced by the code in  lispmode.e
  1781.  */
  1782. keytable lsp_tab;   /* to keep the key bindings for lisp mode (just
  1783.                display-matching-parens at present) */
  1784. suffix_lsp()
  1785. {
  1786.     mode_keys = lsp_tab;
  1787.     major_mode = strsave("LSP");
  1788.     make_mode();
  1789. }
  1790.  
  1791.  
  1792. /* declare routines that are defined elsewhere */
  1793. command goto_line();
  1794. command delete_hacking_tabs();
  1795. command scroll_down();
  1796. command scroll_up();
  1797. command compare_windows();
  1798.  
  1799. when_loading()
  1800. {
  1801.     /* set desired defaults */
  1802.     use_default = 1;
  1803.     margin_right = 78;
  1804.     num_kbufs = 4;
  1805.     use_default = 0;
  1806.  
  1807.     /* supply desired bindings */
  1808.     cx_tab['g']        = (short) goto_line;
  1809.     reg_tab[ALT(CTRL('J'))] = (short) to_indentation;
  1810.     reg_tab[CTRL('H')]    = (short) delete_hacking_tabs;
  1811.     reg_tab[NUMDIGIT(2)]    = (short) scroll_down;
  1812.     reg_tab[NUMDIGIT(8)]    = (short) scroll_up;
  1813.     reg_tab[CTRL('I')]    = (short) indent_under;
  1814.     reg_tab[ALT(CTRL('C'))] = (short) compare_windows;
  1815.  
  1816.     lsp_tab[')'] =
  1817.       lsp_tab[']'] =
  1818.         lsp_tab['}'] = (short) show_matching_delimiter;
  1819.  
  1820.     /* for IBM-AT, swap the <esc> and <backquote> keys */
  1821. /*    keytran[NUMCTRL(GREYESC)] = keytran[GREYESC] = '`';
  1822.     keytran[NUMALT(GREYESC)] = ALT('`');
  1823.     keytran['`'] = ESC;    */
  1824. }
  1825. ******************************************************************
  1826. local.hlp follows
  1827. ******************************************************************
  1828.  
  1829. Fill-indented (<esc><tab>) fills the region, making the indentation equal to
  1830. that of the first line.  This is useful, for instance, when editing a
  1831. quotation that is indented from the left margin.
  1832.  
  1833.  
  1834. Indent-next (C-M) goes to the next line and then indents under.  This is
  1835. useful for writing programs in languages such as Pascal.
  1836.  
  1837. Indent-less (A-M) decreases the indentation of the current line to match some
  1838. previous line.  The use of this routine is as follows.  After typing a line
  1839. of, say, Pascal, press C-M to start a new line indented under the previous
  1840. line (command indent-next above).  Then you can press A-M to unindent one
  1841. nesting level (for example, when leaving a BEGIN-END block).  Each A-M will
  1842. unindent another level.
  1843.  
  1844. Display-matching-parens is a command to toggle the behavior of the closing
  1845. delimiters  )  ]  }  to control whether Epsilon automatically shows the
  1846. matching open delimiter.
  1847.  
  1848. Query-replace (A-%) remembers its arguments.  Query-replace-again (C-X %)
  1849. restarts query-replace with the previous arguments.
  1850.  
  1851. Insert-time inserts the current date and time into the buffer at point.
  1852.  
  1853. Show-time (C-X t) shows the current date and time in the echo area.
  1854.  
  1855. The next few commands are for scrolling when using two windows.
  1856.    Next-page-lower (C-Z) is like next-page (C-V), but it controls the window
  1857.      below the current one.
  1858.    Previous-page-lower (A-Z) is like previous-page (A-V), but for the window
  1859.      below the current one.
  1860.    Next-page-both (C-A-Z) shows the next page in both the current window and
  1861.      the one below.
  1862.  
  1863. Split-and-find (C-X 4) splits the current window into two, and finds a file
  1864. in the lower one.
  1865.  
  1866. Process-mem shows the amount of memory reserved for the process buffer and
  1867. used by currently used by Epsilon.  Give an argument of 0 to see this
  1868. information.  A positive argument tries to set the process buffer allocation
  1869. to that number of K.  This requires some explanation.  I normally set the
  1870. Epsilon environment variable set epsilon=-m1 to allocate no space for the
  1871. process buffer, so that when editing large files, Epsilon doesn't start
  1872. swapping until absolutely necessary.  If I intend to use the process buffer,
  1873. say for compiling, I give Epsilon a command like   C-U 250 A-X proc<esc>
  1874. which reserves 250K for the process buffer.  This command isn't fully
  1875. protected:  you can probably confuse Epsilon by giving unusual arguments.
  1876.  
  1877. Mark-whole-buffer (C-X h) puts mark at the beginning of the buffer, and point
  1878. at the end.  It is useful for killing the entire buffer, say for inclusion in
  1879. another.
  1880.  
  1881. Goto-beginning (A-<) and goto-end (A->) leave a mark behind.
  1882.  
  1883. Visit-file (C-X C-V) uses the name of the buffer if no file name is specified.
  1884.  
  1885. Show-point (C-X =) also shows the decimal and octal values of the character
  1886. at point. 
  1887.  
  1888. Next-page (C-V) and Previous-page (A-V) leave just one line of overlap.
  1889.  
  1890. I also include several other miscellaneous modifications and personal
  1891. preferences for key bindings.  For example, the upward and downward arrows
  1892. on the keypad cause the screen to scroll in the corresponding direction.
  1893.  
  1894. ******************************************************************
  1895. lispmode.e follows
  1896. ******************************************************************
  1897. /************************************************************************
  1898. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  1899. *                                    *
  1900. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  1901. *                                    *
  1902. * Limited permission is hereby granted to reproduce and modify this    *
  1903. * copyrighted material provided that the resulting code is used only in    *
  1904. * conjunction with Lugaru products and that this notice is retained in    *
  1905. * any such reproduction or modification.                *
  1906. ************************************************************************/
  1907. /************************************************************************
  1908. * Portions of this file 
  1909. *    Copyright (C) 1985 Robert C. Pettengill
  1910. * Permission is granted to reproduce and use this copyrighted material
  1911. * for any purpose whatsoever.
  1912. ************************************************************************/
  1913.  
  1914. #include "eel.h"
  1915.  
  1916. #define LEFTD    '('
  1917. #define RIGHTD    ')'
  1918. #define LISP_INDENT    991    /* this_cmd code for lisp-indent command */
  1919.  
  1920. /*
  1921. Automatic indentation for Lisp code.
  1922. */
  1923. command delete_hacking_tabs();
  1924. keytable lisp_tab;            /* key table for lisp mode */
  1925. int lisp_comment_col = 40;    /* column for lisp comments to begin */
  1926.  
  1927. /* by default, the indenting levels are 2 spaces apart */
  1928. #define INCR    2
  1929.  
  1930. /*  find the column position of the ( in the current level
  1931.     and return that pos + INCR
  1932. */
  1933.  
  1934. lisp_compute_indent()
  1935. {
  1936.     int ind = 0;                /* indentation to use */
  1937.     int orig = point;
  1938.     if (lisp_move_level(-1, RIGHTD, LEFTD) > 0)
  1939.         ind = current_column() + INCR;
  1940.     else
  1941.         ind = 0;
  1942.     point = orig;
  1943.     return ind;
  1944. }
  1945.  
  1946. /* Indenter called on a new line */
  1947.  
  1948. command lisp_indenter()        
  1949. {
  1950.     to_indentation();        /* this seems to be needed, why? */
  1951.     to_column(lisp_compute_indent());
  1952. }
  1953.  
  1954. /*  Indent an existing line of lisp code.  If we're not in this line's
  1955.     indentation, though, or our new indentation matches the old,
  1956.     just insert a tab.
  1957. */
  1958.  
  1959. command lisp_indent() on lisp_tab['\t']
  1960. {
  1961.     int orig = point;
  1962.     int orig_column = current_column();
  1963.  
  1964.     to_indentation();
  1965.     if (orig_column > current_column()) {    /* if not in indentation */
  1966.         point = orig;
  1967.         insert('\t');            /* insert a tab */
  1968.     } else if (prev_cmd == LISP_INDENT)    /* repeated, make bigger */
  1969.         to_column(orig_column + INCR);
  1970.     else
  1971.         to_column(lisp_compute_indent());
  1972.     this_cmd = LISP_INDENT;
  1973. }
  1974.  
  1975. command lisp_comment() on lisp_tab[ALT(';')]
  1976. {
  1977.     end_of_line();
  1978.     if (lisp_comment_col > (current_column() + 1)) 
  1979.         to_column(lisp_comment_col);
  1980.     else insert(' ');
  1981.     insert(';');
  1982. }
  1983.  
  1984. command lisp_def_begin() on lisp_tab[ALT(CTRL('A'))]
  1985. {
  1986.     re_search(-1,"^%(def");
  1987. }
  1988.  
  1989. command lisp_def_end() on lisp_tab[ALT(CTRL('E'))]
  1990. {
  1991.     int orig = point;
  1992.     lisp_def_begin();
  1993.     forward_level();
  1994.  
  1995. }
  1996.  
  1997. command lisp_up_level() on lisp_tab[ALT(CTRL('U'))]
  1998. {
  1999.     lisp_move_level(-1,RIGHTD,LEFTD);
  2000. }
  2001.  
  2002. command lisp_down_level() on lisp_tab[ALT(CTRL('D'))]
  2003. {
  2004.     lisp_move_level(1,LEFTD,RIGHTD);  /* not quite right */
  2005. }
  2006.  
  2007. /*
  2008. Move in direction dir to find a parenthesis that would
  2009. match first at point. Return 1 on success.  Otherwise go to
  2010. starting point, and return 0.
  2011. */
  2012.  
  2013. lisp_move_level(dir, first, second)
  2014. char first, second;
  2015. {
  2016. int orig = point;
  2017. int level = -dir;        /* hack for up & down level */
  2018. char pat[6];            /* temporary pattern */
  2019.  
  2020. sprintf(pat, "[%c%c]", first, second);
  2021. while (re_search(dir, pat)) {        /* look for either first or second */
  2022.     if (character(point - (dir > 0)) == first)
  2023.         level++;
  2024.     else
  2025.         level--;
  2026.     if (level == 0)        /* when we return to same level, done */
  2027.         return 1;
  2028. }
  2029. point = orig;
  2030. return 0;
  2031. }
  2032.  
  2033. command lisp_mode()
  2034. {
  2035.     mode_keys = lisp_tab;        /* use these keys */
  2036.     lisp_tab[')'] = lisp_tab[']'] = (short) show_matching_delimiter;
  2037.     lisp_tab[CTRL('H')] = (short) delete_hacking_tabs;
  2038.     major_mode = strsave("Lisp");
  2039.     make_mode();
  2040.     indenter = lisp_indenter;
  2041.     auto_indent = 1;
  2042.     margin_right = 80;
  2043. }
  2044.  
  2045. /* make this the default mode for .l, and .lsp files */
  2046. suffix_l()    { lisp_mode(); }
  2047. suffix_lsp()    { lisp_mode(); }
  2048. ******************************************************************
  2049. krypt.e follows
  2050. ******************************************************************
  2051. /*  -*- Mode: C -*-
  2052.  *  
  2053.  *  File:   [ZonkerPC]c:\ep\lib\krypt.e
  2054.  *  Author: rcp  
  2055.  *  Date:   16-Nov-1986 12:34:25 
  2056.  *  
  2057.  *  Description:  file encryption for epsilon based on
  2058.  *
  2059.  *    Crypt:    Encryption routines for MicroEMACS
  2060.  *        written by Dana Hoggatt and Daniel Lawrence
  2061.  */
  2062.  
  2063. #include "eel.h"
  2064.  
  2065. int keyy;    /* 29 bit encipherment key */
  2066. int salt;    /* salt to spice up key with */
  2067.  
  2068. command krypt()
  2069.  
  2070. {
  2071.     char pw[24];
  2072.     int pos = 0, last = size(), c, n = 0;
  2073.     
  2074.     keyy = 0;            /* 29 bit encipherment key */
  2075.     salt = 0;            /* salt to spice up key with */
  2076.     get_string(pw, "Enter password: ");
  2077.     for(n=0; n < strlen(pw); n++)
  2078.         pw[n] = crypt(pw[n]);
  2079.     for (; pos < last; pos++) {
  2080.         c = character(pos);
  2081.         c = crypt(c);
  2082.         replace(pos,c);    
  2083.     }
  2084. }
  2085.  
  2086. /**********
  2087.  *
  2088.  *    crypt - in place encryption/decryption of a buffer
  2089.  *
  2090.  *    (C) Copyright 1986, Dana L. Hoggatt
  2091.  *    1216, Beck Lane, Lafayette, IN
  2092.  *
  2093.  *    When consulting directly with the author of this routine, 
  2094.  *    please refer to this routine as the "DLH-POLY-86-B CIPHER".  
  2095.  *
  2096.  *    This routine was written for Dan Lawrence, for use in V3.8 of
  2097.  *    MICRO-emacs, a public domain text/program editor.  
  2098.  *
  2099.  *    I kept the following goals in mind when preparing this function:
  2100.  *
  2101.  *        1.    All printable characters were to be encrypted back
  2102.  *        into the printable range, control characters and
  2103.  *        high-bit characters were to remain unaffected.  this
  2104.  *        way, encrypted would still be just as cheap to 
  2105.  *        transmit down a 7-bit data path as they were before.
  2106.  *
  2107.  *        2.    The encryption had to be portable.  The encrypted 
  2108.  *        file from one computer should be able to be decrypted 
  2109.  *        on another computer.
  2110.  *
  2111.  *        3.    The encryption had to be inexpensive, both in terms
  2112.  *        of speed and space.
  2113.  *
  2114.  *        4.    The system needed to be secure against all but the
  2115.  *        most determined of attackers.
  2116.  *
  2117.  *    ...  Decryption is totally isomorphic, and is performed 
  2118.  *    in the same manner by the same routine.  
  2119.  *
  2120.  *    For the interest of cryptologists, at the heart of this 
  2121.  *    function is a Beaufort Cipher.  The cipher alphabet is the 
  2122.  *    range of printable characters (' ' to '~'), all "control" 
  2123.  *    and "high-bit" characters are left unaltered.
  2124.  *
  2125.  *    The key is a variant autokey, derived from a wieghted sum 
  2126.  *    of all the previous clear text and cipher text.  A counter 
  2127.  *    is used as salt to obiterate any simple cyclic behavior 
  2128.  *    from the clear text, and key feedback is used to assure 
  2129.  *    that the entire message is based on the original key, 
  2130.  *    preventing attacks on the last part of the message as if 
  2131.  *    it were a pure autokey system.
  2132.  *
  2133.  *    Overall security of encrypted data depends upon three 
  2134.  *    factors:  the fundamental cryptographic system must be 
  2135.  *    difficult to compromise; exhaustive searching of the key 
  2136.  *    space must be computationally expensive; keys and plaintext 
  2137.  *    must remain out of sight.  This system satisfies this set
  2138.  *    of conditions to within the degree desired for Micro-EMACS.
  2139.  *
  2140.  *    Though direct methods of attack (against systems such as 
  2141.  *    this) do exist, they are not well known and will consume 
  2142.  *    considerable amounts of computing time.  An exhaustive
  2143.  *    search requires over a billion investigations, on average.
  2144.  *
  2145.  *    The choice, entry, storage, manipulation, alteration, 
  2146.  *    protection and security of the keys themselves are the 
  2147.  *    responsiblity of the user.  
  2148.  *
  2149.  **********/
  2150.  
  2151. /* [ZonkerPC]c:\ep\lib\krypt.e, 22-Nov-1986 15:19:46, Edit by rcp 
  2152.  * hacked to work for epsilon - changed crypt to work a character at
  2153.  * a time.
  2154.  */
  2155.  
  2156. crypt(cc)
  2157. int cc;        /* current character being considered */
  2158.  
  2159. {
  2160.     int nc;
  2161.     
  2162.     /* only encipher printable characters */
  2163.     if ((cc >= ' ') && (cc <= '~')) {
  2164.  
  2165. /**  If the upper bit (bit 29) is set, feed it back into the key.  This 
  2166.     assures us that the starting key affects the entire message.  **/
  2167.  
  2168.         keyy &= 0x1FFFFFFFL;    /* strip off overflow */
  2169.         if (keyy & 0x10000000L) {
  2170.             keyy ^= 0x0040A001L;    /* feedback */
  2171.         }
  2172.  
  2173. /**  Down-bias the character, perform a Beaufort encipherment, and 
  2174.     up-bias the character again.  We want key to be positive 
  2175.     so that the left shift here will be more portable and the 
  2176.     mod95() faster   **/
  2177.  
  2178.         nc = mod95((int)(keyy % 95) - (cc - ' ')) + ' ';
  2179.  
  2180. /**  the salt will spice up the key a little bit, helping to obscure 
  2181.     any patterns in the clear text, particularly when all the 
  2182.     characters (or long sequences of them) are the same.  We do 
  2183.     not want the salt to go negative, or it will affect the key 
  2184.     too radically.  It is always a good idea to chop off cyclics 
  2185.     to prime values.  **/
  2186.  
  2187.         if (++salt >= 20857) {    /* prime modulus */
  2188.         salt = 0;
  2189.     }        
  2190.  
  2191. /**  our autokey (a special case of the running key) is being 
  2192.     generated by a wieghted checksum of clear text, cipher 
  2193.     text, and salt.   **/
  2194.  
  2195.         keyy = keyy + keyy + nc + cc + salt;
  2196.         return(nc);
  2197.     }
  2198.     else
  2199.         return(cc);
  2200.     }    
  2201.  
  2202. mod95(val)
  2203. int val;
  2204. {
  2205.     /*  The mathematical MOD does not match the computer MOD  */
  2206.  
  2207.     /*  Yes, what I do here may look strange, but it gets the
  2208.         job done, and portably at that.  */
  2209.  
  2210.     while (val >= 9500)
  2211.         val -= 9500;
  2212.     while (val >= 950)
  2213.         val -= 950;
  2214.     while (val >= 95)
  2215.         val -= 95;
  2216.     while (val < 0)
  2217.         val += 95;
  2218.     return (val);
  2219. }
  2220. ******************************************************************
  2221. kmode.e follows
  2222. ******************************************************************
  2223. /************************************************************************
  2224. Most of this is copyright (C) 1986, Bob Knight.  The rest is copyrighted
  2225. by Lugaru Software, as noted in the following copyright blurb.
  2226.  
  2227. This material may be used and distributed freely, provided that it is not
  2228. used as part of a product to be sold for profit.
  2229.  
  2230. The ideas for most of the commands implemented here come primarily
  2231. from TOPS-20 EMACS, by Richard M. Stallman and others.
  2232. ************************************************************************/
  2233. /************************************************************************
  2234. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  2235. *                                    *
  2236. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  2237. *                                    *
  2238. * Limited permission is hereby granted to reproduce and modify this    *
  2239. * copyrighted material provided that the resulting code is used only in    *
  2240. * conjunction with Lugaru products and that this notice is retained in    *
  2241. * any such reproduction or modification.                *
  2242. ************************************************************************/
  2243.  
  2244. /*
  2245. This file contains the following commands:
  2246. lowercase_region - lowercases the current region, bound to C-X C-L
  2247. capitalize_region - uppercases the current region, bound to C-X C-U
  2248. set_comment_strings - set the begin-comment and end-comment strings
  2249. set_comment_column - set the default column for beginning comments, bound
  2250.              to C-X ;
  2251. indent_for_comment - indent to the comment column on the current line, bound
  2252.              to M-;
  2253. up_comment_line - go to the previous line and indent to the comment column, 
  2254.              bound to M-P
  2255. down_comment_line - go to the next line and indent to the comment column,
  2256.              bound to M-N
  2257. revert_file - restore the current buffer from the associated disk file, bound
  2258.              to C-X C-R
  2259. date_edit - insert an "edited-by" line at the beginning of the file, bound to
  2260.              M-Z
  2261. make - spawn a process and issue a make command, bound to C-X C-Q
  2262. connect_to_directory - connect to a named directory
  2263. count_lines_region - count the number of lines in the current region, bound to
  2264.              M-=
  2265. search_for_string_in_files - perform a re_search of the named files
  2266.  
  2267. In addition, comment_start and comment_end are set for various extensions of
  2268. files as they are visited.
  2269. */
  2270.  
  2271. #include "eel.h"
  2272. char comment_start[80] = "; ", comment_end[80] = "", make_string[80] = "";
  2273. int comment_column = 40;
  2274.  
  2275. /* lowercase the region */
  2276. command lowercase_region() on cx_tab[CTRL('l')]
  2277. {
  2278.     do_region_case(1);
  2279. }
  2280.  
  2281. /* capitalize the region */
  2282. command capitalize_region() on cx_tab[CTRL('u')]
  2283. {
  2284.     do_region_case(0);
  2285. }
  2286.  
  2287. /* Routine for region case converts */
  2288. do_region_case(do_lower)
  2289. {
  2290.     int c, from = point, to = mark, temp;
  2291.     char resp[80];
  2292.  
  2293.     if (from > to)
  2294.         temp = from, from = to, to = temp;
  2295.  
  2296.     if ((to-from)>250)
  2297.         get_string(resp, "Do you really want to case convert such a large region? [y]");
  2298.     else *resp = 'Y';
  2299.  
  2300.     if (toupper(*resp) != 'N') {
  2301.         for (; from <= to; from++) {
  2302.             check_abort();
  2303.             c = character(from);
  2304.             replace(from, do_lower ? tolower(c) : toupper(c));
  2305.         }
  2306.     }
  2307. }
  2308.  
  2309. /* Set comment start and comment end strings, initially "; " */
  2310. command set_comment_strings()
  2311. {
  2312.     char msg[80], tmp[80];
  2313.     
  2314.     sprintf(msg,"Comment start [%s]: ",comment_start);
  2315.     get_string(tmp,msg);
  2316.     if(*tmp)
  2317.         strcpy(comment_start,tmp);
  2318.     get_string(tmp,"Comment end:  ");
  2319.     strcpy(comment_end,tmp);
  2320.     say("Comment start = %s, comment end = %s",
  2321.         comment_start,comment_end);
  2322. }
  2323.  
  2324. /* Set comment column */
  2325. command set_comment_column() on cx_tab[';']
  2326. {
  2327.     comment_column = (has_arg ? iter : 40);
  2328.     iter = 0;
  2329.     say("Comment column = %d",comment_column);
  2330. }
  2331.  
  2332. /* Indent for comment */
  2333. command indent_for_comment() on reg_tab[ALT(';')]
  2334. {
  2335.     do_comment();
  2336. }
  2337.  
  2338. /* Up comment line */
  2339. command up_comment_line() on reg_tab[ALT('p')]
  2340. {
  2341.     maybe_flush_comment_line();
  2342.     point = prev_screen_line(1);
  2343.     do_comment();
  2344. }
  2345.  
  2346. /* Down comment line */
  2347. command down_comment_line() on reg_tab[ALT('n')]
  2348. {
  2349.     maybe_flush_comment_line();
  2350.     point = next_screen_line(1);
  2351.     do_comment();
  2352. }
  2353.  
  2354. /* maybe_flush_comment_line - flush a line if the only thing on it is a
  2355.    comment start followed by comment end.  flush is a misnomer, we simply
  2356.    flush the comment start and comment end */
  2357. maybe_flush_comment_line()
  2358. {
  2359.     int to, from;
  2360.     char foo[80], bar[80];
  2361.     
  2362.     to_end_line();
  2363.     to = point;
  2364.     to_begin_line();
  2365.     from = point;
  2366.     for (;point < to;point++) {
  2367.         if ((curchar() != ' ') & (curchar() != '\t')) break;
  2368.     }
  2369.     if (curchar() != '\n') {
  2370.         strcpy(bar,comment_start);  strcat(bar,comment_end);
  2371.         strcat(bar,"\n");
  2372.         grab(point,point+strlen(bar),foo);
  2373.         if (!strncmp(foo,bar,strlen(bar))) 
  2374.             delete(from,point+strlen(bar)-1);
  2375.     }
  2376. }
  2377.  
  2378. /* do_comment - routine for emplacing comments on the current line */
  2379. do_comment()
  2380. {
  2381.     int to, found, start, from;
  2382.     char foo[80];
  2383.  
  2384.     to_end_line();
  2385.     to = point;
  2386.     to_begin_line();
  2387.     found = 0;
  2388.     start = point;
  2389.     for (; point < to; point++) {
  2390.         grab(point,point+strlen(comment_start),foo);
  2391.         if (!strncmp(foo,comment_start,strlen(comment_start))) {
  2392.             found = 1;
  2393.             break;
  2394.         }
  2395.     }
  2396.     if (found==1) {
  2397.         if (current_column() < comment_column) {
  2398.             to_column(comment_column);
  2399.         } else {
  2400.             if (current_column() > comment_column) {
  2401.                 from = point;
  2402.                 for (point--;point >= start;point--) {
  2403.                     if ((curchar() != ' ') &    
  2404.                         (curchar() != '\t')) break;
  2405.                 }
  2406.                 point++;
  2407.                 delete(point,from);
  2408.                 if (current_column() > comment_column)
  2409.                     insert(' ');
  2410.                 else to_column(comment_column);
  2411.             }
  2412.         }
  2413.         point = point + strlen(comment_start);
  2414.     } else {
  2415.         if (current_column() < comment_column)
  2416.             to_column(comment_column);
  2417.     
  2418.         if (current_column() > comment_column)
  2419.             insert(' ');
  2420.         stuff(comment_start);  stuff(comment_end);
  2421.         point = point - strlen(comment_end);
  2422.     }
  2423. }
  2424.  
  2425. /* Revert file - restore the current buffer from its associated disk file */
  2426. command revert_file() on cx_tab[CTRL('R')]
  2427. {
  2428.     char resp[80];
  2429.     int old_point;
  2430.     
  2431.     if(!strcmp(bufname,"process"))
  2432.         say("Can't revert process");
  2433.     else {
  2434.         get_string(resp, "Restore file from disk? [n]");
  2435.  
  2436.         if (toupper(*resp) == 'Y') {
  2437.             old_point = point;
  2438.             read_file(filename);
  2439.             point = old_point;
  2440.         }
  2441.     }
  2442. }
  2443.  
  2444. /* Date edit - insert a line at the start of the file with date/time, etc. */
  2445. command date_edit() on reg_tab[ALT('z')]
  2446. {
  2447.     char edit_string[100], month_string[6];
  2448.     struct time_info date_time;
  2449.  
  2450.     point = 0;
  2451.     insert('\n');
  2452.     point = 0;
  2453.  
  2454.     time_and_day(&date_time);
  2455.  
  2456.     switch (date_time.month) {
  2457.         case 1:
  2458.             strcpy(month_string,"Jan");
  2459.             break;
  2460.         case 2:
  2461.             strcpy(month_string,"Feb");
  2462.             break;
  2463.         case 3:
  2464.             strcpy(month_string,"Mar");
  2465.             break;
  2466.         case 4:
  2467.             strcpy(month_string,"Apr");
  2468.             break;
  2469.         case 5:
  2470.             strcpy(month_string,"May");
  2471.             break;
  2472.         case 6:
  2473.             strcpy(month_string,"Jun");
  2474.             break;
  2475.         case 7:
  2476.             strcpy(month_string,"Jul");
  2477.             break;
  2478.         case 8:
  2479.             strcpy(month_string,"Aug");
  2480.             break;
  2481.         case 9:
  2482.             strcpy(month_string,"Sep");
  2483.             break;
  2484.         case 10:
  2485.             strcpy(month_string,"Oct");
  2486.             break;
  2487.         case 11:
  2488.             strcpy(month_string,"Nov");
  2489.             break;
  2490.         case 12:
  2491.             strcpy(month_string,"Dec");
  2492.             break;
  2493.         }
  2494.  
  2495.     sprintf(edit_string,
  2496.         "%s[%s]%s, %2d-%s-%04d %2d:%02d:%02d, Edit by %s%s\n%s%s",
  2497.         comment_start, getenv("sysname"), filename, date_time.day,
  2498.         month_string, date_time.year, date_time.hour, 
  2499.         date_time.minute, date_time.second, getenv("user"),
  2500.         comment_end, comment_start, comment_end);
  2501.     stuff(edit_string);
  2502.     point = point - strlen(comment_end);
  2503. }
  2504.  
  2505. /* Comment string sets for various suffixes
  2506.    Eventually to be expanded to mode-type editing */
  2507. suffix_asm()
  2508. {
  2509.     strcpy(comment_start,"; ");  strcpy(comment_end,"");
  2510. }
  2511.  
  2512. suffix_plm()
  2513. {
  2514.     strcpy(comment_start,"/* ");  strcpy(comment_end," */");
  2515. }
  2516.  
  2517. suffix_pas()
  2518. {
  2519.     strcpy(comment_start,"(* ");  strcpy(comment_end," *)");
  2520. }
  2521.  
  2522. suffix_c()
  2523. {
  2524.     strcpy(comment_start,"/* ");  strcpy(comment_end," */");
  2525.     c_mode();
  2526. }
  2527.  
  2528. suffix_h()
  2529. {
  2530.     strcpy(comment_start,"/* ");  strcpy(comment_end," */");
  2531.     c_mode();
  2532. }
  2533.  
  2534. suffix_e()
  2535. {
  2536.     strcpy(comment_start,"/* ");  strcpy(comment_end," */");
  2537.     c_mode();
  2538. }
  2539.  
  2540. /* Don't look at me!  I didn't choose BASIC for the MicroSCADA package! */
  2541. suffix_bas()
  2542. {
  2543.     strcpy(comment_start,"' ");  strcpy(comment_end,"");
  2544. }
  2545.  
  2546. /* make - create a process window, if no present, then fire up a make */
  2547. command make() on cx_tab[CTRL('Q')]
  2548. {
  2549.     int error;
  2550.     char foo[80],tmp[80];
  2551.     
  2552.     sprintf(foo,"Enter filename to make [%s]:  ",make_string);
  2553.     get_string(tmp,foo);
  2554.     if (*tmp) 
  2555.         strcpy(make_string,tmp);
  2556.     if (*make_string) {
  2557.         error = 0;
  2558.         if (!another) {
  2559.             zap("process");
  2560.             error = concur_shell(getenv("COMSPEC"),tmp);
  2561.         } else {
  2562.             say("A process is already running.");
  2563.         }
  2564.         if (error) {
  2565.             say("Couldn't exec");
  2566.         } else {
  2567.             to_buffer("process");
  2568.             point = size();
  2569.             sprintf(tmp,"make %s\n",make_string);
  2570.             stuff(tmp);
  2571.         }
  2572.     } else {
  2573.         say("Null make string not allowed");
  2574.     }
  2575. }
  2576.  
  2577. /* connect_to_directory */
  2578. command connect_to_directory()
  2579. {
  2580.     char dir[80];
  2581.     
  2582.     get_string(dir,"Connect to directory [\\]:  ");
  2583.     if (!*dir)
  2584.         strcpy(dir,"\\");
  2585.     if (chdir(dir))
  2586.         say("Unable to connect to %s",dir);
  2587.     else {
  2588.         if (another) {
  2589.             to_buffer("process");
  2590.             point = size();
  2591.             insert('\n');
  2592.             to_buffer(previous_buffer);
  2593.         }
  2594.     }
  2595. }
  2596.  
  2597. /* count_lines_region */
  2598. command count_lines_region() on reg_tab[ALT('=')]
  2599. {
  2600.     int curpoint = point, nlines = 1, temp;
  2601.     
  2602.     if (point > mark)
  2603.         temp = point, point = mark, mark = temp;
  2604.     for (;point <= mark;) {
  2605.         check_abort();
  2606.         if (!nl_forward())
  2607.             break;
  2608.         if (point <= mark)
  2609.             nlines++;
  2610.     }
  2611.     say("%d",nlines);
  2612.     point = curpoint;
  2613. }
  2614.  
  2615. /* search_for_string_in_files - 
  2616.     search the current directory for a given string */
  2617. command search_for_string_in_files()
  2618. {
  2619.     char str[80], files[80], tmp[80];
  2620.     
  2621.     get_string(str,"Search for string:  ");
  2622.     if(*str) {
  2623.         get_string(files,"in files:  ");
  2624.  
  2625.         fondle_buffers();
  2626.  
  2627.         to_buffer("found_buffer");
  2628.         sprintf(tmp,"String search for '%s' in files %s\n\n",
  2629.             str,files);
  2630.         stuff(tmp);
  2631.     
  2632.         to_buffer("filename_buffer");
  2633.         if(!do_dired(files)) {
  2634.             do_file_search(str);
  2635.             to_buffer("search_buffer");
  2636.             modified = 0;
  2637.             to_buffer("filename_buffer");
  2638.             modified = 0;
  2639.             to_buffer("found_buffer");
  2640.             delete_buffer("search_buffer");
  2641.             delete_buffer("filename_buffer");
  2642.             point=size();
  2643.             stuff("Done.\n");
  2644.             modified = 0;
  2645.         } else 
  2646.             say("File(s) not found");
  2647.     } else
  2648.         say("Null string invalid");
  2649. }
  2650.  
  2651. fondle_buffers()
  2652. {
  2653.     zap("filename_buffer");
  2654.     zap("search_buffer");
  2655.     create("found_buffer");
  2656. }
  2657.  
  2658. do_file_search(str) 
  2659.     char *str;
  2660. {
  2661.     
  2662.     int from, opoint;
  2663.     char tmp[80], tmp2[80], filename[80];
  2664.  
  2665.     for(point=0;point < size();) {
  2666.         check_abort();
  2667.         if ((!nl_forward()) | (point >= size()))
  2668.             break;
  2669.         move_to_column(16);
  2670.         grab(point,point+4,tmp);
  2671.         if(strncmp(tmp,"<DIR>",5)) { /* If no match, not directory */
  2672.             move_to_column(2);
  2673.             from = point;
  2674.             for(;curchar() != ' ';point++);
  2675.             grab(from,point--,filename);
  2676.             to_buffer("found_buffer");
  2677.             sprintf(tmp,"Searching %s\n",filename);
  2678.             stuff(tmp);
  2679.             to_buffer("search_buffer");
  2680.             file_read(filename,1);
  2681.             do {
  2682.                 check_abort();
  2683.                 if (re_search(1,str)) {
  2684.                     opoint = point;
  2685.                     to_begin_line();
  2686.                     from = point;
  2687.                     to_end_line();
  2688.                     grab(from,point,tmp);
  2689.                     sprintf(tmp2,"%6d: %s\n",opoint,tmp);
  2690.                     to_buffer("found_buffer");
  2691.                     stuff(tmp2);
  2692.                     to_buffer("search_buffer");
  2693.                     point = opoint++;
  2694.                 }
  2695.             } while (point<size());
  2696.         }
  2697.         to_buffer("filename_buffer");
  2698.     }
  2699. }
  2700. ******************************************************************
  2701. tex.e follows
  2702. ******************************************************************
  2703. /********** Documentation to be inserted in file "edoc" ***********
  2704.  
  2705. show-matching-dollar    Insert $ and show matching $ or $$ in TeX mode.
  2706.         Calls normal-character to insert the key $, then shows the
  2707.         matching $ that delimits math-mode or displayed material.
  2708.  
  2709. tex-mode        Show delimiters for TeX code and fill.
  2710.         This command puts the current buffer in TeX mode and
  2711.         is invoked automatically for a file with extension .tex .
  2712.         ([{ are flashed using show-matching-delimiter().  Dollar signs
  2713.         $ or $$ invoke show-matching-dollar().  fill-mode is set on, and
  2714.         fill-column is set to 72.  The mode line says TeX Fill.
  2715.  
  2716. ***********             End of documentation            **********/
  2717.  
  2718. -----  Gary R. Smith  (smith#gary@b.mfenet@nmfecc.arpa)
  2719.  
  2720. /****************** Beginning of file "tex.e" ******************/
  2721.  
  2722. #include "eel.h"
  2723.  
  2724. /*
  2725. Show delimiters for TeX code and fill.
  2726. Written by Gary R. Smith in Oct. 1986.
  2727.             
  2728. Fill mode is enabled automatically and the fill column set to 72.
  2729.  
  2730. When one of )]} is typed, the matching ([{ is flashed, by binding the
  2731. former keys to show-matching-delimiter().
  2732.  
  2733. Matching dollar signs, which indicate math-mode and displayed
  2734. material, are searched for using show-matching-dollar().  That
  2735. function performs searches that are limited to a small portion of
  2736. text by these assumptions about the TeX code:  (a) new paragraphs do
  2737. not begin in $...$ or $$...$$, and (b) $...$ is not nested within
  2738. $$...$$, or vice versa.  The following searches are made:
  2739.  
  2740. (1) If the $ just typed is preceded by another $, search backwards,
  2741.     counting occurrences of $$, until a solitary $ or the beginning of
  2742.     the buffer or the beginning of a paragraph is found (\n\n, i.e., a
  2743.     blank line, or TeX command \par).  If the $$ just typed is the
  2744.     first, third, fifth, etc., occurrence, then flash the first of the
  2745.     matching $$.
  2746.  
  2747. (2) A solitary $ causes a search backwards, counting occurrences of
  2748.     solitary $, until $$ or the beginning of the buffer or the
  2749.     beginning of a paragraph is found.  If the $ just typed is the
  2750.     first, third, fifth, etc., occurrence, then flash the first of the
  2751.     matching $.
  2752. */
  2753.  
  2754. buffer int tex_mode_on = 0;     /* Are we in TeX mode? */
  2755.  
  2756. keytable tex_tab;               /* Key table for TeX mode */
  2757.  
  2758. command show_matching_dollar() on tex_tab['$']
  2759. {
  2760.         int orig;
  2761.         
  2762.         normal_character();
  2763.         iter = 0;
  2764.         say("");
  2765.         orig = point;
  2766.         if (dollar_match()) show_line();        /* Function from prog.e */
  2767.         point = orig;
  2768.         return;
  2769. }
  2770.  
  2771. dollar_match()  /* Return 1 if backwards search finds matching $,
  2772.                    return 0 otherwise */
  2773. {
  2774.         int double = 0;
  2775.         int count = 0;
  2776.         int loc;        /* Will hold location of match, if found */
  2777.         
  2778.         if (point < 3) return 0;
  2779.         point -= 2;
  2780.         if (curchar() == '$') double = 1;       /* $$ just typed */
  2781.         else point++;
  2782.         
  2783.         while (re_search(-1, "$|\n\n|\\par")) { /* To beginning or break */
  2784.                 if (curchar() == '$') { /* Found $ */
  2785.                         if (double) {   /* Trying to match $$ */
  2786.                                 if (point > 0 && character(point-1) == '$') {
  2787.                                         /* Yes $$ */
  2788.                                         point--;
  2789.                                         if (!count++) loc = point;
  2790.                                         /* Count, and save loc if first */
  2791.                                 }
  2792.                                 else break;     /* Found solitary $ */
  2793.                         }
  2794.                         else {          /* Trying to match solitary $ */
  2795.                                 if (!point) {
  2796.                                         if (!count++) loc = 0;
  2797.                                 }
  2798.                                 else if (character(point-1) != '$') {
  2799.                                         /* Found $ */
  2800.                                         if (!count++) loc = point;
  2801.                                         /* Count, and save loc if first */
  2802.                                 }
  2803.                                 else break;     /* Found $$ */
  2804.                         }
  2805.                 }
  2806.                 else break;     /* Found beginning of paragraph */
  2807.         }
  2808.         
  2809.         point = loc;
  2810.         return count % 2;
  2811. }
  2812.  
  2813. command tex_mode()
  2814. {
  2815.         mode_keys = tex_tab;            /* Use these keys */
  2816.         tex_tab[')'] = (short) show_matching_delimiter;
  2817.         tex_tab[']'] = (short) show_matching_delimiter;
  2818.         tex_tab['}'] = (short) show_matching_delimiter;
  2819.         fill_mode = 1;
  2820.         margin_right = 72;
  2821.         tex_mode_on = 1;
  2822.         major_mode = strsave("TeX");
  2823.         make_mode();
  2824. }
  2825.  
  2826. /* Make this the default mode for .tex files */
  2827. suffix_tex()    { tex_mode(); }
  2828.  
  2829. /****************** End of file "tex.e" ******************/
  2830. ******************************************************************
  2831. fortran.e follows
  2832. ******************************************************************
  2833. /********** Documentation to be inserted in file "edoc" ***********
  2834.  
  2835. for-mode        Do automatic indentation of Fortran code.
  2836.         This command puts the current buffer in Fortran mode and
  2837.         is invoked automatically for a file with extension .for .
  2838.         <Enter> runs fortran-indent-line() to insert all necessary tabs
  2839.         or spaces in the line just typed.  tab-size is set to 3.  When 
  2840.         the buffer is written, you are asked if it should be untabified.
  2841.         Matching ('s are shown when typed.  fill-mode is set on, and
  2842.         fill-column is set to 72, so excess space-delimited entities
  2843.         move to the next line.  The mode line says Fortran Fill.
  2844.  
  2845. fortran-indent-line     Indents previous line of Fortran code.
  2846.         Determines where whitespace should be adjusted to put statement
  2847.         numbers in the required columns and to show the block structure of the
  2848.         code.  Does nothing to full-line or on-line comments.  If the state-
  2849.         ment before the one just typed was incomplete, a continuation is made.
  2850.         if-then-else-elseif-endif blocks are indented to show code structure.
  2851.         do-continue blocks are also, if there is a continue for each do.
  2852.         A do-loop without a continue will cause improper indentation of the
  2853.         following statement, unless the loop is only two lines long.
  2854.  
  2855. fortran-indent-region   Indent a region of Fortran code.
  2856.         Indents all lines that terminate between point and mark using
  2857.         fortran-indent-line().
  2858.  
  2859. ***********             End of documentation            **********/
  2860.  
  2861. /*-----  Gary R. Smith  (smith#gary@b.mfenet@nmfecc.arpa)*/
  2862.  
  2863. /****************** Beginning of file "fortran.e" ******************/
  2864.  
  2865. #include "eel.h"
  2866.  
  2867. /*
  2868. Automatic indentation for Fortran code.
  2869. Written by Gary R. Smith in Sept. 1986.
  2870.  
  2871. Indentation occurs after each Fortran statement is typed, or when
  2872. the command fortran-indent-region is given.  Entering of Fortran code
  2873. is speeded up, because the programmer can let Epsilon insert the spaces
  2874. needed to produce clearly indented code.
  2875.  
  2876. Indentation involves scanning a statement and the lines preceding it
  2877. to determine where whitespace should be adjusted to put statement
  2878. numbers in the required columns and to show the block structure of the
  2879. code.  The following steps occur:
  2880. 1. If the line begins with a comment character, nothing is done.
  2881. 2. If the previous statement was incomplete (ends in one of "=+-*,(" ),
  2882.    the present line is indented as a continuation and the remaining steps
  2883.    are omitted.
  2884. 3. If the line begins with a number (string of digits), indentation
  2885.    and right justification occurs for a statement number.
  2886. 4. For lines that are neither comments nor continuations, the presence
  2887.    of if-then-else-elseif-endif or do-continue blocks is detected by
  2888.    examination of the first strings (after statement numbers, if any) in both
  2889.    the previous and present statements.  An indentation level found from the
  2890.    previous statement is used for the present line except in these cases:
  2891.    (a) Presence of "if-then", "else", "elseif-then", or "do" in the previous
  2892.        statement, increments (by tab_size) the indentation level for the
  2893.        present line.
  2894.    (b) Presence of "else", "elseif-then", "endif", or "continue" on the
  2895.        present line, decrements the indentation level for the present line.
  2896.        (Note that all "continue"s are treated as if they end do-continue
  2897.        blocks and may be indented too little if they do not.)
  2898. 5. If the previous statement begins with a statement number, it ends a
  2899.    two-line do-loop if the statement before it contains "do" followed by
  2900.    that statement number.  In this case, the indentation level for the
  2901.    present line is decremented.  Only two-line do-loops are detected;
  2902.    automatic indentation of longer loops occurs only if they end with
  2903.    "continue".
  2904.  
  2905. The previous statement is found by checking the previous line and its
  2906. predecessors, skipping blank and empty lines and (both full-line and
  2907. on-line) comments, for a line that is not a continuation.
  2908.  
  2909. Fill mode is enabled automatically and the fill column set to 73.
  2910. Therefore, a space entered past column 72 will cause space-delimited
  2911. entities to move to the next line.  If the last character remaining
  2912. on the long line indicates an incomplete statement, the next line is
  2913. made a continuation automatically.
  2914.  
  2915. The command fortran-indent-region indents all lines that terminate
  2916. between point and mark.  The steps described above are performed on all
  2917. of the lines.  A future improvement would be to minimize time-consuming
  2918. searches by remembering the indentation level from one line to the next.
  2919. */
  2920.  
  2921. buffer int fortran_mode = 0;    /* Are we in fortran mode? */
  2922.  
  2923. keytable fortran_tab;           /* Key table for fortran mode */
  2924.  
  2925. #define FORTRAN_SKIP "(([ \t]*\n)|([ \t]*[!#].*\n))+"
  2926. #define FORTRAN_COMMENT "cC!#*"
  2927. #define FORTRAN_OP "=+-*,("
  2928. #define FORTRAN_CONT '.'
  2929. #define MAXWORD 80
  2930. #define NBEGWORDS 4
  2931. #define NENDWORDS 5
  2932.  
  2933. char *beg_word[NBEGWORDS];
  2934. char *end_word[NENDWORDS];
  2935.  
  2936. command fortran_indent_region() on fortran_tab[ALT(CTRL('\\'))]
  2937. {
  2938.         int temp, *begin;
  2939.  
  2940.         if (point > mark) {     /* If point follows mark, swap */
  2941.                 temp = mark;
  2942.                 mark = point;
  2943.                 point = temp;
  2944.         }
  2945.         if (nl_reverse())       /* To begin of line, even if it's first */
  2946.                 point++;
  2947.         begin = alloc_spot();
  2948.         *begin = point;
  2949.         while (point < mark) {  /* Indent each line in region */
  2950.                 if (!nl_forward()) break;
  2951.                 fortran_indent_line();
  2952.         }
  2953.         mark = *begin;          /* Region is just-indented set of lines */
  2954.         free_spot(begin);
  2955.         iter = 0;
  2956.         return;
  2957. }
  2958.  
  2959. fortran_indent_line()
  2960. {
  2961.         int *orig;
  2962.         int this_beg, prev_end, prev_indent, prev_cont, prev_stmt;
  2963.         int stmt_no_len, this_col6;
  2964.         char key_word[MAXWORD];
  2965.         int i, cmp_result;
  2966.         char stmt_no[6], stmt_np[6];
  2967.         
  2968.         if (point == 0) return; /* Handle first line if indenting region */
  2969.         
  2970.         this_beg = prev_screen_line(1);
  2971.         if (index(FORTRAN_COMMENT, character(this_beg))) return;
  2972.                                 /* Comment found */
  2973.         orig = alloc_spot();
  2974.         *orig = point;
  2975.         re_search(-1, "[ \t]*\n");
  2976.         if (point == this_beg) goto exit;
  2977.                                 /* Blank or empty line found */
  2978.         
  2979.         point = this_beg;
  2980.         prev_end = find_prev_end();
  2981.         if (prev_end > 0 && stmt_incomp(prev_end)) {
  2982.                                         /* Test if stmt is incomplete */
  2983.                 prev_indent = find_indent(prev_end);
  2984.                 prev_cont = check_cont(prev_end);       /* 1 if was cont. */
  2985.                 if (check_cont(this_beg)) move_to_column(6);
  2986.                 else make_cont();       /* Make this line a continuation
  2987.                                            by replacing cols. 1-6 */
  2988.                 to_column(6 + prev_indent + !prev_cont * tab_size);
  2989.                         /* Replace indentation with same as previous line
  2990.                            + tab_size if previous stmt not continuation */
  2991.                 goto exit;
  2992.         }
  2993.         
  2994.         point = this_beg;
  2995.         if (stmt_no_len = check_no(stmt_no)) {
  2996.                 to_column(5 - stmt_no_len);     /* Right justify stmt no */
  2997.                 point = point + stmt_no_len;    /* Point after stmt no */
  2998.         }
  2999.         to_column(6);   /* Remove whitespace and
  3000.                            put space in col. 6 ( or 1-6 if no stmt no) */
  3001.         this_col6 = point;
  3002.  
  3003.         if (prev_end > 0) {             /* Test that previous stmt found */
  3004.                 point = prev_end;
  3005.                 prev_indent = find_prev_stmt(stmt_no);  /* Find indentation */
  3006.                 if (find_word(1, key_word)) {
  3007.                                         /* Word that began previous stmt */
  3008.                         for(i=0; i < NBEGWORDS; ++i) {  /* Is it on list? */
  3009.                                 cmp_result = strcmp(key_word, beg_word[i]);
  3010.                                 if (cmp_result >= 0) break;
  3011.                         }
  3012.                         if (cmp_result == 0 && i == 0) {
  3013.                                         /* Is if followed by then? */
  3014.                                 point = prev_end;
  3015.                                 find_word(-1, key_word);
  3016.                                 if (strcmp(key_word, "then")) 
  3017.                                         cmp_result = 1; /* No */
  3018.                         }
  3019.                         if (!cmp_result) {
  3020.                                 prev_indent += tab_size;
  3021.                                 goto fin;
  3022.                         }
  3023.                         else {
  3024.                 /* Not beginning of block, check for two-line do-loop */
  3025.                                 if (*stmt_no == '\0') goto this;
  3026.                                 to_begin_line();
  3027.                                 if ((prev_end = find_prev_end()) < 0)
  3028.                                         goto this;
  3029.                                 find_prev_stmt(stmt_np);
  3030.                                 if (find_word(1, key_word)) {
  3031.                                         if (strcmp(key_word, "do"))
  3032.                                                 goto this;
  3033.                                         if (check_no(stmt_np) &&
  3034.                                                 !strcmp(stmt_no, stmt_np)) {
  3035.                                                 prev_indent -= tab_size;
  3036.                                                 goto fin;
  3037.                                         }
  3038.                                 }
  3039.                                 else {
  3040.                                         key_word_error();
  3041.                                         goto exit;
  3042.                                 }
  3043.                         }
  3044.                 }
  3045.                 else {          /* Apparent error in user type-in */
  3046.                         key_word_error();
  3047.                         goto exit;
  3048.                 }
  3049.         }
  3050.         else goto exit;         /* Nothing to be done if no previous stmt */
  3051.  
  3052. this:   point = this_col6;
  3053.         if (find_word(1, key_word)) {   /* Word that begins this stmt */
  3054.                 for(i=0; i < NENDWORDS; ++i) {  /* Is it on list? */
  3055.                         cmp_result = strcmp(key_word, end_word[i]);
  3056.                         if (cmp_result >= 0) break;
  3057.                 }
  3058.                 if (!cmp_result) prev_indent -= tab_size;
  3059.         }
  3060.         else {          /* Apparent error in user type-in */
  3061.                 key_word_error();
  3062.                 goto exit;
  3063.         }
  3064.         
  3065. fin:    point = this_col6;
  3066.         if (prev_indent > 0) insert_to_column(6, 6 + prev_indent);
  3067. exit:   point = *orig;
  3068.         free_spot(orig);
  3069.         return;
  3070. }
  3071.                 
  3072. find_prev_end() /* Move point to last character of previous stmt,
  3073.                            passing comments and whitespace.  Return
  3074.                            point if there was a previous statement,
  3075.                            -1 if not */
  3076. {
  3077.         fortran_skip_lines();
  3078.         re_search(-1, FORTRAN_SKIP);    /* Skip to end of stmt */
  3079.         if (point > 0) return point;    /* Last character found */
  3080.         else return -1;                 /* No previous stmt */
  3081. }
  3082.  
  3083. fortran_skip_lines()    /* Assumes point is at beginning of a line and
  3084.                            skips back over blank, empty, or comment lines */
  3085. {
  3086.         re_search(-1, "[ \t\n]*");      /* Skip to a line with darkspace */
  3087.         if (point == 0) return;         /* Done if at beginning of file */
  3088.         while (to_begin_line(), index(FORTRAN_COMMENT, curchar())) {
  3089.                                 /* Comment line found */
  3090.                 re_search(-1, "[ \t\n]*");/* Skip to a line with darkspace */
  3091.                 if (point == 0) return;
  3092.         }
  3093.         nl_forward();                   /* After \n of searchable line */
  3094.         return;
  3095. }
  3096.  
  3097. stmt_incomp(loc)        /* Check if character before loc indicates an
  3098.                            incomplete stmt.  Return nonzero, if incomplete */
  3099. int loc;
  3100. {
  3101.         if (loc > 0)
  3102.                 return (index(FORTRAN_OP, character(--loc)) != 0);
  3103.         else return 0;
  3104. }
  3105.  
  3106. find_indent(loc)        /* Return number of columns of indentation in
  3107.                            the stmt surrounding loc.  Point is left
  3108.                            after the end of the indentation */
  3109. int loc;
  3110. {
  3111.         point = loc;
  3112.         move_to_column(6);      /* Position point after continuation col. */
  3113.         re_search(1, "[ \t]*"); /* Move point to first darkspace character */
  3114.         return current_column() - 6;
  3115. }
  3116.  
  3117. check_cont(loc) /* Return 1 if the line containing loc has whitespace
  3118.                    in cols. 1-5, then a darkspace character in col. 6.
  3119.                    Otherwise return 0.  Leave point after col. 6. */
  3120. int loc;
  3121. {
  3122.         point = loc;
  3123.         to_begin_line();
  3124.         re_search(1, "[ \t]*"); /* Move point to first darkspace character */
  3125.         if (current_column() == 5) {
  3126.                 ++point;
  3127.                 return 1;
  3128.         }
  3129.         else {
  3130.                 move_to_column(6);
  3131.                 return 0;
  3132.         }
  3133. }
  3134.  
  3135. make_cont()             /* Make line containing point a continuation by
  3136.                            replacing initial whitespace with 5 columns of
  3137.                            whitespace followed by the continuation char.
  3138.                            First darkspace should be the first char
  3139.                            of Fortran on this line */
  3140. {
  3141.         to_begin_line();
  3142.         to_column(5);
  3143.         insert(FORTRAN_CONT);
  3144.         return;         /* Point is left after continuation char. */
  3145. }
  3146.  
  3147. check_no(stmt_no)       /* Check if, following point, there is (optional)
  3148.                            whitespace, then a string of 5 or fewer digits
  3149.                            (a Fortran statement number).  If so, return
  3150.                            pointer to it in stmt_no */
  3151. char *stmt_no;
  3152. {
  3153.         int orig = point;
  3154.         int begin;
  3155.         int length;
  3156.         
  3157.         re_search(1, "[ \t]*");         /* Skip whitespace, if any */
  3158.         begin = point;
  3159.         while(isdigit(curchar())) point++;
  3160.         length = point - begin;         /* Length of string of digits */
  3161.         if (length > 0 && length <= 5) {        /* String was found */
  3162.                 point = begin;  
  3163.                 parse_string(1, "[0-9]*", stmt_no);
  3164.         }
  3165.         else {                                  /* Not found */
  3166.                 length = 0;
  3167.                 *stmt_no = '\0';
  3168.         }
  3169.  
  3170.         point = orig;
  3171.         return length;
  3172. }
  3173.  
  3174. find_prev_stmt(stmt_no) /* Find start of previous statement, when point is in
  3175.                            it, returning length of statement's indentation
  3176.                            or -1 if there was no previous statement.
  3177.                            Also, return pointer stmt_no to a statement
  3178.                            number, if present */
  3179. char *stmt_no;
  3180. {
  3181.         while (point > 0 && check_cont(point)) {
  3182.                 to_begin_line();
  3183.                 fortran_skip_lines();
  3184.                         /* Skip back over empty and blank lines & comments */
  3185.                 --point;
  3186.         }
  3187.         if (point >= 0) {
  3188.                 to_begin_line();
  3189.                 check_no(stmt_no);
  3190.                 return find_indent(point);
  3191.         }
  3192.         else return -1;
  3193. }
  3194.  
  3195. find_word(dir, word)  /* Searching in direction dir, 
  3196.                          find string of alphabetic characters beginning
  3197.                          at point, and copy the string to word,
  3198.                          changing to lower case, and return
  3199.                          the length of the string as function value */
  3200. int dir;
  3201. char *word;
  3202. {
  3203.         int length;
  3204.         
  3205.         length = parse_string(dir, "[a-zA-Z]*", word);
  3206.         while ((*word++ = tolower(*word)) != '\0');
  3207.         return length;
  3208. }
  3209.  
  3210. #define MAXERRSTRING 10
  3211. key_word_error()        /* Report apparent error in user type-in */
  3212. {
  3213.         char err_string[MAXERRSTRING+1];
  3214.  
  3215.         grab(point, point+MAXERRSTRING, err_string);
  3216.         say("%s%s", "Expected Fortran keyword but found: ",
  3217.                 err_string);
  3218.         maybe_ding();
  3219.         return;
  3220. }
  3221.  
  3222. command for_mode()
  3223. {
  3224.         char resp[80];
  3225.  
  3226.         mode_keys = fortran_tab;                /* Use these keys */
  3227.         fortran_tab[')'] = (short) show_matching_delimiter;
  3228.         indenter = fortran_indent_line;
  3229.         auto_indent = 1;
  3230.         fill_mode = 1;
  3231.         margin_right = 73;
  3232.         fortran_mode = 1;
  3233.         major_mode = strsave("Fortran");
  3234.         make_mode();
  3235.  
  3236.         beg_word[0] = strsave("if");
  3237.         beg_word[1] = strsave("elseif");
  3238.         beg_word[2] = strsave("else");
  3239.         beg_word[3] = strsave("do");
  3240.  
  3241.         end_word[0] = strsave("endif");
  3242.         end_word[1] = strsave("end");
  3243.         end_word[2] = strsave("elseif");
  3244.         end_word[3] = strsave("else");
  3245.         end_word[4] = strsave("continue");
  3246.  
  3247.         if (search(1, "\t")) {
  3248.                 get_string(resp, "Tab found in file, untabify buffer? [y]");
  3249.                 if (toupper(*resp) != 'N') {
  3250.                         resp[0] = 'a';
  3251.                         while (!isdigit(*resp)) {
  3252.                                 resp[0] = '3';
  3253.                                 get_string(resp,
  3254.                                         "What size tab for untabify? [3]");
  3255.                         }
  3256.                         tab_size = resp[0] - '0';
  3257.                         build_first = 1;
  3258.                         maybe_refresh();
  3259.  
  3260.                         point = 0;
  3261.                         mark = size();
  3262.                         untabify_region();
  3263.                 }
  3264.         }
  3265.         point = 0;
  3266.         mark = 0;
  3267.         tab_size = 3;
  3268. }
  3269.  
  3270. /* Make this the default mode for .for files */
  3271. suffix_for()    { for_mode(); }
  3272.  
  3273. /* save_file() from files.e was modified to behave appropriately if
  3274.    narrow or fortran mode is on, by Gary R. Smith, Sept. 1986 */
  3275.  
  3276. buffer int narrow_mode;
  3277.  
  3278. command save_file() on cx_tab[CTRL('S')]
  3279. {
  3280.         char backupname[80];
  3281.         int err;
  3282.         int mod;
  3283.         char resp[80];
  3284.         
  3285.         iter = 0;
  3286.         if (!*filename)
  3287.                 return write_file();
  3288.         strcpy(backupname, filename);
  3289.         strcpy(get_extension(backupname), ".bak");
  3290.         if (want_backups && strcmp(filename, backupname)) {
  3291.                 delete_file(backupname);        /* don't check errors */
  3292.                 rename_file(filename, backupname);
  3293.         }
  3294.         if (fortran_mode) {     /* Fortran file may need to be untabified */
  3295.                 get_string(resp, "Untabify buffer? [y]");
  3296.                 if (toupper(*resp) != 'N') {
  3297.                         point = 0;
  3298.                         mark = size();
  3299.                         untabify_region();
  3300.                 }
  3301.         }
  3302.         mod = modified;
  3303.         if (err = file_write(filename, strip_returns))
  3304.                 file_error(err,filename,"write error");
  3305.         else
  3306.                 say("%s written.", filename);
  3307.                 if (narrow_mode)
  3308.                         modified = mod;
  3309.         return err;
  3310. }
  3311.  
  3312. /****************** End of file "fortran.e" ******************/
  3313. ******************************************************************
  3314. for_ext.e follows
  3315. ******************************************************************
  3316. /* Written by James S. Storey */
  3317.  
  3318. /* Subroutines and commands in Fortran extension table (C-] table)
  3319.     These routines insert templates for Fortran statements. */
  3320.  
  3321. #include "eel.h"
  3322.  
  3323. #define PREINDENT() if (current_column() < 6) move_to_column(6);\
  3324. if (current_column() < 6) to_column(6)
  3325.  
  3326. #define MENU "for_menu"
  3327.  
  3328. keytable fort_tab;    /* table for basic commands */
  3329. keytable fort_ext_tab;    /* table for extended commands */
  3330.  
  3331. buffer short bell_key;
  3332.  
  3333. get_fort_menu()    /* make sure Fortran menu file is ready to go */
  3334. {    
  3335.     int exists = exist("-fort_menu");
  3336.     char *oldbuf = bufname;
  3337.         
  3338.  
  3339.     create("-fort_menu");
  3340.     bufname = "-fort_menu";
  3341.     if (!exists) {
  3342.         sayput("Loading Fortran menu file. . .");
  3343.         if (file_read(MENU, 1)) {
  3344.             bufname = oldbuf;
  3345.             delete_buffer("-fort_menu");
  3346.             gripe("Can't find Fortran menu file %s", MENU);
  3347.             say("");
  3348.             return 0;
  3349.         }
  3350.         say("");
  3351.         point = 0;
  3352.         bufname = oldbuf;
  3353.         return 1;
  3354.     }
  3355.     else {
  3356.         if (size()==0) {
  3357.             bufname = oldbuf;
  3358.             delete_buffer("-fort_menu");
  3359.             gripe("No Fortran menu file %s", MENU);
  3360.             return 0;
  3361.         }
  3362.         point = 0;
  3363.         bufname = oldbuf;
  3364.         return 1;
  3365.     }
  3366. }
  3367.  
  3368. fort_menu() on fort_ext_tab[CTRL(']')], fort_ext_tab['?']
  3369. {
  3370.     sayput("C-] ");
  3371.     if (get_fort_menu())
  3372.         view_buffer("-fort_menu");
  3373.     check_abort();
  3374.     do {
  3375.         getkey();
  3376.     } while ((key == CTRL(']'))||(key == '?'));
  3377.     say("");
  3378.     do_again();
  3379. }
  3380.  
  3381. fort_function()    on fort_ext_tab['f']
  3382. {
  3383.     jmp_buf this_level, *old_level = top_level;
  3384.     short orig_ret = fort_tab[CTRL('J')];
  3385.     int i;
  3386.  
  3387.     /* Set up abort trap to unbind keys */
  3388.     top_level = &this_level;
  3389.     bell_key = fort_tab[CTRL('G')];
  3390.     if (setjmp(top_level)) {
  3391.         major_mode = strsave("Fortran");
  3392.         make_mode();
  3393.         say("Aborted.");
  3394.         fort_tab[CTRL('J')] = orig_ret;
  3395.         reg_tab[CTRL('G')] = find_index("abort");
  3396.         fort_tab[CTRL('G')] = bell_key;
  3397.         top_level = old_level;
  3398.         return;
  3399.     }
  3400.  
  3401.     PREINDENT();
  3402.     bprintf("FUNCTION ()\n\n");
  3403.     fort_indenter();
  3404.     stuff("RETURN\n");
  3405.     fort_indenter();
  3406.     stuff("END\n");
  3407.     for (i=1; i++<=4; nl_reverse())
  3408.         ;
  3409.     move_to_column(6);
  3410.     re_search(1,"[ \t]*");
  3411.     insert(' ');
  3412.     --point;
  3413.     major_mode = strsave("FUNCTION type (single letter)");
  3414.     strcpy(mode, major_mode);
  3415.     maybe_refresh();
  3416.  
  3417.     /* Get type, completing on a single key */
  3418.     fort_tab[CTRL('G')] = find_index("f-abort");
  3419.     reg_tab[CTRL('G')] = find_index("f-abort");
  3420.     do {
  3421.         getkey();
  3422.         check_abort();
  3423.         if ((key >= 'A') && (key <= 'Z'))
  3424.             key -= 'A' - 'a';
  3425.         switch (key) {
  3426.             case ' ': {
  3427.                 delete(point,point+1);
  3428.                 break;
  3429.             }
  3430.             case 'c': {
  3431.                 stuff("CHARACTER");
  3432.                 break;
  3433.             }
  3434.             case 'd': {
  3435.                 stuff("DOUBLE PRECISION");
  3436.                 break;
  3437.             }
  3438.             case 'i': {
  3439.                 stuff("INTEGER");
  3440.                 break;
  3441.             }
  3442.             case 'j': {
  3443.                 stuff("COMPLEX");
  3444.                 break;
  3445.             }
  3446.             case 'l': {
  3447.                 stuff("LOGICAL");
  3448.                 break;
  3449.             }
  3450.             case 'r': {
  3451.                 stuff("REAL");
  3452.                 break;
  3453.             }
  3454.             case BELL: {
  3455.                 ungot_key=BELL;
  3456.                 f_abort();
  3457.                 break;
  3458.             }
  3459.             default : {
  3460.                 maybe_ding();
  3461.                 break;
  3462.             }
  3463.         }
  3464.     } while (!index(" cdijlr",key));
  3465.  
  3466.     /* Input function name in recursive edit mode. */
  3467.     point += 10;
  3468.     fort_tab[CTRL('J')] = find_index("exit-level");
  3469.     fort_tab[(' ')] = find_index("exit-level");
  3470.     major_mode = strsave("FUNCTION name (<cr> to exit)");
  3471.     strcpy(mode, major_mode);
  3472.     recursive_edit();
  3473.     fort_tab[(' ')] = find_index("normal-character");
  3474.     check_abort();
  3475.  
  3476.     /* Input parameters in recursive edit mode. */
  3477.     ++point;
  3478.     major_mode = strsave("FUNCTION parameters (<cr> to exit)");
  3479.     strcpy(mode, major_mode);
  3480.     recursive_edit();
  3481.     check_abort();
  3482.  
  3483.     /* Restore keys */
  3484.     major_mode = strsave("Fortran");
  3485.     make_mode();
  3486.     fort_tab[CTRL('J')] = orig_ret;
  3487.     reg_tab[CTRL('G')] = find_index("abort");
  3488.     fort_tab[CTRL('G')] = bell_key;
  3489.     nl_forward();
  3490.     top_level = old_level;
  3491. }
  3492.  
  3493. fort_program() on fort_ext_tab['p']
  3494. {
  3495.     int i;
  3496.  
  3497.     PREINDENT();
  3498.     bprintf("PROGRAM \n\n");
  3499.     fort_indenter();
  3500.     stuff("END\n");
  3501.     for (i=1; i++<=3; nl_reverse())
  3502.         ;
  3503. }
  3504.  
  3505. fort_subroutine() on fort_ext_tab['s']
  3506. {
  3507.     jmp_buf this_level, *old_level = top_level;
  3508.     short orig_ret = fort_tab[CTRL('J')];
  3509.     int i;
  3510.  
  3511.     /* Set up abort trap to unbind keys */
  3512.     top_level = &this_level;
  3513.     bell_key = fort_tab[CTRL('G')];
  3514.     if (setjmp(top_level)) {
  3515.         major_mode = strsave("Fortran");
  3516.         make_mode();
  3517.         say("Aborted.");
  3518.         fort_tab[CTRL('J')] = orig_ret;
  3519.         reg_tab[CTRL('G')] = find_index("abort");
  3520.         fort_tab[CTRL('G')] = bell_key;
  3521.         top_level = old_level;
  3522.         return;
  3523.     }
  3524.  
  3525.     PREINDENT();
  3526.     bprintf("SUBROUTINE ()\n\n");
  3527.     fort_indenter();
  3528.     stuff("RETURN\n");
  3529.     fort_indenter();
  3530.     stuff("END\n");
  3531.     for (i=1; i++<=3; nl_reverse())
  3532.         ;
  3533.     point -=3;
  3534.  
  3535.     /* Input subroutine name in recursive edit mode. */
  3536.     fort_tab[CTRL('J')] = find_index("exit-level");
  3537.     fort_tab[(' ')] = find_index("exit-level");
  3538.     fort_tab[CTRL('G')] = find_index("f-abort");
  3539.     reg_tab[CTRL('G')] = find_index("f-abort");
  3540.     major_mode = strsave("SUBROUTINE name (<cr> to exit)");
  3541.     strcpy(mode, major_mode);
  3542.     recursive_edit();
  3543.     fort_tab[(' ')] = find_index("normal-character");
  3544.     check_abort();
  3545.  
  3546.     /* Input parameters in recursive edit mode. */
  3547.     ++point;
  3548.     major_mode = strsave("SUBROUTINE parameters (<cr> to exit)");
  3549.     strcpy(mode, major_mode);
  3550.     recursive_edit();
  3551.     check_abort();
  3552.  
  3553.     /* Restore keys */
  3554.     major_mode = strsave("Fortran");
  3555.     make_mode();
  3556.     fort_tab[CTRL('J')] = orig_ret;
  3557.     reg_tab[CTRL('G')] = find_index("abort");
  3558.     fort_tab[CTRL('G')] = bell_key;
  3559.     top_level = old_level;
  3560.     nl_forward();
  3561. }
  3562.  
  3563.  
  3564. fort_character() on fort_ext_tab['a']
  3565. {
  3566.     PREINDENT();
  3567.     stuff("CHARACTER\t\t");
  3568. }
  3569.  
  3570. fort_double() on fort_ext_tab['d']
  3571. {
  3572.     PREINDENT();
  3573.     stuff("DOUBLE PRECISION\t");
  3574. }
  3575.  
  3576. fort_complex() on fort_ext_tab['j']
  3577. {
  3578.     PREINDENT();
  3579.     stuff("COMPLEX\t\t");
  3580. }
  3581.  
  3582. fort_integer() on fort_ext_tab['i']
  3583. {
  3584.     PREINDENT();
  3585.     stuff("INTEGER\t\t");
  3586. }
  3587.  
  3588. fort_logical() on fort_ext_tab['l']
  3589. {
  3590.     PREINDENT();
  3591.     stuff("LOGICAL\t\t");
  3592. }
  3593.  
  3594. fort_real() on fort_ext_tab['r']
  3595. {
  3596.     PREINDENT();
  3597.     stuff("REAL\t\t\t");
  3598. }
  3599.  
  3600.  
  3601.  
  3602. fort_common() on fort_ext_tab[ALT('c')]
  3603. {
  3604.     PREINDENT();
  3605.     stuff("COMMON /  / ");
  3606.     point-=3;
  3607. }
  3608.  
  3609. fort_data() on fort_ext_tab[ALT('d')]
  3610. {
  3611.     PREINDENT();
  3612.     stuff("DATA //");
  3613.     point-=2;
  3614. }
  3615.  
  3616.  
  3617.  
  3618. fort_blockif() on fort_ext_tab[CTRL('B')]
  3619. {
  3620.     short orig_ret = fort_tab[CTRL('J')];
  3621.  
  3622.     bell_key = fort_tab[CTRL('G')];
  3623.  
  3624.     PREINDENT();
  3625.     stuff("IF () THEN\n");
  3626.     fort_indenter();
  3627.     fort_tabify();
  3628.     insert('\n');
  3629.     fort_indenter();
  3630.     stuff("ENDIF\n");
  3631.     nl_reverse();
  3632.     nl_reverse();
  3633.     nl_reverse();
  3634.     point -= 6;
  3635.  
  3636.     /* enter condition in recursive edit mode */
  3637.     fort_tab[CTRL('G')] = find_index("f-abort");
  3638.     reg_tab[CTRL('G')] = find_index("f-abort");
  3639.     fort_tab[CTRL('J')] = find_index("exit-level");
  3640.     major_mode = strsave("IF condition (<cr> to exit)");
  3641.     strcpy(mode, major_mode);
  3642.     recursive_edit();
  3643.  
  3644.     /* Restore keys */
  3645.     major_mode = strsave("Fortran");
  3646.     make_mode();
  3647.     fort_tab[CTRL('J')] = orig_ret;
  3648.     reg_tab[CTRL('G')] = find_index("abort");
  3649.     fort_tab[CTRL('G')] = bell_key;
  3650.     check_abort();
  3651.  
  3652.     nl_forward();
  3653.     to_end_line();
  3654. }
  3655.  
  3656.  
  3657. fort_call() on fort_ext_tab['c']
  3658. {
  3659.     stuff("CALL ()");
  3660.     point-=2;
  3661. }
  3662.  
  3663. fort_continue() on fort_ext_tab[CTRL('C')]
  3664. {
  3665.     PREINDENT();
  3666.     stuff("CONTINUE\n");
  3667.     fort_indenter();
  3668. }
  3669.  
  3670. fort_do() on fort_ext_tab[CTRL('D')]
  3671. {
  3672.     jmp_buf this_level, *old_level = top_level;
  3673.     char line_no[20];
  3674.     int tag;
  3675.     short orig_ret = fort_tab[CTRL('J')];
  3676.  
  3677.     /* Set up abort trap to unbind keys */
  3678.     top_level = &this_level;
  3679.     bell_key = fort_tab[CTRL('G')];
  3680.     if (setjmp(top_level)) {
  3681.         major_mode = strsave("Fortran");
  3682.         make_mode();
  3683.         say("Aborted.");
  3684.         fort_tab[' '] = find_index("maybe-break-line");
  3685.         fort_tab[CTRL('J')] = orig_ret;
  3686.         reg_tab[CTRL('G')] = find_index("abort");
  3687.         fort_tab[CTRL('G')] = bell_key;
  3688.         top_level = old_level;
  3689.         return;
  3690.     }
  3691.  
  3692.     PREINDENT();
  3693.     bprintf("DO  =,\n");
  3694.     fort_indenter();
  3695.     fort_tabify();
  3696.     nl_reverse();
  3697.     point -= 3;
  3698.  
  3699.     /* Input line number in recursive edit mode.
  3700.         Space or <cr> exits.    */
  3701.     fort_tab[CTRL('J')] = find_index("exit-level");
  3702.     fort_tab[' '] = find_index("exit-level");
  3703.     fort_tab[CTRL('G')] = find_index("f-abort");
  3704.     reg_tab[CTRL('G')] = find_index("f-abort");
  3705.     major_mode = strsave("DO CONTINUE line number (<cr> to exit)");
  3706.     strcpy(mode, major_mode);
  3707.     recursive_edit();
  3708.     check_abort();
  3709.  
  3710.     /* Grab the line number if entered */
  3711.     tag = point;
  3712.     re_search(-1,"[0123456789]*");
  3713.     if (point!=tag)
  3714.         grab(point,tag,line_no);
  3715.     nl_forward();
  3716.     to_end_line();
  3717.     insert('\n');
  3718.     fort_indenter();
  3719.     fort_tabify();
  3720.     stuff("continue\n");
  3721.     nl_reverse();
  3722.     nl_reverse();
  3723.     tag = point++;
  3724.     bprintf("%5.5s",line_no);
  3725.     re_search(1,"[ \t]*");
  3726.     say("Continuation line?");
  3727.     major_mode = strsave("DO CONTINUE query");
  3728.     strcpy(mode, major_mode);
  3729.     maybe_refresh();
  3730.     getkey();
  3731.     if (key == CTRL('G'))
  3732.         error("Aborted.");
  3733.     delete(point,point+8);
  3734.     if ((key == CTRL('H'))||(toupper(key) == 'N')||(key == GREYBACK)) {
  3735.         to_end_line();
  3736.         delete(tag,point);
  3737.     }
  3738.     else
  3739.         stuff("CONTINUE");
  3740.     say("");
  3741.  
  3742.     /* Input index in recursive edit mode.  <cr> exits */
  3743.     search(-1,"=,");
  3744.     major_mode = strsave("DO index (<cr> or Space to exit)");
  3745.     strcpy(mode, major_mode);
  3746.     recursive_edit();
  3747.     check_abort();
  3748.  
  3749.     /* insert range */
  3750.     ++point;
  3751.     major_mode = strsave("DO start (<cr> or Space to exit)");
  3752.     strcpy(mode, major_mode);
  3753.     recursive_edit();
  3754.     check_abort();
  3755.     ++point;
  3756.     major_mode = strsave("DO end (<cr> or Space to exit)");
  3757.     strcpy(mode, major_mode);
  3758.     recursive_edit();
  3759.  
  3760.     /* Restore keys */
  3761.     major_mode = strsave("Fortran");
  3762.     make_mode();
  3763.     fort_tab[' '] = find_index("maybe-break-line");
  3764.     fort_tab[CTRL('J')] = orig_ret;
  3765.     reg_tab[CTRL('G')] = find_index("abort");
  3766.     fort_tab[CTRL('G')] = bell_key;
  3767.     top_level = old_level;
  3768.  
  3769.     check_abort();
  3770.     ++point;
  3771.     nl_forward();
  3772.     --point;
  3773. }
  3774.  
  3775.  
  3776. fort_else() on fort_ext_tab[CTRL('E')]
  3777. {
  3778.     PREINDENT();
  3779.     fort_delete_tab();
  3780.     stuff("ELSE\n");
  3781.     fort_indenter();
  3782.     fort_tabify();
  3783. }
  3784.  
  3785. fort_elseif() on fort_ext_tab['e']
  3786. {
  3787.     short orig_ret = fort_tab[CTRL('J')];
  3788.  
  3789.     bell_key = fort_tab[CTRL('G')];
  3790.  
  3791.     PREINDENT();
  3792.     fort_delete_tab();
  3793.     stuff("ELSEIF () THEN\n");
  3794.     fort_indenter();
  3795.     fort_tabify();
  3796.     nl_reverse();
  3797.     point -= 6;
  3798.  
  3799.     /* enter condition in recursive edit mode */
  3800.     fort_tab[CTRL('J')] = find_index("exit-level");
  3801.     fort_tab[CTRL('G')] = find_index("f-abort");
  3802.     reg_tab[CTRL('G')] = find_index("f-abort");
  3803.     major_mode = strsave("ELSE IF condition (<cr> to exit)");
  3804.     strcpy(mode, major_mode);
  3805.     recursive_edit();
  3806.  
  3807.     /* Restore keys */
  3808.     major_mode = strsave("Fortran");
  3809.     make_mode();
  3810.     fort_tab[CTRL('J')] = orig_ret;
  3811.     reg_tab[CTRL('G')] = find_index("abort");
  3812.     fort_tab[CTRL('G')] = bell_key;
  3813.     check_abort();
  3814.  
  3815.     nl_forward();
  3816.     nl_forward();
  3817.     --point;
  3818. }
  3819.  
  3820. fort_goto() on fort_ext_tab['g']
  3821. {
  3822.     PREINDENT();
  3823.     stuff("GOTO ");
  3824. }
  3825.  
  3826. fort_if() on fort_ext_tab[CTRL('I')]
  3827. {
  3828.     short orig_ret = fort_tab[CTRL('J')];
  3829.  
  3830.     bell_key = fort_tab[CTRL('G')];
  3831.  
  3832.     PREINDENT();
  3833.     stuff("IF () ");
  3834.     point -= 2;
  3835.  
  3836.     /* enter condition in recursive edit mode */
  3837.     fort_tab[CTRL('J')] = find_index("exit-level");
  3838.     fort_tab[CTRL('G')] = find_index("f-abort");
  3839.     reg_tab[CTRL('G')] = find_index("f-abort");
  3840.     major_mode = strsave("IF condition (<cr> to exit)");
  3841.     strcpy(mode, major_mode);
  3842.     recursive_edit();
  3843.  
  3844.     /* Restore keys */
  3845.     major_mode = strsave("Fortran");
  3846.     make_mode();
  3847.     fort_tab[CTRL('J')] = orig_ret;
  3848.     reg_tab[CTRL('G')] = find_index("abort");
  3849.     fort_tab[CTRL('G')] = bell_key;
  3850.     check_abort();
  3851.  
  3852.     point +=2;
  3853. }
  3854.  
  3855.  
  3856.  
  3857. fort_format() on fort_ext_tab[CTRL('f')]
  3858. {
  3859.     jmp_buf this_level, *old_level = top_level;
  3860.     char line_no[20];
  3861.     short orig_ret = fort_tab[CTRL('J')];
  3862.     int tag;
  3863.  
  3864.     /* Set up abort trap to unbind keys */
  3865.     top_level = &this_level;
  3866.     bell_key = fort_tab[CTRL('G')];
  3867.     if (setjmp(top_level)) {
  3868.         major_mode = strsave("Fortran");
  3869.         make_mode();
  3870.         say("Aborted.");
  3871.         fort_tab[' '] = find_index("maybe-break-line");
  3872.         fort_tab[CTRL('J')] = orig_ret;
  3873.         reg_tab[CTRL('G')] = find_index("abort");
  3874.         fort_tab[CTRL('G')] = bell_key;
  3875.         top_level = old_level;
  3876.         return;
  3877.     }
  3878.  
  3879.     PREINDENT();
  3880.     bprintf("FORMAT ()");
  3881.     to_begin_line();
  3882.  
  3883.     /* Input line number in recursive edit mode.
  3884.         Space or <cr> exits.    */
  3885.     fort_tab[CTRL('J')] = find_index("exit-level");
  3886.     fort_tab[' '] = find_index("exit-level");
  3887.     fort_tab[CTRL('G')] = find_index("f-abort");
  3888.     reg_tab[CTRL('G')] = find_index("f-abort");
  3889.     major_mode = strsave("FORMAT line number");
  3890.     make_mode();
  3891.  
  3892.     recursive_edit();
  3893.     check_abort();
  3894.  
  3895.     /* Grab the line number if entered, and right justify */
  3896.     tag = point;
  3897.     re_search(-1,"[0123456789]*");
  3898.     if (point!=tag) {
  3899.         grab(point,tag,line_no);
  3900.         move_to_column(0);
  3901.         delete(point,tag);
  3902.         bprintf("%5.5s",line_no);
  3903.     }
  3904.  
  3905.     /* Restore keys */
  3906.     major_mode = strsave("Fortran");
  3907.     make_mode();
  3908.     fort_tab[' '] = find_index("maybe-break-line");
  3909.     fort_tab[CTRL('J')] = orig_ret;
  3910.     reg_tab[CTRL('G')] = find_index("abort");
  3911.     fort_tab[CTRL('G')] = bell_key;
  3912.     top_level = old_level;
  3913.  
  3914.     search(1,"FORMAT (");
  3915. }
  3916.  
  3917.  
  3918. fort_open() on fort_ext_tab[CTRL('o')]
  3919. {
  3920.     jmp_buf this_level, *old_level = top_level;
  3921.     char unit_no[20];
  3922.     int tag;
  3923.     short orig_ret = fort_tab[CTRL('J')];
  3924.  
  3925.     /* Set up abort trap to unbind keys */
  3926.     top_level = &this_level;
  3927.     bell_key = fort_tab[CTRL('G')];
  3928.     if (setjmp(top_level)) {
  3929.         major_mode = strsave("Fortran");
  3930.         make_mode();
  3931.         say("Aborted.");
  3932.         fort_tab[' '] = find_index("maybe-break-line");
  3933.         fort_tab[CTRL('J')] = orig_ret;
  3934.         reg_tab[CTRL('G')] = find_index("abort");
  3935.         fort_tab[CTRL('G')] = bell_key;
  3936.         top_level = old_level;
  3937.         return;
  3938.     }
  3939.  
  3940.     PREINDENT();
  3941.     bprintf("OPEN (*,FILE='for*.dat',status='new')");
  3942.     point -= 31;
  3943.     major_mode = strsave("OPEN unit number (<cr> or Space to exit)");
  3944.     strcpy(mode, major_mode);
  3945.     maybe_refresh();
  3946.     getkey();
  3947.     check_abort();
  3948.     ungot_key = key;
  3949.     delete(point,point+1);
  3950.  
  3951.     /* Input unit number in recursive edit mode.
  3952.         Space, or <cr> exits.    */
  3953.     fort_tab[CTRL('J')] = find_index("exit-level");
  3954.     fort_tab[' '] = find_index("exit-level");
  3955.     fort_tab[CTRL('G')] = find_index("f-abort");
  3956.     reg_tab[CTRL('G')] = find_index("f-abort");
  3957.     recursive_edit();
  3958.     fort_tab[' '] = find_index("maybe-break-line");
  3959.  
  3960.     /* Grab the unit number if entered, and right justify */
  3961.     tag = point;
  3962.     re_search(-1,"[0123456789]*");
  3963.     if (point!=tag) {
  3964.         grab(point,tag,unit_no);
  3965.     }
  3966.     else{
  3967.         unit_no[0] = 0;
  3968.     }
  3969.  
  3970.     /* Query standard file name */
  3971.     if (search(1,"for*")) {
  3972.         delete(point,point-1);
  3973.         tag = point-3;
  3974.         bprintf("%.4s",unit_no);
  3975.         point = tag;
  3976.         say("Standard Filename?");
  3977.         major_mode = strsave("OPEN filename query");
  3978.         strcpy(mode, major_mode);
  3979.         maybe_refresh();
  3980.         getkey();
  3981.         if (key == CTRL('G'))
  3982.             error("Aborted.");
  3983.         if ((key == CTRL('H'))
  3984.             ||(toupper(key) == 'N')||(key == GREYBACK)) {
  3985.             if (search(1,"dat")) {
  3986.                 delete(tag,point);
  3987.                 /* Enter filename in recursive edit */
  3988.                 major_mode = strsave(
  3989.                     "OPEN file name (<cr> to exit)");
  3990.                 strcpy(mode, major_mode);
  3991.                 recursive_edit();
  3992.             }
  3993.         }
  3994.         else {
  3995.             delete(point,point+3);
  3996.             stuff("FOR");
  3997.             if (search(1,"dat")) {
  3998.                 delete(point-3,point);
  3999.                 stuff("DAT");
  4000.             }
  4001.         }
  4002.         say("");
  4003.     }
  4004.  
  4005.     /* Query status */
  4006.     if (search(1,"status")) {
  4007.         point -= 6;
  4008.         say("Status=New?");
  4009.         major_mode = strsave("OPEN status query");
  4010.         strcpy(mode,major_mode);
  4011.         maybe_refresh();
  4012.         getkey();
  4013.         if (key == CTRL('G'))
  4014.             error("Aborted.");
  4015.         delete(point,point+12);
  4016.         if ((key == CTRL('H'))
  4017.             ||(toupper(key) == 'N')||(key == GREYBACK)) {
  4018.             delete(point-1,point);
  4019.         }
  4020.         else
  4021.             stuff("STATUS='NEW'");
  4022.         say("");
  4023.     }
  4024.  
  4025.     /* Restore keys */
  4026.     major_mode = strsave("Fortran");
  4027.     make_mode();
  4028.     fort_tab[CTRL('J')] = orig_ret;
  4029.     reg_tab[CTRL('G')] = find_index("abort");
  4030.     fort_tab[CTRL('G')] = bell_key;
  4031.     check_abort();
  4032.     top_level = old_level;
  4033.  
  4034.     to_end_line();
  4035. }
  4036.  
  4037.  
  4038. fort_read() on fort_ext_tab[CTRL('r')]
  4039. {
  4040.     PREINDENT();
  4041.     stuff("READ (*,*) ");
  4042.  
  4043.     /* Input unit number */
  4044.     point -= 5;
  4045.     maybe_refresh();
  4046.     getkey();
  4047.     if (isdigit(key)) {
  4048.         delete(point,point+1);
  4049.         while (isdigit(key)) {
  4050.             insert(key);
  4051.             maybe_refresh();
  4052.             getkey();
  4053.         }
  4054.     }
  4055.     else {
  4056.         check_abort();
  4057.         ++point;
  4058.     }
  4059.  
  4060.     /* Input format line number */
  4061.     ++point;
  4062.     maybe_refresh();
  4063.     getkey();
  4064.     if (isdigit(key)) {
  4065.         delete(point,point+1);
  4066.         while (isdigit(key)) {
  4067.             insert(key);
  4068.             maybe_refresh();
  4069.             getkey();
  4070.         }
  4071.     }
  4072.     else {
  4073.         check_abort();
  4074.         ++point;
  4075.     }
  4076.  
  4077.     point += 2;
  4078. }
  4079.  
  4080.  
  4081. fort_write() on fort_ext_tab[CTRL('w')]
  4082. {
  4083.     PREINDENT();
  4084.     stuff("WRITE (*,*) ");
  4085.  
  4086.     /* Input unit number */
  4087.     point -= 5;
  4088.     maybe_refresh();
  4089.     getkey();
  4090.     if (isdigit(key)) {
  4091.         delete(point,point+1);
  4092.         while (isdigit(key)) {
  4093.             insert(key);
  4094.             maybe_refresh();
  4095.             getkey();
  4096.         }
  4097.     }
  4098.     else {
  4099.         check_abort();
  4100.         ++point;
  4101.     }
  4102.  
  4103.     /* Input format line number */
  4104.     ++point;
  4105.     maybe_refresh();
  4106.     getkey();
  4107.     if (isdigit(key)) {
  4108.         delete(point,point+1);
  4109.         while (isdigit(key)) {
  4110.             insert(key);
  4111.             maybe_refresh();
  4112.             getkey();
  4113.         }
  4114.     }
  4115.     else {
  4116.         check_abort();
  4117.         ++point;
  4118.     }
  4119.  
  4120.     point += 2;
  4121. }
  4122.  
  4123.  
  4124. /* Commands to prompt for and complete names of fort- routines */
  4125. /* Requires modified COMPLETE.E file */
  4126. /*
  4127. /char *fsub_match(s, start) 
  4128. /char *s;
  4129. /{
  4130. /int i;
  4131. /
  4132. /for (; i = name_match(s, start); start = 0)
  4133. /    switch (name_type(i)) {
  4134. /        case NT_COMMAND: case NT_SUBR:
  4135. /            return name_name(i);
  4136. /    }
  4137. /return 0;
  4138. /}
  4139. /
  4140. /get_fsub(res, pr)
  4141. /char *res, *pr;
  4142. /{
  4143. /strcpy(res,"fort-");
  4144. /comp_read(res, pr, fsub_match, 0);
  4145. /}
  4146. /
  4147. /get_fsub_index(pr)
  4148. /char *pr;
  4149. /{
  4150. /char fsub[80];
  4151. /int name_index;
  4152. /
  4153. /get_fsub(fsub, pr);
  4154. /name_index = find_index(fsub);
  4155. /if (name_index && (name_type(name_index) == NT_SUBR ||
  4156. /            name_type(name_index) == NT_COMMAND))
  4157. /    return name_index;
  4158. /error("There's no Fortran command named '%.50s'.",fsub);
  4159. /return 0;
  4160. /}
  4161. /
  4162. /command fort_named() on fort_tab[ALT(']')], fort_tab[FALT(2)]
  4163. /{
  4164. /char msg[40];
  4165. /int index;
  4166. /
  4167. /if (has_arg)
  4168. /    sprintf(msg, "%d Fortran Command: ", iter);
  4169. /else
  4170. /    sprintf(msg, "Fortran Command: ");
  4171. /if (index = get_fsub_index(msg))
  4172. /    do_command(index);
  4173. /}
  4174. */
  4175.  
  4176. when_loading()
  4177. {
  4178.     int i;
  4179.  
  4180.     fort_tab[CTRL(']')] = find_index("fort-ext-tab");
  4181.     for (i = 'A'; i <= 'Z'; i++) {
  4182.         if (fort_ext_tab[ALT(i)] <= 0)
  4183.             fort_ext_tab[ALT(i)] = find_index("case-indirect");
  4184.         if (fort_ext_tab[i] <= 0)
  4185.             fort_ext_tab[i] = find_index("case-indirect");
  4186.     }
  4187.     fort_ext_tab[CTRL('H')] = find_index("fort-delete-tab");
  4188. }
  4189. ******************************************************************
  4190. for_load.e follows
  4191. ******************************************************************
  4192. /************************************************************************
  4193. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  4194. *                                    *
  4195. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  4196. *                                    *
  4197. * Limited permission is hereby granted to reproduce and modify this    *
  4198. * copyrighted material provided that the resulting code is used only in    *
  4199. * conjunction with Lugaru products and that this notice is retained in    *
  4200. * any such reproduction or modification.                *
  4201. ************************************************************************/
  4202.  
  4203. /*          Developed by James S. Storey                                   */
  4204.  
  4205. #include "eel.h"
  4206.  
  4207. /* This mode auto-loads from files FOR_MODE and FOR_EXT */
  4208. #define FOR_MODE "for_mode"
  4209. #define FOR_EXT "for_ext"
  4210.  
  4211. /* Format buffer for FORTRAN programs.
  4212.     This command puts the current buffer in the Fortran mode,
  4213.     appropriate for editing programs written in Fortran.
  4214.     Command names are of the form fort-COMMAND.  A series of
  4215.     statement commands automatically insert a template for most
  4216.     Fortran statements.  These statement commands are bound to keys
  4217.     prefixed by the C-] key.
  4218.  
  4219.     By default, the find-file command automatically turns on
  4220.     Fortran mode for files with the extensions .f or .for. */
  4221.         
  4222. command fort_mode()
  4223. {
  4224.     char *_fort_tab = "fort-tab", *_ind_ptr = "fort-indenter";
  4225.     short *_fort_ptr;
  4226.  
  4227.     if (!find_index("fort-tab")) {
  4228.         sayput("Loading Fortran mode commands. . .");
  4229.         load_commands(FOR_MODE);
  4230.         load_commands(FOR_EXT);
  4231.         say("");
  4232.     }
  4233.     _fort_ptr=index_table(find_index(_fort_tab));
  4234.     mode_keys = _fort_ptr;
  4235.     major_mode = strsave("Fortran");
  4236.     make_mode();
  4237.     (short) indenter = find_index(_ind_ptr);
  4238.     auto_indent = 1;
  4239.     tab_size = 6;
  4240. }
  4241.  
  4242. /* make this the default mode for .f and .for files */
  4243. suffix_f()    { fort_mode(); }
  4244. suffix_for()    { fort_mode(); }
  4245. ******************************************************************
  4246. for_menu follows
  4247. ******************************************************************
  4248. ^B    block if    d    double prec.    l    logical
  4249. c    call        i    integer        ^O    open
  4250. a    character    ^E    else        p    program
  4251. A-c    common        e    elseif        ^R    read
  4252. j    complex        ^F    format        r    real
  4253. ^C    continue    f    function    s    subroutine
  4254. A-d    data        g    goto        ^W    write
  4255. ^D    do        ^I    if        
  4256. ******************************************************************
  4257. for_mode.e follows
  4258. ******************************************************************
  4259. /* Written by James S. Storey */
  4260.  
  4261. /* Subroutines and commands for Fortran mode.
  4262.     These commands are read in when Fortran mode is invoked for the 
  4263.     first time    */
  4264.  
  4265. #include "eel.h"
  4266.  
  4267. int structured = 1;    /* 1 indents to previous line, 0 indents to col 7 */
  4268. int Matchdelim = 1;    /* 1 for showing matching ')' */
  4269.  
  4270. keytable fort_tab;        /* key table for Fortran mode */
  4271.  
  4272. buffer short bell_key;
  4273.  
  4274. f_abort()
  4275. {
  4276.     fort_tab[BELL] = bell_key;
  4277.     reg_tab[BELL] = find_index("abort");
  4278.     if (recursion_level>0)
  4279.         exit_level();
  4280.     user_abort = 1;
  4281. }
  4282.  
  4283.  
  4284. /* Routine used by fort-cont and fort-indent to decide how to continue
  4285.  the line. */
  4286.  
  4287. fort_cont_indent()
  4288. {
  4289.     char cont_char;
  4290.     int eol = point, indent_col;
  4291.  
  4292.     to_begin_line();
  4293.     cont_char=curchar();
  4294.     if (index("*cC",cont_char)) {    /* Previous line was a comment */
  4295.         indent_col = 3;
  4296.         if (structured) {    /* find first darkspace past col 1 */
  4297.             ++point;    /* skip comment character */
  4298.             if ((re_search(1, "[^ \t]")) && (point <= eol)) {
  4299.                 /* set indentation to begn of darkspace */
  4300.                 indent_col = current_column() -1;
  4301.             }
  4302.         }
  4303.         point = eol+1;
  4304.         bprintf("%c  ",cont_char);
  4305.         to_column(indent_col);
  4306.     }
  4307.     else {                /* Previous line was a statement */
  4308.         indent_col = 6;
  4309.         if (structured) {    /* find first darkspace past col 1 */
  4310.             move_to_column(6);
  4311.             if ((re_search(1, "[^ \t]")) && (point <= eol)) {
  4312.                 /* set indentation to begn of darkspace */
  4313.                 indent_col = current_column() -1;
  4314.             }
  4315.         }
  4316.         point = eol+1;
  4317.         bprintf("     +");
  4318.         to_column(indent_col);
  4319.     }
  4320. }
  4321.  
  4322. /* fort-cont    Fortran continue current line.
  4323.     Continues current line on next line.  If the current line is
  4324.     blank, another blank line is inserted.  If the current line is
  4325.     a comment line, the comment character is copied to the next
  4326.     line and the line is indented to column 4. If the current line
  4327.     is a program line, the continuation character '+' is inserted
  4328.     in column 6 */
  4329.  
  4330. command fort_cont() on fort_tab[ALT('j')], fort_tab[CTRL(ALT('j'))]
  4331. {
  4332.     insert('\n');
  4333.     --point;
  4334.     fort_cont_indent();
  4335. }
  4336.  
  4337. /* fort-late-cont    This command makes an existing line into a
  4338.     continuation of the previous line. */
  4339.  
  4340. command fort_late_cont() /* on A-N-+ */
  4341. {
  4342.     int orig = point;
  4343.  
  4344.     move_to_column(6);
  4345.     if (current_column() < 6) {
  4346.         to_column(5);
  4347.         insert('+');
  4348.     }
  4349.     else {
  4350.         if (character(point-1) == '\t')
  4351.             orig += tab_size - 1;
  4352.         delete_hacking_tabs();
  4353.         insert('+');
  4354.         point = orig;
  4355.     }
  4356. }
  4357.  
  4358.  
  4359. /* command to toggle structured indentation */
  4360.  
  4361. command set_struct()
  4362. {
  4363.     structured = (has_arg? (iter != 0) : !structured);
  4364.     say(structured?"Structured indentation on" :
  4365.         "Structured indentation off");
  4366.     iter = 1;
  4367. }
  4368.  
  4369. /* fort-indenter    Indent newlines in Fortran mode.
  4370.     Called following a newline character.  If the newline is at the
  4371.     end of a line, the line is indented normally.  If the newline
  4372.     is the middle of a program line, the line is continued as in
  4373.     "fort-cont", Fortran continue current line.  
  4374.  
  4375.     Bugs: With auto-fill, it continues lines after a newline if the
  4376.     last character in the previous line is at the fill-column, and
  4377.     it does not continue lines if more than one space preceded the
  4378.     character which caused the auto-fill. */ 
  4379.  
  4380. fort_indenter()
  4381. {
  4382.     int orig = point;
  4383.  
  4384.     /* Check for newline at the end of a line, or followed by blanks */
  4385.  
  4386.     to_end_line();
  4387.     if (!re_search(-1, "[^ \t]") || point < orig) {
  4388.  
  4389.         /* Check for auto-return */
  4390.  
  4391.         point = orig-1;
  4392.         if ((current_column() < margin_right-1) || !(fill_mode)) {
  4393.             ++point;
  4394.             if (structured) {
  4395.                 indent_previous();
  4396.                 if (current_column() < 6)
  4397.                     to_column(6);
  4398.             }
  4399.             else
  4400.                 to_column(6);    /* indent to column 7 */
  4401.         }
  4402.         else
  4403.             /* Auto-return, continue previous line */
  4404.             fort_cont_indent();
  4405.     }
  4406.     else {
  4407.         point = orig-1;
  4408.         fort_cont_indent();
  4409.     }
  4410. }
  4411.  
  4412. /* backward-kill-spaces(back) Delete up to BACK spaces preceding point */
  4413.  
  4414. backward_kill_spaces(back)
  4415. int back;
  4416. {
  4417.     int orig = point;
  4418.  
  4419.     re_search(-1,"( )*");
  4420.     if (point <= orig-back) {
  4421.         point = orig;
  4422.         delete(point-back,point);
  4423.     }
  4424.     else {
  4425.         delete(point,orig);
  4426.     }
  4427. }
  4428.  
  4429. /* fort-tabify    Indent by half-tabs.
  4430.     If the point is in the current line's indentation, a half-tab is
  4431.     added to the indentation.  Otherwise, if the point is in columns
  4432.     1 to 6, whitespace is added out to column 6, or if the point is
  4433.     past column 6, a half-tab is added before the point.
  4434.  
  4435.     When adding half-tabs, if the point is preceded by 1/2 a tab or
  4436.     more spaces, the spaces following the last tab-stop are deleted
  4437.     and a tab is added.  Otherwise, spaces are added up to 1/2 a tab
  4438.     past the last tab stop. */
  4439.  
  4440. #define HALF_TAB tab_size/2
  4441.  
  4442. command fort_tabify() on fort_tab[CTRL('I')]
  4443. {
  4444.     int orig = point, excess, lack;
  4445.  
  4446.     /* skip leading blanks */
  4447.     to_begin_line();
  4448.     if (!re_search(1, "[^ \t]") || point > orig) { /* skip blanks */
  4449.         point = orig;
  4450.         to_indentation();
  4451.     }
  4452.     else                       /* restore point */
  4453.         point = orig;
  4454.  
  4455.     /* Tabify line */
  4456.     if (current_column() < 5 )     /* insert tab */
  4457.         to_column(6);
  4458.     else {                /* insert half-tab */
  4459.         excess = (current_column()%tab_size);
  4460.         lack = HALF_TAB-excess;
  4461.         if (lack > 0) {        /* between tab and half-tab stops */
  4462.             for (; lack-- > 0; insert(' ')) ;
  4463.         }
  4464.         else {            /* between half-tab and tab stops */
  4465.             backward_kill_spaces(excess);
  4466.             insert('\t');
  4467.         }
  4468.     }
  4469. }
  4470.  
  4471. /* fort-delete-tab    If at column 7, delete the label field.  Otherwise,
  4472.     Delete a half tab preceding the point, hacking full tabs. */
  4473.     
  4474.  
  4475. fort_delete_tab()  /* on fort_ext_tab[CTRL('H')] */
  4476. {
  4477.     int excess, i;
  4478.  
  4479.     if (current_column() == tab_size) {
  4480.         if (character(point-1) == '\t')
  4481.             delete(point-1,point);
  4482.         else
  4483.             backward_kill_spaces(tab_size);
  4484.         return;
  4485.     }
  4486.     /* Else */
  4487.     excess = (current_column()%tab_size);
  4488.     if (excess == 0) {        /* at a tab stop */
  4489.         if (character(point-1) == '\t') {
  4490.             /* delete previous tab, insert half tab */
  4491.             delete(point-1,point);
  4492.             for( i=1 ; i++ <=HALF_TAB ; insert(' ')) ;
  4493.         }
  4494.         else         /* delete to last non-space or half tab stop */
  4495.             backward_kill_spaces(HALF_TAB);
  4496.     }
  4497.     else  {
  4498.         if (excess <= HALF_TAB)        /* Between tab and half tab */
  4499.             backward_kill_spaces(excess);
  4500.         else                /* Between half tab and tab */
  4501.             backward_kill_spaces(excess-HALF_TAB);
  4502.     }
  4503. }
  4504.  
  4505. /* fort-merge    Fortran merge continuation with previous.
  4506.     Merges the current line with the previous, removing line numbers
  4507.     and continuation characters (if necessary) for statement lines,
  4508.     and removing the comment character for comment lines.  An error
  4509.     message is given if the command would merge a comment character
  4510.     onto the end of a statement character. */
  4511.  
  4512. command fort_merge() on fort_tab[ALT('^')]
  4513. {
  4514.     int orig = point, bol;
  4515.  
  4516.     to_begin_line();
  4517.     bol = point;
  4518.     if (index("*cC",curchar())) {    /* Merge continuation line */
  4519.         --point;
  4520.         to_begin_line();
  4521.         if (!index("*cC",curchar())) {  
  4522.             /* Error: Attempt to Merge with statement */
  4523.             say("Error: cannot merge continuation line with statement line");
  4524.             point = orig;
  4525.             return;
  4526.         }
  4527.         else {                
  4528.             if (orig = bol)
  4529.                 orig = bol-1;
  4530.             else
  4531.                 orig -= 2;
  4532.             delete(bol-1,bol+1);
  4533.         }
  4534.     }
  4535.     else {
  4536.         if (!search(1, "\t") || (point > bol+6)) { 
  4537.             /* No tabs in Col 1-6 */
  4538.             if (orig < bol+6)
  4539.                 orig = bol-1;  /* end of previous line */
  4540.             else
  4541.                 orig -= 7;     /* orig minus amount deleted */
  4542.             delete(bol-1,bol+6);
  4543.         }
  4544.         else {
  4545.             if (orig < point)
  4546.                 orig = bol-1;    /* end of previous line */
  4547.             else
  4548.                 orig -= point-bol+1;
  4549.                            /* orig minus amount deleted */
  4550.             delete(bol-1,point);
  4551.         }
  4552.     }
  4553.     point = orig;
  4554. }
  4555.  
  4556. /* fort-comment    Pad the current line with blanks out to column 80.
  4557.     This command allows end of line comments that will wrap to the
  4558.     next screen line. */
  4559.  
  4560. command fort_comment() on fort_tab[ALT(';')]
  4561. {
  4562.     int orig=point, col7;
  4563.  
  4564.     move_to_column(6);
  4565.     col7 = point;
  4566.     for (point = orig; point <= col7+72; insert(' '))
  4567.         ;
  4568. }
  4569.  
  4570. when_loading()
  4571. {
  4572.     int i;
  4573.  
  4574.     for (i = 'A'; i <= 'Z'; i++)
  4575.         if (fort_tab[ALT(i)] <= 0)
  4576.             fort_tab[ALT(i)] = find_index("case-indirect");
  4577.     if (Matchdelim)
  4578.         fort_tab[')'] = find_index("show-matching-delimiter");
  4579.     fort_tab[ALT('i')] = find_index("indent-under");
  4580.     fort_tab[CTRL('M')] = find_index("newline");
  4581.     fort_tab[CTRL('H')] = find_index("delete-hacking-tabs");
  4582.     keytran[NUMALT(GREYPLUS)] = NUMALT(GREYPLUS);
  4583.     fort_tab[NUMALT(GREYPLUS)] = (short) fort_late_cont;
  4584. }
  4585. ******************************************************************
  4586. for_pas.doc follows
  4587. ******************************************************************
  4588. Received: FROM SU-SIERRA.ARPA BY B.ISI.EDU WITH TCP ; 31 Oct 86 14:35:16 PST
  4589. Date: Fri 31 Oct 86 13:00:36-PST
  4590. From: James S. Storey <FAT.STOREY@Sierra.Stanford.EDU>
  4591. Subject: EEL code for Fortran and Pascal modes
  4592. To: info-ibmpc@B.ISI.EDU
  4593. Message-ID: <12251267181.17.FAT.STOREY@Sierra.Stanford.EDU>
  4594.  
  4595.  
  4596. I am sending a number of files which make up a Fortran and a Pascal mode
  4597. for Epsilon (I have V3.01).  The files are: FOR_LOAD.E, FOR_MODE.E, 
  4598. FOR_EXT.E, FOR_MENU, PAS_LOAD.E, PAS_MODE.E, PAS_EXT.E, and PAS_MENU.
  4599. I attempted to make them somewhat user friendly,
  4600. with some prompts and an on-line menu, but have not had time to document
  4601. everything, so the source code is the only complete description of what the
  4602. commands do.  This should be usable by anyone with a version of Epsilon
  4603. that supports EEL code, but will probably be most useful to people with
  4604. some familiarity of EEL, who can customize the code to their particular
  4605. whims.
  4606.  
  4607. Because I often use the process window, and like to have memory available,
  4608. I set up the commands to be read in only when a Fortran (or Pascal) program
  4609. is being edited, similar to the auto-load stuff on UNIX Emacs.  Thus, when
  4610. the commands are not used, they are not loaded.  The Fortran commands will be
  4611. auto-loaded whenever a file with the extension .f or .for is edited, and
  4612. the Pascal commands with .p or .pas.  In my system, I use a similar auto
  4613. loading for the C-mode, bufed, and dired commands, so my basic editor is
  4614. leaner than the standard configuration.
  4615.  
  4616. To set up the Fortran mode, the following files must be installed.  First,
  4617. the file FOR_LOAD.E must be compiled and loaded into the basic Epsilon.  I
  4618. suggest saving the state, rather than loading this file every time.  Next,
  4619. set up a subdirectory \epsilon\modes, and compile the files FOR_MODE.E and
  4620. FOR_EXT.E, with the *.B output in this subdirectory.  Also, copy the file
  4621. FOR_MENU into this subdirectory.  The file FOR_LOAD.E assumes that the
  4622. auto-load files are in the subdirectory "C:\EPSILON\MODES".  If a different
  4623. subdirectory will be used, lines 17 and 18 should be changed.  If the menu is
  4624. in a different subdirectory, change line 12 of FOR_EXT.E.  Similar steps will
  4625. set up the Pascal mode, using the PAS files instead of the FOR files.
  4626.  
  4627. There are two levels of complexity available.  The first takes care of
  4628. indenting and several other minor chores.  For the Fortran mode, this is in
  4629. the file FOR_MODE.  The more complex mode is a template system, setting up a
  4630. SUBROUTINE outline or a DO loop outline, for example.  These commands are in
  4631. the file FOR_EXT.  If this extension is not desired, the auto-load command
  4632. "fort_mode()" should be altered, deleting the line
  4633.  
  4634.         load_commands(FOR_EXT);
  4635.  
  4636. The organization of the Pascal mode is similar.  For the extension commands,
  4637. a new prefix key CRTL-] is defined.  This is intended to be analagous to the
  4638. prefix key CTRL-[.  The key sequence CTRL-] CTRL-] will call up an on-line
  4639. menu of the available completions of the CTRL-].
  4640.  
  4641. For those who are not put off by EEL code, I have implemented a command which
  4642. prompts for and completes the Fortran or Pascal mode commands.  However,
  4643. this requires modifying the source code of the file complete.e.  I did not
  4644. want these modes to be unusable by people who do not want to mess with 
  4645. the source code, so the files supplied have these commands - fort_named() and
  4646. pas_named() - as comments.  For the adventureous types, the following
  4647. modifications are needed.  First, remove the comment characters /* and */
  4648. surrounding the commands fsub_match(), get_fsub(), get_fsub_index(), and
  4649. fort_named() in FOR_EXT.E (similarly for the Pascal mode).  Next, in the
  4650. Epsilon source file COMPLETE.E, make the following two changes:
  4651.  
  4652. 1) Line 29: change
  4653.  
  4654.     int i = 0, j, num_match = 0;
  4655.  
  4656. to 
  4657.  
  4658.     int i = strlen(trystr), j, num_match = 0;
  4659.  
  4660. 2) Before every call to comp_read(), add the line 
  4661.  
  4662.     res[0]=0;
  4663.  
  4664. (8 occurances).  The first change allows a partially formed string to be
  4665. passed to comp_read, so the command completed will already have the prefix
  4666. "fort-" or "pas-".  The second change sets this initial string to NULL, so
  4667. the existing commands operate the same.  Once these changes are made, and
  4668. the whole thing is recompiled, the completion is invoked by ALT-].  The
  4669. command is similar to the ALT-X command, prompting for fortran or pascal
  4670. commands and completing.
  4671.  
  4672. I have used both formats for about 9 months now, and I think I have cleaned
  4673. up all the major bugs.  One minor bug that creeps in now and then is that
  4674. the new keytable associated with the prefix key CTRL-] seems to have bindings
  4675. which I never asked for.  So, when a key which is not defined is pressed,
  4676. odd things sometimes happen.  These have always been benign, and I have not
  4677. had the time to track down what is happening.  If anyone does manage to fix
  4678. this, I would appreciate it if they would let me know what the problem is.
  4679.  
  4680. I grant full right to anyone to use and modify these programs, subject to
  4681. to conditions of the modified Lugaru code in the *_LOAD.E files.  I would
  4682. appreciate hearing about any good extensions any bugs found, especially if
  4683. the cure has been found as well.  I will be losing this computer account as I
  4684. move into the wild world of industry, so if there are any questions or
  4685. suggestions, the best way to contact me is by U.S. mail, at
  4686.  
  4687.     James S. Storey
  4688.     Teknekron, C.S.D.
  4689.     2121 Allston Way
  4690.     Berkeley, CA, 94704
  4691.  
  4692.     (415) 548-4100
  4693.  
  4694. ******************************************************************
  4695. pascal.e follows
  4696. ******************************************************************
  4697.  
  4698. /* Modifications and extensions to the Epsilon editor.  Bruce K. Hillyer.
  4699.  * Portions of this code are covered by the following notice:
  4700.  */
  4701.  
  4702. /************************************************************************
  4703. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  4704. *                                    *
  4705. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  4706. *                                    *
  4707. * Limited permission is hereby granted to reproduce and modify this    *
  4708. * copyrighted material provided that the resulting code is used only in    *
  4709. * conjunction with Lugaru products and that this notice is retained in    *
  4710. * any such reproduction or modification.                *
  4711. ************************************************************************/
  4712.  
  4713.  
  4714.  
  4715. #include "eel.h"
  4716.  
  4717. /* find a line before this one that is less indented, line up with it.
  4718.  *
  4719.  * The use of this routine is as follows.  After typing a line of, say,
  4720.  * Pascal, press C-M to start a new line indented under the previous
  4721.  * line (see command indent_next() below).  Then you can press A-i to
  4722.  * unindent one nesting level. 
  4723.  */
  4724.  
  4725. command indent_less() on reg_tab[ALT('i')] {
  4726.  
  4727.     int orig_column;    /* indentation of original line           */
  4728.     int prev_indent;    /* indentation of some previous line       */
  4729.     int orig;        /* point of original indentation       */
  4730.     int prev_try;    /* to guarantee the loop keeps progressing */
  4731.  
  4732.     to_indentation();
  4733.     orig = point;
  4734.     orig_column = current_column();
  4735.  
  4736.     /* scan backwards for a line that is indented less */
  4737.     do {
  4738.         prev_try = point;
  4739.     to_begin_line();
  4740.     re_search(-1, "[^ \t\n]");    /* find previous non-blank line */
  4741.     to_indentation();
  4742.     prev_indent = current_column();
  4743.     } while (point < prev_try && prev_indent >= orig_column);
  4744.  
  4745.     point = orig;
  4746.     to_column((prev_indent < orig_column) ? prev_indent : 0);
  4747. }
  4748.  
  4749.  
  4750. /*  Go to the next line and then indent under
  4751.  */
  4752. command indent_next() on reg_tab[CTRL('M')]
  4753. {
  4754.     insert('\n');
  4755.     indent_under();
  4756. }
  4757.  
  4758.  
  4759. /* automatically display matching delimiters (toggle)
  4760.  */
  4761.  
  4762. command display_matching_parens()
  4763. {
  4764.  
  4765.     int display_matching_mode =
  4766.        (has_arg ? (iter != 0)
  4767.             : !(mode_keys[')'] == (short) show_matching_delimiter
  4768.             && mode_keys[']'] == (short) show_matching_delimiter
  4769.             && mode_keys['}'] == (short) show_matching_delimiter
  4770.                )
  4771.        );
  4772.     if (display_matching_mode) {
  4773.         say("Display matching )]}");
  4774.         mode_keys[')'] =
  4775.           mode_keys[']'] =
  4776.             mode_keys['}'] = (short) show_matching_delimiter;
  4777.     }
  4778.     else {
  4779.         say("No display matching )]}");
  4780.         mode_keys[')'] =
  4781.           mode_keys[']'] =
  4782.             mode_keys['}'] = 0;
  4783.     }
  4784.     iter = 1;
  4785. }
  4786. ******************************************************************
  4787. pas_ext.e follows
  4788. ******************************************************************
  4789. /* Written by James S. Storey */
  4790.  
  4791. /* Subroutines and commands in Pascal extension table (C-] table)
  4792.     These routines insert templates for Pascal statements. */
  4793.  
  4794. #include "eel.h"
  4795.  
  4796. #define MENU "pas_menu"
  4797.  
  4798. /* define an RE matching Pascal comments or whitespace, on same line */
  4799. #define P_SKIP "((%(%*([^*\n]|%*[^)\n])*%*%))|{([^}\n])*}|[ \t])*"
  4800.  
  4801. keytable pas_tab;    /* table for basic commands */
  4802. keytable pas_ext_tab;    /* table for extended commands */
  4803.  
  4804. buffer short bell_key;
  4805.  
  4806. int end_comments = 1;    /* end_comments=1 causes comments to be added to 
  4807.               end statements */
  4808.  
  4809. get_pas_menu()    /* make sure Pascal menu file is ready to go */
  4810. {    
  4811.     int exists = exist("-pas_menu");
  4812.     char *oldbuf = bufname;
  4813.         
  4814.  
  4815.     create("-pas_menu");
  4816.     bufname = "-pas_menu";
  4817.     if (!exists) {
  4818.         sayput("Loading Pascal menu file. . .");
  4819.         if (file_read(MENU, 1)) {
  4820.             bufname = oldbuf;
  4821.             delete_buffer("-menu");
  4822.             gripe("Can't find Pascal menu file %s", MENU);
  4823.             say("");
  4824.             return 0;
  4825.         }
  4826.         say("");
  4827.         point = 0;
  4828.         bufname = oldbuf;
  4829.         return 1;
  4830.     }
  4831.     else {
  4832.         if (size()==0) {
  4833.             bufname = oldbuf;
  4834.             delete_buffer("-pas_menu");
  4835.             gripe("No Pascal menu file %s", MENU);
  4836.             return 0;
  4837.         }
  4838.         point = 0;
  4839.         bufname = oldbuf;
  4840.         return 1;
  4841.     }
  4842. }
  4843.  
  4844. pas_menu() on pas_ext_tab[CTRL(']')], pas_ext_tab['?']
  4845. {
  4846.     sayput("C-] ");
  4847.     if (get_pas_menu())
  4848.         view_buffer("-pas_menu");
  4849.     check_abort();
  4850.     do {
  4851.         getkey();
  4852.     } while ((key == CTRL(']'))||(key == '?'));
  4853.     say("");
  4854.     do_again();
  4855. }
  4856.  
  4857. command set_comments()    /* Command to toggle end_comments */
  4858. {
  4859.     end_comments = (has_arg? (iter != 0) : !end_comments);
  4860.     say(end_comments?"End comments":"No end comments");
  4861.     iter = 1;
  4862. }
  4863.  
  4864.  
  4865.  
  4866. pas_begin() on pas_ext_tab[CTRL('B')]
  4867. {
  4868.     stuff("BEGIN\n");
  4869.     pas_tabify();
  4870.     insert('\n');
  4871.     pas_indenter();
  4872.     pas_tabify();
  4873.     stuff("END;");
  4874.     if (end_comments)
  4875.         stuff(" (* BEGIN *)");
  4876.     search(-1,"\n");
  4877. }
  4878.  
  4879. pas_end() on pas_ext_tab['e']
  4880. {
  4881.     stuff("END;\n");
  4882.     pas_indenter();
  4883. }
  4884.  
  4885. pas_program() on pas_ext_tab['p']
  4886. {
  4887.     jmp_buf this_level, *old_level = top_level;
  4888.     int i, tag1, tag2, diff1, diff2;
  4889.     char prog_name[40];
  4890.     short orig_ret = pas_tab[CTRL('J')],
  4891.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  4892.  
  4893.     /* Set up abort trap to unbind keys */
  4894.     top_level = &this_level;
  4895.     bell_key = pas_tab[CTRL('G')];
  4896.     if (setjmp(top_level)) {
  4897.         major_mode = strsave("Pascal");
  4898.         make_mode();
  4899.         say("Aborted.");
  4900.         pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  4901.         reg_tab[CTRL('G')] = find_index("abort");
  4902.         pas_tab[CTRL('G')] = bell_key;
  4903.         top_level = old_level;
  4904.         return;
  4905.     }
  4906.  
  4907.     /* Insert PROGRAM, BEGIN/END block, label with program name */
  4908.     bprintf("PROGRAM  ();\n\n");
  4909.     stuff("BEGIN");
  4910.     if (end_comments)
  4911.         stuff(" (*  *)");
  4912.     tag1 = point-3;
  4913.     insert('\n');
  4914.     pas_tabify();
  4915.     insert('\n');
  4916.     stuff("END.");
  4917.     if (end_comments) {
  4918.         stuff("  (*  *)");
  4919.         tag2 = point-3;
  4920.     }
  4921.     insert('\n');
  4922.     for (i=1; i++<=5; nl_reverse())
  4923.         ;
  4924.     point -= 4;
  4925.  
  4926.     /* tag BEGIN and END comments for inserting program name */
  4927.     if (end_comments) {
  4928.         diff1 = tag1-point;
  4929.         diff2 = tag2-point;
  4930.     }
  4931.  
  4932.     /* Input program name in recursive edit mode.
  4933.         <cr>, A-<cr> and space exit from recursion    */
  4934.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  4935.     pas_tab[CTRL('J')] = find_index("exit-level");
  4936.     pas_tab[CTRL('G')] = find_index("p-abort");
  4937.     reg_tab[CTRL('G')] = find_index("p-abort");
  4938.     pas_tab[' '] = find_index("exit-level");
  4939.     major_mode = strsave("PROGRAM name (<cr> to exit)");
  4940.     strcpy(mode, major_mode);
  4941.     recursive_edit();
  4942.     pas_tab[' '] = find_index("normal-character");
  4943.     pas_tab[CTRL('J')] = orig_ret;
  4944.     check_abort();
  4945.     
  4946.     /* Grab the program name and insert it in BEGIN and END comments */
  4947.     if (end_comments) {
  4948.         tag1 = point;
  4949.         backward_word();
  4950.         grab(point,tag1,prog_name);
  4951.         point = tag1+diff2;
  4952.         stuff(prog_name);
  4953.         point = tag1+diff1;
  4954.         stuff(prog_name);
  4955.         point = tag1+2;
  4956.     }
  4957.     
  4958.     /* Input parameters in recursive edit mode.  A-<cr> exits */
  4959.     major_mode = strsave("PROGRAM parameters (A-<cr> to exit)");
  4960.     strcpy(mode, major_mode);
  4961.     recursive_edit();
  4962.     check_abort();
  4963.  
  4964.     /* Set point to beginning of next block, and tag location */
  4965.     nl_forward();
  4966.     nl_forward();
  4967.     tag1 = point;
  4968.  
  4969.     /* Insert CONST declaration block, and delete if C-H is input */
  4970.     insert('\n');
  4971.     --point;
  4972.     stuff("CONST\n");
  4973.     pas_tabify();
  4974.     stuff(";\n");
  4975.     point -= 2;
  4976.     major_mode = strsave("PROGRAM CONST block (BACKSPACE to delete)");
  4977.     strcpy(mode, major_mode);
  4978.     maybe_refresh();
  4979.     getkey();
  4980.     if (key == CTRL('G'))
  4981.         error("Aborted.");
  4982.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  4983.         delete(tag1,point+3);
  4984.     }
  4985.     else {
  4986.         ungot_key = key;
  4987.         delete(point,point+1);
  4988.         major_mode = strsave("PROGRAM CONST block (A-<cr> to exit)");
  4989.         strcpy(mode, major_mode);
  4990.         recursive_edit();
  4991.         check_abort();
  4992.         nl_forward();
  4993.         nl_forward();
  4994.         tag1 = point;
  4995.     }
  4996.  
  4997.     /* Insert TYPE declaration block, and delete if C-H is input */
  4998.     insert('\n');
  4999.     --point;
  5000.     stuff("TYPE\n");
  5001.     pas_tabify();
  5002.     stuff(";\n");
  5003.     point -= 2;
  5004.     major_mode = strsave("PROGRAM TYPE block (BACKSPACE to delete)");
  5005.     strcpy(mode, major_mode);
  5006.     maybe_refresh();
  5007.     getkey();
  5008.     if (key == CTRL('G'))
  5009.         error("Aborted.");
  5010.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5011.         delete(tag1,point+3);
  5012.     }
  5013.     else {
  5014.         ungot_key = key;
  5015.         delete(point,point+1);
  5016.         major_mode = strsave("PROGRAM TYPE block (A-<cr> to exit)");
  5017.         strcpy(mode, major_mode);
  5018.         recursive_edit();
  5019.         check_abort();
  5020.         nl_forward();
  5021.         nl_forward();
  5022.         tag1 = point;
  5023.     }
  5024.  
  5025.     /* Insert VAR declaration block, and delete if C-H is input */
  5026.     insert('\n');
  5027.     --point;
  5028.     stuff("VAR\n");
  5029.     pas_tabify();
  5030.     stuff(";\n");
  5031.     point -= 2;
  5032.     major_mode = strsave("PROGRAM VAR block (BACKSPACE to delete)");
  5033.     strcpy(mode, major_mode);
  5034.     maybe_refresh();
  5035.     getkey();
  5036.     if (key == CTRL('G'))
  5037.         error("Aborted.");
  5038.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5039.         delete(tag1,point+3);
  5040.     }
  5041.     else {
  5042.         ungot_key = key;
  5043.         delete(point,point+1);
  5044.         major_mode = strsave("PROGRAM VAR block (A-<cr> to exit)");
  5045.         strcpy(mode, major_mode);
  5046.         recursive_edit();
  5047.         check_abort();
  5048.         nl_forward();
  5049.         nl_forward();
  5050.         tag1 = point;
  5051.     }
  5052.  
  5053.     /* Restore keys */
  5054.     major_mode = strsave("Pascal");
  5055.     make_mode();
  5056.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5057.     reg_tab[CTRL('G')] = find_index("abort");
  5058.     pas_tab[CTRL('G')] = bell_key;
  5059.     top_level = old_level;
  5060.  
  5061.     /* Move point to beginning of program body */
  5062.     nl_forward();
  5063.     to_end_line();
  5064. }
  5065.  
  5066. pas_var_param()
  5067. {
  5068.     stuff("VAR ");
  5069. }
  5070.  
  5071. pas_procedure() on pas_ext_tab[CTRL('P')]
  5072. {
  5073.     jmp_buf this_level, *old_level = top_level;
  5074.     int i, tag1, tag2, diff1, diff2, left = current_column();
  5075.     char proc_name[40];
  5076.     short orig_ret = pas_tab[CTRL('J')],
  5077.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5078.  
  5079.     /* Set up abort trap to unbind keys */
  5080.     top_level = &this_level;
  5081.     bell_key = pas_tab[CTRL('G')];
  5082.     if (setjmp(top_level)) {
  5083.         major_mode = strsave("Pascal");
  5084.         make_mode();
  5085.         say("Aborted.");
  5086.         pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5087.         reg_tab[CTRL('G')] = find_index("abort");
  5088.         pas_tab[CTRL('G')] = bell_key;
  5089.         top_level = old_level;
  5090.         return;
  5091.     }
  5092.  
  5093.     /* Insert PROCEDURE, BEGIN/END block, label with procedure name */
  5094.     bprintf("PROCEDURE  ();\n\n");
  5095.     to_column(left);
  5096.     stuff("BEGIN");
  5097.     if (end_comments)
  5098.         stuff(" (*  *)");
  5099.     tag1 = point-3;
  5100.     insert('\n');
  5101.     to_column(left);
  5102.     pas_tabify();
  5103.     insert('\n');
  5104.     to_column(left);
  5105.     stuff("END;");
  5106.     if (end_comments) {
  5107.         stuff("  (*  *)");
  5108.         tag2 = point-3;
  5109.     }
  5110.     insert('\n');
  5111.     for (i=1; i++<=5; nl_reverse())
  5112.         ;
  5113.     point -= 4;
  5114.  
  5115.     /* tag BEGIN and END comments for inserting procedure name */
  5116.     if (end_comments) {
  5117.         diff1 = tag1-point;
  5118.         diff2 = tag2-point;
  5119.     }
  5120.  
  5121.     /* Input procedure name in recursive edit mode.
  5122.         <cr>, A-<cr> and space exit from recursion    */
  5123.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5124.     pas_tab[CTRL('J')] = find_index("exit-level");
  5125.     pas_tab[' '] = find_index("exit-level");
  5126.     pas_tab[CTRL('G')] = find_index("p-abort");
  5127.     reg_tab[CTRL('G')] = find_index("p-abort");
  5128.     major_mode = strsave("PROCEDURE name (<cr> to exit)");
  5129.     strcpy(mode, major_mode);
  5130.     recursive_edit();
  5131.     pas_tab[' '] = find_index("normal-character");
  5132.     pas_tab[CTRL('J')] = orig_ret;
  5133.     check_abort();
  5134.  
  5135.     /* Grab the procedure name and insert it in BEGIN and END comments */
  5136.     tag1 = point;
  5137.     if (end_comments) {
  5138.         backward_word();
  5139.         grab(point,tag1,proc_name);
  5140.         point = tag1+diff2;
  5141.         stuff(proc_name);
  5142.         point = tag1+diff1;
  5143.         stuff(proc_name);
  5144.     }
  5145.     point = tag1+2;
  5146.     
  5147.     
  5148.     /* Input parameters in recursive edit mode.  A-<cr> exits,
  5149.         ^V inserts the string "VAR "        */
  5150.     pas_tab[CTRL('V')] = (short) pas_var_param;
  5151.     major_mode = strsave("PROCEDURE parameters (A-<cr> to exit)");
  5152.     strcpy(mode, major_mode);
  5153.     recursive_edit();
  5154.     pas_tab[CTRL('V')] = find_index("next-page");
  5155.     check_abort();
  5156.     
  5157.  
  5158.     /* Set point to beginning of next block, and tag location */
  5159.     nl_forward();
  5160.     nl_forward();
  5161.     tag1 = point;
  5162.  
  5163.     /* Insert TYPE declaration block, and delete if C-H is input */
  5164.     insert('\n');
  5165.     --point;
  5166.     to_column(left);
  5167.     stuff("TYPE\n");
  5168.     to_column(left);
  5169.     pas_tabify();
  5170.     stuff(";\n");
  5171.     point -= 2;
  5172.     major_mode = strsave("PROCEDURE TYPE block (BACKSPACE to delete)");
  5173.     strcpy(mode, major_mode);
  5174.     maybe_refresh();
  5175.     getkey();
  5176.     if (key == CTRL('G'))
  5177.         error("Aborted.");
  5178.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5179.         delete(tag1,point+3);
  5180.     }
  5181.     else {
  5182.         ungot_key = key;
  5183.         delete(point,point+1);
  5184.         major_mode = strsave("PROCEDURE TYPE block (A-<cr> to exit)");
  5185.         strcpy(mode, major_mode);
  5186.         recursive_edit();
  5187.         check_abort();
  5188.         nl_forward();
  5189.         nl_forward();
  5190.         tag1 = point;
  5191.     }
  5192.  
  5193.     /* Insert VAR declaration block, and delete if C-H is input */
  5194.     insert('\n');
  5195.     --point;
  5196.     to_column(left);
  5197.     stuff("VAR\n");
  5198.     to_column(left);
  5199.     pas_tabify();
  5200.     stuff(";\n");
  5201.     point -= 2;
  5202.     major_mode = strsave("PROCEDURE VAR block (BACKSPACE to delete)");
  5203.     strcpy(mode, major_mode);
  5204.     maybe_refresh();
  5205.     getkey();
  5206.     if (key == CTRL('G'))
  5207.         error("Aborted.");
  5208.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5209.         delete(tag1,point+3);
  5210.     }
  5211.     else {
  5212.         ungot_key = key;
  5213.         delete(point,point+1);
  5214.         major_mode = strsave("PROCEDURE VAR block (A-<cr> to exit)");
  5215.         strcpy(mode, major_mode);
  5216.         recursive_edit();
  5217.         check_abort();
  5218.         nl_forward();
  5219.         nl_forward();
  5220.         tag1 = point;
  5221.     }
  5222.  
  5223.     /* Restore keys */
  5224.     major_mode = strsave("Pascal");
  5225.     make_mode();
  5226.     reg_tab[CTRL('G')] = find_index("abort");
  5227.     pas_tab[CTRL('G')] = bell_key;
  5228.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5229.     top_level = old_level;
  5230.  
  5231.     /* Move point to beginning of procedure body */
  5232.     nl_forward();
  5233.     to_end_line();
  5234. }
  5235.  
  5236. pas_function() on pas_ext_tab['f']
  5237. {
  5238.     jmp_buf this_level, *old_level = top_level;
  5239.     int i, tag1, tag2, diff1, diff2, left = current_column();
  5240.     char func_name[40];
  5241.     short orig_ret = pas_tab[CTRL('J')],
  5242.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5243.  
  5244.     /* Set up abort trap to unbind keys */
  5245.     top_level = &this_level;
  5246.     bell_key = pas_tab[CTRL('G')];
  5247.     if (setjmp(top_level)) {
  5248.         major_mode = strsave("Pascal");
  5249.         make_mode();
  5250.         say("Aborted.");
  5251.         pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5252.         reg_tab[CTRL('G')] = find_index("abort");
  5253.         pas_tab[CTRL('G')] = bell_key;
  5254.         top_level = old_level;
  5255.         return;
  5256.     }
  5257.  
  5258.  
  5259.     /* Insert FUNCTION, BEGIN/END block, label with function name */
  5260.     bprintf("FUNCTION  (): ;\n\n");
  5261.     to_column(left);
  5262.     stuff("BEGIN");
  5263.     if (end_comments)
  5264.         stuff(" (*  *)");
  5265.     tag1 = point-3;
  5266.     insert('\n');
  5267.     to_column(left);
  5268.     pas_tabify();
  5269.     insert('\n');
  5270.     to_column(left);
  5271.     stuff("END;");
  5272.     if (end_comments) {
  5273.         stuff("  (*  *)");
  5274.         tag2 = point-3;
  5275.     }
  5276.     insert('\n');
  5277.     for (i=1; i++<=5; nl_reverse())
  5278.         ;
  5279.     point -= 6;
  5280.  
  5281.     /* tag BEGIN and END comments for inserting function name */
  5282.     if (end_comments) {
  5283.         diff1 = tag1-point;
  5284.         diff2 = tag2-point;
  5285.     }
  5286.  
  5287.     /* Input function name in recursive edit mode.
  5288.         <cr>, A-<cr> and space exit from recursion    */
  5289.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5290.     pas_tab[CTRL('J')] = find_index("exit-level");
  5291.     pas_tab[' '] = find_index("exit-level");
  5292.     pas_tab[CTRL('G')] = find_index("p-abort");
  5293.     reg_tab[CTRL('G')] = find_index("p-abort");
  5294.     major_mode = strsave("FUNCTION name (<cr> to exit)");
  5295.     strcpy(mode, major_mode);
  5296.     recursive_edit();
  5297.     pas_tab[' '] = find_index("normal-character");
  5298.     pas_tab[CTRL('J')] = orig_ret;
  5299.     check_abort();
  5300.  
  5301.     /* Grab the function name and insert it in BEGIN and END comments */
  5302.     tag1 = point;
  5303.     if (end_comments) {
  5304.         backward_word();
  5305.         grab(point,tag1,func_name);
  5306.         point = tag1+diff2;
  5307.         stuff(func_name);
  5308.         point = tag1+diff1;
  5309.         stuff(func_name);
  5310.     }
  5311.     point = tag1+2;
  5312.     
  5313.     /* Input parameters in recursive edit mode.  A-<cr> exits,
  5314.         ^V inserts the string "VAR "        */
  5315.     pas_tab[CTRL('V')] = (short) pas_var_param;
  5316.     major_mode = strsave("FUNCTION parameters (A-<cr> to exit)");
  5317.     strcpy(mode, major_mode);
  5318.     recursive_edit();
  5319.     pas_tab[CTRL('V')] = find_index("next-page");
  5320.     check_abort();
  5321.     
  5322.     /* Input function type in recursive edit mode.
  5323.         <cr> or A-<cr> exits. */
  5324.     search(1,":");
  5325.     ++point;
  5326.     pas_tab[CTRL('J')] = find_index("exit-level");
  5327.     major_mode = strsave("FUNCTION type (<cr> to exit)");
  5328.     strcpy(mode, major_mode);
  5329.     recursive_edit();
  5330.     pas_tab[CTRL('J')] = orig_ret;
  5331.     check_abort();
  5332.  
  5333.     /* Set point to beginning of next block, and tag location */
  5334.     nl_forward();
  5335.     nl_forward();
  5336.     tag1 = point;
  5337.  
  5338.     /* Insert TYPE declaration block, and delete if C-H is input */
  5339.     insert('\n');
  5340.     --point;
  5341.     to_column(left);
  5342.     stuff("TYPE\n");
  5343.     to_column(left);
  5344.     pas_tabify();
  5345.     stuff(";\n");
  5346.     point -= 2;
  5347.     major_mode = strsave("FUNCTION TYPE block (BACKSPACE to delete)");
  5348.     strcpy(mode, major_mode);
  5349.     maybe_refresh();
  5350.     getkey();
  5351.     if (key == CTRL('G'))
  5352.         error("Aborted.");
  5353.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5354.         delete(tag1,point+3);
  5355.     }
  5356.     else {
  5357.         ungot_key = key;
  5358.         delete(point,point+1);
  5359.         major_mode = strsave("FUNCTION TYPE block (A-<cr> to exit)");
  5360.         strcpy(mode, major_mode);
  5361.         recursive_edit();
  5362.         check_abort();
  5363.         nl_forward();
  5364.         nl_forward();
  5365.         tag1 = point;
  5366.     }
  5367.  
  5368.     /* Insert VAR declaration block, and delete if C-H is input */
  5369.     insert('\n');
  5370.     --point;
  5371.     to_column(left);
  5372.     stuff("VAR\n");
  5373.     to_column(left);
  5374.     pas_tabify();
  5375.     stuff(";\n");
  5376.     point -= 2;
  5377.     major_mode = strsave("FUNCTION VAR block (BACKSPACE to delete)");
  5378.     strcpy(mode, major_mode);
  5379.     maybe_refresh();
  5380.     getkey();
  5381.     if (key == CTRL('G'))
  5382.         error("Aborted.");
  5383.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5384.         delete(tag1,point+3);
  5385.     }
  5386.     else {
  5387.         ungot_key = key;
  5388.         delete(point,point+1);
  5389.         major_mode = strsave("FUNCTION VAR block (A-<cr> to exit)");
  5390.         strcpy(mode, major_mode);
  5391.         recursive_edit();
  5392.         check_abort();
  5393.         nl_forward();
  5394.         nl_forward();
  5395.         tag1 = point;
  5396.     }
  5397.  
  5398.     /* Restore keys */
  5399.     major_mode = strsave("Pascal");
  5400.     make_mode();
  5401.     reg_tab[CTRL('G')] = find_index("abort");
  5402.     pas_tab[CTRL('G')] = bell_key;
  5403.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5404.     top_level = old_level;
  5405.  
  5406.     /* Move point to beginning of function body */
  5407.     nl_forward();
  5408.     to_end_line();
  5409. }
  5410.  
  5411. pas_var() on pas_ext_tab[CTRL('V')]
  5412. {
  5413.     stuff("VAR\n");
  5414.     pas_indenter();
  5415.     pas_tabify();
  5416. }
  5417.  
  5418. pas_type() on pas_ext_tab[CTRL('T')]
  5419. {
  5420.     stuff("TYPE\n");
  5421.     pas_indenter();
  5422.     pas_tabify();
  5423. }
  5424.  
  5425. pas_record() on pas_ext_tab['r']
  5426. {
  5427.     int left ,exit;
  5428.  
  5429.     /* Insert RECORD */
  5430.     stuff("RECORD\n");
  5431.     point -= 7;
  5432.  
  5433.     /* Check for new indentation */
  5434.     exit = 0;
  5435.      say("Set indentation (TAB or BACKSPACE)");
  5436.     do {
  5437.         refresh();
  5438.         getkey();
  5439.         switch (key) {
  5440.             case CTRL('H') : ;
  5441.             case GREYBACK  : {
  5442.                 pas_delete_tab();
  5443.                 break;
  5444.             }
  5445.             case CTRL('I') : ;
  5446.             case GREYTAB   : {
  5447.                 pas_tabify();
  5448.                 break;
  5449.             }
  5450.             default : exit = 1;
  5451.         }
  5452.     } while (!exit);
  5453.     say("");
  5454.     check_abort();
  5455.     left = current_column();
  5456.  
  5457.     /* Insert END */
  5458.     nl_forward();
  5459.     to_column(left);
  5460.     pas_tabify();
  5461.     insert('\n');
  5462.     to_column(left);
  5463.     stuff("END;");
  5464.     if (end_comments)
  5465.         stuff(" (* RECORD *)");
  5466.     nl_reverse();
  5467.     insert(';');
  5468.     --point;
  5469.     maybe_refresh();
  5470.     getkey();
  5471.     check_abort();
  5472.     ungot_key = key;
  5473.     delete(point,point+1);
  5474. }
  5475.  
  5476.  
  5477. pas_while() on pas_ext_tab[CTRL('W')]
  5478. {
  5479.     int tag1,tag2;
  5480.     short orig_ret = pas_tab[CTRL('J')],
  5481.         orig_eq = pas_tab['='],
  5482.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5483.  
  5484.  
  5485.     bell_key = pas_tab[CTRL('G')];
  5486.  
  5487.     /* Insert WHILE DO */
  5488.     stuff("WHILE  DO\n");
  5489.     point -= 4;
  5490.  
  5491.     /* Input condition in recursive edit mode.  A-<cr> or <cr> exits */
  5492.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5493.     pas_tab['='] = find_index("normal-character");
  5494.     pas_tab[CTRL('J')] = find_index("exit-level");
  5495.     pas_tab[CTRL('G')] = find_index("p-abort");
  5496.     reg_tab[CTRL('G')] = find_index("p-abort");
  5497.     major_mode = strsave("WHILE condition (<cr> to exit)");
  5498.     strcpy(mode, major_mode);
  5499.     recursive_edit();
  5500.     major_mode = strsave("Pascal");
  5501.     make_mode();
  5502.     pas_tab[CTRL('J')] = orig_ret;
  5503.     pas_tab['='] = orig_eq;
  5504.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5505.     reg_tab[CTRL('G')] = find_index("abort");
  5506.     pas_tab[CTRL('G')] = bell_key;
  5507.     check_abort();
  5508.  
  5509.     /* Insert BEGIN/END pair, delete if CTRL('H') is entered */
  5510.     to_end_line();
  5511.     tag1 = point;
  5512.     stuff(" BEGIN");
  5513.     nl_forward();
  5514.     pas_indenter();
  5515.     pas_tabify();
  5516.     insert('\n');
  5517.     pas_indenter();
  5518.     pas_tabify();
  5519.     stuff("END;");
  5520.     if (end_comments)
  5521.         stuff(" (* WHILE *)");
  5522.     tag2 = point;
  5523.     nl_reverse();
  5524.     insert(';');
  5525.     --point;
  5526.     maybe_refresh();
  5527.     getkey();
  5528.     if (key == CTRL('G'))
  5529.         error("Aborted.");
  5530.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5531.         delete(point,tag2+1);
  5532.         delete(tag1,tag1+6);
  5533.     }
  5534.     else {
  5535.         ungot_key = key;
  5536.         delete(point,point+1);
  5537.     }
  5538. }
  5539.  
  5540. pas_for() on pas_ext_tab[CTRL('F')]
  5541. {
  5542.     jmp_buf this_level, *old_level = top_level;
  5543.     int tag1,tag2;
  5544.     short orig_ret = pas_tab[CTRL('J')],
  5545.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5546.  
  5547.     /* Set up abort trap to unbind keys */
  5548.     top_level = &this_level;
  5549.     bell_key = pas_tab[CTRL('G')];
  5550.     if (setjmp(top_level)) {
  5551.         major_mode = strsave("Pascal");
  5552.         make_mode();
  5553.         say("Aborted.");
  5554.         pas_tab[CTRL('J')] = orig_ret;
  5555.         pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5556.         reg_tab[CTRL('G')] = find_index("abort");
  5557.         pas_tab[CTRL('G')] = bell_key;
  5558.         top_level = old_level;
  5559.         return;
  5560.     }
  5561.  
  5562.     /* Insert FOR TO DO */
  5563.     stuff("FOR  :=  TO  DO\n");
  5564.     point -= 12;
  5565.  
  5566.     /* Input index in recursive edit mode.  A-<cr> or <cr> exits */
  5567.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5568.     pas_tab[CTRL('J')] = find_index("exit-level");
  5569.     pas_tab[CTRL('G')] = find_index("p-abort");
  5570.     reg_tab[CTRL('G')] = find_index("p-abort");
  5571.     major_mode = strsave("FOR index (<cr> to exit)");
  5572.     strcpy(mode, major_mode);
  5573.     recursive_edit();
  5574.     check_abort();
  5575.  
  5576.     /* find ":=" on this line */
  5577.     to_begin_line();
  5578.     search(1,":=");
  5579.  
  5580.     /* Input start in recursive edit mode.  A-<cr> or <cr> exits */
  5581.     ++point;
  5582.     major_mode = strsave("FOR start (<cr> to exit)");
  5583.     strcpy(mode, major_mode);
  5584.     recursive_edit();
  5585.     check_abort();
  5586.     
  5587.     /* Change TO to DOWNTO on 'd' or 'D' */
  5588.     re_search(1,"( )*");
  5589.     stuff("down");
  5590.     point -= 4;
  5591.     major_mode = strsave("FOR downTO (d for DOWNTO)");
  5592.     strcpy(mode, major_mode);
  5593.     maybe_refresh();
  5594.     delete(point,point+4);
  5595.     getkey();
  5596.     if (key == CTRL('G'))
  5597.         error("Aborted.");
  5598.     if (toupper(key) == 'D')
  5599.         stuff("DOWN");
  5600.  
  5601.     /* Input end in recursive edit mode.  A-<cr> or <cr> exits */
  5602.     point += 3;
  5603.     major_mode = strsave("FOR end (<cr> to exit)");
  5604.     strcpy(mode, major_mode);
  5605.     recursive_edit();
  5606.     pas_tab[CTRL('J')] = orig_ret;
  5607.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5608.     reg_tab[CTRL('G')] = find_index("abort");
  5609.     pas_tab[CTRL('G')] = bell_key;
  5610.     top_level = old_level;
  5611.     check_abort();
  5612.  
  5613.     /* Insert BEGIN/END pair, delete if CTRL('H') is entered */
  5614.     to_end_line();
  5615.     tag1 = point;
  5616.     stuff(" BEGIN");
  5617.     nl_forward();
  5618.     pas_indenter();
  5619.     pas_tabify();
  5620.     insert('\n');
  5621.     pas_indenter();
  5622.     pas_tabify();
  5623.     stuff("END;");
  5624.     if (end_comments)
  5625.         stuff(" (* FOR *)");
  5626.     tag2 = point;
  5627.     nl_reverse();
  5628.     insert(';');
  5629.     --point;
  5630.     major_mode = strsave("FOR body (BACKSPACE to delete)");
  5631.     strcpy(mode, major_mode);
  5632.     maybe_refresh();
  5633.     getkey();
  5634.     if (key == CTRL('G'))
  5635.         error("Aborted.");
  5636.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5637.         delete(point,tag2+1);
  5638.         delete(tag1,tag1+6);
  5639.     }
  5640.     else {
  5641.         ungot_key = key;
  5642.         delete(point,point+1);
  5643.     }
  5644.     major_mode = strsave("Pascal");
  5645.     make_mode();
  5646. }
  5647.  
  5648. pas_with() on pas_ext_tab['w']
  5649. {
  5650.     int tag1,tag2;
  5651.     short orig_ret = pas_tab[CTRL('J')],
  5652.         orig_eq = pas_tab['='],
  5653.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5654.  
  5655.     bell_key = pas_tab[CTRL('G')];
  5656.  
  5657.     /* Insert WITH DO */
  5658.     stuff("WITH  DO\n");
  5659.     point -= 4;
  5660.  
  5661.     /* Input condition in recursive edit mode.  A-<cr> or <cr> exits */
  5662.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5663.     pas_tab['='] = find_index("normal-character");
  5664.     pas_tab[CTRL('J')] = find_index("exit-level");
  5665.     pas_tab[CTRL('G')] = find_index("p-abort");
  5666.     reg_tab[CTRL('G')] = find_index("p-abort");
  5667.     major_mode = strsave("WHILE condition (<cr> to exit)");
  5668.     strcpy(mode, major_mode);
  5669.     recursive_edit();
  5670.     major_mode = strsave("Pascal");
  5671.     make_mode();
  5672.     pas_tab[CTRL('J')] = orig_ret;
  5673.     pas_tab['='] = orig_eq;
  5674.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5675.     reg_tab[CTRL('G')] = find_index("abort");
  5676.     pas_tab[CTRL('G')] = bell_key;
  5677.     check_abort();
  5678.  
  5679.     /* Insert BEGIN/END pair, delete if CTRL('H') is entered */
  5680.     to_end_line();
  5681.     tag1 = point;
  5682.     stuff(" BEGIN");
  5683.     nl_forward();
  5684.     pas_indenter();
  5685.     pas_tabify();
  5686.     insert('\n');
  5687.     pas_indenter();
  5688.     pas_tabify();
  5689.     stuff("END;");
  5690.     if (end_comments)
  5691.         stuff(" (* WITH *)");
  5692.     tag2 = point;
  5693.     nl_reverse();
  5694.     insert(';');
  5695.     --point;
  5696.     maybe_refresh();
  5697.     getkey();
  5698.     if (key == CTRL('G'))
  5699.         error("Aborted.");
  5700.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5701.         delete(point,tag2+1);
  5702.         delete(tag1,tag1+6);
  5703.     }
  5704.     else {
  5705.         ungot_key = key;
  5706.         delete(point,point+1);
  5707.     }
  5708. }
  5709.  
  5710. pas_if() on pas_ext_tab[CTRL('I')]
  5711. {
  5712.     int tag1,tag2;
  5713.     short orig_ret = pas_tab[CTRL('J')],
  5714.         orig_eq = pas_tab['='],
  5715.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5716.  
  5717.     bell_key = pas_tab[CTRL('G')];
  5718.  
  5719.     /* Insert IF THEN */
  5720.     stuff("IF  THEN\n");
  5721.     point -= 6;
  5722.  
  5723.     /* Input condition in recursive edit mode.  A-<cr> or <cr> exits */
  5724.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5725.     pas_tab['='] = find_index("normal-character");
  5726.     pas_tab[CTRL('J')] = find_index("exit-level");
  5727.     pas_tab[CTRL('G')] = find_index("p-abort");
  5728.     reg_tab[CTRL('G')] = find_index("p-abort");
  5729.     major_mode = strsave("IF condition (<cr> to exit)");
  5730.     strcpy(mode, major_mode);
  5731.     recursive_edit();
  5732.     major_mode = strsave("Pascal");
  5733.     make_mode();
  5734.     pas_tab[CTRL('J')] = orig_ret;
  5735.     pas_tab['='] = orig_eq;
  5736.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5737.     reg_tab[CTRL('G')] = find_index("abort");
  5738.     pas_tab[CTRL('G')] = bell_key;
  5739.     check_abort();
  5740.  
  5741.     /* Insert BEGIN/END pair, delete if CTRL('H') is entered */
  5742.     to_end_line();
  5743.     tag1 = point;
  5744.     stuff(" BEGIN");
  5745.     nl_forward();
  5746.     pas_indenter();
  5747.     pas_tabify();
  5748.     insert('\n');
  5749.     pas_indenter();
  5750.     pas_tabify();
  5751.     stuff("END;");
  5752.     if (end_comments)
  5753.         stuff(" (* THEN *)");
  5754.     tag2 = point;
  5755.     nl_reverse();
  5756.     insert(';');
  5757.     --point;
  5758.     maybe_refresh();
  5759.     getkey();
  5760.     if (key == CTRL('G'))
  5761.         error("Aborted.");
  5762.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5763.         delete(point,tag2+1);
  5764.         delete(tag1,tag1+6);
  5765.     }
  5766.     else {
  5767.         ungot_key = key;
  5768.         delete(point,point+1);
  5769.     }
  5770. }
  5771.  
  5772. pas_else() on pas_ext_tab[CTRL('E')]
  5773. {
  5774.     int tag1,tag2;
  5775.     short exit;
  5776.  
  5777.     /* delete half-tab */
  5778.     pas_delete_tab();
  5779.  
  5780.     /* Insert ELSE */
  5781.     stuff("ELSE\n");
  5782.  
  5783.     /* Delete ; on previous line */
  5784.     --point;
  5785.     nl_reverse();
  5786.     re_search(-1,P_SKIP);
  5787.     if (character(point-1) == ';')
  5788.         delete(point-1,point);
  5789.     nl_forward();
  5790.     nl_forward();
  5791.     point -= 5;
  5792.  
  5793.     /* Check for new indentation */
  5794.     exit = 0;
  5795.     say("Set indentation (TAB or BACKSPACE)");
  5796.     do {
  5797.         refresh();
  5798.         getkey();
  5799.         switch (key) {
  5800.             case CTRL('H') : ;
  5801.             case GREYBACK  : {
  5802.                 pas_delete_tab();
  5803.                 break;
  5804.             }
  5805.             case CTRL('I') : ;
  5806.             case GREYTAB   : {
  5807.                 pas_tabify();
  5808.                 break;
  5809.             }
  5810.             default : exit = 1;
  5811.         }
  5812.     } while (!exit);
  5813.     say("");
  5814.     check_abort();
  5815.  
  5816.     /* Insert BEGIN/END pair, delete if CTRL('H') is entered */
  5817.     to_end_line();
  5818.     tag1 = point;
  5819.     stuff(" BEGIN");
  5820.     nl_forward();
  5821.     pas_indenter();
  5822.     pas_tabify();
  5823.     insert('\n');
  5824.     pas_indenter();
  5825.     pas_tabify();
  5826.     stuff("END;");
  5827.     if (end_comments)
  5828.         stuff(" (* ELSE *)");
  5829.     tag2 = point;
  5830.     nl_reverse();
  5831.     insert(';');
  5832.     --point;
  5833.     maybe_refresh();
  5834.     getkey();
  5835.     check_abort();
  5836.     if ((key == CTRL('H'))||(key == GREYBACK)) {
  5837.         delete(point,tag2+1);
  5838.         delete(tag1,tag1+6);
  5839.     }
  5840.     else {
  5841.         ungot_key = key;
  5842.         delete(point,point+1);
  5843.     }
  5844. }
  5845.  
  5846. pas_repeat() on pas_ext_tab[CTRL('R')]
  5847. {
  5848.     short exit, orig_ret = pas_tab[CTRL('J')],
  5849.         orig_eq = pas_tab['='],
  5850.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5851.  
  5852.     bell_key = pas_tab[CTRL('G')];
  5853.  
  5854.     /* Insert REPEAT */
  5855.     stuff("REPEAT\n");
  5856.     point -= 7;
  5857.  
  5858.     /* Check for new indentation */
  5859.     exit = 0;
  5860.     say("Set indentation (TAB or BACKSPACE)");
  5861.     do {
  5862.         refresh();
  5863.         getkey();
  5864.         switch (key) {
  5865.             case CTRL('H') : ;
  5866.             case GREYBACK  : {
  5867.                 pas_delete_tab();
  5868.                 break;
  5869.             }
  5870.             case CTRL('I') : ;
  5871.             case GREYTAB   : {
  5872.                 pas_tabify();
  5873.                 break;
  5874.             }
  5875.             default : exit = 1;
  5876.         }
  5877.     } while (!exit);
  5878.     say("");
  5879.     check_abort();
  5880.  
  5881.     /* Insert UNTIL */
  5882.     nl_forward();
  5883.     insert('\n');
  5884.     pas_indenter();
  5885.     stuff("UNTIL ;");
  5886.     --point;
  5887.  
  5888.     /* Input condition in recursive edit mode.  A-<cr> or <cr> exits */
  5889.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5890.     pas_tab['='] = find_index("normal-character");
  5891.     pas_tab[CTRL('J')] = find_index("exit-level");
  5892.     pas_tab[CTRL('G')] = find_index("p-abort");
  5893.     reg_tab[CTRL('G')] = find_index("p-abort");
  5894.     major_mode = strsave("UNTIL condition (<cr> to exit)");
  5895.     strcpy(mode, major_mode);
  5896.     recursive_edit();
  5897.     major_mode = strsave("Pascal");
  5898.     make_mode();
  5899.     pas_tab[CTRL('J')] = orig_ret;
  5900.     pas_tab['='] = orig_eq;
  5901.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5902.     reg_tab[CTRL('G')] = find_index("abort");
  5903.     pas_tab[CTRL('G')] = bell_key;
  5904.     check_abort();
  5905.  
  5906.     /* go to indentation of loop body */
  5907.     nl_reverse();
  5908.     pas_indenter();
  5909.     pas_tabify();
  5910. }
  5911.  
  5912. pas_case() on pas_ext_tab[CTRL('C')]
  5913. {
  5914.     short orig_ret = pas_tab[CTRL('J')],
  5915.         orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  5916.  
  5917.     bell_key = pas_tab[CTRL('G')];
  5918.  
  5919.     /* Insert CASE OF */
  5920.     stuff("CASE  OF\n");
  5921.     point -= 4;
  5922.  
  5923.     /* Input case expression in recursive edit mode.
  5924.         A-<cr> or <cr> exits             */
  5925.     pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  5926.     pas_tab[CTRL('J')] = find_index("exit-level");
  5927.     pas_tab[CTRL('G')] = find_index("p-abort");
  5928.     reg_tab[CTRL('G')] = find_index("p-abort");
  5929.     major_mode = strsave("CASE expression (<cr> to exit)");
  5930.     strcpy(mode, major_mode);
  5931.     recursive_edit();
  5932.     major_mode = strsave("Pascal");
  5933.     make_mode();
  5934.     reg_tab[CTRL('G')] = find_index("abort");
  5935.     pas_tab[CTRL('G')] = bell_key;
  5936.     pas_tab[CTRL('J')] = orig_ret;
  5937.     pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  5938.     check_abort();
  5939.  
  5940.     /* Insert END */
  5941.     to_end_line();
  5942.     nl_forward();
  5943.     pas_indenter();
  5944.     pas_tabify();
  5945.     insert('\n');
  5946.     pas_indenter();
  5947.     pas_tabify();
  5948.     stuff("END;");
  5949.     if (end_comments)
  5950.         stuff(" (* CASE *)");
  5951.     nl_reverse();
  5952.     insert(' :');
  5953.     point-=2;
  5954. }
  5955.  
  5956. /* Commands to prompt for and complete names of pas- routines */
  5957. /* Requires modified COMPLETE.E file */
  5958. /*
  5959. /char *psub_match(s, start) 
  5960. /char *s;
  5961. /{
  5962. /int i;
  5963. /
  5964. /for (; i = name_match(s, start); start = 0)
  5965. /    switch (name_type(i)) {
  5966. /        case NT_COMMAND: case NT_SUBR:
  5967. /            return name_name(i);
  5968. /    }
  5969. /return 0;
  5970. /}
  5971. /
  5972. /get_psub(res, pr)
  5973. /char *res, *pr;
  5974. /{
  5975. /strcpy(res,"pas-");
  5976. /comp_read(res, pr, psub_match, 0);
  5977. /}
  5978. /
  5979. /get_psub_index(pr)
  5980. /char *pr;
  5981. /{
  5982. /char psub[80];
  5983. /int name_index;
  5984. /
  5985. /get_psub(psub, pr);
  5986. /name_index = find_index(psub);
  5987. /if (name_index && (name_type(name_index) == NT_SUBR ||
  5988. /            name_type(name_index) == NT_COMMAND))
  5989. /    return name_index;
  5990. /error("There's no Pascal command named '%.50s'.",psub);
  5991. /return 0;
  5992. /}
  5993. /
  5994. /command pas_named() on pas_tab[ALT(']')], pas_tab[FALT(2)]
  5995. /{
  5996. /char msg[40];
  5997. /int index;
  5998. /
  5999. /if (has_arg)
  6000. /    sprintf(msg, "%d Pascal Command: ", iter);
  6001. /else
  6002. /    sprintf(msg, "Pascal Command: ");
  6003. /if (index = get_psub_index(msg))
  6004. /    do_command(index);
  6005. /}
  6006. */
  6007.  
  6008. when_loading()
  6009. {
  6010.     int i;
  6011.  
  6012.     pas_tab[CTRL(']')] = find_index("pas-ext-tab");
  6013.     for (i = 'A'; i <= 'Z'; i++) {
  6014.         if (pas_ext_tab[ALT(i)] <= 0)
  6015.             pas_ext_tab[ALT(i)] = find_index("case-indirect");
  6016.         if (pas_ext_tab[i] <= 0)
  6017.             pas_ext_tab[i] = find_index("case-indirect");
  6018.     }
  6019.     pas_ext_tab[CTRL('H')] = find_index("pas-delete-tab");
  6020. }
  6021. ******************************************************************
  6022. pas_load.e follows
  6023. ******************************************************************
  6024. /************************************************************************
  6025. * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. *
  6026. *                                    *
  6027. *     Copyright (C) 1985 Lugaru Software Ltd.  All rights reserved.    *
  6028. *                                    *
  6029. * Limited permission is hereby granted to reproduce and modify this    *
  6030. * copyrighted material provided that the resulting code is used only in    *
  6031. * conjunction with Lugaru products and that this notice is retained in    *
  6032. * any such reproduction or modification.                *
  6033. ************************************************************************/
  6034.  
  6035. /*          Developed by James S. Storey                                   */
  6036.  
  6037. #include "eel.h"
  6038.  
  6039. /* This mode auto-loads from files PAS_MODE and PAS_EXT */
  6040. #define PAS_MODE "pas_mode"
  6041. #define PAS_EXT "pas_ext"
  6042.  
  6043. /* Format buffer for Pascal programs.
  6044.     This command puts the current buffer in the Pascal mode,
  6045.     appropriate for editing programs written in Pascal.
  6046.     Command names are of the form pas-COMMAND.  A series of
  6047.     statement commands automatically insert a template for most
  6048.     Pascal statements.  These statement commands are bound to keys
  6049.     prefixed by the C-] key.
  6050.  
  6051.     By default, the find-file command automatically turns on
  6052.     Pascal mode for files with the extensions .p or .pas. */
  6053.  
  6054.         
  6055. command pas_mode()
  6056. {
  6057.     char *_pas_tab = "pas-tab", *_ind_ptr = "pas-indenter";
  6058.     short *_pas_ptr;
  6059.  
  6060.     if (!find_index("pas-tab")) {
  6061.         sayput("Loading Pascal mode commands. . .");
  6062.         load_commands(PAS_MODE);
  6063.         load_commands(PAS_EXT);
  6064.         say("");
  6065.     }
  6066.     _pas_ptr=index_table(find_index(_pas_tab));
  6067.     mode_keys = _pas_ptr;
  6068.     major_mode = strsave("Pascal");
  6069.     make_mode();
  6070.     (short) indenter = find_index(_ind_ptr);
  6071.     auto_indent = 1;
  6072. }
  6073.  
  6074. /* make this the default mode for .p and .pas files */
  6075. suffix_p()    { pas_mode(); }
  6076. suffix_pas()    { pas_mode(); }
  6077. ******************************************************************
  6078. pas_menu follows
  6079. ******************************************************************
  6080. ^B    begin        ^H    del tabs    ^T    type
  6081. ^C    case        ^I    if        w    with        
  6082. ^E    else        ^P    procedure    ^W    while        
  6083. e    end        p    program        ^V    var         
  6084. ^F    for        r    record        
  6085. f    function    ^R    repeat        
  6086. ******************************************************************
  6087. pas_mode.e follows
  6088. ******************************************************************
  6089. /* Written by James S. Storey */
  6090.  
  6091. /* Subroutines and commands for Pascal mode.
  6092.     These commands are read in when Pascal mode is invoked for the 
  6093.     first time    */
  6094.  
  6095. #include "eel.h"
  6096.  
  6097. /* define an RE matching Pascal comments or whitespace */
  6098. #define P_LSKIP "((%(%*([^*]|%*[^)])*%*%))|{([^}])*}|[ \t\n])*"
  6099.  
  6100. /* define an RE matching Pascal comments or whitespace, on same line */
  6101. #define P_SKIP "((%(%*([^*\n]|%*[^)\n])*%*%))|{([^}\n])*}|[ \t])*"
  6102.  
  6103. int Matchdelim = 1;    /* 1 for showing matching ')' */
  6104.  
  6105. keytable pas_tab;        /* key table for Pascal mode */
  6106.  
  6107. buffer short bell_key;
  6108.  
  6109. p_abort()
  6110. {
  6111.     pas_tab[BELL] = bell_key;
  6112.     reg_tab[BELL] = find_index("abort");
  6113.     if (recursion_level>0)
  6114.         exit_level();
  6115.     user_abort = 1;
  6116. }
  6117.  
  6118.  
  6119. /* backward-kill-spaces(back) Delete up to BACK spaces preceding point */
  6120.  
  6121. backward_kill_spaces(back)
  6122. int back;
  6123. {
  6124.     int orig = point;
  6125.  
  6126.     re_search(-1,"( )*");
  6127.     if (point <= orig-back) {
  6128.         point = orig;
  6129.         delete(point-back,point);
  6130.     }
  6131.     else {
  6132.         delete(point,orig);
  6133.     }
  6134. }
  6135.  
  6136. /* pas-tabify    Indent by half-tabs.
  6137.     If the point is in the current line's indentation, a half-tab is
  6138.     added to the indentation.  Otherwise, a half-tab is added before
  6139.     the point.
  6140.  
  6141.     When adding half-tabs, if the point is preceded by 1/2 a tab or
  6142.     more spaces, the spaces following the last tab-stop are deleted
  6143.     and a tab is added.  Otherwise, spaces are added up to 1/2 a tab
  6144.     past the last tab stop. */
  6145.  
  6146. #define HALF_TAB tab_size/2
  6147.     
  6148. command pas_tabify() on pas_tab[CTRL('I')]
  6149. {
  6150.     int orig = point, excess, lack;
  6151.  
  6152.     /* skip leading blanks */
  6153.     to_begin_line();
  6154.     if (!re_search(1, "[^ \t]") || point > orig) { /* skip blanks */
  6155.         point = orig;
  6156.         to_indentation();
  6157.     }
  6158.     else                       /* restore point */
  6159.         point = orig;
  6160.  
  6161.     /* Insert half tab */
  6162.     excess = (current_column()%tab_size);
  6163.     lack = HALF_TAB-excess;
  6164.     if (lack > 0) {        /* between tab and half-tab stops */
  6165.         for (; lack-- > 0; insert(' ')) ;
  6166.     }
  6167.     else {            /* between half-tab and tab stops */
  6168.         backward_kill_spaces(excess);
  6169.         insert('\t');
  6170.     }
  6171. }
  6172.  
  6173. /* pas-delete-tab    Delete a half tab preceding the point, hacking full
  6174.     tabs. */
  6175.  
  6176. pas_delete_tab()  /* on pas_ext_tab[CTRL('H')] */
  6177. {
  6178.     int excess, i;
  6179.  
  6180.     excess = (current_column()%tab_size);
  6181.     if (excess == 0) {        /* at a tab stop */
  6182.         if (character(point-1) == '\t') {
  6183.             /* delete previous tab, insert half tab */
  6184.             delete(point-1,point);
  6185.             for( i=1 ; i++ <=HALF_TAB ; insert(' ')) ;
  6186.         }
  6187.         else         /* delete to last non-space or half tab stop */
  6188.             backward_kill_spaces(HALF_TAB);
  6189.     }
  6190.     else  {
  6191.         if (excess <= HALF_TAB)        /* Between tab and half tab */
  6192.             backward_kill_spaces(excess);
  6193.         else                /* Between half tab and tab */
  6194.             backward_kill_spaces(excess-HALF_TAB);
  6195.     }
  6196. }
  6197.  
  6198.  
  6199. /* pas-comment    Insert a pascal comment. */
  6200.  
  6201. command pas_comment() on pas_tab[ALT(';')]
  6202. {
  6203. #define L_COMMENT  "(*"
  6204. #define R_COMMENT  "*)"
  6205.  
  6206.     int com_size;
  6207.     short orig_alt_ret = pas_tab[CTRL(ALT('j'))];
  6208.  
  6209.     bell_key = pas_tab[BELL];
  6210.  
  6211.     com_size = strlen(R_COMMENT);
  6212.     bprintf("%s  %s",L_COMMENT,R_COMMENT);
  6213.     point -= com_size+1;
  6214.     major_mode = strsave("COMMENT body (BACKSPACE to delete)");
  6215.     strcpy(mode, major_mode);
  6216.     maybe_refresh();
  6217.     getkey();
  6218.     if (((key == CTRL('H'))||(key == GREYBACK))||(key == CTRL('G'))) {
  6219.         delete(point-com_size-1,point+com_size+1);
  6220.         major_mode = strsave("Pascal");
  6221.         strcpy(mode, major_mode);
  6222.     }
  6223.     else {
  6224.         ungot_key = key;
  6225.         pas_tab[BELL] = find_index("p-abort");
  6226.         reg_tab[BELL] = find_index("p-abort");
  6227.         pas_tab[CTRL(ALT('j'))] = find_index("exit-level");
  6228.         major_mode = strsave("COMMENT body (A-<cr> to exit)");
  6229.         strcpy(mode, major_mode);
  6230.         recursive_edit();
  6231.         major_mode = strsave("Pascal");
  6232.         strcpy(mode, major_mode);
  6233.         pas_tab[CTRL(ALT('j'))] = orig_alt_ret;
  6234.         check_abort();
  6235.         reg_tab[BELL] = find_index("abort");
  6236.         pas_tab[BELL] = bell_key;
  6237.  
  6238.         point += com_size+1;
  6239.     }
  6240. }
  6241.  
  6242. /* pas_indenter    Like the command indent previous, but gives no indentation
  6243.     if the previous line is not indented. */
  6244.  
  6245. command pas_indenter() on pas_tab[ALT('i')]
  6246. {
  6247.     int orig_column, prev_indent;
  6248.     int orig = point;
  6249.  
  6250.     orig_column = current_column();            /* point's column */
  6251.     to_begin_line();
  6252.     if (re_search(-1, "[^ \t\n]")) {  /* find previous non-blank line */
  6253.         to_indentation();
  6254.         prev_indent = current_column();
  6255.     }
  6256.     else
  6257.         prev_indent = 0;
  6258.     point = orig;
  6259.     to_indentation();        /* go to current line's indent */
  6260.  
  6261.     to_column(prev_indent);        /* indentation as previous */
  6262. }
  6263.  
  6264. /* pas-return    Insert a ';' if necessary, then return. */
  6265.  
  6266. pas_return() on pas_tab[CTRL('J')]
  6267. {
  6268.     int orig = point;
  6269.     char prev,comm[3];
  6270.     
  6271.     to_end_line();
  6272.     if (point == orig) {
  6273.         re_search(-1,P_SKIP);
  6274.         if (point>0) {
  6275.             prev = character(point-1);
  6276.             if ( (prev!=';') && (prev!='\n') ) {
  6277.                 grab(point-2,point,comm);
  6278.                 if ( (strncmp(comm,"*)",2)) &&
  6279.                     (prev!='}')) {
  6280.                     insert(';');
  6281.                     ++orig;
  6282.                 }
  6283.             }
  6284.         }
  6285.     }
  6286.     point = orig;
  6287.     insert('\n');
  6288.     pas_indenter();
  6289. }
  6290.  
  6291. /* norm-return    Normal return. */
  6292.  
  6293. norm_return() on pas_tab[CTRL(ALT('j'))],pas_tab[ALT('j')]
  6294. {
  6295.     insert('\n');    
  6296.     pas_indenter();
  6297. }
  6298.  
  6299. /* pas-equal    Inserts " := " */
  6300. pas_equal() on pas_tab['=']
  6301. {
  6302.     stuff(" := ");
  6303. }
  6304.  
  6305. normal_equal() on pas_tab[ALT('=')]
  6306. {
  6307.     insert('=');
  6308. }
  6309.  
  6310. when_loading()
  6311. {
  6312.     int i;
  6313.  
  6314.     pas_tab[CTRL('M')] = find_index("newline");
  6315.     pas_tab[CTRL('H')] = find_index("delete-hacking-tabs");
  6316.     for (i = 'A'; i <= 'Z'; i++)
  6317.         if (pas_tab[ALT(i)] <= 0)
  6318.             pas_tab[ALT(i)] = find_index("case-indirect");
  6319.     if (Matchdelim)
  6320.         pas_tab[')'] = pas_tab[']'] =
  6321.             find_index("show-matching-delimiter");
  6322. }
  6323. ******************************************************************
  6324. this completes all *.e files
  6325. ******************************************************************
  6326.  
  6327. p.s. to editor...  I know I should have put all this into an *.arc
  6328. file but I don't know how to mail binaries, although I do know how
  6329. to retrieve binaries from simtel.
  6330. -------
  6331.