home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
vipf.zip
/
ipfview.mod
< prev
next >
Wrap
Text File
|
1994-03-21
|
24KB
|
790 lines
IMPLEMENTATION MODULE IPFView;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
FROM SYSTEM IMPORT TSIZE;
IMPORT IO, Str, Lib, IPF (*, IPFDump*);
IMPORT Window;
FROM Window IMPORT FullScreen;
CONST
OUT = FALSE;
(*-------------------------------------------------- browser *)
VAR
PopDef: Window.WinDef;
PopWin: Window.WinType;
SearchTxt: IPF.aString;
PROCEDURE PopUp (lines: CARDINAL);
BEGIN
PopDef.Y2:= PopDef.Y1 + lines + 2;
PopWin:= Window.Open( PopDef );
Window.Use( PopWin );
END PopUp;
PROCEDURE PopDown;
BEGIN
Window.Use( Window.FullScreen );
Window.Close( PopWin );
END PopDown;
PROCEDURE Yell (msg: ARRAY OF CHAR);
VAR
ch: CHAR;
BEGIN
PopUp( 5 );
IO.WrStr( " " ); IO.WrStr( msg ); ch:= IO.RdKey();
PopDown;
END Yell;
TYPE
aBuildHook = PROCEDURE (): CARDINAL;
aLineHook = PROCEDURE (CARDINAL);
aChooseHook = PROCEDURE ((*key*) CHAR,
VAR (*beg*) CARDINAL,
VAR (*row*) CARDINAL,
VAR (*col*) CARDINAL): BOOLEAN; (* continue? *)
PROCEDURE Browse (Build: aBuildHook; Line: aLineHook; Choose: aChooseHook;
begin, row, col: CARDINAL);
VAR
cnt: IPF.anIndex;
i, j, k: IPF.anIndex;
line: CARDINAL;
done: BOOLEAN;
move: CHAR;
search: ARRAY [0..79] OF CHAR;
PROCEDURE Up;
BEGIN
IF row > 0 THEN
DEC(row);
IF row < begin THEN
DEC(begin);
Window.InsLine; Window.GotoXY( 1,1 );
Line( row );
END;
Window.GotoXY( 1, row - begin + 1 );
END;
END Up;
PROCEDURE Down;
BEGIN
IF row < cnt-1 THEN
INC(row);
IF row = begin + Window.CurrentScreenDepth THEN
INC(begin);
IO.WrLn;
Line( row );
END;
Window.GotoXY( 1, row - begin + 1 );
END;
END Down;
PROCEDURE Refresh;
BEGIN
Window.Clear;
Window.SetWrap( FALSE );
line:= 1; i:= begin;
WHILE (line <= Window.CurrentScreenDepth) AND (i < cnt) DO
Window.GotoXY( 1, i - begin + 1 ); Line( i );
INC(line); INC( i );
END;
END Refresh;
PROCEDURE MovedUp;
BEGIN
IF begin > row THEN
begin:= row;
Refresh;
END;
END MovedUp;
PROCEDURE MovedDown;
BEGIN
IF begin + Window.CurrentScreenDepth <= row THEN
IF row >= Window.CurrentScreenDepth THEN
begin:= row - Window.CurrentScreenDepth + 1;
ELSE
begin:= 0;
END;
Refresh;
END;
END MovedDown;
BEGIN
done:= FALSE;
REPEAT
cnt:= Build();
IF (begin >= cnt) OR (row >= cnt) THEN begin:= 0; row:= 0 END;
Refresh;
LOOP
Window.GotoXY( col + 1, row - begin + 1);
Window.CursorOn; move:= IO.RdKey(); Window.CursorOff;
CASE CAP(move) OF
| 0C: (* extended *)
move:= IO.RdKey();
CASE move OF
| CHR(72): (* up *)
Up;
| CHR(80): (* down *)
Down;
| CHR(73): (* page up *)
IF row > Window.CurrentScreenDepth THEN
DEC( row, Window.CurrentScreenDepth );
ELSE
row:= 0;
END;
MovedUp;
| CHR(81): (* page down *)
IF row + Window.CurrentScreenDepth < cnt THEN
INC( row, Window.CurrentScreenDepth );
ELSE
row:= cnt-1;
END;
MovedDown;
| CHR(132): (* ctrl-page up *)
row:= 0; col:= 0; MovedUp;
| CHR(118): (* ctrl-page down *)
row:= cnt-1; col:= 0; MovedDown;
| CHR(75): (* left *)
IF col > 0 THEN DEC(col) END;
| CHR(77): (* right *)
IF col < 79 THEN INC(col) END;
| CHR(71): (* home *)
col:= 0;
| CHR(79): (* end *)
col:= 79;
END;
| CHR(27): (* quit *)
done:= TRUE;
EXIT;
| "S": (* search *)
PopUp( 3 );
IO.WrLn; IO.WrStr( " Search: " ); IO.RdStr( SearchTxt );
PopDown;
| "?": (* help *)
PopUp( Window.CurrentScreenDepth - 12 );
IO.WrLn; IO.WrStr( " ESC quit" );
IO.WrLn; IO.WrStr( " ENTER open text" );
IO.WrLn; IO.WrStr( " SPACE unfold/fold" );
IO.WrLn; IO.WrStr( " I index" );
IO.WrLn; IO.WrStr( " S define search text" );
IO.WrLn; IO.WrStr( " F find next occurrence" );
IO.WrLn; IO.WrStr( " arrows move cursor" );
IO.WrLn; IO.WrStr( " pg up/dn move pagewise" );
IO.WrLn; IO.WrStr( " ctrl-pgup/dn goto start/end" );
IO.WrLn; IO.WrStr( " home/end start/end of line" );
move:= IO.RdKey();
PopDown;
ELSE
done:= NOT Choose( CAP(move), begin, row, col );
MovedUp; MovedDown;
EXIT;
END;
END (*key loop*);
UNTIL done;
END Browse;
(*-------------------------------------------------- table-of-contents *)
CONST
Open = 4;
VAR
TocCnt: IPF.anIndex;
Toc: POINTER TO ARRAY IPF.anIndex OF IPF.anIndex;
PROCEDURE BuildToc (): CARDINAL;
VAR
i: IPF.anIndex;
l: CARDINAL;
BEGIN
TocCnt:= 0; l:= 9;
FOR i:= 0 TO IPF.TocCnt-1 DO
WITH IPF.Toc^[i]^ DO
IF (nest # 0) AND NOT (IPF.Hidden IN flags)
AND
(nest <= l)
THEN
l:= nest;
Toc^[TocCnt]:= i; INC(TocCnt);
IF (IPF.HasChildren IN flags) AND (Open IN flags) THEN
INC(l);
END;
END;
END;
END;
RETURN TocCnt;
END BuildToc;
PROCEDURE TocLine (i: CARDINAL);
BEGIN
WITH IPF.Toc^[Toc^[i]]^ DO
IF nest > 0 THEN
IO.WrCharRep( " ", (nest-1) * 4 );
END;
IF IPF.HasChildren IN flags THEN
IF Open IN flags THEN
IO.WrStr( "[-] " );
ELSE
IO.WrStr( "[+] " );
END;
END;
IO.WrStr( title^ );
IF OUT THEN IO.WrCard( Toc^[i], 5 ) END;
END;
END TocLine;
PROCEDURE TocChoose (key: CHAR; VAR beg, row, col: CARDINAL): BOOLEAN;
VAR
r, p: CARDINAL;
BEGIN
CASE key OF
| 15C: (* enter *)
IF IPF.Toc^[Toc^[row]]^.slotCnt > 0 THEN
BrowseText( Toc^[row] );
END;
| " ": (* un/fold *)
WITH IPF.Toc^[Toc^[row]]^ DO
IF Open IN flags THEN
EXCL( flags, Open );
ELSE
INCL( flags, Open );
END;
END (*with slot*);
| "I": (* index *)
BrowseIdx;
| "F": (* find *)
r:= row+1;
WHILE r < TocCnt DO
WITH IPF.Toc^[Toc^[r]]^ DO
p:= Str.Pos( title^, SearchTxt );
IF p # MAX(CARDINAL) THEN
IF IPF.HasChildren IN flags THEN INC(p,4) END;
row:= r; col:= p + (nest-1)*4;
IF row >= beg + Window.CurrentScreenDepth THEN
beg:= row - Window.CurrentScreenDepth + 1
END;
RETURN TRUE;
END;
END;
INC(r);
END;
| "O": (* output *)
IF OUT THEN
PopUp( 5 );
IO.WrStr( " Dump entry: " ); r:= IO.RdCard();
PopDown;
Window.Clear; Window.SetWrap( TRUE );
(* IPFDump.OutSlot( IPF.Toc^[r]^.slot^[0] );*)
IF IO.RdKey() = "a" THEN END;
END;
END;
RETURN TRUE;
END TocChoose;
PROCEDURE BrowseToc;
BEGIN
ALLOCATE( Toc, IPF.TocCnt * TSIZE(IPF.anIndex) );
Browse( BuildToc, TocLine, TocChoose, 0,0,0 );
DEALLOCATE( Toc, IPF.TocCnt * TSIZE(IPF.anIndex) );
END BrowseToc;
(*-------------------------------------------------- index *)
PROCEDURE BuildIdx (): CARDINAL;
BEGIN
RETURN IPF.IdxCnt;
END BuildIdx;
PROCEDURE IdxLine (i: CARDINAL);
BEGIN
WITH IPF.Idx^[i]^ DO
IO.WrCharRep( " ", level * 4 );
IO.WrStr( name^ );
END;
END IdxLine;
PROCEDURE IdxChoose (key: CHAR; VAR beg, row, col: CARDINAL): BOOLEAN;
VAR
r, p: CARDINAL;
BEGIN
CASE key OF
| 15C: (* enter *)
BrowseText( IPF.Idx^[row]^.toc );
| "F": (* find *)
r:= row+1;
WHILE r < IPF.IdxCnt DO
WITH IPF.Idx^[r]^ DO
p:= Str.Pos( name^, SearchTxt );
IF p # MAX(CARDINAL) THEN
row:= r; col:= p + level*4;
IF row >= beg + Window.CurrentScreenDepth THEN
beg:= row - Window.CurrentScreenDepth + 1
END;
RETURN TRUE;
END;
END;
INC(r);
END;
END;
RETURN TRUE;
END IdxChoose;
PROCEDURE BrowseIdx;
BEGIN
Browse( BuildIdx, IdxLine, IdxChoose, 0,0,0 );
END BrowseIdx;
(*-------------------------------------------------- slots *)
CONST
MaxLines = 1000;
MaxRefs = 500;
TYPE
aLine = POINTER TO IPF.aString;
aLineNo = [1..MaxLines];
aRefNo = [1..MaxRefs];
CONST
NoRef = MAX(IPF.anIndex);
VAR
LineCnt: CARDINAL;
Line: ARRAY aLineNo OF aLine;
Indent: ARRAY aLineNo OF CARDINAL;
Offset: ARRAY aLineNo OF LONGCARD;
RefCnt: CARDINAL;
Ref: ARRAY aRefNo OF RECORD
start, end: LONGCARD; (* offset *)
ref: IPF.anIndex;
END;
AutoStart: CARDINAL; (* where automatic refs start *)
PROCEDURE BuildLines (i: IPF.anIndex);
VAR
row: aLineNo; (* current line *)
col: CARDINAL; (* current column *)
ofs: LONGCARD; (* current offset in chars (excl. CRLF) *)
cofs: LONGCARD; (* committed offset *)
line: IPF.aString; (* current line *)
part: IPF.aString; (* current unbreakable part of line *)
s: IPF.anIndex; (* index into slots *)
t: IPF.anIndex; (* index into slot text *)
w: IPF.aWord; (* current word *)
id: IPF.aWord; (* escape sequence *)
base,len: IPF.anIndex; (* base index and length of escape sequence *)
word: IPF.aString; (* text of word *)
spc: BOOLEAN; (* spacing mode *)
monoSpc: BOOLEAN; (* monospace section? *)
nextleft: CARDINAL; (* next left margin *)
left, right: CARDINAL; (* margins *)
align: BOOLEAN; (* aligning? *)
alignment: CARDINAL; (* alignment *)
style: CARDINAL; (* current style *)
ref: IPF.anIndex; (* of toc entry referenced *)
k: IPF.anIndex; (* temp *)
flag: CARDINAL; (* flags for reference *)
PROCEDURE Reset;
BEGIN
spc:= TRUE; align:= FALSE;
style:= 0; ref:= NoRef;
END Reset;
INLINE PROCEDURE RoomFor (l: CARDINAL): BOOLEAN;
BEGIN
RETURN (col + l) <= (Window.ScreenWidth - left - right);
END RoomFor;
PROCEDURE CRCR;
VAR
l: CARDINAL;
BEGIN
IF line[0] = 0C THEN
Line[row]:= NIL;
ELSE
l:= Str.Length(line);
ALLOCATE( Line[row], l + 1 );
Str.Assign( Line[row]^, line );
Indent[row]:= left;
Offset[row]:= cofs; INC( cofs, VAL(LONGCARD,l) );
line:= "";
END;
IF row < HIGH(Line) THEN INC(row) END;
col:= 1; left:= nextleft;
END CRCR;
PROCEDURE Spc;
VAR
l: CARDINAL;
s: CARDINAL;
BEGIN
IF part[0] # 0C THEN
l:= Str.Length( part );
IF NOT RoomFor( l ) THEN CRCR END;
Str.Append( line, part ); INC(col,l);
part:= "";
END;
IF (col > 1) AND RoomFor(1) THEN
Str.Append( line, " " ); INC(col); INC(ofs);
END;
END Spc;
INLINE PROCEDURE CR;
BEGIN
IF part[0] # 0C THEN Spc END;
CRCR;
END CR;
INLINE PROCEDURE OptCR;
BEGIN
IF (col # 1) OR (part[0] # 0C) THEN CR END;
END OptCR;
INLINE PROCEDURE OptSecondCR;
BEGIN
IF (row < 2)
OR
(Line[row-1] # NIL)
THEN CR END;
END OptSecondCR;
(*#save,call(o_a_copy=>off)*)
INLINE PROCEDURE JustAdd (txt: ARRAY OF CHAR);
BEGIN
Str.Append( part, txt ); INC( ofs, VAL(LONGCARD,Str.Length(txt)) );
END JustAdd;
INLINE PROCEDURE Add (txt: ARRAY OF CHAR);
BEGIN
JustAdd( txt );
IF spc AND NOT monoSpc THEN Spc END;
END Add;
(*#restore*)
BEGIN (*BuildLines*)
WITH IPF.Toc^[i]^ DO
(* init to known state *)
RefCnt:= 0; AutoStart:= 0;
nextleft:= 0; left:= 0; right:= 1;
monoSpc:= FALSE; spc:= TRUE; Reset;
line:= ""; part:= ""; row:= 1; col:= 1; ofs:= 0; cofs:= 0;
Add( title^ );
(* process slots *)
FOR s:= 0 TO slotCnt-1 DO WITH IPF.Slot^[slot^[s]]^ DO
(* process words *)
FOR t:= 0 TO textCnt-1 DO
w:= text^[t];
IF w >= localCnt THEN (* control word *)
CASE w OF
| 0FAH: (* paragraph *)
OptCR; Reset; OptSecondCR;
| 0FCH: (* space control *)
spc:= NOT spc;
| 0FDH: (* line break *)
OptCR; spc:= TRUE;
| 0FEH: (* space *)
Spc;
| 0FFH: (* escape *)
len:= VAL(IPF.anIndex, text^[t+1] );
id:= text^[t+2];
base:= t+3;
INC( t, len ); DEC( len, 2 );
CASE id OF
| 2, 17, 18: (* set left margin *)
nextleft:= VAL(CARDINAL, text^[base] );
IF (id = 17) THEN
CR;
ELSIF (col = 1) AND (part[0] = 0C) THEN
left:= nextleft;
ELSE
WHILE col + left <= nextleft DO Spc END;
END;
| 3: (* set right margin *)
right:= VAL(CARDINAL, text^[base] );
| 4: (* change style *)
style:= VAL(CARDINAL, text^[base] );
| 5, 7, 15: (* reference, footnote, inlined-ref *)
IF (id = 15) AND (len = 3) THEN k:= 1 ELSE k:= 0 END;
ref:= VAL(IPF.anIndex,text^[base+k]) + 256 * VAL(IPF.anIndex,text^[base+k+1]);
IF len > 2+k THEN
flag:= VAL(CARDINAL, text^[base+k+2]);
ELSE
flag:= 0;
END;
IF RefCnt < HIGH(Ref) THEN
INC( RefCnt );
Ref[RefCnt].ref:= ref;
Ref[RefCnt].start:= ofs;
IF id = 15 THEN
Str.Append( word, IPF.Toc^[ref]^.title^ );
Ref[RefCnt].end:= ofs;
END;
IF RefCnt = HIGH(Ref) THEN
Yell( "Out of reference memory. Discarding rest..." );
END;
IF (AutoStart = 0) AND (id = 5) AND (flag AND 40H # 0) THEN
AutoStart:= RefCnt;
END;
END;
| 8: (* end of reference *)
Ref[RefCnt].end:= ofs;
| 11: (* begin monospace example *)
nextleft:= 4;
OptCR; OptSecondCR; left:= 4;
monoSpc:= TRUE;
| 12: (* end monospace example *)
nextleft:= 0; OptCR; OptSecondCR; left:= 0;
monoSpc:= FALSE;
| 13: (* special text colour *)
(* do nothing *)
| 19, 20: (* set fore/back colour *)
(* do nothing *)
| 26: (* begin lines *)
align:= TRUE; alignment:= VAL(CARDINAL,text^[base]);
OptCR;
| 27: (* end lines *)
align:= FALSE;
| 28: (* set left margin to current pos *)
nextleft:= col-1;
ELSE
Add( "{esc?}" );
END;
ELSE (*plain control*)
Add( "{ctrl?}" );
END;
ELSE (*plain word*)
Str.Assign( word, IPF.Dict^[local^[w]]^ );
Add( word );
END (*if control or word*);
IF row = HIGH(Line) THEN LineCnt:= row; RETURN END;
END (*for words*);
END END (*with slot*);
END;
OptCR;
LineCnt:= row;
END BuildLines;
PROCEDURE KillLines;
VAR
l: aLineNo;
BEGIN
FOR l:= 1 TO LineCnt DO
IF Line[l] # NIL THEN DEALLOCATE( Line[l], Str.Length(Line[l]^)+1 ) END;
END;
END KillLines;
VAR
Goto: IPF.anIndex;
Beg,Row,Col: CARDINAL;
PROCEDURE TextBuild (): CARDINAL;
BEGIN
RETURN LineCnt;
END TextBuild;
PROCEDURE Invert (x,l: CARDINAL);
CONST
InvAtt = 07FH;
VAR
c: CARDINAL;
line: ARRAY [0..79] OF RECORD
ch: CHAR;
att: SHORTCARD;
END;
BEGIN
IF l = 0 THEN RETURN END;
Window.RdBufferLn( Window.FullScreen, 1, Window.WhereY(), ADR(line), 80 );
IF line[x].ch # " " THEN line[x].att:= InvAtt END;
FOR c:= x+1 TO x+l-2 DO
line[c].att:= InvAtt;
END;
IF line[x+l-1].ch # " " THEN line[x+l-1].att:= InvAtt END;
Window.WrBufferLn( Window.FullScreen, 1, Window.WhereY(), ADR(line), 80 );
END Invert;
PROCEDURE TextLine (l: CARDINAL);
VAR
r: CARDINAL;
s,e: LONGCARD;
at: CARDINAL;
BEGIN
IF Line[l+1] # NIL THEN
IO.WrCharRep( " ", Indent[l+1] );
IO.WrStr( Line[l+1]^ );
s:= Offset[l+1];
e:= s + VAL(LONGCARD, Str.Length(Line[l+1]^));
FOR r:= 1 TO RefCnt DO
WITH Ref[r] DO
IF (start >= s) AND (start < e) THEN
at:= Indent[l+1] + VAL(CARDINAL, start - s);
IF end <= e THEN (*on same line*)
Invert( at, VAL(CARDINAL, end - start ));
ELSE
Invert( at, VAL(CARDINAL, e - s) - at );
END;
ELSIF (end > s) AND (end < e) THEN
Invert( Indent[l+1], VAL(CARDINAL,end - s) );
END;
END;
END;
END;
END TextLine;
PROCEDURE TextChoose (key: CHAR; VAR beg,row,col: CARDINAL): BOOLEAN;
VAR
r: aRefNo;
l,p: CARDINAL;
s: LONGCARD;
BEGIN
CASE key OF
| CHR(13): (* choose *)
s:= Offset[row+1];
IF col > Indent[row+1] THEN INC( s, VAL(LONGCARD, col - Indent[row+1] )) END;
FOR r:= 1 TO RefCnt DO WITH Ref[r] DO
IF (s >= start) AND (s < end) THEN
IF ref < IPF.TocCnt THEN
Goto:= ref;
Beg:= beg; Row:= row; Col:= col;
RETURN FALSE;
ELSE
Yell( "The reference of out of range! Decoding error? ..." );
END;
END;
END END;
| "F": (* find *)
l:= row+2;
WHILE l <= LineCnt DO
IF Line[l] # NIL THEN
p:= Str.Pos( Line[l]^, SearchTxt );
IF p # MAX(CARDINAL) THEN
row:= l-1; col:= p + Indent[l];
IF row >= beg + Window.CurrentScreenDepth THEN
beg:= row - Window.CurrentScreenDepth + 1
END;
RETURN TRUE;
END;
END;
INC(l);
END;
END;
RETURN TRUE;
END TextChoose;
PROCEDURE ViewLines;
VAR
l: aLineNo;
ch: CHAR;
BEGIN
Browse( TextBuild, TextLine, TextChoose, Beg,Row,Col );
END ViewLines;
PROCEDURE BrowseText (i: IPF.anIndex);
CONST
Size = 16;
TYPE
aPos = INTEGER [0..Size-1];
VAR
ch: CHAR;
hist: ARRAY aPos OF RECORD
ref: IPF.anIndex;
beg,row,col: CARDINAL;
END;
at: aPos;
prev: IPF.anIndex;
returned: BOOLEAN;
BEGIN
FOR at:= 0 TO 15 DO hist[at].ref:= NoRef END; at:= 0;
Goto:= i; Beg:= 0; Row:= 0; Col:= 0;
returned:= FALSE;
REPEAT
BuildLines( Goto ); prev:= Goto; Goto:= NoRef;
IF (AutoStart = 0) OR returned THEN
ViewLines;
KillLines;
returned:= (Goto = NoRef);
IF Goto # NoRef THEN
hist[at].ref:= prev;
hist[at].beg:= Beg;
hist[at].row:= Row;
hist[at].col:= Col;
at:= (at+1) MOD Size;
Beg:= 0; Row:= 0; Col:= 0;
ELSE
IF at = 0 THEN at:= Size-1 ELSE at:= at-1 END;
Goto:= hist[at].ref; hist[at].ref:= NoRef;
Beg:= hist[at].beg;
Row:= hist[at].row;
Col:= hist[at].col;
END;
ELSE (*autostart*)
KillLines;
IF AutoStart > 1 THEN
hist[at].ref:= prev;
hist[at].beg:= Beg;
hist[at].row:= Row;
hist[at].col:= Col;
at:= (at+1) MOD Size;
END;
Beg:= 0; Row:= 0; Col:= 0;
WHILE AutoStart < RefCnt DO
hist[at].ref:= Ref[AutoStart].ref;
hist[at].beg:= Beg;
hist[at].row:= Row;
hist[at].col:= Col;
at:= (at+1) MOD Size;
INC(AutoStart);
END;
Goto:= Ref[AutoStart].ref;
returned:= TRUE;
END;
UNTIL Goto = NoRef;
END BrowseText;
BEGIN (*IPFView*)
Window.Use( FullScreen );
Window.Info( Window.FullScreen, PopDef );
WITH PopDef DO
X1:= 10; X2:= 70;
Y1:= 5; Y2:= 16;
CursorOn:= TRUE; WrapOn:= TRUE; Hidden:= FALSE; FrameOn:= TRUE;
FrameDef:= Window.SingleFrame;
FrameFore:= Foreground;
FrameBack:= Background;
END;
END IPFView.