[net.micro.6809] MicroEMACS OS-9 Part 2 of 7

jimomura@lsuc.UUCP (Jim Omura) (05/04/86)

==========
os.9/public.domain #72, from jimomura, 8051 chars, Fri Mar 21 21:21:28 1986

----------
TITLE: 'microEMACS' part 3 'uebuffer1.c'
/*
 * Buffer management.
 * Some of the functions are internal,
 * and some are actually attached to user
 * keys. Like everyone else, they set hints
 * for the display system.
 */
#include        <stdio.h>
#include        "ueed.h"

#ifndef OS9
/*
 * Attach a buffer to a window. The
 * values of dot and mark come from the buffer
 * if the use count is 0. Otherwise, they come
 * from some other window.
 */
usebuffer(f, n)
{
        register BUFFER *bp;
        register WINDOW *wp;
        register int    s;
        char            bufn[NBUFN];

        if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE)
                return (s);
        if ((bp=bfind(bufn, TRUE, 0)) == NULL)
                return (FALSE);
        if (--curbp->b_nwnd == 0) {             /* Last use.            */
                curbp->b_dotp  = curwp->w_dotp;
                curbp->b_doto  = curwp->w_doto;
                curbp->b_markp = curwp->w_markp;
                curbp->b_marko = curwp->w_marko;
        }
        curbp = bp;                             /* Switch.              */
        curwp->w_bufp  = bp;
        curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
        curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.         */
        if (bp->b_nwnd++ == 0) {                /* First use.           */
                curwp->w_dotp  = bp->b_dotp;
                curwp->w_doto  = bp->b_doto;
                curwp->w_markp = bp->b_markp;
                curwp->w_marko = bp->b_marko;
                return (TRUE);
        }
        wp = wheadp;                            /* Look for old.        */
        while (wp != NULL) {
                if (wp!=curwp && wp->w_bufp==bp) {
                        curwp->w_dotp  = wp->w_dotp;
                        curwp->w_doto  = wp->w_doto;
                        curwp->w_markp = wp->w_markp;
                        curwp->w_marko = wp->w_marko;
                        break;
                }
                wp = wp->w_wndp;
        }
        return (TRUE);
}

/*
 * Dispose of a buffer, by name.
 * Ask for the name. Look it up (don't get too
 * upset if it isn't there at all!). Get quite upset
 * if the buffer is being displayed. Clear the buffer (ask
 * if the buffer has been changed). Then free the header
 * line and the buffer header. Bound to "C-X K".
 */
killbuffer(f, n)
{
        register BUFFER *bp;
        register BUFFER *bp1;
        register BUFFER *bp2;
        register int    s;
        char            bufn[NBUFN];

        if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE)
                return (s);
        if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown.     */
                return (TRUE);
        if (bp->b_nwnd != 0) {                  /* Error if on screen.  */
                mlwrite("Buffer is being displayed");
                return (FALSE);
        }
        if ((s=bclear(bp)) != TRUE)             /* Blow text away.      */
                return (s);
        free((char *) bp->b_linep);             /* Release header line. */
        bp1 = NULL;                             /* Find the header.     */
        bp2 = bheadp;
        while (bp2 != bp) {
                bp1 = bp2;
                bp2 = bp2->b_bufp;
        }
        bp2 = bp2->b_bufp;                      /* Next one in chain.   */
        if (bp1 == NULL)                        /* Unlink it.           */
                bheadp = bp2;
        else
                bp1->b_bufp = bp2;
        free((char *) bp);                      /* Release buffer block */
        return (TRUE);
}

/*
 * List all of the active
 * buffers. First update the special
 * buffer that holds the list. Next make
 * sure at least 1 window is displaying the
 * buffer list, splitting the screen if this
 * is what it takes. Lastly, repaint all of
 * the windows that are displaying the
 * list. Bound to "C-X C-B".
 */
listbuffers(f, n)
{
        register WINDOW *wp;
        register BUFFER *bp;
        register int    s;

        if ((s=makelist()) != TRUE)
                return (s);
        if (blistp->b_nwnd == 0) {              /* Not on screen yet.   */
                if ((wp=wpopup()) == NULL)
                        return (FALSE);
                bp = wp->w_bufp;
                if (--bp->b_nwnd == 0) {
                        bp->b_dotp  = wp->w_dotp;
                        bp->b_doto  = wp->w_doto;
                        bp->b_markp = wp->w_markp;
                        bp->b_marko = wp->w_marko;
                }
                wp->w_bufp  = blistp;
                ++blistp->b_nwnd;
        }
        wp = wheadp;
        while (wp != NULL) {
                if (wp->w_bufp == blistp) {
                        wp->w_linep = lforw(blistp->b_linep);
                        wp->w_dotp  = lforw(blistp->b_linep);
                        wp->w_doto  = 0;
                        wp->w_markp = NULL;
                        wp->w_marko = 0;
                        wp->w_flag |= WFMODE|WFHARD;
                }
                wp = wp->w_wndp;
        }
        return (TRUE);
}

/*
 * This routine rebuilds the
 * text in the special secret buffer
 * that holds the buffer list. It is called
 * by the list buffers command. Return TRUE
 * if everything works. Return FALSE if there
 * is an error (if there is no memory).
 */
makelist()
{
        register char   *cp1;
        register char   *cp2;
        register int    c;
        register BUFFER *bp;
        register LINE   *lp;
        register int    nbytes;
        register int    s;
        register int    type;
        char            b[6+1];
        char            line[128];

        blistp->b_flag &= ~BFCHG;               /* Don't complain!      */
        if ((s=bclear(blistp)) != TRUE)         /* Blow old text away   */
                return (s);
        strcpy(blistp->b_fname, "");
        if (addline("C   Size Buffer           File") == FALSE
        ||  addline("-   ---- ------           ----") == FALSE)
                return (FALSE);
        bp = bheadp;                            /* For all buffers      */
        while (bp != NULL) {
                if ((bp->b_flag&BFTEMP) != 0) { /* Skip magic ones.     */
                        bp = bp->b_bufp;
                        continue;
                }
                cp1 = &line[0];                 /* Start at left edge   */
                if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed       */
                        *cp1++ = '*';
                else
                        *cp1++ = ' ';
                *cp1++ = ' ';                   /* Gap.                 */
                nbytes = 0;                     /* Count bytes in buf.  */
                lp = lforw(bp->b_linep);
                while (lp != bp->b_linep) {
                        nbytes += llength(lp)+1;
                        lp = lforw(lp);
                }
                itoa(b, 6, nbytes);             /* 6 digit buffer size. */
                cp2 = &b[0];
                while ((c = *cp2++) != 0)
                        *cp1++ = c;
                *cp1++ = ' ';                   /* Gap.                 */
                cp2 = &bp->b_bname[0];          /* Buffer name          */
                while ((c = *cp2++) != 0)
                        *cp1++ = c;
                cp2 = &bp->b_fname[0];          /* File name            */
                if (*cp2 != 0) {
                        while (cp1 < &line[1+1+6+1+NBUFN+1])
                                *cp1++ = ' ';           
                        while ((c = *cp2++) != 0) {
                                if (cp1 < &line[128-1])
                                        *cp1++ = c;
                        }
                }
                *cp1 = 0;                       /* Add to the buffer.   */
                if (addline(line) == FALSE)
                        return (FALSE);
                bp = bp->b_bufp;
        }
        return (TRUE);                          /* All done             */
}
#endif

