home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-08-17 | 33.9 KB | 1,588 lines |
- Path: sparky!uunet!haven.umd.edu!darwin.sura.net!mips!swrinde!cs.utexas.edu!torn!watserv2.uwaterloo.ca!watserv1!mks.com!ant
- From: ant@mks.com (Anthony Howe)
- Newsgroups: comp.editors
- Subject: Ant's Editor August '92
- Message-ID: <1992Aug17.134903.15667@mks.com>
- Date: 17 Aug 92 13:49:03 GMT
- Sender: ant@mks.com (Anthony Howe)
- Organization: Mortice Kern Systems, Waterloo, Ontario, CANADA
- Lines: 1577
-
- Anthony's Editor August 92
- ==========================
-
- WHAT'S NEW
-
- + Configuartion file support for help text and key bindings.
- + Message line: tells you that the file has been modified or saved.
- + Block, Cut, and Paste commands.
- + Fixed control character display problem.
- - Dropped flip-editor-style command.
- - Dropped TERMCAP function-key support in favour of configuration files.
-
- AE'91, in its obfuscated form, won "Best Utility" in the 1991 International
- Obfuscated C Code Contest. Since that contest, AE has been revised and
- extended in order to try new ideas and provide better functionality, while
- still retaining a simple interface and modualar design. There are four
- files included in the August '92 distribution.
-
- ae.man Manual reference and installation guide.
- ae.c The source.
- ae.rc Configuration file for AE
- ea.rc Configuration file for EA (ansi cursor keys)
-
- AE'92 merges two schools of thought by providing both VI style (modual)
- and EMACS style (modeless) editing interfaces. Users can configure the
- command-key bindings and the help text for either style.
-
- AE'92 is simple enough that anyone can modify it to add features. The
- source is in the Public Domain, so people are free to modify and use
- as they see fit.
-
- e.g.
- o Tutorials on the Buffer Gap Scheme and/or editor design.
- o A basis for an editor that can be built into a project.
- o An editor for novice users.
-
- AE has been know to compile on a wide variety of machines and compilers
- like BSD and System V Unix with GNU C, PC mahcines with WatCom C or Turbo C,
- and ATARI ST machines with Sozobon C. Any machine that provides at least
- K&R C and a CURSES library should have no trouble getting AE to compile.
-
- See the INSTALLATION section of the manual on how to build AE. Also
- take note of the BUG section of the manual.
-
- Anthony Howe
- ant@mks.com
-
- ----ae.man---
- 0. NAME
-
- ae Ant's Editor August '92
-
-
- 1. SYNOPSIS
-
- ae <filename>
- ea <filename>
-
-
- 2. OPERANDS
-
- filename The name of a existing or new file to edit is required.
-
-
- 3. DESCRIPTION
-
- AE is a full screen, modual text editor, and EA is a full screen,
- modelss text editor. The source should be portable to any environment
- that provides a K&R C compiler and a CURSES library.
-
- Text files consists of lines of printable text or tab characters.
- A line can be of arbitary length and is delimited by either a
- newline or the end of file. Carriage return is mapped to newline
- on input and ignored on output. Tab stops are every eight columns.
-
-
- 4. COMMANDS
-
- Two default configuration files are supplied. "ae.rc" is read when
- AE is invoked, and "ea.rc" is read when EA is used.
-
-
- 4.1 AE MODUAL STYLE
-
- h j k l left, down, up, right cursor movement
- H J K L word left, page down, page up, word right
- [ ] beginning and end of line
- t b top and bottom of file
- i ESC enter insert mode, escape to leave
- x delete character under the cursor
- X delete character left of the cursor
- ? toggle help on/off
- B toggle block on/off
- C cut block to scrap
- P paste scrap into buffer
- F write buffer to file
- R refresh the screen
- Q quit
-
-
- 4.2 EA MODELESS STYLE
-
- cursor keys left, down, up, right cursor movement
- ^W ^E word left, word right
- ^N ^P page down, page up
- ^A ^D beginning and end of line
- ^T ^B top and bottom of file
- backspace delete character left of the cursor
- ^X delete character under the cursor
- F1 toggle help on/off
- F2 toggle block on/off
- F3 cut block to scrap
- F4 paste scrap into buffer
- ^F write buffer to file
- ^R refresh the screen
- ^C quit
-
-
- 5. CONFIGURATION
-
- The user is able to configure the editor with the help text and keys
- that the user likes. It is possible to define a modual or modeless
- key interface and support multi-character key sequences.
-
- The configuration file layout is fairly simple. All control words
- begin on a line starting with a period (.). Invalid keywords are
- ignored. The following keys words are used:
-
- .help_text
- All the subsequent lines upto the next keyword are considered
- help text. The terminating keyword is discarded. There may
- be more than one .help_text given.
-
- .insert_enter <string>
- .insert_exit <string>
- Enter and exit insert mode.
-
- .delete_left <string>
- .delete_right <string>
- Delete character to the left or right of the cursor.
-
- .block <string>
- .cut <string>
- .paste <string>
- Block on/off toggle, cut block, and paste before.
-
- .cursor_up <string>
- .cursor_down <string>
- .cursor_left <string>
- .cursor_right <string>
- Cursor motion in four directions. Typically the arrow keys.
-
- .page_up <string>
- .page_down <string>
- Previous or next screen full of text.
-
- .word_left <string>
- .word_right <string>
- Move to word left or right of the current cursor.
-
- .line_left <string>
- .line_right <string>
- Move to the beginning or end of the line.
-
- .file_top <string>
- .file_bottom <string>
- Move to the top and bottom of the file buffer.
-
- .help <string>
- Toggle the help text and ruler line on and off.
-
- .quit <string>
- Exit the editor.
-
- .redraw <string>
- Force a screen redraw.
-
- .file_save <string>
- Save the file buffer to the current filename.
-
- .itself <character>
- The following character represents itself. This is really a
- redundant keyword since any key not defined by a keyword,
- automatically represents itself.
-
- .stty_erase
- .stty_kill
- Declare that the terminal's values for the erase and kill
- characters should be used in insert mode to backspace-erase,
- or discard and restart input.
-
- The parameters <string> and <character> can be any text other than
- whitspace (blank, tab, carriage-return, and newline). It is possible
- to specify control keys by prefixing the following characters with a
- caret (^):
-
- @ a b c d e f g h i j k l m n o
- p q r s t u v w x y z [ \ ] ^ _
-
- Also numeric and literal escapes are possible. A numeric escape
- begins with a backslash followed by either an octal number with
- leading '0', a hex number with leading '0x', or a decimal number.
- The value must be between 0 to 255.
-
- A literal escape also begins with a backslash but is then followed
- by a character that is not a digit.
-
- eg.
- .insert_enter i <-- single character string
- .insert_exit ^[ <-- defines ASCII ESC
- .delete_right \0x7f <-- defines ASCII DEL
- .cursor_up ^[[A <-- defines sequence ESC [ A
-
- Note that the name of the editor determines whether or not the editor
- behaves in a modual (AE) or modeless (EA) fashion.
-
-
- 6. EXIT STATUS
-
- 0 Success termination.
- 1 General error.
- 2 Usage error.
- 3 Failed to initialize the screen.
- 4 Problem with the configuration file.
-
-
- 7. INSTALLATION
-
- Requires K&R C and a CURSES library for the given target machine.
-
- To build AE on System V equivalent systems, type
-
- cc -O -o ae ae.c -lcurses
-
- To build AE on BSD equivalent systems, type
-
- cc -O -o ae ae.c -lcurses -ltermcap
-
- To build AE on systems that have POSIX.1 or System V termios library,
- add to the command line -DPOSIX=1, like
-
- cc -DPOSIX=1 -O -o ae ae.c -lcurses
-
- To use EA version of AE either link or copy the file to EA.
-
- cp ae ea
-
- If the constants BUF, HUP, AE_CONFIG, or AE_CONFIG are not defined on
- the compile command line then the defaults used are
-
- BUF = 32767
- HUP = "ae.hup"
- AE_CONFIG = "ae.rc"
- EA_CONFIG = "ea.rc"
-
- The BUF size should be set at compile time to 32767. This value was
- used because the Sozobon C compiler for the Atari ST has 16 bit ints
- and a limit on the size of arrays & structures of 32k. Also the
- WatCom C compiler for the PC also has 16 bits ints. On machines that
- have 32 bit ints (most unix boxes), a larger value for BUF could be
- used.
-
- It is recommend that compact memory model be used on PC class
- machines. Small memory model may work too provided BUF is not too
- large.
-
- HUP should define the name of the fall-back write file. POSIX should
- be defined for systems that have POSIX.1 termios support (which is
- based on System V termios).
-
- Most EBCDIC machines use block mode terminals. This is a problem
- that has not been addressed and/or tested for.
-
-
- 8. BUGS
-
- This editor will display a file with long lines, but has trouble
- scrolling the screen with long lines. Paging up and down should
- work correctly, however.
-
-
- 9. REFERENCES
-
- [Fin80] Craig A. Finseth, "Theory and Practice of Text Editors or
- A Cookbook For An EMACS", TM-165, MIT Lab. for Computer
- Science
-
- [KeP81] Kernighan & Plauger, "Software Tools in Pascal",
- Addison-Wesley, 81, chapter 6
-
- [Mil86] Eugene W. Myers & Webb Miller, "Row-replacement Algorithums
- for Screen Editors", TR 86-19, Dept. of Compter Science,
- U. of Arizona
-
- [MyM86] Eugene W. Myers & Webb Miller, "A simple row-replacement
- method", TR 86-28, Dept. of Compter Science, U. of Arizona
-
- [Mil87] Webb Miller, "A Software Tools Sampler", Prentice Hall, 87
- ISBN 0-13-822305-X, chapter 5
-
- [net90] "Editor 101/102" articles from comp.editors
-
-
- 10. FILES
-
- ae.man AE August '92 manual
- ae.c AE August '92 source
- ae.rc Configuration file for AE modual style
- ea.rc Configuration file for EA modeless style (ansi cursor keys)
-
- ----ae.c----
- /*
- * ae.c
- *
- * Anthony's Editor August '92
- *
- * Public Domain 1991, 1992 by Anthony Howe. All rights released.
- */
-
- #include <ctype.h>
- #include <curses.h>
- #include <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #undef _
- #ifdef __STDC__
- #define _(x) x
- #else
- #define _(x) ()
- #endif
-
- #ifndef BUF
- #define BUF 32767
- #endif /* BUF */
-
- #ifndef HUP
- #define HUP "ae.hup"
- #endif /* HUP */
-
- #ifndef AE_CONFIG
- #define AE_CONFIG "ae.rc"
- #endif /* AE_CONFIG */
-
- #ifndef EA_CONFIG
- #define EA_CONFIG "ea.rc"
- #endif /* EA_CONFIG */
-
- /* Exit status. */
- #define EXIT_OK 0
- #define EXIT_ERROR 1
- #define EXIT_USAGE 2
- #define EXIT_INITSCR 3
- #define EXIT_CONFIG 4
-
- /* Screen partitioning. */
- #define MSGLINE 0
- #define HELPLINE 1
- #undef TEXTLINE
-
- #define NOMARK -1
-
- typedef struct keytable_t {
- int key;
- void (*func) _((void));
- } keytable_t;
-
- int done, modified, modeless;
- int point, page, epage;
- int row, col;
- int input;
- int marker = NOMARK;
- int textline = HELPLINE;
- size_t nscrap;
- char buf[BUF];
- char *ebuf;
- char *gap = buf;
- char *egap;
- char *filename;
- char *scrap;
-
- /*
- * The following assertions must be maintained.
- *
- * o buf <= gap <= egap <= ebuf
- * If gap == egap then the buffer is full.
- *
- * o cursor = ptr(point) and cursor < gap or egap <= cursor
- *
- * o page <= point < epage
- *
- * o 0 <= point <= pos(ebuf) <= BUF
- *
- *
- * Memory representation of the file:
- *
- * low buf -->+----------+
- * | front |
- * | of file |
- * gap -->+----------+<-- character not in file
- * | hole |
- * egap -->+----------+<-- character in file
- * | back |
- * | of file |
- * high ebuf -->+----------+<-- character not in file
- *
- *
- * Point & Gap
- *
- * The Point is the current cursor position while the Gap is the
- * position where the last edit operation took place. The Gap is
- * ment to be the cursor but to avoid shuffling characters while
- * the cursor moves it is easier to just move a pointer and when
- * something serious has to be done then you move the Gap to the
- * Point.
- *
- *
- * Use of stdio for portability.
- *
- * Stdio will handle the necessary conversions of text files to
- * and from a machine specific format. Things like fixed length
- * records; CRLF mapping into <newline> (\n) and back again;
- * null padding; control-Z end-of-file marks; and other assorted
- * bizare issues that appear on many unusual machines.
- *
- * AE is meant to be simple in both code and usage. With that
- * in mind certain assumptions are made.
- *
- * Reading: If a file cannot be opened, assume that it is a
- * new file. If an error occurs, fall back to a safe state and
- * assume an empty file. fread() is typed size_t which is an
- * unsigned number. Zero (0) would indicate a read error or an
- * empty file. A return value less than BUF is alright, since
- * we asked for the maximum allowed.
- *
- * Writing: If the file cannot be opened or a write error occurs,
- * then we scramble and save the user's changes in a file called
- * ae.hup. If ae.hup fails to open or a write error occurs, then
- * we assume that shit happens.
- *
- */
-
- int adjust _((int, int));
- int nextline _((int));
- int pos _((char *));
- int prevline _((int));
- int save _((char *));
- char *ptr _((int));
- void fatal _((int));
- void ruler _((int));
-
- void backsp _((void));
- void bottom _((void));
- void delete _((void));
- void display _((void));
- void down _((void));
- void file _((void));
- void help _((void));
- void insert _((void));
- void insert_mode _((void));
- void left _((void));
- void lnbegin _((void));
- void lnend _((void));
- void movegap _((void));
- void pgdown _((void));
- void pgup _((void));
- void redraw _((void));
- void right _((void));
- void quit _((void));
- void flip _((void));
- void top _((void));
- void up _((void));
- void wleft _((void));
- void wright _((void));
- void block _((void));
- void cut _((void));
- void paste _((void));
-
- /*
- * Configurable help and key support.
- *
- * The user is able to configure the editor with the help text
- * and keys that the user likes. It is possible to define a
- * modual or modeless key interface and support multi-character
- * key sequences.
- *
- * The configuration file layout is fairly simple. All control
- * words begin on a line starting with a period (.). Invalid
- * keywords are ignored. The following keys words are used:
- *
- * .help_text
- * All the subsequent lines upto the next keyword are
- * considered help text. The terminating keyword is
- * discarded. There may be more than one .help_text
- * given.
- *
- * .insert_enter <string>
- * .insert_exit <string>
- * Enter and exit insert mode. Use of .insert_enter will
- * denote a modual user interface.
- *
- * .delete_left <string>
- * .delete_right <string>
- * Delete character to the left or right of the cursor.
- *
- * .block <string>
- * .cut <string>
- * .paste <string>
- * Block on/off toggle, cut block, and paste before.
- *
- * .cursor_up <string>
- * .cursor_down <string>
- * .cursor_left <string>
- * .cursor_right <string>
- * Cursor motion in four directions. Typically the
- * arrow keys.
- *
- * .page_up <string>
- * .page_down <string>
- * Previous or next screen full of text.
- *
- * .word_left <string>
- * .word_right <string>
- * Move to word left or right of the current cursor.
- *
- * .line_left <string>
- * .line_right <string>
- * Move to the beginning or end of the line.
- *
- * .file_top <string>
- * .file_bottom <string>
- * Move to the top and bottom of the file buffer.
- *
- * .help <string>
- * Toggle the help text and ruler line on and off.
- *
- * .quit <string>
- * Exit the editor.
- *
- * .redraw <string>
- * Force a screen redraw.
- *
- * .file_save <string>
- * Save the file buffer to the current filename.
- *
- * .itself <character>
- * The following character represents itself. This is
- * really a redundant keyword since any key not defined
- * by a keyword, automatically represents itself.
- *
- * .stty_erase
- * .stty_kill
- * Declare that the terminal's values for the erase and
- * kill characters should be used in insert mode to
- * backspace-erase, or discard and restart input.
- *
- * The parameters <string> and <character> can be any text
- * other than whitspace (blank, tab, carriage-return, and newline).
- * It is possible to specify control keys by prefixing the following
- * characters with a caret (^):
- *
- * @ a b c d e f g h i j k l m n o
- * p q r s t u v w x y z [ \ ] ^ _
- *
- * Also numeric and literal escapes are possible. A numeric escape
- * begins with a backslash followed by either an octal number with
- * leading '0', a hex number with leading '0x', or a decimal number.
- * The value must be between 0 to 255.
- *
- * A literal escape also begins with a backslash but is then followed
- * by a character that is not a digit.
- *
- * eg.
- * .insert_enter i <-- single character string
- * .insert_exit ^[ <-- defines ASCII ESC
- * .delete_right \0x7f <-- defines ASCII DEL
- * .cursor_up ^[[A <-- defines sequence ESC [ A
- *
- * Note that the name of the editor determines whether or not
- * the editor behaves in a modual or modeless fashion.
- */
-
- #define K_INSERT_ENTER (-101)
- #define K_INSERT_EXIT (-102)
- #define K_DELETE_LEFT (-103)
- #define K_DELETE_RIGHT (-104)
-
- #define K_BLOCK (-105)
- #define K_CUT (-106)
- #define K_PASTE (-107)
-
- #define K_CURSOR_UP (-200)
- #define K_CURSOR_DOWN (-201)
- #define K_CURSOR_LEFT (-202)
- #define K_CURSOR_RIGHT (-203)
- #define K_PAGE_UP (-204)
- #define K_PAGE_DOWN (-205)
- #define K_WORD_LEFT (-206)
- #define K_WORD_RIGHT (-207)
- #define K_LINE_LEFT (-208)
- #define K_LINE_RIGHT (-209)
- #define K_FILE_TOP (-210)
- #define K_FILE_BOTTOM (-211)
-
- #define K_HELP_TEXT (-300)
- #define K_HELP (-301)
- #define K_QUIT (-302)
- #define K_REDRAW (-303)
- #define K_FILE_SAVE (-304)
-
- #define K_ITSELF (-400)
- #define K_STTY_ERASE (-401)
- #define K_STTY_KILL (-402)
-
- typedef struct keymap_t {
- short code;
- char *entry;
- } keymap_t;
-
- keymap_t *key_map;
- keymap_t key_names[] = {
- { K_INSERT_ENTER, ".insert_enter" },
- { K_INSERT_EXIT, ".insert_exit" },
- { K_DELETE_LEFT, ".delete_left" },
- { K_DELETE_RIGHT, ".delete_right" },
- { K_BLOCK, ".block" },
- { K_CUT, ".cut" },
- { K_PASTE, ".paste" },
- { K_CURSOR_UP, ".cursor_up" },
- { K_CURSOR_DOWN, ".cursor_down" },
- { K_CURSOR_LEFT, ".cursor_left" },
- { K_CURSOR_RIGHT, ".cursor_right" },
- { K_PAGE_UP, ".page_up" },
- { K_PAGE_DOWN, ".page_down" },
- { K_WORD_LEFT, ".word_left" },
- { K_WORD_RIGHT, ".word_right" },
- { K_LINE_LEFT, ".line_left" },
- { K_LINE_RIGHT, ".line_right" },
- { K_FILE_TOP, ".file_top" },
- { K_FILE_BOTTOM, ".file_bottom" },
- { K_HELP_TEXT, ".help_text" },
- { K_HELP, ".help" },
- { K_QUIT, ".quit" },
- { K_REDRAW, ".redraw" },
- { K_FILE_SAVE, ".file_save" },
- { K_ITSELF, ".itself" },
- { K_STTY_ERASE, ".stty_erase" },
- { K_STTY_KILL, ".stty_kill" },
- { 0, NULL }
- };
-
- /* initkey() and encodekey() error values. */
- #define INITKEY_OK 0
- #define INITKEY_OPEN 1
- #define INITKEY_MEMORY 2
- #define INITKEY_SYNTAX 3
- #define INITKEY_INVALID 4
- #define INITKEY_RANGE 5
-
- static char blank[] = " \t\r\n";
-
- char *strlwr _((char *));
- char *strdup _((char *));
- int initkey _((char *, keymap_t **));
- int encodekey _((char *, char **));
- char *gethelp _((FILE *));
- void finikey _((keymap_t *));
- int getkey _((keymap_t *));
-
- /*
- * Convert a string to lower case. Return the string pointer.
- */
- char *
- strlwr(str)
- char *str;
- {
- register char *s;
- for (s = str; *s != '\0'; ++s)
- *s = tolower(*s);
- return (str);
- }
-
- /*
- * Make a duplicate of a string. Return a pointer to an allocated
- * copy of the string, or NULL if malloc() failed.
- */
- char *
- strdup(str)
- char *str;
- {
- char *new;
- if ((new = (char*) malloc(strlen(str)+1)) != NULL)
- (void) strcpy(new, str);
- return (new);
- }
-
- /*
- * Return an INITKEY_xxx error status. Pass-back a pointer to
- * an encoded string, or NULL for an error in 'strp'.
- */
- int
- encodekey(str, strp)
- char *str, **strp;
- {
- long number;
- char *ptr, *p, *ctrl;
- static char control[] = "@abcdefghijklmnopqrstuvwxyz[\\]^_";
- *strp = NULL;
- if ((ptr = strdup(str)) == NULL)
- return (INITKEY_MEMORY);
- /* Duplicating the string is a cheap way of allocating
- * enough memory to store the encoded string. The
- * process of encoding always generates a string less
- * than or equal to the original string length.
- */
- for (p = ptr; *str != '\0'; ++p) {
- switch (*str) {
- case '^':
- /* Non-ASCII dependant control key mapping. */
- ++str;
- *str = tolower(*str);
- if ((ctrl = strchr(control, *str)) == NULL) {
- free(ptr);
- return (INITKEY_INVALID);
- }
- *p = (char) (ctrl - control);
- ++str;
- break;
- case '\\':
- /* Escapes. */
- ++str;
- if (isdigit(*str)) {
- /* Numeric escapes allow for
- * octal \0nnn
- * hex \0xnn
- * decimal \nnn
- */
- number = strtol(str, &str, 0);
- if (UCHAR_MAX <= number) {
- free(ptr);
- return (INITKEY_RANGE);
- }
- *p = (char) number;
- break;
- }
- /* Literal escapes. */
- default:
- /* Character. */
- *p = *str++;
- }
- }
- *p = '\0';
- *strp = ptr;
- return (INITKEY_OK);
- }
-
- /*
- * Return a pointer to allocated memory containing help text,
- * or NULL if malloc() failed.
- */
- char *
- gethelp(fp)
- FILE *fp;
- {
- size_t helplen, buflen;
- char *help, *ptr, buf[BUFSIZ];
- help = (char*) malloc(helplen = 1);
- if (help == NULL)
- return (NULL);
- help[0] = '\0';
- while (fgets(buf, BUFSIZ, fp) != NULL && buf[0] != '.') {
- buflen = strlen(buf);
- ptr = (char*) realloc(help, helplen + buflen);
- if (ptr == NULL)
- break;
- help = ptr;
- (void) strcpy(help + helplen - 1, buf);
- helplen += buflen;
- }
- return (help);
- }
-
- /*
- * Read a configuration file from either the current directory or
- * the user's home directory. Return an error status. Pass-back
- * either a pointer to a key mapping table, or NULL if an error
- * occured.
- */
- int
- initkey(fn, keys)
- char *fn;
- keymap_t **keys;
- {
- FILE *fp;
- int error, klen;
- keymap_t *kptr, *kn, *kp;
- char *word, buffer[BUFSIZ];
- kptr = NULL;
- error = INITKEY_OPEN;
- if ((fp = fopen(fn, "r")) == NULL) {
- if ((word = getenv("HOME")) == NULL)
- goto error_1;
- (void) sprintf(buffer, "%s/%s", word, fn);
- if ((fp = fopen(buffer, "r")) == NULL) {
- (void) sprintf(buffer, "%s\\%s", word, fn);
- if ((fp = fopen(buffer, "r")) == NULL)
- goto error_1;
- }
- }
- if ((kptr = (keymap_t*) malloc(sizeof (keymap_t))) == NULL) {
- error = INITKEY_MEMORY;
- goto error_2;
- }
- klen = 1;
- while (fgets(buffer, BUFSIZ, fp) != NULL) {
- if (buffer[0] != '.' || (word = strtok(buffer, blank)) == NULL)
- continue;
- (void) strlwr(word);
- for (kn = key_names; kn->entry != NULL; ++kn) {
- if (strcmp(word, kn->entry) == 0) {
- error = INITKEY_MEMORY;
- kp = (keymap_t*) realloc(
- kptr, ++klen * sizeof (keymap_t)
- );
- if (kp == NULL)
- goto error_2;
- kptr = kp;
- switch (kn->code) {
- case K_STTY_ERASE:
- buffer[0] = erasechar();
- buffer[1] = '\0';
- word = strdup(buffer);
- break;
- case K_STTY_KILL:
- buffer[0] = killchar();
- buffer[1] = '\0';
- word = strdup(buffer);
- break;
- case K_HELP_TEXT:
- word = gethelp(fp);
- break;
- default:
- word = strtok(NULL, blank);
- if (word == NULL) {
- error = INITKEY_SYNTAX;
- goto error_2;
- }
- error = encodekey(word, &word);
- }
- if (word == NULL)
- goto error_2;
- kptr[klen-2].entry = word;
- if (kn->code == K_ITSELF)
- kptr[klen-2].code = *word;
- else
- kptr[klen-2].code = kn->code;
- break;
- }
- }
- }
- error = INITKEY_OK;
- error_2:
- (void) fclose(fp);
- /* Assert that last keymap_t in kptr[] is zero. */
- kptr[klen-1].code = 0;
- kptr[klen-1].entry = NULL;
- if (error != INITKEY_OK) {
- finikey(kptr);
- kptr = NULL;
- }
- error_1:
- *keys = kptr;
- return (error);
- }
-
- void
- finikey(keys)
- keymap_t *keys;
- {
- keymap_t *kp;
- if (keys != NULL) {
- for (kp = keys; kp->entry != NULL; ++kp)
- free(kp->entry);
- free(keys);
- }
- }
-
- int
- getkey(keys)
- keymap_t *keys;
- {
- keymap_t *k;
- int submatch;
- static char buffer[128];
- static char *record = buffer;
-
- /* If recorded bytes remain, return next recorded byte. */
- if (*record != '\0')
- return (*record++);
- /* Reset record buffer. */
- record = buffer;
- do {
- /* Read and record one byte. */
- *record++ = getch();
- *record = '\0';
-
- /* If recorded bytes match any multi-byte sequence... */
- for (k = keys, submatch = 0; k->entry != NULL; ++k) {
- char *p, *q;
- for (p = buffer, q = k->entry; *p == *q; ++p, ++q) {
- if (*p == '\0') {
- /* Return extended key code. */
- return (k->code);
- }
- }
- if (*p == '\0') {
- /* Recorded bytes match anchored substring. */
- submatch = 1;
- }
- }
- /* If recorded bytes matched an anchored substring, loop. */
- } while (submatch);
- /* Return first recorded byte. */
- record = buffer;
- return (*record++);
- }
-
- /* ASCII Control Codes */
- #undef CTRL
- #define CTRL(x) ((x) & 0x1f)
-
- keytable_t table[] = {
- { K_CURSOR_LEFT, left },
- { K_CURSOR_RIGHT, right },
- { K_CURSOR_DOWN, down },
- { K_CURSOR_UP, up },
- { K_WORD_LEFT, wleft },
- { K_WORD_RIGHT, wright },
- { K_PAGE_UP, pgup },
- { K_PAGE_DOWN, pgdown },
- { K_LINE_LEFT, lnbegin },
- { K_LINE_RIGHT, lnend },
- { K_FILE_TOP, top },
- { K_FILE_BOTTOM, bottom },
- { K_DELETE_LEFT, backsp },
- { K_DELETE_RIGHT, delete },
- { K_INSERT_ENTER, insert_mode },
- { K_BLOCK, block },
- { K_CUT, cut },
- { K_PASTE, paste },
- { K_FILE_SAVE, file },
- { K_REDRAW, redraw },
- { K_HELP, help },
- { K_QUIT, quit },
- { K_ITSELF, NULL },
- { 0, NULL }
- };
-
- #ifdef POSIX
-
- #include <termios.h>
-
- /*
- * Set the desired input mode.
- *
- * FALSE enables immediate character processing (disable line processing
- * and signals for INTR, QUIT, and SUSP). TRUE enables line processing
- * and signals (disables immediate character processing). In either
- * case flow control (XON/XOFF) is still active.
- *
- * If the termios function calls fail, then fall back on using
- * CURSES' cbreak()/nocbreak() functions; however signals will be
- * still be in effect.
- */
- void
- lineinput(bf)
- int bf;
- {
- int error;
- struct termios term;
- error = tcgetattr(fileno(stdin), &term) < 0;
- if (!error) {
- if (bf)
- term.c_lflag |= ISIG | ICANON;
- else
- term.c_lflag &= ~(ISIG | ICANON);
- error = tcsetattr(fileno(stdin), TCSANOW, &term) < 0;
- }
- /* Fall back on CURSES functions that do almost what we need if
- * either tcgetattr() or tcsetattr() fail.
- */
- if (error) {
- if (bf)
- nocbreak();
- else
- cbreak();
- }
- }
-
- #else /* not POSIX */
-
- #define lineinput(bf) (bf ? nocbreak() : cbreak());
-
- #endif /* POSIX */
-
-
- char *
- ptr(offset)
- int offset;
- {
- if (offset < 0)
- return (buf);
- return (buf+offset + (buf+offset < gap ? 0 : egap-gap));
- }
-
- int
- pos(pointer)
- char *pointer;
- {
- return (pointer-buf - (pointer < egap ? 0 : egap-gap));
- }
-
- void
- top()
- {
- point = 0;
- }
-
- void
- bottom()
- {
- epage = point = pos(ebuf);
- }
-
- void
- quit()
- {
- done = 1;
- }
-
- void
- redraw()
- {
- int col;
- keymap_t *kp;
- clear();
- if (textline != HELPLINE) {
- move(HELPLINE, 0);
- /* Display all the help text entries. */
- for (kp = key_map; kp->entry != NULL; ++kp)
- if (kp->code == K_HELP_TEXT)
- addstr(kp->entry);
- ruler(COLS);
- getyx(stdscr, textline, col);
- }
- display();
- }
-
- void
- movegap()
- {
- char *p = ptr(point);
- while (p < gap)
- *--egap = *--gap;
- while (egap < p)
- *gap++ = *egap++;
- point = pos(egap);
- }
-
- int
- prevline(offset)
- int offset;
- {
- char *p;
- while (buf < (p = ptr(--offset)) && *p != '\n')
- ;
- return (buf < p ? ++offset : 0);
- }
-
- int
- nextline(offset)
- int offset;
- {
- char *p;
- while ((p = ptr(offset++)) < ebuf && *p != '\n')
- ;
- return (p < ebuf ? offset : pos(ebuf));
- }
-
- int
- adjust(offset, column)
- int offset, column;
- {
- char *p;
- int i = 0;
- while ((p = ptr(offset)) < ebuf && *p != '\n' && i < column) {
- i += *p == '\t' ? 8-(i&7) : 1;
- ++offset;
- }
- return (offset);
- }
-
- void
- left()
- {
- if (0 < point)
- --point;
- }
-
- void
- right()
- {
- if (point < pos(ebuf))
- ++point;
- }
-
- void
- up()
- {
- point = adjust(prevline(prevline(point)-1), col);
- }
-
- void
- down()
- {
- point = adjust(nextline(point), col);
- }
-
- void
- lnbegin()
- {
- point = prevline(point);
- }
-
- void
- lnend()
- {
- point = nextline(point);
- left();
- }
-
- void
- wleft()
- {
- char *p;
- while (!isspace(*(p = ptr(point))) && buf < p)
- --point;
- while (isspace(*(p = ptr(point))) && buf < p)
- --point;
- }
-
- void
- pgdown()
- {
- page = point = prevline(epage-1);
- while (textline < row--)
- down();
- epage = pos(ebuf);
- }
-
- void
- pgup()
- {
- int i = LINES;
- while (textline < --i) {
- page = prevline(page-1);
- up();
- }
- }
-
- void
- wright()
- {
- char *p;
- while (!isspace(*(p = ptr(point))) && p < ebuf)
- ++point;
- while (isspace(*(p = ptr(point))) && p < ebuf)
- ++point;
- }
-
- void
- insert()
- {
- movegap();
- if (gap < egap) {
- *gap++ = input == '\r' ? '\n' : input;
- modified = TRUE;
- }
- point = pos(egap);
- }
-
- keymap_t key_exit[] = {
- { K_INSERT_EXIT, NULL },
- { K_STTY_ERASE, NULL },
- { 0, NULL }
- };
-
- void
- insert_mode()
- {
- int ch;
- movegap();
- while ((ch = getkey(key_exit)) != K_INSERT_EXIT) {
- if (ch == K_STTY_ERASE) {
- if (buf < gap) {
- --gap;
- modified = TRUE;
- }
- } else if (gap < egap) {
- *gap++ = ch == '\r' ? '\n' : ch;
- modified = TRUE;
- }
- point = pos(egap);
- display();
- }
- }
-
- void
- backsp()
- {
- movegap();
- if (buf < gap) {
- --gap;
- modified = TRUE;
- }
- point = pos(egap);
- }
-
- void
- delete()
- {
- movegap();
- if (egap < ebuf) {
- point = pos(++egap);
- modified = TRUE;
- }
- }
-
- void
- file()
- {
- if (!save(filename))
- save(HUP);
- }
-
- int
- save(fn)
- char *fn;
- {
- FILE *fp;
- size_t length;
- int opoint, ok;
- fp = fopen(fn, "w");
- if ((ok = (fp != NULL))) {
- opoint = point;
- top();
- movegap();
- length = (size_t) (ebuf-egap);
- ok = fwrite(egap, sizeof (char), length, fp) == length;
- (void) fclose(fp);
- point = opoint;
- if (ok)
- modified = FALSE;
- }
- return (ok);
- }
-
- void
- help()
- {
- textline = textline == HELPLINE ? -1 : HELPLINE;
- redraw();
- }
-
- void
- block()
- {
- marker = marker == NOMARK ? point : NOMARK;
- }
-
- void
- cut()
- {
- char *p;
- int opoint = point;
- if (marker == NOMARK || point == marker)
- return;
- if (scrap != NULL) {
- free(scrap);
- scrap = NULL;
- }
- if (point < marker) {
- nscrap = marker - point;
- p = ptr(point);
- } else {
- nscrap = point - marker;
- p = ptr(marker);
- point = marker;
- }
- movegap();
- if ((scrap = malloc(nscrap)) == NULL) {
- point = opoint;
- beep();
- } else {
- (void) memcpy(scrap, p, nscrap);
- egap += nscrap;
- block();
- point = pos(egap);
- modified = TRUE;
- }
- }
-
- void
- paste()
- {
- if (nscrap < egap - gap) {
- movegap();
- memcpy(gap, scrap, nscrap);
- gap += nscrap;
- point = pos(egap);
- modified = TRUE;
- } else {
- beep();
- }
- }
-
- void
- ruler(ncols)
- int ncols;
- {
- int r, c, col;
- char buffer[5];
- getyx(stdscr, r, c);
- for (col = 1; col <= ncols; ++col) {
- switch (col % 10) {
- case 0:
- sprintf(buffer, "%d", col);
- mvprintw(r, col - strlen(buffer), buffer);
- break;
- case 5:
- addch('5');
- break;
- default:
- addch('.');
- }
- }
- }
-
- void
- display()
- {
- char *p;
- int i, j;
- standout();
- mvprintw(MSGLINE, 0, "File \"%s\" ", filename);
- if (modified) {
- addstr("modified.");
- } else {
- i = point;
- j = epage;
- bottom();
- printw("%d bytes.", point);
- point = i;
- epage = j;
- }
- standend();
- clrtoeol();
- if (point < page)
- page = prevline(point);
- if (epage <= point) {
- page = nextline(point);
- i = (page == pos(ebuf) ? LINES-2 : LINES) - textline;
- while (0 < i--)
- page = prevline(page-1);
- }
- move(textline, 0);
- i = textline;
- j = 0;
- epage = page;
- while (1) {
- if (point == epage) {
- row = i;
- col = j;
- }
- p = ptr(epage);
- if (LINES <= i || ebuf <= p)
- break;
- if (*p != '\r') {
- if (marker != NOMARK) {
- if ((marker <= epage && epage < point)
- || (point <= epage && epage < marker))
- standout();
- else
- standend();
- }
- if (isprint(*p) || *p == '\t' || *p == '\n') {
- j += *p == '\t' ? 8-(j&7) : 1;
- addch(*p);
- } else {
- char *ctrl = unctrl(*p);
- j += (int) strlen(ctrl);
- addstr(ctrl);
- }
- }
- if (*p == '\n' || COLS <= j) {
- j -= COLS;
- if (j < 0)
- j = 0;
- ++i;
- }
- ++epage;
- }
- standend();
- clrtobot();
- if (++i < LINES)
- mvaddstr(i, 0, "<< EOF >>");
- move(row, col);
- refresh();
- }
-
- void
- fatal(code)
- int code;
- {
- static char *exit_msg[] = {
- "Program terminated successfully.\n",
- "Unspecified error.\n",
- "usage: ae <file>\n\tea <file>\n",
- "Program failed to initialize the screen.\n",
- "Problem with configuration file.\n",
- };
- if (curscr != NULL) {
- endwin();
- putchar('\n');
- }
- fputs(exit_msg[code], stderr);
- exit(code);
- }
-
- int
- main(argc, argv)
- int argc;
- char **argv;
- {
- FILE *fp;
- char *p = *argv;
- int i = (int) strlen(p);
- egap = ebuf = buf + BUF;
- if (initscr() == NULL)
- fatal(EXIT_INITSCR);
- if (argc < 2)
- fatal(EXIT_USAGE);
- /* Find basename. */
- while (0 <= i && p[i] != '\\' && p[i] != '/')
- --i;
- p += i+1;
- if (strncmp(p, "ae", 2) == 0 || strncmp(p, "AE", 2) == 0) {
- keymap_t *kp;
- if (initkey(AE_CONFIG, &key_map) != INITKEY_OK)
- fatal(EXIT_CONFIG);
- modeless = FALSE;
- /* Define insert mode keys from the master table. */
- for (kp = key_map; kp->entry != NULL; ++kp) {
- switch (kp->code) {
- case K_INSERT_EXIT:
- key_exit[0].entry = kp->entry;
- break;
- case K_STTY_ERASE:
- key_exit[1].entry = kp->entry;
- break;
- }
- }
- } else if (strncmp(p, "ea", 2) == 0 || strncmp(p, "EA", 2) == 0) {
- if (initkey(EA_CONFIG, &key_map) != INITKEY_OK)
- fatal(EXIT_CONFIG);
- modeless = TRUE;
- } else {
- fatal(EXIT_USAGE);
- }
- noecho();
- lineinput(FALSE);
- idlok(stdscr, TRUE);
- fp = fopen(filename = *++argv, "r");
- if (fp != NULL) {
- gap += fread(buf, sizeof (char), (size_t) BUF, fp);
- fclose(fp);
- }
- top();
- help();
- while (!done) {
- display();
- i = 0;
- input = getkey(key_map);
- while (table[i].key != 0 && input != table[i].key)
- ++i;
- if (table[i].func != NULL)
- (*table[i].func)();
- else if (modeless)
- insert();
- }
- if (scrap != NULL)
- free(scrap);
- finikey(key_map);
- endwin();
- putchar('\n');
- return (EXIT_OK);
- }
- ----ae.rc----
- .help_text
- Left, right, up, down h j k l Beginning and end of line [ ]
- Word left and right H L Top and bottom of file t b
- Page up and down J K Delete left and right X x
- Insert on and off i ESC Help on and off ?
- Save file F Block on and off B
- Redraw R Cut block to scrap C
- Quit Q Paste scrap into buffer P
- .end
- .stty_erase
- .cursor_up k
- .cursor_down j
- .cursor_left h
- .cursor_right l
- .page_up K
- .page_down J
- .word_left H
- .word_right L
- .line_left [
- .line_right ]
- .file_top t
- .file_bottom b
- .delete_left X
- .delete_right x
- .insert_enter i
- .insert_exit ^[
- .help ?
- .block B
- .cut C
- .paste P
- .file_save F
- .redraw R
- .quit Q
- ----ea.rc----
- .help_text
- Left, right, up, down arrow keys Beginning and end of line ^A ^D
- Word left and right ^W ^E Top and bottom of file ^T ^B
- Page up and down ^P ^N Delete left and right backspace ^X
- Insert typed keys Help on and off F1
- Save file ^F Block on and off F2
- Redraw ^R Cut block to scrap F3
- Quit ^C Paste scrap into buffer F4
- .end
- .cursor_up ^[[A
- .cursor_down ^[[B
- .cursor_left ^[[D
- .cursor_right ^[[C
- .page_up ^P
- .page_down ^N
- .word_left ^W
- .word_right ^E
- .line_left ^A
- .line_right ^D
- .file_top ^T
- .file_bottom ^B
- .delete_left ^H
- .delete_right ^X
- .help ^[f1
- .block ^[f2
- .cut ^[f3
- .paste ^[f4
- .file_save ^F
- .redraw ^R
- .quit ^C
- --
- ant@mks.com Anthony C Howe
- Mortice Kern Systems Inc. 35 King St. N., Waterloo, Ontario, Canada, N2J 6W9
- "Nice legs. For a human that is." - Worf (Q-pid)
-