FUNCTION LEADBLANKS(* (PTR: PTRTYPE; VAR BYTES: INTEGER): INTEGER *); (* On entry- PTR points to the beginning of a line On exit- function returns the number of leading blanks on that line. bytes has the offset into the line of the first non-blank character *) VAR OLDPTR: PTRTYPE; INDENT: INTEGER; BEGIN OLDPTR:=PTR; INDENT:=0; WHILE ORD(EBUF^[PTR]) IN [HT,SP,DLE] DO BEGIN IF EBUF^[PTR]=CHR(DLE) THEN BEGIN PTR:=PTR+1; INDENT:=INDENT+ORD(EBUF^[PTR])-32 END ELSE IF ORD(EBUF^[PTR])=SP THEN INDENT:=INDENT+1 ELSE (*HT*) INDENT:=((INDENT DIV 8)+1)*8; (* KLUDGE FOR COLUMNAR TAB! *) PTR:=PTR+1 END; BYTES:=PTR-OLDPTR; LEADBLANKS:=INDENT; END(*LEADBLANKS*); PROCEDURE REDISPLAY; (* Do a total update of the screen. Note that this code is partially a duplicate of lineout/upscreen for reasons of speed. This procedure is called only from centercursor *) VAR LINEDIST,EOLDIST,LINE: INTEGER; PTR: PTRTYPE; T: PACKED ARRAY [0..MAXSW] OF CHAR; BEGIN BLANKCRT(1); LINE:=1; PTR:=LINE1PTR; REPEAT BLANKS:=MIN(LEADBLANKS(PTR,BYTES),SCREENWIDTH); GOTOXY(BLANKS,LINE); PTR:=PTR+BYTES; EOLDIST:=SCAN(MAXCHAR,=CHR(EOL),EBUF^[PTR]); LINEDIST:=MAX(0,MIN(EOLDIST,SCREENWIDTH-BLANKS+1)); MOVELEFT(EBUF^[PTR],T[0],LINEDIST); IF EBUF^[PTR+LINEDIST]<>CHR(EOL) THEN (* Line truncation *) T[MAX(0,LINEDIST-1)]:='!'; WRITE(T:LINEDIST); PTR:=PTR+EOLDIST+1; LINE:=LINE+1 UNTIL (LINE>SCREENHEIGHT) OR (PTR>=BUFCOUNT) END; PROCEDURE CENTERCURSOR (*VAR LINE: INTEGER; LINESUP: INTEGER; NEWSCREEN: BOOLEAN*); (* Figure out if the cursor is still on the screen. If it is, and newscreen is false, then no redisplay is done. Otherwise an attempt is made to position the cursor at line "linesup". line is then updated to the actual line the cursor was forced to. *) VAR MARK: INTEGER; PTR: PTRTYPE; BEGIN IF EBUF^[CURSOR]=CHR(EOL) THEN PTR:=CURSOR ELSE PTR:=CURSOR+1; LINE:=0; REPEAT PTR:=PTR-1; PTR:=SCAN(-MAXCHAR,=CHR(EOL),EBUF^[PTR])+PTR; LINE:=LINE+1; IF LINE=LINESUP THEN MARK:=PTR; UNTIL (LINE>SCREENHEIGHT) OR ((LINE1PTR=PTR+1) AND NOT NEWSCREEN) OR (PTR<1); IF LINE>SCREENHEIGHT THEN (* Off the screen *) BEGIN LINE1PTR:=MARK+1; REDISPLAY; LINE:=LINESUP END ELSE IF LINE1PTR=PTR+1 THEN BEGIN IF NEWSCREEN THEN REDISPLAY END ELSE BEGIN LINE1PTR:=1; REDISPLAY END; END; PROCEDURE FINDXY(*VAR INDENT,LINE: INTEGER*); VAR I,LEAD: INTEGER; PTR,EOLPTR: PTRTYPE; BEGIN (* Place CRT cursor on the screen at the position corresponding to the logical cursor. *) LINE:=1; PTR:=LINE1PTR; EOLPTR:=SCAN(MAXCHAR,=CHR(EOL),EBUF^[PTR])+PTR; WHILE EOLPTR 1000 THEN OVERFLOW:=TRUE ELSE BEGIN N:=N*10+ORD(CH)-ORD('0'); CH:=GETCH END UNTIL (NOT (CH IN ['0'..'9'])) OR OVERFLOW; IF OVERFLOW THEN BEGIN ERROR('Repeatfactor > 10,000',NONFATAL); GETNUM:=0; END ELSE GETNUM:=N; COMMAND:=MAPTOCOMMAND(CH); (* Takes CH and maps it to a command *) END; PROCEDURE GETLEADING; BEGIN (* Sets: LINESTART ......... A pointer to the beginning of the line STUFFSTART ........ A pointer to the beginning of the text on the line BYTES ............. The number of bytes between LINESTART and STUFFSTART BLANKS ............ The indentation of the line *) LINESTART:=CURSOR; IF EBUF^[LINESTART]=CHR(EOL) THEN LINESTART:=LINESTART-1; (* for scan! *) LINESTART:=SCAN(-MAXCHAR,=CHR(EOL),EBUF^[LINESTART])+LINESTART+1; BLANKS:=LEADBLANKS(LINESTART,BYTES); STUFFSTART:=LINESTART+BYTES END (* GETLEADING *); FUNCTION OKTODEL (* (CURSOR,ANCHOR: PTRTYPE):BOOLEAN *) ; BEGIN IF ABS(CURSOR-ANCHOR)>(BUFSIZE-BUFCOUNT)+10 THEN BEGIN MSG:= 'There is no room to copy the deletion. Do you wish to delete anyway? (y/n)'; PUTMSG; IF UCLC(GETCH)='Y' THEN OKTODEL:=TRUE ELSE OKTODEL:=FALSE; END ELSE BEGIN (* COPYLINE is set by the caller *) COPYOK:=TRUE; COPYLENGTH:=ABS(CURSOR-ANCHOR); COPYSTART:=BUFSIZE-COPYLENGTH+1; MOVELEFT(EBUF^[MIN(CURSOR,ANCHOR)],EBUF^[COPYSTART],COPYLENGTH); OKTODEL:=TRUE END; END; PROCEDURE LINEOUT(*VAR PTR:PTRTYPE; BYTES,BLANKS,LINE:INTEGER*); (* Write a line out *) VAR LINEDIST,EOLDIST: INTEGER; T: PACKED ARRAY [0..MAXSW] OF CHAR; BEGIN GOTOXY(BLANKS,LINE); PTR:=PTR+BYTES; EOLDIST:=SCAN(MAXCHAR,=CHR(EOL),EBUF^[PTR]); LINEDIST:=MAX(0,MIN(EOLDIST,SCREENWIDTH-BLANKS+1)); MOVELEFT(EBUF^[PTR],T[0],LINEDIST); IF EBUF^[PTR+LINEDIST]<>CHR(EOL) THEN (* Line truncation *) BEGIN LINEDIST:=MAX(LINEDIST,1); T[LINEDIST-1]:='!'; END; WRITE(T:LINEDIST); PTR:=PTR+EOLDIST+1 END; PROCEDURE UPSCREEN(*FIRSTLINE,WHOLESCREEN: BOOLEAN; LINE: INTEGER*); (* Zap, Insert and Delete call this procedure to update (possibly partially) the screen. FIRSTLINE means only the line that the cursor is on need be updated. WHOLESCREEN means that everything must be updated. If neither of these is true then only the part of the screen that's after the cursor is updated *) VAR PTR: PTRTYPE; BEGIN (* Upscreen *) IF FIRSTLINE THEN BEGIN GETLEADING; GOTOXY(0,LINE); ERASETOEOL; (* Clean the line *) LINEOUT(LINESTART,BYTES,BLANKS,LINE) (* Just this line *) END ELSE IF WHOLESCREEN THEN CENTERCURSOR(TRASH,MIDDLE,TRUE) ELSE (* Only update the part of the screen after the cursor *) BEGIN GOTOXY(0,LINE); CONTROL(ETOEOS); GETLEADING; PTR:=LINESTART; REPEAT BLANKS:=MIN(LEADBLANKS(PTR,BYTES),SCREENWIDTH); LINEOUT(PTR,BYTES,BLANKS,LINE); (* Writes out the line at ptr *) LINE:=LINE+1 UNTIL (LINE>SCREENHEIGHT) OR (PTR>=BUFCOUNT) END; END; PROCEDURE READJUST(*CURSOR:PTRTYPE; DELTA: INTEGER*); (* if DELTA<0 then move all affected markers to CURSOR. Also adjust all markers >= CURSOR by DELTA *) VAR I: INTEGER; BEGIN WITH PAGEZERO DO FOR I:=0 TO COUNT-1 DO IF POFFSET[I]>=CURSOR THEN POFFSET[I]:=MAX(POFFSET[I]+DELTA,CURSOR); IF (COPYSTART>=CURSOR) AND (COPYSTART1) AND (EBUF^[STUFFSTART]<>RUNOFFCH) AND (EBUF^[STUFFSTART]<>CHR(EOL)) DO BEGIN CURSOR:=LINESTART-1; GETLEADING END; PTR:=MAX(1,CURSOR+1); X:=PARAMARGIN; END ELSE BEGIN PTR:=LINESTART; IF BLANKS=PARAMARGIN THEN X:=PARAMARGIN ELSE X:=LMARGIN END; CURSOR:=BUFSIZE-(BUFCOUNT-PTR)+1; (* Split the buffer *) MOVERIGHT(EBUF^[PTR],EBUF^[CURSOR],BUFCOUNT-PTR); (* Now dribble back the (rest of the) paragraph *) EBUF^[PTR]:=CHR(DLE); EBUF^[PTR+1]:=CHR(X+32); PTR:=PTR+2; EBUF^[CURSOR-1]:=CHR(EOL); (* sentinel for getleading *) DONE:=FALSE; REPEAT WHILE EBUF^[CURSOR] IN [CHR(HT),CHR(SP),CHR(DLE)] DO IF EBUF^[CURSOR]=CHR(DLE) THEN CURSOR:=CURSOR+2 ELSE CURSOR:=CURSOR+1; WPTR:=CURSOR; (* Skip over a token *) WHILE NOT (EBUF^[CURSOR] IN [CHR(EOL),' ','-']) DO CURSOR:=CURSOR+1; IF (EBUF^[CURSOR-1]='.') AND (EBUF^[CURSOR]=' ') AND (EBUF^[CURSOR+1]=' ') THEN CURSOR:=CURSOR+1; WLENGTH:=CURSOR-WPTR+1; (* Including the delimiter *) IF (X+WLENGTH>RMARGIN) OR (RMARGIN-LMARGIN+1<=WLENGTH) THEN BEGIN IF EBUF^[PTR-1]=' ' THEN PTR:=PTR-1; EBUF^[PTR]:=CHR(EOL); EBUF^[PTR+1]:=CHR(DLE); EBUF^[PTR+2]:=CHR(LMARGIN+32); PTR:=PTR+3; X:=LMARGIN END; CURSOR:=CURSOR+1; MOVELEFT(EBUF^[WPTR],EBUF^[PTR],WLENGTH); IF EBUF^[CURSOR-1]=CHR(EOL) THEN BEGIN IF EBUF^[CURSOR]=CHR(0) THEN DONE:=TRUE ELSE BEGIN GETLEADING; DONE:=(EBUF^[STUFFSTART]=CHR(EOL)) OR (EBUF^[STUFFSTART]=RUNOFFCH); (* The last transfer will move over the for the paragraph *) IF NOT DONE THEN EBUF^[PTR+WLENGTH-1]:=' '; END END; X:=X+WLENGTH; PTR:=PTR+WLENGTH; UNTIL DONE; READJUST(PARAPTR,(BUFSIZE-CURSOR+PTR+1)-BUFCOUNT); BUFCOUNT:=BUFSIZE-CURSOR+PTR+1; MOVELEFT(EBUF^[CURSOR],EBUF^[PTR],BUFSIZE-CURSOR+1); EBUF^[BUFCOUNT]:=CHR(0); CURSOR:=SAVE; GETLEADING; CURSOR:=MAX(CURSOR,STUFFSTART) END; END; PROCEDURE GETNAME(*MSG:STRING; VAR M:NAME*); VAR I: INTEGER; S: STRING; BEGIN NEEDPROMPT:=TRUE; HOME; ERASETOEOL; WRITE(MSG,' what marker? '); READLN(S); MOVELEFT(S[1],M[0],MIN(8,LENGTH(S))); FILLCHAR(M[LENGTH(S)],MAX(0,8-LENGTH(S)),' ') END;