Dobbs cpm screen editor (3 of 3)

Keith Brown. kbrown at west44.UUCP
Sat Jul 7 03:56:47 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[789].c ed10.c'
cat >ed7.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/* screen editor: prompt line module.
 * 
 * source: ed7.c
 * version: march 6, 1981.
 */

/* define the prompt line data */

char pmtln[MAXLEN] ;		/* mode */
char pmtfn[SYSFNMAX] ;		/* file name */

/*
 * put error message on prompt line.
 * wait for response.
 */

pmtmess(s1,s2)
char *s1,*s2 ;
{
int x,y ;
	/* save cursor */
	x=outgetx() ;
	y=outgety() ;
	outxy(0,0) ;
	/* make sure line is correct */
	outdelln() ;
	pmtln1() ;
	pmtcol1(x) ;
	/* output error message */
	fmtsout(s1,outgetx()) ;
	fmtsout(s2,outgetx()) ;
	/* wait for input from console */
	syscin() ;
	/* redraw prompt line */
	pmtln1() ;
	pmtcol1(x) ;
	pmtfl1(pmtfn) ;
	pmtmd1(pmtln) ;
	/* restore cursor */
	outxy(x,y) ;
}

/* write new mode message on prompt line */

pmtmode(s)
char *s ;
{
int x,y ;			/* save cursor on entry */
	/* save cursor */
	x=outgetx() ;
	y=outgety() ;
	/* redraw whole line */
	outxy(0,0) ;
	outdelln() ;
	pmtln1() ;
	pmtcol1(x) ;
	pmtfl1(pmtfn) ;
	pmtmd1(s) ;
	/* restore cursor */
	outxy(x,y) ;
}

/* update file name on prompt line */

pmtfile(s)
char *s ;
{
int x,y ;
	/* save cursor */
	x=outgetx() ;
	y=outgety() ;
	/* update whole line */
	outxy(0,0) ;
	outdelln() ;
	pmtln1() ;
	pmtcol1(x) ;	/* x param missing in Dobbs. MUST be wrong (KEDB) */
	pmtfl1(s) ;
	pmtmd1(pmtln) ;
	/* restore cursor */
	outxy(x,y) ;
}

/* change mode on prompt line to edit */

pmtedit()
{
	pmtmode("edit:") ;
}

/* update line and column numbers on prompt line */

pmtline()
{
int x,y ;
	/* save cursor */
	x=outgetx() ;
	y=outgety() ;
	/* redraw whole line */
	outxy(0,0) ;
	outdelln() ;
	pmtln1() ;
	pmtcol1(x) ;
	pmtfl1(pmtfn) ;
	pmtmd1(pmtln) ;
	/* restore cursor */
	outxy(x,y) ;
}

/* update just the column number on the prompt line */

pmtcol()
{
int x,y ;
	/* save cursor */
	x=outgetx() ;
	y=outgety() ;
	/* update column number */
	pmtcol1(x) ;
	/* update cursor */
	outxy(x,y) ;
}

/* update mode:  call getcmnd() to write on prompt line */

pmtcmnd(mode,buffer)
char *mode, *buffer ;
{
int x,y ;
	/* save cursor */
	x=outgetx() ;
	y=outgety() ;
	pmtmd1(mode) ;
	/* user types command on prompt line */
	getcmnd(buffer,outgetx()) ;
	/* restore cursor */
	outxy(x,y) ;  /* correction to Dobbs source (line missing) (KEDB) */
}

/* update and print mode */

pmtmd1(s)
char *s ;
{
int i ;
	outxy(40,0) ;
	fmtsout(s,40) ;
	i=0 ;
	while (pmtln[i++]=(*s++)) {
		;
	}
}

/* print the file name on the prompt line */

pmtfl1(s)
char *s ;
{
int i ;
	outxy(25,0) ;
	if (*s == EOS) {
		fmtsout("no file",25) ;
	}
	else {
		fmtsout(s,25) ;
	}
	i=0 ;
	while (pmtfn[i++]=(*s++)) {
		;
	}
}

/* print the line number on the prompt line */

pmtln1()
{
	outxy(0,0) ;
	fmtsout("line: ",0) ;
	putdec(bufln(),5) ;
}

/* print column number of the cursor */

pmtcol1(x)
int x ;
{
	outxy(12,0) ;
	fmtsout("column: ",12) ;
	putdec(x,3) ;
}
____EOF____
cat >ed8.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/*
 * screen editor operating system module.
 *
 * source:  ed8.c
 * version:  cpm
 */

