PROCEDURE INSERTIT; CONST FUDGEFACTOR=10; VAR THEREST,LEFTPART,SAVEBUFCOUNT: PTRTYPE; CLEARED,WARNED,OK,NOTEXTYET,EXITPROMPT,FIRSTLINE: BOOLEAN; SPACES,LMOVE,X,LINE,EOLDIST,RJUST: INTEGER; CONTEXT: PACKED ARRAY [0..MAXSTRING] OF CHAR; PROCEDURE SLAMRIGHT; (* Move (slam) the portion of the EBUF^ to the right of (and including) the cursor so that the last NUL in the file (EBUF^[BUFCOUNT]) is now at EBUF^[BUFSIZE]. THEREST points to the beginning of the right-justified text. *) BEGIN GETLEADING; THEREST:=BUFSIZE-(BUFCOUNT-CURSOR); LMOVE:=BUFCOUNT-CURSOR+1; MOVERIGHT(EBUF^[CURSOR],EBUF^[THEREST],LMOVE); GETLEADING; (* Set blanks *) IF THEREST-CURSORCHR(ESC)) THEN (* We want the blanks before THEREST *) BEGIN BUFCOUNT:=BUFCOUNT+2; THEREST:=THEREST-2; LMOVE:=LMOVE+2; CURSOR:=SCAN(-MAXCHAR,=CHR(EOL),EBUF^[CURSOR-1])+CURSOR; END; MOVELEFT(EBUF^[THEREST],EBUF^[CURSOR],LMOVE); READJUST(LEFTPART+1,CURSOR-(LEFTPART+1)); BUFCOUNT:=BUFCOUNT+CURSOR-(LEFTPART+1); WITH PAGEZERO DO IF FILLING AND NOT AUTOINDENT AND (CH=CHR(ETX)) THEN BEGIN THEFIXER(CURSOR,1,FALSE); FIRSTLINE:=FALSE END; UPSCREEN(FIRSTLINE,EXITPROMPT OR (CH=CHR(ESC)),LINE); GETLEADING; CURSOR:=MAX(CURSOR,STUFFSTART); LASTPAT:=LEFTPART+1; COPYOK:=TRUE; COPYSTART:=LASTPAT; COPYLENGTH:=CURSOR-LASTPAT; NEXTCOMMAND END; FUNCTION CHECK(VALUE:INTEGER): BOOLEAN; (* VALUE is the potential value of the cursor. If it is not in legal range then CHECK is false. This function also warns the user if s/he is getting too close to overflowing the buffer *) BEGIN CHECK:=TRUE; IF VALUE<=LEFTPART THEN BEGIN OK:=FALSE; CHECK:=FALSE; ERROR('No insertion to back over.',NONFATAL); PROMPT; GOTOXY(X,LINE) END ELSE IF VALUE>=THEREST-MAXCHAR THEN BEGIN IF NOT WARNED THEN BEGIN ERROR('Please finish up the insertion',NONFATAL); PROMPT; GOTOXY(X,LINE); WARNED:=TRUE END; IF VALUE>THEREST-FUDGEFACTOR THEN BEGIN ERROR('Buffer Overflow!!!!',NONFATAL); WRAPUP; EXIT(INSERTIT); END END END; PROCEDURE SPACEOVER; (* This procedure handles spaces and tabs inserted into the buffer *) BEGIN IF CH=CHR(HT) THEN SPACES:=8-X+ORD(ODD(X) AND ODD(248)) ELSE SPACES:=1; IF CHECK(CURSOR+SPACES) THEN BEGIN FILLCHAR(EBUF^[CURSOR],SPACES,' '); CURSOR:=CURSOR+SPACES END END; PROCEDURE FIXUP; FORWARD; PROCEDURE ENDLINE; (* First, if there was no text inserted on the current line, then convert all of the spaces to blank compression codes. Then insert an into the buffer followed by the appropriate number of spaces for the indentation. *) BEGIN WITH PAGEZERO DO BEGIN IF NOTEXTYET THEN FIXUP; EBUF^[CURSOR]:=CHR(EOL); IF AUTOINDENT THEN GETLEADING ELSE IF FILLING THEN BEGIN GETLEADING; IF EBUF^[STUFFSTART]=CHR(EOL) THEN (* Empty line *) BLANKS:=PARAMARGIN ELSE BLANKS:=LMARGIN END ELSE BLANKS:=0; IF CHECK(CURSOR+BLANKS+1) THEN BEGIN FILLCHAR(EBUF^[CURSOR+1],BLANKS,' '); CURSOR:=CURSOR+BLANKS+1 END; NOTEXTYET:=TRUE; END; END; PROCEDURE BACKUP; (* If the CH is a backspace then decrement cursor by 1. If this would result in backing over an or a blank compression code, then fall into the code for a (also changing the CH to for communication to the outer block) *) VAR PTR: PTRTYPE; BEGIN IF CH=CHR(DC1) THEN BEGIN GETLEADING; IF CHECK(LINESTART) THEN CURSOR:=LINESTART END ELSE IF (CH=CHR(BS)) AND NOT( (EBUF^[CURSOR-2]=CHR(DLE)) OR (EBUF^[CURSOR-1]=CHR(EOL)) ) THEN BEGIN IF CURSOR or equivalent *) CH:=CHR(DEL); (* Tell the CRT driver that the line has changed *) GETLEADING; IF CHECK(LINESTART-1) THEN CURSOR:=LINESTART-1; NOTEXTYET:=FALSE; (* thank you shawn! *) END END; PROCEDURE FIXUP; (* Convert the indentation spaces into blank compression codes, and move the current line around accordingly *) BEGIN (* First compress the current line *) EBUF^[CURSOR]:=CHR(EOL); (* Fool Getleading *) GETLEADING; IF BYTES >= 2 THEN (* OK to put in # as it stands *) MOVELEFT(EBUF^[STUFFSTART],EBUF^[LINESTART+2],CURSOR-STUFFSTART) ELSE IF CHECK(CURSOR+2-BYTES) THEN MOVERIGHT(EBUF^[STUFFSTART],EBUF^[STUFFSTART+2-BYTES],CURSOR-STUFFSTART) ELSE BEGIN OK:=FALSE; EXIT(FIXUP) END; CURSOR:=CURSOR-(BYTES-2); EBUF^[LINESTART]:=CHR(DLE); EBUF^[LINESTART+1]:=CHR(32+BLANKS); END; PROCEDURE INSERTCH; (* This procedure inserts a single character into the buffer. It also handles all of the control codes (EOL,BS,DEL) and buffer over- and under- flow conditions. INSERTCH is called by the CRT handler *) BEGIN REPEAT OK:=TRUE; (* No errors that invalidate the current character have occured *) CH:=GETCH; IF MAPTOCOMMAND(CH)=LEFT THEN CH:=CHR(BS); IF ORD(CH) IN [SP,HT,EOL,BS,DEL,ETX,ESC,DC1] THEN BEGIN (* and are handled in the body of insertit *) IF ORD(CH) IN [SP,HT] THEN SPACEOVER ELSE IF ORD(CH)=EOL THEN ENDLINE ELSE IF ORD(CH) IN [DC1,BS,DEL] THEN BACKUP; END ELSE BEGIN (* A character to insert! *) IF (CH<'!') OR (CH>'~') THEN CH:='?'; (* No non-printing characters *) IF NOTEXTYET THEN FIXUP; IF CHECK(CURSOR+1) AND OK THEN BEGIN NOTEXTYET:=FALSE; EBUF^[CURSOR]:=CH; CURSOR:=CURSOR+1 END; END; UNTIL OK; END; PROCEDURE POPDOWN; (* Displays CONTEXT, doing an implied scrollup if nec. *) BEGIN IF CLEARED THEN ERASETOEOL ELSE BEGIN CLEARED:=TRUE; CONTROL(ETOEOS) END; GOTOXY(RJUST,LINE); ERASETOEOL; WRITE(CHR(LF)); IF LINE=SCREENHEIGHT THEN BEGIN EXITPROMPT:=TRUE; LINE:=SCREENHEIGHT-1 END; WRITE(CONTEXT:EOLDIST); FIRSTLINE:=FALSE; (* Says that the whole screen has been affected. *) END; PROCEDURE WRITESP(CH:CHAR;HOWMANY:INTEGER); BEGIN IF X+HOWMANY<=SCREENWIDTH THEN WRITE(CH:HOWMANY); IF X+HOWMANY>=SCREENWIDTH THEN BEGIN GOTOXY(SCREENWIDTH,LINE); IF X+HOWMANY>SCREENWIDTH THEN BEGIN WRITE('!'); GOTOXY(SCREENWIDTH,LINE) END END; X:=MIN(SCREENWIDTH,X+HOWMANY) END; PROCEDURE CLEANSCREEN; (* Code to, if possible, only erase the line, otherwise clear the screen. Then call popdown *) BEGIN FIRSTLINE:=FALSE; IF CLEARED THEN BEGIN IF XSCREENHEIGHT THEN BEGIN LINE:=LINE-1; WRITELN; EXITPROMPT:=TRUE END; IF EOLDIST<>0 THEN POPDOWN END; PROCEDURE POPOV; (* When in filling mode, this procedure is called when a line is overflowed (X >= rightmargin). The word is scanned off and "popped" down to the next line. *) VAR WLENGTH: INTEGER; SAVE,PTR: PTRTYPE; WORD: PACKED ARRAY [0..MAXSW] OF CHAR; BEGIN IF NOTEXTYET THEN FIXUP; IF CH=' ' THEN BEGIN PTR:=CURSOR-1; WLENGTH:=0 END ELSE BEGIN PTR:=MAX(SCAN(-MAXCHAR,='-',EBUF^[CURSOR-1]), SCAN(-MAXCHAR,=' ',EBUF^[CURSOR-1]))+CURSOR-1; WLENGTH:=(CURSOR-PTR)-1; WITH PAGEZERO DO IF WLENGTH>=RMARGIN-LMARGIN THEN BEGIN WRITESP(CH,1); EXIT(POPOV) END; GOTOXY(X-WLENGTH+1,LINE); ERASETOEOL; MOVERIGHT(EBUF^[PTR+1],EBUF^[PTR+3],WLENGTH); MOVELEFT(EBUF^[PTR+3],WORD,WLENGTH) END; CURSOR:=CURSOR+2; EBUF^[PTR]:=CHR(EOL); EBUF^[PTR+1]:=CHR(DLE); WITH PAGEZERO DO IF AUTOINDENT THEN BEGIN SAVE:=CURSOR; (* Set blanks to the indentation of the line above *) CURSOR:=PTR; GETLEADING; CURSOR:=SAVE END ELSE BLANKS:=LMARGIN; EBUF^[PTR+2]:=CHR(BLANKS+32); CLEANSCREEN; X:=BLANKS; GOTOXY(X,LINE); WRITE(WORD:WLENGTH); X:=X+WLENGTH; NOTEXTYET:=FALSE END; BEGIN (* INSERT *) CLEARED:=FALSE; EOLDIST:=SCAN(MAXCHAR,=CHR(EOL),EBUF^[CURSOR]); MOVELEFT(EBUF^[CURSOR],CONTEXT[0],EOLDIST); RJUST:=SCREENWIDTH-EOLDIST; SLAMRIGHT; SAVEBUFCOUNT:=BUFCOUNT; PROMPTLINE:= ' Insert: Text { a char, a line} [ accepts, escapes]'; PROMPT; EXITPROMPT:=FALSE; NEEDPROMPT:=TRUE; LEFTPART:=CURSOR-1; NOTEXTYET:=FALSE; FINDXY(X,LINE); GOTOXY(X,LINE); ERASETOEOL; FIRSTLINE:=TRUE; IF EOLDIST<>0 THEN (* A context needs to be displayed *) IF RJUST>X THEN (* and it will fit on the current line ... *) BEGIN GOTOXY(RJUST,LINE); WRITE(CONTEXT:EOLDIST); GOTOXY(X,LINE) END ELSE (* and it won't fit on the current line *) BEGIN FIRSTLINE:=FALSE; CONTROL(ETOEOS);(* Clear the screen *) WRITELN; IF LINE=SCREENHEIGHT THEN BEGIN LINE:=SCREENHEIGHT-1; EXITPROMPT:=TRUE END; GOTOXY(RJUST,LINE+1); WRITE(CONTEXT:EOLDIST); GOTOXY(X,LINE) END; REPEAT INSERTCH; IF NOT (ORD(CH) IN [EOL,ETX,ESC,DEL,DC1]) THEN BEGIN IF TRANSLATE[CH]=LEFT THEN BEGIN IF X<=SCREENWIDTH THEN WRITE(CHR(BS),' ',CHR(BS)); X:=X-1 END ELSE IF CH=CHR(HT) THEN WRITESP(' ',SPACES) ELSE IF PAGEZERO.FILLING AND (X+1>=PAGEZERO.RMARGIN) THEN POPOV ELSE WRITESP(CH,1); IF NOT PAGEZERO.FILLING AND (X=SCREENWIDTH-8) AND (CH<>CHR(BS)) THEN WRITE(CHR(BELL)); IF (EOLDIST<>0) AND (X>=RJUST) AND FIRSTLINE THEN (*ran into context *) BEGIN POPDOWN; GOTOXY(X,LINE) END; END ELSE (* ch in [eol,etx,esc,del,dc1] *) BEGIN IF CH=CHR(EOL) THEN BEGIN CLEANSCREEN; X:=BLANKS; GOTOXY(X,LINE); END ELSE IF CH=CHR(DEL) THEN BEGIN IF LINE<=1 THEN (* Rubbed out all of what was on the screen *) BEGIN BUFCOUNT:=CURSOR+1; EBUF^[CURSOR]:=CHR(EOL); CENTERCURSOR(LINE,MIDDLE,TRUE); IF EOLDIST<>0 THEN POPDOWN; IF EXITPROMPT THEN BEGIN PROMPT; EXITPROMPT:=FALSE END END ELSE BEGIN GOTOXY(0,LINE); CLEARED:=FALSE; ERASETOEOL; LINE:=LINE-1 END; GETLEADING; X:=BLANKS-BYTES+CURSOR-LINESTART; GOTOXY(X,LINE) END ELSE IF CH=CHR(DC1) THEN BEGIN X:=0; GOTOXY(X,LINE); ERASETOEOL END; END; UNTIL CH IN [CHR(ETX),CHR(ESC)]; IF CH=CHR(ESC) THEN CURSOR:=LEFTPART+1; BUFCOUNT:=SAVEBUFCOUNT; WRAPUP; END;