Dobbs cpm screen editor (2 of 3)

Keith Brown. kbrown at west44.UUCP
Sat Jul 7 03:55:43 AEST 1984



<nobody eats my lines and lives>

Here are the sources to the Dr. Dobbs. 'red' editor as promised a few
weeks ago. The sources as given here are untouched and virginal as I
thought thats the way you would prefer them. I do have a few hacked
versions of the thing and I have put a few comments in the sources
to point out what I have done to this relatively untouched version.
My fingerprint is KEDB so to get a quick(ish) summary, just do an
	fgrep KEDB ed*.[ch]
I am not, nor do I intend to, document this thing. If you want to
know what it does then either look at the code (it's pretty self
explanatory) or obtain a copy of Dr. Dobbs journal (No 63 1982).
I no longer have this journal (I typed this in some time ago!!)
and unfortunately do not have an unhacked ed1.h. I can't remember
the origonal special function key codes so I've just included
a few I have made up. Feel free to change them yourselves, the originals
weren't particularly logical anyway!!
Anyway, hope you have as much fun hacking these as I didn't.
		Cheers,
			Keith B.
P.S.
	To unbundle, make and enter a new directory, copy the news
files into it, remove the news headers and this blurb from the tops
and run each file through 'sh' (ie. type 'sh fname' for each shar).
If u r not using UNIX then u will have 2 unbundle the files by hand.

---------------- CUT HERE ------------------

echo 'unbundling ed[456].c'
cat >ed4.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/*
 * Screen editor:  window module.
 *
 * source: ed4.c
 * version: august 20 1981.
 */

/* data global to this module */

char editbuf[MAXLEN] ;		/* the edit buffer */
int editp ;			/* cursor: buffer index */
int editpmax ;			/* length of buffer */
int edcflag ;			/* buffer change flag */

/* abort any changes made to current line */

edabt()
{
	/* get unchanged line and reset cursor */
	edgetln() ;
	edredraw() ;
	edbegin() ;
	edcflag=NO ;
}

/* put cursor at beginning of current line */

edbegin()
{
	editp=0 ;
	outxy(0,outgety()) ;
}

/*
 * change editbuf[editp] to c.
 * don't make change if line would become too long.
 */

edchng(c)
char c ;
{
char oldc ;
int k ;
	/* if at right margin then insert char */
	if (editp >= editpmax) {
		edins(c) ;
		return ;
	}
	/* change char and print length of line */
	oldc=editbuf[editp] ;
	editbuf[editp]=c ;
	fmtadj(editbuf,editp,editpmax) ;
	k=fmtlen(editbuf,editpmax) ;
	if (k > SCRNW1) {
		/* line would become too long */
		/* undo the change */
		editbuf[editp]=oldc ;
		fmtadj(editbuf,editp,editpmax) ;
	}
	else {
		/* set change flag, redraw line */
		edcflag=YES ;
		editp++ ;
		edredraw() ;
	}
}

/* delete the char to left of cursor if it exists */

eddel()
{
int k ;
	/* just move left one one column if past end of line */
	if (edxpos() < outgetx()) {
		outxy(outgetx()-1,outgety()) ;
		return ;
	}
	/* do nothing if cursor is at left margin */
	if (editp == 0) {
		return ;
	}
	edcflag=YES ;
	/* compress buffer (delete char) */
	k=editp ;
	while (k < editpmax) {
		editbuf[k-1]=editbuf[k] ;
		k++ ;
	}
	/* update pointers, redraw line */
	editp-- ;
	editpmax-- ;
	edredraw() ;
}

/* edit the next line. do not go to end of buffer */

eddn()
{
int oldx ;
	/* save visual position of cursor */
	oldx=outgetx() ;
	/* replace current edit line */
	if (edrepl() != OK) {
		return (ERR) ;
	}
	/* do not go past last non null line */
	if (bufnrbot()) {
		return (OK) ;
	}
	/* move down one line in buffer */
	if (bufdn() != OK) {
		return (ERR) ;
	}
	edgetln() ;
	/*
	 * put cursor as close as possible on this
	 * new line to where it was on the oldline.
	 */
	editp=edscan(oldx) ;
	/* update screen */
	if (edatbot()) {
		edsup(bufln()-SCRNL2) ;
		outxy(oldx,SCRNL1) ;
	}
	else {
		outxy(oldx,outgety()+1) ;
	}
	return (OK) ;
}