/* all calls to the operating system are made here.
 * only this module and the assembler libraries wil have to
 * be re-written for a new operating system.
 */

/* the routines syscstat() & syscin() & syscout() come in 2 flavours.
 * cpm 2.2 & 1.4.
 * Comment out whatever you don't need.
 */

/* cpm 2.2 versions of syscstat(), syscin() & syscout(). */

/* return -1 if no character is ready from the console.
 * otherwise return the character.
 */

syscstat()
{
	return(cpm(6,-1)) ;
}

/* wait for next character from the console.
 * do not echo it.
 */

syscin()
{
int c ;
	while ((c=cpm(6,-1)) == 0) {
		;
	}
	return (c) ;
}

/* print character on the console */

syscout(c)
char c ;
{
	cpm(6,c) ;
	/* return(c) ; Don't bother cos it isn't used (KEDB) */
}

/* cpm 1.4 versions of syscstat(), syscin(), syscout() */

/* start comment out --------------------------
#asm
;	bios(n,bc)
;
;	calls the n'th bios routine.
;	bc is put into the bc register as a parameter.
;	returns whatever bios puts into the a reg.
;
QZBIOS:
	POP	H	; get return address
	POP	B	;	bc
	POP	D	;	n
	PUSH	D	; restore stack the way it woz.
	PUSH	B
	PUSH	H
	LHLD	1	; point HL at start of bios jump table.
	DCX	H
	DCX	H
	DCX	H
	MOV 	A,E	; put index into jump table into de
	ADD	A
	ADD	E
	MVI	D,0
	MOV	E,A
	DAD	D	; point hl at proper entry in jump table
	PUSH	H	; push call address
	LXI	H,QZBIOS1  ; point hl at return address
	XTHL		; push return address - get call address
	PCHL		; call proper bios routine
QZBIOS1:
	MOV	L,A	; put return code from bios into hl
	MVI	H,0
	RET		; go back to small-c
#endasm

syscstat()
{
	if (bios(2,0) == 255) {
		return (-1) ;
	}
	else {
		return (0) ;
	}
}

syscin()
{
	return (bios(3,0)) ;
}

syscout(c)
char c ;
{
	bios(4,c) ;
	return (c) ;
}

--------------- end comment out */

/* print character ont the printer */

syslout(c)
char c  ;
{
	cpm(5,6) ;
	/* return (c) ;		(KEDB) */
}

#asm
;
; sysend()
;
;  return address of last usable memory location ;
;
QZSYSEND:
	LHLD	6	; get address of BDOS-1
	DCX	H
	RET		; return
#endasm

/* open a file */

sysopen(name, mode)
char *name, *mode ;
{
int file ;
	if ((file=fopen(name,mode)) == 0) {
		return (ERR) ;
	}
	else {
		/* yet another example of a pointless else!! (KEDB) */
		return (file) ;
	}
}

/* close a file */

sysclose(file)
int file ;
{
	/* fclose doesn't reliably return OK */
	fclose(file) ;
	return (OK) ;
}

/* read next character from file */

sysrdch(file)
int file ;
{
int c ;
	if ((c=getc(file)) == -1) {
		return (EOF) ;
	}
	else {
		return (c) ;
	}
}

/* write next char to file */

syspshch(c,file)
char c ;
int file ;
{
	if (putc(c,file) == -1) {
		error("disc write failed") ;
		return (ERR) ;
	}
	else {
		return (c) ;
	}
}

/* read one char from end of file */

syspopch(file)
int file ;
{
	error("syspopch() not implemented") ;
	return (ERR) ;
}

/* check filename syntax */

syschkfn(args)
char *args ;
{
	return (OK) ;
}

/* copy file name from args to buffer */
/* strcpy() calls can be made on most proper systems!! (KEDB) */

syscopfn(args,buffer)
char *args, *buffer ;
{
int n ;
	n=0 ;
	while (n < SYSFNMAX-1) {
		if (args[n] == EOS) {
			break ;
		}
		else {
			buffer[n] = args[n] ;
			n++ ;
		}
	}
	buffer[n] = EOS ;
}

/* move a block of n bytes down (towards high addresses).
 * block starts a source and the first byte goes to dest.
 * this routine is only called from bufmovdn() as follows.
 *	sysmovdn( n=to-from+1, dest=to+length, sources=to ) ;
 */

#asm
QZSYSMOVDN:
	POP	H	; get return address
	POP	B	; BC = source
	POP	D	; DE = dest
	XTHL		; HL = n, restore return address
	JMP	SYSMOVDN2	; go enter loop
