{$B+} {Boolean complete evaluation on} {$I+} {I/O checking on} {$N-} {No numeric coprocessor} {$R-} {Range checking off} {$S-} {Stack checking on} {$V-} {Var String checking off} Uses Crt,Dos,Printer; Const MaxWidth = 128; RtMrg : Integer = 76; LeftM : Integer = 1; Wrap : Boolean = True; InSrt : Boolean = True; GoodColorCard : Boolean = True; {set false for IBM CGA} Type Line = String[MaxWidth]; LPtr = ^LineRec; LineRec = Record Last : LPtr; Data : Line; Next : LPtr; Clr : BYTE; End; ScreenLine = String[80]; String80 = String[80]; Word = String[24]; Var LWord : ScreenLine; { left margin spacer } Find ,Repl , InPut,OutPut : Word; Fore , Back, Attr : Byte; { text colors for Write} BaseOfScreen,Mode : LongInt; { used by FASTWRITE } WaitforRetrace : Boolean; { " " " } VidStatPort, VidModePort : LongInt; { " " " } ModePortData : Byte Absolute $40 : $65; { } SearchString, Replacement : ScreenLine; TextLine ,BlankLine : ScreenLine; FileFound, Finished ,Changed : Boolean; TabSet : Array [1..MaxWidth] Of Boolean; TextFile : Text; WorkFile : Text; Ln,LastLn,NextLn, FirstLn,EndLn : LPtr; MaxLines : Integer ; IBeg , IEnd : Integer ; BlockBeg, BlockEnd : LPtr; I , J, {cursor position: i = line, j = column} Len, {length of current line} NLines, {length of file} NBl, {number of buffer lines} Top, {first line on screen} Offset, K, N : Integer; Choice, Ch : Char; (*-------------------------------------------------------------------*) Function YN: Boolean; Begin Repeat Ch := ReadKey Until Ch In['y','Y','n','N']; If UpCase(Ch) = 'Y' Then YN := True Else YN := False; End; Procedure Beep; Begin Sound(800); Delay(400); NoSound; Delay(1000); End; Procedure Capitalize(var fname:word); Begin For J := 1 To Length(FName) Do FName[J] := UpCase(FName[J]); End; Procedure ReadFile; Var OvFlw : Boolean; InputLine : String[255]; Begin If ParamStr(1) = '' Then Begin Write('File to edit: '); ReadLn(Input); End Else InPut := ParamStr(1); Capitalize(Input); New(Ln); Ln^.Data := ''; FirstLn := Ln; EndLn := Ln; Assign(WorkFile,Input); {$I-} ReSet(WorkFile); {I+} If IoResult = 0 Then Begin OvFlw := False; MaxLines := MemAvail Div 12; If MaxLines < 0 Then MaxLines := 2730; NLines := 0; Write(' Reading file '); While Not (Eof(WorkFile) Or OvFlw) Do Begin ReadLn(WorkFile,InputLine); If Length(InputLine) > MaxWidth Then Begin WriteLn('File is too fat for this editor'); OvFlw := True; Delay(1000); End Else Begin Ln^.Data := InputLine; LastLn := Ln; New(Ln); Ln^.data := ''; Ln^.last := LastLn; LastLn^.Next := Ln; NLines := NLines + 1; If NLines > MaxLines Then Begin WriteLn('File is too long. Not enough memory'); OvFlw := True; Delay(1000); End; End; End; {not EOF} EndLn := Ln; If Not OvFlw Then FileFound := True; End {IOresult = 0} Else Begin Write('Can''t find this file. Is this a new file?'); If YN Then Begin FileFound := True; NLines := 1; New(Ln); Ln^.Data := ''; FirstLn^.Next := Ln; Ln^.Last := FirstLn; EndLn := Ln; End Else FileFound := False; End; Close(WorkFile); End; Procedure WriteFile; { save changes to file } Begin GotoXY(1,1); For J := 1 To 45 Do Write(' '); GotoXY(1,1); Write('Text was changed. Save? '); If YN Then Begin Write('as: '); ReadLn(OutPut); If OutPut = '' Then OutPut := Input; Capitalize(OutPut); GotoXY(40,1); WriteLn(' Writing to disk as ',OutPut); Assign(WorkFile,OutPut); ReWrite(WorkFile); Ln := EndLn^.Next; Repeat WriteLn(WorkFile,Ln^.Data); Ln := Ln^.Next Until Ln = EndLn; Close(WorkFile); End; End; {------------------------- FastWrite Routines -------------------------} Function Attribute(Foreground, Background : Byte) : Byte; {-Translates foreground and background colors into video attributes. "And 127" masks out the blink bit. Add 128 to the result to set it.} Begin Attribute := ((Background Shl 4) + Foreground) And 127; End; Function EgaInstalled : Boolean; {-Test for presence of the EGA. I have little idea how this works, but it does.} Begin Inline( $B8/$00/$12 { MOV AX,$1200} /$BB/$10/$00 { MOV BX,$10} /$B9/$FF/$FF { MOV CX,$FFFF} /$CD/$10 { INT $10} /$31/$C0 { XOR AX,AX} /$81/$F9/$FF/$FF { CMP CX,$FFFF} /$74/$01 { JE DONE} /$40 { INC AX} /$88/$46/$04 {DONE: MOV [BP+$04],AL} ); End; Procedure GetVideoMode; {-Video mode of 7 indicates mono display; all other modes are for color displays. This routine MUST be called before any of the screen writing routines are used!} Var Mode : Integer; Vid : Integer Absolute $40 : $63; Begin Inline( $B4/$0F {MOV AH,$F} /$CD/$10 {INT $10} /$30/$E4 {XOR AH,AH} /$89/$46/Row { MOV CH,[BP+>Row] ;CX = Row * 256} /$FE/$CD { DEC CH ;Row to 0..24 range} /$D1/$E9 { SHR CX,1 ;CX = Row * 128} /$89/$CF { MOV DI,CX ;Store in DI} /$D1/$EF { SHR DI,1 ;DI = Row * 64} /$D1/$EF { SHR DI,1 ;DI = Row * 32} /$01/$CF { ADD DI,CX ;DI = (Row * 160)} /$8B/$8E/>Col { MOV CX,[BP+>Col] ;CX = Column} /$49 { DEC CX ;Col to 0..79 range} /$D1/$E1 { SHL CX,1 ;Account for attribute bytes} /$01/$CF { ADD DI,CX ;DI = (Row * 160) + (Col * 2)} /$8E/$06/>BaseOfScreen { MOV ES,[>BaseOfScreen] ;ES:DI points to Base:Row,Col} /$8A/$0E/>WaitForRetrace{ MOV CL,[>WaitForRetrace] ;Grab this before changing DS} /$8C/$D2 { MOV DX,SS ;Move SS...} /$8E/$DA { MOV DS,DX ; into DS} /$8D/$B6/>St { LEA SI,[BP+>St] ;DS:SI points to St[0]} /$FC { CLD ;Set direction to forward} /$AC { LODSB ;AX = Length(St); DS:SI -> St[1]} /$91 { XCHG AX,CX ;CX = Length; AL = Wait} /$E3/$29 { JCXZ Exit ;If string empty, Exit} /$8A/$A6/>Attr { MOV AH,[BP+>Attr] ;AH = Attribute} /$D0/$D8 { RCR AL,1 ;If WaitForRetrace is False...} /$73/$1D { JNC NoWait ; use NoWait routine} /$BA/$DA/$03 { MOV DX,$03DA ;Point DX to CGA status port} /$AC {Next: LODSB ;Load next character into AL} { ; AH already has Attr} /$89/$C3 { MOV BX,AX ;Store video word in BX} /$FA { CLI ;No interrupts now} /$EC {WaitNoH: IN AL,DX ;Get 6845 status} /$A8/$08 { TEST AL,8 ;Check for vertical retrace} /$75/$09 { JNZ Store ; In progress? go} /$D0/$D8 { RCR AL,1 ;Else, wait for end of} /$72/$F7 { JC WaitNoH ; horizontal retrace} /$EC {WaitH: IN AL,DX ;Get 6845 status again} /$D0/$D8 { RCR AL,1 ;Wait for horizontal} /$73/$FB { JNC WaitH ; retrace} /$89/$D8 {Store: MOV AX,BX ;Move word back to AX...} /$AB { STOSW ; and then to screen} /$FB { STI ;Allow interrupts} /$E2/$E8 { LOOP Next ;Get next character} /$EB/$04 { JMP SHORT Exit ;Done} /$AC {NoWait: LODSB ;Load next character into AL} { ; AH already has Attr} /$AB { STOSW ;Move video word into place} /$E2/$FC { LOOP NoWait ;Get next character} /$1F {Exit: POP DS ;Restore DS} ); End; Procedure FastWriteV( Var St; Row, Col, Attr : Byte ); {-Works with string variables ONLY. (I made St an untyped parameter only to make this easier to use when type checking is on.) This is just FastWrite optimized for use with string Variables, for times when speed really matters.} Begin Inline( $1E { PUSH DS} /$31/$C0 { XOR AX,AX} /$88/$C1 { MOV CL,AL} /$8A/$6E/BaseOfScreen { MOV ES,[>BaseOfScreen]} /$8A/$0E/>WaitForRetrace{ MOV CL,[>WaitForRetrace]} /$C5/$76/= Offset Then Begin GotoXY(LeftM - Offset + 1, 2); Write('|'); End; If RtMrg >= Offset Then Begin GotoXY(RtMrg - Offset + 1, 2); Write('|'); End; TextColor( Fore ); TextBackGround( Back ); End; End; Procedure StatusLine; Begin Textline := BlankLine; Insert(' Line: Column:',TextLine,1); If Insrt Then Insert('Insert ',TextLine,26) Else Insert('OverWrite ',TextLine,25); If Wrap Then Insert(' WordWrap',TextLine,35) Else Insert(' NoWrap ',TextLine,35); Insert(' Workfile:',TextLine,47); Insert(Input,TextLine,58); FastWriteV(TextLine,1,1,Attr); RulerLine; End; Procedure WriteLine(Row,Attr:Byte); { direct write to screen } Var Len : Byte; { writes blanks where there is no text} Contents : ScreenLine; Begin TextLine := BlankLine; Contents := Copy(Ln^.Data,Offset,80); Len := Ord(Contents[0]); Insert(Contents,TextLine,1); If Len = 80 Then TextLine[80] := '+' Else If Len > 0 Then TextLine[80] := '<'; FastWriteV(TextLine,Row,1,Attr); End; Procedure Screen; { rewrites the bottom 23 lines } Var Row : Byte; TopLn : LPtr; Begin { makes sure i and ln are in register } Ln := EndLn^.Next; If Top > 1 Then For K := 2 To Top Do Ln := Ln^.Next; TopLn := Ln; For Row := 3 to 25 do Begin WriteLine(Row,Attr); If Ln <> EndLn Then Ln := Ln^.Next; End; Ln := TopLn; Row := I - Top; While Row > 0 do Begin Ln := Ln^.Next; Row := Row - 1; End; End; Procedure Help; Begin Window(1, 1, 80, 25); ClrScr; GetVideoMode; FastWrite('ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»', 1, 1, Attr ); FastWrite('º Window Editor -- by GDSOFT º', 2, 1, Attr ); FastWrite('º ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ º', 3, 1, Attr ); FastWrite('º ³ ^X line up ³ ³ ^S column left ³ ³ Alt-A Ascii ³ º', 4, 1, Attr ); FastWrite('º ³ ^E line down ³ ³ ^D column right ³ ³ Alt-B Back Color ³ º', 5, 1, Attr ); FastWrite('º ³ ^C page up ³ ³ ^PgUp file home ³ ³ Alt-C Copy Block ³ º', 6, 1, Attr ); FastWrite('º ³ ^R page down ³ ³ ^PgDn file end ³ ³ Alt-D Del Block ³ º', 7, 1, Attr ); FastWrite('º ³ ^K quit ³ ³ ^N insert line ³ ³ Alt-F Fore Color ³ º', 8, 1, Attr ); FastWrite('º ³ ^P set margins ³ ³ ^Y delete line ³ ³ Alt-G Goto Block ³ º', 9, 1, Attr ); FastWrite('º ³ ^BkSp delete word ³ ³ BkSp delete char ³ ³ Alt-M Move Block ³ º',10, 1, Attr ); FastWrite('º ³ ^V toggle ins ³ ³ Ins toggle insert ³ ³ Alt-N Clr Marks ³ º',11, 1, Attr ); FastWrite('º ³ ^W window dn ³ ³ ³ ³ Alt-S Beg Block ³ º',12, 1, Attr ); FastWrite('º ³ ^Z window up ³ ³ Del delete char ³ ³ Alt-T End Block ³ º',13, 1, Attr ); FastWrite('º ³ ^Home erase bol ³ ³ Home beg of line ³ ³ ³ º',14, 1, Attr ); FastWrite('º ³ ^End erase eol ³ ³ End end of line ³ ³ SPELLING CHECK ³ º',15, 1, Attr ); FastWrite('º ³ ^F next word ³ ³ Tab next tab stop ³ ³ Alt-0 Document ³ º',16, 1, Attr ); FastWrite('º ³ ^A prev word ³ ³ BTab last tab stop ³ ³ Alt-1 Word ³ º',17, 1, Attr ); FastWrite('º ³ F1 help ³ ³ F6 replace ³ ³ ³ º',18, 1, Attr ); FastWrite('º ³ F2 clear marks ³ ³ F7 page up ³ ³ ³ º',19, 1, Attr ); FastWrite('º ³ F3 quit ³ ³ F8 page down ³ ³ ³ º',20, 1, Attr ); FastWrite('º ³ F4 set margins ³ ³ F9 prev word ³ ³ ³ º',21, 1, Attr ); FastWrite('º ³ F5 search ³ ³ F10 next word ³ ³ ³ º',22, 1, Attr ); FastWrite('º ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º',23, 1, Attr ); FastWrite('º Press any key to return to your editing..... º',24, 1, Attr ); FastWrite('ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ',25, 1, Attr ); Repeat Until KeyPressed; Ch := ReadKey; StatusLine; Screen; End; Procedure PageUp; Begin If Top > 22 Then Begin Top := Top - 22; I := I - 22; End Else Begin I := I - Top + 1; Top := 1; End; Screen; End; Procedure PageDown; begin If Top <= (NLines - 44) Then Begin Top := Top + 22; I := I + 22; End Else If NLines > 22 Then Begin I := I - Top + NLines - 22; Top := NLines - 22; End; Screen; End; Procedure Cursor; { make sure the cursor is visible on the screen } Var ii,jj,chgd : Word; Shifted : Boolean; Begin Shifted := False; If I < 1 Then Begin I := 1; Ln := EndLn^.Next; End; If I > NLines Then Begin I := NLines; Ln := EndLn^.Last; End; If J < 1 Then J := 1; If J > MaxWidth Then J := MaxWidth; Len := Ord(Ln^.Data[0]); If ( J > Offset + 77 ) Then Begin Offset := 10 * ( J Div 10 ) - 59; Shifted := True; End; If J < Offset Then Begin Offset := 10 * ( ( J - 10 ) Div 10 ) + 1; Shifted := True; End; If I < Top Then Begin Top := I; Shifted := True; End; If I > Top + 22 Then Begin Top := I - 22; Shifted := True; End; If Shifted Then Begin RulerLine; Screen; End; Str(i:4,ii); Str(j:3,jj); If Changed Then Chgd := ' * ' Else Chgd := ' '; FastWriteV(ii,1,7,Attr); GetVideoMode; FastWriteV(jj,1,20,Attr); GetVideoMode; FastWriteV(Chgd,1,76,Attr); GetVideoMode; GotoXY( J - Offset + 1, i - top + 3); End; Procedure CursorLeft; Begin J := J - 1; If J < 1 Then Begin I := I - 1; If I < 1 Then Begin I := 1; J := 1; Ln := EndLn^.Next ; Exit; End; J := Length(Ln^.Last^.Data) + 1 ; Ln := Ln^.Last ; End End; Procedure CursorRight; Begin j := j + 1; if j > MaxWidth then Begin i := i + 1; If I > NLines then Begin I := NLines; Ln := EndLn^.Last ; End Else If I < NLines Then Ln := Ln^.Next ; J := 1; End; End; Procedure ParaForm; { set margins, wordwrap on/off } Begin GotoXY(1,1); ClrEol; Write('WordWrap? '); If YN Then Wrap := True Else Begin Wrap := False; LeftM := 1; LWord := ''; End; If Wrap Then Begin GotoXY(15,1); Write('Left margin: '); ReadLn(LeftM); LWord := ''; While Length(LWord) < LeftM - 1 Do LWord := LWord + ' '; RulerLine; Repeat GotoXY(35,1); Write('Right margin: '); ReadLn(RtMrg); Until RtMrg > LeftM + 24; End; ClrScr; StatusLine; Screen; End; { ParaForm } Procedure InsertLn(contents:line); {insert after current line} Begin New(NextLn); NextLn^.Data := Contents; NextLn^.Last := Ln; NextLn^.Next := Ln^.Next; Ln^.Next^.Last := NextLn; Ln^.Next := NextLn; NLines := NLines + 1; End; Procedure CutLine; { start new line after } Var More : Line; Begin More := Copy(Ln^.Data,J,Len-J+1); Delete(Ln^.Data,J,Len-J+1); InsertLn(LWord + More); i := i + 1; j := LeftM; Screen; End; Procedure WordWrap; Begin N := 0; Repeat J := J - 1; N := N + 1; Until (Ln^.Data[J] = ' ') Or (J = 1); J := J + 1; Len := Len + 1; CutLine; J := LeftM + N - 1 ; end; Procedure StackLine; { put current line on top of previous line } begin j := length(ln^.last^.data)+1; ln^.last^.data := ln^.last^.data + ln^.data; ln^.last^.next := ln^.next; { isolate current line } ln^.next^.last := ln^.last; Dispose(Ln); { and zap it} I := I - 1; NLines := NLines - 1; Screen; End; Procedure DeleteLine; Begin Ln^.Last^.Next := Ln^.Next; { isolate current line } Ln^.Next^.Last := Ln^.Last; Dispose(Ln); { and zap it} J := 1 ; I := I - 1; NLines := NLines - 1; Changed := True; StatusLine; Screen; End; Procedure DeleteEOL; Begin If J < MaxWidth Then Begin Ln^.Data := Copy ( Ln^.Data, 1 , J - 1 ) ; Changed := True; End; If J > 1 Then J := J - 1; StatusLine ; Screen ; End; Procedure DeleteBOL; Begin If J > 1 Then Begin Ln^.Data := Copy ( BlankLine, 1, J ) + Copy ( Ln^.Data, J + 1 , MaxWidth ) ; Changed := True; End; If J < MaxWidth Then J := J + 1; StatusLine ; Screen ; End; Procedure DeleteWord; Var EndW : Byte; Begin While (( Copy(Ln^.Data,J,1) <> ' ' ) And ( J > 0 )) Do J := J - 1 ; If J = 0 Then J := 1 ; EndW := J + 1; While (( Copy(Ln^.Data,EndW,1) <> ' ' ) And ( EndW < MaxWidth )) Do EndW := EndW + 1 ; If J = 1 Then Ln^.Data := Copy ( Ln^.Data , EndW + 1, MaxWidth ) Else Ln^.Data := Copy ( Ln^.Data, 1, J ) + Copy ( Ln^.Data , EndW + 1, MaxWidth ) ; Changed := True ; StatusLine ; Screen ; End; Procedure PrevWord; Begin (* if i am in a word then skip to the space *) While (Not ((Ln^.Data[j] = ' ') Or ( j >= Length(Ln^.Data) ))) And (( i <> 1 ) Or ( j <> 1 )) Do CursorLeft; (* find end of previous word *) While ((Ln^.Data[j] = ' ') Or ( j >= Length(Ln^.Data) )) And (( i <> 1 ) Or ( j <> 1 )) Do CursorLeft; (* find start of previous word *) While (Not ((Ln^.Data[j] = ' ') Or ( j >= Length(Ln^.Data) ))) And (( i <> 1 ) Or ( j <> 1 )) do CursorLeft; CursorRight; End; Procedure NextWord; Begin (* if i am in a word, then move to the whitespace *) while (not ((Ln^.Data[j] = ' ') or ( j >= length(Ln^.Data)))) and ( i < NLines ) do CursorRight; (* skip over the space to the other word *) while ((Ln^.Data[j] = ' ') or ( j >= Length(Ln^.Data))) and ( i < NLines ) do CursorRight; End; Procedure Tab; Begin If J < MaxWidth Then Begin Repeat J := J + 1; Until ( TabSet [J]= True ) Or ( J = MaxWidth ); End; End; Procedure BackTab; Begin If J > 1 Then Begin Repeat J := J - 1; Until ( TabSet [J]= True ) Or ( J = 1 ); End; End; Procedure Search; var Temp : ScreenLine; Pointer, Position : Integer; LocPtr , Location : Integer; TmpPtr : LPtr; Begin Window(1, 1, 80, 25); GotoXY(1, 1); ClrEol; Write('Search: Enter string: <',SearchString,'> '); Temp := ''; ReadLn(Temp); If Temp <> '' Then SearchString := Temp; If Length( SearchString ) = 0 Then Begin StatusLine; Screen; Exit; End; GotoXY(1,1); ClrEol; Write('Searching...'); NextWord; TmpPtr := Ln; LocPtr := J; For Location := I + 1 To NLines Do begin (* look for matches on this line *) Pointer := Pos (SearchString, Copy(Ln^.Data,LocPtr,MaxWidth)); (* if there was a match then get ready to print it *) If (Pointer > 0) Then Begin I := Location - 1 ; J := Pointer; StatusLine; Screen; Exit; End Else If Location <> NLines Then Begin Ln := Ln^.Next ; LocPtr := 1 ; End End; Window(1, 1, 80, 25); GotoXY(1, 1); ClrEol; Write('Search string not found. Press any key to exit...'); Repeat Until KeyPressed; Ch := ReadKey; Ln := TmpPtr ; StatusLine; Screen; End; Procedure Replace; Var Temp : ScreenLine; Pointer , Position : Integer; Location, Len : Integer; Begin Window(1, 1, 80, 25); GotoXY(1, 1); ClrEol; Write('Replace: Enter search string: <',SearchString,'> '); Temp := ''; ReadLn(Temp); If Temp <> '' Then SearchString := Temp; If Length(SearchString) = 0 Then Begin StatusLine; Screen; Exit; End; GotoXY(1, 1); ClrEol; Write('Replace: Enter replacement string: <',replacement,'> '); Temp := ''; ReadLn(Temp); if Temp <> '' Then Replacement := Temp; Len := Length (Replacement); Ln := EndLn^.Next ; I := 1 ; J := 1 ; GotoXY(1, 1); ClrEol; Write('Searching...'); For Location := 1 to NLines Do Begin (* look for matches on this line *) Position := Pos (SearchString, Ln^.Data ); (* if there was a match then get ready to print it *) While (Position > 0) Do Begin I := Location ; J := Position ; If Location > 8 Then Top := Location - 8 Else Top := 1 ; Screen ; TextColor( Back ); TextBackGround( Fore ); GotoXY( J - Offset + 1, I - Top + 3 ); Write ( SearchString ); TextColor( Fore ); TextBackGround( Back ); GotoXY(1, 1); ClrEol; Write('Replace (Y/N/ESC)? '); Ch := ReadKey; If Ord (Ch)= 27 Then Begin I := 1; J := 1; Ln := EndLn^.Next ; StatusLine; Screen; Exit; End; If Ch In ['y','Y'] Then Begin Ln^.Data := Copy (Ln^.Data, 1, Position - 1) + Replacement + Copy (Ln^.Data, Position + Length (SearchString), MaxWidth); Position := Pos (SearchString, Copy (Ln^.Data, Position + Len + 1,MaxWidth)) ; End Else Position := Pos (SearchString, Copy (Ln^.Data, Position + Length(SearchString) + 1,MaxWidth)) ; End; Ln := Ln^.Next ; GotoXY(1, 1); ClrEol; Write('Searching...'); End; Window(1, 1, 80, 25); GotoXY(1, 1); ClrEol; Write('End of replace. Press any key to exit...'); Repeat Until KeyPressed; Ch := ReadKey; Ln := EndLn^.Next ; I := 1 ; J := 1 ; StatusLine; Screen; End; Procedure ClearMarks ; Begin IBeg := 0 ; IEnd := 0 ; BlockBeg := Nil ; BlockEnd := Nil ; End; Procedure InsertMark( Mark : Char ); Begin If Mark = 'B' Then Begin If BlockBeg = Nil Then Begin BlockBeg := Ln ; IBeg := I ; End Else { BlockBeg Already Defined } Write(#7); End; If Mark = 'E' Then Begin If BlockEnd = Nil Then Begin BlockEnd := Ln ; IEnd := I ; End Else { BlockEnd Already Defined } Write(#7); End; End; Procedure GotoBlock ; Begin If BlockBeg <> Nil Then Begin Ln := BlockBeg ; I := IBeg; J := 1 ; If ( I >= 12 ) Then Top := I - 8; StatusLine ; Screen ; End; End; Procedure DeleteBlock; Var TPtr : LPtr; Begin If IEnd < IBeg Then Exit; Ln := BlockEnd ; I := IEnd ; Repeat TPtr := Ln^.Last; { save location of previous line } Ln^.Last^.Next := Ln^.Next; { isolate current line } Ln^.Next^.Last := Ln^.Last; Dispose(Ln); { and zap it} J := 1 ; I := I - 1; NLines := NLines - 1; Ln := TPtr; Until Ln = BlockBeg^.Last ; If I >= 12 Then Top := I - 8 Else Top := 1 ; Changed := True; ClearMarks; StatusLine; Screen; End; Procedure CopyBlock; var TPtr : LPtr ; Size : Integer; Begin If IEnd < IBeg then Exit; If (IBeg < I) And (I <= IEnd) Then Exit; Size := IEnd - IBeg - 1; { exclude markers } If Size = 0 Then Exit; If NLines + Size <= MaxLines Then Begin Repeat InsertLn (BlockEnd^.Data) ; BlockEnd := BlockEnd^.Last ; NLines := NLines + 1 ; Until BlockEnd = BlockBeg^.Last ; End Else Write(#7); Changed := True; ClearMarks; StatusLine; Screen; End; Procedure MoveBlock; Var Size : Integer; TPtr : LPtr; Begin If IEnd < IBeg Then Exit; If (IBeg <= I) And (I <= IEnd + 1) Then Exit; Size := IEnd - IBeg + 1; If NLines + Size <= MaxLines Then Begin TPtr := Ln^.Next ; BlockBeg^.Last^.Next := BlockEnd^.Next ; BlockEnd^.Next^.Last := BlockBeg^.Last ; Ln^.Next := BlockBeg ; TPtr^.Last := BlockEnd ; BlockBeg^.Last := Ln ; BlockEnd^.Next := TPtr ; End Else Write(#7); Changed := True; ClearMarks; StatusLine; Screen; End; Procedure WriteBlock ; Var TPtr : LPtr ; Begin If ((BlockBeg = Nil) Or (BlockEnd = Nil)) Then Exit ; If IBeg + 1 < IEnd Then Begin GotoXY(1,1); For J := 1 To 45 Do Write(' '); GotoXY(1,1); Write('Write Block To Disk ? '); If YN Then Begin Write('as: '); ReadLn(OutPut); If OutPut = '' Then OutPut := Input; Capitalize(OutPut); GotoXY(40,1); WriteLn(' Writing to disk as ',OutPut); Assign(WorkFile,OutPut); ReWrite(WorkFile); TPtr := BlockBeg; Repeat WriteLn(WorkFile,TPtr^.Data); TPtr := TPtr^.Next Until TPtr = BlockEnd; Close(WorkFile); End; End Else Write(#7); StatusLine ; Screen ; End; Procedure AddChar; { keyboard entry } begin Changed := True; While J > Len + 1 Do Begin Ln^.Data := Ln^.Data + ' ' ; Len := Len + 1 ; End; If J = Len + 1 Then Ln^.Data := Ln^.Data + Ch Else If InSrt Then Insert(Ch,Ln^.Data,J) Else Ln^.Data[J] := Ch; J := J + 1; WriteLine( I - Top + 3,Attr); If (J > RtMrg + 2) And Wrap Then WordWrap; End; Procedure Ascii; Var AscNo, Repeats, R : Integer; AsciiLine : ScreenLine; Begin AsciiLine := ''; GotoXY( 1, 1); ClrEol; Write('Enter ASCII code number: --- '); GotoXY(26,1); Readln(AscNo); GotoXY(1,1); Write('Enter number of repeats: -- '); GotoXY(26,1); ReadLn(Repeats); If Not(Repeats In [1..79]) Then Repeats := 1; If (AscNo > 0) And (AscNo < 256) Then Begin For R := 1 To Repeats Do Begin Ch := Chr(AscNo); AsciiLine := AsciiLine + Ch ; End; End; While J > Length(Ln^.Data) + 1 Do Begin Ln^.Data := Ln^.Data + ' ' ; Len := Len + 1 ; End; J := J - 1; If J = Length(Ln^.Data) + 1 Then Ln^.Data := Ln^.Data + AsciiLine Else If InSrt Then Insert(AsciiLine,Ln^.Data,J) Else Ln^.Data := Copy(Ln^.Data,1,J) + AsciiLine + Copy(Ln^.Data,J + Length(AsciiLine),128); Changed := True; StatusLine; Screen; End; Procedure Leave; Var Trash : Char; Begin VideoOff; Repeat Until KeyPressed; Trash := ReadKey; If (Trash = #0) And (KeyPressed) Then Trash := ReadKey; VideoOn; End; Procedure Colors; Begin Case Ch Of #48 : Back := (Back + 1) Mod 8; #33 : Fore := (Fore + 1) Mod 16; End; Attr := Attribute( Fore, Back ); StatusLine; Screen; End; Procedure Command; Begin If Ch = #0 Then If KeyPressed Then Ch := ReadKey; { keypad input } Case Ch Of {alt 1} 'x' : Begin { do something useful here } End; {alt A} #30 : Ascii; {alt B, alt F} #48,#33 : If Mode <> 7 Then Colors; {alt C} #46 : CopyBlock; {alt D} #32 : DeleteBlock; {alt G} #34 : GotoBlock; {alt H} #35 : Help; {alt K} #37 : ; {alt L} #38 : Leave; {alt M} #50 : MoveBlock; {alt N} #49 : ClearMarks; {alt S} #31 : InsertMark('B'); {alt T} #20 : InsertMark('E'); {alt W} #17 : WriteBlock; {alt X} #45 : Finished := True; {tab} #9 : Tab; {bktab} #15 : BackTab; {F1} #59 : Help; {F2} #60 : ClearMarks; {F3} #61 : Finished := True; {F4} #62 : ParaForm ; {F5} #63 : Search ; {F6} #64 : Replace; {F7} #65 : PageUp ; {F8} #66 : PageDown; {F9} #67 : PrevWord; {F10} #68 : NextWord; {home} #71 : J := LeftM; {end } #79 : J := Len + 1; {^home} #119 : DeleteBOL; {^end } #117 : DeleteEOL; {^A} #116,#1 : PrevWord; {^D} #77, #4 : J := J + 1; {^S} #75,#19 : If J > 1 Then J := J - 1; {^E} #72, #5 : If I > 1 Then Begin I := I - 1; Ln := Ln^.Last; End; {^F} #115,#6 : NextWord; {^X} #80,#24 : If I < NLines Then Begin I := I + 1; Ln := Ln^.Next; End; {del}#83, #7 : Begin Delete(Ln^.Data,J,1); WriteLine(I - Top + 3,Attr); End; { <-- } #8 : If J = 1 Then StackLine Else Begin J := J - 1; Delete(Ln^.Data,J,1); Cursor; WriteLine(i - Top + 3,Attr); End; {^<--} #127 : DeleteWord; {Enter} #13 : Begin If InSrt Then Begin If J = Len Then J := J + 1; CutLine; End Else Begin I := I + 1 ; J := 1 ; Ln^ := Ln^.Next^ End; End; {^R} #73,#18 : PageUp; {^C} #81, #3 : PageDown; {^PgUp} #132 : Begin I := 1; Top := 1; Ln := FirstLn; Screen; End; {^PgDn} #118 : Begin I := NLines; Top := NLines - 22; Ln := EndLn; Screen; End; {^Y} #25 : DeleteLine; {^N} #14 : Begin Ln := Ln^.Last; InsertLn(''); Screen; End; {Ins}#22,#82 : Begin If InSrt Then InSrt := False Else InSrt := True; StatusLine; End; {^P} #16 : ParaForm; {^W} #23 : If Top > 1 Then Begin Top := Top - 1; I := I - 1; Screen; End; {^Z} #26 : If Top < NLines + 22 Then Begin Top := Top + 1; I := I + 1; Screen; End; {^K} #27,#11 : Finished := True; Else Begin GotoXY(1,1); WriteLn('****** COMMAND NOT RECOGNIZED ****** '); Beep; StatusLine; End; End; {case} End; Begin {Main} CheckBreak := TRUE; DirectVideo := TRUE; ClearMarks ; GetVideoMode; IF BaseOfScreen = $B000 Then Begin Fore := White; Back := Black; End Else Begin Fore := White; { make these whatever you want } Back := Black; End; Attr := Attribute( Fore, Back ); TextColor( Fore ); TextBackground( Back ); ClrScr; BlankLine := ''; For J := 1 To 80 Do BlankLine := BlankLine + ' '; For I := 1 To MaxWidth Do TabSet[I]:=( I Mod 8 ) = 1; FileFound := False; ReadFile; If FileFound Then Begin FirstLn^.Last := EndLn ; EndLn^.Next := FirstLn ; { close chain, endless loop } J := 1; I := 1 ; Top := 1; Offset := 1 ; Find := '.'; Repl := ''; Nbl := 0; Lword := ''; SearchString := ''; Finished := False; Replacement := ''; Changed := False; ClrScr; StatusLine; Screen; Repeat Cursor; Ch := ReadKey; Case Ch Of #0..#31,#127 : Command; Else AddChar; End; Until Finished; If Changed Then WriteFile; End; {FileFound} TextAttr := 7; ClrScr; End.