==========
os.9/public.domain #73, from jimomura, 4861 chars, Fri Mar 21 21:29:33 1986

----------
TITLE: 'microEMACS' part 4 'uebuffer2.c'
/*
 * Buffer management.
 * Some of the functions are internal,
 * and some are actually attached to user
 * keys. Like everyone else, they set hints
 * for the display system.
 */
#include        <stdio.h>
#include        "ueed.h"

#ifndef OS9
itoa(buf, width, num)
register char   buf[];
register int    width;
register int    num;
{
        buf[width] = 0;                         /* End of string.       */
        while (num >= 10) {                     /* Conditional digits.  */
                buf[--width] = (num%10) + '0';
                num /= 10;
        }
        buf[--width] = num + '0';               /* Always 1 digit.      */
        while (width != 0)                      /* Pad with blanks.     */
                buf[--width] = ' ';
}

/*
 * The argument "text" points to
 * a string. Append this line to the
 * buffer list buffer. Handcraft the EOL
 * on the end. Return TRUE if it worked and
 * FALSE if you ran out of room.
 */
addline(text)
char    *text;
{
        register LINE   *lp;
        register int    i;
        register int    ntext;

        ntext = strlen(text);
        if ((lp=lalloc(ntext)) == NULL)
                return (FALSE);
        for (i=0; i<ntext; ++i)
                lputc(lp, i, text[i]);
        blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end    */
        lp->l_bp = blistp->b_linep->l_bp;
        blistp->b_linep->l_bp = lp;
        lp->l_fp = blistp->b_linep;
        if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
                blistp->b_dotp = lp;            /* move it to new line  */
        return (TRUE);
}
#endif

/*
 * Look through the list of
 * buffers. Return TRUE if there
 * are any changed buffers. Buffers
 * that hold magic internal stuff are
 * not considered; who cares if the
 * list of buffer names is hacked.
 * Return FALSE if no buffers
 * have been changed.
 */
anycb()
{
        register BUFFER *bp;

        bp = bheadp;
        while (bp != NULL) {
                if ((bp->b_flag&BFTEMP)==0 && (bp->b_flag&BFCHG)!=0)
                        return (TRUE);
                bp = bp->b_bufp;
        }
        return (FALSE);
}

/*
 * Find a buffer, by name. Return a pointer
 * to the BUFFER structure associated with it. If
 * the named buffer is found, but is a TEMP buffer (like
 * the buffer list) conplain. If the buffer is not found
 * and the "cflag" is TRUE, create it. The "bflag" is
 * the settings for the flags in in buffer.
 */
BUFFER *bfind(bname, cflag, bflag)
register char *bname;
{
        register BUFFER *bp;
        register LINE   *lp;

        bp = bheadp;
        while (bp != NULL) {
                if (strcmp(bname, bp->b_bname) == 0) {
                        if ((bp->b_flag&BFTEMP) != 0) {
                                mlwrite("Cannot select builtin buffer");
                                return (NULL);
                        }
                        return (bp);
                }
                bp = bp->b_bufp;
        }
        if (cflag != FALSE) {
                if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
                        return (NULL);
                if ((lp=lalloc(0)) == NULL) {
                        free((char *) bp);
                        return (NULL);
                }
                bp->b_bufp  = bheadp;
                bheadp = bp;
                bp->b_dotp  = lp;
                bp->b_doto  = 
                bp->b_markp = 
                bp->b_marko = 
                bp->b_nwnd  = 0;
                bp->b_linep = lp;
                bp->b_flag  = bflag;
                strcpy(bp->b_fname, "");
                strcpy(bp->b_bname, bname);
                lp->l_fp = lp;
                lp->l_bp = lp;
        }
        return (bp);
}

/*
 * This routine blows away all of the text
 * in a buffer. If the buffer is marked as changed
 * then we ask if it is ok to blow it away; this is
 * to save the user the grief of losing text. The
 * window chain is nearly always wrong if this gets
 * called; the caller must arrange for the updates
 * that are required. Return TRUE if everything
 * looks good.
 */
bclear(bp)
register BUFFER *bp;
{
        register LINE   *lp;
        register int    s;
        
        if ((bp->b_flag&BFTEMP) == 0            /* Not scratch buffer.  */
        && (bp->b_flag&BFCHG) != 0              /* Something changed    */
        && (s=mlyesno("Discard changes")) != TRUE)
                return (s);
        bp->b_flag  &= ~BFCHG;                  /* Not changed          */
        while ((lp=lforw(bp->b_linep)) != bp->b_linep)
                lfree(lp);
        bp->b_dotp  = bp->b_linep;              /* Fix "."              */
        bp->b_doto  = 
        bp->b_markp =                      /* Invalidate "mark"    */
        bp->b_marko = 0;
        return (TRUE);
}

==========
os.9/public.domain #74, from jimomura, 1953 chars, Fri Mar 21 21:33:48 1986

----------
TITLE: 'microEMACS' part 5 'uecoco.c'
/*
 * The routines in this file provide support for the COCO /TERM  terminal
 * under OS9. The serial I/O services are provided by routines in
 * "termio.c".
 * Adapted 1/5/86 by:
 * Bob Santy
 * 5 Johnson Ave
 * Medford, MA 02155
 * (617) 488-7160
 */

#include        <stdio.h>
#include        "ueed.h"

/* Color Computer /TERM specifications        */
#define NROW    16    /* Screen size.         */
#define NCOL    32    /* Edit if you want to. */
#define BEL     0x07  /* BEL character.       */
#define ESC     0x1B  /* ESC character.       */
#define CURSOR  0x02  /* Commands manual p126 */
#define CEOL    0x04  /* 1.01 Supplement      */
#define CEOS    0x0B  /* 1.01 Supplement      */

extern  int     ttopen();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern  int     ttclose();
extern  int     cocomove();
extern  int     cocoeeol();
extern  int     cocoeeop();
extern  int     cocobeep();
extern  int     cocoopen();

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM    term    = {
        NROW-1,
        NCOL,
        cocoopen,
        ttclose,
        ttgetc,
        ttputc,
        ttflush,
        cocomove,
        cocoeeol,
        cocoeeop,
        cocobeep
};

/*
 * Cursor move command.
 */