;
; this code is 15 times faster than the 'C' code it replaces.
SYSMOVDN1:
	LDAX	B	; *dest-- = *source--
	STAX	D
	DCX	B
	DCX	D
	DCX	H	; while ((n--) > 0)
SYSMOVDN2:
	MOV	A,L
	ORA	H
	JNZ	SYSMOVDN1
;
	XTHL		; HL = return address
	PUSH	H	; restore stack
	PUSH	H
	PUSH	H
	RET		; return
#endasm

/* move block of n bytes up (towards low addresses)
 * the block starts at source and the first byte goes to dest.
 * this routine is called only from bufmovup() as follows,
 *	sysmovup( n=to-from+1, dest=from-length, source=from )
 */


#asm
QZSYSMOVUP:
	POP	H	; get return address
	POP	B	; BC = source
	POP	D	; DE = dest
	XTHL		; HL = n, save return address
	JMP	SYSMOVDN2	; go enter loop
;
; this code is 15 times faster than the 'C' code it replaces.
SYSMOVUP1:
	LDAX	B	; *dest++ = *source++
	STAX	D
	INX	B
	INX	D
	DCX	H	; while ((n--) > 0)
SYSMOVUP2:
	MOV	A,L
	ORA	H
	JNZ	SYSMOVUP1
;
	XTHL		; HL = return address
	PUSH	H	; restore stack
	PUSH	H
	PUSH	H
	RET		; return
#endasm
____EOF____
cat >ed9.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/*
 * screen editor general utilities.
 *
 * Source: ed9.c
 * Version: may 3, 1981.
 */


/* convert lower case to upper case */

toupper(c)
int c ;
{
	if ((c < 'a') || (c >'z')) {
		return (c) ;
	}
	else {
		return (c-32) ;
	}
}

/* convert upper case to lower case */

tolower(c)
int c ;
{
	if ((c < 'A') || (c >'Z')) {
		return (c) ;
	}
	else {
		return (c+32) ;
	}
}


/* return: is first token in args a number ? */
/* return value of number in *val */

number(args,val)
char *args ;
int *val ;
{
char c ;
	c=(*args++) ;
	if ((c < '0') || (c > '9')) {
		return (NO) ;
	}
	*val=c-'0' ;
	while (c=(*args++)) {
		if ((c < '0') || (c > '9')) {
			break ;
		}
		*val=(*val*10)+c-'0' ;
	}
	return (YES) ; 
}

/* convert character buffer to numeric */

ctoi(buf,index)
char *buf ;
int index ;
{
int k ;
	while ((buf[index] == ' ') || (buf[index] == TAB)) {
		index++ ;
	}
	k=0 ;
	while ((buf[index] >= '0') && (buf[index] <= '9')) {
		k=(k*10)+buf[index]-'0' ;
		index++ ;
	}
	return (k) ;
}

/* return maximum of m,n */

max(m,n)
int m,n ;
{
	if (m >= n) {
		return (m) ;
	}
	else {
		return (n) ;
	}
}

/* return minimum of m,n */

min(m,n)
int m,n ;
{
	if (m <= n) {
		return (m) ;
	}
	else {
		return (n) ;
	}
}

/*
 * put decimal integer n in field width >= w.
 * left justify the number in the field.
 */

putdec(n,w)
int n,w ;
{
char chars[10] ;
int i,nd ;
	nd=itoc(n,chars,10) ;
	i=0 ;
	while (i < nd) {
		syscout(chars[i++]) ;
	}
	i=nd ;
	while (i++ < w) {
		syscout(' ') ;
	}
}

/* convert integer n to character string in str */

itoc(n,str,size)
int n ;
char *str ;
int size ;
{
int absval ;
int len ;
int i,j,k ;
	absval=abs(n) ;
	/* generate digits */
	str[0]=0 ;
	i=1 ;
	while (i < size) {
		str[i++]=(absval%10)+'0' ;
		absval=absval/10 ;
		if (absval == 0) {
			break ;
		}
	}
	/* generate sign */
	if ((i < size) && (n < 0)) {
		str[i++]='-' ;
	}
	len=i-1 ;
	/* reverse sign, digits */
	i-- ;
	j=0 ;
	while (j < i) {
		k=str[i] ;
		str[i]=str[j] ;
		str[j]=k ;
		i-- ;
		j++ ;
	}
	return (len) ;
}

/* return absolute value of n */

