(* Improved DOS MORE, derived from R A M van Geel's SHOW.PAS of Nov 1994, but now very heavily fiddled with by JRS. If ParamCount = 0 then it shows Standard Input { try C:\> DIR | SHOWER } else if parameter = /? then it shows short Help else it shows that file. NOT restricted to 80 cols * 25 rows, colour, page 0, screen. If the whole file cannot be loaded, the border goes red. Layout is by JRS's program CLEAN-TP.PAS. Compile with TP7/BP7 to REAL or PROTECTED mode; test on empty, normal, vast input. In PROTECTED, it will need RTM.EXE & DPMI16BI.OVL, or subs. In the display, the following effects occur for specific characters : #0 ^@ NUL '' shows as Space. #7 ^G BEL '' is ignored. #8 ^H BS '' removes the previous character of the line. #9 ^I TAB ' ' is expanded. #10 ^J LF (when without #13 ^M CR) does LF, but could be better handled? #255 $FF 'ÿ' shows as Space. The effect of #27 ^[ ESC with ANSI.SYS is not considered. Output is of original input, apart for truncation to 255 chars/line. Outputs "Y" "Z" differ in what they leave on the screen, unredirected. J R Stockton, www.merlyn.demon.co.uk : Home, Surrey, UK. 94/12/13++ - RvG may use this with acknowledgement only in the source-code. *) (* Derived from an original POSTed, as SHOW.PAS, headed : From: R.A.M.vGeel@kub.nl (GEEL R.A.M.VAN) Subject: Re: scrolling Date: Wed, 02 Nov 1994 13:04 MET Wrote this as an alternative for the (horrible) type|more command. Hope it helps Rob van Geel *) {-000----------------------------------------TEST--------------------------------------} {-001-was-very-long-line---that-breaks-CLEAN-TP--------------------------------} { 1 2 3 4 5 6 7 8 9} {123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890} {$M 2048, 1024, 655360} {$X+} program SHOWER {$IFDEF WINDOWS} Fail {$ENDIF} ; uses {$IFDEF MSDOS} {for SetMemTop} Memory, {$ENDIF} Dos, Crt { will need new Crt or patch for PC>=200MHz; Crt is essential here }; const MsgNone = 0 ; MsgNoClose = 10 ; MsgNoFile = 2 ; MsgNoDrive = 152 ; MsgHelp = 250 ; (* procedure Border(const Hue : word) ; begin asm mov AH,0Bh ; mov BX,Hue ; int 10h end end {Border} ; *) procedure SetBorder(Colour : byte) ; assembler ; asm mov AH,0Bh ; mov BH,00h ; MOV BL,[Colour] ; int 10h end {SetBorder} ; function GetBorder : byte ; assembler ; asm mov AX,1008h ; int 10h ; mov AL,BH end {GetBorder} ; type PNewLine = ^NewLine ; NewLine = record Next, Prev : PNewLine ; No : longint ; PLine : ^string end ; TFiler = object FileName : PathStr ; Buf : array [0..4095] of char ; constructor Init ; procedure DoMsg(const MsgNumber : byte) ; virtual ; function OpenAFiler : byte ; virtual ; function CloseFiler : byte ; virtual ; destructor Done ; virtual ; end {TFiler} ; TShower = object(TFiler) SaveMode : word ; PSave, PShow : pointer ; CurSize, ScreenSize : word ; FstCol, MaxL, Xcur, Ycur : byte ; First, ToP : PNewLine ; Amount, Last : longint ; Sk : string ; Cmd : char ; Bord : byte ; constructor Init ; procedure CursorOn ; virtual ; procedure NoCursor ; virtual ; procedure SaveScreen ; virtual ; procedure RestoreScr ; virtual ; procedure DoMsg(const MsgNumber : byte) ; virtual ; procedure GetInput ; virtual ; procedure ShowText ; virtual ; procedure WaitShow ; virtual ; procedure UpDateText ; virtual ; function UpdatePointer(Change : longint) : boolean ; virtual ; function StepPointer : boolean ; virtual ; function Sought(P : PNewLine) : boolean ; virtual ; procedure Run ; virtual ; procedure StandOut ; virtual ; destructor Done ; virtual ; end {TShower} ; constructor TFiler.Init ; begin FileName := ParamStr(1) ; if ParamStr(1)='/?' then begin DoMsg(MsgHelp) ; HALT(1) end ; DoMsg(OpenAFiler) end {TFiler.Init} ; procedure TFiler.DoMsg(const MsgNumber : byte); begin case MsgNumber of MsgNoFile : begin Writeln(FileName, ' not found') ; HALT(1) end ; MsgNoClose : Writeln('Could not close file') ; MsgNoDrive : begin Writeln('Drive not ready') ; HALT(1) end ; end {case} ; end {TFiler.DoMsg} ; function TFiler.OpenAFiler : byte ; begin Assign(Input, FileName) ; SetTextBuf(Input, Buf) ; {$I-} Reset(Input) {$I+} ; OpenAFiler := IOResult end {TFiler.OpenAFiler} ; function TFiler.CloseFiler : byte ; begin {$I-} Close(Input) {$I+} ; CloseFiler := IOResult end {TFiler.CloseFiler} ; destructor TFiler.Done ; begin DoMsg(CloseFiler) end {TFiler.Done} ; var ScrCols, ScrPage, ScrRows : byte ; constructor TShower.Init ; var Sg : word ; begin inherited Init ; {$IFDEF OLD} Bord := GetBorder ; SaveMode := LastMode ; ScrCols := Succ(Lo(WindMax)) ; ScrRows := Succ(Hi(WindMax)) ; asm mov AH,0Fh ; int 10h ; mov ScrPage,BH end ; Inc(WindMax) { Prevents screen scroll after writing to bottom right corner: see The Pascal Magazine #4 p.28 col.2 by Bob Swart } ; ScreenSize := 2*ScrCols*ScrRows ; if LastMode=Mono then Sg := SegB000 else Sg := SegB800 ; (* ThisMode ? *) PShow := Ptr(Sg, ScrPage*ScreenSize) ; SaveScreen ; GetInput ; NoCursor ; FstCol := 1 ; Amount := +1 ; ShowText ; {$ELSE} Bord := GetBorder ; SaveMode := LastMode ; if {ThisMode} Mem[Seg0040:$49]=Mono then Sg := SegB000 else Sg := SegB800 ; (* ThisMode ? *) asm mov AH,0Fh ; int 10h ; mov ScrPage,BH end ; { ScrCols := Succ(Lo(WindMax)) ; ScrRows := Succ(Hi(WindMax)) ; } ScrCols := MemW[Seg0040:$4A] ; ScrRows := Succ(Mem[Seg0040:$84]) ; Inc(WindMax) { Prevents screen scroll after writing to bottom right corner: see The Pascal Magazine #4 p.28 col.2 by Bob Swart } ; ScreenSize := 2*ScrCols*ScrRows ; PShow := Ptr(Sg, ScrPage*ScreenSize) ; SaveScreen ; GetInput ; NoCursor ; FstCol := 1 ; Amount := +1 ; ShowText ; {$ENDIF} end {TShower.Init} ; procedure TShower.NoCursor ; var S : word ; begin asm mov AH,03h ; mov BH,0 ; int 10h ; mov S,CX ; mov AH,01h ; mov BH,0 ; mov CX,2000h ; int 10h end ; CurSize := S end {TShower.NoCursor} ; procedure TShower.CursorOn ; var S : word ; begin S := CurSize ; asm mov ah,01h ; mov bh,0 ; mov cx,S ; int 10h end ; end {TShower.CursorOn} ; procedure TShower.SaveScreen; begin GetMem(PSave, ScreenSize) ; Move(PShow^, PSave^, ScreenSize) ; Xcur := WhereX ; Ycur := WhereY end {TShower.SaveScreen} ; procedure TShower.RestoreScr ; begin Move(PSave^, PShow^, ScreenSize) ; FreeMem(PSave, ScreenSize) ; GoToXY(Xcur, Ycur) end {TShower.RestoreScr} ; procedure TShower.DoMsg(const MsgNumber : byte); begin if MsgNumber=MsgHelp then begin Writeln('* SHOWER (c) 1994..7 Robert van Geel / John Stockton *') ; Writeln( 'Mode: ' + {$IFDEF MSDOS} 'MSDOS' {$ENDIF} {$IFDEF DPMI} 'DPMI' {$ENDIF} + '; ' + 'Usage: [|] SHOWER [] [|]'^M^J^J, 'Help : ?.'^M^J + 'Shift: Up Dn, PgUp PgDn, ^PgUp ^PgDn; Left Right tab TAB Home End .'^M^J + 'Speed: ^Left ^Right, Space.'^M^J + 'Saved: ^Home.'^M^J + 'Lines: H/L 25/50.'^M^J + 'Seeks: S... N, F B.'^M^J + 'Exits: ![...], Escape/X, Y, Z.'^J) end else inherited DoMsg(MsgNumber) ; end {TShower.DoMsg} ; function TShower.UpdatePointer(Change : longint) : boolean ; begin UpdatePointer := false ; while (Change>0) and (ToP^.No<=Last-ScrRows) do begin UpdatePointer := true ; ToP := ToP^.Next ; Dec(Change) end ; while (Change<0) and (ToP^.No>1) do begin UpdatePointer := true ; ToP := ToP^.Prev ; Inc(Change) end ; end {TShower.UpdatePointer} ; function TShower.StepPointer : boolean ; const By : array [boolean] of shortint = (-1, +1) ; begin StepPointer := UpDatePointer(By[Amount>0]) end {TShower.StepPointer} ; function TShower.Sought(P : PNewLine) : boolean ; begin Sought := Pos(Sk, P^.PLine^)<>0 end {TShower.Sought} ; procedure TShower.UpDateText ; var Written : byte ; Tmpy : PNewLine ; S : string ; B : byte ; {$IFDEF OK} const S7 = ' ' ; {$ELSE} C : char ; {$ENDIF} begin MaxL := 0 ; Written := 0 ; GoToXY(1, 1) ; Tmpy := ToP ; if Assigned(First) then while Written#0 then Dec(S[0]) ; ^I : repeat S := S + #32 until (Length(S) mod 8)=0 ; { ^J : ? } else S := S + C ; end {C} ; end {B} ; {$ENDIF} if Length(S)>MaxL then MaxL := Length(S) ; Write(Copy(S, FstCol, ScrCols)) ; end ; LowVideo ; if WhereX<=ScrCols then ClrEol ; Inc(Written) ; if Written1 then begin Dec(FstCol) ; UpDateText end {Left} ; #77 : if FstCol<255 then begin Inc(FstCol) ; UpDateText end {Right} ; #115 : Slowness := Slowness + Slowness div 3 {Ctrl-left} ; #116 : Slowness := Slowness - Slowness div 4 {Ctrl-right} ; #15 : begin for K := #1 to #8 do if FstCol>1 then Dec(FstCol) ; UpDateText end {Shift-Tab} ; #45 : BREAK {Alt-X : Quit} ; else Write(^G) end {case ReadKey} ; ^I : begin for K := #1 to #8 do if FstCol<255 then Inc(FstCol) ; UpDateText end {Tab} ; ^M : ScrollBy := Amount ; '!' : begin Cd := '' ; repeat K := ReadKey ; if K=#13 then BREAK ; Cd := Cd+K until false ; CursorOn ; ClrScr ; if Cd='' then Write('Type EXIT to return to SHOWER') else Cd := ' /C '+Cd ; SwapVectors ; Exec(GetEnv('COMSPEC'), 'CON'+Cd) ; SwapVectors ; if Cd>'' then WaitShow else ShowText ; NoCursor end {Push-to-DOS} ; '?' : begin ClrScr ; DoMsg(MsgHelp) ; Write('File: "', FileName, '", Seek "', Sk, '" ', Ch[Amount>0]) ; if Assigned(Top) then Write(', Col ', FstCol, ', Line ', ToP^.No, '/', Last) ; WaitShow end {info} ; 'B' : if Amount>0 then Amount := -Amount {Backwards gear} ; 'F' : if Amount<0 then Amount := -Amount {Forwards gear} ; 'H','L' : begin TextMode(LastMode xor Font8x8) ; ScrCols := Succ(Lo(WindMax)) ; ScrRows := Succ(Hi(WindMax)) ; Inc(WindMax) ; NoCursor ; ShowText end ; 'N' : if Sk>'' then begin while StepPointer and (not Sought(ToP)) do ; ShowText end {Next match} ; 'S' : begin Sk := '' ; repeat K := ReadKey ; if K=#13 then BREAK ; Sk := Sk+K until false ; if Sk>'' then while (not Sought(ToP)) and StepPointer do ; ShowText end {Seek exact match} ; 'X', #27 : BREAK {X Esc: Quit} ; 'Y' : begin SetBorder(Magenta) ; StandOut ; BREAK end ; 'Z' : begin SetBorder(Green) ; RestoreScr ; StandOut ; BREAK end ; #32 : begin Auto := not Auto ; if Auto then ScrollBy := Amount end ; else Write(^G) end {case Cmd} ; end {KeyPressed} ; if ScrollBy<>0 then begin Amount := ScrollBy ; if Assigned(ToP) and UpdatePointer(ScrollBy) then UpDateText else Auto := false ; end ; if Auto then Delay(Slowness) else ScrollBy := 0 ; until false ; end {TShower.Run} ; procedure TShower.GetInput ; var Pold, Pnew : PNewLine ; TmpStr : string ; begin SetBorder(Blue) ; Pold := NIL ; {Lest no input:} First := NIL ; Pnew := NIL ; while not EoF(Input) do begin if MaxAvail>=SizeOf(Pnew)+SizeOf(string) then New(PNew) else begin SetBorder(Red) ; BREAK end ; if Assigned(Pold) then begin Pold^.Next := Pnew ; Pnew^.No := Succ(Pold^.No) end else begin First := Pnew ; Pnew^.No := 1 end ; with Pnew^ do begin Prev := Pold ; Readln(Input, TmpStr) { Truncate at 255 } ; GetMem(PLine, Length(TmpStr)+1) { At least enough room } ; PLine^ := TmpStr end {Pnew^} ; Pold := Pnew ; end {N EoF} ; if Assigned(Pnew) then with Pnew^ do begin Next := NIL ; Last := No end ; ToP := First ; {$IFDEF MSDOS} { Free heap for Exec : see Brian Long, The Borland Pascal Problem Solver, pp.48 } SetMemTop(HeapPtr) ; (* Write('Freed ', AbAd(HeapEnd)-AbAd(HeapPtr), '':3) ; HeapEnd := HeapPtr ; *) {$ELSE} { DPMI : RTM frees Heap } {$ENDIF} end {TShower.GetInput} ; procedure TShower.StandOut ; var X : PNewLine ; begin Write(^M) ; Assign(Output, '') ; Rewrite(Output) ; X := First ; while Assigned(X) do begin Writeln(X^.PLine^) ; X := X^.Next end ; Close(Output) end {TShower.StandOut} ; destructor TShower.Done ; var X : PNewLine ; begin SetBorder(Bord) {?} ; inherited Done ; while Assigned(First) do begin X := First ; with X^ do begin FreeMem(PLine, Length(PLine^)+1) ; First := Next end ; Dispose(X) end {Assigned} ; if Cmd<>'Z' then RestoreScr ; Dec(WindMax) ; TextMode(SaveMode) ; CursorOn ; end {TShower.Done} ; var AShower : TShower ; BEGIN {$IFDEF DEBUG} {$IFDEF DPMI} HeapLimit := 0 {$ENDIF} {$ENDIF} ; with AShower do begin Init ; Run ; Done end ; END. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9