home *** CD-ROM | disk | FTP | other *** search
- {$C-}
-
- PROGRAM browse;
-
- {bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}
-
- {*************************************************************************}
- {* Copyright (c) Kim Kokkonen, TurboPower Software, 1985 *}
- {* Released to the public domain for personal, non-commercial use only *}
- {*************************************************************************}
-
- {Source: Kim Kokkonen's disk 1/86
- revisions by [SD]
- * 1986 *
- - 02/27 : read cmd line param for file name; use cursor pad keys; F1, F6
- - 03/01 : force user enter filename if file not found
- }
-
-
- {.F-}
- {
- --- IBM PC SPECIFIC ---
- BROWSE through two files simultaneously in two independent windows.
-
- writes directly to video memory, but with timing interlocks for c/g card.
- keys are set up to resemble WordStar cursor movements.
- see GETKEY to do keyboard customization.
- requires Turbo version 3.0 to compile as it stands.
- set min/max heap=$200/$200 paragraphs.
- written 8/2/85, Kim Kokkonen, 408-378-3672, CompuServe [72457,2131]
- updated 10/3/85 for faster video writes.
-
- FEATURES:
- filenames may include drive and path
- unlimited size files (or 32767 lines of 199 chars each, anyway)
- two circular RAM buffers each of 127 text lines paged from disk
- full forward and reverse scrolling at high speed
- horizontal scrolling
- synchronized windows mode
- pop-up help (type ^H for help)
- seek to line number
- search for strings (forward, uppercase modes only)
- invoke DOS process and return to place in BROWSE
- (requires ~96K free RAM at entry to BROWSE to invoke DOS)
- }
- {.F+}
-
- CONST
- {* NOTE: 127 lines * 199 char/line = 25273 chars }
- {*} Version : string[30] = '0.0a-PC Oct. 3, 1985 [SD 3/86]';
- LineSize = 199; {max line length stored, longer lines truncated}
- BufSize = 140; {lines of text (-1) in each textbuffer; orig=127}
- LinAvail = 32; {lines to always keep available at top of buffer}
- slines = 11; {number of lines (-1) in each window}
- WindColor = 15; {video attribute to use in text windows}
- GoodColorCard = True; {set false for IBM CGA, which requires
- timing interlocks to avoid snow on screen.
- Compaq graphics card among others allows
- this constant to be TRUE, and faster as a
- result. GoodColorCard is ignored if mono
- adapter is in use.}
- TYPE
- Window = 0..1;
- PathString = STRING[64];
- TextFile = Text[1024];
- LineBuffer = STRING[LineSize];
- ByteBuffer = ARRAY[0..LineSize] OF Byte;
- TextBuffer = ARRAY[0..BufSize] OF LineBuffer;
- TwoText = ARRAY[Window] OF TextFile;
- TwoBuffer = ARRAY[Window] OF TextBuffer;
- TwoPath = ARRAY[Window] OF PathString;
- TwoState = ARRAY[Window] OF Boolean;
- TwoInt = ARRAY[Window] OF Integer;
- FullScreen = ARRAY[1..4000] OF Byte;
- regpack = RECORD
- CASE Integer OF
- 1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
- 2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
- END;
-
- VAR
- f : TwoText;
- b : TwoBuffer;
- p : TwoPath;
- NotPadded, s : TwoState;
- LinNum, OldPtr, BotPtr, TopPtr, BufPtr, OldEdge, LeftEdge : TwoInt;
- SearchString : LineBuffer;
- SeekNumber : Integer;
-
- {watch out -- the following l, bl, len, reg are used at all scope levels}
- l : LineBuffer;
- bl : ByteBuffer ABSOLUTE l;
- len : Byte ABSOLUTE l;
- reg : regpack;
-
- TmpWind, N : Window; {which window we are in}
- Bufmod, CursorType, VidStatPort, VidModePort, ScreenSeg : Integer;
- SavScr : FullScreen;
- ch : Byte;
- NoWait, Synced : Boolean;
- {BIOS stores most recent video mode select port value here}
- ModePortData : Byte ABSOLUTE $40 : $65;
-
- {*} Use_Params : BOOLEAN;
-
- PROCEDURE CursorOn(CursorType : Integer);
- {restore the stored cursor}
- BEGIN
- reg.cx := CursorType;
- reg.ah := 1;
- Intr($10, reg);
- END; {cursoron}
-
- PROCEDURE CursorOff(VAR CursorType : Integer);
- {save the current cursor and turn off the cursor}
- VAR
- DOScursor : Integer ABSOLUTE $40 : $60;
- BEGIN
- CursorType := DOScursor;
- reg.ch := $20;
- reg.ah := 1;
- Intr($10, reg);
- END; {cursoroff}
-
- FUNCTION which_screen(VAR CursorType, VidStatPort, VidModePort : Integer)
- : Integer;
- {-determines which screen TURBO is writing to}
- {-and gets a default cursor type and video port}
- VAR
- {holds video controller port base address}
- vid : Integer ABSOLUTE $40 : $63;
- BEGIN
- GoToXY(1, 1);
- Mem[$B000 : 0] := 0;
- Mem[$B800 : 0] := 0;
- Write(' ');
- IF Mem[$B000 : 0] = $20 THEN BEGIN
- {monochrome adapter}
- which_screen := $B000;
- CursorType := $B0C;
- NoWait := True;
- END ELSE BEGIN
- {color/graphics adapter}
- which_screen := $B800;
- CursorType := $607;
- NoWait := False;
- END;
- VidStatPort := vid+6; {video status port for either card}
- VidModePort := vid+4; {video mode port for either card}
- NoWait := NoWait OR GoodColorCard;
- END; {which_screen}
-
- PROCEDURE DrawCenterBar(i : Byte);
- {-center bar holds context sensitive "prompts"}
- BEGIN
- GoToXY(1, 13);
- IF i = 1 THEN
- Write('═══════════════════════════════════════════════════════════════════════════════')
- ELSE IF i = 2 THEN
- { Write('═════════════════════════════ Press ^H for Help ═══════════════════════════════')}
- {*} Write('══════════════════════════ Press F1 or ^H for Help ════════════════════════════')
- ELSE IF i = 3 THEN
- Write('══════════════════ Searches are "Forward, Uppercase" only ═════════════════════');
- END; {drawcenterbar}
-
- PROCEDURE DrawBorder;
- {-draw a border for each window}
- BEGIN
- TextColor(WindColor);
- {note following clrscr sets the attribute bytes for the text areas we later write to}
- ClrScr;
- TextColor(0);
- TextBackground(7);
- GoToXY(1, 12);
- Write('' : 79);
- GoToXY(1, 14);
- Write('' : 79);
- END; {drawborder}
-
- PROCEDURE ClearStat(N : Window; l, r : Byte);
- {clear status line from col l to col r inclusive}
- BEGIN
- GoToXY(l, 12+2*N);
- Write(' ' : (r-l+1));
- END;
-
- PROCEDURE MoveToStat(N : Window; l : Byte);
- {-move to position on status line}
- BEGIN
- GoToXY(l, 12+2*N);
- END; {movetostat}
-
- PROCEDURE DrawTitle(N : Window);
- {-show the fixed title info}
- BEGIN
- MoveToStat(N, 49); Write('Line ');
- MoveToStat(N, 67); Write('Col ');
- END; {drawtitle}
-
- PROCEDURE ShowWindow(N : Window);
- {-make obvious which window is active}
- BEGIN
- CursorOn(CursorType);
- IF Synced THEN BEGIN
- {show char in opposite window also}
- MoveToStat(1-N, 45);
- Write(Chr(25-N), Chr(25-N));
- END ELSE
- {erase char from previous window}
- ClearStat(1-N, 45, 46);
-
- {put appropriate char in this window}
- MoveToStat(N, 45); Write(Chr(24+N), Chr(24+N));
- CursorOff(CursorType);
- END; {showwindow}
-
- PROCEDURE WaitOn(N : Window);
- {-show a wait symbol}
- BEGIN
- CursorOn(CursorType);
- ClearStat(N, 3, 43);
- MoveToStat(N, 16);
- TextColor(16); {blinking reverse video}
- Write('--- W A I T ---');
- TextColor(0);
- CursorOff(CursorType);
- END; {waiton}
-
- PROCEDURE WaitOff(N : Window);
- {-turn off wait symbol and restore what it overwrote}
- BEGIN
- {put up file name again}
- CursorOn(CursorType);
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('File: ', p[N]);
- CursorOff(CursorType);
- END; {waitoff}
-
- FUNCTION BuffPrior(N : Window;
- VAR BotPtr, BufPtr : TwoInt) : Integer;
- {-return the number of lines to bottom of buffer}
- BEGIN
- IF BotPtr[N] > BufPtr[N] THEN
- BuffPrior := BufPtr[N]-BotPtr[N]+Bufmod
- ELSE
- BuffPrior := BufPtr[N]-BotPtr[N];
- END; {buffprior}
-
- FUNCTION BuffAfter(N : Window;
- VAR TopPtr, BufPtr : TwoInt) : Integer;
- {-return the number of lines to top of buffer}
- BEGIN
- IF TopPtr[N] < BufPtr[N] THEN
- BuffAfter := TopPtr[N]+Bufmod-BufPtr[N]
- ELSE
- BuffAfter := TopPtr[N]-BufPtr[N];
- END; {buffafter}
-
- FUNCTION CurrLine(N : Window) : Integer;
- {-return the current line number of the file in the window}
- BEGIN
- {lines from bottom of buffer to current plus lines to bottom of file}
- CurrLine := BuffPrior(N, BotPtr, BufPtr)+LinNum[N];
- END; {currline}
-
- PROCEDURE ShowLin(N : Window;
- VAR LinNum, BotPtr, BufPtr : TwoInt);
- {-display the current range of lines}
- VAR
- lins : Integer;
- BEGIN
- {erase previous range}
- CursorOn(CursorType);
- ClearStat(N, 54, 64);
- lins := CurrLine(N);
- {write new range}
- MoveToStat(N, 54); Write(lins, '-', lins+slines-1);
- {turn off cursor again}
- CursorOff(CursorType);
- END; {showlin}
-
- PROCEDURE ShowCol(N : Window; LeftEdge : TwoInt);
- {-show the current column range}
- VAR
- t : Integer;
- BEGIN
- {erase previous range}
- CursorOn(CursorType);
- ClearStat(N, 71, 77);
- t := LeftEdge[N];
- {write new range}
- MoveToStat(N, 71); Write(t, '-', t+79);
- CursorOff(CursorType);
- END; {showcol}
-
- FUNCTION ModSucc(N : Integer) : Integer;
- {-increment the argument mod bufmod}
- BEGIN
- ModSucc := (N+1) MOD Bufmod;
- END; {modsucc}
-
- FUNCTION ModPred(N : Integer) : Integer;
- {-decrement the argument mod bufmod}
- BEGIN
- IF N <= 0 THEN ModPred := BufSize ELSE ModPred := N-1;
- END; {modpred}
-
- PROCEDURE BrkOff;
- {-shut off ctrl-break check to assure WordStar ^C gets through}
- BEGIN
- reg.ax := $3301;
- reg.dx := 0;
- MsDos(reg);
- END; {brkoff}
-
- PROCEDURE GetFile(N : Window;
- VAR f : TwoText;
- VAR p : TwoPath;
- VAR s : TwoState);
- {-open either of the files for read}
- VAR
- good : Boolean;
- ch : Char;
- BEGIN
- DrawCenterBar(1);
- CursorOn(CursorType);
- REPEAT
- ClearStat(N, 3, 77);
-
- {*} {only use cmd line params the 1st time program is invoked}
- if (Use_Params) AND ( ParamCount > N ) then {eg 0 for 1st file; 1 for 2nd}
- begin
- MoveToStat(N,3);
- p[N] := ParamStr(N+1);
- s[N] := TRUE;
- end
- else
- begin
- MoveToStat(N, 3);
- Write('Enter file for this window (<ret> for none): ');
- Read(p[N]);
- s[N] := (p[N] <> ''); {false means no file in window}
- end; {if,ParamCount}
-
- ClearStat(N, 3, 77);
- MoveToStat(N, 3);
-
- IF s[N] THEN BEGIN
- {see if file exists}
- Assign(f[N], p[N]);
- {$I-} Reset(f[N]); {$I+}
- good := (IOResult = 0);
- IF good THEN
- Write('File: ', p[N])
- ELSE BEGIN
- Write(p[N], ' not found... press any key to try again');
- Use_Params := FALSE;
- Read(Kbd, ch);
- END;
- END ELSE BEGIN
- good := True;
- Write('File: none');
- END;
- UNTIL good;
- DrawCenterBar(2);
- CursorOff(CursorType);
- END; {getfile}
-
- PROCEDURE ReadAndExpandLine(VAR f : TextFile; VAR nl : LineBuffer);
- {-read a line from the file and expand tabs, returning a line}
- VAR
- i, o : Byte;
- BEGIN
- ReadLn(f, l);
- i := 1;
- o := 0;
- WHILE i <= len DO BEGIN
- IF l[i] = #9 THEN BEGIN
- {expand tabs}
- o := o+1;
- nl[o] := #32;
- WHILE (o MOD 8) <> 0 DO BEGIN
- o := o+1;
- nl[o] := #32;
- END;
- END ELSE BEGIN
- {insert regular character}
- {could insert a high bit or other filter here}
- o := o+1;
- nl[o] := l[i];
- END;
- i := i+1;
- END;
- {set length of nl}
- nl[0] := Chr(o);
- END; {readandexpandline}
-
- PROCEDURE PadBuffer(N : Window;
- VAR BotPtr, TopPtr, BufPtr, LinNum : TwoInt;
- VAR NotPadded : TwoState);
- {-assure end of buffer will fill screen with blanks}
- VAR
- cnt : Integer;
- BEGIN
- cnt := 1;
- WHILE cnt < slines DO BEGIN
- {fill with empty lines}
- b[N][TopPtr[N]] := '';
- TopPtr[N] := ModSucc(TopPtr[N]);
- IF TopPtr[N] = BotPtr[N] THEN BEGIN
- {buffer full, compensate}
- BotPtr[N] := ModSucc(BotPtr[N]);
- LinNum[N] := LinNum[N]+1;
- END;
- cnt := cnt+1;
- END;
- NotPadded[N] := False;
- END; {padbuffer}
-
- PROCEDURE FillBuff(N : Window;
- linstart : Integer;
- VAR BotPtr, TopPtr, BufPtr, LinNum : TwoInt;
- VAR NotPadded : TwoState);
- {-fill the buffer from the beginning, referenced from linstart}
- VAR
- ch : Char;
- BEGIN
- NotPadded[N] := True;
- BotPtr[N] := 0;
- BufPtr[N] := 0;
- TopPtr[N] := 0;
- LinNum[N] := linstart; {always holds line num at bottom of buffer}
- IF s[N] THEN BEGIN
- WHILE NOT(EoF(f[N])) AND (TopPtr[N] < BufSize) DO BEGIN
- ReadAndExpandLine(f[N], b[N][TopPtr[N]]);
- TopPtr[N] := TopPtr[N]+1;
- IF KeyPressed THEN Read(Kbd, ch);
- END;
- {pad buffer with blanks for short files}
- IF EoF(f[N]) THEN
- PadBuffer(N, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END;
- END; {fillbuff}
-
- FUNCTION CalcScrAdd(r : Byte) : Integer;
- {-return the offset into the screen segment of a given row at column 1}
- VAR
- t : Integer;
- BEGIN
- {fast way of saying 160*(r-1)}
- t := (r-1) SHL 4;
- CalcScrAdd := ((t SHL 2)+t) SHL 1;
- END; {calcscradd}
-
- PROCEDURE ScrollWind(r1, r2, lines : Byte);
- {-scroll the region between rows r1 and r2 by lines lines}
- {lines>0 scrolls up, <0 scrolls down, =0 erases window}
- BEGIN
- reg.al := Abs(lines);
- IF lines > 0 THEN reg.ah := 6 ELSE reg.ah := 7;
- reg.cx := (r1-1) SHL 8;
- reg.dx := ((r2-1) SHL 8) OR 79;
- reg.bh := WindColor;
- Intr($10, reg);
- END; {scollwind}
-
- PROCEDURE MoveToScreen(N : Window; VAR LeftEdge, BufPtr, OldPtr : TwoInt);
- {-move buffer info to screen}
- VAR
- cnt, r, sadd, left : Integer;
- rt, rb, lines : Byte;
-
- PROCEDURE WriteLine(r, sadd, left : Integer);
- {-write the line of text ref'ed by r to video memory starting at sadd}
- BEGIN
- {assure l right padded with blanks}
- FillChar(l[1], LineSize, #32);
- {put real data at beginning of l}
- l := Copy(b[N][r], left, 80);
-
- IF NoWait THEN BEGIN
- {write to video, no timing interlocks}
- INLINE(
- $A1/ScreenSeg/ {MOV AX,screenseg}
- $8E/$C0/ {MOV ES,AX}
- $8B/$7E/$06/ {MOV DI,[BP+06]}
- $BE/l/ {MOV SI,offset(l)}
- $46/ {INC SI, skip length byte}
- $B9/$50/$00/ {MOV CX,0050}
- $FC/ {CLD }
- $A4/ {MOVSB }
- $47/ {INC DI, skip attribute}
- $E2/$FC {LOOP 0116}
- );
- END ELSE BEGIN
- {write to video memory with timing interlocks}
- {.F+}
- INLINE(
- {get screenseg into es}
- $A1/ScreenSeg/ {MOV AX,screenseg}
- $8E/$C0/ {MOV ES,AX}
-
- {get screen offset sadd into di}
- $8B/$7E/$06/ {MOV DI,[BP+06]}
-
- {get video status port into dx}
- $8B/$16/VidStatPort/ {MOV DX,vidstatport}
-
- {point to string data with si, string is in dataseg}
- $BE/l/ {MOV SI,offset(l)}
- $46/ {INC SI}
-
- {move 80 bytes to fill one row of screen}
- $B9/$50/$00/ {MOV CX,0050}
- $FC/ {CLD }
-
- {loop to write to screen}
- $AC/ {LODSB }
- $8A/$D8/ {MOV BL,AL}
- $B4/$09/ {MOV AH,09}
- $FA/ {CLI }
- $EC/ {IN AL,DX}
- $D0/$D8/ {RCR AL,1}
- $72/$FB/ {JB 0106}
- $EC/ {IN AL,DX}
- $20/$E0/ {AND AL,AH}
- $75/$FB/ {JNZ 010B}
- $8A/$C3/ {MOV AL,BL}
- $AA/ {STOSB }
- $47/ {INC DI}
- $FB/ {STI }
- $E2/$E9 {LOOP 0100}
- {.F+}
- ); {end of inline}
- END;
- END; {writeline}
-
- BEGIN
- r := BufPtr[N]; {starting row in buffer}
- rt := 14*N+1; {starting row on screen}
- left := LeftEdge[N]; {first char of string that we display}
-
- {redraw entire window}
- sadd := CalcScrAdd(rt); {starting address on screen for this window}
- FOR cnt := 1 TO slines DO BEGIN
- {loop through lines, all guaranteed to exist in buffer}
- WriteLine(r, sadd, left);
- {address of next line of screen}
- sadd := sadd+160;
- {next row of buffer}
- r := ModSucc(r);
- END;
-
- END; {movetoscreen}
-
- PROCEDURE InitWindow(N : Window;
- VAR BotPtr, TopPtr, BufPtr, OldPtr,
- LeftEdge, OldEdge, LinNum : TwoInt;
- VAR NotPadded : TwoState);
- {-initialize everything for a single window}
- BEGIN
- NotPadded[N] := True;
- FillBuff(N, 1, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- LeftEdge[N] := 1;
- OldEdge[N] := 1;
- OldPtr[N] := BufPtr[N];
- MoveToScreen(N, LeftEdge, BufPtr, OldPtr);
- DrawTitle(N);
- ShowLin(N, LinNum, BotPtr, BufPtr);
- ShowCol(N, LeftEdge);
- END; {initwindow}
-
- PROCEDURE SwitchN(VAR N : Window);
- {-switch to opposite window}
- BEGIN
- IF s[1-N] THEN
- N := 1-N
- ELSE BEGIN
- {get another file for the unused window}
- GetFile(1-N, f, p, s);
- IF s[1-N] THEN BEGIN
- {got a file, initialize it and window}
- N := 1-N;
- DrawTitle(N);
- InitWindow(N, BotPtr, TopPtr, BufPtr, OldPtr,
- LeftEdge, OldEdge, LinNum, NotPadded);
- END;
- END;
- ShowWindow(N);
- END; {switchn}
-
- PROCEDURE UpdateBuff(N : Window;
- VAR BotPtr, TopPtr, BufPtr, LinNum : TwoInt;
- VAR NotPadded : TwoState);
- {-determine whether to add to buffer and do so}
- VAR
- buffleft : Integer;
- BEGIN
- {see if we are within linavail of top of buffer}
- IF BuffAfter(N, TopPtr, BufPtr) < LinAvail THEN BEGIN
- {add linavail's worth of buffer}
- buffleft := LinAvail;
- WHILE NOT(EoF(f[N])) AND (buffleft > 0) DO BEGIN
- ReadAndExpandLine(f[N], b[N][TopPtr[N]]);
- buffleft := buffleft-1;
- TopPtr[N] := ModSucc(TopPtr[N]);
- BotPtr[N] := ModSucc(BotPtr[N]);
- LinNum[N] := LinNum[N]+1;
- END;
- IF EoF(f[N]) AND NotPadded[N] THEN
- PadBuffer(N, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END;
- END; {updatebuff}
-
- PROCEDURE ShowRight(N : Byte; VAR BufPtr, LeftEdge : TwoInt);
- {-set leftedge so end of longest line shows}
- VAR
- maxlen, len, lin, cnt : Integer;
- BEGIN
- lin := BufPtr[N];
- maxlen := 0;
- {get maximum line length in window}
- FOR cnt := 1 TO slines DO BEGIN
- len := Length(b[N][lin]);
- IF len > maxlen THEN maxlen := len;
- lin := ModSucc(lin);
- END;
- {convert to a leftedge value}
- len := maxlen-79;
- IF len < 1 THEN len := 1;
- {reset leftedge if appropriate}
- IF LeftEdge[N] < len THEN LeftEdge[N] := len;
- END; {showright}
-
- PROCEDURE SeekBack(N : Window; backn : Integer;
- VAR BotPtr, TopPtr, BufPtr, OldPtr, LinNum : TwoInt);
- {-resynchronize buffer from beginning}
- {-backn is the number of lines to move final bufptr back}
- VAR
- linsave, linbegin, r : Integer;
- ch : Char;
- BEGIN
-
- {may take a while, put up a wait sign}
- WaitOn(N);
-
- {get and save current line number - note that bufprior=0 to arrive here}
- linsave := LinNum[N];
-
- {new line to resynchronize beginning of buffer}
- linbegin := linsave-(BufSize SHR 1);
- IF linbegin < 1 THEN linbegin := 1;
-
- {reset file and leave file pointer ready to read linbegin}
- Reset(f[N]);
- Flush(f[N]);
- FOR r := 1 TO linbegin DO BEGIN
- ReadLn(f[N], l);
- {clear keyboard buffer of any strokes built up during delay}
- IF KeyPressed THEN Read(Kbd, ch);
- END;
-
- {fill buffer starting at linbegin}
- FillBuff(N, linbegin, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
-
- {set bufptr to be at correct line}
- BufPtr[N] := linsave-linbegin-backn;
- {guarantee we redisplay}
- OldPtr[N] := -2;
- WaitOff(N);
- END; {seekback}
-
- FUNCTION GetLineNumber(N : Window) : Integer;
- {-return a legal line number to seek}
- VAR
- seeknum : Integer;
- good : Boolean;
- ch : Char;
- BEGIN
- {prompt for the number}
- DrawCenterBar(1);
- CursorOn(CursorType);
- REPEAT
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('Enter line number: ');
- {$I-} Read(seeknum); {$I+}
- good := (IOResult = 0);
- IF NOT(good) THEN BEGIN
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('Illegal number... Press key to try again');
- Read(Kbd, ch);
- END ELSE BEGIN
- good := (seeknum >= 1);
- IF NOT(good) THEN BEGIN
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('Illegal number... Press key to try again');
- Read(Kbd, ch);
- END;
- END;
- UNTIL good;
- DrawCenterBar(2);
- CursorOff(CursorType);
- GetLineNumber := seeknum;
- END; {getlinenumber}
-
- PROCEDURE SeekLine(N : Window; seeknum : Integer;
- VAR BotPtr, TopPtr, BufPtr, OldPtr, LinNum : TwoInt;
- VAR NotPadded : TwoState);
- {-seek to a desired line number}
- VAR
- lin : Integer;
-
- PROCEDURE SeekAhead(N : Window; seeknum, lin : Integer;
- VAR BotPtr, TopPtr, BufPtr, LinNum : TwoInt;
- VAR NotPadded : TwoState);
- {-seek forward to find line seeknum, starting at line lin}
- {return buffers set up at line found, or at end of file}
- BEGIN
- WHILE (BuffAfter(N, TopPtr, BufPtr) > slines) AND (lin < seeknum) DO BEGIN
- {update file buffer as needed}
- UpdateBuff(N, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- lin := lin+1;
- BufPtr[N] := ModSucc(BufPtr[N]);
- END;
- END; {seekahead}
-
- BEGIN
-
- WaitOn(N);
-
- lin := CurrLine(N);
- IF seeknum > lin THEN BEGIN
- {seeknum is ahead of us}
- SeekAhead(N, seeknum, lin, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END ELSE IF seeknum >= LinNum[N] THEN BEGIN
- {seeknum is behind us, but in current buffer}
- BufPtr[N] := BotPtr[N];
- lin := LinNum[N];
- SeekAhead(N, seeknum, lin, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END ELSE BEGIN
- {seeknum is behind current buffer}
- {reset}
- Reset(f[N]);
- Flush(f[N]);
- NotPadded[N] := True;
- {refill the buffer}
- FillBuff(N, 1, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- {now seeknum is ahead of us}
- SeekAhead(N, seeknum, 1, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END;
-
- WaitOff(N);
- END; {seekline}
-
- PROCEDURE SeekString(N : Window;
- VAR BotPtr, TopPtr, BufPtr, OldPtr, LinNum : TwoInt;
- VAR NotPadded : TwoState;
- VAR SearchString : LineBuffer);
- {-search for a string}
- VAR
- notfound : Boolean;
- ch : Char;
- spos : Integer;
-
- FUNCTION StUpcase(s : LineBuffer) : LineBuffer;
- {-return the uppercase of a string}
- VAR
- i : Byte;
- BEGIN
- FOR i := 1 TO Length(s) DO s[i] := UpCase(s[i]);
- StUpcase := s;
- END; {stupcase}
-
- BEGIN
- IF SearchString = '' THEN BEGIN
- {get the search string}
- DrawCenterBar(3);
- CursorOn(CursorType);
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('Search String: ');
- Read(SearchString);
- SearchString := StUpcase(SearchString);
- DrawCenterBar(2);
- WaitOff(N);
- END;
-
- IF SearchString <> '' THEN BEGIN
- {do the search}
- WaitOn(N);
- notfound := True;
- WHILE notfound AND (BuffAfter(N, TopPtr, BufPtr) > slines) DO BEGIN
- {scan forward through buffer and update buffer as necessary}
- BufPtr[N] := ModSucc(BufPtr[N]);
- notfound := (Pos(SearchString, StUpcase(b[N][BufPtr[N]])) = 0);
- UpdateBuff(N, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END;
- IF notfound THEN BEGIN
- {complain}
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('String not found. Press any key...');
- Read(Kbd, ch);
- END ELSE BEGIN
- {make sure string found shows on screen}
- spos := Pos(SearchString, StUpcase(b[N][BufPtr[N]]));
- IF spos < LeftEdge[N] THEN
- {string is off left edge of screen}
- LeftEdge[N] := spos
- ELSE IF (spos+Length(SearchString)) > (LeftEdge[N]+79) THEN
- {string is off right edge of screen}
- LeftEdge[N] := spos+Length(SearchString)-80;
- END;
- WaitOff(N);
- END;
-
- END; {seekstring}
-
- PROCEDURE initialize(VAR N : Window);
- {-set up everything}
- VAR
- w : Window;
- BEGIN
- {avoid problems with ^C char used for WordStar scrolling}
- BrkOff;
- {some constants}
- Bufmod := BufSize+1;
- SearchString := '';
- Synced := False;
-
- {initialize selected windows}
- FOR w := 0 TO 1 DO IF s[w] THEN
- InitWindow(w, BotPtr, TopPtr, BufPtr, OldPtr,
- LeftEdge, OldEdge, LinNum, NotPadded);
-
- {pick initial window}
- IF s[0] THEN N := 0 ELSE N := 1;
-
- {show which window is active}
- ShowWindow(N);
- END; {initialize}
-
- PROCEDURE CloseUp;
- {-close up to quit}
- BEGIN
- IF s[0] THEN Close(f[0]);
- IF s[1] THEN Close(f[1]);
- GoToXY(1, 25);
- CursorOn(CursorType);
- TextColor(7);
- TextBackground(0);
- Halt;
- END; {closeup}
-
- PROCEDURE VideoOff;
- {-avoid snow writing full screen to c/g card}
- BEGIN
- {clear video enable bit}
- Port[VidModePort] := ModePortData AND 247;
- END;
-
- PROCEDURE VideoOn;
- {-reenable video}
- BEGIN
- {set video enable bit}
- Port[VidModePort] := ModePortData OR 8;
- END;
-
- PROCEDURE SaveScreen;
- BEGIN
- Move(Mem[ScreenSeg : 0], SavScr, 4000);
- END; {savescreen}
-
- PROCEDURE RestoreScreen;
- BEGIN
- Move(SavScr, Mem[ScreenSeg : 0], 4000);
- END; {restorescreen}
-
- PROCEDURE invokeDOS;
- {-start a new DOS shell, then return to browser}
- VAR
- save_ax : Integer;
- ch : Char;
-
- PROCEDURE execute_string(s : PathString; VAR sav_ax : Integer);
- {-execute a command line}
- {-provided by russ nelson, potsdam, ny}
- VAR
- save_ax : Integer;
- CONST
- save_ss : Integer = 0;
- save_sp : Integer = 0;
- BEGIN
- s[Length(s)+1] := ^M;
- INLINE(
- $1E/ {push ds}
- $55/ {push bp}
- $2E/$8C/$16/save_ss/ {mov cs:[save_ss],ss}
- $2E/$89/$26/save_sp/ {mov cs:[save_sp],sp}
- $8C/$D0/ {mov ax,ss}
- $8E/$D8/ {mov ds,ax}
- $8D/$76/< s/ {lea si,s[bp]}
- $CD/$2E/ {int 2Eh}
- $2E/$8E/$16/save_ss/ {mov ss,cs:[save_ss]}
- $2E/$8B/$26/save_sp/ {mov sp,cs:[save_sp]}
- $5D/ {pop bp}
- $1F/ {pop ds}
- $89/$46/< save_ax {mov save_ax[bp],ax}
- );
- sav_ax := save_ax;
- END; {execute_string}
-
- BEGIN
- {store screen}
- IF NOT(NoWait) THEN VideoOff;
- SaveScreen;
- IF NOT(NoWait) THEN VideoOn;
- CursorOn(CursorType);
- TextColor(7);
- TextBackground(0);
-
- {clear screen and put up help}
- ClrScr;
- WriteLn('Type EXIT to return to BROWSE...');
-
- {start new DOS shell}
- execute_string('command', save_ax);
-
- {restore screen}
- TextColor(0);
- TextBackground(7);
- CursorOff(CursorType);
- VideoOff;
- RestoreScreen;
- VideoOn;
-
- {check errors - this particular interrupt doesn't provide many}
- IF save_ax <> 0 THEN BEGIN
- DrawCenterBar(3);
- CursorOn(CursorType);
- ClearStat(N, 3, 43);
- MoveToStat(N, 3);
- Write('Can''t invoke DOS. Press any key...');
- Read(Kbd, ch);
- DrawCenterBar(2);
- WaitOff(N);
- END;
-
- END; {invokeDOS}
-
- PROCEDURE ShowHelp;
- {-provide a pop-up help screen}
- CONST
- helpLines = 16; {was 15 in orig. version}
- helpX = 11;
- helpY = 6;
- TYPE
- HelpArray = ARRAY[1..helpLines] OF STRING[60];
- VAR
- ch : Char;
- i, r : Byte;
- CONST
- ha : HelpArray =
- (
- '╔════════════════════════════════════════════════════════╗',
- {*} '║ Version ║',
- '║ Window Browser - by TurboPower Software ║',
- '║ ┌────────────────────────┐ ┌─────────────────────────┐ ║',
- '║ │ ^Z,^X line up │ │ ^S column left │ ║',
- '║ │ ^W,^E line down │ │ ^D column right │ ║',
- '║ │ ^C page up │ │ ^Q^S left of line │ ║',
- '║ │ ^R page down │ │ ^Q^D right of line │ ║',
- '║ │ ^Q^R file home │ │ ^Q^N seek line number│ ║',
- '║ │ ^Q^C file end │ │ ^Q^F string search │ ║',
- '║ │ ^K^R new file │ │ ^L search again │ ║',
- {*} '║ │ ^K^D quit │ │ F6,^N switch windows │ ║',
- '║ │ ^K^I invoke DOS │ │ ^B (un)sync windows│ ║',
- '║ └────────────────────────┘ └─────────────────────────┘ ║',
- '║ Press any key to return to your browsing.... ║',
- '╚════════════════════════════════════════════════════════╝'
- );
-
- PROCEDURE SetScreenAttr(a : Byte);
- {-set entire screen to a given attribute}
- VAR
- i : Integer;
- BEGIN
- i := 1;
- WHILE i < 4000 DO BEGIN
- Mem[ScreenSeg : i] := a;
- i := i+2;
- END;
- END; {setscreenattr}
-
- BEGIN
- {*insert version #}
- for i:=1 to Length(Version) do ha[2][i+1+Pos('n',ha[2])] := Version[i];
-
- IF NOT(NoWait) THEN VideoOff;
- SaveScreen;
- SetScreenAttr(7); {put background in low video}
- IF NOT(NoWait) THEN VideoOn;
- {write help}
- CursorOn(CursorType);
- TextColor(15);
- TextBackground(0);
- r := helpY;
- FOR i := 1 TO helpLines DO BEGIN
- GoToXY(helpX, r);
- Write(ha[i]);
- r := r+1;
- END;
- TextColor(0);
- TextBackground(7);
- CursorOff(CursorType);
- Read(Kbd, ch);
- IF NOT(NoWait) THEN VideoOff;
- RestoreScreen;
- IF NOT(NoWait) THEN VideoOn;
- END; {showhelp}
-
- {-----------------------------------------------------------
- key action codes used here:
- 15: ^H help
- 2: ^Z,^X line up 9: ^S column left
- 1: ^W,^E line down 10: ^D column right
- 4: ^C page up 11: ^Q^S left of line
- 3: ^R page down 12: ^Q^D right of line
- 5: ^Q^R file home 14: ^Q^N seek line number
- 6: ^Q^C file end 16: ^Q^F string search
- 13: ^K^R new file 17: ^L search again
- 7: ^K^D quit 8: ^N switch windows
- 19: ^K^I invoke DOS 18: ^B (un)sync windows
-
- cursor pad keys produce <Esc> then the byte:
- UP = ESC-72 = 'H'= code 2 above HOME = 71 = 'G'= code 11
- DN = -80 = 'P'= 1 PGUP = 73 = 'I'= 4
- LT = -75 = 'K'= 9 END = 79 = 'O'= 12
- RT = -77 = 'M'= 10 PGDN = 81 = 'Q'= 3
-
- CTL-HOME = 119 = 'w' = 5
- END = 117 = 'u' = 6
-
- F1 = HELP = 59 = ';' = code 15
- F6 = switch windows = 64 = '@' = 8
- -----------------------------------------------------------}
-
- FUNCTION GetKey : Byte;
- {-return a keycode for a legal keystroke}
- {customize here for favorite cursor keys}
- {this is currently set up for WordStar-like keys only}
- {*note 2/86: i've added the pc's cursor pad keys: SD}
-
- VAR
- good : Boolean;
- ch : Char;
- {*} ESC : BOOLEAN;
- BEGIN
- {don't let keystrokes get ahead of the action}
- WHILE KeyPressed DO Read(Kbd, ch);
- REPEAT
- Read(Kbd, ch);
-
- {*} ESC := (ch=^[);
- if ESC then read(kbd,ch);
-
- good := True;
- CASE ch OF
-
- {[SD] *** IBM-PC cursor key-pad ***}
- {LEFT} 'K' : GetKey := 9;
- {RIGHT} 'M' : GetKey := 10;
- {DOWN} 'H' : GetKey := 1;
- {UP} 'P' : GetKey := 2;
- {HOME} 'G' : GetKey := 11;
- {END} 'O' : GetKey := 12;
- {PGDN} 'Q' : GetKey := 4;
- {PGUP} 'I' : GetKey := 3;
- {CTL-HOME} 'w': GetKey := 5;
- {CTL-END} 'u': GetKey := 6;
- {F1:HELP} ';': GetKey := 15;
- {F6:sw win} '@': GetKey := 8;
-
-
- { ORIGINAL keyboard set up (still in effect) }
- ^S : GetKey := 9;
- ^D : GetKey := 10;
- ^W, ^E : GetKey := 1;
- ^Z, ^X : GetKey := 2;
- ^Q : BEGIN
- Read(Kbd, ch);
- CASE ch OF
- ^R, 'r', 'R' : GetKey := 5;
- ^C, 'c', 'C' : GetKey := 6;
- ^S, 's', 'S' : GetKey := 11;
- ^D, 'd', 'D' : GetKey := 12;
- ^N, 'n', 'N' : GetKey := 14;
- ^F, 'f', 'F' : GetKey := 16;
- ELSE
- good := False;
- END;
- END;
- ^K : BEGIN
- Read(Kbd, ch);
- CASE ch OF
- ^X, ^D, 'x', 'X', 'd', 'D' : GetKey := 7;
- ^R, 'r', 'R' : GetKey := 13;
- ^I, 'i', 'I' : GetKey := 19;
- ELSE
- good := False;
- END;
- END;
- ^N : GetKey := 8;
- ^B : GetKey := 18;
- ^R : GetKey := 3;
- ^C : GetKey := 4;
- ^H : GetKey := 15;
- ^L : GetKey := 17;
- ELSE
- good := False;
- END;
- UNTIL good;
- END; {getkey}
-
- PROCEDURE update(N : Window);
- {-update the screen and buffers for window n}
- BEGIN
- {update file buffer as needed}
- UpdateBuff(N, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
-
- IF (OldPtr[N] <> BufPtr[N]) OR (OldEdge[N] <> LeftEdge[N]) THEN BEGIN
- {update screen data}
- MoveToScreen(N, LeftEdge, BufPtr, OldPtr);
- IF OldPtr[N] <> BufPtr[N] THEN BEGIN
- OldPtr[N] := BufPtr[N];
- {update line status}
- ShowLin(N, LinNum, BotPtr, BufPtr);
- END;
- IF OldEdge[N] <> LeftEdge[N] THEN BEGIN
- OldEdge[N] := LeftEdge[N];
- {update column status}
- ShowCol(N, LeftEdge);
- END;
- END;
- END; {update}
-
- PROCEDURE doOp(VAR N : Window; ch : Byte);
- VAR
- temp : Integer;
- BEGIN
- {-operate based on key}
- CASE ch OF
-
- {scroll one line up}
- 1 : IF BuffPrior(N, BotPtr, BufPtr) > 0 THEN
- BufPtr[N] := ModPred(BufPtr[N])
- ELSE IF LinNum[N] > 1 THEN
- {need to rebuild buffer from beginning}
- SeekBack(N, 1, BotPtr, TopPtr, BufPtr, OldPtr, LinNum);
-
- {scroll one line down}
- 2 : IF BuffAfter(N, TopPtr, BufPtr) > slines THEN
- BufPtr[N] := ModSucc(BufPtr[N]);
-
- {scroll page up}
- 3 : IF BuffPrior(N, BotPtr, BufPtr) > slines THEN
- FOR temp := 1 TO slines DO BufPtr[N] := ModPred(BufPtr[N])
- ELSE IF LinNum[N] > 1 THEN
- {need to rebuild buffer from beginning}
- SeekBack(N, slines, BotPtr, TopPtr, BufPtr, OldPtr, LinNum)
- ELSE
- {set to beginning of file}
- BufPtr[N] := BotPtr[N];
-
- {scroll page down}
- 4 : IF BuffAfter(N, TopPtr, BufPtr) > slines THEN
- FOR temp := 1 TO slines DO
- IF BuffAfter(N, TopPtr, BufPtr) > slines THEN
- BufPtr[N] := ModSucc(BufPtr[N]);
-
- {home}
- 5 : IF LinNum[N] > 1 THEN BEGIN
- {reset}
- WaitOn(N);
- Reset(f[N]);
- Flush(f[N]);
- LeftEdge[N] := 1;
- NotPadded[N] := True;
- {refill the buffer}
- FillBuff(N, 1, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- OldPtr[N] := -2; {guarantee redisplay}
- WaitOff(N);
- END ELSE
- BufPtr[N] := 0;
-
- {end}
- 6 : BEGIN
- IF NOT(EoF(f[N])) THEN WaitOn(N);
- WHILE NOT(EoF(f[N])) DO BEGIN
- BufPtr[N] := TopPtr[N];
- UpdateBuff(N, BotPtr, TopPtr, BufPtr, LinNum, NotPadded);
- END;
- BufPtr[N] := TopPtr[N];
- FOR temp := 1 TO slines DO
- BufPtr[N] := ModPred(BufPtr[N]);
- {guarantee redisplay}
- OldPtr[N] := -2;
- WaitOff(N);
- END;
-
- {quit}
- 7 : CloseUp;
-
- {switch windows}
- 8 : SwitchN(N);
-
- {scroll left}
- 9 : IF LeftEdge[N] > 1 THEN
- LeftEdge[N] := LeftEdge[N]-1;
-
- {scroll right}
- 10 : IF LeftEdge[N] < LineSize-79 THEN
- LeftEdge[N] := LeftEdge[N]+1;
-
- {set left edge to beginning of screen}
- 11 : LeftEdge[N] := 1;
-
- {set right edge to show longest line}
- 12 : ShowRight(N, BufPtr, LeftEdge);
-
- {open new file in current window}
- 13 : BEGIN
- Close(f[N]);
- GetFile(N, f, p, s);
- IF s[N] THEN BEGIN
- {open the new window}
- InitWindow(N, BotPtr, TopPtr, BufPtr, OldPtr,
- LeftEdge, OldEdge, LinNum, NotPadded);
- ShowWindow(N);
- END ELSE BEGIN
- {clear the now-empty window}
- ScrollWind(1+14*N, 11+14*N, 0);
- {make sure other window is open and switch to it}
- IF s[1-N] THEN SwitchN(N) ELSE CloseUp;
- END;
- END;
-
- {seek to line number}
- 14 : BEGIN
- SeekNumber := GetLineNumber(N);
- SeekLine(N, SeekNumber,
- BotPtr, TopPtr, BufPtr, OldPtr, LinNum, NotPadded);
- END;
-
- 15 : ShowHelp;
-
- {search for a new string}
- 16 : BEGIN
- SearchString := '';
- SeekString(N, BotPtr, TopPtr, BufPtr,
- OldPtr, LinNum, NotPadded, SearchString);
- END;
-
- {search for prior string}
- 17 : SeekString(N, BotPtr, TopPtr, BufPtr,
- OldPtr, LinNum, NotPadded, SearchString);
-
- 19 : invokeDOS;
-
- END; {case}
- END; {DoOp}
-
- BEGIN {main}
-
- {get screen segment, cursortype, and video port addresses}
- ScreenSeg := which_screen(CursorType, VidStatPort, VidModePort);
- {draw screen border and titles}
- DrawBorder;
-
- {get input files}
-
- {*} Use_Params := TRUE; {get filename from cmd line}
- GetFile(0, f, p, s);
- GetFile(1, f, p, s);
- Use_Params := FALSE; {from now on, get file name from user}
-
- {close up if no files}
- IF NOT(s[0] OR s[1]) THEN BEGIN
- GoToXY(1, 25);
- Halt;
- END;
-
- {initialize globals and turn off cursor, return active window}
- initialize(N);
-
- {main loop}
- WHILE True DO BEGIN
-
- {update screen and buffers}
- update(N);
- IF Synced AND s[0] AND s[1] THEN update(1-N);
-
- {get new keystroke}
- ch := GetKey;
-
- {operate based on keystroke}
- IF ch = 18 THEN BEGIN
- {handle window synchronization}
- Synced := NOT(Synced);
- ShowWindow(N);
- END ELSE BEGIN
- {do any other operation}
- doOp(N, ch);
- IF Synced AND s[0] AND s[1] AND (ch <> 15) AND (ch <> 19) THEN BEGIN
- IF ch = 14 THEN
- {seek to same line number as other window}
- SeekLine(1-N, SeekNumber, BotPtr, TopPtr, BufPtr, OldPtr, LinNum, NotPadded)
- ELSE BEGIN
- {convert string search to one for same string in other window}
- IF ch = 16 THEN ch := 17;
- {do operation in other window}
- TmpWind := 1-N;
- doOp(TmpWind, ch);
- END;
- END;
- END;
-
- END; {while true}
-
- END.
-