/* put cursor at the end of the current line */

edend()
{
	editp=editpmax ;
	outxy(edxpos(),outgety()) ;

	/* comment out ---- put cursor at end of screen -
 	 * outxy(SCRNW1,outgety()) ;
	 * -----end comment out
	 */
}

/*
 * start editing line n
 * redraw the screen with cursor at position p
 */

edgo(n,p)
int n, p ;
{
	/* replace current line */
	if (edrepl() == ERR) {
		return (ERR) ;
	}
	/* go to new line */
	if (bufgo(n) == ERR) {
		return (ERR) ;
	}
	/* prevent going past end of buffer */
	if (bufatbot()) {
		if (bufup() == ERR) {
			return (ERR) ;
		}
	}
	/* redraw the screen */
	bufout(bufln(),1,SCRNL1) ;
	edgetln() ;
	editp=min(p,editpmax) ;
	outxy(edxpos(),1) ;
	return (OK) ;
}

/* insert c into the buffer if possible */

edins(c)
char c ;
{
int k ;
	/* do nothing if edit buffer is full */
	if (editpmax >= MAXLEN) {
		return ;
	}
	/* fill out line if we are past its end */
	if ((editp == editpmax) && (edxpos() < outgetx())) {
		k=outgetx()-edxpos() ;
		editpmax=editpmax+k ;
		while (k-- > 0) {
			editbuf[editp++]=' ' ;
		}
		editp=editpmax ;
	}
	/* make room for inserted character */
	k=editpmax ;
	while (k > editp) {
		editbuf[k]=editbuf[k-1] ;
		k-- ;
	}
	/* insert character, update pointers */
	editbuf[editp]=c ;
	editp++ ;
	editpmax++ ;
	/* recalculate print length of line */
	fmtadj(editbuf,editp-1,editpmax) ;
	k=fmtlen(editbuf,editpmax) ;
	if (k > SCRNW1) {
		/* line would become too long */
		/* delete what we just inserted */
		eddel() ;
	}
	else {
		/* set change flag, redraw line */
		edcflag=YES ;
		edredraw() ;
	}
}

/* join (concatenate) the current line with the one above it */

edjoin()
{
int k ;
	/* do nothing if at top of file */
	if (bufattop()) {
		return ;
	}
	/* replace lower line temporarily */
	if (edrepl() != OK) {
		return ;
	}
	/* get upper line into buffer */
	if (bufup() != OK) {
		return ;
	}
	k=bufgetln(editbuf,MAXLEN) ;
	/* append lower line to buffer */
	if (bufdn() != OK) {
		return ;
	}
	k=k+bufgetln(editbuf+k,MAXLEN-k) ;
	/* abort if the screen isn't wide enough */
	if (k > SCRNW1) {
		return ;
	}
	/* replace upper line */
	if (bufup() != OK) {
		return ;
	}
	editpmax=k ;
	edcflag=YES ;
	if (edrepl() != OK) {
		return ;
	}
	/* delete the lower line */
	if (bufdn() != OK) {
		return ;
	}
	if (bufdel() != OK) {
		return ;
	}
	if (bufup() != OK) {
		return ;
	}
	/* update the screen */
	if (edattop()) {
		edredraw() ;
	}
	else {
		k=outgety()-1 ;
		bufout(bufln(),k,SCRNL-k) ;
		outxy(0,k) ;
		edredraw() ;
	}
}

/* delete chars until end of line or c found */