cocomove(row, col)
{
        ttputc(CURSOR);
        cocoparm(col);
        cocoparm(row);
}

/*
 * Clear to end of line.
 */
cocoeeol()
{
        ttputc(CEOL);
}

/*
 * Clear to end of screen.
 */
cocoeeop()
{
        ttputc(CEOS);
}

/*
 * Sound the horn (will work in
 * OS9 Rev 2.00
 */
cocobeep()
{
        ttputc(BEL);
        ttflush();
}

/*
 * Cursor position needs 32 added to
 * X and Y coordinates.
 */
cocoparm(n)
register int    n;
{
        ttputc(n + 32);
}

/*
 * Open terminal.  No special codes.
 */
cocoopen()
{
        ttopen();
}

==========
os.9/public.domain #75, from jimomura, 1223 chars, Fri Mar 21 21:36:22 1986

----------
TITLE: 'microEMACS' part 6 'uedisplay.h'
/* #define WFDEBUG 0                       /* Window flag debug. */

typedef struct  VIDEO {
        short   v_flag;                 /* Flags */
        char    v_text[1];              /* Screen data. */
}       VIDEO;

#define VFCHG   0x0001                  /* Changed. */

#ifdef DISPLAY1
int     sgarbf  = TRUE;                 /* TRUE if screen is garbage */
int     mpresf  = FALSE;                /* TRUE if message in last line */
int     vtrow   = 0;                    /* Row location of SW cursor */
int     vtcol   = 0;                    /* Column location of SW cursor */
int     ttrow   = HUGE;                 /* Row location of HW cursor */
int     ttcol   = HUGE;                 /* Column location of HW cursor */
#else
extern int     sgarbf;                 /* TRUE if screen is garbage */
extern int     mpresf;                /* TRUE if message in last line */
extern int     vtrow;                    /* Row location of SW cursor */
extern int     vtcol;                    /* Column location of SW cursor */
extern int     ttrow;                 /* Row location of HW cursor */
extern int     ttcol;                 /* Column location of HW cursor */
#endif

==========
os.9/public.domain #76, from jimomura, 11146 chars, Fri Mar 21 21:57:12 1986

----------
TITLE: 'microEMACS' part 7 'uedisplay1.c'
/*
 * The functions in this file handle redisplay. There are two halves, the
 * ones that update the virtual display screen, and the ones that make the
 * physical display screen the same as the virtual display screen. These
 * functions use hints that are left in the windows by the commands.
 *
 * REVISION HISTORY:
 *
 * ?    Steve Wilhite, 1-Dec-85
 *      - massive cleanup on code.
 */

#include        <stdio.h>
#include        "ueed.h"
#define DISPLAY1 1
#include        "uedisplay.h"

VIDEO   **vscreen;                      /* Virtual screen. */
VIDEO   **pscreen;                      /* Physical screen. */

/*
 * Initialize the data structures used by the display code. The edge vectors
 * used to access the screens are set up. The operating system's terminal I/O
 * channel is set up. All the other things get initialized at compile time.
 * The original window has "WFCHG" set, so that it will get completely
 * redrawn on the first call to "update".
 */
vtinit()
{
    register int i;
    register VIDEO *vp;

    (*term.t_open)();
    vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));

    if (vscreen == NULL)
        exit(1);

    pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));

    if (pscreen == NULL)
        exit(1);

    for (i = 0; i < term.t_nrow; ++i)
        {
        vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);

        if (vp == NULL)
            exit(1);

        vscreen[i] = vp;
        vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);

        if (vp == NULL)
            exit(1);

        pscreen[i] = vp;
        }
}

/*
 * Clean up the virtual terminal system, in anticipation for a return to the
 * operating system. Move down to the last line and clear it out (the next
 * system prompt will be written in the line). Shut down the channel to the
 * terminal.
 */
vttidy()
{
    movecursor(term.t_nrow, 0);
    (*term.t_eeol)();
    (*term.t_close)();
}

/*
 * Set the virtual cursor to the specified row and column on the virtual
 * screen. There is no checking for nonsense values; this might be a good
 * idea during the early stages.
 */
vtmove(row, col)
{
    vtrow = row;
    vtcol = col;
}

/*
 * Write a character to the virtual screen. The virtual row and column are
 * updated. If the line is too long put a "$" in the last column. This routine
 * only puts printing characters into the virtual terminal buffers. Only
 * column overflow is checked.
 */
vtputc(c)
    int c;

{
    register VIDEO      *vp;

    vp = vscreen[vtrow];

    if (vtcol >= term.t_ncol)
        vp->v_text[term.t_ncol - 1] = '$';
    else if (c == '\t')
        {
        do
            {
            vtputc(' ');
            }
        while ((vtcol&0x07) != 0);
        }
    else if (c < 0x20 || c == 0x7F)
        {
        vtputc('^');
        vtputc(c ^ 0x40);
        }
    else
        vp->v_text[vtcol++] = c;                
}

/*
 * Erase from the end of the software cursor to the end of the line on which
 * the software cursor is located.
 */
vteeol()
{
    register VIDEO      *vp;

    vp = vscreen[vtrow];
    while (vtcol < term.t_ncol)
        vp->v_text[vtcol++] = ' ';
}

/*
 * Make sure that the display is right. This is a three part process. First,
 * scan through all of the windows looking for dirty ones. Check the framing,
 * and refresh the screen. Second, make sure that "currow" and "curcol" are
 * correct for the current window. Third, make the virtual and physical
 * screens the same.
 */
