home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / ngdump.zoo / ngdump.pas < prev    next >
Pascal/Delphi Source File  |  1990-06-21  |  13KB  |  545 lines

  1. {$R+,I+,V-}
  2.  
  3. program ngdump;
  4.  
  5. uses crt, dos,
  6.      BufIO;
  7.  
  8. const progname = 'NGDUMP';
  9.       version  = 'V1.0';
  10.       copyright = 'Copyright 1989 J.P.Pedersen, 1990 E.v.Asperen';
  11.  
  12.       MaxNameLen = 40;
  13.       MaxLineLen = 160;
  14.  
  15. type gentry = record                    {General entry type}
  16.                 filptr:longint;
  17.                 name:string[MaxNameLen];
  18.               end;
  19.      line   = string[MaxLineLen];
  20.  
  21. var
  22.      mennu:array[0..3,0..8] of gentry;  {Buffer to hold variable part of guide menu structure}
  23.      itemlist:array[0..3] of byte;               {Menu structure info}
  24.      errorinfo:array[3..6] of string[14];        {Buffer for error messages}
  25.      f:file;                                                                                    {The guide file}
  26.      propath,homedir,streng:string;              {String variables, mostly for path and file use}
  27.      erro,
  28.         seealsonum,
  29.         menuantal,
  30.         menunr : byte;                           {Byte variables}
  31.      entrytype : (et_misc, et_short, et_long);
  32.      guidename : line;
  33.  
  34. const MaxLevel = 10;
  35.       OutBufSize   = 4096;
  36.  
  37. type FileBuffer = array [1..OutBufSize] of byte;
  38.  
  39. var  outf    : array [1..MaxLevel] of text;
  40.      flevel  : 1..MaxLevel;
  41.      OutBuf  : array [1..MaxLevel] of ^FileBuffer;
  42.      Nfiles  : word;
  43.      numentries : longint;
  44.  
  45.  
  46.  
  47. procedure threenitvars;                 {Initialize variables}
  48. begin
  49.     menunr := 0;
  50. end;
  51.  
  52. procedure twonitvars;                   {Initialize variables}
  53. begin
  54.     threenitvars;
  55. end;
  56.  
  57. procedure initvars;                     {Initialize variables}
  58. var str5:string;
  59. begin
  60.     twonitvars;
  61.     errorinfo[3] := 'File not found';
  62.     errorinfo[4] := 'Not an NG file';
  63.     errorinfo[5] := 'Unexpected EOF';
  64.     errorinfo[6] := 'Corrupted file';
  65.     str5 := '';propath := paramstr(0);
  66.     while (pos('\',propath) > 0) do begin
  67.         str5 := str5+copy(propath,1,pos('\',propath));
  68.         propath := copy(propath,pos('\',propath)+1,length(propath)-(pos('\',propath)+1));
  69.     end;
  70.     propath := str5;
  71. end;
  72.  
  73. var attr, startattr : byte;
  74.  
  75. procedure WriteNgString(var outf:text; s:string);
  76. var i,j:byte;
  77.     c:char;
  78. begin
  79.     i := 1;
  80.     attr := startattr;
  81.     while (i <= length(s)) do begin
  82.         c := s[i];
  83.         if c = #255 then begin
  84.             {Expand spaces}
  85.             inc(i);
  86.             c := s[i];
  87.             for j := 1 to ord(c) do begin
  88.                 write(outf, ' ');
  89.             end;
  90.         end
  91.         else begin
  92.             if (c = '!') and (i = 1) then write(outf, c);
  93.             write(outf, c);
  94.         end;
  95.         inc(i);
  96.     end;
  97.  
  98.     writeln(outf);
  99. end;
  100.  
  101. procedure WriteString(s:string);
  102. begin
  103.   WriteNgString(outf[flevel], s);
  104. end;
  105.  
  106. const Fx = 10; Fy = 2;
  107.       Gx = 10; Gy = 3;
  108.       Mx = 10; My = 5;
  109.       Cx = 10; Cy = 7;
  110.       Lx = 10; Ly = 8;
  111.       Sx = 10; Sy = 10;
  112.  
  113.  
  114. procedure ShowShort(s:string);
  115. begin
  116.   gotoxy(Sx, Sy);  ClrEol;
  117.   gotoxy(1, Sy+1); ClrEol;
  118.   gotoxy(Sx, Sy);  WriteNgString(Output, s);
  119. end;
  120.  
  121. procedure ShowLong(n:longint);
  122. begin
  123.   gotoxy(Lx, Ly); write(n:7);
  124. end;
  125.  
  126. procedure ShowEndLong;
  127. begin
  128.   gotoxy(Lx, Ly); ClrEol;
  129. end;
  130.  
  131. procedure ShowFile(s:string);
  132. begin
  133.   gotoxy(Fx, Fy); ClrEol; write(s);
  134. end;
  135.  
  136. procedure ShowGuide(s:string);
  137. begin
  138.   gotoxy(Gx, Gy); ClrEol; write(s);
  139. end;
  140.  
  141. procedure ShowCount(n:longint);
  142. begin
  143.   gotoxy(Cx, Cy); write(n:7);
  144. end;
  145.  
  146. procedure ShowMenu(s:string);
  147. begin
  148.   gotoxy(Mx, My); ClrEol; WriteNgString(output, s);
  149. end;
  150.  
  151. procedure ScreenInit;
  152. begin
  153.   ClrScr;
  154.   gotoxy(Fx-8, Fy); write(' file:');
  155.   gotoxy(Gx-8, Gy); write('guide:');
  156.   gotoxy(Mx-8, My); write(' menu:');
  157.   gotoxy(Cx-8, Cy); write('count:');
  158.   gotoxy(Lx-8, Ly); write('lines:');
  159.   gotoxy(Sx-8, Sy); write('entry:');
  160. end;
  161.  
  162. procedure ScreenExit;
  163. begin
  164.   gotoxy(1, Sy+3); ClrScr;
  165. end;
  166.  
  167. procedure Usage;                        {Write usage info}
  168. begin
  169.   writeln;
  170.   writeln('usage:        ngdump filename');
  171.   writeln;
  172.   Halt(1);
  173. end;
  174.  
  175. procedure slutlort(b:byte);  {Exit on error and display relevant error message}
  176. begin
  177.   if b > 3 then close(f);
  178.   if b > 2 then begin
  179.      writeln('NGDUMP ERROR #', b, ': '+errorinfo[b]+', cannot proceed');
  180.   end;
  181.   if b < 3 then usage;
  182.   halt(0);
  183. end;
  184.  
  185. procedure sllut(b:byte); {Error handler without exit, just indicating the error type}
  186. var sl:byte;
  187. begin
  188.   sl := 0;
  189.   if b > 3 then close(f);
  190.   writeln(' ',errorinfo[b],' - Press any key');
  191.   erro := 1;
  192. end;
  193.  
  194. function decrypt(b:byte):byte;          {Decrypt byte from NG format}
  195. begin
  196. (*
  197.   if ((b mod 32)>=16) then b := b-16 else b := b+16;
  198.   if ((b mod 16)>=8) then b := b-8 else b := b+8;
  199.   if ((b mod 4)>=2) then b := b-2 else b := b+2;
  200.   decrypt := b;
  201. *)
  202.   decrypt := b xor (16+8+2);   { this is somewhat more efficient... EVAS}
  203. end;
  204.  
  205. function read_byte:byte;                {Read and decrypt byte}
  206. var tb:byte;
  207.     numread:word;
  208. begin
  209.   bread(f, tb, 1, numread);
  210.   read_byte := tb xor 26;
  211. end;
  212.  
  213. function read_word:word;                {Read and decrypt word}
  214. var tb:byte;
  215. begin
  216.   tb := read_byte;
  217.   read_word := word(tb) or (word(read_byte) shl 8);
  218. end;
  219.  
  220. function read_long:longint;             {Read and decrypt longint}
  221. var tw:word;
  222. begin
  223.   tw := read_word;
  224.   read_long := longint(tw) or (longint(read_word) shl 16);
  225. end;
  226.  
  227. type BigStr = string[255];
  228.  
  229. procedure read_string(maxlen:byte; var s:BigStr);
  230. var c,j:byte;
  231. begin
  232.   j := 0;
  233.   repeat
  234.     c := read_byte;
  235.     inc(j);
  236.     s[j] := chr(c);
  237.   until (c = 0) or (j = maxlen);
  238.   s[0] := chr(j-1);
  239. end;
  240.  
  241. procedure read_menu;             {Read a menu structure into the menu buffer}
  242. var items,i,j:word;
  243. begin
  244.   mennu[menunr,0].filptr := bpos(f)-2;
  245.   bskip(f, 2);
  246.   items := read_word;
  247.   itemlist[menunr] := items;
  248.   bskip(f, 20);
  249.   for i := 1 to items-1 do begin
  250.     mennu[menunr,i].filptr := read_long;
  251.   end;
  252.   bskip(f, items * 8);
  253.   for i := 0 to items-1 do begin
  254.      with mennu[menunr, i] do begin
  255.         read_string( 40, name );
  256.      end;
  257.   end;
  258.   bskip(f, 1);
  259. end;
  260.  
  261. procedure skip_short_long;       {Skip procedure for the initial menu bseek}
  262. var length:word;
  263. begin
  264.   length := read_word;
  265.   bskip(f, length + 22);
  266. end;
  267.  
  268. procedure read_header(modf:byte); {Read NG file header and enter the guide name in the screen template}
  269. var buf       : array[0..377] of byte;
  270.     i,numread : word;
  271. begin
  272.   bread(f, buf, sizeof(buf), numread);
  273.   if ((buf[0]<>ord('N')) or (buf[1]<>ord('G'))) then begin
  274.      {If the two first characters in the file are not 'NG', the file is no guide}
  275.      if modf = 0
  276.       then slutlort(4)
  277.       else sllut(4);
  278.   end;
  279.  
  280.   menuantal := buf[6];
  281.   i := 0;
  282.   repeat
  283.     guidename[i+1] := chr(buf[i+8]);
  284.     inc(i);
  285.   until (buf[i+8] = 0);
  286.   guidename[0] := chr(i);
  287.  
  288.   ShowGuide( guidename );
  289.   bseek(f, 378);
  290. end;
  291.  
  292. procedure read_menus(modf:boolean);  {Initial menu bseek, indexing the whole file}
  293. var id : word;
  294. begin
  295.   repeat
  296.     id := read_word;
  297.     if (id < 2) then begin
  298.        skip_short_long
  299.     end
  300.     else if (id = 2) then begin
  301.        read_menu;
  302.        inc(menunr);
  303.     end
  304.     else if (id <> 5) then begin
  305.        if (filesize(f) <> bpos(f)) then begin
  306.           if (not modf)
  307.            then slutlort(5)
  308.            else sllut(5);        {NG file error}
  309.        end
  310.        else id := 5;
  311.     end;
  312.   until (id = 5);
  313.  
  314.   if (menunr <> menuantal) then begin
  315.      if (not modf)
  316.       then slutlort(6)
  317.       else sllut(6);                {Incomplete file}
  318.   end;
  319. end;
  320.  
  321. function MakeName:Dos.PathStr;
  322. var fname:Dos.PathStr;
  323. begin
  324.   inc(Nfiles);
  325.   str(Nfiles, fname);
  326.   MakeName := fname;
  327. end;
  328.  
  329. procedure OpenOutFile(n:word; s:Dos.PathStr);
  330. begin
  331.   assign(outf[n], s); rewrite(outf[n]);
  332.   SetTextBuf(outf[n], OutBuf[n]^, OutBufSize);
  333. end;
  334.  
  335. procedure read_entry(level:byte; fp:longint); forward;
  336.  
  337. procedure read_short_entry(level:byte);
  338. {Read short entry from file and wring some information out of it}
  339. var i, items: word;
  340.     subject : line;
  341.     entrypos, subj_pos, p0, p   : longint;
  342. begin
  343.   bskip(f, 2);
  344.   items := read_word;
  345.   bskip(f, 20);
  346.   p0 := bpos(f);
  347.   subj_pos := p0 + longint(items) * 6;
  348.   for i := 1 to items do begin
  349.     bskip(f, 2);
  350.     entrypos := read_long;
  351.     p := bpos(f);
  352.     bseek(f, subj_pos);
  353.     read_string( MaxLineLen, subject );
  354.     subj_pos := bpos(f);
  355.     write(outf[flevel], '!short:'); WriteString(subject);
  356. {}  ShowShort(subject);
  357.     read_entry(level+1, entrypos);
  358.     bseek(f, p);
  359.   end;
  360. end;
  361.  
  362. procedure read_long_entry;
  363. {Read long entry information}
  364. const MaxSeeAlso = 20;
  365. var i, linens, dlength, seealso_num : word;
  366.     s : line;
  367. begin
  368.   bskip(f, 2);
  369.   linens := read_word;
  370.   dlength := read_word;
  371. {} ShowLong(linens);
  372.   bskip(f, 18);       { 10 + links to prev/next entry (long's) }
  373.   for i := 1 to linens do begin
  374.     read_string( MaxLineLen, s );
  375.     WriteString(s);
  376.   end;
  377.  
  378.   if dlength <> 0 then begin            {If there are seealso entries, read them}
  379.      seealso_num := read_word;
  380.      { skip the offsets for the SeeAlso-items; }
  381.      bskip(f, seealso_num * 4);
  382.      { read the items; }
  383.      for i := 1 to seealso_num do begin
  384.         if i <= MaxSeeAlso then begin
  385.            read_string( MaxLineLen, s );
  386.            writeln(outf[flevel], '!seealso: "', s, '"');
  387.         end;
  388.      end;
  389.   end;
  390. {} ShowEndLong;
  391. end;
  392.  
  393. procedure read_entry(level:byte; fp:longint); {Read some kind of file entry}
  394. var id:word; fname:dos.pathstr;
  395. begin
  396.   inc(numentries); ShowCount(numentries);
  397.   bseek(f, fp);
  398.   id := read_word;
  399.   case id of
  400.    0: begin
  401.         if (level > 0) then begin
  402.            fname := MakeName;
  403.            writeln(outf[flevel], '!file: ',fname+'.NGO');
  404.            inc(flevel);
  405. {$ifdef Debug}
  406.            assign(outf[flevel], 'CON'); rewrite(outf[flevel]);
  407. {$else}
  408.            OpenOutFile(flevel, fname+'.DAT');
  409. {$endif}
  410.            read_short_entry(level);
  411.            close(outf[flevel]);
  412.            dec(flevel);
  413.         end
  414.         else begin
  415.            read_short_entry(level);
  416.         end;
  417.       end;
  418.    1: begin
  419. (*
  420.         if (level > 0) and (not odd(level)) then begin
  421.            fname := MakeName;
  422.            writeln(outf[flevel], '!long: ',fname+'.NGO');
  423.            inc(flevel);
  424. {$ifdef Debug}
  425.            assign(outf[flevel], 'CON'); rewrite(outf[flevel]);
  426. {$else}
  427.            OpenOutFile(flevel, fname+'.DAT');
  428. {$endif}
  429.            read_long_entry;
  430.            close(outf[flevel]);
  431.            dec(flevel);
  432.         end
  433.         else begin
  434.            read_long_entry;
  435.         end;
  436. *)
  437.         read_long_entry;
  438.       end;
  439.   end;
  440. end;
  441.  
  442.  
  443. procedure Main;
  444. label Next;
  445. var i,j,k:word;
  446.     linkf : text;
  447.     fname : Dos.PathStr;
  448. begin
  449.   numentries := 0;
  450.  
  451.   { create Menu Link Control File; }
  452.   assign(linkf, 'GUIDE.LCF'); rewrite(linkf);
  453.   writeln(linkf, '!name:'^i, guidename);
  454.   writeln(linkf);
  455.  
  456.   for i := 0 to menuantal-1 do begin
  457.      writeln(linkf, '!menu:'^i, mennu[i,0].name);
  458.      ShowMenu(mennu[i,0].name);
  459.      for j := 1 to itemlist[i]-1 do begin
  460.         close(outf[flevel]);
  461.         fname := MakeName;
  462.         OpenOutFile(flevel, fname+'.dat');
  463.         ShowMenu(mennu[i,j].name);
  464.         writeln(linkf, ^i, mennu[i,j].name, ^i, fname+'.ngo');
  465.         read_entry( 0, mennu[i,j].filptr );
  466. Next:
  467.      end;
  468.   end;
  469.  
  470.   close(linkf);
  471.  
  472.   { write a makefile; }
  473.   assign(linkf, 'MAKEGUID'); rewrite(linkf);
  474.   writeln(linkf, '.dat.ngo:');
  475.   writeln(linkf, ^i'ngc $<');
  476.   writeln(linkf);
  477.   write(linkf, 'OBJECTS=');
  478.   j := 0;
  479.   for i := 1 to Nfiles do begin
  480.      str(i, fname);
  481.      fname := fname + '.ngo ';
  482.      write(linkf, fname);
  483.      inc(j, length(fname));
  484.      if (j > 65) then begin
  485.         write(linkf, '\'^m^j^i);
  486.         j := 0;
  487.      end;
  488.   end;
  489.   writeln(linkf);
  490.   writeln(linkf);
  491.   writeln(linkf, 'guide.ng:    $(OBJECTS)');
  492.   writeln(linkf, ^i'ngml guide.lcf');
  493.   close(linkf);
  494. end;
  495.  
  496. var i:byte;
  497. begin                        {Main loop and command-line parser}
  498.   flevel := 1;
  499.   Nfiles := 0;
  500.   for i := 1 to MaxLevel do begin
  501.     new(OutBuf[i]);
  502.   end;
  503.  
  504. {$ifndef Debug}
  505.   assign(outf[flevel], 'CON');
  506. {$else}
  507.   assign(outf[flevel], 'GUIDE.DAT');
  508. {$endif}
  509.   rewrite(outf[flevel]);
  510.   SetTextBuf(outf[flevel], OutBuf[flevel]^, OutBufSize);
  511.  
  512.   writeln(progname,' ',version,'. ',copyright,'.');
  513.   initvars; {Initialize global variables}
  514.  
  515.   if ((paramstr(1)='/?') or (paramstr(1)='/h') or (paramstr(1)='/H')) then begin
  516.      Usage;
  517.   end;
  518.  
  519.   if (ParamCount <> 1) then begin
  520.      Usage;
  521.   end;
  522.  
  523.   streng := paramstr(1);
  524.  
  525.   if pos('.',streng)=0
  526.    then streng := streng+'.NG';        {Expand file name}
  527.  
  528.   assign(f, streng);
  529. {$I-}
  530.   reset(f, 1);
  531.   if ioresult<>0 then slutlort(3);   {If file does not exist, terminate and write cause of death}
  532. {$I+}
  533.  
  534.   ScreenInit;
  535.   ShowFile(streng);
  536.   ShowMenu('reading menu-info...');
  537.   read_header(0);
  538.   read_menus(False);
  539.   Main;
  540.  
  541.   close(f);
  542.   close(outf[flevel]);
  543.   ScreenExit;
  544. end.
  545.