home *** CD-ROM | disk | FTP | other *** search
- {$C-}
-
- PROGRAM browse;
-
- {*************************************************************************}
- {* Copyright (c) Kim Kokkonen, TurboPower Software, 1985 *}
- {* Released to the public domain for personal, non-commercial use only *}
- {*************************************************************************}
-
- {.F-}
- {
- 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
-
- FEATURES:
- filenames may include drive and path
- unlimited size files (or 32767 lines of 127 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
- linesize = 127; {max line length stored}
- bufsize = 127; {lines of text (-1) in each textbuffer}
- 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}
-
- 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;
- synced : Boolean;
- {BIOS stores most recent video mode select port value here}
- modeportdata : Byte ABSOLUTE $40 : $65;
-
- 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;
- END ELSE BEGIN
- {color/graphics adapter}
- which_screen := $B800;
- cursortype := $607;
- END;
- vidstatport := vid+6; {video status port for either card}
- vidmodeport := vid+4; {video mode port for either card}
- 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 ══════════════════════════════╡')
- 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;
- LowVideo;
- GoToXY(1, 12);
- Write('ZD D?');
- GoToXY(1, 14);
- Write('@D DY');
- 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}
- NormVideo;
- 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}
- NormVideo;
- movetostat(n, 45); Write(Chr(24+n), Chr(24+n));
- LowVideo;
- cursoroff(cursortype);
- END; {showwindow}
-
- PROCEDURE waiton(n : Window);
- {-show a wait symbol}
- BEGIN
- cursoron(cursortype);
- clearstat(n, 3, 43);
- movetostat(n, 16);
- TextColor(23); {blinking low intensity}
- Write('--- W A I T ---');
- LowVideo;
- 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);
- 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}
- 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');
- 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);
-
- {write to video memory with timing interlocks}
- {.F-}
- INLINE(
- {get screenseg into es}
- $BB/screenseg/ {MOV BX,offset(screenseg)}
- $8B/$07/ {MOV AX,[BX]}
- $8E/$C0/ {MOV ES,AX}
-
- {get screen offset sadd into di}
- $8B/$7E/$06/ {MOV DI,[BP+06]}
-
- {get video status port into dx}
- $BB/vidstatport/ {MOV BX,offset(vidstatport)}
- $8B/$17/ {MOV DX,[BX]}
-
- {point to string data with si}
- $BB/l/ {MOV BX,offset(l)}
- $43/ {INC BX}
- $8B/$F3/ {MOV SI,BX}
-
- {move 80 bytes to fill one row of screen}
- $B9/$50/$00/ {MOV CX,0050}
- $FA/ {CLI }
-
- {loop to write to screen}
- {124:}
- $EC/ {IN AL,DX}
- $A8/$01/ {TEST AL,01}
- $75/$FB/ {JNZ 0124}
-
- {12A:}
- $EC/ {IN AL,DX}
- $A8/$01/ {TEST AL,01}
- $74/$FB/ {JZ 012A}
-
- {write byte in "safe period"}
- $A4/ {MOVSB }
- $47/ {INC DI - skip attribute byte}
- $E2/$F2/ {LOOP 0124}
-
- {done now}
- $FB {STI }
-
- {.F+}
- ); {end of inline}
-
- END; {writeline}
-
- BEGIN
- r := bufptr[n]; {starting row in buffer}
- rt := 14*n+1; {starting row on screen}
- lines := r-oldptr[n]; {vertical lines of scrolling}
- left := leftedge[n]; {first char of string that we display}
-
- IF abs(lines) = 1 THEN BEGIN
-
- {single line scroll, use BIOS scroll for speed}
- rb := rt+10;
- scrollwind(rt, rt+10, lines);
- IF lines = 1 THEN BEGIN
- {scroll up}
- sadd := calcscradd(rb);
- r := (r+slines-1) MOD bufmod;
- writeline(r, sadd, left);
- END ELSE BEGIN
- {scroll down}
- sadd := calcscradd(rt);
- writeline(r, sadd, left);
- END;
-
- END ELSE BEGIN
-
- {horizontal or multiline scroll, 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;
- 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);
- 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}
- videooff;
- savescreen;
- videoon;
- cursoron(cursortype);
- LowVideo;
-
- {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}
- 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 = 15;
- helpx = 11;
- helpy = 6;
- TYPE
- helparray = ARRAY[1..helplines] OF STRING[60];
- VAR
- ch : Char;
- i, r : Byte;
- CONST
- ha : helparray =
- (
- '╔════════════════════════════════════════════════════════╗',
- '║ 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 │ │ ^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
- videooff;
- savescreen;
- setscreenattr(7); {put background in low video}
- videoon;
- {write help}
- cursoron(cursortype);
- TextColor(15);
- r := helpy;
- FOR i := 1 TO helplines DO BEGIN
- GoToXY(helpx, r);
- Write(ha[i]);
- r := r+1;
- END;
- LowVideo;
- cursoroff(cursortype);
- Read(Kbd, ch);
- videooff;
- restorescreen;
- videoon;
- END; {showhelp}
-
- 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}
- VAR
- good : Boolean;
- ch : Char;
- BEGIN
- {don't let keystrokes get ahead of the action}
- WHILE KeyPressed DO Read(Kbd, ch);
- REPEAT
- Read(Kbd, ch);
- good := True;
- CASE ch OF
- ^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}
- getfile(0, f, p, s);
- getfile(1, f, p, s);
-
- {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.