update()
{
    register LINE *lp;
    register WINDOW *wp;
    register VIDEO *vp1;
    register VIDEO *vp2;
    register int i;
    register int j;
    register int c;

    wp = wheadp;

    while (wp != NULL)
        {
        /* Look at any window with update flags set on. */

        if (wp->w_flag != 0)
            {
            /* If not force reframe, check the framing. */

            if ((wp->w_flag & WFFORCE) == 0)
                {
                lp = wp->w_linep;

                for (i = 0; i < wp->w_ntrows; ++i)
                    {
                    if (lp == wp->w_dotp)
                        goto out;

                    if (lp == wp->w_bufp->b_linep)
                        break;

                    lp = lforw(lp);
                    }
                }

            /* Not acceptable, better compute a new value for the line at the
             * top of the window. Then set the "WFHARD" flag to force full
             * redraw.
             */
            i = wp->w_force;

            if (i > 0)
                {
                --i;

                if (i >= wp->w_ntrows)
                  i = wp->w_ntrows-1;
                }
            else if (i < 0)
                {
                i += wp->w_ntrows;

                if (i < 0)
                    i = 0;
                }
            else
                i = wp->w_ntrows/2;

            lp = wp->w_dotp;

            while (i != 0 && lback(lp) != wp->w_bufp->b_linep)
                {
                --i;
                lp = lback(lp);
                }

            wp->w_linep = lp;
            wp->w_flag |= WFHARD;       /* Force full. */

out:
            /* Try to use reduced update. Mode line update has its own special
             * flag. The fast update is used if the only thing to do is within
             * the line editing.
             */
            lp = wp->w_linep;
            i = wp->w_toprow;

            if ((wp->w_flag & ~WFMODE) == WFEDIT)
                {
                while (lp != wp->w_dotp)
                    {
                    ++i;
                    lp = lforw(lp);
                    }

                vscreen[i]->v_flag |= VFCHG;
                vtmove(i, 0);

                for (j = 0; j < llength(lp); ++j)
                    vtputc(lgetc(lp, j));

                vteeol();
                }
             else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0)
                {
                while (i < wp->w_toprow+wp->w_ntrows)
                    {
                    vscreen[i]->v_flag |= VFCHG;
                    vtmove(i, 0);

                    if (lp != wp->w_bufp->b_linep)
                        {
                        for (j = 0; j < llength(lp); ++j)
                            vtputc(lgetc(lp, j));

                        lp = lforw(lp);
                        }

                    vteeol();
                    ++i;
                    }
                }
#ifndef WFDEBUG
            if ((wp->w_flag&WFMODE) != 0)
                modeline(wp);

            wp->w_flag  = 
            wp->w_force = 0;
#endif
            }           
#ifdef WFDEBUG
        modeline(wp);
        wp->w_flag =  
        wp->w_force = 0;
#endif
        wp = wp->w_wndp;
        }

    /* Always recompute the row and column number of the hardware cursor. This
     * is the only update for simple moves.
     */
    lp = curwp->w_linep;
    currow = curwp->w_toprow;

    while (lp != curwp->w_dotp)
        {
        ++currow;
        lp = lforw(lp);
        }

    curcol = 
    i = 0;

    while (i < curwp->w_doto)
        {
        c = lgetc(lp, i++);

        if (c == '\t')
            curcol |= 0x07;
        else if (c < 0x20 || c == 0x7F)
            ++curcol;

        ++curcol;
        }

    if (curcol >= term.t_ncol)          /* Long line. */
        curcol = term.t_ncol-1;

    /* Special hacking if the screen is garbage. Clear the hardware screen,
     * and update your copy to agree with it. Set all the virtual screen
     * change bits, to force a full update.
     */
    if (sgarbf != FALSE)
        {
        for (i = 0; i < term.t_nrow; ++i)
            {
            vscreen[i]->v_flag |= VFCHG;
            vp1 = pscreen[i];
            for (j = 0; j < term.t_ncol; ++j)
                vp1->v_text[j] = ' ';
            }

        movecursor(0, 0);               /* Erase the screen. */
        (*term.t_eeop)();
        sgarbf = FALSE;                 /* Erase-page clears */
        mpresf = FALSE;                 /* the message area. */
        }

    /* Make sure that the physical and virtual displays agree. Unlike before,
     * the "updateline" code is only called with a line that has been updated
     * for sure.
     */
    for (i = 0; i < term.t_nrow; ++i)
        {
        vp1 = vscreen[i];

        if ((vp1->v_flag&VFCHG) != 0)
            {
            vp1->v_flag &= ~VFCHG;
            vp2 = pscreen[i];
            updateline(i, &vp1->v_text[0], &vp2->v_text[0]);
            }
        }

    /* Finally, update the hardware cursor and flush out buffers. */

    movecursor(currow, curcol);
    (*term.t_flush)();
}

/*
 * Update a single line. This does not know how to use insert or delete
 * character sequences; we are using VT52 functionality. Update the physical
 * row and column variables. It does try an exploit erase to end of line. The
 * RAINBOW version of this routine uses fast video.
 */
updateline(row, vline, pline)
    char vline[];
    char pline[];
{
#ifdef RAINBOW
    register char *cp1;
    register char *cp2;
    register int nch;

    cp1 = &vline[0];                    /* Use fast video. */
    cp2 = &pline[0];
    putline(row+1, 1, cp1);
    nch = term.t_ncol;

    do
        {
        *cp2 = *cp1;
        ++cp2;
        ++cp1;
        }
    while (--nch);
#else
    register char *cp1;
    register char *cp2;
    register char *cp3;
    register char *cp4;
    register char *cp5;
    register int nbflag;

    cp1 = &vline[0];                    /* Compute left match.  */
    cp2 = &pline[0];

    while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0])
        {
        ++cp1;
        ++cp2;
        }

    /* This can still happen, even though we only call this routine on changed
     * lines. A hard update is always done when a line splits, a massive
     * change is done, or a buffer is displayed twice. This optimizes out most
     * of the excess updating. A lot of computes are used, but these tend to
     * be hard operations that do a lot of update, so I don't really care.
     */
    if (cp1 == &vline[term.t_ncol])             /* All equal. */
        return;

    nbflag = FALSE;
    cp3 = &vline[term.t_ncol];          /* Compute right match. */
    cp4 = &pline[term.t_ncol];

    while (cp3[-1] == cp4[-1])
        {
        --cp3;
        --cp4;
        if (cp3[0] != ' ')              /* Note if any nonblank */
            nbflag = TRUE;              /* in right match. */
        }

    cp5 = cp3;

    if (nbflag == FALSE)                /* Erase to EOL ? */
        {
        while (cp5!=cp1 && cp5[-1]==' ')
            --cp5;

        if (cp3-cp5 <= 3)               /* Use only if erase is */
            cp5 = cp3;                  /* fewer characters. */
        }

    movecursor(row, cp1-&vline[0]);     /* Go to start of line. */

    while (cp1 != cp5)                  /* Ordinary. */
        {
        (*term.t_putchar)(*cp1);
        ++ttcol;
        *cp2++ = *cp1++;
        }

    if (cp5 != cp3)                     /* Erase. */
        {
        (*term.t_eeol)();
        while (cp1 != cp3)
            *cp2++ = *cp1++;
        }
#endif
}

==========
os.9/public.domain #77, from jimomura, 7492 chars, Fri Mar 21 22:10:12 1986

----------
TITLE: 'microEMACS' part 8 'uedisplay2.c'
/*
 * The functions in this file handle redisplay. There are two halves, the
 * ones that update the virtual display screen, and the ones that make the
 * physical display screen the same as the virtual display screen. These
 * functions use hints that are left in the windows by the commands.
 *
 * REVISION HISTORY:
 *
 * ?    Steve Wilhite, 1-Dec-85
 *      - massive cleanup on code.
 */

#include        <stdio.h>
#include        "ueed.h"
#include        "uedisplay.h"

extern VIDEO   **vscreen;                      /* Virtual screen. */

/*
 * Redisplay the mode line for the window pointed to by the "wp". This is the
 * only routine that has any idea of how the modeline is formatted. You can
 * change the modeline format by hacking at this routine. Called by "update"
 * any time there is a dirty window.
 */