abs(n)
int n ;
{
	if (n < 0) {
		return (-n) ;
	}
	else {
		return (n) ;
	}
}

/* system error routine */

syserr(s)
char *s ;
{
	pmtmess("system error: ",s) ;
}

/* user error routine */

error(s)
char *s ;
{
	pmtmess("error: ",s) ;
}

/* disk error routine */

diskerr (s)
char *s ;
{
	pmtmess("disk error: ",s) ;
}

/* read the next line of the file into
 * the buffer of size n that p points to.
 * succesful calls to readline() read the file
 * from front to back.
 */

readline(file,p,n)
int file;
char *p ;
int n ;
{
int c ;
int k ;
	k=0 ;
	while (1) {
		c=sysrdch(file) ;
		if (c == ERR) {
			return (ERR) ;
		}
		if (c == EOF) {
			/* ignore line without CR */
			return (EOF) ;
		}
		if (c == CR) {
			return (k) ;
		}
		if (k < n) {
			/* move char to buffer */
			*p++ = c ;
		}
		/* always bump count */
		k++ ;
	}
}

/* push (same as write) line to end of file.
 * line is in the buffer of size n that p points to.
 * lines written by this routine may be read by
 * either readline() or popline().
 */

pushline(file,p,n)
int file ;
char *p ;
int n ;
{
	/* write all but trailing CR */
	while ((n--) > 0) {
		if (syspshch(*p++,file) == ERR) {
			return (ERR) ;
		}
	}
	/* write trailing CR */
	return (syspshch(CR,file)) ;
}

/*
 * pop a line from the back of the file.
 * the line should have been pushed using pushline().
 */

popline(file,p,n)
int file ;
char *p ;
int n ;
{
int c ;
int k,kmax,t ;
	/* first char must be CR */
	c=syspopch(file) ;
	if (c == EOF) {
		/* at START of file */
		return (EOF) ;
	}
	if (c == CR) {
		/* put into buffer */
		*p++ = CR ;
		k=1 ;
	}
	/* pop line into buffer in reverse order */
	while (1) {
		c=syspopch(file) ;
		if (c == ERR) {
			return (ERR) ;
		}
		if (c == EOF) {
			break ;
		}
		if (c == CR) {
			/* this ends ANOTHER line */
			/* push it back		  */
			if (syspshch(CR,file) == ERR) {
				return (ERR) ;
			}
			break ;
		}
		/* non-special case */
		if (k < n) {
			/* put into buffer */
			*p++ = c ;
		}
		/* always bump count */
		k++ ;
	}
	/* remember if we truncated the line */
	kmax=k ;
	/* reverse the buffer */
	k=min(k,n-1) ;
	t=0 ;
	while (k > t) {
		/* swap p[t], p[k] */
		c=p[k] ;
		p[k]=p[t] ;
		p[t]=c ;
		k-- ;
		t++ ;
	}
	return (kmax) ;
}
____EOF____
cat >ed10.c <<____EOF____
#include "ed0.h"
#include "ed1.h"

/*
 * Screen editor:  Buffer module.
 *
 * source:  ed10.c
 * version:  April 7, 1981.
 */

/*
 * Define the variables global to this module.
 * buffer must be dclared after all other variables
 * of the entire program.
 * Note: buffer must have non-zero dimension.
 */

int bufcflag ;		/* main buffer changed flag */
char *bufp ;		/* start of current line */
char *bufpmax ;		/* end of last line */
char *bufend ;		/* last byte of buffer */
int bufline ;		/* current line number */
int bufmaxln ;		/* number of lines in buffer */
char buffer[1] ;	/* start of buffer */

/*
 * This code is built around several invariant assumptions.
 * First, the last line is always completely empty.
 * When bufp points to the last line there is NO
 * CR following it.
 * Second, bufp points to the last line if and only if
 * bufline == bufmaxln+1.
 * Third, bufline is always greater than zero.
 * line zero only exists only to make scanning for the
 * start of line 1 easier.
 */

/* clear the main buffer */

bufnew()
{
	/* point past line zero */
	bufp=bufpmax=buffer+1 ;
	/* point at last byte of buffer */
	bufend=sysend()-1000 ;
	/* at line one. no lines in buffer */
	bufline=1 ;
	bufmaxln=0 ;
	/* line zero is always a null line */
	buffer[0]=CR ;
	/* indicate no need to save file yet */
	bufcflag=NO ;
}

/* return current line number */

bufln()
{
	return (bufline) ;
}

