home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 198_02 / main.c < prev    next >
Text File  |  1990-01-23  |  56KB  |  1,612 lines

  1. /*
  2.  *    MicroEMACS 3.9
  3.  *             written by Dave G. Conroy.
  4.  *            substatially modified by Daniel M. Lawrence
  5.  *
  6.  *    (C)opyright 1987 by Daniel M. Lawrence
  7.  *    MicroEMACS 3.9 can be copied and distributed freely for any
  8.  *    non-commercial purposes. MicroEMACS 3.9 can only be incorporated
  9.  *    into commercial software with the permission of the current author.
  10.  *
  11.  * This file contains the main driving routine, and some keyboard processing
  12.  * code, for the MicroEMACS screen editor.
  13.  *
  14.  * REVISION HISTORY:
  15.  *
  16.  * 1.0  Steve Wilhite, 30-Nov-85
  17.  *      - Removed the old LK201 and VT100 logic. Added code to support the
  18.  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  19.  *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  20.  *      Steve Wilhite, 1-Dec-85
  21.  *      - massive cleanup on code in display.c and search.c
  22.  *
  23.  * 2.0  George Jones, 12-Dec-85
  24.  *      - Ported to Amiga.
  25.  *
  26.  * 3.0  Daniel Lawrence, 29-Dec-85
  27.  *      - rebound keys/added new fast buffered I/O for AMIGA
  28.  *    - added META- repeat commands
  29.  *    - added reposition default to center screen (yeah!)
  30.  *    - changed exit with modified buffers message
  31.  *    - made filesave tell us what it is doing
  32.  *    - changed search string entry to terminate with <ESC>
  33.  *      so we can use <NL> in search/replace strings
  34.  *    - updated version number in mode line to 3.0
  35.  *    12-Jan-86
  36.  *    - Added code to reconize the search/replace functions
  37.  *    - Added code to perform search/replace & query functions
  38.  *    14-Jan-86
  39.  *    - moved search logic to separate function in search.c
  40.  *    - added replace and query replace functions
  41.  *    - separated out control key expansions to be used by others in search.c
  42.  *    15-Jan-86
  43.  *    - changed "visiting" to finding
  44.  *    - changed yes/no responses to not need return
  45.  *    - cleaned up various messages
  46.  *    16-jan-86
  47.  *    - fixed spurious spawn message in MSDOS
  48.  *    - added ^X-S synonym to save command
  49.  *    - moved escape to shell to ^X-C
  50.  *    21-jan-86
  51.  *    - added code to suspend shell under BSD
  52.  *    22-jan-86
  53.  *    - added function key support (SPEC) under MSDOS
  54.  *    - Abort now prints [Aborted] on message line
  55.  *    23-jan-86
  56.  *    - Added modes and commands to set/unset them
  57.  *    24-jan-86
  58.  *    - Added Goto Line command
  59.  *    - added Rename Buffer command
  60.  *    28-jan-86
  61.  *    - added goto beginning and end of paragraph commands (META-P/META-N)
  62.  *    - re-wrote kdelete to use realloc. Gained MUCH speed here when
  63.  *      doing large wipes on both UNIX and MSDOS. Changed kill buffer
  64.  *      allocation block size from 256 bytes to 1 k
  65.  *    29-jan-86
  66.  *    - moved extern function declarations to efunc.h
  67.  *    - made name[] name binding table
  68.  *    30-jan-86
  69.  *    - fixed Previous/Next paragraph command not to wrap around EOF
  70.  *    - added Fill Paragraph command (META-Q)
  71.  *    4-feb-86
  72.  *    - added code to properly display long lines, scrolling them right
  73.  *      to left
  74.  *    5-feb-85
  75.  *    - rewrote code to right/left scroll...much better
  76.  *    - added shifted arrow keys on IBMPC
  77.  *    6-feb-85
  78.  *    - add option to allow forward-word to jump to beginning of
  79.  *      next word instead of end of current one. This is different from
  80.  *      other emacs' but can be configured off in estruct.h
  81.  *    - added VIEW mode to allow a buffer to be read only
  82.  *       (-v switch on command line will activate this)
  83.  *    - changed quick exit to write out ALL changed buffers!!!
  84.  *      MAKE SURE YOU KNOW THIS WHEN META-Zing
  85.  *    10-feb-86
  86.  *    - added handling of lines longer than allowed on file read in
  87.  *      (they wrap on additional lines)
  88.  *    - made having space clear the message line and NOT insert itself
  89.  *      a configuration option in ed.h
  90.  *    11-feb-86
  91.  *    - added Describe-command and Help commands.
  92.  *    13-feb-86
  93.  *    - added View file command (^X ^V) and finished HELP command
  94.  *    14-feb-86
  95.  *    - added option to let main loop skip update if type ahead commands
  96.  *       are queued up
  97.  *    16-feb-86
  98.  *    - added Insert File command
  99.  *    17-feb-86
  100.  *    - added scroll next window up/down commands
  101.  *    18-feb-86
  102.  *    - added CMODE indentation
  103.  *    - re-arranged header files to standardize extern and global
  104.  *      definitions
  105.  *    - changed version number to 3.2
  106.  *    - added numeric arguments to search, reverse search and
  107.  *      search and replace
  108.  *    24-feb-86
  109.  *    - added Bind To Key function (^C for now) to allow the user
  110.  *      to change his command keys
  111.  *    - added Unbind key function (M-^C for now)
  112.  *    - added execute named command to execute unbound commands (M-X)
  113.  *    - added describe bindings command (not bound)
  114.  *    - changed version number to 3.3
  115.  *    25-feb-86
  116.  *    - scrapped CERROR mode (too many compilers)
  117.  *    - added EXACT mode for case sensitive searchers
  118.  *    26-feb-86
  119.  *    - added command completion on execute named command and
  120.  *      all routined grabbing a command name
  121.  *    - adding execute-command-line command and its support functions
  122.  *      (in preparation for sourcing files)
  123.  *    - added Execute Buffer command
  124.  *    27-feb-86
  125.  *    - added execute(source) file command and added code to automatically
  126.  *      execute emacs.rc (or .emacsrc on UNIX) before initial read in
  127.  *    - changed version number to 3.4
  128.  *    4-mar-86
  129.  *    - changed word delete to be consistant with word move (it gets
  130.  *      rid of the inter word space now) This is configurable with the
  131.  *      NFWORD symbol in estruct.h
  132.  *    - added B_ACTIVE entry to the buffer table. Let emacs read multiple
  133.  *      file names from the command line and only read them in as needed
  134.  *    5-mar-85
  135.  *    - rewrote command line parser to get rid of my patchy code
  136.  *    - changed version number to 3.5
  137.  *    1-apr-86
  138.  *    - added support for Aztec C 3.20e under MSDOS
  139.  *    - fixed bug in mlwrite on ADM3's and their ilk under V7
  140.  *    - added insertion of pounds in column one under CMODE
  141.  *    - changed version number to 3.6
  142.  *    3-apr-86
  143.  *    - added next-buffer command (^X-X)
  144.  *    5-apr-86
  145.  *    - added kill paragraph command (M-^W)
  146.  *    - changed fill-paragraph to leave 2 spaces after a period at the
  147.  *      end of a word.
  148.  *    - added OVERWRITE mode
  149.  *    7-apr-86
  150.  *    - fixed overwrite mode to handle tabs
  151.  *    8-apr-86
  152.  *    - added add/delete global mode (<ESC>M & <ESC> ^M) commands
  153.  *    9-apr-86
  154.  *    - added insert space command
  155.  *    - moved bindings around        ^C    insert space
  156.  *                    M-K    bind-to-key
  157.  *                    INSERT    insert space
  158.  *                    DELETE    forwdel
  159.  *    - added hunt forward and hunt reverse commands
  160.  *    10-apr-86
  161.  *    - fixed bug in DOBUF with non-terminated command string
  162.  *    15-apr-86
  163.  *    - fixed tab expansion bug in DISPLAY which hung the AMIGA
  164.  *      (sent in by Dawn Banks)
  165.  *    - fixed curcol problen if forwline/backline during keyboard
  166.  *      macro execution (sent in by Ernst Christen)
  167.  *    - added AMIGA function/cursor key support
  168.  *    - fixed nonterminating <NL> replacement bug
  169.  *    - fixed word wrapping problems
  170.  *    16-apr-86
  171.  *    - updated documentation and froze development for 3.6 net release
  172.  *    23-apr-86    version 3.6a
  173.  *    - added foreground and background colors. Setable with the
  174.  *      add mode commands for the moment
  175.  *    24-apr-86
  176.  *    - added command to pipe CLI output to a buffer
  177.  *    25-apr-86
  178.  *    - added Dana Hoggatt's code to replace Lattice's sick system()
  179.  *      function. Now we no longer care what the switchar is.
  180.  *    - cleaned up the positioning on several of the spawing commands
  181.  *    26-apr-86
  182.  *    - added an output flush in vttidy(). Unix really appreciates this.
  183.  *    - added filter-buffer (^X#) command to send a buffer through
  184.  *      a DOS filter
  185.  *    - made automatic CMODE on .c and .h file compilation dependant
  186.  *      in estruct.h
  187.  *    1-may-86
  188.  *    - optimized some code in update(). It certainly need a lot more.
  189.  *    - added Aztec profiling capabilities. These are conditional on
  190.  *      the APROF symbol in estruct.h
  191.  *    2-may-86
  192.  *    - added (u)ndo command in query-replace. undoes last repalce.
  193.  *    6-may-86
  194.  *    - re-organized and wrote the update() function in display.c
  195.  *      Now my color hacks are in the right places and the code can be
  196.  *      understood.
  197.  *    [Released version 3.6f for BETA test sites]
  198.  *    8-may-86
  199.  *    - fixed bug in new display routine to wrap cursor on extended
  200.  *      lines at the right time
  201.  *    - modified the buffer-position command to give reasonable info
  202.  *    9-may-86
  203.  *    - improved the word wrap algorithm as not to discard non-space
  204.  *      delimiters. The backscan now looks for white space rather than
  205.  *      !inword().
  206.  *    [Released version 3.6g to Krannert]
  207.  *    10-may-86
  208.  *    - Added IBMPC.C an IBM-PC specific display driver. This makes paging
  209.  *      4-6 times faster. Also made some conditional changes to DISPLAY.C
  210.  *      to eliminate the pscreen[] if using the PC driver.
  211.  *    [changed version number to 3.6i]
  212.  *    12-may-86
  213.  *    - added delete-window (^X 0) command to dispose of a single window
  214.  *    - fixed problem with multiple prefixes from a command line which
  215.  *      was reported by John Gamble
  216.  *    14-may-86
  217.  *    - Added Aztec support for the IBMPC display driver. Had to
  218.  *      readjust some includes and defines for this.
  219.  *    - fixed bug in delete-window.
  220.  *    - fixed some bizarre behavior with the cursor after coming back
  221.  *      from spawn calls.
  222.  *    [changed version number to 3.7 freezing development for net release]
  223.  *    15-may-86
  224.  *    - (that didn't last long...) Added execute-macro-(1 thru 20) commands
  225.  *      to execute macro buffers (named "[Macro nn]")
  226.  *    - changed BFTEMP to BFINVS and cleaned up treatment of invisible
  227.  *      buffers.
  228.  *    16-may-86
  229.  *    - added store-macro (unbound) to store any executed command lines to
  230.  *      macro buffer.
  231.  *    - added clear-message-line (unbound) command to do just that
  232.  *    - added resize-window command to change a window's size to the
  233.  *      specified argument
  234.  *    - improved help's logic not to re-read the file if it was already
  235.  *      in a buffer
  236.  *    - added MAGIC mode to all structures and command tables, but the
  237.  *      regular expression code that John Gamble is writing is not ready.
  238.  *    18-may-86
  239.  *    - added interactive prompt requests in command line execution (i.e.
  240.  *      while executing a macro, a parameter starting with an at sign (@)
  241.  *      causes emacs to prompt with the rest of the parameter and return
  242.  *      the resulting input as the value of the parameter).
  243.  *    - added arguments to split-current-window to force the cursor into
  244.  *      the upper or lower window.
  245.  *    20-may-86
  246.  *    - added support for the Microsoft C compiler as per the changes
  247.  *      sent in by Oliver Sharp
  248.  *    - made some upgrades and fixes for VMS sent in by Guy Streeter
  249.  *    21-may-86
  250.  *    - fixed an Aztec bug in ttgetc by clearing the upper byte
  251.  *    - fixed buf in CMODE with #preprocesser input (bug fix submitted by
  252.  *      Willis of unknown path)
  253.  *    - added support of alternative startup file ( @<filename> ) in
  254.  *      the command line
  255.  *    - added ^Q quoting in interactive input (mlreplyt()).
  256.  *    - added re-binding of meta-prefix and ctlx-prefix
  257.  *    22-may-86
  258.  *    - reorganized getkey routines to make more sense and let prefix
  259.  *      binding work properly.
  260.  *    23-may-86
  261.  *    - checked new code on BSD4.2 and made a few fixes
  262.  *    - added optional fence matching while in CMODE
  263.  *    - added goto and search command line arguments by Mike Spitzer
  264.  *    26-may-86
  265.  *    - added parameter fetching from buffers
  266.  *    27-may-86
  267.  *    - fixed some HP150 bugs......
  268.  *    31-may-86
  269.  *    - Added Wang PC keyboard support from modifications by
  270.  *      Sid Shapiro @ Wang Institute
  271.  *    - Fixed some reverse video bugs with code submitted by Peter Chubb
  272.  *    - Fixed bug in nextbuffer reported by Dave Forslund
  273.  *    - added system V support (USG) from Linwood Varney
  274.  *    2-jun-86
  275.  *    - changed defines to just define one Unix define (for example,
  276.  *      just define BSD for Unix BSD 4.2)
  277.  *    - Added Incremental search functions written by D. R. Banks
  278.  *      in file ISEARCH.C
  279.  *    - added insert-string (unbound) command to help the macro
  280.  *      language out.
  281.  *    - added unmark-buffer (M-~) command to turn off the current buffers
  282.  *      change flag
  283.  *    - fixed nxtarg to truncate strings longer than asked for max length
  284.  *    4-jun-86
  285.  *    - added special characters in command line tokens. Tilde (~) is
  286.  *      the special lead-in character for "nrtb".
  287.  *    - Fixed bad ifdef in Aztec code so it could look at HOME dir
  288.  *      for startup, help, and emacs.rc files
  289.  *    6-jun-86
  290.  *    - make delete word commands clear the kill buffer if not after another
  291.  *      kill command
  292.  *    11-jun-86
  293.  *    - made ~@ in string arguments pass as char(192) to nxtarg() so one can
  294.  *      quote @ at the beginning of string arguments
  295.  *    - changed buffer size vars in listbuffers() to long (for big files)
  296.  *    - re-wrote buffer-position command to be much faster
  297.  *    12-jun-86
  298.  *    - added count-words (M-^C) command to count the words/chars and
  299.  *      lines in a region
  300.  *    - changed regions so they could be larger than 65535 (short ->
  301.  *      long in the REGION structure)
  302.  *    - changed ldelete() and all callers to use a long size. The kill
  303.  *      buffer will still have a problem >65535 that can not be solved
  304.  *      until I restructure it.
  305.  *    - grouped paragraph commands and word count together under symbol
  306.  *      WORDPRO to allow them to be conditionally made (or not)
  307.  *    13-jun-86
  308.  *    - re-wrote kill buffer routines again. Now they support an unlimited
  309.  *      size kill buffer, and are (in theory) faster.
  310.  *    - changed delete-next-word (M-D) to not eat the newline after a word,
  311.  *      instead it checks and eats a newline at the cursor.
  312.  *    17-jun-86
  313.  *    - added numeric argument to next/previous-window to access the nth
  314.  *      window from the top/bottom
  315.  *    - added support for the Data General 10 MSDOS machine
  316.  *    - added save-window (unbound) and restore-window (unbound) commands
  317.  *      for the use of the menu script. Save-window remembers which window
  318.  *      is current, and restore-window returns the cursor to that window.
  319.  *    20-jun-86
  320.  *    - fixed a bug with the fence matching locking up near the beginning
  321.  *      of a buffer
  322.  *    - added argument to update to selectively force a complete update
  323.  *    - added update-screen (unbound) command so macros can force a
  324.  *      screen update
  325.  *    21-jun-86
  326.  *    - rearranged token() and nxtarg() calls so that command names and
  327.  *      repeat counts could also be prompted and fetched from buffers
  328.  *      [this broke later with the exec re-write....]
  329.  *    - added write-message (unbound) command to write out a message
  330.  *      on the message line (for macros)
  331.  *    - changed ifdef's so that color modes are recognized as legal in
  332.  *      b/w version, and simply do nothing (allowing us to use the same
  333.  *      script files)
  334.  *    [Released version 3.7 on July 1 to the net and elswhere]
  335.  *    2-jul-86
  336.  *    - Changed search string terminator to always be the meta character
  337.  *      even if it is rebound.
  338.  *    3-jul-86
  339.  *    - removed extra calls to set color in startup code. This caused the
  340.  *      original current window to always be the global colors.
  341.  *    7-jul-86
  342.  *    - Fixed bugs in mlreplyt() to work properly with all terminators
  343.  *      including control and spec characters
  344.  *    22-jul-86
  345.  *    - fixed replaces() so that it will return FALSE properly on the
  346.  *      input of the replacement string.
  347.  *    - added a definition for FAILED as a return type.....
  348.  *    - changed version number to 3.7b
  349.  *    23-jul-86
  350.  *    - fixed o -> 0 problem in TERMIO.C
  351.  *    - made ^U universal-argument re-bindable
  352.  *    - wrote atoi() for systems (like Aztec) where it acts strangely
  353.  *    - changed version number to 3.7c
  354.  *    25-jul-86
  355.  *    - make ^G abort-command rebindable
  356.  *    29-jul-86
  357.  *    - added HP110 Portable Computer support
  358.  *    - changed version number to 3.7d
  359.  *    30-jul-86
  360.  *    - Fixed a couple of errors in the new VMS code as pointer
  361.  *      out by Ken Shacklford
  362.  *    - split terminal open/close routines into screen and keyboard
  363.  *      open/close routines
  364.  *    - closed the keyboard during all disk I/O so that OS errors
  365.  *      can be respoded to correctly (especially on the HP150)
  366.  *    - changed version number to 3.7e
  367.  *    31-jul-86
  368.  *    - added label-function-key (unbound) command under symbol FLABEL
  369.  *      (primarily for the HP150)
  370.  *    4-aug-86
  371.  *    - added fixes for Microsoft C as suggested by ihnp4!ihuxm!gmd1
  372.  *        <<remember to fix [list] deletion bug as reported
  373.  *          by craig@hp-pcd>>
  374.  *    8-aug-86
  375.  *    - fixed beginning misspelling error everywhere
  376.  *    - fixed some more MSC errors
  377.  *    - changed version number to 3.7g
  378.  *    20-aug-86
  379.  *    - fixed CMODE .h scanning bug
  380.  *    - changed version number to 3.7h
  381.  *    30-aug-86
  382.  *    - fixed killing renamed [list] buffer (it can't) as submitted
  383.  *      by James Aldridge
  384.  *    - Added code to allow multiple lines to display during
  385.  *      vertical retrace
  386.  *      [total disaster....yanked it back out]
  387.  *    9-sep-86
  388.  *    - added M-A (apropos) command to list commands containing a substring.
  389.  *    - fixed an inefficiency in the display update code submitted
  390.  *      by William W. Carlson (wwc@pur-ee)
  391.  *    10-sep-86
  392.  *    - added Dana Hoggatt's code for encryption and spliced it into the
  393.  *      proper commands. CRYPT mode now triggers encryption.
  394.  *    - added -k flag to allow encryption key (no spaces) in command line
  395.  *    14-sep-86
  396.  *    - added missing lastflag/thisflag processing to docmd()
  397.  *    - changed version to 3.7i and froze for partial release via mail
  398.  *      and BBS
  399.  *    05-oct-86
  400.  *    - changed some strcpys in MAIN.C to strncpys as suggested by John
  401.  *      Gamble
  402.  *    - replaces SEARCH.C and ISEARCH.C with versions modified by
  403.  *      John Gamble
  404.  *    10-oct-86
  405.  *    - removed references to lflick....it just won't work that way.
  406.  *    - removed defines LAT2 and LAT3...the code no longer is Lattice
  407.  *      version dependant.
  408.  *    14-oct-86
  409.  *    - changed spawn so that it will not not pause if executed from
  410.  *      a command line
  411.  *    15-oct-86
  412.  *    - added argument concatination (+) to the macro parsing
  413.  *    - added [] as fence pairs
  414.  *    16-oct-86
  415.  *    - rewrote all macro line parsing routines and rearranged the
  416.  *      mlreply code. Saved 6K!!! Have blazed the path for expanding
  417.  *      the command language.
  418.  *    17-oct-86
  419.  *    - added new keyboard macro routines (plus a new level to the
  420.  *      input character function)
  421.  *    22-oct-86
  422.  *    - improved EGA cursor problems
  423.  *    - added -r (restricted) switch to command line for BBS use
  424.  *    06-nov-86
  425.  *    - fixed terminator declarations from char to int in getarg() and
  426.  *      nxtarg() in EXEC.C as pointed out by John Gamble
  427.  *    07-nov-86
  428.  *    - made wordrap() user callable as wrap-word (M-FNW) and changed
  429.  *      the getckey() routine so that illegal keystrokes (too many
  430.  *      prefixes set) could be used for internal bindings. When word
  431.  *      wrap conditions are met, the keystroke M-FNW is executed. Added
  432.  *      word wrap check/call to newline().
  433.  *    11-nov-86
  434.  *    - added and checked support for Mark Williams C 86
  435.  *    12-nov-86
  436.  *    - added goto-matching-fence (M-^F) command to jump to a matching
  437.  *      fence "({[]})" or beep if there is none. This can reframe the
  438.  *      screen.
  439.  *    - added code and structure elements to support change-screen-size
  440.  *      command (M-^S) to change the number of lines being used by
  441.  *      MicroEMACS.
  442.  *    15-nov-86
  443.  *    - finished debugging change-screen-size
  444.  *    17-nov-86
  445.  *    - Incorporated in James Turner's modifications for the Atari ST
  446.  *        23-sep-86
  447.  *        - added support for the Atari ST line of computers (jmt)
  448.  *          - added a '\r' to the end of each line on output and strip
  449.  *            it on input for the SHOW function from the desktop
  450.  *          - added 3 new mode functions (HIREZ, MEDREZ, and LOREZ);
  451.  *            chgrez routine in TERM structure; and MULTREZ define in
  452.  *            ESTRUCT.H to handle multiple screen resolutions
  453.  *    [note....ST still not running under Lattice yet...]
  454.  *    25-nov-86
  455.  *    - Made the filter-buffer (^X-#) command not work on VIEW mode
  456.  *      buffers
  457.  *    - Made the quick-exit (M-Z) command throw out a newline after
  458.  *      each message so they could be seen.
  459.  *    26-nov-86
  460.  *    - fixed a couple of bugs in change-screen-size (M-^S) command
  461.  *    - changed file read behavior on long lines and last lines
  462.  *      with no newline (it no longer throws the partial line out)
  463.  *    - [as suggested by Dave Tweten] Made adding a ^Z to the end
  464.  *      of an output file under MSDOS configurable under the
  465.  *      CTRL-Z symbol in ESTRUCT.H
  466.  *    - [Dave Tweten] Spawn will look up the "TMP" environment variable
  467.  *      for use during various pipeing commands.
  468.  *    - [Dave Tweten] changed pipe command under MSDOS to use '>>'
  469.  *      instead of '>'
  470.  *    04-dec-86
  471.  *    - moved processing of '@' and '#' so that they can be outside
  472.  *      the quotes in an argument, and added hooks to process '%' for
  473.  *      environment and user variables.
  474.  *    - modified IBMPC.C to sense the graphics adapter (CGA and MONO)
  475.  *      at runtime to cut down on the number of versions.
  476.  *    05-dec-86
  477.  *    - changed macro directive character to "!" instead of "$" (see
  478.  *      below) and fixed the standard .rc file to comply.
  479.  *    - added code to interpret environment variables ($vars). Added
  480.  *      hooks for built in functions (&func). So, to recap:
  481.  *
  482.  *        @<string>    prompt and return a string from the user
  483.  *        #<buffer name>    get the next line from a buffer and advance
  484.  *        %<var>        get user variable <var>
  485.  *        $<evar>        get environment variable <evar>
  486.  *        &<func>        evaluate function <func>
  487.  *
  488.  *    - allowed repeat counts to be any of the above
  489.  *    - added code to allow insert-string (unbound) to use its
  490.  *      repeat count properly
  491.  *    - added set (^X-A) command to set variables. Only works on
  492.  *      environmental vars yet.
  493.  *    9-dec-86
  494.  *    - added some code for user defined variables...more to come
  495.  *    - added options for malloc() memory pool tracking
  496.  *    - preliminary user variables (%) working
  497.  *    - changed terminal calls to macro's (to prepare for the new
  498.  *      terminal drivers)
  499.  *    15-dec-86
  500.  *    - changed previous-line (^P) and next-line (^N) to return a
  501.  *      FALSE at the end or beginning of the file so repeated
  502.  *      macros involving them terminate properly!
  503.  *    - added code for $CURCOL and $CURLINE
  504.  *    20-dec-86
  505.  *    - set (^X-A) now works with all vars
  506.  *    - added some new functions
  507.  *          &ADD &SUB &TIMES &DIV &MOD &NEG &CAT
  508.  *    - once again rearranged functions to control macro execution. Did
  509.  *      away with getarg()
  510.  *    23-dec-86
  511.  *    - added string functions
  512.  *          &LEFt &RIGht &MID
  513.  *    31-dec-86
  514.  *    - added many logical functions
  515.  *          &NOT &EQUal &LESs &GREater
  516.  *    - added string functions
  517.  *          &SEQual &SLEss &SGReater
  518.  *    - added variable indirection with &INDirect
  519.  *    - made fixes to allow recursive macro executions
  520.  *      (improved speed during macro execution as well)
  521.  *    3-jan-87
  522.  *    - added $FLICKER to control flicker supression
  523.  *    - made spawn commands restricted
  524.  *    - cleaned up lots of unintentional int<->char problems
  525.  *    4-jan-87
  526.  *    - Fixed broken pipe-command (^X-@) command under MSDOS
  527.  *    - added !IF  !ELSE  !ENDIF  directives and changed the
  528.  *      name of !END to !ENDM....real slick stuff
  529.  *    5-jan-87
  530.  *    - quick-exit (M-Z) aborts on any filewrite errors
  531.  *    8-jan-87
  532.  *    - debugged a lot of the new directive and evaluation code.
  533.  *      BEWARE of stack space overflows! (increasing stack to
  534.  *      16K under MSDOS)
  535.  *    - removed non-standard DEC Rainbow keyboard support...let someone
  536.  *      PLEASE implement this in the standard manner using key bindings
  537.  *      and send the results to me.
  538.  *    - added change-screen-width () command and $CURWIDTH variable
  539.  *    11-jan-87
  540.  *    - fixed an incredibly deeply buried bug in vtputc and combined
  541.  *      it with vtpute (saving about 200 bytes!)
  542.  *    16-jan-87
  543.  *    - added code to handle controlling multiple screen resolutions...
  544.  *      allowed the IBM-PC driver to force Mono or CGA modes.
  545.  *    - added current buffer name and filename variables
  546.  *      $cbufname and $cfname
  547.  *    18-jan-87
  548.  *    - added $sres variable to control screen resolution
  549.  *    - added $debug variable to control macro debugging code (no longer
  550.  *      is this activated by GLOBAL spell mode)
  551.  *    - fixed bug in -g command line option
  552.  *    - Released Version 3.8 to BBSNET
  553.  *    21-jan-87
  554.  *    - added $status variable to record return status of last command
  555.  *    2-feb-87
  556.  *    - added ATARI 1040 support...runs in all three modes right now
  557.  *    - added $palette var with palette value in it
  558.  *    - undefined "register" in BIND.C and INPUT.C for ST520 & LATTICE
  559.  *      to get around a nasty Lattice bug
  560.  *    4-feb-87
  561.  *    - added, debugged code for switching all 1040ST color modes, added
  562.  *      code for HIGH monochrome mode as well, DENSE still pending
  563.  *    5-feb-87
  564.  *    - with John Gamble, found and corrected the infamous bad matching
  565.  *      fence problems.
  566.  *    - added error return check in various add/delete mode commands
  567.  *    10-feb-87
  568.  *    - re-arrange code in docmd() so that labels are stored in
  569.  *      macro buffers
  570.  *    - fixed !RETURN to only return if (execlevel == 0) [If we are
  571.  *      currently executing]
  572.  *    14-feb-87
  573.  *    - added to outp() calls in the EGA driver to fix a bug in the BIOS
  574.  *    - adding code for 1040ST 40 line DENSE mode (not complete)
  575.  *    25-feb-87
  576.  *    - added auto-save "ASAVE" mode....variables $asave and $acount
  577.  *      control the frequency of saving and count until next save
  578.  *    - added &and and &or as functions for logical anding and oring
  579.  *    - added string length &LEN, upper and lower case string funtions
  580.  *      &LOWER and &UPPER
  581.  *    27-feb-87
  582.  *    - added $lastkey   last keystroke struck and
  583.  *            $curchar    character under cursor
  584.  *    28-feb-87
  585.  *    - added code for trim-line (^X^T) command and table entries
  586.  *      for the entab-line (^X^E) and detab-line (^X^D) commands.
  587.  *      These are conditional on AEDIT (Advanced editing) in estruct.h
  588.  *    18-mar-87
  589.  *    - finished above three commands
  590.  *    - added $version environment variable to return the current
  591.  *      MicroEMACS version number
  592.  *    - added $discmd emvironment variable. This is a logical flag that
  593.  *      indicates if emacs should be echoing commands on the command line.
  594.  *      real useful in order to stop flashing macros and .rc files
  595.  *    - added $progname environment variable. this always returns the
  596.  *      string "MicroEMACS". OEM's should change this so that macros can
  597.  *      tell if they are running on an unmodified emacs or not.
  598.  *    - fixed a minor bug in the CGA/MONO detection routine in IBMPC.C
  599.  *    20-mar-87
  600.  *    - integrated EGAPC.C into IBMPC.C and eliminated the file. Now an
  601.  *      EGA user can switch from EGA to CGA modes at will
  602.  *    - A LOT of little fixes and corrections sent in by John Ruply
  603.  *    25-mar-87
  604.  *    - Fixed buffer variables so they will work when referencing the
  605.  *      current buffer
  606.  *    26-mar-87
  607.  *    - Fixed atoi() to be more reasonable. trailing whitespace ignored,
  608.  *      only one leading sign, no non-digits allowed after the sign.
  609.  *    - fixed buffer variables to go from the point to the end of
  610.  *      line.
  611.  *    28-mar-87
  612.  *    - fixed bugs with 8 bit chars as submited by Jari Salminen
  613.  *    - replace AZTEC/MSDOS agetc() with a1getc() which won't strip
  614.  *      the high order bit
  615.  *    30-mar-87
  616.  *    - changed list-buffers (^X^B) so that with any argument, it will
  617.  *      also list the normally invisable buffers
  618.  *    - added store-procedure and execute-procedure/run (M-^E)
  619.  *      commands to store and execute named procedures.
  620.  *    31-mar-87
  621.  *    - Fixed infinite loop in ^X-X command (when [LIST] is the
  622.  *      only buffer left) as pointed out by John Maline
  623.  *    - made filenames in getfile() always lower case as pointed
  624.  *      out by John Maline
  625.  *    2-apr-87
  626.  *    - Fixed buffer variables so they would work on non-current displayed
  627.  *      buffers. They should now work with ALL buffers....
  628.  *    3-apr-87
  629.  *    - Yanked AZTEC profiling code....not very useful
  630.  *    - Modified IBMPC driver so it will not start in EGA mode
  631.  *    - allow the next-buffer (^X-X) command to have a preceding
  632.  *      non-negative argument.
  633.  *    14-apr-87
  634.  *    - added John Gamble's modified search.c. The code has cut apx
  635.  *      200-300 bytes off the executable.
  636.  *    - added the &RND function to generate a random integer between
  637.  *      1 and its arguments value. Also $SEED is availible as the
  638.  *      random number seed.
  639.  *    - changed the -k command line switch so if there is no argument,
  640.  *      it will prompt for one when the file is read
  641.  *    15-apr-87
  642.  *    - added 20 bytes of buffer in getval()'s local argument alloc so
  643.  *      when it returns a value, it has enough stack space to do at least
  644.  *      one strcpy() before stomping on the returned value. ALWAYS call
  645.  *      getval() ONLY from within a strcpy() call.
  646.  *    - made $curcol return a 1 based value instead of a zero based one.
  647.  *      [changed this back later for 3.8o   it was simply wrong.....]
  648.  *    16-apr-87
  649.  *    - re-wrote strncpy() for AZTEC & MSDOS so it null terminates the
  650.  *      string.
  651.  *    - changed pipe() to pipecmd() to avoid conflicts with various
  652.  *      UNIX systems
  653.  *    24-apr-87
  654.  *    - changed open parameters on AMIGA window open to 0/0/640/200
  655.  *    [Froze and released v3.8i via BBS net]
  656.  *    14-may-87
  657.  *    - added nop (M-FNC) that gets called on every command loop
  658.  *    - added $wline, returns and sets # lines in current window
  659.  *    - added $cwline, returns and set current line within window
  660.  *    - added $target, returns/sets target for line moves
  661.  *    - added $search, returns/sets default search string
  662.  *    - added $replace, returns/sets default replace string
  663.  *    - added $match, returns last matched string in magic search
  664.  *    29-may-87
  665.  *    - rewrote word deletes to not kill trailing non-whitespace after
  666.  *      the last word. Also a zero argument will cause it to just delete
  667.  *      the word and nothing else.
  668.  *    - more fixes for the search pattern environment variables
  669.  *    30-may-87
  670.  *    - forced all windows to redraw on a width change
  671.  *    2-jun-87
  672.  *    - forced clear-message-line to overide $discmd
  673.  *    - added mlforce() routine and call it in clear-message-line,
  674.  *      write-message and when $debug is TRUE
  675.  *    - recoded the startup sequence in main()....Much Better...
  676.  *    4-jun-87
  677.  *    - forced interactive arguments ( @"question" ) to ALWAYS be echoed
  678.  *      regardless of the setting of $discmd.
  679.  *    7-jun-87
  680.  *    - started adding support for Turbo C under MSDOS
  681.  *    11-jun-87
  682.  *    - words now include ONLY upper/lower case alphas and digits
  683.  *    - fixed some more bugs with the startup..(ORed in the global modes)
  684.  *    - took more limits off the self-insert list....
  685.  *    16-jun-87
  686.  *    - macro debugging now displays the name of the current macro.
  687.  *    - fixed a problem in expandp() in search.c that kept high-byte
  688.  *      characters from working in search strings
  689.  *    18-jun-87
  690.  *    - added &sindex <str1> <str2> function which searches for string 2
  691.  *      within string 1
  692.  *    [released verion 3.8o internally]
  693.  *    19-jun-87
  694.  *    - added $cmode and $gmode to return and set the mode of the
  695.  *      current buffer and the global mode
  696.  *    - separated findvar() out from setvar() so it could be used in
  697.  *      the !LOOP directive (which got canned....read on)
  698.  *    - %No such variable message now types the name of the offending
  699.  *      variable
  700.  *    22-jun-87
  701.  *    - fixed startup bug when editing the startup file
  702.  *    - added the !LOOP <var> <label> directive
  703.  *    26-jun-87
  704.  *    - dumped !LOOP......added !WHILE. This needed and caused a vaste
  705.  *      reorginization in exec.c which mainly involved moving all the
  706.  *      directive handling from docmd() to dobuf(), in the process
  707.  *      getting rid of a lot of junk and making the result smaller
  708.  *      than it started.....(yea!)
  709.  *    - added $tpause to control the fence flashing time in CMODE.
  710.  *      The value is machine dependant, but you can multiply the
  711.  *      original in macros to stay machine independant. (as
  712.  *      suggested by Baron O.A. Grey)
  713.  *    - added hook to execute M-FNR (null) during a file read, after
  714.  *      the name is set and right before the file is read. Took out
  715.  *      any auto-CMODE code, as this is now handled with a macro.
  716.  *      (also suggested by Baron O.A. Grey)
  717.  *    - Added Baron O.A. Grey's SYSTEM V typeahead() code...I hope
  718.  *      this works....if you check this out, drop me a line.
  719.  *    - Added new variable $pending, returns a logical telling if
  720.  *      a typed ahead character is pending.
  721.  *    29-jun-87
  722.  *    - Made adjustmode() use curbp-> instead of curwp->w_bufp-> which
  723.  *      fixed some bugs in the startup routines.
  724.  *    - added $lwidth to return the length of the current line
  725.  *    2-jul-87
  726.  *    - Added &env <str> which returns the value of the environment
  727.  *      variable <str> where possible
  728.  *    - Fixed a NASTY bug in execbuf()..the buffer for the name
  729.  *      of the buffer to execute was NBUFN long, and got overflowed
  730.  *      with a long interactive argument.
  731.  *    3-jul-87
  732.  *    - Moved the loop to match a key against its binding out of execute()
  733.  *      to getbind() so it could be used later elsewhere.
  734.  *    - Added &bind <keyname> which returns the function bound to the
  735.  *      named key
  736.  *    - changed execute-file to look in the executable path first...
  737.  *    6-jul-87
  738.  *    - changed $curchar to return a newline at the end of a line and
  739.  *      it no longer advances the cursor
  740.  *    - a lot of minor changes sent by various people....
  741.  *    7-jul-87
  742.  *    - some amiga specific fixes as suggested by Kenn Barry
  743.  *    - added $line [read/write] that contains the current line in the
  744.  *      current buffer
  745.  *    - changed $curcol so setting it beyond the end of the line will
  746.  *      move the cursor to the end of the line and then fail.
  747.  *    10-jul-87
  748.  *    - added a number of fixes and optimizations along with the rest
  749.  *      of the TURBO-C support as submited by John Maline
  750.  *    13-jun-87
  751.  *    - caused dobuf() to copy lastflag to thisflag so the first
  752.  *      command executed will inherit the lastflag from the command
  753.  *      before the execute-buffer command. (needed this for smooth
  754.  *      scrolling to work)
  755.  *    - made flook() look first in the $HOME directory, then in the
  756.  *      current directory, then down the $PATH, and then in the
  757.  *      list in epath.h
  758.  *    14-jul-87
  759.  *    - added some fixes for VMS along with support for the SMG
  760.  *      screen package as submited by Curtis Smith
  761.  *    15-jul-87
  762.  *    - fixed M-^H (delete-previous-word) so it can delete the first
  763.  *      word in a file....I think there may be more of this kind of thing
  764.  *      to fix.
  765.  *    16-jul-87
  766.  *    - added code to allow arbitrary sized lines to be read from files..
  767.  *      speed up file reading in the process.
  768.  *    - made out of memory conditions safer.. especial on file reads
  769.  *    - fixed a bug in bind having to do with uppercasing function
  770.  *      key names (submitted by Jari Salminen)
  771.  *    - made ST520 exit in the same resolution that EMACS was started in
  772.  *      (for the 1040ST)
  773.  *    [FROZE development and released version 3.9 to USENET]
  774.  */
  775.  
  776. #include        <stdio.h>
  777.  
  778. /* make global definitions not external */
  779. #define    maindef
  780.  
  781. #include        "estruct.h"    /* global structures and defines */
  782. #include    "efunc.h"    /* function declarations and name table    */
  783. #include    "edef.h"    /* global definitions */
  784. #include    "ebind.h"    /* default key bindings */
  785.  
  786. /* for MSDOS, increase the default stack space */
  787.  
  788. #if    MSDOS & LATTICE
  789. unsigned _stack = 32767;
  790. #endif
  791.  
  792. #if    ATARI & LATTICE & 0
  793. int _mneed = 256000;        /* reset memory pool size */
  794. #endif
  795.  
  796. #if    MSDOS & AZTEC
  797. int _STKSIZ = 32767/16;        /* stack size in paragraphs */
  798. int _STKRED = 1024;        /* stack checking limit */
  799. int _HEAPSIZ = 4096/16;        /* (in paragraphs) */
  800. int _STKLOW = 0;        /* default is stack above heap (small only) */
  801. #endif
  802.  
  803. #if    MSDOS & TURBO
  804. unsigned _stklen = 32768;
  805. #endif
  806.  
  807. #if     VMS
  808. #include        <ssdef.h>
  809. #define GOOD    (SS$_NORMAL)
  810. #endif
  811.  
  812. #ifndef GOOD
  813. #define GOOD    0
  814. #endif
  815.  
  816. int termflag;        /* if true, keep terminal in normal mode */
  817.  
  818. #if    CALLABLE
  819. int exitflag;        /* set when time to exit */
  820.  
  821. /* edit a given file */
  822. emacsone(name)
  823. char *name;
  824. {
  825.     int argc;
  826.     char *argv[3];
  827.  
  828.     argv[0] = "emacs";
  829.     argv[1] = name;
  830.     argv[2] = NULL;
  831.     argc = ((name == NULL || *name == '\0')? 1 : 2);
  832.     emacsmain(argc, argv);
  833. }
  834.  
  835. /* edit according to simulated command line */
  836. emacsmain(argc, argv)
  837. char *argv[];
  838. {
  839.     emacspgm(argc, argv);
  840.     freeall();
  841. }
  842.  
  843. /* free all dynamically allocated areas */
  844. freeall()
  845. {
  846.     kdelete();
  847.     frallwindows();
  848.     frallbuffers();
  849. #if    RAMSIZE
  850.     printf("used ram is %d\n", envram);
  851. #endif
  852. }
  853.  
  854. emacspgm(argc, argv)
  855. #else
  856. main(argc, argv)
  857. #endif
  858.  
  859. char    *argv[];
  860. {
  861.         register int    c;        /* command character */
  862.         register int    f;        /* default flag */
  863.         register int    n;        /* numeric repeat count */
  864.         register int    mflag;        /* negative flag on repeat */
  865.     register BUFFER *bp;        /* temp buffer pointer */
  866.     register int    firstfile;    /* first file flag */
  867.     register int    carg;        /* current arg to scan */
  868.     register int    startflag;    /* startup executed flag */
  869.     BUFFER *firstbp;        /* ptr to first buffer in cmd line */
  870.     int basec;            /* c stripped of meta character */
  871.     int viewflag;            /* are we starting in view mode? */
  872.         int gotoflag;                   /* do we need to goto a line at start? */
  873.         int gline;                      /* if so, what line? */
  874.         int searchflag;                 /* Do we need to search at start? */
  875.     int savelflag;            /* temp store for lastflag */
  876.         char bname[NBUFN];        /* buffer name of file to read */
  877.     char vname[NVSIZE+1];
  878.         VDESC vd;
  879. #if    CRYPT
  880.     int cryptflg;            /* encrypting on the way in? */
  881.     char ekey[NPAT];        /* startup encryption key */
  882. #endif
  883.     extern char *pathname[];    /* startup file path/name array */
  884.  
  885. #if    CALLABLE
  886.     exitflag = FALSE;
  887. #endif
  888.  
  889.     /* initialize the editor */
  890.     firstbp = NULL;
  891.     sgarbf = TRUE;
  892.     mpresf = FALSE;
  893.     mllen = 0;
  894.     termflag = FALSE;
  895.         vtinit();        /* Display */
  896.         edinit("main");        /* Buffers, windows */
  897.     varinit();        /* user variables */
  898.     fkeyinit();        /* fast key table */
  899.  
  900.     firstflag = FALSE;
  901.     viewflag = FALSE;    /* view mode defaults off in command line */
  902.     gotoflag = FALSE;    /* set to off to begin with */
  903.     searchflag = FALSE;    /* set to off to begin with */
  904.     firstfile = TRUE;    /* no file to edit yet */
  905.     startflag = FALSE;    /* startup file not executed yet */
  906. #if    CRYPT
  907.     cryptflg = FALSE;    /* no encryption by default */
  908. #endif
  909.  
  910.     /* Parse the command line */
  911.     for (carg = 1; carg < argc; ++carg) {
  912.  
  913.         /* Process Switches */
  914.         if (argv[carg][0] == '-') {
  915.             switch (argv[carg][1]) {
  916.                 case 'c':    /* -c for changeable file */
  917.                 case 'C':
  918.                     viewflag = FALSE;
  919.                     break;
  920.                 case 'm':
  921.                 case 'M':
  922. #if    MENUS
  923.                     curwp->w_ntrows = term.t_nrow - 2;
  924.                     menuflag = TRUE;
  925. #endif
  926.                     break;
  927.                 case 'e':    /* -e for Edit file */
  928.                 case 'E':
  929.                     viewflag = FALSE;
  930.                     break;
  931.                 case 'g':    /* -g for initial goto */
  932.                 case 'G':
  933.                     gotoflag = TRUE;
  934.                     gline = atoi(&argv[carg][2]);
  935.                     break;
  936.                 case 'i':    /* -i<var> <value> */
  937.                 case 'I':    /* set inital value for var */
  938.                     bytecopy(vname, &argv[carg][2], NVSIZE);
  939.                     findvar(vname, &vd, NVSIZE + 1);
  940.                     ++carg;
  941.                     if (vd.v_type == -1)
  942.                 mlwrite("%%No such variable as '%s'", vname);
  943.                     else if (carg >= argc) svar(&vd, "");
  944.                     else svar(&vd, argv[carg]);
  945.                     break;
  946. #if    CRYPT
  947.                 case 'k':    /* -k<key> for code key */
  948.                 case 'K':
  949.                     cryptflg = TRUE;
  950.                     bytecopy(ekey, &argv[carg][2], NPAT-1);
  951.                     break;
  952. #endif
  953.                 case 'r':    /* -r restrictive use */
  954.                 case 'R':
  955.                     restflag = TRUE;
  956.                     break;
  957.                 case 's':    /* -s for initial search string */
  958.                 case 'S':
  959.                     searchflag = TRUE;
  960.                     bytecopy(pat,&argv[carg][2],NPAT-1);
  961.                     setjtable(pat);
  962.                     break;
  963.                 case 't':
  964.                 case 'T':
  965.                     if (!termflag) {
  966.                         termflag = TRUE;
  967.                         TTflush(); TTclose(); TTopen();
  968.                     }
  969.                     break;
  970.                 case 'v':    /* -v for View File */
  971.                 case 'V':
  972.                     viewflag = TRUE;
  973.                     break;
  974.                 default:    /* unknown switch */
  975.                     /* ignore this for now */
  976.                     break;
  977.             }
  978.  
  979.         } else if (argv[carg][0]== '@') {
  980.  
  981.             /* Process Startup macroes */
  982.             if (startup(&argv[carg][1]) == TRUE)
  983.                 /* don't execute emacs.rc */
  984.                 startflag = TRUE;
  985.  
  986.         } else {
  987.  
  988.             /* Process an input file */
  989.  
  990.             /* set up a buffer for this file */
  991.                     makename(bname, argv[carg]);
  992.             unqname(bname);
  993.  
  994.             /* set this to inactive */
  995.             bp = bfind(bname, TRUE, 0);
  996.             strcpy(bp->b_fname, argv[carg]);
  997.             bp->b_active = FALSE;
  998.             if (firstfile) {
  999.                 firstbp = bp;
  1000.                 firstfile = FALSE;
  1001.             }
  1002.  
  1003.             /* set the modes appropriatly */
  1004.             if (viewflag)
  1005.                 bp->b_mode |= MDVIEW;
  1006. #if    CRYPT
  1007.             if (cryptflg) {
  1008.                 bp->b_mode |= MDCRYPT;
  1009.                 crypt((char *)NULL, (unsigned) 0);
  1010.                 crypt(ekey, (unsigned) strlen(ekey));
  1011.                 bytecopy(bp->b_key, ekey, NPAT-1);
  1012.             }
  1013. #endif
  1014.         }
  1015.     }
  1016.  
  1017.     /* if invoked with no other startup files,
  1018.        run the system startup file here */
  1019.     if (startflag == FALSE) {
  1020.  
  1021.         /* if emacs.rc is one of the input files....don't clobber it */
  1022.         if (!firstfile && strcmp(pathname[0], firstbp->b_bname) == 0) {
  1023.             c = firstbp->b_bname[0];
  1024.             firstbp->b_bname[0] = '[';
  1025.             startup("");
  1026.             firstbp->b_bname[0] = c;
  1027.         } else {
  1028.             startup("");
  1029.         }
  1030.         startflag = TRUE;
  1031.     }
  1032.  
  1033.     /* if there are any files to read, read the first one! */
  1034.     bp = bfind("main", FALSE, 0);
  1035.     if (firstfile == FALSE) {
  1036.         swbuffer(firstbp);
  1037.         curbp->b_mode |= gmode;
  1038.         zotbuf(bp);
  1039.     } else
  1040.         bp->b_mode |= gmode;
  1041.  
  1042. #if    MENUS
  1043.     if (menuflag) menuinit();
  1044. #endif
  1045.  
  1046.         /* Deal with startup gotos and searches */
  1047.         if (gotoflag && searchflag) {
  1048.             update(FALSE);
  1049.         mlwrite("[Can not search and goto at the same time!]");
  1050.     }
  1051.         else if (gotoflag) {
  1052.                 if (gotoline(TRUE,gline) == FALSE) {
  1053.                     update(FALSE);
  1054.             mlwrite("[Bogus goto argument]");
  1055.         }
  1056.         } else if (searchflag) {
  1057.                 if (forwhunt(FALSE, 0) == FALSE)
  1058.                     update(FALSE);
  1059.         }
  1060.  
  1061.     /* setup to process commands */
  1062.         lastflag = 0;                           /* Fake last flags.     */
  1063.  
  1064. loop:
  1065.  
  1066. #if    CALLABLE
  1067.     if (exitflag == TRUE) return(GOOD);
  1068. #endif
  1069.  
  1070.     /* execute the "command" macro...normally null */
  1071.     savelflag = lastflag;    /* preserve lastflag through this */
  1072.     execute(FUNC|'C', HOOK, 1);
  1073.     lastflag = savelflag;
  1074.  
  1075.     /* Fix up the screen    */
  1076.         update(FALSE);
  1077.  
  1078.     /* get the next command from the keyboard */
  1079.     c = getcmd();
  1080.  
  1081.     /* if there is something on the command line, clear it */
  1082.         if (mpresf != FALSE) {
  1083.                 mlerase();
  1084.                 update(FALSE);
  1085. #if    CLRMSG
  1086.                 if (c == ' ')                   /* ITS EMACS does this  */
  1087.                         goto loop;
  1088. #endif
  1089.         }
  1090.         f = FALSE;
  1091.         n = 1;
  1092.  
  1093.     /* do META-# processing if needed */
  1094.  
  1095.     basec = c & ~META;        /* strip meta char off if there */
  1096.     if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
  1097.         f = TRUE;        /* there is a # arg */
  1098.         n = 0;            /* start with a zero default */
  1099.         mflag = 1;        /* current minus flag */
  1100.         c = basec;        /* strip the META */
  1101.         while ((c >= '0' && c <= '9') || (c == '-')) {
  1102.             if (c == '-') {
  1103.                 /* already hit a minus or digit? */
  1104.                 if ((mflag == -1) || (n != 0))
  1105.                     break;
  1106.                 mflag = -1;
  1107.             } else {
  1108.                 n = n * 10 + (c - '0');
  1109.             }
  1110.             if ((n == 0) && (mflag == -1))    /* lonely - */
  1111.                 mlwrite("Arg:");
  1112.             else
  1113.                 mlwrite("Arg: %d",n * mflag);
  1114.  
  1115.             c = getcmd();    /* get the next key */
  1116.         }
  1117.         n = n * mflag;    /* figure in the sign */
  1118.     }
  1119.  
  1120.     /* do ^U repeat argument processing */
  1121.  
  1122.         if (c == reptc) {                  /* ^U, start argument   */
  1123.                 f = TRUE;
  1124.                 n = 4;                          /* with argument of 4 */
  1125.                 mflag = 0;                      /* that can be discarded. */
  1126.                 mlwrite("Arg: 4");
  1127.                 while ((c=getcmd()) >='0' && c<='9' || c==reptc || c=='-'){
  1128.                         if (c == reptc)
  1129.                 if ((n > 0) == ((n*4) > 0))
  1130.                                     n = n*4;
  1131.                             else
  1132.                                 n = 1;
  1133.                         /*
  1134.                          * If dash, and start of argument string, set arg.
  1135.                          * to -1.  Otherwise, insert it.
  1136.                          */
  1137.                         else if (c == '-') {
  1138.                                 if (mflag)
  1139.                                         break;
  1140.                                 n = 0;
  1141.                                 mflag = -1;
  1142.                         }
  1143.                         /*
  1144.                          * If first digit entered, replace previous argument
  1145.                          * with digit and set sign.  Otherwise, append to arg.
  1146.                          */
  1147.                         else {
  1148.                                 if (!mflag) {
  1149.                                         n = 0;
  1150.                                         mflag = 1;
  1151.                                 }
  1152.                                 n = 10*n + c - '0';
  1153.                         }
  1154.                         mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
  1155.                 }
  1156.                 /*
  1157.                  * Make arguments preceded by a minus sign negative and change
  1158.                  * the special argument "^U -" to an effective "^U -1".
  1159.                  */
  1160.                 if (mflag == -1) {
  1161.                         if (n == 0)
  1162.                                 n++;
  1163.                         n = -n;
  1164.                 }
  1165.         }
  1166.  
  1167.     /* and execute the command */
  1168.         execute(c, f, n);
  1169.         goto loop;
  1170. }
  1171.  
  1172. int useoldargs = FALSE;    /* saved universal arg so C-U n meta command */
  1173. int execnold;        /* repeats command instead of meta */
  1174. int execfold;
  1175. int inmeta = FALSE;    /* true if next command was prefixed by a meta */
  1176. int incex = FALSE;    /* true if next command was prefixed by a C-X */
  1177. int inspecial = FALSE;    /* true if next command was prefixed by a FN */
  1178.  
  1179. meta(f, n)    /* dummy function for binding to meta prefix */
  1180. {
  1181.     inmeta = TRUE;
  1182.     useoldargs = TRUE;
  1183.     execfold = f;
  1184.     execnold = n;
  1185. }
  1186.  
  1187. cex(f, n)    /* dummy function for binding to control-x prefix */
  1188. {
  1189.     incex = TRUE;
  1190.     useoldargs = TRUE;
  1191.     execfold = f;
  1192.     execnold = n;
  1193. }
  1194.  
  1195. #if    DECEDT
  1196. special(f, n)    /* dummy function for binding to special prefix */
  1197. {
  1198.     inspecial = TRUE;
  1199.     useoldargs = TRUE;
  1200.     execfold = f;
  1201.     execnold = n;
  1202. }
  1203. #endif
  1204.  
  1205. unarg()        /* dummy function for binding to universal-argument */
  1206. {
  1207. }
  1208.  
  1209. /*
  1210.  * Initialize all of the buffers and windows. The buffer name is passed down
  1211.  * as an argument, because the main routine may have been told to read in a
  1212.  * file by default, and we want the buffer name to be right.
  1213.  */
  1214. edinit(bname)
  1215. char    bname[];
  1216. {
  1217.         register BUFFER *bp;
  1218.         register WINDOW *wp;
  1219.     char *malloc();
  1220.  
  1221.         bp = bfind(bname, TRUE, 0);             /* First buffer         */
  1222.         blistp = bfind("[List]", TRUE, BFINVS); /* Buffer list buffer   */
  1223.         wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  1224.         if (bp==NULL || wp==NULL || blistp==NULL)
  1225.                 exit(1);
  1226.         curbp  = bp;                            /* Make this current    */
  1227.         wheadp = wp;
  1228.         curwp  = wp;
  1229.         wp->w_wndp  = NULL;                     /* Initialize window    */
  1230.         wp->w_bufp  = bp;
  1231.         bp->b_nwnd  = 1;                        /* Displayed.           */
  1232.         wp->w_linep = bp->b_linep;
  1233.         wp->w_dotp  = bp->b_linep;
  1234.         wp->w_doto  = 0;
  1235.         wp->w_markp = NULL;
  1236.         wp->w_marko = 0;
  1237.         wp->w_toprow = 0;
  1238. #if    COLOR
  1239.     /* initalize colors to global defaults */
  1240.     wp->w_fcolor = gfcolor;
  1241.     wp->w_bcolor = gbcolor;
  1242. #endif
  1243.     wp->w_fcol = 0;
  1244.         wp->w_ntrows = term.t_nrow - 1 - menuflag; /* "-1" for mode line.  */
  1245.         wp->w_force = 0;
  1246.         wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  1247. }
  1248.  
  1249. /*
  1250.  * This is the general command execution routine. It handles the fake binding
  1251.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  1252.  * and arranges to move it to the "lastflag", so that the next command can
  1253.  * look at it. Return the status of command.
  1254.  */
  1255. execute(c, f, n)
  1256. {
  1257.         register int status;
  1258.     int (*execfunc)();        /* ptr to function to execute */
  1259.     int (*getbind())();
  1260.  
  1261.     if (f == HOOK)
  1262.         f = FALSE;
  1263.     else if (useoldargs == TRUE) {
  1264.         if (f == FALSE) {f = execfold; n = execnold;}
  1265.         useoldargs = FALSE;
  1266.     }
  1267.  
  1268.     /* if the keystroke is a bound function...do it */
  1269.     execfunc = getbind(c);
  1270.         if (execfunc != NULL) {
  1271.         thisflag = 0;
  1272.         status     = (*execfunc)(f, n);
  1273.         lastflag = thisflag;
  1274.         return (status);
  1275.         }
  1276.  
  1277.         /*
  1278.          * If a space was typed, fill column is defined, the argument is non-
  1279.          * negative, wrap mode is enabled, and we are now past fill column,
  1280.      * and we are not read-only, perform word wrap.
  1281.          */
  1282.         if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  1283.         n >= 0 && getccol(FALSE) > fillcol &&
  1284.         (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  1285.         execute(FUNC|'W', HOOK, 1);
  1286.  
  1287.         if ((c>=0x20 && c<=0xFF)) {    /* Self inserting.      */
  1288.                 if (n <= 0) {                   /* Fenceposts.          */
  1289.                         lastflag = 0;
  1290.                         return (n<0 ? FALSE : TRUE);
  1291.                 }
  1292.                 thisflag = 0;                   /* For the future.      */
  1293.  
  1294.         /* if we are in overwrite mode, not at eol,
  1295.            and next char is not a tab or we are at a tab stop,
  1296.            delete a char forword            */
  1297.         if (curwp->w_bufp->b_mode & MDOVER &&
  1298.             curwp->w_doto < curwp->w_dotp->l_used &&
  1299.             (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  1300.              (curwp->w_doto) % tabsize == (tabsize - 1)))
  1301.                 ldelete(1L, FALSE);
  1302.  
  1303.         /* do the appropriate insertion */
  1304.         if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
  1305.                 status = insbrace(n, c);
  1306.             else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
  1307.                 status = inspound();
  1308.             else
  1309.                     status = linsert(n, c);
  1310.  
  1311. #if    CFENCE
  1312.         /* check for CMODE fence matching */
  1313.         if ((c == '}' || c == ')' || c == ']') &&
  1314.                 (curbp->b_mode & MDCMOD) != 0)
  1315.             fmatch(c);
  1316. #endif
  1317.  
  1318.         /* check auto-save mode */
  1319.         if (curbp->b_mode & MDASAVE)
  1320.             if (--gacount <= 0) {
  1321.                 /* and save the file if needed */
  1322.                 upscreen(FALSE, 0);
  1323. #if    ABACKUP
  1324.                 fileback(FALSE, 0);
  1325. #else
  1326.                 filesave(FALSE, 0);
  1327. #endif
  1328.                 gacount = gasave;
  1329.             }
  1330.  
  1331.                 lastflag = thisflag;
  1332.                 return (status);
  1333.         }
  1334.     TTbeep();
  1335.     mlwrite("[Key not bound]");        /* complain        */
  1336.         lastflag = 0;                           /* Fake last flags.     */
  1337.         return (FALSE);
  1338. }
  1339.  
  1340. /*
  1341.  * Fancy quit command, as implemented by Norm. If the any buffer has
  1342.  * changed do a write on that buffer and exit emacs, otherwise simply exit.
  1343.  */
  1344. quickexit(f, n)
  1345. {
  1346.     register BUFFER *bp;    /* scanning pointer to buffers */
  1347.         register BUFFER *oldcb; /* original current buffer */
  1348.     register int status;
  1349.  
  1350.         oldcb = curbp;                          /* save in case we fail */
  1351.  
  1352.     bp = bheadp;
  1353.     while (bp != NULL) {
  1354.             if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  1355.             && (bp->b_flag&BFINVS) == 0) {    /* Real.                */
  1356.             curbp = bp;        /* make that buffer cur    */
  1357.             mlwrite("[Saving %s]",bp->b_fname);
  1358.             mlwrite("\n");
  1359.                     if ((status = filesave(f, n)) != TRUE) {
  1360.                         curbp = oldcb;    /* restore curbp */
  1361.                 sgarbf = TRUE;    /* fix up screen */
  1362.                 curwp->w_flag = WFHARD;
  1363.                         return(status);
  1364.                     }
  1365.         }
  1366.         bp = bp->b_bufp;        /* on to the next buffer */
  1367.     }
  1368.         quit(f, n);                             /* conditionally quit   */
  1369.     return(TRUE);
  1370. }
  1371.  
  1372. /*
  1373.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  1374.  * has been changed and not written out. Normally bound to "C-X C-C".
  1375.  */
  1376. quit(f, n)
  1377. {
  1378.         register int    s;
  1379.  
  1380.         if (f != FALSE                          /* Argument forces it.  */
  1381.         || anycb() == FALSE                     /* All buffers clean.   */
  1382.                         /* User says it's OK.   */
  1383.         || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
  1384. #if    FILOCK
  1385.         if (lockrel() != TRUE) {
  1386.             TTputc('\n');
  1387.             TTputc('\r');
  1388.             TTclose();
  1389.             TTkclose();
  1390.             exit(1);
  1391.         }
  1392. #endif
  1393.                 vttidy();
  1394. #if    CALLABLE
  1395.         exitflag = TRUE;
  1396.         return(s);
  1397. #else
  1398.                 exit(GOOD);
  1399. #endif
  1400.         }
  1401.     mlwrite("");
  1402.         return (s);
  1403. }
  1404.  
  1405. /*
  1406.  * Begin a keyboard macro.
  1407.  * Error if not at the top level in keyboard processing. Set up variables and
  1408.  * return.
  1409.  */
  1410. ctlxlp(f, n)
  1411. {
  1412.         if (kbdmode != STOP) {
  1413.                 mlwrite("%%Macro already active");
  1414.                 return(FALSE);
  1415.         }
  1416.         mlwrite("[Start macro]");
  1417.     kbdptr = &kbdm[0];
  1418.     kbdend = kbdptr;
  1419.         kbdmode = RECORD;
  1420.         return (TRUE);
  1421. }
  1422.  
  1423. /*
  1424.  * End keyboard macro. Check for the same limit conditions as the above
  1425.  * routine. Set up the variables and return to the caller.
  1426.  */
  1427. ctlxrp(f, n)
  1428. {
  1429.         if (kbdmode == STOP) {
  1430.                 mlwrite("%%Macro not active");
  1431.                 return(FALSE);
  1432.         }
  1433.     if (kbdmode == RECORD) {
  1434.             mlwrite("[End macro]");
  1435.             kbdmode = STOP;
  1436.     }
  1437.         return(TRUE);
  1438. }
  1439.  
  1440. /*
  1441.  * Execute a macro.
  1442.  * The command argument is the number of times to loop. Quit as soon as a
  1443.  * command gets an error. Return TRUE if all ok, else FALSE.
  1444.  */
  1445. ctlxe(f, n)
  1446. {
  1447.         if (kbdmode != STOP) {
  1448.                 mlwrite("%%Macro already active");
  1449.                 return(FALSE);
  1450.         }
  1451.         if (n <= 0)
  1452.                 return (TRUE);
  1453.     kbdrep = n;        /* remember how many times to execute */
  1454.     kbdmode = PLAY;        /* start us in play mode */
  1455.     kbdptr = &kbdm[0];    /*    at the beginning */
  1456.     return(TRUE);
  1457. }
  1458.  
  1459. /*
  1460.  * Abort.
  1461.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  1462.  * Sometimes called as a routine, to do general aborting of stuff.
  1463.  */
  1464. ctrlg(f, n)
  1465. {
  1466.         TTbeep();
  1467.     kbdmode = STOP;
  1468.     mlwrite("[Aborted]");
  1469.         return(ABORT);
  1470. }
  1471.  
  1472. /* tell the user that this command is illegal while we are in
  1473.    VIEW (read-only) mode                */
  1474.  
  1475. rdonly()
  1476.  
  1477. {
  1478.     TTbeep();
  1479.     mlwrite("[Key illegal in VIEW mode]");
  1480.     return(FALSE);
  1481. }
  1482.  
  1483. resterr()
  1484.  
  1485. {
  1486.     TTbeep();
  1487.     mlwrite("[That command is RESTRICTED]");
  1488.     return(FALSE);
  1489. }
  1490.  
  1491. nullproc()    /* user function that does NOTHING */
  1492.  
  1493. {
  1494. }
  1495.  
  1496. /*****        Compiler specific Library functions    ****/
  1497.  
  1498. #if    (MWC86 & MSDOS) | DECUSC
  1499. movmem(source, dest, size)
  1500.  
  1501. char *source;    /* mem location to move memory from */
  1502. char *dest;    /* memory location to move text to */
  1503. int size;    /* number of bytes to move */
  1504.  
  1505. {
  1506.     register int i;
  1507.  
  1508.     for (i=0; i < size; i++)
  1509.         *dest++ = *source++;
  1510. }
  1511. #endif
  1512.  
  1513. /*    bytecopy:    copy a string...with length restrictions
  1514.             ALWAYS null terminate
  1515. */
  1516.  
  1517. char *bytecopy(dst, src, maxlen)
  1518.  
  1519. char *dst;    /* destination of copied string */
  1520. char *src;    /* source */
  1521. int maxlen;    /* maximum length */
  1522.  
  1523. {
  1524.     char *dptr;    /* ptr into dst */
  1525.  
  1526.     dptr = dst;
  1527.     while (*src && (maxlen-- > 0))
  1528.         *dptr++ = *src++;
  1529.     *dptr = 0;
  1530.     return(dst);
  1531. }
  1532.  
  1533. #if    DECUSC
  1534. fgetc(iop) FILE *iop; { return(getc(iop)); }
  1535. fputc(c, iop) char c; FILE *iop; { return(putc(c, iop)); }
  1536. #endif
  1537.  
  1538. #if    RAMSIZE
  1539. /*    These routines will allow me to track memory usage by placing
  1540.     a layer on top of the standard system malloc() and free() calls.
  1541.     with this code defined, the environment variable, $RAM, will
  1542.     report on the number of bytes allocated via malloc.
  1543.  
  1544.     with SHOWRAM defined, the number is also posted on the
  1545.     end of the bottom mode line and is updated whenever it is changed.
  1546. */
  1547.  
  1548. #undef    malloc
  1549. #undef    free
  1550.  
  1551. char *allocate(nbytes)    /* allocate nbytes and track */
  1552.  
  1553. unsigned nbytes;    /* # of bytes to allocate */
  1554.  
  1555. {
  1556.     unsigned *mp;    /* ptr returned from malloc */
  1557.     char *malloc();
  1558.  
  1559.     mp = malloc(nbytes + sizeof(unsigned));
  1560.     if (mp != NULL) {
  1561.         envram += nbytes;
  1562.         *mp = nbytes;
  1563.         ++mp;
  1564. #if    RAMSHOW
  1565.         dspram();
  1566. #endif
  1567.     }
  1568.  
  1569.     return(mp);
  1570. }
  1571.  
  1572. release(mp)    /* release malloced memory and track */
  1573.  
  1574. char *mp;    /* chunk of RAM to release */
  1575.  
  1576. {
  1577.     unsigned *lp;    /* ptr to the long containing the block size */
  1578.  
  1579.     if (mp != NULL) {
  1580.         lp = ((unsigned *)mp) - 1;
  1581.  
  1582.         /* update amount of ram currently malloced */
  1583.         envram -= (long)*lp;
  1584.         free(lp);
  1585. #if    RAMSHOW
  1586.         dspram();
  1587. #endif
  1588.     }
  1589. }
  1590.  
  1591. #if    RAMSHOW
  1592. dspram()    /* display the amount of RAM currently malloced */
  1593.  
  1594. {
  1595.     char mbuf[20];
  1596.     char *sp;
  1597.  
  1598.     TTmove(term.t_nrow - 1, 70);
  1599. #if    COLOR
  1600.     TTforg(7);
  1601.     TTbacg(0);
  1602. #endif
  1603.     sprintf(mbuf, "[%lu]", envram);
  1604.     sp = &mbuf[0];
  1605.     while (*sp)
  1606.         TTputc(*sp++);
  1607.     TTmove(term.t_nrow, 0);
  1608.     movecursor(term.t_nrow, 0);
  1609. }
  1610. #endif
  1611. #endif
  1612.