home *** CD-ROM | disk | FTP | other *** search
- {$R+,I+,V-}
-
- program ngdump;
-
- uses crt, dos,
- BufIO;
-
- const progname = 'NGDUMP';
- version = 'V1.0';
- copyright = 'Copyright 1989 J.P.Pedersen, 1990 E.v.Asperen';
-
- MaxNameLen = 40;
- MaxLineLen = 160;
-
- type gentry = record {General entry type}
- filptr:longint;
- name:string[MaxNameLen];
- end;
- line = string[MaxLineLen];
-
- var
- mennu:array[0..3,0..8] of gentry; {Buffer to hold variable part of guide menu structure}
- itemlist:array[0..3] of byte; {Menu structure info}
- errorinfo:array[3..6] of string[14]; {Buffer for error messages}
- f:file; {The guide file}
- propath,homedir,streng:string; {String variables, mostly for path and file use}
- erro,
- seealsonum,
- menuantal,
- menunr : byte; {Byte variables}
- entrytype : (et_misc, et_short, et_long);
- guidename : line;
-
- const MaxLevel = 10;
- OutBufSize = 4096;
-
- type FileBuffer = array [1..OutBufSize] of byte;
-
- var outf : array [1..MaxLevel] of text;
- flevel : 1..MaxLevel;
- OutBuf : array [1..MaxLevel] of ^FileBuffer;
- Nfiles : word;
- numentries : longint;
-
-
-
- procedure threenitvars; {Initialize variables}
- begin
- menunr := 0;
- end;
-
- procedure twonitvars; {Initialize variables}
- begin
- threenitvars;
- end;
-
- procedure initvars; {Initialize variables}
- var str5:string;
- begin
- twonitvars;
- errorinfo[3] := 'File not found';
- errorinfo[4] := 'Not an NG file';
- errorinfo[5] := 'Unexpected EOF';
- errorinfo[6] := 'Corrupted file';
- str5 := '';propath := paramstr(0);
- while (pos('\',propath) > 0) do begin
- str5 := str5+copy(propath,1,pos('\',propath));
- propath := copy(propath,pos('\',propath)+1,length(propath)-(pos('\',propath)+1));
- end;
- propath := str5;
- end;
-
- var attr, startattr : byte;
-
- procedure WriteNgString(var outf:text; s:string);
- var i,j:byte;
- c:char;
- begin
- i := 1;
- attr := startattr;
- while (i <= length(s)) do begin
- c := s[i];
- if c = #255 then begin
- {Expand spaces}
- inc(i);
- c := s[i];
- for j := 1 to ord(c) do begin
- write(outf, ' ');
- end;
- end
- else begin
- if (c = '!') and (i = 1) then write(outf, c);
- write(outf, c);
- end;
- inc(i);
- end;
-
- writeln(outf);
- end;
-
- procedure WriteString(s:string);
- begin
- WriteNgString(outf[flevel], s);
- end;
-
- const Fx = 10; Fy = 2;
- Gx = 10; Gy = 3;
- Mx = 10; My = 5;
- Cx = 10; Cy = 7;
- Lx = 10; Ly = 8;
- Sx = 10; Sy = 10;
-
-
- procedure ShowShort(s:string);
- begin
- gotoxy(Sx, Sy); ClrEol;
- gotoxy(1, Sy+1); ClrEol;
- gotoxy(Sx, Sy); WriteNgString(Output, s);
- end;
-
- procedure ShowLong(n:longint);
- begin
- gotoxy(Lx, Ly); write(n:7);
- end;
-
- procedure ShowEndLong;
- begin
- gotoxy(Lx, Ly); ClrEol;
- end;
-
- procedure ShowFile(s:string);
- begin
- gotoxy(Fx, Fy); ClrEol; write(s);
- end;
-
- procedure ShowGuide(s:string);
- begin
- gotoxy(Gx, Gy); ClrEol; write(s);
- end;
-
- procedure ShowCount(n:longint);
- begin
- gotoxy(Cx, Cy); write(n:7);
- end;
-
- procedure ShowMenu(s:string);
- begin
- gotoxy(Mx, My); ClrEol; WriteNgString(output, s);
- end;
-
- procedure ScreenInit;
- begin
- ClrScr;
- gotoxy(Fx-8, Fy); write(' file:');
- gotoxy(Gx-8, Gy); write('guide:');
- gotoxy(Mx-8, My); write(' menu:');
- gotoxy(Cx-8, Cy); write('count:');
- gotoxy(Lx-8, Ly); write('lines:');
- gotoxy(Sx-8, Sy); write('entry:');
- end;
-
- procedure ScreenExit;
- begin
- gotoxy(1, Sy+3); ClrScr;
- end;
-
- procedure Usage; {Write usage info}
- begin
- writeln;
- writeln('usage: ngdump filename');
- writeln;
- Halt(1);
- end;
-
- procedure slutlort(b:byte); {Exit on error and display relevant error message}
- begin
- if b > 3 then close(f);
- if b > 2 then begin
- writeln('NGDUMP ERROR #', b, ': '+errorinfo[b]+', cannot proceed');
- end;
- if b < 3 then usage;
- halt(0);
- end;
-
- procedure sllut(b:byte); {Error handler without exit, just indicating the error type}
- var sl:byte;
- begin
- sl := 0;
- if b > 3 then close(f);
- writeln(' ',errorinfo[b],' - Press any key');
- erro := 1;
- end;
-
- function decrypt(b:byte):byte; {Decrypt byte from NG format}
- begin
- (*
- if ((b mod 32)>=16) then b := b-16 else b := b+16;
- if ((b mod 16)>=8) then b := b-8 else b := b+8;
- if ((b mod 4)>=2) then b := b-2 else b := b+2;
- decrypt := b;
- *)
- decrypt := b xor (16+8+2); { this is somewhat more efficient... EVAS}
- end;
-
- function read_byte:byte; {Read and decrypt byte}
- var tb:byte;
- numread:word;
- begin
- bread(f, tb, 1, numread);
- read_byte := tb xor 26;
- end;
-
- function read_word:word; {Read and decrypt word}
- var tb:byte;
- begin
- tb := read_byte;
- read_word := word(tb) or (word(read_byte) shl 8);
- end;
-
- function read_long:longint; {Read and decrypt longint}
- var tw:word;
- begin
- tw := read_word;
- read_long := longint(tw) or (longint(read_word) shl 16);
- end;
-
- type BigStr = string[255];
-
- procedure read_string(maxlen:byte; var s:BigStr);
- var c,j:byte;
- begin
- j := 0;
- repeat
- c := read_byte;
- inc(j);
- s[j] := chr(c);
- until (c = 0) or (j = maxlen);
- s[0] := chr(j-1);
- end;
-
- procedure read_menu; {Read a menu structure into the menu buffer}
- var items,i,j:word;
- begin
- mennu[menunr,0].filptr := bpos(f)-2;
- bskip(f, 2);
- items := read_word;
- itemlist[menunr] := items;
- bskip(f, 20);
- for i := 1 to items-1 do begin
- mennu[menunr,i].filptr := read_long;
- end;
- bskip(f, items * 8);
- for i := 0 to items-1 do begin
- with mennu[menunr, i] do begin
- read_string( 40, name );
- end;
- end;
- bskip(f, 1);
- end;
-
- procedure skip_short_long; {Skip procedure for the initial menu bseek}
- var length:word;
- begin
- length := read_word;
- bskip(f, length + 22);
- end;
-
- procedure read_header(modf:byte); {Read NG file header and enter the guide name in the screen template}
- var buf : array[0..377] of byte;
- i,numread : word;
- begin
- bread(f, buf, sizeof(buf), numread);
- if ((buf[0]<>ord('N')) or (buf[1]<>ord('G'))) then begin
- {If the two first characters in the file are not 'NG', the file is no guide}
- if modf = 0
- then slutlort(4)
- else sllut(4);
- end;
-
- menuantal := buf[6];
- i := 0;
- repeat
- guidename[i+1] := chr(buf[i+8]);
- inc(i);
- until (buf[i+8] = 0);
- guidename[0] := chr(i);
-
- ShowGuide( guidename );
- bseek(f, 378);
- end;
-
- procedure read_menus(modf:boolean); {Initial menu bseek, indexing the whole file}
- var id : word;
- begin
- repeat
- id := read_word;
- if (id < 2) then begin
- skip_short_long
- end
- else if (id = 2) then begin
- read_menu;
- inc(menunr);
- end
- else if (id <> 5) then begin
- if (filesize(f) <> bpos(f)) then begin
- if (not modf)
- then slutlort(5)
- else sllut(5); {NG file error}
- end
- else id := 5;
- end;
- until (id = 5);
-
- if (menunr <> menuantal) then begin
- if (not modf)
- then slutlort(6)
- else sllut(6); {Incomplete file}
- end;
- end;
-
- function MakeName:Dos.PathStr;
- var fname:Dos.PathStr;
- begin
- inc(Nfiles);
- str(Nfiles, fname);
- MakeName := fname;
- end;
-
- procedure OpenOutFile(n:word; s:Dos.PathStr);
- begin
- assign(outf[n], s); rewrite(outf[n]);
- SetTextBuf(outf[n], OutBuf[n]^, OutBufSize);
- end;
-
- procedure read_entry(level:byte; fp:longint); forward;
-
- procedure read_short_entry(level:byte);
- {Read short entry from file and wring some information out of it}
- var i, items: word;
- subject : line;
- entrypos, subj_pos, p0, p : longint;
- begin
- bskip(f, 2);
- items := read_word;
- bskip(f, 20);
- p0 := bpos(f);
- subj_pos := p0 + longint(items) * 6;
- for i := 1 to items do begin
- bskip(f, 2);
- entrypos := read_long;
- p := bpos(f);
- bseek(f, subj_pos);
- read_string( MaxLineLen, subject );
- subj_pos := bpos(f);
- write(outf[flevel], '!short:'); WriteString(subject);
- {} ShowShort(subject);
- read_entry(level+1, entrypos);
- bseek(f, p);
- end;
- end;
-
- procedure read_long_entry;
- {Read long entry information}
- const MaxSeeAlso = 20;
- var i, linens, dlength, seealso_num : word;
- s : line;
- begin
- bskip(f, 2);
- linens := read_word;
- dlength := read_word;
- {} ShowLong(linens);
- bskip(f, 18); { 10 + links to prev/next entry (long's) }
- for i := 1 to linens do begin
- read_string( MaxLineLen, s );
- WriteString(s);
- end;
-
- if dlength <> 0 then begin {If there are seealso entries, read them}
- seealso_num := read_word;
- { skip the offsets for the SeeAlso-items; }
- bskip(f, seealso_num * 4);
- { read the items; }
- for i := 1 to seealso_num do begin
- if i <= MaxSeeAlso then begin
- read_string( MaxLineLen, s );
- writeln(outf[flevel], '!seealso: "', s, '"');
- end;
- end;
- end;
- {} ShowEndLong;
- end;
-
- procedure read_entry(level:byte; fp:longint); {Read some kind of file entry}
- var id:word; fname:dos.pathstr;
- begin
- inc(numentries); ShowCount(numentries);
- bseek(f, fp);
- id := read_word;
- case id of
- 0: begin
- if (level > 0) then begin
- fname := MakeName;
- writeln(outf[flevel], '!file: ',fname+'.NGO');
- inc(flevel);
- {$ifdef Debug}
- assign(outf[flevel], 'CON'); rewrite(outf[flevel]);
- {$else}
- OpenOutFile(flevel, fname+'.DAT');
- {$endif}
- read_short_entry(level);
- close(outf[flevel]);
- dec(flevel);
- end
- else begin
- read_short_entry(level);
- end;
- end;
- 1: begin
- (*
- if (level > 0) and (not odd(level)) then begin
- fname := MakeName;
- writeln(outf[flevel], '!long: ',fname+'.NGO');
- inc(flevel);
- {$ifdef Debug}
- assign(outf[flevel], 'CON'); rewrite(outf[flevel]);
- {$else}
- OpenOutFile(flevel, fname+'.DAT');
- {$endif}
- read_long_entry;
- close(outf[flevel]);
- dec(flevel);
- end
- else begin
- read_long_entry;
- end;
- *)
- read_long_entry;
- end;
- end;
- end;
-
-
- procedure Main;
- label Next;
- var i,j,k:word;
- linkf : text;
- fname : Dos.PathStr;
- begin
- numentries := 0;
-
- { create Menu Link Control File; }
- assign(linkf, 'GUIDE.LCF'); rewrite(linkf);
- writeln(linkf, '!name:'^i, guidename);
- writeln(linkf);
-
- for i := 0 to menuantal-1 do begin
- writeln(linkf, '!menu:'^i, mennu[i,0].name);
- ShowMenu(mennu[i,0].name);
- for j := 1 to itemlist[i]-1 do begin
- close(outf[flevel]);
- fname := MakeName;
- OpenOutFile(flevel, fname+'.dat');
- ShowMenu(mennu[i,j].name);
- writeln(linkf, ^i, mennu[i,j].name, ^i, fname+'.ngo');
- read_entry( 0, mennu[i,j].filptr );
- Next:
- end;
- end;
-
- close(linkf);
-
- { write a makefile; }
- assign(linkf, 'MAKEGUID'); rewrite(linkf);
- writeln(linkf, '.dat.ngo:');
- writeln(linkf, ^i'ngc $<');
- writeln(linkf);
- write(linkf, 'OBJECTS=');
- j := 0;
- for i := 1 to Nfiles do begin
- str(i, fname);
- fname := fname + '.ngo ';
- write(linkf, fname);
- inc(j, length(fname));
- if (j > 65) then begin
- write(linkf, '\'^m^j^i);
- j := 0;
- end;
- end;
- writeln(linkf);
- writeln(linkf);
- writeln(linkf, 'guide.ng: $(OBJECTS)');
- writeln(linkf, ^i'ngml guide.lcf');
- close(linkf);
- end;
-
- var i:byte;
- begin {Main loop and command-line parser}
- flevel := 1;
- Nfiles := 0;
- for i := 1 to MaxLevel do begin
- new(OutBuf[i]);
- end;
-
- {$ifndef Debug}
- assign(outf[flevel], 'CON');
- {$else}
- assign(outf[flevel], 'GUIDE.DAT');
- {$endif}
- rewrite(outf[flevel]);
- SetTextBuf(outf[flevel], OutBuf[flevel]^, OutBufSize);
-
- writeln(progname,' ',version,'. ',copyright,'.');
- initvars; {Initialize global variables}
-
- if ((paramstr(1)='/?') or (paramstr(1)='/h') or (paramstr(1)='/H')) then begin
- Usage;
- end;
-
- if (ParamCount <> 1) then begin
- Usage;
- end;
-
- streng := paramstr(1);
-
- if pos('.',streng)=0
- then streng := streng+'.NG'; {Expand file name}
-
- assign(f, streng);
- {$I-}
- reset(f, 1);
- if ioresult<>0 then slutlort(3); {If file does not exist, terminate and write cause of death}
- {$I+}
-
- ScreenInit;
- ShowFile(streng);
- ShowMenu('reading menu-info...');
- read_header(0);
- read_menus(False);
- Main;
-
- close(f);
- close(outf[flevel]);
- ScreenExit;
- end.