modeline(wp)
    WINDOW *wp;
{
    register char *cp;
    register int c;
    register int n;
    register BUFFER *bp;

    n = wp->w_toprow+wp->w_ntrows;              /* Location. */
    vscreen[n]->v_flag |= VFCHG;                /* Redraw next time. */
    vtmove(n, 0);                               /* Seek to right line. */
    vtputc('-');
    bp = wp->w_bufp;

    if ((bp->b_flag&BFCHG) != 0)                /* "*" if changed. */
        vtputc('*');
    else
        vtputc('-');

    n  = 2;
    cp = " MicroEMACS -";                     /* Buffer name. */

    while ((c = *cp++) != 0)
        {
        vtputc(c);
        ++n;
        }

#ifndef OS9
    cp = &bp->b_bname[0];

    while ((c = *cp++) != 0)
        {
        vtputc(c);
        ++n;
        }

    vtputc(' ');
    ++n;
#endif

    if (bp->b_fname[0] != 0)            /* File name. */
        {
        cp = " File: ";

        while ((c = *cp++) != 0)
            {
            vtputc(c);
            ++n;
            }

        cp = &bp->b_fname[0];

        while ((c = *cp++) != 0)
            {
            vtputc(c);
            ++n;
            }

        vtputc(' ');
        ++n;
        }

#ifdef WFDEBUG
    vtputc('-');
    vtputc((wp->w_flag&WFMODE)!=0  ? 'M' : '-');
    vtputc((wp->w_flag&WFHARD)!=0  ? 'H' : '-');
    vtputc((wp->w_flag&WFEDIT)!=0  ? 'E' : '-');
    vtputc((wp->w_flag&WFMOVE)!=0  ? 'V' : '-');
    vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : '-');
    n += 6;
#endif

    while (n < term.t_ncol)             /* Pad to full width. */
        {
        vtputc('-');
        ++n;
        }
}

/*
 * Send a command to the terminal to move the hardware cursor to row "row"
 * and column "col". The row and column arguments are origin 0. Optimize out
 * random calls. Update "ttrow" and "ttcol".
 */
movecursor(row, col)
    {
    if (row!=ttrow || col!=ttcol)
        {
        ttrow = row;
        ttcol = col;
        (*term.t_move)(row, col);
        }
    }

/*
 * Erase the message line. This is a special routine because the message line
 * is not considered to be part of the virtual screen. It always works
 * immediately; the terminal buffer is flushed via a call to the flusher.
 */
mlerase()
    {
    movecursor(term.t_nrow, 0);
    (*term.t_eeol)();
    (*term.t_flush)();
    mpresf = FALSE;
    }

/*
 * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
 * ABORT. The ABORT status is returned if the user bumps out of the question
 * with a ^G. Used any time a confirmation is required.
 */
mlyesno(prompt)
    char *prompt;
    {
    register int s;
    char buf[64];

    for (;;)
        {
        strcpy(buf, prompt);
        strcat(buf, " [y/n]? ");
        s = mlreply(buf, buf, sizeof(buf));

        if (s == ABORT)
            return (ABORT);

        if (s != FALSE)
            {
            if (buf[0]=='y' || buf[0]=='Y')
                return (TRUE);

            if (buf[0]=='n' || buf[0]=='N')
                return (FALSE);
            }
        }
    }

/*
 * Write a prompt into the message line, then read back a response. Keep
 * track of the physical position of the cursor. If we are in a keyboard
 * macro throw the prompt away, and return the remembered response. This
 * lets macros run at full speed. The reply is always terminated by a carriage
 * return. Handle erase, kill, and abort keys.
 */
mlreply(prompt, buf, nbuf)
    char *prompt;
    char *buf;
    {
    register int cpos;
    register int i;
    register int c;

    cpos = 0;

    if (kbdmop != NULL)
        {
        while ((c = *kbdmop++) != '\0')
            buf[cpos++] = c;

        buf[cpos] = 0;

        if (buf[0] == 0)
            return (FALSE);

        return (TRUE);
        }

    mlwrite(prompt);

    for (;;)
        {
        c = (*term.t_getchar)();

        switch (c)
            {
            case 0x0D:                  /* Return, end of line */
                buf[cpos++] = 0;

                if (kbdmip != NULL)
                    {
                    if (kbdmip+cpos > &kbdm[NKBDM-3])
                        {
                        ctrlg(FALSE, 0);
                        (*term.t_flush)();
                        return (ABORT);
                        }

                    for (i=0; i<cpos; ++i)
                        *kbdmip++ = buf[i];
                    }

                (*term.t_putchar)('\r');
                ttcol = 0;
                (*term.t_flush)();

                if (buf[0] == 0)
                    return (FALSE);

                return (TRUE);

            case 0x07:                  /* Bell, abort */
                (*term.t_putchar)('^');
                (*term.t_putchar)('G');
                ttcol += 2;
                ctrlg(FALSE, 0);
                (*term.t_flush)();
                return (ABORT);

            case 0x7F:                  /* Rubout, erase */
            case 0x08:                  /* Backspace, erase */
                if (cpos != 0)
                    {
                    (*term.t_putchar)('\b');
                    (*term.t_putchar)(' ');
                    (*term.t_putchar)('\b');
                    --ttcol;

                    if (buf[--cpos] < 0x20)
                        {
                        (*term.t_putchar)('\b');
                        (*term.t_putchar)(' ');
                        (*term.t_putchar)('\b');
                        --ttcol;
                        }

                    (*term.t_flush)();
                    }

                break;

            case 0x15:                  /* C-U, kill */
                while (cpos != 0)
                    {
                    (*term.t_putchar)('\b');
                    (*term.t_putchar)(' ');
                    (*term.t_putchar)('\b');
                    --ttcol;

                    if (buf[--cpos] < 0x20)
                        {
                        (*term.t_putchar)('\b');
                        (*term.t_putchar)(' ');
                        (*term.t_putchar)('\b');
                        --ttcol;
                        }
                    }

                (*term.t_flush)();
                break;

            default:
                if (cpos < nbuf-1)
                    {
                    buf[cpos++] = c;

                    if (c < ' ')
                        {
                        (*term.t_putchar)('^');
                        ++ttcol;
                        c ^= 0x40;
                        }

                    (*term.t_putchar)(c);
                    ++ttcol;
                    (*term.t_flush)();
                    }
            }
        }
    }


==========
os.9/public.domain #78, from jimomura, 3718 chars, Fri Mar 21 22:17:22 1986

----------
TITLE: 'microEMACS' part 9 'uedisplay3.c'
/*
 * The functions in this file handle redisplay. There are two halves, the
 * ones that update the virtual display screen, and the ones that make the
 * physical display screen the same as the virtual display screen. These
 * functions use hints that are left in the windows by the commands.
 *
 * REVISION HISTORY:
 *
 * ?    Steve Wilhite, 1-Dec-85
 *      - massive cleanup on code.
 */