/*
 * return YES if the buffer (ie.. the file) has been
 * changed since the last time the file was changed.
 */

bufchng()
{
	return (bufcflag) ;
}

/* the file has been saved. clear bufcflag */

bufsaved()
{
	bufcflag=NO ;
}

/* return number of bytes left in the buffer */

buffree()
{
	return (bufend-bufp) ;
}

/* position buffer pointers to start of indicated line */

bufgo(line)
int line ;
{
	/* put request into range. prevent extension. */
	line=min(bufmaxln+1,line) ;
	line=max(1,line) ;
	/* already at proper line? return. */
	if (line == bufline) {
		return (OK) ;
	}
	/* move through buffer one line at a time */
	while (line < bufline) {
		if (bufup() == ERR) {
			return (ERR) ;
		}
	}
	while (line > bufline) {
		if (bufdn() == ERR) {
			return (ERR) ;
		}
	}
	/* we have reached the line we wanted */
	return (OK) ;
}

/*
 * move one line closer to front of buffer, i.e.,
 * set buffer pointers to start of previous line.
 */

bufup()
{
char *oldbufp ;
	oldbufp=bufp ;
	/* cant move past line 1 */
	if (bufattop()) {
		return (OK) ;
	}
	/* move past CR of previous line */
	if (*--bufp != CR) {
		syserr("bufup: missing CR") ;
		bufp=oldbufp ;
		return (ERR) ;
	}
	/* move to start of previous line */
	while (*--bufp != CR) {
		;
	}
	bufp++ ;
	/* make sure we havent gone too far !! */
	if (bufp < (buffer+1)) {
		syserr("bufup: bufp underflow") ;
		bufp=oldbufp ;
		return (ERR) ;
	}
	/* success!! we are at previous line */
	bufline-- ;
	return (OK) ;
}

/*
 * move one line closer to end of buffer, i.e,
 * set buffer pointers to start of next line.
 */

bufdn()
{
char *oldbufp ;
	oldbufp=bufp ;
	/* do nothing silly if at end of buffer */
	if (bufatbot()) {
		return (OK) ;
	}
	/* scan past current line and CR */
	while (*bufp++ != CR) {
		;
	}
	/* make sure we havent gone too far */
	if (bufp > bufpmax) {
		syserr("bufdn: bufp overflow") ;
		bufp=oldbufp ;
		return (ERR) ;
	}
	/* success!! we are at next line */
	bufline++ ;
	return (OK) ;
}

/*
 * Insert a line before the current line.
 * p points to a line of length n to be inserted.
 * Note: n does not include trailing CR.
 */

bufins(p,n)
char *p ;
int n ;
{
int k ;
	/* make room in the buffer for the line */
	if (bufext(n+1) == ERR) {
		return (ERR) ;
	}
	/* put the line and CR into the buffer */
	k=0 ;
	while (k < n) {
		*(bufp+k)=(*(p+k));
		k++ ;
	}
	*(bufp+k)=CR ;
	/* increase number of lines in buffer */
	bufmaxln++ ;
	/*
	 * special case: inserting a null line at
	 * end of file is not a significant change..
	 */
	if ((n==0) && (bufnrbot())) {
		;
	}
	else {
		bufcflag=YES ;
	}
	return (OK) ;
}

/* delete the current line */

bufdel()
{
	return (bufdeln(1)) ;
}

/* delete n lines, starting with the current line. */

bufdeln(n)
int n ;
{
int oldline, k ;
char *oldbufp ;
	/* remember current buffer parameters */
	oldline=bufline ;
	oldbufp=bufp ;
	/* scan for first line after deleted lines */
	k=0 ;
	while ((n--) > 0) {
		if (bufatbot()) {
			break ;
		}
		if (bufdn() == ERR) {
			bufline=oldline ;
			bufp=oldbufp ;	/*
					 * probable mistake in Dr.Dobbs
					 * corrected. Was oldbufp=bufp !!!!
					 * (KEDB).
					 */
			return (ERR) ;
		}
		k++ ;
	}
	/* compress buffer. Update pointers */
	bufmovup(bufp,bufpmax-1,bufp-oldbufp) ;
	bufpmax=bufpmax-(bufp-oldbufp) ;
	bufp=oldbufp ;
	bufline=oldline ;
	bufmaxln=bufmaxln-k ;
	bufcflag=YES ;
	return (OK) ;
}

/*
 * replace current line with the line that
 * p points to. The new line is of length n.
 */

