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