#include        <stdio.h>
#include        "ueed.h"
#include        "uedisplay.h"

/*
 * Write a message into the message line. Keep track of the physical cursor
 * position. A small class of printf like format items is handled. 
 * This routine is probably one of the lease portable.
 * Assumes all arguments (with the possible exception of the first) are passed
 * in the order expected on a downward growing stack without addtional
 * padding; this assumption is made by the "++" in the 
 * argument scan loop.  It works for the two or less argument case
 * on OSK despite the fact the first two arguments are passed in registers.
 * Set the "message line" flag TRUE.
 */
mlwrite(fmt, arg)
    char *fmt;
    {
    register int c;
    register char *ap;

    movecursor(term.t_nrow, 0);
    ap = (char *) &arg;
    while ((c = *fmt++) != 0) {
        if (c != '%') {
            (*term.t_putchar)(c);
            ++ttcol;
            }
        else
            {
            c = *fmt++;
            switch (c) {
                case 'd':
                    mlputi(*(int *)ap, 10);
                    ap += sizeof(int);
                    break;

                case 'o':
                    mlputi(*(int *)ap,  8);
                    ap += sizeof(int);
                    break;

                case 'x':
                    mlputi(*(int *)ap, 16);
                    ap += sizeof(int);
                    break;

                case 'D':  /* this is %ld on many printf impleminations */
                    mlputli(*(long *)ap, 10);
                    ap += sizeof(long);
                    break;

                case 's':
                    mlputs(*(char **)ap);
                    ap += sizeof(char *);
                    break;

                default:
                    (*term.t_putchar)(c);
                    ++ttcol;
                }
            }
        }
    (*term.t_eeol)();
    (*term.t_flush)();
    mpresf = TRUE;
    }

/*
 * Write out a string. Update the physical cursor position. This assumes that
 * the characters in the string all have width "1"; if this is not the case
 * things will get screwed up a little.
 */
mlputs(s)
    char *s;
    {
    register int c;

    while ((c = *s++) != 0)
        {
        (*term.t_putchar)(c);
        ++ttcol;
        }
    }

/*
 * Write out an integer, in the specified radix. Update the physical cursor
 * position. This will not handle any negative numbers; maybe it should.
 */
mlputi(i, r)
    {
    register int q;
    static char hexdigits[] = "0123456789ABCDEF";

    if (i < 0)
        {
        i = -i;
        (*term.t_putchar)('-');
        }

    q = i/r;

    if (q != 0)
        mlputi(q, r);

    (*term.t_putchar)(hexdigits[i%r]);
    ++ttcol;
    }

/*
 * do the same except as a long integer.
 */
mlputli(l, r)
    long l;
    {
    register long q;

    if (l < 0)
        {
        l = -l;
        (*term.t_putchar)('-');
        }

    q = l/r;

    if (q != 0)
        mlputli(q, r);

    (*term.t_putchar)((int)(l%r)+'0');
    ++ttcol;
    }

#ifdef RAINBOW

putline(row, col, buf)
    int row, col;
    char buf[];
    {
    int n;

    n = strlen(buf);
    if (col + n - 1 > term.t_ncol)
        n = term.t_ncol - col + 1;
    Put_Data(row, col, n, buf);
    }
#endif


==========
os.9/public.domain #79, from jimomura, 10892 chars, Fri Mar 21 22:32:08 1986

----------
TITLE: 'microEMACS' part 10 'ueed.h'
/*
 * This file is the general header file for all parts of the MicroEMACS
 * display editor. It contains definitions used by everyone, and it contains
 * the stuff you have to edit to create a version of the editor for a specific
 * operating system and terminal.
 */

/* #define AMIGA   1                       /* AmigaDOS, Lattice            */
/* #define ST520   0                       /* ST520, TOS                   */
/* #define MWC86   0
/* #define V7      0                       /* V7 UN*X or Coherent          */
/* #define VMS     0                       /* VAX/VMS                      */
/* #define CPM     0                       /* CP/M-86                      */
/* #define OS9     1                       /* os9/6809 level 1 (coco)      */
/* #define OSK     1                       /* os9/68000 predefined         */
/* #define MSDOS   0                       /* MS-DOS predefined            */

/* #define ANSI    1                       /* ANSI terminal (Vt100)        */
#define VT52    1                       /* VT52 terminal (Zenith).      */
/* #define VT100   0                       /* Handle VT100 style keypad.   */
/* #define LK201   0                       /* Handle LK201 style keypad.   */
/* #define RAINBOW 0                       /* Use Rainbow fast video.      */
/* #define TERMCAP 0                       /* Use TERMCAP                  */

#define CVMVAS  1                       /* C-V, M-V arg. in screens.    */

#define NFILEN  80                      /* # of bytes, file name        */
#define NBUFN   16                      /* # of bytes, buffer name      */
#define NLINE   256                     /* # of bytes, line             */
#define NKBDM   256                     /* # of strokes, keyboard macro */
#define NPAT    80                      /* # of bytes, pattern          */
#define HUGE    1000                    /* Huge number                  */

#define AGRAVE  0x60                    /* M- prefix,   Grave (LK201)   */
#define METACH  0x1B                    /* M- prefix,   Control-[, ESC  */
#define CTMECH  0x1C                    /* C-M- prefix, Control-\       */
#define EXITCH  0x1D                    /* Exit level,  Control-]       */
#define CTRLCH  0x1E                    /* C- prefix,   Control-^       */
#define HELPCH  0x1F                    /* Help key,    Control-_       */

#define CTRL    0x0100                  /* Control flag, or'ed in       */
#define META    0x0200                  /* Meta flag, or'ed in          */
#define CTLX    0x0400                  /* ^X flag, or'ed in            */

#define FALSE   0                       /* False, no, bad, etc.         */
#define TRUE    1                       /* True, yes, good, etc.        */
#define ABORT   2                       /* Death, ^G, abort, etc.       */

#define FIOSUC  0                       /* File I/O, success.           */
#define FIOFNF  1                       /* File I/O, file not found.    */
#define FIOEOF  2                       /* File I/O, end of file.       */
#define FIOERR  3                       /* File I/O, error.             */

#define CFCPCN  0x0001                  /* Last command was C-P, C-N    */
#define CFKILL  0x0002                  /* Last command was a kill      */

/*
 * There is a window structure allocated for every active display window. The
 * windows are kept in a big list, in top to bottom screen order, with the
 * listhead at "wheadp". Each window contains its own values of dot and mark.
 * The flag field contains some bits that are set by commands to guide
 * redisplay; although this is a bit of a compromise in terms of decoupling,
 * the full blown redisplay is just too expensive to run for every input
 * character. 
 */
