home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / editors / 2019 < prev    next >
Encoding:
Text File  |  1992-08-17  |  33.9 KB  |  1,588 lines

  1. Path: sparky!uunet!haven.umd.edu!darwin.sura.net!mips!swrinde!cs.utexas.edu!torn!watserv2.uwaterloo.ca!watserv1!mks.com!ant
  2. From: ant@mks.com (Anthony Howe)
  3. Newsgroups: comp.editors
  4. Subject: Ant's Editor August '92
  5. Message-ID: <1992Aug17.134903.15667@mks.com>
  6. Date: 17 Aug 92 13:49:03 GMT
  7. Sender: ant@mks.com (Anthony Howe)
  8. Organization: Mortice Kern Systems, Waterloo, Ontario, CANADA
  9. Lines: 1577
  10.  
  11. Anthony's Editor August 92
  12. ==========================
  13.  
  14. WHAT'S NEW
  15.  
  16.   +    Configuartion file support for help text and key bindings.
  17.   +    Message line: tells you that the file has been modified or saved.
  18.   +    Block, Cut, and Paste commands.
  19.   +    Fixed control character display problem.
  20.   -    Dropped flip-editor-style command.
  21.   -    Dropped TERMCAP function-key support in favour of configuration files.
  22.  
  23. AE'91, in its obfuscated form, won "Best Utility" in the 1991 International
  24. Obfuscated C Code Contest.  Since that contest, AE has been revised and
  25. extended in order to try new ideas and provide better functionality, while
  26. still retaining a simple interface and modualar design.  There are four 
  27. files included in the August '92 distribution.
  28.  
  29.     ae.man        Manual reference and installation guide.
  30.     ae.c        The source.
  31.     ae.rc        Configuration file for AE
  32.     ea.rc        Configuration file for EA (ansi cursor keys)
  33.  
  34. AE'92 merges two schools of thought by providing both VI style (modual)
  35. and EMACS style (modeless) editing interfaces.  Users can configure the
  36. command-key bindings and the help text for either style.
  37.  
  38. AE'92 is simple enough that anyone can modify it to add features.  The
  39. source is in the Public Domain, so people are free to modify and use
  40. as they see fit.  
  41.  
  42. e.g.
  43.     o  Tutorials on the Buffer Gap Scheme and/or editor design.
  44.     o  A basis for an editor that can be built into a project.
  45.     o  An editor for novice users.
  46.  
  47. AE has been know to compile on a wide variety of machines and compilers
  48. like BSD and System V Unix with GNU C, PC mahcines with WatCom C or Turbo C,
  49. and ATARI ST machines with Sozobon C.  Any machine that provides at least 
  50. K&R C and a CURSES library should have no trouble getting AE to compile.
  51.  
  52. See the INSTALLATION section of the manual on how to build AE.  Also
  53. take note of the BUG section of the manual.
  54.  
  55. Anthony Howe
  56. ant@mks.com
  57.  
  58. ----ae.man---
  59. 0.  NAME
  60.  
  61.     ae    Ant's Editor  August '92
  62.  
  63.  
  64. 1.  SYNOPSIS
  65.  
  66.     ae <filename>    
  67.     ea <filename>
  68.  
  69.  
  70. 2.  OPERANDS
  71.  
  72. filename    The name of a existing or new file to edit is required.
  73.  
  74.  
  75. 3.  DESCRIPTION
  76.  
  77. AE is a full screen, modual text editor, and EA is a full screen,
  78. modelss text editor.  The source should be portable to any environment
  79. that provides a K&R C compiler and a CURSES library.
  80.  
  81. Text files consists of lines of printable text or tab characters.  
  82. A line can be of arbitary length and is delimited by either a 
  83. newline or the end of file.  Carriage return is mapped to newline 
  84. on input and ignored on output.  Tab stops are every eight columns.
  85.  
  86.  
  87. 4.  COMMANDS
  88.  
  89. Two default configuration files are supplied.  "ae.rc" is read when 
  90. AE is invoked, and "ea.rc" is read when EA is used.
  91.  
  92.  
  93. 4.1  AE  MODUAL STYLE
  94.  
  95. h j k l        left, down, up, right cursor movement
  96. H J K L        word left, page down, page up, word right
  97. [ ]        beginning and end of line
  98. t b        top and bottom of file
  99. i ESC        enter insert mode, escape to leave
  100. x        delete character under the cursor
  101. X        delete character left of the cursor
  102. ?        toggle help on/off
  103. B        toggle block on/off
  104. C        cut block to scrap
  105. P        paste scrap into buffer
  106. F        write buffer to file
  107. R        refresh the screen
  108. Q        quit
  109.  
  110.  
  111. 4.2  EA  MODELESS STYLE
  112.  
  113. cursor keys    left, down, up, right cursor movement
  114. ^W ^E        word left,  word right
  115. ^N ^P        page down, page up
  116. ^A ^D        beginning and end of line
  117. ^T ^B        top and bottom of file
  118. backspace    delete character left of the cursor
  119. ^X        delete character under the cursor
  120. F1        toggle help on/off
  121. F2        toggle block on/off
  122. F3        cut block to scrap
  123. F4        paste scrap into buffer
  124. ^F        write buffer to file
  125. ^R        refresh the screen
  126. ^C        quit
  127.  
  128.  
  129. 5.  CONFIGURATION
  130.  
  131. The user is able to configure the editor with the help text and keys
  132. that the user likes.  It is possible to define a modual or modeless
  133. key interface and support multi-character key sequences.
  134.  
  135. The configuration file layout is fairly simple.  All control words
  136. begin on a line starting with a period (.).  Invalid keywords are
  137. ignored.  The following keys words are used:
  138.  
  139. .help_text
  140.     All the subsequent lines upto the next keyword are considered
  141.     help text.  The terminating keyword is discarded.  There may
  142.     be more than one .help_text given.
  143.  
  144. .insert_enter <string>
  145. .insert_exit <string>
  146.     Enter and exit insert mode.  
  147.  
  148. .delete_left <string>
  149. .delete_right <string>
  150.     Delete character to the left or right of the cursor.
  151.  
  152. .block <string>
  153. .cut <string>
  154. .paste <string>
  155.     Block on/off toggle, cut block, and paste before.
  156.  
  157. .cursor_up <string>
  158. .cursor_down <string>
  159. .cursor_left <string>
  160. .cursor_right <string>
  161.     Cursor motion in four directions.  Typically the arrow keys.
  162.  
  163. .page_up <string>
  164. .page_down <string>
  165.         Previous or next screen full of text.
  166.  
  167. .word_left <string>
  168. .word_right <string>
  169.         Move to word left or right of the current cursor.
  170.  
  171. .line_left <string>
  172. .line_right <string>
  173.     Move to the beginning or end of the line.
  174.  
  175. .file_top <string>
  176. .file_bottom <string>
  177.     Move to the top and bottom of the file buffer.
  178.  
  179. .help <string>
  180.     Toggle the help text and ruler line on and off.
  181.  
  182. .quit <string>
  183.     Exit the editor.
  184.  
  185. .redraw <string>
  186.     Force a screen redraw.
  187.  
  188. .file_save <string>
  189.     Save the file buffer to the current filename.
  190.  
  191. .itself  <character>
  192.     The following character represents itself.  This is really a
  193.     redundant keyword since any key not defined by a keyword,
  194.     automatically represents itself.
  195.  
  196. .stty_erase
  197. .stty_kill
  198.     Declare that the terminal's values for the erase and kill
  199.     characters should be used in insert mode to backspace-erase,
  200.     or discard and restart input.
  201.  
  202. The parameters <string> and <character> can be any text other than
  203. whitspace (blank, tab, carriage-return, and newline).  It is possible
  204. to specify control keys by prefixing the following characters with a
  205. caret (^):
  206.  
  207.     @ a b c d e f g h i j k l m n o 
  208.     p q r s t u v w x y z [ \ ] ^ _
  209.  
  210. Also numeric and literal escapes are possible.  A numeric escape
  211. begins with a backslash followed by either an octal number with 
  212. leading '0', a hex number with leading '0x', or a decimal number.
  213. The value must be between 0 to 255.
  214.  
  215. A literal escape also begins with a backslash but is then followed
  216. by a character that is not a digit.
  217.  
  218. eg.
  219.     .insert_enter    i        <-- single character string
  220.     .insert_exit    ^[        <-- defines ASCII ESC
  221.     .delete_right    \0x7f        <-- defines ASCII DEL
  222.     .cursor_up    ^[[A        <-- defines sequence ESC [ A
  223.  
  224. Note that the name of the editor determines whether or not the editor
  225. behaves in a modual (AE) or modeless (EA) fashion.
  226.  
  227.  
  228. 6.  EXIT STATUS
  229.  
  230. 0    Success termination.
  231. 1    General error.
  232. 2    Usage error.
  233. 3    Failed to initialize the screen.
  234. 4    Problem with the configuration file.
  235.  
  236.  
  237. 7.  INSTALLATION 
  238.  
  239. Requires K&R C and a CURSES library for the given target machine.
  240.  
  241. To build AE on System V equivalent systems, type
  242.  
  243.     cc -O -o ae ae.c -lcurses
  244.  
  245. To build AE on BSD equivalent systems, type
  246.  
  247.     cc -O -o ae ae.c -lcurses -ltermcap
  248.  
  249. To build AE on systems that have POSIX.1 or System V termios library,
  250. add to the command line -DPOSIX=1, like
  251.  
  252.     cc -DPOSIX=1 -O -o ae ae.c -lcurses 
  253.  
  254. To use EA version of AE either link or copy the file to EA.
  255.  
  256.     cp ae ea
  257.  
  258. If the constants BUF, HUP, AE_CONFIG, or AE_CONFIG are not defined on
  259. the compile command line then the defaults used are
  260.  
  261.     BUF       = 32767 
  262.     HUP       = "ae.hup"
  263.     AE_CONFIG = "ae.rc"
  264.     EA_CONFIG = "ea.rc"
  265.  
  266. The BUF size should be set at compile time to 32767.  This value was
  267. used because the Sozobon C compiler for the Atari ST has 16 bit ints
  268. and a limit on the size of arrays & structures of 32k.  Also the
  269. WatCom C compiler for the PC also has 16 bits ints.  On machines that
  270. have 32 bit ints (most unix boxes), a larger value for BUF could be
  271. used.
  272.  
  273. It is recommend that compact memory model be used on PC class
  274. machines.  Small memory model may work too provided BUF is not too
  275. large.
  276.  
  277. HUP should define the name of the fall-back write file.  POSIX should
  278. be defined for systems that have POSIX.1 termios support (which is
  279. based on System V termios).
  280.  
  281. Most EBCDIC machines use block mode terminals.  This is a problem
  282. that has not been addressed and/or tested for.
  283.  
  284.  
  285. 8.  BUGS
  286.  
  287. This editor will display a file with long lines, but has trouble
  288. scrolling the screen with long lines.  Paging up and down should
  289. work correctly, however.
  290.  
  291.  
  292. 9.  REFERENCES
  293.  
  294. [Fin80]    Craig A. Finseth, "Theory and Practice of Text Editors or 
  295.     A Cookbook For An EMACS", TM-165, MIT Lab. for Computer 
  296.     Science
  297.  
  298. [KeP81]    Kernighan & Plauger, "Software Tools in Pascal", 
  299.     Addison-Wesley, 81, chapter 6
  300.  
  301. [Mil86]    Eugene W. Myers & Webb Miller, "Row-replacement Algorithums
  302.     for Screen Editors", TR 86-19, Dept. of Compter Science, 
  303.     U. of Arizona
  304.  
  305. [MyM86]    Eugene W. Myers & Webb Miller, "A simple row-replacement 
  306.     method", TR 86-28, Dept. of Compter Science, U. of Arizona
  307.  
  308. [Mil87]    Webb Miller, "A Software Tools Sampler", Prentice Hall, 87
  309.     ISBN 0-13-822305-X, chapter 5
  310.  
  311. [net90]    "Editor 101/102" articles from comp.editors
  312.  
  313.  
  314. 10.  FILES
  315.  
  316. ae.man        AE August '92 manual
  317. ae.c        AE August '92 source 
  318. ae.rc        Configuration file for AE modual style
  319. ea.rc        Configuration file for EA modeless style (ansi cursor keys)
  320.  
  321. ----ae.c----
  322. /*
  323.  *    ae.c        
  324.  *
  325.  *    Anthony's Editor  August '92
  326.  *
  327.  *    Public Domain 1991, 1992 by Anthony Howe.  All rights released.
  328.  */
  329.  
  330. #include <ctype.h>
  331. #include <curses.h>
  332. #include <limits.h>
  333. #include <stdio.h>
  334. #include <stdlib.h>
  335. #include <string.h>
  336.  
  337. #undef _
  338. #ifdef __STDC__
  339. #define _(x)    x
  340. #else
  341. #define _(x)    ()
  342. #endif
  343.  
  344. #ifndef BUF
  345. #define BUF        32767
  346. #endif /* BUF */
  347.  
  348. #ifndef HUP
  349. #define HUP        "ae.hup"
  350. #endif /* HUP */
  351.  
  352. #ifndef AE_CONFIG
  353. #define AE_CONFIG    "ae.rc"
  354. #endif /* AE_CONFIG */
  355.  
  356. #ifndef EA_CONFIG
  357. #define EA_CONFIG    "ea.rc"
  358. #endif /* EA_CONFIG */
  359.  
  360. /* Exit status. */
  361. #define EXIT_OK        0
  362. #define EXIT_ERROR    1
  363. #define EXIT_USAGE    2
  364. #define EXIT_INITSCR    3
  365. #define EXIT_CONFIG    4
  366.  
  367. /* Screen partitioning. */
  368. #define MSGLINE        0
  369. #define HELPLINE    1
  370. #undef  TEXTLINE    
  371.  
  372. #define NOMARK        -1
  373.  
  374. typedef struct keytable_t {
  375.     int key;
  376.     void (*func) _((void));
  377. } keytable_t;
  378.  
  379. int done, modified, modeless;
  380. int point, page, epage;
  381. int row, col;
  382. int input;
  383. int marker = NOMARK;
  384. int textline = HELPLINE;
  385. size_t nscrap;
  386. char buf[BUF];
  387. char *ebuf;
  388. char *gap = buf;
  389. char *egap;
  390. char *filename;
  391. char *scrap;
  392.  
  393. /*
  394.  *    The following assertions must be maintained.
  395.  *
  396.  *    o  buf <= gap <= egap <= ebuf
  397.  *        If gap == egap then the buffer is full.
  398.  *
  399.  *    o  cursor = ptr(point) and cursor < gap or egap <= cursor 
  400.  *
  401.  *    o  page <= point < epage
  402.  *
  403.  *    o  0 <= point <= pos(ebuf) <= BUF
  404.  *
  405.  *
  406.  *    Memory representation of the file:
  407.  *
  408.  *        low    buf  -->+----------+
  409.  *                |  front   |
  410.  *                | of file  |
  411.  *            gap  -->+----------+<-- character not in file 
  412.  *                |   hole   |
  413.  *            egap -->+----------+<-- character in file
  414.  *                |   back   |
  415.  *                | of file  |
  416.  *        high    ebuf -->+----------+<-- character not in file 
  417.  *
  418.  *
  419.  *    Point & Gap
  420.  *
  421.  *    The Point is the current cursor position while the Gap is the 
  422.  *    position where the last edit operation took place. The Gap is 
  423.  *    ment to be the cursor but to avoid shuffling characters while 
  424.  *    the cursor moves it is easier to just move a pointer and when 
  425.  *    something serious has to be done then you move the Gap to the 
  426.  *    Point. 
  427.  *
  428.  *
  429.  *    Use of stdio for portability.
  430.  *
  431.  *    Stdio will handle the necessary conversions of text files to 
  432.  *    and from a machine specific format.  Things like fixed length 
  433.  *    records; CRLF mapping into <newline> (\n) and back again; 
  434.  *    null padding; control-Z end-of-file marks; and other assorted 
  435.  *    bizare issues that appear on many unusual machines.
  436.  *
  437.  *    AE is meant to be simple in both code and usage.  With that
  438.  *    in mind certain assumptions are made.
  439.  *
  440.  *    Reading:  If a file cannot be opened, assume that it is a
  441.  *    new file.  If an error occurs, fall back to a safe state and
  442.  *    assume an empty file.  fread() is typed size_t which is an
  443.  *    unsigned number.  Zero (0) would indicate a read error or an
  444.  *    empty file.  A return value less than BUF is alright, since
  445.  *    we asked for the maximum allowed.
  446.  *
  447.  *    Writing:  If the file cannot be opened or a write error occurs,
  448.  *    then we scramble and save the user's changes in a file called 
  449.  *    ae.hup.  If ae.hup fails to open or a write error occurs, then 
  450.  *    we assume that shit happens.
  451.  *
  452.  */
  453.  
  454. int adjust _((int, int));
  455. int nextline _((int));
  456. int pos _((char *));
  457. int prevline _((int));
  458. int save _((char *));
  459. char *ptr _((int));
  460. void fatal _((int));
  461. void ruler _((int));
  462.  
  463. void backsp _((void));
  464. void bottom _((void));
  465. void delete _((void));
  466. void display _((void));
  467. void down _((void));
  468. void file _((void));
  469. void help _((void));
  470. void insert _((void));
  471. void insert_mode _((void));
  472. void left _((void));
  473. void lnbegin _((void));
  474. void lnend _((void));
  475. void movegap _((void));
  476. void pgdown _((void));
  477. void pgup _((void));
  478. void redraw _((void));
  479. void right _((void));
  480. void quit _((void));
  481. void flip _((void));
  482. void top _((void));
  483. void up _((void));
  484. void wleft _((void));
  485. void wright _((void));
  486. void block _((void));
  487. void cut _((void));
  488. void paste _((void));
  489.  
  490. /*
  491.  *    Configurable help and key support.
  492.  *
  493.  *    The user is able to configure the editor with the help text 
  494.  *    and keys that the user likes.  It is possible to define a 
  495.  *    modual or modeless key interface and support multi-character 
  496.  *    key sequences.
  497.  *
  498.  *    The configuration file layout is fairly simple.  All control 
  499.  *    words begin on a line starting with a period (.).  Invalid 
  500.  *    keywords are ignored.  The following keys words are used:
  501.  *
  502.  *    .help_text
  503.  *        All the subsequent lines upto the next keyword are
  504.  *        considered help text.  The terminating keyword is
  505.  *        discarded.  There may be more than one .help_text
  506.  *        given.
  507.  *
  508.  *    .insert_enter <string>
  509.  *    .insert_exit <string>
  510.  *        Enter and exit insert mode.  Use of .insert_enter will
  511.  *        denote a modual user interface.
  512.  *
  513.  *    .delete_left <string>
  514.  *    .delete_right <string>
  515.  *        Delete character to the left or right of the cursor.
  516.  *
  517.  *    .block <string>
  518.  *    .cut <string>
  519.  *    .paste <string>
  520.  *        Block on/off toggle, cut block, and paste before.
  521.  *
  522.  *    .cursor_up <string>
  523.  *    .cursor_down <string>
  524.  *    .cursor_left <string>
  525.  *    .cursor_right <string>
  526.  *        Cursor motion in four directions.  Typically the 
  527.  *        arrow keys.
  528.  *        
  529.  *    .page_up <string>
  530.  *    .page_down <string>
  531.  *        Previous or next screen full of text.
  532.  *        
  533.  *    .word_left <string>
  534.  *    .word_right <string>
  535.  *        Move to word left or right of the current cursor.
  536.  *
  537.  *    .line_left <string>
  538.  *    .line_right <string>
  539.  *        Move to the beginning or end of the line.
  540.  *
  541.  *    .file_top <string>
  542.  *    .file_bottom <string>
  543.  *        Move to the top and bottom of the file buffer.
  544.  *
  545.  *    .help <string>
  546.  *        Toggle the help text and ruler line on and off.
  547.  *
  548.  *    .quit <string>
  549.  *        Exit the editor.
  550.  *
  551.  *    .redraw <string>
  552.  *        Force a screen redraw.
  553.  *
  554.  *    .file_save <string>
  555.  *        Save the file buffer to the current filename.
  556.  *
  557.  *    .itself  <character>
  558.  *        The following character represents itself.  This is
  559.  *        really a redundant keyword since any key not defined
  560.  *        by a keyword, automatically represents itself.
  561.  *
  562.  *    .stty_erase
  563.  *    .stty_kill
  564.  *        Declare that the terminal's values for the erase and
  565.  *        kill characters should be used in insert mode to 
  566.  *        backspace-erase, or discard and restart input.
  567.  *
  568.  *    The parameters <string> and <character> can be any text
  569.  *    other than whitspace (blank, tab, carriage-return, and newline).
  570.  *    It is possible to specify control keys by prefixing the following
  571.  *    characters with a caret (^):
  572.  *
  573.  *        @ a b c d e f g h i j k l m n o 
  574.  *        p q r s t u v w x y z [ \ ] ^ _
  575.  *    
  576.  *    Also numeric and literal escapes are possible.  A numeric escape
  577.  *    begins with a backslash followed by either an octal number with 
  578.  *    leading '0', a hex number with leading '0x', or a decimal number.
  579.  *    The value must be between 0 to 255.
  580.  *
  581.  *    A literal escape also begins with a backslash but is then followed
  582.  *    by a character that is not a digit.
  583.  *    
  584.  *    eg.
  585.  *        .insert_enter    i        <-- single character string
  586.  *        .insert_exit    ^[        <-- defines ASCII ESC
  587.  *        .delete_right    \0x7f        <-- defines ASCII DEL
  588.  *        .cursor_up    ^[[A        <-- defines sequence ESC [ A
  589.  *
  590.  *    Note that the name of the editor determines whether or not
  591.  *    the editor behaves in a modual or modeless fashion.
  592.  */
  593.  
  594. #define K_INSERT_ENTER    (-101)
  595. #define K_INSERT_EXIT    (-102)
  596. #define K_DELETE_LEFT    (-103)
  597. #define K_DELETE_RIGHT    (-104)
  598.  
  599. #define K_BLOCK        (-105)
  600. #define K_CUT        (-106)
  601. #define K_PASTE        (-107)
  602.  
  603. #define K_CURSOR_UP    (-200)
  604. #define K_CURSOR_DOWN    (-201)
  605. #define K_CURSOR_LEFT    (-202)
  606. #define K_CURSOR_RIGHT    (-203)
  607. #define K_PAGE_UP    (-204)
  608. #define K_PAGE_DOWN    (-205)
  609. #define K_WORD_LEFT    (-206)
  610. #define K_WORD_RIGHT    (-207)
  611. #define K_LINE_LEFT    (-208)
  612. #define K_LINE_RIGHT    (-209)
  613. #define K_FILE_TOP    (-210)
  614. #define K_FILE_BOTTOM    (-211)
  615.  
  616. #define K_HELP_TEXT    (-300)
  617. #define K_HELP        (-301)
  618. #define K_QUIT        (-302)
  619. #define K_REDRAW    (-303)
  620. #define K_FILE_SAVE    (-304)
  621.  
  622. #define K_ITSELF    (-400)
  623. #define K_STTY_ERASE    (-401)
  624. #define K_STTY_KILL    (-402)
  625.  
  626. typedef struct keymap_t {
  627.     short code;
  628.     char *entry;
  629. } keymap_t;
  630.  
  631. keymap_t *key_map;
  632. keymap_t key_names[] = {
  633.     { K_INSERT_ENTER, ".insert_enter" },
  634.     { K_INSERT_EXIT, ".insert_exit" },
  635.     { K_DELETE_LEFT, ".delete_left" },
  636.     { K_DELETE_RIGHT, ".delete_right" },
  637.     { K_BLOCK, ".block" },
  638.     { K_CUT, ".cut" },
  639.     { K_PASTE, ".paste" },
  640.     { K_CURSOR_UP, ".cursor_up" },
  641.     { K_CURSOR_DOWN, ".cursor_down" },
  642.     { K_CURSOR_LEFT, ".cursor_left" },
  643.     { K_CURSOR_RIGHT, ".cursor_right" },
  644.     { K_PAGE_UP, ".page_up" },
  645.     { K_PAGE_DOWN, ".page_down" },
  646.     { K_WORD_LEFT, ".word_left" },
  647.     { K_WORD_RIGHT, ".word_right" },
  648.     { K_LINE_LEFT, ".line_left" },
  649.     { K_LINE_RIGHT, ".line_right" },
  650.     { K_FILE_TOP, ".file_top" },
  651.     { K_FILE_BOTTOM, ".file_bottom" },
  652.     { K_HELP_TEXT, ".help_text" },
  653.     { K_HELP, ".help" },
  654.     { K_QUIT, ".quit" },
  655.     { K_REDRAW, ".redraw" },
  656.     { K_FILE_SAVE, ".file_save" },
  657.     { K_ITSELF, ".itself" },
  658.     { K_STTY_ERASE, ".stty_erase" },
  659.     { K_STTY_KILL, ".stty_kill" },
  660.     { 0, NULL }
  661. };
  662.  
  663. /* initkey() and encodekey() error values. */
  664. #define INITKEY_OK    0
  665. #define INITKEY_OPEN    1
  666. #define INITKEY_MEMORY    2
  667. #define INITKEY_SYNTAX    3
  668. #define INITKEY_INVALID    4
  669. #define INITKEY_RANGE    5
  670.  
  671. static char blank[] = " \t\r\n";
  672.  
  673. char *strlwr _((char *));
  674. char *strdup _((char *));
  675. int initkey _((char *, keymap_t **));
  676. int encodekey _((char *, char **));
  677. char *gethelp _((FILE *));
  678. void finikey _((keymap_t *));
  679. int getkey _((keymap_t *));
  680.  
  681. /*
  682.  *    Convert a string to lower case.  Return the string pointer.
  683.  */
  684. char *
  685. strlwr(str)
  686. char *str;
  687. {
  688.     register char *s;
  689.     for (s = str; *s != '\0'; ++s)
  690.         *s = tolower(*s);
  691.     return (str);
  692. }
  693.  
  694. /*
  695.  *    Make a duplicate of a string.  Return a pointer to an allocated
  696.  *    copy of the string, or NULL if malloc() failed.
  697.  */
  698. char *
  699. strdup(str)
  700. char *str;
  701. {
  702.     char *new;
  703.     if ((new = (char*) malloc(strlen(str)+1)) != NULL)
  704.         (void) strcpy(new, str);
  705.     return (new);
  706. }    
  707.  
  708. /*
  709.  *    Return an INITKEY_xxx error status.  Pass-back a pointer to
  710.  *    an encoded string, or NULL for an error in 'strp'.  
  711.  */
  712. int
  713. encodekey(str, strp)
  714. char *str, **strp;
  715. {
  716.     long number;
  717.     char *ptr, *p, *ctrl;
  718.     static char control[] = "@abcdefghijklmnopqrstuvwxyz[\\]^_";
  719.     *strp = NULL;
  720.     if ((ptr = strdup(str)) == NULL)
  721.         return (INITKEY_MEMORY);
  722.     /* Duplicating the string is a cheap way of allocating
  723.      * enough memory to store the encoded string. The 
  724.      * process of encoding always generates a string less
  725.      * than or equal to the original string length.
  726.      */
  727.     for (p = ptr; *str != '\0'; ++p) {
  728.         switch (*str) {
  729.         case '^':
  730.             /* Non-ASCII dependant control key mapping. */
  731.             ++str;
  732.             *str = tolower(*str);
  733.             if ((ctrl = strchr(control, *str)) == NULL) {
  734.                 free(ptr);
  735.                 return (INITKEY_INVALID);
  736.             }
  737.             *p = (char) (ctrl - control);    
  738.             ++str;
  739.             break;
  740.         case '\\':
  741.             /* Escapes. */
  742.             ++str;
  743.             if (isdigit(*str)) {
  744.                 /* Numeric escapes allow for
  745.                  *  octal    \0nnn
  746.                  *  hex        \0xnn
  747.                  *  decimal    \nnn 
  748.                  */
  749.                 number = strtol(str, &str, 0);
  750.                 if (UCHAR_MAX <= number) {
  751.                     free(ptr);
  752.                     return (INITKEY_RANGE);
  753.                 }
  754.                 *p = (char) number;
  755.                 break;
  756.             }
  757.             /* Literal escapes. */
  758.         default:
  759.             /* Character. */
  760.             *p = *str++;
  761.         }
  762.     }
  763.     *p = '\0';
  764.     *strp = ptr;
  765.     return (INITKEY_OK);
  766. }
  767.  
  768. /*
  769.  *    Return a pointer to allocated memory containing help text, 
  770.  *    or NULL if malloc() failed.
  771.  */
  772. char *
  773. gethelp(fp)
  774. FILE *fp;
  775. {
  776.     size_t helplen, buflen;
  777.     char *help, *ptr, buf[BUFSIZ];
  778.     help = (char*) malloc(helplen = 1);
  779.     if (help == NULL)
  780.         return (NULL);
  781.     help[0] = '\0';
  782.     while (fgets(buf, BUFSIZ, fp) != NULL && buf[0] != '.') {
  783.         buflen = strlen(buf);
  784.         ptr = (char*) realloc(help, helplen + buflen);    
  785.         if (ptr == NULL) 
  786.             break;
  787.         help = ptr;
  788.         (void) strcpy(help + helplen - 1, buf);
  789.         helplen += buflen;
  790.     }
  791.     return (help);
  792. }
  793.  
  794. /*
  795.  *    Read a configuration file from either the current directory or
  796.  *    the user's home directory.  Return an error status.  Pass-back
  797.  *    either a pointer to a key mapping table, or NULL if an error
  798.  *    occured.
  799.  */
  800. int
  801. initkey(fn, keys)
  802. char *fn;
  803. keymap_t **keys;
  804. {
  805.     FILE *fp;
  806.     int error, klen;
  807.     keymap_t *kptr, *kn, *kp;
  808.     char *word, buffer[BUFSIZ];
  809.     kptr = NULL;
  810.     error = INITKEY_OPEN;
  811.     if ((fp = fopen(fn, "r")) == NULL) {
  812.         if ((word = getenv("HOME")) == NULL)
  813.             goto error_1;
  814.         (void) sprintf(buffer, "%s/%s", word, fn);
  815.         if ((fp = fopen(buffer, "r")) == NULL) {
  816.             (void) sprintf(buffer, "%s\\%s", word, fn);
  817.             if ((fp = fopen(buffer, "r")) == NULL)
  818.                 goto error_1;
  819.         }
  820.     }
  821.     if ((kptr = (keymap_t*) malloc(sizeof (keymap_t))) == NULL) {
  822.         error = INITKEY_MEMORY;
  823.         goto error_2;
  824.     }
  825.     klen = 1;
  826.     while (fgets(buffer, BUFSIZ, fp) != NULL) {
  827.         if (buffer[0] != '.' || (word = strtok(buffer, blank)) == NULL)
  828.             continue;
  829.         (void) strlwr(word);
  830.         for (kn = key_names; kn->entry != NULL; ++kn) {
  831.             if (strcmp(word, kn->entry) == 0) {
  832.                 error = INITKEY_MEMORY;
  833.                 kp = (keymap_t*) realloc(
  834.                     kptr, ++klen * sizeof (keymap_t)
  835.                 );
  836.                 if (kp == NULL)
  837.                     goto error_2;
  838.                 kptr = kp;
  839.                 switch (kn->code) {
  840.                 case K_STTY_ERASE:
  841.                     buffer[0] = erasechar();
  842.                     buffer[1] = '\0';
  843.                     word = strdup(buffer);
  844.                     break;
  845.                 case K_STTY_KILL:
  846.                     buffer[0] = killchar();
  847.                     buffer[1] = '\0';
  848.                     word = strdup(buffer);
  849.                     break;
  850.                 case K_HELP_TEXT:
  851.                     word = gethelp(fp);
  852.                     break;
  853.                 default:
  854.                     word = strtok(NULL, blank);
  855.                     if (word == NULL) {
  856.                         error = INITKEY_SYNTAX;
  857.                         goto error_2;
  858.                     }
  859.                     error = encodekey(word, &word);
  860.                 }
  861.                 if (word == NULL)
  862.                     goto error_2;
  863.                 kptr[klen-2].entry = word;
  864.                 if (kn->code == K_ITSELF)
  865.                     kptr[klen-2].code = *word;
  866.                 else
  867.                     kptr[klen-2].code = kn->code;
  868.                 break;
  869.             }
  870.         }
  871.     }
  872.     error = INITKEY_OK;
  873. error_2:
  874.     (void) fclose(fp);
  875.     /* Assert that last keymap_t in kptr[] is zero. */
  876.     kptr[klen-1].code = 0;
  877.     kptr[klen-1].entry = NULL;
  878.     if (error != INITKEY_OK) {
  879.         finikey(kptr);
  880.         kptr = NULL;
  881.     }
  882. error_1:
  883.     *keys = kptr;
  884.     return (error);
  885. }
  886.  
  887. void
  888. finikey(keys)
  889. keymap_t *keys;
  890. {
  891.     keymap_t *kp;
  892.     if (keys != NULL) {
  893.         for (kp = keys; kp->entry != NULL; ++kp)
  894.             free(kp->entry);
  895.         free(keys);
  896.     }
  897. }
  898.  
  899. int
  900. getkey(keys)
  901. keymap_t *keys;
  902. {
  903.     keymap_t *k;
  904.     int submatch;
  905.     static char buffer[128];
  906.     static char *record = buffer;
  907.  
  908.     /* If recorded bytes remain, return next recorded byte. */
  909.     if (*record != '\0')
  910.         return (*record++);
  911.     /* Reset record buffer. */
  912.     record = buffer;
  913.     do {
  914.         /* Read and record one byte. */
  915.         *record++ = getch();
  916.         *record = '\0';
  917.  
  918.         /* If recorded bytes match any multi-byte sequence... */
  919.         for (k = keys, submatch = 0; k->entry != NULL; ++k) {
  920.             char *p, *q; 
  921.             for (p = buffer, q = k->entry; *p == *q; ++p, ++q) {
  922.                 if (*p == '\0') {
  923.                     /* Return extended key code. */
  924.                     return (k->code);
  925.                 }
  926.             }
  927.             if (*p == '\0') {
  928.                 /* Recorded bytes match anchored substring. */
  929.                 submatch = 1;
  930.             }
  931.         }
  932.         /* If recorded bytes matched an anchored substring, loop. */
  933.     } while (submatch);
  934.     /* Return first recorded byte. */
  935.     record = buffer;
  936.     return (*record++);
  937. }
  938.  
  939. /* ASCII Control Codes */
  940. #undef CTRL
  941. #define CTRL(x)        ((x) & 0x1f)
  942.  
  943. keytable_t table[] = {
  944.     { K_CURSOR_LEFT, left },
  945.     { K_CURSOR_RIGHT, right },
  946.     { K_CURSOR_DOWN, down },
  947.     { K_CURSOR_UP, up },
  948.     { K_WORD_LEFT, wleft },
  949.     { K_WORD_RIGHT, wright },
  950.     { K_PAGE_UP, pgup },
  951.     { K_PAGE_DOWN, pgdown },
  952.     { K_LINE_LEFT, lnbegin },
  953.     { K_LINE_RIGHT, lnend },
  954.     { K_FILE_TOP, top },
  955.     { K_FILE_BOTTOM, bottom },
  956.     { K_DELETE_LEFT, backsp },
  957.     { K_DELETE_RIGHT, delete },
  958.     { K_INSERT_ENTER, insert_mode },
  959.     { K_BLOCK, block },
  960.     { K_CUT, cut },
  961.     { K_PASTE, paste },
  962.     { K_FILE_SAVE, file },
  963.     { K_REDRAW, redraw },
  964.     { K_HELP, help },
  965.     { K_QUIT, quit },
  966.     { K_ITSELF, NULL },
  967.     { 0, NULL }
  968. };
  969.  
  970. #ifdef POSIX
  971.  
  972. #include <termios.h>
  973.  
  974. /*
  975.  *    Set the desired input mode.
  976.  *
  977.  *    FALSE enables immediate character processing (disable line processing
  978.  *    and signals for INTR, QUIT, and SUSP).  TRUE enables line processing 
  979.  *    and signals (disables immediate character processing).  In either 
  980.  *    case flow control (XON/XOFF) is still active.  
  981.  *
  982.  *    If the termios function calls fail, then fall back on using 
  983.  *    CURSES' cbreak()/nocbreak() functions; however signals will be
  984.  *    still be in effect.
  985.  */
  986. void
  987. lineinput(bf)
  988. int bf;
  989. {
  990.     int error;
  991.     struct termios term;
  992.     error = tcgetattr(fileno(stdin), &term) < 0;
  993.     if (!error) {
  994.         if (bf)
  995.             term.c_lflag |= ISIG | ICANON;
  996.         else
  997.             term.c_lflag &= ~(ISIG | ICANON);
  998.         error = tcsetattr(fileno(stdin), TCSANOW, &term) < 0;
  999.     }
  1000.     /* Fall back on CURSES functions that do almost what we need if
  1001.      * either tcgetattr() or tcsetattr() fail.
  1002.      */
  1003.     if (error) {
  1004.         if (bf)
  1005.             nocbreak();
  1006.         else
  1007.             cbreak();
  1008.     }
  1009. }
  1010.  
  1011. #else /* not POSIX */
  1012.  
  1013. #define lineinput(bf)    (bf ? nocbreak() : cbreak());
  1014.  
  1015. #endif /* POSIX */
  1016.  
  1017.  
  1018. char *
  1019. ptr(offset)
  1020. int offset;
  1021. {
  1022.     if (offset < 0)
  1023.         return (buf);
  1024.     return (buf+offset + (buf+offset < gap ? 0 : egap-gap));
  1025. }
  1026.  
  1027. int
  1028. pos(pointer)
  1029. char *pointer;
  1030. {
  1031.     return (pointer-buf - (pointer < egap ? 0 : egap-gap)); 
  1032. }
  1033.  
  1034. void
  1035. top()
  1036. {
  1037.     point = 0;
  1038. }
  1039.  
  1040. void
  1041. bottom()
  1042. {
  1043.     epage = point = pos(ebuf);
  1044. }
  1045.  
  1046. void
  1047. quit()
  1048. {
  1049.     done = 1;
  1050. }
  1051.  
  1052. void
  1053. redraw()
  1054. {
  1055.     int col;
  1056.     keymap_t *kp;
  1057.     clear();
  1058.     if (textline != HELPLINE) {
  1059.         move(HELPLINE, 0);
  1060.         /* Display all the help text entries. */
  1061.         for (kp = key_map; kp->entry != NULL; ++kp)
  1062.             if (kp->code == K_HELP_TEXT)
  1063.                 addstr(kp->entry);
  1064.         ruler(COLS);
  1065.         getyx(stdscr, textline, col);
  1066.     }
  1067.     display();
  1068. }
  1069.  
  1070. void
  1071. movegap()
  1072. {
  1073.     char *p = ptr(point);
  1074.     while (p < gap)
  1075.         *--egap = *--gap;
  1076.     while (egap < p)
  1077.         *gap++ = *egap++;
  1078.     point = pos(egap);
  1079. }
  1080.  
  1081. int
  1082. prevline(offset)
  1083. int offset;
  1084. {
  1085.     char *p;
  1086.     while (buf < (p = ptr(--offset)) && *p != '\n')
  1087.         ;
  1088.     return (buf < p ? ++offset : 0);
  1089. }
  1090.  
  1091. int
  1092. nextline(offset)
  1093. int offset;
  1094. {
  1095.     char *p;
  1096.     while ((p = ptr(offset++)) < ebuf && *p != '\n')    
  1097.         ;
  1098.     return (p < ebuf ? offset : pos(ebuf));
  1099. }
  1100.  
  1101. int
  1102. adjust(offset, column)
  1103. int offset, column;
  1104. {
  1105.     char *p;
  1106.     int i = 0;
  1107.     while ((p = ptr(offset)) < ebuf && *p != '\n' && i < column) {
  1108.         i += *p == '\t' ? 8-(i&7) : 1;
  1109.         ++offset;
  1110.     }
  1111.     return (offset);
  1112. }
  1113.  
  1114. void
  1115. left()
  1116. {
  1117.     if (0 < point)
  1118.         --point;
  1119.  
  1120. void
  1121. right()
  1122. {
  1123.     if (point < pos(ebuf))
  1124.         ++point;
  1125. }
  1126.  
  1127. void
  1128. up()
  1129. {
  1130.     point = adjust(prevline(prevline(point)-1), col);
  1131. }
  1132.  
  1133. void
  1134. down()
  1135. {
  1136.     point = adjust(nextline(point), col);
  1137. }
  1138.  
  1139. void
  1140. lnbegin()
  1141. {
  1142.     point = prevline(point);
  1143. }
  1144.  
  1145. void
  1146. lnend()
  1147. {
  1148.     point = nextline(point);
  1149.     left();
  1150. }
  1151.  
  1152. void
  1153. wleft()
  1154. {
  1155.     char *p;
  1156.     while (!isspace(*(p = ptr(point))) && buf < p)
  1157.         --point;
  1158.     while (isspace(*(p = ptr(point))) && buf < p)
  1159.         --point;
  1160. }
  1161.  
  1162. void
  1163. pgdown()
  1164. {
  1165.     page = point = prevline(epage-1);
  1166.     while (textline < row--)
  1167.         down();
  1168.     epage = pos(ebuf);
  1169. }
  1170.  
  1171. void
  1172. pgup()
  1173. {
  1174.     int i = LINES;
  1175.     while (textline < --i) {
  1176.         page = prevline(page-1); 
  1177.         up();
  1178.     }
  1179. }
  1180.  
  1181. void
  1182. wright()
  1183. {
  1184.     char *p;
  1185.     while (!isspace(*(p = ptr(point))) && p < ebuf)
  1186.         ++point;
  1187.     while (isspace(*(p = ptr(point))) && p < ebuf)
  1188.         ++point;
  1189. }
  1190.  
  1191. void
  1192. insert()
  1193. {
  1194.     movegap();
  1195.     if (gap < egap) {
  1196.         *gap++ = input == '\r' ? '\n' : input;
  1197.         modified = TRUE;
  1198.     }
  1199.     point = pos(egap);
  1200. }
  1201.  
  1202. keymap_t key_exit[] = {
  1203.     { K_INSERT_EXIT, NULL },
  1204.     { K_STTY_ERASE, NULL },
  1205.     { 0, NULL }
  1206. };
  1207.  
  1208. void
  1209. insert_mode()
  1210. {
  1211.     int ch;
  1212.     movegap();
  1213.     while ((ch = getkey(key_exit)) != K_INSERT_EXIT) {
  1214.         if (ch == K_STTY_ERASE) {
  1215.             if (buf < gap) {
  1216.                 --gap;
  1217.                 modified = TRUE;
  1218.             }
  1219.         } else if (gap < egap) {
  1220.             *gap++ = ch == '\r' ? '\n' : ch;
  1221.             modified = TRUE;
  1222.         }
  1223.         point = pos(egap);
  1224.         display();
  1225.     }
  1226. }
  1227.  
  1228. void
  1229. backsp()
  1230. {
  1231.     movegap();
  1232.     if (buf < gap) {
  1233.         --gap;
  1234.         modified = TRUE;
  1235.     }
  1236.     point = pos(egap);
  1237. }
  1238.  
  1239. void
  1240. delete()
  1241. {
  1242.     movegap();
  1243.     if (egap < ebuf) {
  1244.         point = pos(++egap);
  1245.         modified = TRUE;
  1246.     }
  1247. }
  1248.  
  1249. void
  1250. file()
  1251. {
  1252.     if (!save(filename))
  1253.         save(HUP);
  1254. }
  1255.  
  1256. int
  1257. save(fn)
  1258. char *fn;
  1259. {
  1260.     FILE *fp;
  1261.     size_t length;
  1262.     int opoint, ok;
  1263.     fp = fopen(fn, "w");
  1264.     if ((ok = (fp != NULL))) {
  1265.         opoint = point;
  1266.         top();
  1267.         movegap();
  1268.         length = (size_t) (ebuf-egap);
  1269.         ok = fwrite(egap, sizeof (char), length, fp) == length;
  1270.         (void) fclose(fp);
  1271.         point = opoint;
  1272.         if (ok)
  1273.             modified = FALSE;
  1274.     }
  1275.     return (ok);
  1276. }
  1277.  
  1278. void
  1279. help()
  1280. {
  1281.     textline = textline == HELPLINE ? -1 : HELPLINE;
  1282.     redraw();
  1283. }
  1284.  
  1285. void
  1286. block()
  1287. {
  1288.     marker = marker == NOMARK ? point : NOMARK;
  1289. }
  1290.  
  1291. void
  1292. cut()
  1293. {
  1294.     char *p;
  1295.     int opoint = point;
  1296.     if (marker == NOMARK || point == marker)
  1297.         return;
  1298.     if (scrap != NULL) {
  1299.         free(scrap);
  1300.         scrap = NULL;
  1301.     }
  1302.     if (point < marker) {
  1303.         nscrap = marker - point;
  1304.         p = ptr(point);
  1305.     } else {
  1306.         nscrap = point - marker;
  1307.         p = ptr(marker);
  1308.         point = marker;
  1309.     }
  1310.     movegap();
  1311.     if ((scrap = malloc(nscrap)) == NULL) {
  1312.         point = opoint;
  1313.         beep();
  1314.     } else {
  1315.         (void) memcpy(scrap, p, nscrap);
  1316.         egap += nscrap;
  1317.         block();
  1318.         point = pos(egap);
  1319.         modified = TRUE;
  1320.     }
  1321. }
  1322.  
  1323. void
  1324. paste()
  1325. {
  1326.     if (nscrap < egap - gap) {
  1327.         movegap();
  1328.         memcpy(gap, scrap, nscrap);
  1329.         gap += nscrap;
  1330.         point = pos(egap);
  1331.         modified = TRUE;
  1332.     } else {
  1333.         beep();
  1334.     }
  1335. }
  1336.  
  1337. void
  1338. ruler(ncols)
  1339. int ncols;
  1340. {
  1341.     int r, c, col;
  1342.     char buffer[5];
  1343.     getyx(stdscr, r, c);
  1344.     for (col = 1; col <= ncols; ++col) {
  1345.         switch (col % 10) {
  1346.         case 0:
  1347.             sprintf(buffer, "%d", col);
  1348.             mvprintw(r, col - strlen(buffer), buffer);
  1349.             break;
  1350.         case 5:
  1351.             addch('5');
  1352.             break;
  1353.         default:
  1354.             addch('.');
  1355.         }
  1356.     }
  1357. }
  1358.  
  1359. void
  1360. display()
  1361. {
  1362.     char *p;
  1363.     int i, j;
  1364.     standout();
  1365.     mvprintw(MSGLINE, 0, "File \"%s\" ", filename);
  1366.     if (modified) {
  1367.         addstr("modified.");
  1368.     } else {
  1369.         i = point;
  1370.         j = epage;
  1371.         bottom();     
  1372.         printw("%d bytes.", point);
  1373.         point = i;
  1374.         epage = j;
  1375.     }
  1376.     standend();
  1377.     clrtoeol();
  1378.     if (point < page)
  1379.         page = prevline(point);
  1380.     if (epage <= point) {
  1381.         page = nextline(point); 
  1382.         i = (page == pos(ebuf) ? LINES-2 : LINES) - textline; 
  1383.         while (0 < i--)
  1384.             page = prevline(page-1);
  1385.     }
  1386.     move(textline, 0);
  1387.     i = textline;
  1388.     j = 0;
  1389.     epage = page;
  1390.     while (1) {
  1391.         if (point == epage) {
  1392.             row = i;
  1393.             col = j;
  1394.         }
  1395.         p = ptr(epage);
  1396.         if (LINES <= i || ebuf <= p)
  1397.             break;
  1398.         if (*p != '\r') {
  1399.             if (marker != NOMARK) {
  1400.                 if ((marker <= epage && epage < point)
  1401.                 || (point <= epage && epage < marker))
  1402.                     standout();
  1403.                 else
  1404.                     standend();
  1405.             }
  1406.             if (isprint(*p) || *p == '\t' || *p == '\n') {
  1407.                 j += *p == '\t' ? 8-(j&7) : 1;
  1408.                 addch(*p);
  1409.             } else {
  1410.                 char *ctrl = unctrl(*p);
  1411.                 j += (int) strlen(ctrl);
  1412.                 addstr(ctrl);
  1413.             }
  1414.         }
  1415.         if (*p == '\n' || COLS <= j) {
  1416.             j -= COLS;
  1417.             if (j < 0)
  1418.                 j = 0;
  1419.             ++i;
  1420.         }
  1421.         ++epage;
  1422.     }
  1423.     standend();
  1424.     clrtobot();
  1425.     if (++i < LINES)
  1426.         mvaddstr(i, 0, "<< EOF >>");
  1427.     move(row, col);
  1428.     refresh();
  1429. }
  1430.  
  1431. void
  1432. fatal(code)
  1433. int code;
  1434. {
  1435.     static char *exit_msg[] = {
  1436.         "Program terminated successfully.\n",
  1437.         "Unspecified error.\n",
  1438.         "usage:    ae <file>\n\tea <file>\n",
  1439.         "Program failed to initialize the screen.\n",
  1440.         "Problem with configuration file.\n",
  1441.     };
  1442.     if (curscr != NULL) {
  1443.         endwin();
  1444.         putchar('\n');
  1445.     }
  1446.     fputs(exit_msg[code], stderr);
  1447.     exit(code);
  1448. }
  1449.  
  1450. int
  1451. main(argc, argv)
  1452. int argc;
  1453. char **argv;
  1454. {
  1455.     FILE *fp;
  1456.     char *p = *argv;
  1457.     int i = (int) strlen(p);
  1458.     egap = ebuf = buf + BUF;
  1459.     if (initscr() == NULL)
  1460.         fatal(EXIT_INITSCR);
  1461.     if (argc < 2)
  1462.         fatal(EXIT_USAGE);
  1463.     /* Find basename. */
  1464.     while (0 <= i && p[i] != '\\' && p[i] != '/')
  1465.         --i;
  1466.     p += i+1;
  1467.     if (strncmp(p, "ae", 2) == 0 || strncmp(p, "AE", 2) == 0) {
  1468.         keymap_t *kp;
  1469.         if (initkey(AE_CONFIG, &key_map) != INITKEY_OK)
  1470.             fatal(EXIT_CONFIG);
  1471.         modeless = FALSE;
  1472.         /* Define insert mode keys from the master table. */
  1473.         for (kp = key_map; kp->entry != NULL; ++kp) {
  1474.             switch (kp->code) {
  1475.             case K_INSERT_EXIT:
  1476.                 key_exit[0].entry = kp->entry;
  1477.                 break;
  1478.             case K_STTY_ERASE:
  1479.                 key_exit[1].entry = kp->entry;
  1480.                 break;
  1481.             }
  1482.         }
  1483.     } else if (strncmp(p, "ea", 2) == 0 || strncmp(p, "EA", 2) == 0) {
  1484.         if (initkey(EA_CONFIG, &key_map) != INITKEY_OK)
  1485.             fatal(EXIT_CONFIG);
  1486.         modeless = TRUE;
  1487.     } else {
  1488.         fatal(EXIT_USAGE);
  1489.     }
  1490.     noecho();
  1491.     lineinput(FALSE);
  1492.     idlok(stdscr, TRUE);
  1493.     fp = fopen(filename = *++argv, "r");
  1494.     if (fp != NULL) {
  1495.         gap += fread(buf, sizeof (char), (size_t) BUF, fp);
  1496.         fclose(fp);
  1497.     }
  1498.     top();
  1499.     help();
  1500.     while (!done) {
  1501.         display();
  1502.         i = 0; 
  1503.         input = getkey(key_map); 
  1504.         while (table[i].key != 0 && input != table[i].key)
  1505.             ++i;
  1506.         if (table[i].func != NULL) 
  1507.             (*table[i].func)();
  1508.         else if (modeless)
  1509.             insert();
  1510.     }
  1511.     if (scrap != NULL)
  1512.         free(scrap);
  1513.     finikey(key_map);
  1514.     endwin();
  1515.     putchar('\n');
  1516.     return (EXIT_OK);
  1517. }
  1518. ----ae.rc----
  1519. .help_text
  1520. Left, right, up, down    h  j  k  l    Beginning and end of line    [  ]
  1521. Word left and right    H  L        Top and bottom of file        t  b
  1522. Page up and down    J  K        Delete left and right        X  x
  1523. Insert on and off    i  ESC        Help on and off            ?
  1524. Save file        F        Block on and off        B
  1525. Redraw            R        Cut block to scrap        C
  1526. Quit            Q        Paste scrap into buffer        P
  1527. .end
  1528. .stty_erase
  1529. .cursor_up    k
  1530. .cursor_down    j
  1531. .cursor_left    h
  1532. .cursor_right    l
  1533. .page_up    K
  1534. .page_down    J
  1535. .word_left    H
  1536. .word_right    L
  1537. .line_left    [
  1538. .line_right    ]
  1539. .file_top    t
  1540. .file_bottom    b
  1541. .delete_left    X
  1542. .delete_right    x
  1543. .insert_enter    i
  1544. .insert_exit    ^[
  1545. .help        ?
  1546. .block        B
  1547. .cut        C
  1548. .paste        P
  1549. .file_save    F
  1550. .redraw        R
  1551. .quit        Q
  1552. ----ea.rc----
  1553. .help_text
  1554. Left, right, up, down    arrow keys    Beginning and end of line    ^A ^D
  1555. Word left and right    ^W ^E        Top and bottom of file        ^T ^B
  1556. Page up and down    ^P ^N        Delete left and right     backspace ^X
  1557. Insert            typed keys    Help on and off            F1
  1558. Save file        ^F        Block on and off        F2
  1559. Redraw            ^R        Cut block to scrap        F3
  1560. Quit            ^C        Paste scrap into buffer        F4
  1561. .end
  1562. .cursor_up    ^[[A
  1563. .cursor_down    ^[[B
  1564. .cursor_left    ^[[D
  1565. .cursor_right    ^[[C
  1566. .page_up    ^P
  1567. .page_down    ^N
  1568. .word_left    ^W
  1569. .word_right    ^E
  1570. .line_left    ^A
  1571. .line_right    ^D
  1572. .file_top    ^T
  1573. .file_bottom    ^B
  1574. .delete_left    ^H
  1575. .delete_right    ^X
  1576. .help        ^[f1
  1577. .block        ^[f2
  1578. .cut        ^[f3
  1579. .paste        ^[f4
  1580. .file_save    ^F
  1581. .redraw        ^R
  1582. .quit        ^C
  1583. -- 
  1584. ant@mks.com                                                   Anthony C Howe 
  1585. Mortice Kern Systems Inc. 35 King St. N., Waterloo, Ontario, Canada, N2J 6W9
  1586. "Nice legs.  For a human that is." - Worf (Q-pid)
  1587.