bufrepl(p,n)
char *p ;
int n ;
{
int oldlen, k ;
char *nextp ;
	/* do not replace null line. just insert */
	if (bufatbot()) {
		return (bufins(p,n)) ;
	}
	/* point nextp at start of next line */
	if (bufdn() == ERR) {
		return (ERR) ;
	}
	nextp=bufp ;
	if (bufup() == ERR) {
		return (ERR) ;
	}
	/* allow for CR at end */
	n=n+1 ;
	/*
	 * see how to move buffer below us.
	 * up, down, or not at all.
	 */
	oldlen=nextp-bufp ;
	if (oldlen < n) {
		/* move buffer down */
		if (bufext(n-oldlen) == ERR) {
			return (ERR) ;
		}
		bufpmax=bufpmax+n-oldlen ;
	}
	else if (oldlen > n) {
		/* move buffer up */
		bufmovup(nextp,bufpmax-1,oldlen-n) ;
		bufpmax=bufpmax-(oldlen-n) ;
	}
	/* put new line in the hole we just made */
	k=0 ;
	while (k < (n-1)) {
		bufp[k]=p[k] ;
		k++ ;
	}
	bufp[k]=CR ;
	bufcflag=YES ;
	return (OK) ;
}

/*
 * copy current line into buffer thet p points to.
 * the maximum size of that buffer is n.
 * return k=length of line in the main buffer.
 * if k>n then truncate n-k characters and only
 * return n characters in the callers buffer.
 */

bufgetln(p,n)
char *p ;
int n ;
{
int k ;
	/* last line is always null */
	if (bufatbot()) {
		return (0) ;
	}
	/* copy line as long as it is not too long */
	k=0 ;
	while (k < n) {
		if (*(bufp+k) == CR) {
			return (k) ;
		}
		*(p+k)=(*(bufp+k)) ;
		k++ ;
	}
	/* count length but move no more chars */
	while (*(bufp+k) != CR) {
		k++ ;
	}
	return (k) ;
}

/* move buffer down (towards HIGH addresses) */

bufmovdn(from,to,length)
char *from, *to ;
int length ;
{
int k ;
	k=to-from+1 ;
	while ((k--) > 0) {
		*(to+length)=(*to) ;
		to-- ;
	}
}


/* move buffer up (towards LOW addresses) */

bufmovup(from,to,length)
char *from, *to ;
int length ;
{
int k ;
	k=to-from+1 ;
	while ((k--) > 0) {
		*(from-length)=(*from) ;
		from++ ;
	}
}

/*
 * return true if at bottom of buffer.
 * NOTE 1: the last line of the buffer is always null.
 * NOTE 2: the last line number is always bufmaxln+1.
 */

bufatbot()
{
	return (bufline>bufmaxln) ;
}

/*
 * return true if at bottom or at the last
 * real line before the bottom.
 */

bufnrbot()
{
	return (bufline >= bufmaxln) ;
}

/* return true if at top of buffer */

bufattop()
{
	return (bufline == 1) ;
}

/*
 * put nlines lines from buffer starting with
 * line topline at position topy of the screen.
 */

bufout(topline,topy,nlines)
int topline, topy, nlines ;
{
char *p ;		/* p is (char *) not int as in Dr.Dobbs. (KEDB) */
int l ;
	/* remember buffers state */
	l=bufline ;
	p=bufp ;
	/* write out one line at a time */
	while ((nlines--) > 0) {
		outxy(0,topy++) ;
		bufoutln(topline++) ;
	}
	/* restore buffers state */
	bufline=l ;
	bufp=p ;
}

/* print line of main buffer on screen */

bufoutln(line)
int line ;
{
	/* error message does NOT go on prompt line */
	if (bufgo(line) == ERR) {
		fmtsout("disk error: line deleted",0) ;
		outdeol() ;
		return ;
	}
	/* blank out lines below last line of buffer */
	if (bufatbot()) {
		outdeol() ;
	}
	/* write one formatted line out */
	else {
		fmtsout(bufp,0) ;
		outdeol() ;
	}
}

/*
 * simple memory version of bufext.
 * create a whole in buffer at current line.
 * length is the size of the whole.
 */

bufext(length)
int length ;
{
	/* make sure there is room for more */
	if ((bufpmax+length) >= bufend) {
		error("main buffer is full") ;
		return (ERR) ;
	}
	/* move lines below current line down */
	bufmovdn(bufp,bufpmax-1,length) ;
	bufpmax=bufpmax+length ;
	return (OK) ;
}
____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