typedef struct  WINDOW {
        struct  WINDOW *w_wndp;         /* Next window                  */
        struct  BUFFER *w_bufp;         /* Buffer displayed in window   */
        struct  LINE *w_linep;          /* Top line in the window       */
        struct  LINE *w_dotp;           /* Line containing "."          */
        short   w_doto;                 /* Byte offset for "."          */
        struct  LINE *w_markp;          /* Line containing "mark"       */
        short   w_marko;                /* Byte offset for "mark"       */
        char    w_toprow;               /* Origin 0 top row of window   */
        char    w_ntrows;               /* # of rows of text in window  */
        char    w_force;                /* If NZ, forcing row.          */
        char    w_flag;                 /* Flags.                       */
}       WINDOW;

#define WFFORCE 0x01                    /* Window needs forced reframe  */
#define WFMOVE  0x02                    /* Movement from line to line   */
#define WFEDIT  0x04                    /* Editing within a line        */
#define WFHARD  0x08                    /* Better to a full display     */
#define WFMODE  0x10                    /* Update mode line.            */

/*
 * Text is kept in buffers. A buffer header, described below, exists for every
 * buffer in the system. The buffers are kept in a big list, so that commands
 * that search for a buffer by name can find the buffer header. There is a
 * safe store for the dot and mark in the header, but this is only valid if
 * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
 * the buffer is kept in a circularly linked list of lines, with a pointer to
 * the header line in "b_linep".
 */
typedef struct  BUFFER {
        struct  BUFFER *b_bufp;         /* Link to next BUFFER          */
        struct  LINE *b_dotp;           /* Link to "." LINE structure   */
        short   b_doto;                 /* Offset of "." in above LINE  */
        struct  LINE *b_markp;          /* The same as the above two,   */
        short   b_marko;                /* but for the "mark"           */
        struct  LINE *b_linep;          /* Link to the header LINE      */
        char    b_nwnd;                 /* Count of windows on buffer   */
        char    b_flag;                 /* Flags                        */
        char    b_fname[NFILEN];        /* File name                    */
        char    b_bname[NBUFN];         /* Buffer name                  */
}       BUFFER;

#define BFTEMP  0x01                    /* Internal temporary buffer    */
#define BFCHG   0x02                    /* Changed since last write     */

/*
 * The starting position of a region, and the size of the region in
 * characters, is kept in a region structure.  Used by the region commands.
 */
typedef struct  {
        struct  LINE *r_linep;          /* Origin LINE address.         */
        short   r_offset;               /* Origin LINE offset.          */
        short   r_size;                 /* Length in characters.        */
}       REGION;

/*
 * All text is kept in circularly linked lists of "LINE" structures. These
 * begin at the header line (which is the blank line beyond the end of the
 * buffer). This line is pointed to by the "BUFFER". Each line contains a the
 * number of bytes in the line (the "used" size), the size of the text array,
 * and the text. The end of line is not stored as a byte; it's implied. Future
 * additions will include update hints, and a list of marks into the line.
 */
typedef struct  LINE {
        struct  LINE *l_fp;             /* Link to the next line        */
        struct  LINE *l_bp;             /* Link to the previous line    */
        short   l_size;                 /* Allocated size               */
        short   l_used;                 /* Used size                    */
        char    l_text[1];              /* A bunch of characters.       */
}       LINE;

#define lforw(lp)       ((lp)->l_fp)
#define lback(lp)       ((lp)->l_bp)
#define lgetc(lp, n)    ((lp)->l_text[(n)]&0xFF)
#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
#define llength(lp)     ((lp)->l_used)

/*
 * The editor communicates with the display using a high level interface. A
 * "TERM" structure holds useful variables, and indirect pointers to routines
 * that do useful operations. The low level get and put routines are here too.
 * This lets a terminal, in addition to having non standard commands, have
 * funny get and put character code too. The calls might get changed to
 * "termp->t_field" style in the future, to make it possible to run more than
 * one terminal type.
 */  
typedef struct  {
        short   t_nrow;                 /* Number of rows.              */
        short   t_ncol;                 /* Number of columns.           */
        int     (*t_open)();            /* Open terminal at the start.  */
        int     (*t_close)();           /* Close terminal at end.       */
        int     (*t_getchar)();         /* Get character from keyboard. */
        int     (*t_putchar)();         /* Put character to display.    */
        int     (*t_flush)();           /* Flush output buffers.        */
        int     (*t_move)();            /* Move the cursor, origin 0.   */
        int     (*t_eeol)();            /* Erase to end of line.        */
        int     (*t_eeop)();            /* Erase to end of page.        */
        int     (*t_beep)();            /* Beep.                        */
}       TERM;

extern  int     fillcol;                /* Fill column                  */
extern  int     currow;                 /* Cursor row                   */
extern  int     curcol;                 /* Cursor column                */
extern  int     thisflag;               /* Flags, this command          */
extern  int     lastflag;               /* Flags, last command          */
extern  int     curgoal;                /* Goal for C-P, C-N            */
extern  int     mpresf;                 /* Stuff in message line        */
extern  int     sgarbf;                 /* State of screen unknown      */
extern  WINDOW  *curwp;                 /* Current window               */
extern  BUFFER  *curbp;                 /* Current buffer               */
extern  WINDOW  *wheadp;                /* Head of list of windows      */
extern  BUFFER  *bheadp;                /* Head of list of buffers      */
extern  BUFFER  *blistp;                /* Buffer for C-X C-B           */
extern  short   kbdm[];                 /* Holds kayboard macro data    */
extern  short   *kbdmip;                /* Input pointer for above      */
extern  short   *kbdmop;                /* Output pointer for above     */
extern  char    pat[];                  /* Search pattern               */
extern  TERM    term;                   /*(Terminal information.        */

extern  BUFFER  *bfind();               /* Lookup a buffer by name      */
extern  WINDOW  *wpopup();              /* Pop up window creation       */
extern  LINE    *lalloc();              /* Allocate a line              */


==========
os.9/public.domain #80, from jimomura, 9175 chars, Sat Mar 22 18:46:49 1986

----------
TITLE: 'microEMACS' part 11 'uefile1.c'
/*
 * The routines in this file

 * handle the reading and writing of
 * disk files. All of details about the
 * reading and writing of the disk are
 * in "fileio.c".
 */
#include        <stdio.h>
#include        "ueed.h"

/*
 * Read a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "read a file into the current buffer" code.
 * Bound to "C-X C-R".
 */
fileread(f, n)
{
        register int    s;
        char            fname[NFILEN];

        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
                return (s);
        return (readin(fname));
}

#ifndef OS9
/*
 * Select a file for editing.
 * Look around to see if you can find the
 * fine in another buffer; if you can find it
 * just switch to the buffer. If you cannot find
 * the file, create a new buffer, read in the
 * text, and switch to the new buffer.
 * Bound to C-X C-V.
 */