edkill(c)
char c ;
{
int k, p ;
	/* do nothing if at right margin */
	if (editp == editpmax) {
		return ;
	}
	edcflag=YES ;
	/* count number of deleted chars */
	k=1 ;
	while ((editp+k) < editpmax) {
		if (editbuf[editp+k] == c) {
			break ;
		}
		else {
			k++ ;
		}
	}
	/* compress buffer (delete chars) */
	p=editp+k ;
	while (p < editpmax) {
		editbuf[p-k]=editbuf[p] ;
		p++ ;
	}
	/* update buffer size, redraw line */
	editpmax=editpmax-k ;
	edredraw() ;
}

/*
 * move cursor left one column.
 * never move the cursor off the current line.
 */

edleft()
{
	/* if past right margin move left one column */
	if (edxpos() < outgetx()) {
		outxy(max(0,outgetx()-1),outgety()) ;
	}
	/* inside the line move left one character */
	else if (editp != 0) {
		editp-- ;
		outxy(edxpos(),outgety()) ;
	}
}

/* insert a new blank line below the current line */

ednewdn()
{
int k ;
	/*
	 * make sure there is a current line and
	 * put the current line back into the buffer.
	 */
	if (bufatbot()) {
		if (bufins(editbuf,editpmax) != OK) {
			return ;
		}
	}
	else if (edrepl() != OK) {
		return ;
	}
	/* move past current line */
	if (bufdn() != OK) {
		return ;
	}
	/* insert place holder: zero length line */
	if (bufins(editbuf,0) != OK) {
		return ;
	}
	/* start editing the zero length line */
	edgetln() ;
	/* update the screen */
	if (edatbot()) {
		/* note: bufln() >= SCRNL */
		edsup(bufln()-SCRNL2) ;
		outxy(edxpos(),SCRNL1) ;
	}
	else {
		k=outgety() ;
		bufout(bufln(),k+1,SCRNL1-k) ;
		outxy(edxpos(),k+1) ;
	}
}

/* insert a new blank line above the current line */

ednewup()
{
int k ;
	/* put current line back in buffer */
	if (edrepl() != OK) {
		return ;
	}
	/* insert zero length line at current line */
	if (bufins(editbuf,0) != OK) {
		return ;
	}
	/* start editing the zero length line */
	edgetln() ;
	/* update the screen */
	if (edattop()) {
		edsdn(bufln()) ;
		outxy(edxpos(),1) ;
	}
	else {
		k=outgety() ;
		bufout(bufln(),k,SCRNL-k) ;
		outxy(edxpos(),k) ;
	}
}

/*
 * move cursor right one character.
 * never move the cursor off the current line.
 */

edright()
{
	/* if we are outside the line move right one column */
	if (edxpos() < outgetx()) {
		outxy(min(SCRNW1,outgetx()+1),outgety()) ;
	}
	/* if we are inside a tab, move to the end of it */
	else if (edxpos() > outgetx()) {
		outxy(edxpos(),outgety()) ;
	}
	/* move right one character if inside line */
	else if (editp < editpmax) {
		editp++ ;
		outxy(edxpos(),outgety()) ;
	}
	/* else move past end of line */
	else {
		outxy(min(SCRNW1,outgetx()+1),outgety()) ;
	}
}

/*
 * split the current line into two parts.
 * scroll the first half of the old line up.
 */

edsplit()
{
int p, q ;
int k ;
	/* indicate that edit buffer has been saved */
	edcflag=NO ;
	/* replace current line by the first half of line */
	if (bufatbot()) {
		if (bufins(editbuf,editp) != OK) {
			return ;
		}
	}
	else {
		if (bufrepl(editbuf,editp) != OK) {
			return ;
		}
	}
	/* redraw the first half of the line */
	p=editpmax ;
	q=editp ;
	editpmax=editp ;
	editp=0 ;
	edredraw() ;
	/* move the second half of the line down */
	editp=0 ;
	while (q < p) {
		editbuf[editp++]=editbuf[q++] ;
	}
	editpmax=editp ;
	editp=0 ;
	/* insert second half of the line below the first */
	if (bufdn() != OK) {
		return ;
	}
	if (bufins(editbuf,editpmax) != OK) {
		return ;
	}
	/* scroll the screen up and draw the second half */
	if (edatbot()) {
		edsup(bufln()-SCRNL2) ;
		outxy(1,SCRNL1) ;
		edredraw() ;
	}
	else {
		k=outgety() ;
		bufout(bufln(), k+1, SCRNL1-k) ;
		outxy(1,k+1) ;
		edredraw() ;
	}
}

