home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume4
/
uemacs3.6
/
part6
< prev
next >
Wrap
Text File
|
1986-11-30
|
42KB
|
1,217 lines
Subject: MicroEMACS 3.6 (Part 6 of 8)
Newsgroups: mod.sources
Approved: jpn@panda.UUCP
Mod.sources: Volume 4, Issue 103
Submitted by: ihnp4!itivax!duncan!lawrence
echo x - line.c
sed 's/^X//' >line.c <<'*-*-END-of-line.c-*-*'
X/*
X * The functions in this file are a general set of line management utilities.
X * They are the only routines that touch the text. They also touch the buffer
X * and window structures, to make sure that the necessary updating gets done.
X * There are routines in this file that handle the kill buffer too. It isn't
X * here for any good reason.
X *
X * Note that this code only updates the dot and mark values in the window list.
X * Since all the code acts on the current window, the buffer that we are
X * editing must be being displayed, which means that "b_nwnd" is non zero,
X * which means that the dot and mark values in the buffer headers are nonsense.
X */
X
X#include <stdio.h>
X#include "estruct.h"
X#include "edef.h"
X
X#define NBLOCK 16 /* Line block chunk size */
X#define KBLOCK 1024 /* Kill buffer block size */
X
Xchar *kbufp = NULL; /* Kill buffer data */
Xunsigned kused = 0; /* # of bytes used in KB */
Xunsigned ksize = 0; /* # of bytes allocated in KB */
X
X/*
X * This routine allocates a block of memory large enough to hold a LINE
X * containing "used" characters. The block is always rounded up a bit. Return
X * a pointer to the new block, or NULL if there isn't any memory left. Print a
X * message in the message line if no space.
X */
XLINE *
Xlalloc(used)
Xregister int used;
X{
X register LINE *lp;
X register int size;
X char *malloc();
X
X size = (used+NBLOCK-1) & ~(NBLOCK-1);
X if (size == 0) /* Assume that an empty */
X size = NBLOCK; /* line is for type-in. */
X if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
X mlwrite("Cannot allocate %d bytes", size);
X return (NULL);
X }
X lp->l_size = size;
X lp->l_used = used;
X return (lp);
X}
X
X/*
X * Delete line "lp". Fix all of the links that might point at it (they are
X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
X * might be in. Release the memory. The buffers are updated too; the magic
X * conditions described in the above comments don't hold here.
X */
Xlfree(lp)
Xregister LINE *lp;
X{
X register BUFFER *bp;
X register WINDOW *wp;
X
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_linep == lp)
X wp->w_linep = lp->l_fp;
X if (wp->w_dotp == lp) {
X wp->w_dotp = lp->l_fp;
X wp->w_doto = 0;
X }
X if (wp->w_markp == lp) {
X wp->w_markp = lp->l_fp;
X wp->w_marko = 0;
X }
X wp = wp->w_wndp;
X }
X bp = bheadp;
X while (bp != NULL) {
X if (bp->b_nwnd == 0) {
X if (bp->b_dotp == lp) {
X bp->b_dotp = lp->l_fp;
X bp->b_doto = 0;
X }
X if (bp->b_markp == lp) {
X bp->b_markp = lp->l_fp;
X bp->b_marko = 0;
X }
X }
X bp = bp->b_bufp;
X }
X lp->l_bp->l_fp = lp->l_fp;
X lp->l_fp->l_bp = lp->l_bp;
X free((char *) lp);
X}
X
X/*
X * This routine gets called when a character is changed in place in the current
X * buffer. It updates all of the required flags in the buffer and window
X * system. The flag used is passed as an argument; if the buffer is being
X * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
X * mode line needs to be updated (the "*" has to be set).
X */
Xlchange(flag)
Xregister int flag;
X{
X register WINDOW *wp;
X
X if (curbp->b_nwnd != 1) /* Ensure hard. */
X flag = WFHARD;
X if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
X flag |= WFMODE; /* update mode lines. */
X curbp->b_flag |= BFCHG;
X }
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_bufp == curbp)
X wp->w_flag |= flag;
X wp = wp->w_wndp;
X }
X}
X
Xinsspace(f, n) /* insert spaces forward into text */
X
Xint f, n; /* default flag and numeric argument */
X
X{
X linsert(n, ' ');
X backchar(f, n);
X}
X
X/*
X * Insert "n" copies of the character "c" at the current location of dot. In
X * the easy case all that happens is the text is stored in the line. In the
X * hard case, the line has to be reallocated. When the window list is updated,
X * take special care; I screwed it up once. You always update dot in the
X * current window. You update mark, and a dot in another window, if it is
X * greater than the place where you did the insert. Return TRUE if all is
X * well, and FALSE on errors.
X */
Xlinsert(n, c)
X{
X register char *cp1;
X register char *cp2;
X register LINE *lp1;
X register LINE *lp2;
X register LINE *lp3;
X register int doto;
X register int i;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X lchange(WFEDIT);
X lp1 = curwp->w_dotp; /* Current line */
X if (lp1 == curbp->b_linep) { /* At the end: special */
X if (curwp->w_doto != 0) {
X mlwrite("bug: linsert");
X return (FALSE);
X }
X if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
X return (FALSE);
X lp3 = lp1->l_bp; /* Previous line */
X lp3->l_fp = lp2; /* Link in */
X lp2->l_fp = lp1;
X lp1->l_bp = lp2;
X lp2->l_bp = lp3;
X for (i=0; i<n; ++i)
X lp2->l_text[i] = c;
X curwp->w_dotp = lp2;
X curwp->w_doto = n;
X return (TRUE);
X }
X doto = curwp->w_doto; /* Save for later. */
X if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
X if ((lp2=lalloc(lp1->l_used+n)) == NULL)
X return (FALSE);
X cp1 = &lp1->l_text[0];
X cp2 = &lp2->l_text[0];
X while (cp1 != &lp1->l_text[doto])
X *cp2++ = *cp1++;
X cp2 += n;
X while (cp1 != &lp1->l_text[lp1->l_used])
X *cp2++ = *cp1++;
X lp1->l_bp->l_fp = lp2;
X lp2->l_fp = lp1->l_fp;
X lp1->l_fp->l_bp = lp2;
X lp2->l_bp = lp1->l_bp;
X free((char *) lp1);
X } else { /* Easy: in place */
X lp2 = lp1; /* Pretend new line */
X lp2->l_used += n;
X cp2 = &lp1->l_text[lp1->l_used];
X cp1 = cp2-n;
X while (cp1 != &lp1->l_text[doto])
X *--cp2 = *--cp1;
X }
X for (i=0; i<n; ++i) /* Add the characters */
X lp2->l_text[doto+i] = c;
X wp = wheadp; /* Update windows */
X while (wp != NULL) {
X if (wp->w_linep == lp1)
X wp->w_linep = lp2;
X if (wp->w_dotp == lp1) {
X wp->w_dotp = lp2;
X if (wp==curwp || wp->w_doto>doto)
X wp->w_doto += n;
X }
X if (wp->w_markp == lp1) {
X wp->w_markp = lp2;
X if (wp->w_marko > doto)
X wp->w_marko += n;
X }
X wp = wp->w_wndp;
X }
X return (TRUE);
X}
X
X/*
X * Insert a newline into the buffer at the current location of dot in the
X * current window. The funny ass-backwards way it does things is not a botch;
X * it just makes the last line in the file not a special case. Return TRUE if
X * everything works out and FALSE on error (memory allocation failure). The
X * update of dot and mark is a bit easier then in the above case, because the
X * split forces more updating.
X */
Xlnewline()
X{
X register char *cp1;
X register char *cp2;
X register LINE *lp1;
X register LINE *lp2;
X register int doto;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X lchange(WFHARD);
X lp1 = curwp->w_dotp; /* Get the address and */
X doto = curwp->w_doto; /* offset of "." */
X if ((lp2=lalloc(doto)) == NULL) /* New first half line */
X return (FALSE);
X cp1 = &lp1->l_text[0]; /* Shuffle text around */
X cp2 = &lp2->l_text[0];
X while (cp1 != &lp1->l_text[doto])
X *cp2++ = *cp1++;
X cp2 = &lp1->l_text[0];
X while (cp1 != &lp1->l_text[lp1->l_used])
X *cp2++ = *cp1++;
X lp1->l_used -= doto;
X lp2->l_bp = lp1->l_bp;
X lp1->l_bp = lp2;
X lp2->l_bp->l_fp = lp2;
X lp2->l_fp = lp1;
X wp = wheadp; /* Windows */
X while (wp != NULL) {
X if (wp->w_linep == lp1)
X wp->w_linep = lp2;
X if (wp->w_dotp == lp1) {
X if (wp->w_doto < doto)
X wp->w_dotp = lp2;
X else
X wp->w_doto -= doto;
X }
X if (wp->w_markp == lp1) {
X if (wp->w_marko < doto)
X wp->w_markp = lp2;
X else
X wp->w_marko -= doto;
X }
X wp = wp->w_wndp;
X }
X return (TRUE);
X}
X
X/*
X * This function deletes "n" bytes, starting at dot. It understands how do deal
X * with end of lines, etc. It returns TRUE if all of the characters were
X * deleted, and FALSE if they were not (because dot ran into the end of the
X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
X */
Xldelete(n, kflag)
X{
X register char *cp1;
X register char *cp2;
X register LINE *dotp;
X register int doto;
X register int chunk;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X while (n != 0) {
X dotp = curwp->w_dotp;
X doto = curwp->w_doto;
X if (dotp == curbp->b_linep) /* Hit end of buffer. */
X return (FALSE);
X chunk = dotp->l_used-doto; /* Size of chunk. */
X if (chunk > n)
X chunk = n;
X if (chunk == 0) { /* End of line, merge. */
X lchange(WFHARD);
X if (ldelnewline() == FALSE
X || (kflag!=FALSE && kinsert('\n')==FALSE))
X return (FALSE);
X --n;
X continue;
X }
X lchange(WFEDIT);
X cp1 = &dotp->l_text[doto]; /* Scrunch text. */
X cp2 = cp1 + chunk;
X if (kflag != FALSE) { /* Kill? */
X while (cp1 != cp2) {
X if (kinsert(*cp1) == FALSE)
X return (FALSE);
X ++cp1;
X }
X cp1 = &dotp->l_text[doto];
X }
X while (cp2 != &dotp->l_text[dotp->l_used])
X *cp1++ = *cp2++;
X dotp->l_used -= chunk;
X wp = wheadp; /* Fix windows */
X while (wp != NULL) {
X if (wp->w_dotp==dotp && wp->w_doto>=doto) {
X wp->w_doto -= chunk;
X if (wp->w_doto < doto)
X wp->w_doto = doto;
X }
X if (wp->w_markp==dotp && wp->w_marko>=doto) {
X wp->w_marko -= chunk;
X if (wp->w_marko < doto)
X wp->w_marko = doto;
X }
X wp = wp->w_wndp;
X }
X n -= chunk;
X }
X return (TRUE);
X}
X
X/*
X * Delete a newline. Join the current line with the next line. If the next line
X * is the magic header line always return TRUE; merging the last line with the
X * header line can be thought of as always being a successful operation, even
X * if nothing is done, and this makes the kill buffer work "right". Easy cases
X * can be done by shuffling data around. Hard cases require that lines be moved
X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
X * "ldelete" only.
X */
Xldelnewline()
X{
X register char *cp1;
X register char *cp2;
X register LINE *lp1;
X register LINE *lp2;
X register LINE *lp3;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X lp1 = curwp->w_dotp;
X lp2 = lp1->l_fp;
X if (lp2 == curbp->b_linep) { /* At the buffer end. */
X if (lp1->l_used == 0) /* Blank line. */
X lfree(lp1);
X return (TRUE);
X }
X if (lp2->l_used <= lp1->l_size-lp1->l_used) {
X cp1 = &lp1->l_text[lp1->l_used];
X cp2 = &lp2->l_text[0];
X while (cp2 != &lp2->l_text[lp2->l_used])
X *cp1++ = *cp2++;
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_linep == lp2)
X wp->w_linep = lp1;
X if (wp->w_dotp == lp2) {
X wp->w_dotp = lp1;
X wp->w_doto += lp1->l_used;
X }
X if (wp->w_markp == lp2) {
X wp->w_markp = lp1;
X wp->w_marko += lp1->l_used;
X }
X wp = wp->w_wndp;
X }
X lp1->l_used += lp2->l_used;
X lp1->l_fp = lp2->l_fp;
X lp2->l_fp->l_bp = lp1;
X free((char *) lp2);
X return (TRUE);
X }
X if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
X return (FALSE);
X cp1 = &lp1->l_text[0];
X cp2 = &lp3->l_text[0];
X while (cp1 != &lp1->l_text[lp1->l_used])
X *cp2++ = *cp1++;
X cp1 = &lp2->l_text[0];
X while (cp1 != &lp2->l_text[lp2->l_used])
X *cp2++ = *cp1++;
X lp1->l_bp->l_fp = lp3;
X lp3->l_fp = lp2->l_fp;
X lp2->l_fp->l_bp = lp3;
X lp3->l_bp = lp1->l_bp;
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_linep==lp1 || wp->w_linep==lp2)
X wp->w_linep = lp3;
X if (wp->w_dotp == lp1)
X wp->w_dotp = lp3;
X else if (wp->w_dotp == lp2) {
X wp->w_dotp = lp3;
X wp->w_doto += lp1->l_used;
X }
X if (wp->w_markp == lp1)
X wp->w_markp = lp3;
X else if (wp->w_markp == lp2) {
X wp->w_markp = lp3;
X wp->w_marko += lp1->l_used;
X }
X wp = wp->w_wndp;
X }
X free((char *) lp1);
X free((char *) lp2);
X return (TRUE);
X}
X
X/*
X * Delete all of the text saved in the kill buffer. Called by commands when a
X * new kill context is being created. The kill buffer array is released, just
X * in case the buffer has grown to immense size. No errors.
X */
Xkdelete()
X{
X if (kbufp != NULL) {
X free((char *) kbufp);
X kbufp = NULL;
X kused = 0;
X ksize = 0;
X }
X}
X
X/*
X * Insert a character to the kill buffer, enlarging the buffer if there isn't
X * any room. Always grow the buffer in chunks, on the assumption that if you
X * put something in the kill buffer you are going to put more stuff there too
X * later. Return TRUE if all is well, and FALSE on errors.
X */
X
Xkinsert(c)
X{
X register char *nbufp;
X char *realloc();
X char *malloc();
X
X if (kused == ksize) {
X if (ksize == 0) /* first time through? */
X nbufp = malloc(KBLOCK); /* alloc the first block */
X else /* or re allocate a bigger block */
X nbufp = realloc(kbufp, ksize+KBLOCK);
X if (nbufp == NULL) /* abort if it fails */
X return(FALSE);
X kbufp = nbufp; /* point our global at it */
X ksize += KBLOCK; /* and adjust the size */
X }
X kbufp[kused++] = c;
X return (TRUE);
X}
X
X/*
X * This function gets characters from the kill buffer. If the character index
X * "n" is off the end, it returns "-1". This lets the caller just scan along
X * until it gets a "-1" back.
X */
Xkremove(n)
X{
X if (n >= kused)
X return (-1);
X else
X return (kbufp[n] & 0xFF);
X}
X
X#if LATTICE
X/* we need to have the following functions to manage memory that
X don't exist under Lattice */
X
X
Xchar *realloc(ptr, size) /* re-allocate a memory chunk to a
X different size, copying what can
X by copied */
X
Xchar *ptr; /* pointer to the original block */
Xunsigned size; /* # of bytes needed in new block */
X
X{
X char *newptr; /* pointer to new block */
X unsigned csize; /* size of area to copy from old buffer to new */
X char *malloc();
X
X newptr = malloc(size); /* get the new block */
X if (newptr == NULL) /* if malloc fails....*/
X return(NULL);
X
X csize = ksize; /******THIS IS A CHEAT SINCE WE CAN NOT GET
X AT THE SIZE OF THE MALLOCED BLOCK!!
X DO NOT USE THIS FUNCTION GENERICALLY!!!*/
X if (csize > size) /* we need to copy some stuff from */
X csize = size; /* the old buffer to the new */
X
X movmem(ptr, newptr, csize); /* copy the availible bytes */
X free(ptr); /* dump the old buffer */
X return(newptr); /* and return the new */
X}
X#endif
X
*-*-END-of-line.c-*-*
echo x - main.c
sed 's/^X//' >main.c <<'*-*-END-of-main.c-*-*'
X/*
X * This program is in public domain; written by Dave G. Conroy.
X * This file contains the main driving routine, and some keyboard processing
X * code, for the MicroEMACS screen editor.
X *
X * REVISION HISTORY:
X *
X * 1.0 Steve Wilhite, 30-Nov-85
X * - Removed the old LK201 and VT100 logic. Added code to support the
X * DEC Rainbow keyboard (which is a LK201 layout) using the the Level
X * 1 Console In ROM INT. See "rainbow.h" for the function key defs
X * Steve Wilhite, 1-Dec-85
X * - massive cleanup on code in display.c and search.c
X *
X * 2.0 George Jones, 12-Dec-85
X * - Ported to Amiga.
X *
X * 3.0 Daniel Lawrence, 29-Dec-85
X * - rebound keys/added new fast buffered I/O for AMIGA
X * - added META- repeat commands
X * - added reposition default to center screen (yeah!)
X * - changed exit with modified buffers message
X * - made filesave tell us what it is doing
X * - changed search string entry to terminate with <ESC>
X * so we can use <NL> in search/replace strings
X * - updated version number in mode line to 3.0
X * 12-Jan-86
X * - Added code to reconize the Search/replace functions
X * - Added code to perform search/replace & query functions
X * 14-Jan-86
X * - moved search logic to separate function in search.c
X * - added replace and query replace functions
X * - separated out control key expansions to be used by others in search.c
X * 15-Jan-86
X * - changed "visiting" to finding
X * - changed yes/no responces to not need return
X * - cleaned up various messages
X * 16-jan-86
X * - fixed spurious spawn message in MSDOS
X * - added ^X-S synonime to save command
X * - moved escape to shell to ^X-C
X * 21-jan-86
X * - added code to suspend shell under BSD
X * 22-jan-86
X * - added function key support (SPEC) under MSDOS
X * - Abort now prints [Aborted] on message line
X * 23-jan-86
X * - Added modes and commends to set/unset them
X * 24-jan-86
X * - Added Goto Line command
X * - added Rename Buffer command
X * 28-jan-86
X * - added goto begining and end of paragraph commands (META-P/META-N)
X * - re-wrote kdelete to use realloc. gained MUCH speed here when
X * doing large wipes both on UNIX and MSDOS. Changed kill buffer
X * allocation block size from 256 bytes to 1 k
X * 29-jan-86
X * - moved extern function declarations to efunc.h
X * - made name[] name binding table
X * 30-jan-86
X * - fixed Previous/Next paragraph command not to wrap around EOF
X * - added Fill Paragraph command (META-Q)
X * 4-feb-86
X * - added code to properly display long lines, scrolling them right
X * to left
X * 5-feb-85
X * - rewrote code to right/left scroll...much better
X * - added shifted arror keys on IBMPC
X * 6-feb-85
X * - add option to allow forword-word to jump to begining of
X * next word instead of end of current one. This is different from
X * other emacs' but can be configured off in estruct.h
X * - added VIEW mode to allow a buffer to be read only
X * (-v switch on command line will activate this)
X * - changed quick exit to write out ALL changed buffers!!!
X * MAKE SURE YOU KNOW THIS WHEN META-Zing
X * 10-feb-86
X * - added handling of lines longer than allowed on file read in
X * (they wrap on additional lines)
X * - made having space clear the message line and NOT insert itself
X * a configuration option in ed.h
X * 11-feb-86
X * - added Describe-command and Help commands.
X * 13-feb-86
X * - added View file command (^X ^V) and finished HELP command
X * 14-feb-86
X * - added option to let main loop skip update if type ahead commands
X * are queued up
X * 16-feb-86
X * - added Insert File command
X * 17-feb-86
X * - added scroll next window up/down commands
X * 18-feb-86
X * - added CMODE indentation
X * - re-arranged header files to standerdize extern and global
X * definitions
X * - changed version number to 3.2
X * - added numeric arguments to search, reverse search and
X * search and replace
X * 24-feb-86
X * - added Bind To Key function (^C for now) to allow the user
X * to change his command keys
X * - added Unbind key function (M-^C for now)
X * - added execute named command to execute unbound commands (M-X)
X * - added describe bindings command (not bound)
X * - changed version number to 3.3
X * 25-feb-86
X * - scrapped CERROR mode (too many compilers)
X * - added EXACT mode for case sensitive searchers
X * 26-feb-86
X * - added command completion on execute named command and
X * all routined grabbing a command name
X * - adding execute-command-line command and its support functions
X * (in preporation for sourcing files)
X * - added Execute Buffer command
X * 27-feb-86
X * - added execute(source) file command and added code to automatically
X * execute emacs.rc (or .emacsrc on UNIX) before initial read in
X * - changed version number to 3.4
X * 4-mar-86
X * - changed word delete to be consistant with word move (it gets
X * rid of the inter word space now) This is configurable with the
X * NFWORD symbol in estruct.h
X * - added B_ACTIVE entry to the buffer table. Let emacs read multiple
X * file names from the command line and only read them in as needed
X * 5-mar-85
X * - rewrote command line parser to get rid of my patchy code
X * - changed version number to 3.5
X * 1-apr-86
X * - added support for Aztec C 3.20e under MSDOS
X * - fixed bug in mlwrite on ADM3's and thier ilk under V7
X * - added insertion of pounds in column one under CMODE
X * - changed version number to 3.6
X * 3-apr-86
X * - added next-buffer command (^X-X)
X * 5-apr-86
X * - added kill paragraph command (M-^W)
X * - changed fill-paragraph to leave 2 spaces after a period at the
X * end of a word.
X * - added OVERWRITE mode
X * 7-apr-86
X * - fixed overwrite mode to handle tabs
X * 8-apr-86
X * - added add/delete global mode (<ESC>M & <ESC> ^M) commands
X * 9-apr-86
X * - added insert space command
X * - moved bindings around ^C insert space
X * M-K bind-to-key
X * INSERT insert space
X * DELETE forwdel
X * - added hunt forward and hunt reverse commands
X * 10-apr-86
X * - fixed bug in DOBUF with non-terminated command string
X * 15-apr-86
X * - fixed tab expansion bug in DISPLAY which hung the AMIGA
X * (send in by Dawn Banks)
X * - fixed curcol problen if forwline/backline during keyboard
X * macro execution (sent in by Ernst Christen)
X * - added AMIGA function/cursor key support
X * - fixed nonterminating <NL> replacement bug
X * - fixed word wrapping problems
X * 16-apr-86
X * - updated documentation and froze development for 3.6 net release
X */
X
X#include <stdio.h>
X
X/* make global definitions not external */
X#define maindef
X
X#include "estruct.h" /* global structures and defines */
X#include "efunc.h" /* function declarations and name table */
X#include "edef.h" /* global definitions */
X#include "ebind.h" /* default key bindings */
X
X#if VMS
X#include <ssdef.h>
X#define GOOD (SS$_NORMAL)
X#endif
X
X#ifndef GOOD
X#define GOOD 0
X#endif
X
Xmain(argc, argv)
Xchar *argv[];
X{
X register int c;
X register int f;
X register int n;
X register int mflag;
X register BUFFER *bp;
X register int ffile; /* first file flag */
X register int carg; /* current arg to scan */
X int basec; /* c stripped of meta character */
X int viewflag; /* are we starting in view mode? */
X char bname[NBUFN]; /* buffer name of file to read */
X
X /* initialize the editor and process the startup file */
X strcpy(bname, "main"); /* default buffer name */
X edinit(bname); /* Buffers, windows. */
X vtinit(); /* Displays. */
X startup(); /* execute .emacsrc if there */
X viewflag = FALSE;
X ffile = TRUE; /* no file to edit yet */
X update(); /* let the user know we are here */
X
X /* scan through the command line and get the files to edit */
X for (carg = 1; carg < argc; ++carg) {
X /* if its a switch, process it */
X if (argv[carg][0] == '-') {
X switch (argv[carg][1]) {
X case 'v': /* -v for View File */
X case 'V':
X viewflag = TRUE;
X break;
X case 'e': /* -e for Edit file */
X case 'E':
X viewflag = FALSE;
X break;
X default: /* unknown switch */
X /* ignore this for now */
X break;
X }
X } else { /* process a file name */
X /* set up a buffer for this file */
X makename(bname, argv[carg]);
X
X /* if this is the first file, read it in */
X if (ffile) {
X bp = curbp;
X makename(bname, argv[carg]);
X strcpy(bp->b_bname, bname);
X strcpy(bp->b_fname, argv[carg]);
X if (readin(argv[carg], (viewflag==FALSE))
X == ABORT) {
X strcpy(bp->b_bname, "main");
X strcpy(bp->b_fname, "");
X }
X bp->b_dotp = bp->b_linep;
X bp->b_doto = 0;
X ffile = FALSE;
X } else {
X /* set this to inactive */
X bp = bfind(bname, TRUE, 0);
X strcpy(bp->b_fname, argv[carg]);
X bp->b_active = FALSE;
X }
X
X /* set the view mode appropriatly */
X if (viewflag)
X bp->b_mode |= MDVIEW;
X }
X }
X
X /* setup to process commands */
X lastflag = 0; /* Fake last flags. */
X curbp->b_mode = curbp->b_mode | gmode; /* and set default modes*/
X curwp->w_flag |= WFMODE; /* and force an update */
X
Xloop:
X update(); /* Fix up the screen */
X c = getkey();
X if (mpresf != FALSE) {
X mlerase();
X update();
X#if CLRMSG
X if (c == ' ') /* ITS EMACS does this */
X goto loop;
X#endif
X }
X f = FALSE;
X n = 1;
X
X /* do META-# processing if needed */
X
X basec = c & ~META; /* strip meta char off if there */
X if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
X f = TRUE; /* there is a # arg */
X n = 0; /* start with a zero default */
X mflag = 1; /* current minus flag */
X c = basec; /* strip the META */
X while ((c >= '0' && c <= '9') || (c == '-')) {
X if (c == '-') {
X /* already hit a minus or digit? */
X if ((mflag == -1) || (n != 0))
X break;
X mflag = -1;
X } else {
X n = n * 10 + (c - '0');
X }
X if ((n == 0) && (mflag == -1)) /* lonely - */
X mlwrite("Arg:");
X else
X mlwrite("Arg: %d",n * mflag);
X
X c = getkey(); /* get the next key */
X }
X n = n * mflag; /* figure in the sign */
X }
X
X /* do ^U repeat argument processing */
X
X if (c == (CTRL|'U')) { /* ^U, start argument */
X f = TRUE;
X n = 4; /* with argument of 4 */
X mflag = 0; /* that can be discarded. */
X mlwrite("Arg: 4");
X while ((c=getkey()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
X if (c == (CTRL|'U'))
X n = n*4;
X /*
X * If dash, and start of argument string, set arg.
X * to -1. Otherwise, insert it.
X */
X else if (c == '-') {
X if (mflag)
X break;
X n = 0;
X mflag = -1;
X }
X /*
X * If first digit entered, replace previous argument
X * with digit and set sign. Otherwise, append to arg.
X */
X else {
X if (!mflag) {
X n = 0;
X mflag = 1;
X }
X n = 10*n + c - '0';
X }
X mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
X }
X /*
X * Make arguments preceded by a minus sign negative and change
X * the special argument "^U -" to an effective "^U -1".
X */
X if (mflag == -1) {
X if (n == 0)
X n++;
X n = -n;
X }
X }
X if (c == (CTRL|'X')) /* ^X is a prefix */
X c = CTLX | getctl();
X if (kbdmip != NULL) { /* Save macro strokes. */
X if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
X ctrlg(FALSE, 0);
X goto loop;
X }
X if (f != FALSE) {
X *kbdmip++ = (CTRL|'U');
X *kbdmip++ = n;
X }
X *kbdmip++ = c;
X }
X execute(c, f, n); /* Do it. */
X goto loop;
X}
X
X/*
X * Initialize all of the buffers and windows. The buffer name is passed down
X * as an argument, because the main routine may have been told to read in a
X * file by default, and we want the buffer name to be right.
X */
Xedinit(bname)
Xchar bname[];
X{
X register BUFFER *bp;
X register WINDOW *wp;
X char *malloc();
X
X bp = bfind(bname, TRUE, 0); /* First buffer */
X blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer */
X wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window */
X if (bp==NULL || wp==NULL || blistp==NULL)
X exit(1);
X curbp = bp; /* Make this current */
X wheadp = wp;
X curwp = wp;
X wp->w_wndp = NULL; /* Initialize window */
X wp->w_bufp = bp;
X bp->b_nwnd = 1; /* Displayed. */
X wp->w_linep = bp->b_linep;
X wp->w_dotp = bp->b_linep;
X wp->w_doto = 0;
X wp->w_markp = NULL;
X wp->w_marko = 0;
X wp->w_toprow = 0;
X wp->w_ntrows = term.t_nrow-1; /* "-1" for mode line. */
X wp->w_force = 0;
X wp->w_flag = WFMODE|WFHARD; /* Full. */
X}
X
X/*
X * This is the general command execution routine. It handles the fake binding
X * of all the keys to "self-insert". It also clears out the "thisflag" word,
X * and arranges to move it to the "lastflag", so that the next command can
X * look at it. Return the status of command.
X */
Xexecute(c, f, n)
X{
X register KEYTAB *ktp;
X register int status;
X
X ktp = &keytab[0]; /* Look in key table. */
X while (ktp->k_fp != NULL) {
X if (ktp->k_code == c) {
X thisflag = 0;
X status = (*ktp->k_fp)(f, n);
X lastflag = thisflag;
X return (status);
X }
X ++ktp;
X }
X
X /*
X * If a space was typed, fill column is defined, the argument is non-
X * negative, wrap mode is enabled, and we are now past fill column,
X * and we are not read-only, perform word wrap.
X */
X if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
X n >= 0 && getccol(FALSE) > fillcol &&
X (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
X wrapword();
X
X if ((c>=0x20 && c<=0x7E) /* Self inserting. */
X || (c>=0xA0 && c<=0xFE)) {
X if (n <= 0) { /* Fenceposts. */
X lastflag = 0;
X return (n<0 ? FALSE : TRUE);
X }
X thisflag = 0; /* For the future. */
X
X /* if we are in overwrite mode, not at eol,
X and next char is not a tab or we are at a tab stop,
X delete a char forword */
X if (curwp->w_bufp->b_mode & MDOVER &&
X curwp->w_doto < curwp->w_dotp->l_used &&
X (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
X (curwp->w_doto) % 8 == 7))
X ldelete(1, FALSE);
X
X /* do the appropriate insertion */
X if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
X status = insbrace(n, c);
X else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
X status = inspound();
X else
X status = linsert(n, c);
X
X lastflag = thisflag;
X return (status);
X }
X mlwrite("\007[Key not bound]"); /* complain */
X lastflag = 0; /* Fake last flags. */
X return (FALSE);
X}
X
X/*
X * Read in a key.
X * Do the standard keyboard preprocessing. Convert the keys to the internal
X * character set.
X */
Xgetkey()
X{
X int c;
X#if AMIGA
X int d;
X#endif
X
X c = (*term.t_getchar)();
X
X#if RAINBOW
X
X if (c & Function_Key)
X {
X int i;
X
X for (i = 0; i < lk_map_size; i++)
X if (c == lk_map[i][0])
X return lk_map[i][1];
X }
X else if (c == Shift + 015) return CTRL | 'J';
X else if (c == Shift + 0x7F) return META | 0x7F;
X#endif
X
X#if MSDOS
X if (c == 0) { /* Apply SPEC prefix */
X c = getkey();
X return(SPEC | c);
X }
X#endif
X
X#if AMIGA
X /* apply SPEC prefix */
X if ((unsigned)c == 155) {
X c = (*term.t_getchar)();
X
X /* first try to see if it is a cursor key */
X if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
X return(SPEC | c);
X
X /* next, a 2 char sequence */
X d = (*term.t_getchar)();
X if (d == '~')
X return(SPEC | c);
X
X /* decode a 3 char sequence */
X c = d + 32;
X /* if a shifted function key, eat the tilde */
X if (d >= '0' && d <= '9')
X d = (*term.t_getchar)();
X return(SPEC | c);
X }
X#endif
X
X if (c == METACH) { /* Apply M- prefix */
X c = getctl();
X return (META | c);
X }
X
X if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
X c = CTRL | (c+'@');
X return (c);
X}
X
X/*
X * Get a key.
X * Apply control modifications to the read key.
X */
Xgetctl()
X{
X register int c;
X
X c = (*term.t_getchar)();
X if (c>='a' && c<='z') /* Force to upper */
X c -= 0x20;
X if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
X c = CTRL | (c+'@');
X return (c);
X}
X
X/*
X * Fancy quit command, as implemented by Norm. If the any buffer has
X * changed do a write on that buffer and exit emacs, otherwise simply exit.
X */
Xquickexit(f, n)
X{
X register BUFFER *bp; /* scanning pointer to buffers */
X
X bp = bheadp;
X while (bp != NULL) {
X if ((bp->b_flag&BFCHG) != 0 /* Changed. */
X && (bp->b_flag&BFTEMP) == 0) { /* Real. */
X curbp = bp; /* make that buffer cur */
X mlwrite("[Saving %s]",bp->b_fname);
X filesave(f, n);
X }
X bp = bp->b_bufp; /* on to the next buffer */
X }
X quit(f, n); /* conditionally quit */
X}
X
X/*
X * Quit command. If an argument, always quit. Otherwise confirm if a buffer
X * has been changed and not written out. Normally bound to "C-X C-C".
X */
Xquit(f, n)
X{
X register int s;
X
X if (f != FALSE /* Argument forces it. */
X || anycb() == FALSE /* All buffers clean. */
X /* User says it's OK. */
X || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
X#if FILOCK
X if (lockrel() != TRUE) {
X (*term.t_putchar)('\n');
X (*term.t_putchar)('\r');
X (*term.t_close)();
X exit(1);
X }
X#endif
X vttidy();
X exit(GOOD);
X }
X mlwrite("");
X return (s);
X}
X
X/*
X * Begin a keyboard macro.
X * Error if not at the top level in keyboard processing. Set up variables and
X * return.
X */
Xctlxlp(f, n)
X{
X if (kbdmip!=NULL || kbdmop!=NULL) {
X mlwrite("Not now");
X return (FALSE);
X }
X mlwrite("[Start macro]");
X kbdmip = &kbdm[0];
X return (TRUE);
X}
X
X/*
X * End keyboard macro. Check for the same limit conditions as the above
X * routine. Set up the variables and return to the caller.
X */
Xctlxrp(f, n)
X{
X if (kbdmip == NULL) {
X mlwrite("Not now");
X return (FALSE);
X }
X mlwrite("[End macro]");
X kbdmip = NULL;
X return (TRUE);
X}
X
X/*
X * Execute a macro.
X * The command argument is the number of times to loop. Quit as soon as a
X * command gets an error. Return TRUE if all ok, else FALSE.
X */
Xctlxe(f, n)
X{
X register int c;
X register int af;
X register int an;
X register int s;
X
X if (kbdmip!=NULL || kbdmop!=NULL) {
X mlwrite("Not now");
X return (FALSE);
X }
X if (n <= 0)
X return (TRUE);
X do {
X kbdmop = &kbdm[0];
X do {
X af = FALSE;
X an = 1;
X if ((c = *kbdmop++) == (CTRL|'U')) {
X af = TRUE;
X an = *kbdmop++;
X c = *kbdmop++;
X }
X s = TRUE;
X } while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
X kbdmop = NULL;
X } while (s==TRUE && --n);
X return (s);
X}
X
X/*
X * Abort.
X * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
X * Sometimes called as a routine, to do general aborting of stuff.
X */
Xctrlg(f, n)
X{
X (*term.t_beep)();
X if (kbdmip != NULL) {
X kbdm[0] = (CTLX|')');
X kbdmip = NULL;
X }
X mlwrite("[Aborted]");
X return (ABORT);
X}
X
X/* tell the user that this command is illegal while we are in
X VIEW (read-only) mode */
X
Xrdonly()
X
X{
X (*term.t_beep)();
X mlwrite("[Key illegal in VIEW mode]");
X return(FALSE);
X}
*-*-END-of-main.c-*-*
exit