filevisit(f, n)
{
        register BUFFER *bp;
        register WINDOW *wp;
        register LINE   *lp;
        register int    i;
        register int    s;
        char            bname[NBUFN];
        char            fname[NFILEN];

        if ((s=mlreply("Visit file: ", fname, NFILEN)) != TRUE)
                return (s);
        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
                if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) {
                        if (--curbp->b_nwnd == 0) {
                                curbp->b_dotp  = curwp->w_dotp;
                                curbp->b_doto  = curwp->w_doto;
                                curbp->b_markp = curwp->w_markp;
                                curbp->b_marko = curwp->w_marko;
                        }
                        curbp = bp;
                        curwp->w_bufp  = bp;
                        if (bp->b_nwnd++ == 0) {
                                curwp->w_dotp  = bp->b_dotp;
                                curwp->w_doto  = bp->b_doto;
                                curwp->w_markp = bp->b_markp;
                                curwp->w_marko = bp->b_marko;
                        } else {
                                wp = wheadp;
                                while (wp != NULL) {
                                        if (wp!=curwp && wp->w_bufp==bp) {
                                                curwp->w_dotp  = wp->w_dotp;
                                                curwp->w_doto  = wp->w_doto;
                                                curwp->w_markp = wp->w_markp;
                                                curwp->w_marko = wp->w_marko;
                                                break;
                                        }
                                        wp = wp->w_wndp;
                                }
                        }
                        lp = curwp->w_dotp;
                        i = curwp->w_ntrows/2;
                        while (i-- && lback(lp)!=curbp->b_linep)
                                lp = lback(lp);
                        curwp->w_linep = lp;
                        curwp->w_flag |= WFMODE|WFHARD;
                        mlwrite("[Old buffer]");
                        return (TRUE);
                }
        }
        makename(bname, fname);                 /* New buffer name.     */
        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
                s = mlreply("Buffer name: ", bname, NBUFN);
                if (s == ABORT)                 /* ^G to just quit      */
                        return (s);
                if (s == FALSE) {               /* CR to clobber it     */
                        makename(bname, fname);
                        break;
                }
        }
        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
                mlwrite("Cannot create buffer");
                return (FALSE);
        }
        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
                curbp->b_dotp = curwp->w_dotp;
                curbp->b_doto = curwp->w_doto;
                curbp->b_markp = curwp->w_markp;
                curbp->b_marko = curwp->w_marko;
        }
        curbp = bp;                             /* Switch to it.        */
        curwp->w_bufp = bp;
        curbp->b_nwnd++;
        return (readin(fname));                 /* Read it in.          */
}
#endif

/*
 * Read file "fname" into the current
 * buffer, blowing away any text found there. Called
 * by both the read and visit commands. Return the final
 * status of the read. Also called by the mainline,
 * to read in a file specified on the command line as
 * an argument.
 */
readin(fname)
char    fname[];
{
        register LINE   *lp1;
        register LINE   *lp2;
        register int    i;
        register WINDOW *wp;
        register BUFFER *bp;
        register int    s;
        register int    nbytes;
        register int    nline;
        char            line[NLINE];

        bp = curbp;                             /* Cheap.               */
        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
                return (s);
        bp->b_flag &= ~(BFTEMP|BFCHG);
        strcpy(bp->b_fname, fname);
        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
                goto out;
        if (s == FIOFNF) {                      /* File not found.      */
                mlwrite("[New file]");
                goto out;
        }
        mlwrite("[Reading file]");
        nline = 0;
        while ((s=ffgetline(line, NLINE)) == FIOSUC) {
                nbytes = strlen(line);
                if ((lp1=lalloc(nbytes)) == NULL) {
                        s = FIOERR;             /* Keep message on the  */
                        break;                  /* display.             */
                }
                lp2 = lback(curbp->b_linep);
                lp2->l_fp = lp1;
                lp1->l_fp = curbp->b_linep;
                lp1->l_bp = lp2;
                curbp->b_linep->l_bp = lp1;
                for (i=0; i<nbytes; ++i)
                        lputc(lp1, i, line[i]);
                ++nline;
        }
        ffclose();                              /* Ignore errors.       */
        if (s == FIOEOF) {                      /* Don't zap message!   */
                if (nline == 1)
                        mlwrite("[Read 1 line]");
                else
                        mlwrite("[Read %d lines]", nline);
        }
out:
        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
                if (wp->w_bufp == curbp) {
                        wp->w_linep = lforw(curbp->b_linep);
                        wp->w_dotp  = lforw(curbp->b_linep);
                        wp->w_doto  = 
                        wp->w_markp = 
                        wp->w_marko = 0;
                        wp->w_flag |= WFMODE|WFHARD;
                }
        }
        if (s == FIOERR)                        /* False if error.      */
                return (FALSE);
        return (TRUE);
}

/*
 * Take a file name, and from it
 * fabricate a buffer name. This routine knows
 * about the syntax of file names on the target system.
 * I suppose that this information could be put in
 * a better place than a line of code.
 */
makename(bname, fname)
char    bname[];
char    fname[];
{
        register char   *cp1;
        register char   *cp2;

        cp1 = &fname[0];
        while (*cp1 != 0)
                ++cp1;

#ifdef AMIGA
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
                --cp1;
#endif
#ifdef VMS
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
                --cp1;
#endif
#ifdef CPM
        while (cp1!=&fname[0] && cp1[-1]!=':')
                --cp1;
#endif
#ifdef MSDOS
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
                --cp1;
#endif
#ifdef V7
        while (cp1!=&fname[0] && cp1[-1]!='/')
                --cp1;
#endif
#ifdef OSK
        while (cp1!=&fname[0] && cp1[-1]!='/')
                --cp1;
#endif
        cp2 = &bname[0];
        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
                *cp2++ = *cp1++;
        *cp2 = 0;
}

/*
 * Ask for a file name, and write the
 * contents of the current buffer to that file.
 * Update the remembered file name and clear the
 * buffer changed flag. This handling of file names
 * is different from the earlier versions, and
 * is more compatable with Gosling EMACS than
 * with ITS EMACS. Bound to "C-X C-W".
 */
filewrite(f, n)
{
        register WINDOW *wp;
        register int    s;
        char            fname[NFILEN];

        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
                return (s);
        if ((s=writeout(fname)) == TRUE) {
                strcpy(curbp->b_fname, fname);
                curbp->b_flag &= ~BFCHG;
                wp = wheadp;                    /* Update mode lines.   */
                while (wp != NULL) {
                        if (wp->w_bufp == curbp)
                                wp->w_flag |= WFMODE;
                        wp = wp->w_wndp;
                }
        }
        return (s);
}


-- 
James Omura, Barrister & Solicitor, Toronto
ihnp4!utzoo!lsuc!jimomura
Byte Information eXchange: jimomura
(416) 652-3880