/*
 * move cursor right until end of line or
 * character c found.
 */

edsrch(c)
char c ;
{
	/* do nothing if at right margin */
	if (editp == editpmax) {
		return ;
	}
	/* scan for search character */
	editp++ ;
	while (editp < editpmax) {
		if (editbuf[editp] == c) {
			break ;
		}
		else {
			editp++ ;
		}
	}
	/* reset cursor */
	outxy(edxpos(),outgety()) ;
}

/* move cursor up one line if possible */

edup()
{
int oldx ;
	/* save visual position of cursor */
	oldx=outgetx() ;
	/* put current line back in buffer */
	if (edrepl() != OK) {
		return (ERR) ;
	}
	/* done if at top of buffer */
	if (bufattop()) {
		return (OK) ;
	}
	/* start editing the previous line */
	if (bufup() != OK) {
		return (ERR) ;
	}
	edgetln() ;
	/*
	 * put cursor on this new line as close as
	 * possible to where it was on the old line.
	 */
	editp=edscan(oldx) ;
	/* update screen */
	if (edattop()) {
		edsdn(bufln()) ;
		outxy(oldx,1) ;
	}
	else {
		outxy(oldx,outgety()-1) ;
	}
	return (OK) ;
}

/* delete the current line */

edzap()
{
int k ;
	/* delete the line in the buffer */
	if (bufdel() != OK) {
		return ;
	}
	/* move up one line if now at bottom */
	if (bufatbot()) {
		if (bufup() != OK) {
			return ;
		}
		edgetln() ;
		/* update screen */
		if (edattop()) {
			edredraw() ;
		}
		else {
			outdelln() ;
			outxy(0,outgety()-1) ;
		}
		return ;
	}
	/* start editing new line */
	edgetln() ;
	/* update screen */
	if (edattop()) {
		edsup(bufln()) ;
		outxy(0,1) ;
	}
	else {
		k=outgety() ;
		bufout(bufln(),k,SCRNL-k) ;
		outxy(0,k) ;
	}
}

/*
 * return true if the current edit line is being
 * displayed on the bottom line of the screen.
 */

edatbot()
{
	return (outgety() == SCRNL1) ;
}

/*
 * return true if the current edit line is being
 * displayed on the top line of the screen.
 */

edattop()
{
	return (outgety() == 1) ;
}

/*
 * redraw edit line from index to end of line.
 * reposition cursor.
 */

edredraw()
{
	fmtadj(editbuf,0,editpmax) ;
	fmtsubs(editbuf,max(0,editp-1),editpmax) ;
	outxy(edxpos(),outgety()) ;
}

/* return the x position of the cursor on screen */

edxpos()
{
	return (min(SCRNW1,fmtlen(editbuf,editp))) ;
}

/*
 * fill edit buffer from current main buffer line.
 * the caller must chaeck to make sure the main
 * buffer is available.
 */

edgetln()
{
int k ;
	/* put cursor on left margin, reset flag */
	editp=0 ;
	edcflag=NO ;
	/* get edit line from main buffer */
	k=bufgetln(editbuf,MAXLEN) ;
	if (k > MAXLEN) {
		error("line truncated") ;
		editpmax=MAXLEN ;
	}
	else {
		editpmax=k ;
	}
	fmtadj(editbuf,0,editpmax) ;
}

/*
 * replace current main buffer line by edit buffer.
 * the edit buffer is not changed or cleared.
 * return ERR if something goes wrong.
 */

edrepl()
{
	/* do nothing if nothing has changed */
	if (edcflag == NO) {
		return (OK) ;
	}
	/* make sure we dont replace the line twice */
	edcflag=NO ;
	/* insert instead of replace if at bottom of file */
	if (bufatbot()) {
		return (bufins(editbuf,editpmax)) ;
	}
	else {
		return (bufrepl(editbuf,editpmax)) ;
	}
}

/*
 * set editp to the largest index such that
 * buf[editp] will be printed <= xpos.
 */

edscan(xpos)
int xpos ;
{
	editp=0 ;
	while (editp < editpmax) {
		if (fmtlen(editbuf,editp) < xpos) {
			editp++ ;
		}
		else {
			break ;
		}
	}
	return (editp) ;
}

/* scroll the screen up. topline will be new topline. */

edsup(topline)
int topline ;
{
	if (outhasup() == YES) {
		/* hardware scroll */
		outsup() ;
		/* redraw bottom line */
		bufout(topline+SCRNL2,SCRNL1,1) ;
	}
	else {
		/* redraw whole screen */
		bufout(topline,1,SCRNL1) ;
	}
}

/* scroll screen down. topline will be new topline. */

edsdn(topline)
int topline ;
{
	if (outhasdn() == YES) {
		/* hardware scroll */
		outsdn() ;
		/* redraw topline */
		bufout(topline,1,1) ;
	}
	else {
		/* redraw whole screen */
		bufout(topline,1,SCRNL1) ;
	}
}
____EOF____
cat >ed5.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/*
 * screen editor:   output format module
 *
 * source: ed5.c
 * version: march 6 1981.
 */

/* define variables global to this module */

/* define maximal length of a tab character */

int fmttab ;

/* define the current device and device width */

int fmtdev ;		/* device -- YES/NO = LIST/CONSOLE */
int fmtwidth ;		/* device width.   LISTW/SCRNW1 */

/*
 * int fmtcol[i] is the first column at which
 * buf[i] will be printed.
 * fmtsub() and fmtlen() assume fmtcol() is valid on entry.
 */

int fmtcol[MAXLEN1] ;

fmtassn(listflag)
int listflag ;
{
	fmtdev=NO ;
	fmtwidth=SCRNW1 ;
}

/*
 * adjust fmtcol[] to prepare for calls on fmtout() and fmtlen().
 *
 * NOTE:  This routine is neaded as an efficiency
 *	  measure. Without fmtadj(), calls on
 *	  fmtlen() become too slow.
 */

fmtadj(buf,minind,maxind)
char *buf ;
int minind, maxind ;
{
int k ;
	/* line always starts at left margin */
	fmtcol[0]=0 ;
	/* start scanning at minind */
	k=minind ;
	while (k < maxind) {
		if (buf[k] == CR) {
			break ;
		}
		fmtcol[k+1]=fmtcol[k]+fmtlench(buf[k],fmtcol[k]) ;
		k++ ;
	}
}

/* return column at which buf[i] will be printed */

/*
 * In the Dr.Dobbs source this function had an unused
 * parameter. I'm leaving it in until I sus out
 * what is going on here !!!!
 */

fmtlen(buf,i)
char *buf ;
int i ;
{
	return(fmtcol[i]) ;
}

/*
 * print buf[i] ... buf[j-1] on current device so long as
 * characters will not be printed in last column.
 */

fmtsubs(buf,i,j)
char *buf ;
int i,j ;
{
	if (fmtcol[i] >= fmtwidth) {
		return ;
	}
	outxy(fmtcol[i],outgety()) ;		/* position cursor */
	while (i < j) {
		if (buf[i] == CR) {
			break ;
		}
		if (fmtcol[i+1] > fmtwidth) {
			break ;
		}
		fmtoutch(buf[i],fmtcol[i]) ;
		i++ ;
	}
	outdeol() ;	/* clear rest of line */
}

/*
 * print string which ends with CR or EOS to current device.
 * truncate the string if it is too long.
 */

fmtsout(buf,offset)
char *buf ;
int offset ;
{
char c ;
int col, k ;
	col=0 ;
	while (c=(*buf++)) {
		if (c == CR) {
			break ;
		}
		k=fmtlench(c,col) ;
		if ((col+k+offset) > fmtwidth) {
			break ;
		}
		fmtoutch(c,col) ;
		col=col+k ;
	}
}

/* return length of char c at column col */

fmtlench(c,col)
char c ;
int col ;
{
	if (c == TAB) {
		/* tab every fmttab columns */
		return(fmttab-(col%fmttab)) ;
	}
	else if (c < 32) {
		/* control char */
		return (2) ;
	}
	else {
		return (1) ;
	}
}

/*
 * output one character to current device.
 * convert tabs to blanks.
 */

fmtoutch(c,col)
char c ;
int col ;
{
int k ;
	if (c == TAB) {
		k=fmtlench(TAB,col) ;
		while ((k--) > 0) {
			fmtdevch(' ') ;
		}
	}
	else if (c < 32) {
		fmtdevch('^') ;
		fmtdevch(c+64) ;
	}
	else {
		fmtdevch(c) ;
	}
}

/* output character to current device */

fmtdevch(c)
char c ;
{
	if (fmtdev == YES) {
		syslout(c) ;
	}
	else {
		outchar(c) ;
	}
}

/* output a  CR and LF to the current device */

fmtcrlf()
{
	if (fmtdev == YES) {
		syslout(CR) ;
		syslout(LF) ;
	}
	else {
		/* COCK UP:  this should be in out module.
		 * 	     make sure out module knows position !
		 */
		outxy(0,SCRNL1) ;
		syscout(LF) ;
	}
}

/* set tabs at every n columns */

fmtset(n)
int n ;
{
	fmttab=max(1,n) ;
}
____EOF____
cat >ed6.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/*
 * screen editor: terminal output module.
 *
 * source: ed6.c
 * version: Westfield college cifers .
 */

/*
 * This file rewritten for cifer terminals
 * by Keith Brown. 7/11/83.
 */

#define ESC '\033'		/* ASCII escape char */

/* define the current coordinates of the cursor */

int outx, outy ;

/* return the current coordinates of the cursor */

outgetx()
{
	return (outx) ;
}

outgety()
{
	return (outy) ;
}

/* output one printable character to the screen */

outchar(c)
char c ;
{
	syscout((char) c) ;
	outx++ ;
}

/*
 * position cursor to position x,y on screen.
 * 0,0 is the top left hand corner.
 */

outxy(x,y)
int x, y ;
{
register int i ;
	outx=x ;
	outy=y ;
	syscout(ESC) ;
	syscout('P') ;
	syscout((char) x+32) ;
	syscout((char) y+32) ;
}

/*
 * Erase the entire screen.
 * make sure the rightmost column is erased.
 */

outclr()
{
	/* use cifers clear screen facility */
	syscout(ESC) ;
	syscout('J') ;
	outx=0 ;
	outy=0 ;	/* Register the new cursor position (home) */
}

/* delete the line on which the cursor rests
 * leave the cursor at the left margin.
 */

outdelln()
{
	outxy(0,outy) ;
	outdeol() ;
}

/*
 * delete to end of line.
 * assume the last column is blank.
 */

outdeol()
{
	/* use cifers DEOL facility */
	syscout(ESC) ;
	syscout('K') ;
}

/* return YES if terminal has indicated hardware scroll */

outhasup()
{
	return (YES) ;
}

outhasdn()
{
	return (YES) ;
}

/*
 * scroll the screen up.
 * assume the cursor is on the bottom line.
 */

outsup()
{
	outxy(0,SCRNL1) ;
	syscout(LF) ;
}

/*
 * scroll the screen down.
 */

outsdn()
{
	/* insert line at top of screen */
	outxy(0,0) ;
	syscout(ESC) ;
	syscout(':') ;
}
____EOF____

-- 

"Specialist subject, the bleedin' obvious!!"

             Keith Brown  ....!ukc!west44!kbrown
                          ( And other leading Usenet paths )



More information about the Comp.sources.unix mailing list