home *** CD-ROM | disk | FTP | other *** search
/ For Beginners & Professional Hackers / cd.iso / docum / inter42.doc / int2whlp.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-07-20  |  45.7 KB  |  1,321 lines

  1. (*
  2.   Interrupt List -> WinHelp converter (c) 1994 by Christian Müller-Planitz
  3.   ------------------------------------------------------------------------
  4.   e-mail address: see CONST "e_mail"
  5.  
  6.  
  7.   The source and the compiled EXE-file can be freely distributed as long as
  8.   no changes are made without my knowledge.
  9.  
  10.   --------------------------------
  11.   Notes:
  12.    The program was tested with INTLIST38 and INTLIST39 and its output
  13.      was successfully compiled with the MS-Help-compiler "HC31.EXE" V3.10.445.
  14.  
  15.    The program needs the file "INTWHLP.DAT" in the 'source' directory.
  16.  
  17.    The program converted all sourcefiles (INTERRUP.* and *.LST) to
  18.      13 RTF files which needed 11MB on my harddrive.
  19.  
  20.    Compiling the RTF-files without compression took 13 minutes in
  21.      a DOS-Window under Win/NT on a 486-50 (if you run it under DOS
  22.      and if you have a fast hardrive cache, it might be faster).
  23.  
  24.    The (uncompressed) compiled HLP-File was approximately 7MB large.
  25.    If you want to create a compressed HLP-file, you have to exchange the
  26.      comments in the generated help-project file ("RB.HPJ"). Compressing
  27.      reduces the size of the HLP-file to 3MB but it takes
  28.      *more* (?? 28MB ??)  space on your harddrive while compiling.
  29.      In order to speed up compiling the compressed file, I've included a
  30.      temporary file ("RB.PH") of the helpcompiler in this archive.
  31.      Copy this file into the directory containing all the RTF files
  32.      before starting the compiler. This file is specific for INTERLIST39, so
  33.      if you want to get maximal compression in future versions, remove it.
  34.  
  35.    After the compilation finishes, you will find the file "RB.HLP".
  36.      Start Windows, create an icon in the program manager and double-click on it.
  37.  
  38.  
  39.   --------------------------------
  40.  
  41.    If you find this program usefull, if it does not work or if you have ideas
  42.    how to expand its functionality, feel fee to write an e-mail to me.
  43.  
  44.    As usual, I do not take any responsibility for possible damages done by
  45.    this program.
  46.  
  47.  
  48.   Two questions and their answers :
  49.   ---------------------------------
  50.    WHY is the HLP-file so large ?
  51.      In contrast to other programs that convert the interrupt list to
  52.      DOS-based hypertext systems, this program generates a large
  53.      index file that allows you to search for keywords.
  54.  
  55.    WHY did I wrote this program in Pascal and not in C ?
  56.      I think Pascal is a pretty nice language for small projects.
  57.      Another reason is the availability of efficient string handling under Pascal.
  58. *)
  59.  
  60. {$A+,B-,D-,E-,F-,I+,L-,N-,O-,R-,S-,V-}
  61. {$M 16384,25000,200000}
  62. (* minimum heap estimate (1994): 60*(6+10)+(30+40)*(43+10)+50*256=16770 *)
  63. (* (average entry size times (number of entries + 10) for FLAGS, CATEGORIES,
  64.    and CATEGORYKEYS entries) or times 256 for titles.
  65.    Each string in the [*ALIASES] sections requires (length of string) + 5.
  66. *)
  67.  
  68. Program INT2WHLP;
  69.  
  70. uses DOS;
  71.  
  72. { Version 1.00 - 1994
  73.   v. 1.01 -
  74.   v. 1.01a - 1994-02-16:
  75.     published with Ralf Brown's Interrupt List release 40.
  76.   v. 1.02 - 1994-04-07:
  77.     Changed program name from RB2HLP/INTWHLP to INT2WHLP.
  78.     Reduced the amount of RTF control codes.
  79.     Introduced program parameter controlled behaviour.
  80.     Improved flexibility by use of constants for parts of the control.
  81.     Changed and added some windows.
  82.     Extended search key facilities.
  83.   v. 1.03 - 1994-04-17:
  84.     Expanded/Compressed index switch.
  85.     Multi columns compressed index.
  86.     Interrupt titles OVERVIEW.LST.
  87.   v. 1.04 - 1994-04-29:
  88.     Configuration file including:
  89.       Program parameters can be defined in the configuration file. Such
  90.         definitions are overriden by program parameters.
  91.       Several WINHELP parameters, like font and size, can be specified.
  92.       Supplementary information "windows" can be included.
  93.       An ALIAS list can be compiled and written to the HPJ file.
  94.       A BUILDTAG list can be copied from the configuration to the HPJ file.
  95.   v. 1.05 - 1994-05-07:
  96.     Reconsidered default directories.
  97.   v. 1.06 - 1994-05-26:
  98.     Cross-references to tables.
  99.   v. 1.07 - 1994-05-29:
  100.     Edited procedure explain.
  101.     Skip "Section" file break sections (from a "--------!-Section--.."
  102.       divider line up to the next divider line).
  103.     Executable code released with Interrupr List release 41.
  104.     (ProgVers erroneously = '1.06').
  105.   v. 1.08 - 1994-07-10:
  106.     Tables as separate topics.
  107.   v. 1.10 - 1994-07-20:
  108.     Interrupt List release number dependent compilation.
  109.     Published with Interrupt List release 42.
  110.  
  111. }
  112.  
  113. const
  114.   progName  = 'INT2WHLP';
  115.   progVers  = '1.10';
  116.   hfName    = 'INTWIN'; { helpfile name }
  117.   copyright = 'Copyright (C) 1994 by Christian Müller-Planitz';
  118.   e_mail    = '"cmuelle@eos.ncsu.edu" or "cmueller@techfak.uni-bielefeld.de"';
  119.     { e-mail address in Intro/Explain windows }
  120.   e_mailCredits = e_mail;
  121.     { e-mail address in the Credits window }
  122.  
  123.   { the strings ack01 ... are displayed in the Credits window }
  124.  
  125.   { thanks to (excuse the format): }
  126.   ack01 = '\par{\b Bent Lynggaard} for ideas, parts of the code, and the "Miscellaneous Information" entry.';
  127.   ack02 = '';
  128.   ack03 = '';
  129.   ack04 = '';
  130.   ack05 = '';
  131.   {if extended, update procedure "Credits"}
  132.  
  133. {$I INT2WHLP.INC }
  134.  
  135.   Procedure NewHlpPage(VAR F : Text; S, ID, BrowseID : String; Classification : Char);
  136.     type
  137.       intRec = record (* used for fast test and transfer of string *)
  138.     ln: byte;    (* string length *)
  139.     l: longint;  (* 'INT ' *)
  140.     n: word;     (* 'nn' *)
  141.     c7: char;    (* ' ' *)
  142.     l2: longint; (* 'ahal' or 'List' *)
  143.     c12: char;   (* ' ' *)
  144.     w: word;     (* '- ' *)
  145.       end; (* record intRec *)
  146.       nnRec = record ln: byte; w: word; (* for 'nn' *) end;
  147.       ahalRec = record ln: byte; l: longint; (* for 'ahal' *) end;
  148.     const
  149.       linebreak = #13#10'\par\tab';
  150.       intC = ord('I')+ord('N')*$100+ord('T')*$10000+ord(' ')*$1000000;
  151.       listC = ord('L')+ord('i')*$100+ord('s')*$10000+ord('t')*$1000000;
  152.       sepC = ord('-')+ord(' ')*$100;
  153.       int:  string[3] = 'nn';   (* preset length to 2, never changed *)
  154.     VAR
  155.       intR: nnRec absolute int; (* type cast *)
  156.       p,q : Word;
  157.       func: string[5];
  158.       funcR: ahalRec absolute func; (* type cast *)
  159.       ss: string;
  160.       ssR: intRec absolute ss;
  161.  
  162.     Procedure FootNote(Note: Char; ID : String);
  163.       begin
  164.     writeln(F, Note,'{\footnote{',Note,'} ', ID, '}');
  165.       end;
  166.  
  167.  
  168.     procedure insertInt;
  169.       begin
  170.     insert('INT '+int+equStr+func+';'+int+' '+func+';',ss,11);
  171.       (* "INT nn Ar = XXxx;nn XXxx;"  (XXxx = ahal, ah, or --al) *)
  172.     if equStr[3]='L' then delete(ss,21+equBlanks,2);
  173.       (* "--" from AL = --al *)
  174.     insert(copy(ss,18,6+equBlanks+2*ord(equStr[3]='X')),ss,11);
  175.       (* "Ar = XXxx;" *)
  176.       end;
  177.  
  178.     begin
  179.       writeln(F, '\page\pard\keepn\li'+indent+'\fi-'+indent);
  180.     (* the '\page' inserted unconditionally here will cause that each .RTF
  181.        file begin with an empty, unreferenced "topic". This is harmless.
  182.        It requires, though, that [OPTIONS] CONTENTS= is defined, or we
  183.        would be left in an empty topic without an exit.
  184.     *)
  185.       FootNote('#', ID);
  186.       if S<>'' then FootNote('$', S);
  187.       if BrowseID<>'' then FootNote('+', BrowseID);
  188.       if (Classification <> nullClassification) then begin
  189.     ss:=s;
  190.     if (ssR.l=intC) AND (ssR.c7=' ') then begin
  191.       if (length(ss)>14) AND (ssR.c12=' ') AND (ssR.w=sepC) then begin
  192.         (* insert highlight in s *)
  193.         insert('}}',s,7);
  194.         insert('{'+highlightInt+'{',s,1);
  195.           (* 2nd '{' terminates attribute, a ' ' distorts if attrib. is empty *)
  196.         (* insert tiny, short, and full form of INT *)
  197.         intR.w:=ssR.n;   (* length of "int" is preset to 2 *)
  198.         (* same as "int:=copy(ss,5,2);": nn from INT nn ahal - xxxx ... *)
  199.         funcR.l:=ssR.l2;
  200.         funcR.ln:=4;     (* func = 'ahal' *)
  201.         ss[7]:=';';      (* INT nn;ahal - xxxx ... *)
  202.         ss[8]:=int[1];
  203.         ss[9]:=int[2];
  204.         ss[10]:=';';     (* INT nn;nn;l - xxxx ... *)
  205.         delete(ss,11,4); (* INT nn;nn;xxxx ... *)
  206.         if func<>'----' then begin
  207.           if func[3]='-' then begin equStr[3]:='H'; func[0]:=#2; end
  208.           else if func[1]='-' then equStr[3]:='L'
  209.           else equStr[3]:='X';
  210.           insertInt;
  211.     (* INT nn;nn;AX = ahal;INT nn AX = ahal;nn ahal;xxxx ... or
  212.        INT nn;nn;AH = ah;INT nn AH = ah;nn ah;xxxx ... or
  213.        INT nn;nn;AL = al;INT nn AL = al;nn --al;xxxx ...
  214.     *)
  215.           if equStr[3]='X' then begin (* insert also the AH values *)
  216.         equStr[3]:='H';
  217.         func[0]:=#2;
  218.         insertInt;
  219. (* INT nn;nn;AH = ah;INT nn AH = ah;nn ah;AX = ahal;INT nn AX = ahal;nn ahal;xxxx ... *)
  220.           end; (* if ar=ax *)
  221.         end; (* if func<>'----' *)
  222.       end (* if length(ss)>14 ... *)
  223.       else if (length(s)=11) and (ssR.l2=listC) then begin
  224.         insert(copy(ss,1,6)+';',ss,1); (* INT nn;INT nn List *)
  225.         insert(copy(ss,5,3),ss,8); (* INT nn;nn;INT nn List *)
  226.       end; (* else if ... *)
  227.     end; (* if (ssR.l=intC) ... *)
  228.     if (Classification <> InvalidClassification)
  229.     AND (Classification > ' ') then begin
  230.       if categoryKeyStrings[Classification]^<>'' then
  231.         insert(categoryKeyStrings[Classification]^+';',ss,1);
  232.       if (Classification<'A') OR (Classification>'Z') then
  233.         insert(Classification+';',ss,1)
  234.       else insert(Classification+'!;',ss,1);
  235.     end; (* if (Classification<>InvalidClassification) ... *)
  236.     if Classification=tableClassification then begin
  237.       delete(ss,1,8); (* 'II SUBF ' *)
  238.       insert('#'+currentTable+';',ss,1);
  239.     end (* if Classification=tableClassification *)
  240.     else repeat
  241.       p := POS(' - ', ss);
  242.       if p <> 0 then
  243.         begin
  244.           ss[p] := ';';
  245.           delete(ss,succ(p),2);
  246.         end;
  247.     until p=0;
  248.     FootNote('K', SS);
  249.       end; (* if (Classification<>nullClassification) *)
  250.  
  251.       write(F, '{\f0'+headerAttrib,headerSize,' ');
  252.       if classification=specialClassification then write(F, indexHeader);
  253.       writeln(F, S,'}');
  254.       writeln(F, '\par\pard\keep');
  255.  
  256.     end;
  257.  
  258.  
  259.   Procedure AddTopic(VAR F: Text; ST, S, ID: String);
  260.   { print: ST as a string (normally "\par " for new line), S as a hotspot,
  261.     ID as the corresponding jump address or macro.
  262.   }
  263.     const sp: array[0..7] of string[7] =
  264.       ('       ','      ','     ','    ','   ','  ',' ','');
  265.     var p: integer;
  266.     begin
  267.       repeat
  268.     (* detab S, otherwise the string cannot be selected with the cursor
  269.        in a tab position.
  270.     *)
  271.     p:=pos(#9,S);
  272.     if p<>0 then begin S[p]:=' '; insert(sp[(p-1) AND 7],S,p); end;
  273.       until p=0;
  274.       writeln(F, ST,'{\uldb ', S, '}{\v ', ID, '}');
  275.     end;
  276.  
  277.  
  278.   Procedure CheckKeyWords(VAR s : STring);
  279.     CONST KeyWords = 11;
  280.     CONST Keys : Array[1..KeyWords] of String[10] = ('Desc:', 'Notes:',
  281.       'Note:', 'Warning:', 'Index:', 'SeeAlso:', 'Return:', 'BUG:', 'BUGS:',
  282.       'Program:', 'Range:');
  283.     CONST IStr = '{\b ';
  284.     VAR q,p : Integer;
  285.  
  286.     begin
  287.  
  288.       for q:= 1 to KeyWords do
  289.     begin
  290.       p := POS(Keys[q], S);
  291.       if p <> 0 then
  292.         begin
  293.           insert(IStr, S, p);
  294.           insert('}', S, p+Length(Keys[q]) + Length(IStr));
  295.           exit;
  296.         end;
  297.     end;
  298.     end;
  299.  
  300.  
  301.   Function GetSpecialNote(Note : Char)  : String;
  302.     begin
  303.       if flagStrings[Note]^='' then GetSpecialNote:='<unknown note in header>'
  304.       else GetSpecialNote:=flagStrings[Note]^;
  305.     end;
  306.  
  307.  
  308. procedure insertQueued;
  309.   var i,j: word;
  310.   begin
  311.     if (indexColumns>1) OR (queuedEntry='') then exit;
  312.     val('$'+lastSection,i,j);
  313.     if singlesInMain AND (INTcounts[i]=1) then
  314.       AddTopic(IntFile, nl, queuedEntry, lastSection+'_1')
  315.     else AddTopic(IntFile, nl, title, lastSection+'_0');
  316.     queuedEntry:='';
  317.   end; (* procedure insertQueued *)
  318.  
  319.  
  320.   Function ProcessIntList(FName : PathStr) : Boolean;
  321.     LABEL STOP, error_Exit, endOfLoop, table, fobi, noTable;
  322.     type
  323.       kind = (firstPart,inOverview,inFlags,inCategories,inKeys,
  324.     inFileBreakSection,pastTest);
  325.       tableId = array[1..4] of char;
  326.       sRec = record
  327.     l: byte; (* length *)
  328.     w: word; (* with '(T' *)
  329.     d: longint; (* with 'able' *)
  330.     c1: char; (* ' ' *)
  331.     ti: tableId;
  332.     c2: char; (* ')' *)
  333.       end; (* record sRec *)
  334.       castRec = record
  335.     l: byte;
  336.     case byte of
  337.       1: (w: word);
  338.       2: (d: longint);
  339.       end; (* record castRec *)
  340.       dividerRec = record
  341.     s: string[8];    (* '--------' *)
  342.     cat: char;    (* category *)
  343.     c: char;    (* '-' *)
  344.     w: word;    (* Interrupt number, 2 hex digits *)
  345.     d: longint;    (* sub function, 4 hex digits or '-' *)
  346.       end; (* record dividerRec *)
  347.     const
  348.       INTno:     integer = 0;
  349.       bufferString: string = ''; (* transfers part of split string *)
  350.       ta = ord('(')+ord('T')*$100; (* (Table nnnn) *)
  351.       able = ord('a')+ord('b')*$100+ord('l')*$10000+ord('e')*$1000000;
  352.       fo = ord('F')+ord('o')*$100; (* Format of ... *)
  353.       bi = ord('B')+ord('i')*$100; (* Bitfields for ... *)
  354.       Section: String[3] = '--'; (* initialize to length 2 *)
  355.       SubFunc: String[5] = '----'; (* length 4 *)
  356.       allMessages: boolean = false;
  357.  
  358.     VAR
  359.     tP:          ^tableID;
  360.     hLineP,tLineP : ^string; (* pointers to header and (Table) lines *)
  361.     p,q        : integer;
  362.     lineCount  : word; (* for error report *)
  363.     NewSection : Boolean;
  364.     Classification,c      : Char;
  365.     current    : kind;
  366.     inTable    : boolean;
  367.     table_Id   : String[7];
  368.     tableTitle : String[119];
  369.     s          : String;
  370.     SpecialNote : String;
  371.     sR         : sRec absolute s; (* for type cast *)
  372.     sectionR   : castRec absolute Section;
  373.     subFuncR   : castRec absolute SubFunc;
  374.     dR         : dividerRec absolute s;
  375.  
  376.     F1, F2        : Text;
  377.  
  378.     function isNumber(var ti: tableId): boolean;
  379.       var i: integer;
  380.       begin
  381.     isNumber:=false;
  382.     for i:=1 to 4 do case ti[i] of '0'..'9': ; else exit; end;
  383.     isNumber:=true;
  384.       end; (* function isNumber in function ProcessIntList *)
  385.     procedure insertRef;
  386.       begin
  387.     if inTable then AddTopic(F2,nl,'INT '+Section+' '+SubFunc, TopicStr+mainW)
  388.     else if IntTopicStr<>'' then AddTopic(F2,nl,copy(title,1,6),IntTopicStr);
  389.       end; (* procedure insertRef in function ProcessIntList *)
  390.     procedure wrSection;
  391.       begin write(Section,#13); end;
  392.  
  393.     begin
  394.      {$I-}
  395.       assign(F1, InPath + FName);
  396.       reset(F1);
  397.      {$I+}
  398.       if IOResult <> 0 then
  399.     begin
  400.       ProcessIntList := FALSE;
  401.       EXIT;
  402.     end;
  403.  
  404.       writeln('Processing : ', InPath + FName);
  405.       OpenOutFile(F2);
  406.       write(LastSection,#13);
  407.  
  408.       readLine(F1, s);    { ignore copyright in 1st two lines }
  409.       readLine(F1, s);
  410.       lineCount:=2;
  411.       current:=firstPart;
  412.       inTable:=false;
  413.  
  414.       SpecialNote := '';
  415.  
  416.  
  417.       while not(EOF(F1)) do
  418.     begin
  419.       readLine(F1, s);
  420.       inc(lineCount);
  421.       NewSection := (s[1]= '-') and (Pos('--------', s) <> 0);
  422.  
  423.       if NewSection then
  424.         begin
  425.           insertRef;
  426.           inTable:=false;
  427.  
  428.           SectionR.w:=dR.w; (* chars 11..12 of divider line *)
  429.           SubFuncR.d:=dR.d; (* chars 13..16 of divider line *)
  430.           Classification := s[9];
  431.           if Classification = '!' then
  432.         begin
  433.           delete(s,1,12);
  434.  
  435.           q:=0;
  436.           while (s[q] <> '-') and (q < Length(s)) do
  437.             Inc(q);
  438.           s[0] := chr(q-1);  { remove '-' chars at the end }
  439.           if s='OVERVIEW' then current:=inOverview
  440.           else if s='FLAGS' then current:=inFlags
  441.           else if s='CATEGORIES' then current:=inCategories
  442.           else if s='CATEGORYKEYS' then current:=inKeys
  443.           else if s='Section' then begin
  444.             current:=inFileBreakSection;
  445.             Section:=LastSection;
  446.             IntTopicStr:='';
  447.             goto endOfLoop; (* skip file break section *)
  448.           end (* if s='Section' *)
  449.           else current:=firstPart;
  450.           (* Interrupt List release 41 does not include OVERVIEW
  451.              and CATEGORYKEYS as sections, but as separate files.
  452.              The program is prepared for this information being
  453.              parts of the List.
  454.           *)
  455.  
  456.           if s = '' then s:= 'Note';   { shit ! }
  457.  
  458.           if EOF(F1)  then   { last line of document ?}
  459.             goto STOP;
  460.           inc(TopicNo);
  461.           str(TopicNo, TopicStr);
  462.         end { if Classification = '!' }
  463.           else
  464.         begin
  465.           if section<>lastSection then begin
  466.             val('$'+section,INTno,q);
  467.             if q<>0 then begin
  468.               writeln('Cannot interpret interrupt number in line ',
  469.             lineCount,': "',section,'".');
  470.               goto error_Exit;
  471.             end; (* if q<>0 *)
  472.           end; (* if section<>lastSection *)
  473.           current:=pastTest;
  474.           readLine(F1, s);
  475.           inc(lineCount);
  476.           inc(INTcounts[INTno]);
  477.           str(INTcounts[INTno], TopicStr);
  478.           insert(section+'_',TopicStr,1);
  479. (* We could compare already here: "while aliasString=s do ..." if we want to
  480.    use the orginal interrupt header line to find aliases. However,
  481.      1. it is easier to identify the original position of an alias line,
  482.      2. it is easier to determine the alias sequense in the config. file,
  483.      3. it is easier to track the reason for a "not found" error, and
  484.      4. the chance for an alias line to be unique is higher
  485.    if we compare after the manipulation of the header line. Also, if we copy
  486.    from the INTWIN index rather than from the original list, the lines are
  487.    already manipulated.
  488. *)
  489.           while (s[8] <> '-') do   { special flags in titel-line ? }
  490.             begin
  491.               if s[8] <> ' ' then
  492.             SpecialNote:=SpecialNote+#13#10'\par '+GetSpecialNote(s[8]);
  493.               delete(s, 8, 1);
  494.             end;
  495.  
  496.           Insert(subFunc+' ', S, 8);
  497.           while aliasString=S do begin
  498.             saveAlias(nextAliasPP,aliasId+TopicStr);
  499.             getNextAlias(aliasP,aliasId,aliasString);
  500.           end; (* while aliasString=S *)
  501.         end; { else (Classification<>'!') }
  502.  
  503.           if LastSection <> Section then
  504.         begin
  505.           if Classification = '!' then begin
  506.             if indexColumns=1 then insertQueued;
  507.             IntTopicStr:='N_'+TopicStr;
  508.             title:='Notes';
  509.             if (notesCount MOD indexColumns)=0 then write(IntFile,'\par ')
  510.             else  write(IntFile,'\tab ');
  511.             inc(notesCount);
  512.             writeln(IntFile,'{\uldb Notes}{\v ',IntTopicStr,'}');
  513.           end (* if Classification = '!' *)
  514.           else begin (* (Classification <> '!'*)
  515.             if INTno<lastINTno then begin
  516.               (* we cannot tolerate inconsistent sorting in a
  517.              multi-column index.
  518.               *)
  519.               writeln('Inconsistent sorting in file ',FName,
  520.             ' line ',lineCount);
  521.               writeln('INT ',section,' appears after INT ',lastSection);
  522.               if indexColumns>1 then begin
  523.             wl('This can be tolerated only with a single column index.');
  524.          error_Exit:
  525.             errorExit('Please correct the file and try again.',1);
  526.               end (* if indexColumns>1 *)
  527.               else wl('It is recommended to correct the file.');
  528.             end; (* if INTno<lastINTno *)
  529.             if INTno<>lastINTno then begin
  530.               wrSection;
  531.               IntTopicStr:=Section+'_0';
  532.               if indexColumns=1 then begin
  533.             insertQueued;
  534.             queuedEntry:=s;
  535.               end; (* if indexColumns=1 *)
  536.               title:=INTtitles[INTno]^;
  537.               if title='' then title:='INT '+Section;
  538.               lastINTno:=INTno;
  539.             end; (* if INTno<>lastINTno *)
  540.           end; (* else (Classification <> '!') *)
  541.  
  542.           if backRef then AddTopic(SubIntFile,nl,'Interrupts','idInterrupts');
  543.             (* don't insert a backward reference the very first time *)
  544.           backRef:=true; (* but in all the rest *)
  545.           NewHlpPage(SubIntFile, title, IntTopicStr,'i:0', specialClassification);
  546.           if twoIndexes AND indexHeaders then
  547.             OutLn(IndexFile,'\par '+title);
  548.           LastSection := Section;
  549.         end; { if LastSection <> Section }
  550.  
  551.  
  552.           if TopicNo=1 then c:=specialClassification
  553.         (* The initial Interrupt List section should cary the
  554.            indexHeader.
  555.         *)
  556.           else c:=Classification;
  557.           NewHlpPage(F2, s, TopicStr,'l:0', c);
  558.           if SpecialNote <> '' then
  559.         begin
  560.           writeln(F2, '{\cf0 ', SpecialNote, '}'#13#10'\par ');
  561.           SpecialNote := '';
  562.         end; { if SpecialNote <> '' }
  563.  
  564.           OutLN(F2, '{\cf0 Category: '+ Classification +
  565.         ' - ' + categoryStrings[Classification]^ + '}\par');
  566.           if Classification='!' then setTabs(F2, 8, deciPoints, 10)
  567.         (* we will set tabs in the few Notes, but not in all the
  568.            INT entries.
  569.         *)
  570.           else if markKeys then OutLN(F2,'{\b Inp.:}');
  571.           if twoIndexes then AddTopic(IndexFile, indentIndex, s, TopicStr);
  572.           AddTopic(SubIntFile, nl, s, TopicStr);
  573.         end { if NewSection }
  574.       else          { no new section }
  575.        begin
  576.          case current of
  577.            pastTest:     begin
  578.       { this paragraph is un-indented to gain space for code }
  579.       if markKeys then CheckKeyWords(s);
  580.       if tables then case sR.w of
  581.     ta: if (length(s)>=12) AND (sR.d=able) AND (sR.c1=' ') AND (sR.c2=')')
  582.       AND isNumber(sR.ti) then begin
  583.         hLineP:=@bufferString;
  584.         tLineP:=@s;
  585.       table:
  586.         if eof(F1) then begin
  587.           writeln('Unextected end of file in table at INT ',Section,
  588.         ' Subfunc ',SubFunc);
  589.           wrSection;
  590.           goto Stop;
  591.         end; (* if eof(F1) *)
  592.         readln(F1, bufferString);
  593.         inc(lineCount);
  594.         p:=pos('(Table ',tLineP^);
  595.         if (p=0) OR  (length(tLineP^)<p+11) OR (tLineP^[p+11]<>')')then begin
  596.       noTable:
  597.           inc(missingTableCounter);
  598.           if allMessages OR (missingTableCounter<=missingTableLimit) then begin
  599.         writeln('Missing "(Table nnnn)" in INT ',Section,
  600.           ' Subfunc ',SubFunc,' (line ',lineCount,'):');
  601.         writeln(pred(lineCount):5,s:succ(length(s)));
  602.         writeln(lineCount:5,bufferString:succ(length(bufferString)));
  603.         if missingTableCounter=missingTableLimit then begin
  604.           wl(#13#10'Several missing tables encountered. If '
  605.             +progName+' is used on release 40 or lower');
  606.           wl('of the List, it should be started with the program '
  607.             +'parameter -r40, or with key');
  608.           wl('releaseNo=40 in section [OPTIONS] of the configuration file.');
  609.           write('s=stop; m=messages; else continue without messages: ');
  610.           ProcessTime:=ProcessTime-memL[$40:$6C];
  611.           p:=readKeyWd;
  612.           ProcessTime:=ProcessTime+memL[$40:$6C];
  613.             (* sets ProcessTime "pause" ticks later than original *)
  614.           if word(p)<$100 then writeln (* function key *)
  615.           else begin
  616.             writeln(char(p));
  617.             case upcase(char(p)) of
  618.               'S': errorExit('Terminated by user',1);
  619.               'M': allMessages:=true;
  620.             end; (* if ... case ... of *)
  621.           end; (* if word(p)>$ff *)
  622.         end; (* if missingTableCounter=missingTableLimit *)
  623.         wrSection;
  624.           end; (* if allMessages ... *)
  625.           insert(nl,bufferString,1); (* force newline *)
  626.         end (* if (p=0) ... *)
  627.         else begin
  628.           tP:=@tLineP^[p+7];
  629.           if NOT isNumber(tP^) then goto noTable;
  630.           insertRef;
  631.           inTable:=true;
  632.           currentTable:=tP^;
  633.           table_Id:='t'+currentTable;
  634.           tableTitle:=Section+' '+SubFunc+' '+hLineP^;
  635.           while tableAliasString=tableTitle do begin
  636.         saveAlias(nextAliasPP,tableAliasId+table_id);
  637.         getNextAlias(tableAliasP,tableAliasId,tableAliasString);
  638.           end; (* while ... *)
  639.           NewHlpPage(F2, tableTitle, table_Id,'t:0', tableClassification);
  640.           if tableWindow then begin
  641.         AddTopic(F2,nl,'Copy to Main',table_Id+mainW);
  642.         OutLn(F2,'');
  643.           end; (* if tableWindow *)
  644.           AddTopic(TableFile,nl+currentTable+'  ',tableTitle,table_Id);
  645.         end; (* else *)
  646.     end; (* case ta *)
  647.     fo: if pos('Format of ',s)=1 then begin
  648.       fobi:
  649.       hLineP:=@s;
  650.       tLineP:=@bufferString;
  651.       goto table;
  652.     end; (* case fo *)
  653.     bi: if pos('Bitfields for ',s)=1 then goto fobi;
  654.     else begin
  655.       p:=length(s)-4;
  656.       for q:=p downto 1 do begin
  657.         if (s[q]='#') AND ((q=p) OR (s[q+5]<'0') OR (s[q+5]>'9')) then begin
  658.           tP:=@s[q+1];
  659.           if isNumber(tP^) then begin
  660.         insert('}{\v t'+tP^+tableW+'}', S, q+5);
  661.         insert('{\uldb ', S, q);
  662.         if (length(s)-q>150) AND (q>20) then begin
  663.           (* we must ensure keeping length(S)<256 *)
  664.           bufferString:=copy(S, q, 255);
  665.           S[0]:=char(pred(q)); (* delete the copied part *)
  666.         end; (* if (length(s)-q>150)... *)
  667.           end; (* if isNumber *)
  668.         end; (* if (s[q]='#')... *)
  669.       end; (* for q=p *)
  670.     end; (* else *)
  671.       end; (* case sR.W of *)
  672.       { indent again }
  673.                  end; (* case pastTest *)
  674.            firstPart:    check1st(s);
  675.            inOverview:   getINTtitle(s,INTtitles);
  676.            inFlags:      scan(s,flagStrings);
  677.            inCategories: scan(s,categoryStrings);
  678.            inKeys:       scan(s,categoryKeyStrings);
  679.            inFileBreakSection: goto endOfLoop;
  680.          end; (* case current of *)
  681.          OutLN(F2, s);
  682.          if bufferString<>'' then begin
  683.            if inTable then OutLn(F2, bufferString) (* with "newline" *)
  684.            else writeln(F2, bufferString); (* no "newline" (\par ) *)
  685.            bufferString:='';
  686.          end; (* if bufferString<>'' *)
  687.        end; { else (no new section) }
  688.  
  689.       endOfLoop:
  690.     end; { while not(EOF(F1)) }
  691.  
  692.       STOP:
  693.       close(F1);
  694.       closeRTF(F2);
  695.       ProcessIntList := TRUE;
  696.     end;
  697.  
  698.  
  699.   Procedure NewPage(VAR F: Text; Title : String);
  700.     VAR TopicStr : String;
  701.  
  702.       begin
  703.     Inc(TopicNo);
  704.     str(TopicNo, TopicStr);
  705.     AddTopic(IndexFile, nl, Title, TopicStr);
  706.     NewHlpPage(F, Title, TopicStr,'p:0', InvalidClassification);
  707.     setTabs(F, 8, deciPoints, 10);
  708.       end;
  709.  
  710.  
  711.   Procedure ProcessPorts(FName : String);
  712.     LABEL STOP;
  713.     VAR i          : integer;
  714.     s          : String;
  715.     TopicStr   : String;
  716.     NewSection : Boolean;
  717.     F1, F2     : Text;
  718.  
  719.  
  720.  
  721.     begin
  722.       defaultDir(FName,InPath);
  723.      {$I-}
  724.       assign(F1, FName);
  725.       reset(F1);
  726.      {$I+}
  727.       if IOResult <> 0 then
  728.     begin
  729.       writeln('Unable to open ', FName);
  730.       EXIT;
  731.     end;
  732.  
  733.       writeln('Processing : ', FName);
  734.       OpenOutFile(F2);
  735.  
  736.       i:=length(FName);
  737.       while FName[i]<>'\' do dec(i);
  738.       NewPage(F2, copy(FName,succ(i),255)+' Note');
  739.  
  740.       while not(EOF(F1)) do
  741.     begin
  742.       readLine(F1, s);
  743.       NewSection := (s[1]= '-') and (Pos('---------', s) <> 0);
  744.  
  745.       if NewSection then
  746.         begin
  747.           readLine(F1, s);
  748.  
  749.           if EOF(F1)  then   { last line of document ?}
  750.         goto STOP;
  751.  
  752.           if s <> '' then                { why does this happend }
  753.         NewPage(F2, s);
  754.         end
  755.       else
  756.         begin
  757.          CheckKeyWords(s);
  758.          OutLN(F2, s);
  759.         end;
  760.     end;
  761.  
  762.       STOP:
  763.       close(F1);
  764.       closeRTF(F2);
  765.     end;
  766.  
  767.  
  768.   Procedure ProcessFile(FName : String; Title : String);
  769.     VAR s          : String;
  770.     F1, F2     : Text;
  771.  
  772.     begin
  773.       defaultDir(FName,InPath);
  774.      {$I-}
  775.       assign(F1, FName);
  776.       reset(F1);
  777.      {$I+}
  778.       if IOResult <> 0 then
  779.     begin
  780.       writeln('Unable to open ', FName);
  781.       EXIT;
  782.     end;
  783.  
  784.       writeln('Processing : ', FName);
  785.       setTabs(IndexFile, 8, deciPoints, 10);
  786.  
  787.       while not(EOF(F1)) do
  788.     begin
  789.       readLine(F1, s);
  790.       OutLN(IndexFile, s);
  791.     end;
  792.  
  793.       close(F1);
  794.     end;
  795.  
  796.  
  797.   Procedure Credits;
  798.     begin
  799.       OutLn(IndexFile,'');
  800.       AddTopic(IndexFile, nl, 'Credits', 'IDCredit');
  801.       OutLn(IndexFile,'');
  802.       OutLn(IndexFile,compilationStr);
  803.       NewHlpPage(IndexFile, 'Credits', 'IdCredit','m:1', InvalidClassification);
  804.       OutLn(IndexFile,'\pard{\f0'+headerSize+
  805.     '\qc\par Interrupt List (c) by {\b Ralf Brown}\par'); { \qc=centered }
  806.       OutLn(IndexFile,'\par This list was converted from the released ASCII file'
  807.             + '\par to the Windows Help-Format by \par \par'
  808.             + '\par {\b Christian M\''81ller-Planitz}'+header2ndSize);
  809.       OutLn(IndexFile,e_mailCredits); { e-mail address }
  810.       writeIndex('\par\par Thanks to:');
  811.       writeIndex(ack01);
  812.       writeIndex(ack02);
  813.       writeIndex(ack03);
  814.       writeIndex(ack04);
  815.       writeIndex(ack05);
  816.       writeIndex('\par}');
  817.     end;
  818.  
  819.  
  820. procedure processTopics(n: integer);
  821. (* inserts references to n topics in the CONTENTS main index *)
  822.   var i: integer; w: string[13]; title,id: string[39];
  823.   begin
  824.     for i:=1 to n do begin
  825.       str(i,w);
  826.       insert('WINDOW ',w,1);
  827.       title:='';
  828.       profileString(w,'title',title,pred(sizeOf(title)));
  829.       id:='';
  830.       profileString(w,'id',id,pred(sizeOf(id)));
  831.       if (title<>'') AND (id<>'') then AddTopic(IndexFile,nl,title,id);
  832.     end; (* for i:=1 *)
  833.   end; (* procedure processTopics *)
  834.  
  835. procedure processPages(n: integer);
  836. (* processes n "windows" as defined in the configuration file *)
  837.   var
  838.     i,j,wType,files,fType: integer;
  839.     w: string[13];
  840.     f: string[17];
  841.     id: string[17];
  842.     fId,chain: string[21];
  843.     title,fTitle: string[39];
  844.     fileName: pathStr;
  845.   begin
  846.     for i:=1 to n do begin
  847.       str(i,w);
  848.       insert('WINDOW ',w,1);
  849.       title:='';
  850.       profileString(w,'title',title,pred(sizeOf(title)));
  851.       id:='';
  852.       profileString(w,'id',id,pred(sizeOf(id)));
  853.       if (title<>'') AND (id<>'') then begin
  854.     wType:=1;
  855.     profileInt(w,'type',wType);
  856.     files:=1;
  857.     profileInt(w,'files',files);
  858.     case wType of
  859.       1: NewHlpPage(IndexFile,title,id,'f:0',InvalidClassification);
  860.         (* Single entry windows *)
  861.       2: NewHlpPage(IndexFile,title,id,'m:9',InvalidClassification);
  862.         (* Multi entries windows *)
  863.       3: ; (* nop *)   (* Windows with own contents list *)
  864.     end; (* case wType of *)
  865.     for j:=1 to files do begin
  866.       str(j,f);
  867.       insert('file ',f,1);
  868.       fileName:='';
  869.       profileString(w,f,fileName,pred(sizeOf(fileName)));
  870.       if fileName<>'' then begin
  871.         fType:=wType;
  872.         profileInt(w,f+' type',fType);
  873.         case fType of
  874.           1: ProcessFile(fileName,title);
  875.           2: ProcessPorts(fileName);
  876.           3: begin
  877.         (* the RTF file is expecte to be in:
  878.              a. the current directory.
  879.              b. the program's home directory
  880.            if no drive or root is specified.
  881.         *)
  882.         if ((length(fileName)<2) OR (fileName[2]<>':'))
  883.           AND (fileName[1]<>'\') AND (fileName[1]<>'.') then begin
  884.           if exist(filename) OR NOT exist(homeDir+filename) then
  885.             insert(currentDir,filename,1)
  886.           else insert(homeDir,filename,1);
  887.         end; (* if (fileName[2]<':'... *)
  888.         fileName:=fExpand(fileName);
  889.         if NOT exist(fileName) then
  890.           writeln(#7'File ',fileName,' not found, copy to ',currentDir);
  891.         writeln(HPJ,fileName); (* include the file name *)
  892.           end;
  893.           4: begin (* ASCII file in multi file entry *)
  894.         str(j,fTitle);
  895.         str(j,fId);
  896.         insert(title+' - ',fTitle,1);
  897.         insert(id+'_',fId,1);
  898.         chain:=id+':5';
  899.         profileString(w,f+' title',fTitle,pred(sizeOf(fTitle)));
  900.         profileString(w,f+' id',fId,pred(sizeOf(fId)));
  901.         profileString(w,f+' chain',chain,pred(sizeOf(chain)));
  902.         NewHlpPage(IndexFile,fTitle,fId,chain,InvalidClassification);
  903.         defaultDir(fileName,currentDir);
  904.         ProcessFile(fileName,fTitle);
  905.           end; (* case 4 *)
  906.         end; (* case fType of *)
  907.       end (* if fileName<>'' *)
  908.       else writeln(#7'Missing file name for [',w,'] ',f);
  909.     end; (* for j:=1 *)
  910.       end (* if (title<>'') ... *)
  911.       else writeln(#7'Missing title or identifier in ',w);
  912.     end; (* for i:=1 *)
  913.   end; (* procedure processPages *)
  914.  
  915. procedure processFilter;
  916.   var d: dirStr;
  917.   begin
  918.     writeIndex('\page\pard');
  919.     writeIndex('#{\footnote{#} idPartComp}');
  920.     writeIndex('{\f0'+header2ndSize+' This compilation of the Interrupt List does '+#13#10
  921.       +'not contain all the information in the List, see the '#13#10
  922.       +'{\uldb INTERRUP.1ST File}{\v id1st} for the availability of the ');
  923.     writeIndex('complete list.\par\par');
  924.     writeIndex('See {\uldb Filter Method}{\v idFlt_meth} and '#13#10
  925.       +'{\uldb Filter File}{\v idFlt_file} for details.\par}');
  926.     d:=currentDir;
  927.     if NOT exist('FLT_METH.RTF') then begin
  928.       if exist(homeDir+'FLT_METH.RTF') then d:=homeDir
  929.       else writeln(#7'File FLT_METH.RTF not found, copy to ',d);
  930.     end; (* if NOT exist() *)
  931.     writeln(HPJ,d,'FLT_METH.RTF');
  932.     NewHlpPage(IndexFile, 'Filter File', 'idFlt_file','flt:1', invalidClassification);
  933.     processFile(filterFileName,'Filter File');
  934.   end; (* procedure processFilter *)
  935.  
  936. procedure readCategoryKeys;
  937. (* Opens file CATEGORY.KEY if available, and reads definitions to
  938.    categoryKeyStrings. Definitions are of the type
  939.       A - definition A, B - definition B,
  940.    The definitions are inserted as search keys for the appropriate
  941.    categories. Note that more than one keyword per entry is accepted,
  942.    separated by a semicolon, e.g. " c - cachers;spoolers,".
  943.  
  944.    Reads also title file OVERVIEW.LST.
  945.  
  946.    CATEGORY.KEY and OVERVIEW.LST are separate files in Interrupt List
  947.    release 41+.
  948. *)
  949.   var t: text; s: string;
  950.   begin
  951. (*$I-*)
  952.     assign(t,InPath+'category.key');
  953.     reset(t);
  954. (*$I+*)
  955.     if IOresult<>0 then writeln('Unable to open ',InPath,'CATEGORY.KEY')
  956.     else begin
  957.       while NOT eof(t) do begin readln(t,s); scan(s,categoryKeyStrings); end;
  958.       close(t);
  959.     end; (* else *)
  960. (*$I-*)
  961.     assign(t,InPath+'overview.lst');
  962.     reset(t);
  963. (*$I+*)
  964.     if IOresult<>0 then writeln('Unable to open ',InPath,'OVERVIEW.LST')
  965.     else begin
  966.       while NOT eof(t) do begin readln(t,s); getINTtitle(s,INTtitles); end;
  967.       close(t);
  968.     end; (* else *)
  969.   end; (* procedure readCategoryKeys *)
  970.  
  971. procedure INTsToIndex;
  972.   var i,j,k,l: word; s: string[3];
  973.   begin
  974.     for k:=0 to pred(indexPages) do begin
  975.       l:=k*indexRows*indexColumns;
  976.       for i:=0 to pred(indexRows) do begin
  977.     OutLn(IntFile, '');
  978.     for j:=0 to pred(indexColumns) do begin
  979.       if INTcounts[l+i+j*16]<>0 then begin
  980.         write(IntFile,'{\uldb INT ',HEX(l+i+j*16));
  981.         if indexColumns=4 then write(IntFile,' List');
  982.         write(IntFile,'}{\v ',HEX(l+i+j*16),'_0}');
  983.       end (* if INTcounts[]<>0 *)
  984.       else if indexColumns=4 then write(IntFile,'\tab ');
  985.       if j<pred(indexColumns) then write(IntFile,'\tab ');
  986.     end; (* for j:=0 *)
  987.       end; (* for i:=0 *)
  988.       if k<pred(indexPages) then OutLn(IntFile, '');
  989.     end; (* for k:=0 *)
  990.   end; (* procedure INTsToIndex *)
  991.  
  992. procedure initializeArrays;
  993.   var i: integer; ch: char;
  994.   begin
  995.     for ch:='!' to #126 do begin (* default to empty string *)
  996.       flagStrings[ch]:=@emptyString;
  997.       categoryStrings[ch]:=@emptyString;
  998.       categoryKeyStrings[ch]:=@emptyString;
  999.     end; (* for ch:='!' *)
  1000.     categoryStrings['!']:=@noteString;
  1001.     categoryStrings['-']:=@noneString;
  1002.     for i:=$00 to $FF do begin INTcounts[i]:=0; INTtitles[i]:=@emptyString; end;
  1003.   end; (* procedure initializeArrays *)
  1004.  
  1005. procedure findDateAndCopyright;
  1006.   var a,b,c,d: word; s,ss: string[99]; t: text;
  1007.   begin
  1008.     getDate(a,b,c,d);
  1009.     (*$ifdef m_dd_yy *)
  1010.       str(b*1000000+(c*1000+a MOD 100),dateString);
  1011.       dateString[length(dateString)-5]:=dateSep;
  1012.       dateString[length(dateString)-2]:=dateSep;
  1013.     (*$else*)
  1014.       (*$ifdef d_mm_yy *)
  1015.     str(c*1000000+(b*1000+a MOD 100),dateString);
  1016.     dateString[length(dateString)-5]:=dateSep;
  1017.     dateString[length(dateString)-2]:=dateSep;
  1018.       (*$else*)
  1019.     str(a*1000000+(b*1000+c),dateString);
  1020.     dateString[5]:=dateSep;
  1021.     dateString[8]:=dateSep;
  1022.     (*$ifdef yy_mm_dd *) delete(dateString,1,2); (*$endif*)
  1023.       (*$endif*)
  1024.     (*$endif*)
  1025.     getTime(a,b,c,d);
  1026.     str((a*1000+b)+100000,s);
  1027.     s[4]:=timeSep;
  1028.     s[1]:=' ';
  1029.     if a<10 then delete(s,2,1);
  1030.     dateString:=dateString+' -'+s;
  1031.   (*$I-*)
  1032.     assign(t,InPath+'interrup.lst');
  1033.     reset(t);
  1034.     if IOresult<>0 then begin
  1035.       assign(t,InPath+'interrup.a');
  1036.       reset(t);
  1037.       if IOresult<>0 then
  1038.     errorExit('Unable to open INTERRUP file in directory '+InPath,1);
  1039.     end; (* if IOresult<>0 *)
  1040.   (*$I+*)
  1041.     ReadLine(t,s);
  1042.     ReadLine(t,ss);
  1043.     close(t);
  1044.     for a:=1 to 2 do begin
  1045.       b:=pos(#9,s); (* remove two wide areas of whitespace *)
  1046.       if b<>0 then while s[b]=#9 do delete(s,b,1)
  1047.       else begin
  1048.     b:=pos('        ',s);
  1049.     if b<>0 then while s[b]=' ' do delete(s,b,1)
  1050.       end; (* else *)
  1051.       if b<>0 then insert('      ',s,b); (* insert 6 spaces instead *)
  1052.     end; (* for a:=1 *)
  1053.     indexHeader:='{\keep '+s+#13#10'\par{'+header2ndSize+' '+ss+'}'#13#10'\par';
  1054.     if scrollIndexTitle then indexHeader:=indexHeader+'\pard';
  1055.     indexHeader:=indexHeader+#13#10'\par}';
  1056.     compilationStr:=hfName+'.HLP compiled '+dateString+'.';
  1057.     if filtered then compilationStr:=compilationStr
  1058.       +' {\ul Partial compilation.}{\v idPartComp}';
  1059.   end; (* procedure findDateAndCopyright *)
  1060.  
  1061. procedure interpretParameters;
  1062. (* interprets program parameters and parts of the configuration file *)
  1063.   var i,argVal: integer; s: string[79]; blanks: boolean;
  1064.   procedure copyParam(var dest: string; len: byte);
  1065.     begin dest:=copy(s,3+ord(s[3]=':'),len); end;
  1066.   procedure getArgVal;
  1067.     (* assigns value of argument, or $8000, to argVal *)
  1068.     var i: integer; st: string[9];
  1069.     begin
  1070.       copyParam(st,9);
  1071.       val(st,argVal,i);
  1072.       if i<>0 then argVal:=integer($8000);
  1073.     end; (* procedure getArgVal in interpretParameters *)
  1074.   function getBool: boolean;
  1075.     begin getBool:=(length(s)<3) OR (s[3]<>'-'); end;
  1076.   procedure setSize(var fs: string; dp: word);
  1077.     (* converts decipoints to an RTF halfpoint font size string *)
  1078.     begin
  1079.       str(dp DIV 5,fs);
  1080.       insert('\fs',fs,1);
  1081.     end; (* procedure setSize in interpretParameters *)
  1082.  
  1083.   begin
  1084.     blanks:=true;
  1085.     (* first, check configuration file *)
  1086.     profileString('OPTIONS','build',buildExpr,pred(sizeOf(buildExpr)));
  1087.     profileString('OPTIONS','compression',compression,pred(sizeOf(compression)));
  1088.     profileString('OPTIONS','filterFile',filterFileName,pred(sizeOf(filterFileName)));
  1089.     profileBoolean('OPTIONS','singlesInMain',singlesInMain);
  1090.     profileBoolean('OPTIONS','twoIndexes',twoIndexes);
  1091.     profileBoolean('OPTIONS','errorLog',errorLog);
  1092.     profileBoolean('OPTIONS','indexHeaders',indexHeaders);
  1093.     profileInt('OPTIONS','indexColumns',indexColumns);
  1094.     profileBoolean('OPTIONS','markKeys',markKeys);
  1095.     profileBoolean('OPTIONS','equalBlanks',blanks);
  1096.     profileInt('OPTIONS','releaseNo',releaseNo);
  1097.     profileBoolean('OPTIONS','scrollIndexTitle',scrollIndexTitle);
  1098.     profileBoolean('OPTIONS','tableWindow',tableWindow);
  1099.     profileBoolean('OPTIONS','expandedIndex',expandedIndex);
  1100.     (* second, check parameters *)
  1101.     for i:=1 to paramCount do begin
  1102.       s:=paramStr(i);
  1103.       case s[1] of
  1104.     '/','-': begin
  1105.       if length(s)=1 then errorExit(
  1106.         'Missing option after "'+s+'"',1);
  1107.       case upcase(s[2]) of
  1108.         'B': copyParam(buildExpr,pred(sizeOf(buildExpr)));
  1109.         (* legal: any .HPJ [OPTIONS] build= expression *)
  1110.         'C': begin
  1111.           copyParam(compression,pred(sizeOf(compression)));
  1112.         (* legal: 0, 1, no, yes, low, medium, high. Not checked *)
  1113.           if compression='' then compression:='YES';
  1114.         (* default if "-c" or "-c:" is specified *)
  1115.         end; (* case 'C' *)
  1116.         'F': begin
  1117.           copyParam(filterFileName,pred(sizeOf(filterFileName)));
  1118.           if filterFileName='' then errorExit(
  1119.         'No filter file name specified after "'+s+'"',1);
  1120.           filtered:=true;
  1121.         end; (* case 'F' *)
  1122.         '1': singlesInMain:=getBool;
  1123.         '2': twoIndexes:=getBool;
  1124.         'E': errorLog:=getBool;
  1125.         'H': indexHeaders:=getBool;
  1126.         'I': begin getArgVal; indexColumns:=argVal; end;
  1127.         'M': markKeys:=getBool;
  1128.         'Q': blanks:=getBool;
  1129.         'R': begin getArgVal; releaseNo:=argVal; end;
  1130.         'S': scrollIndexTitle:=getBool;
  1131.         'T': tableWindow:=getBool;
  1132.         'X': expandedIndex:=getBool;
  1133.         else errorExit('Unknown option: '+s,1);
  1134.       end; (* case upcase(s[2] of *)
  1135.     end; (* case '/','-' *)
  1136.     else begin
  1137.       if InPath='' then InPath:=s
  1138.       else if OutPath='' then OutPath:=s
  1139.       else errorExit('Too many parameters: '+s,1);
  1140.     end; (* case else *)
  1141.       end; (* case s[1] of *)
  1142.     end; (* for i:=1 *)
  1143.     (* if file paths were not program parameters, try configuration file *)
  1144.     if InPath='' then profileString('FILES','InPath',InPath,pred(sizeOf(InPath)));
  1145.     if OutPath='' then profileString('FILES','OutPath',OutPath,pred(sizeOf(OutPath)));
  1146.     (* read windows settings from configuration file *)
  1147.     profileString('CONFIG','pos and size',windowsPosSize,pred(sizeOf(windowsPosSize)));
  1148.     profileString('CONFIG','secondary pos and size',
  1149.       secWindowsPosSize,pred(sizeOf(secWindowsPosSize)));
  1150.     profileString('CONFIG','background',windowsBackgr,pred(sizeOf(windowsBackgr)));
  1151.     profileString('CONFIG','header background',windowsHdrBackgr,pred(sizeOf(windowsHdrBackgr)));
  1152.     profileString('CONFIG','header font',headerFont,pred(sizeOf(headerFont)));
  1153.     profileString('CONFIG','text font',textFont,pred(sizeOf(textFont)));
  1154.     profileInt('CONFIG','deciPoints',integer(deciPoints));
  1155.     profileInt('CONFIG','header deciPoints',integer(headerDeciPoints));
  1156.     profileInt('CONFIG','header 2nd deciPoints',integer(header2ndDeciPoints));
  1157.     (* update other values *)
  1158.     indexRows:=16; (* in most cases *)
  1159.     indexPages:=1; (* in two cases *)
  1160.     case indexColumns of
  1161.       1: indexRows:=256;
  1162.       4: indexPages:=4;
  1163.       8: indexPages:=2;
  1164.       16: ; (* already ok *)
  1165.       else errorExit('Illegal index columns, only 1, 4, 8, or 16 accepted',1);
  1166.     end; (* case indexColumns of *)
  1167.     if NOT blanks then begin
  1168.       equStr[4]:='=';
  1169.       equStr[0]:=#4; (* equStr = ' Ax=' *)
  1170.       equBlanks:=0;
  1171.     end; (* if NOT blanks *)
  1172.     setSize(fontSize,deciPoints);
  1173.     setSize(headerSize,headerDeciPoints);
  1174.     setSize(header2ndSize,header2ndDeciPoints);
  1175.     filtered:=filterFileName<>'';
  1176.     if NOT indexHeaders then indentIndex:=nl;
  1177.     if releaseNo<41 then begin tables:=false; tableWindow:=false; end;
  1178.     if NOT tableWindow then begin mainW:=''; tableW:=''; end;
  1179.   end; (* procedure interpretParameters *)
  1180.  
  1181.   const
  1182.     windows: integer = 0;
  1183.  
  1184.   var
  1185.     ch: char;
  1186.  
  1187.   begin
  1188.     Intro;
  1189.     if (paramStr(1)='?') OR (paramStr(1)='-?') OR (paramStr(1)='/?')
  1190.       then Explain; (* and exit *)
  1191.  
  1192.     fSplit(paramStr(0),homeDir,currentDir,currentDir);
  1193.       (* works only with DOS 3.30+ - currentDir is used as a dummy *)
  1194.     currentDir:=fExpand('.');
  1195.     if length(currentDir)>3 then begin
  1196.       inc(currentDir[0]);
  1197.       currentDir[length(currentDir)]:='\';
  1198.     end; (* if length()... *)
  1199.     interpretParameters;
  1200.     initializeArrays;
  1201.     nextAliasPP:=@firstAliasP;
  1202.  
  1203.     if InPath='' then begin
  1204.       write('Source directory: ');
  1205.       readln(InPath);
  1206.     end; (* if InPath='' *)
  1207.     if InPath<>'' then begin
  1208.       ch:=InPath[length(InPath)];
  1209.       if (ch<>':') AND (ch<>'\') then
  1210.     begin inc(InPath[0]); InPath[length(InPath)]:='\'; end;
  1211.     end; (* if InPath<>'' *)
  1212.  
  1213.     if OutPath='' then begin
  1214.       write('Dest. directory (has to be created in advance) : ');
  1215.       readln(OutPath);
  1216.     end; (* if OutPath='' *)
  1217.     if OutPath<>'' then begin
  1218.       ch:=OutPath[length(OutPath)];
  1219.       if (ch<>':') AND (ch<>'\') then
  1220.     begin inc(OutPath[0]); OutPath[length(OutPath)]:='\'; end;
  1221.     end; (* if OutPath<>'' *)
  1222.  
  1223.     ProcessTime:=memL[$40:$6C]; { timer ticks since midnight }
  1224.     findDateAndCopyright;
  1225.     CreateHPJ;
  1226.  
  1227.     OpenRTF(IndexFile, 'INDEX.RTF');
  1228.     NewHlpPage(IndexFile, 'Contents:', 'CONTENTS','m:2', specialClassification);
  1229.  
  1230.     readCategoryKeys; (* reads also titles *)
  1231.     OpenRTF(IntFile,   'INT.RTF');
  1232.     OpenRTF(SubIntFile,'SUBINT.RTF');
  1233.     if tables then OpenRTF(TableFile,'TABLE.RTF');
  1234.  
  1235.     if twoIndexes then
  1236.       AddTopic(IndexFile, nl, 'Interrupt Index',
  1237.     '!IfThenElse(IsMark("Compressed_Index"), '
  1238.     +'`JumpId("","idInterrupts")'', `JumpId("","idIndex")'')')
  1239.     else AddTopic(IndexFile, nl, 'Interrupts', 'idInterrupts');
  1240.     if tables then AddTopic(IndexFile, nl, 'Tables', 'idTables');
  1241.     AddTopic(IndexFile, nl, 'FILELIST', '1');
  1242.     AddTopic(IndexFile, nl, 'INTERRUP.1ST File', 'id1st');
  1243.     if filtered then begin
  1244.       AddTopic(IndexFile, nl, 'Filter Method', 'idFlt_meth');
  1245.       AddTopic(IndexFile, nl, 'Filter File', 'idFlt_file');
  1246.     end; (* if filtered *)
  1247.  
  1248.     profileInt('WINDOWS','number',windows);
  1249.     processTopics(windows); (* insert Ports, Memory etc. in index *)
  1250.  
  1251.     Credits;
  1252.  
  1253.     if twoIndexes then begin
  1254.       NewHlpPage(IndexFile, 'Interrupt Index', 'idIndex','m:3', specialClassification);
  1255.       AddTopic(IndexFile, nl, 'Compress index',
  1256.     '!SaveMark("Compressed_Index");JumpId("","idInterrupts")');
  1257.       { the program adds all following entries }
  1258.     end; (* if twoIndexes *)
  1259.     NewHlpPage(IntFile, 'Interrupts', 'idInterrupts','m:4', specialClassification);
  1260.     if twoIndexes then begin
  1261.       AddTopic(IntFile, nl, 'Expand index','!IfThen(IsMark("Compressed_Index"),'
  1262.     +' `DeleteMark("Compressed_Index")'');JumpId("","idIndex")');
  1263.       OutLn(IntFile, '');
  1264.       if indexColumns>1 then setTabs(IntFile, succ(ord(indexColumns<=4))*8,
  1265.     deciPoints, pred(indexColumns));
  1266.     end; (* if twoIndexes *)
  1267.  
  1268.     if tables then NewHlpPage(TableFile, 'Tables\f1'+fontSize
  1269.       +'\par\par Tab# INT Func Title','idTables','m:5', invalidClassification);
  1270.       (* "Tab# INT Func Title" in normal text font and size *)
  1271.  
  1272.     profileList('ALIAS',aliasP); (* read [ALIAS] section from config. file *)
  1273.     getNextAlias(aliasP,aliasId,aliasString); (* get the first one (if any) *)
  1274.     profileList('TABLEALIAS',tableAliasP);
  1275.     getNextAlias(tableAliasP,tableAliasId,tableAliasString);
  1276.  
  1277.     (* process either "interrup.lst" or "interrup.a".."interrup.?" *)
  1278.     if NOT ProcessIntList('interrup.lst') then begin
  1279.       ch := 'a';
  1280.       while ProcessIntList('interrup.'+ch) do inc(ch);
  1281.     end; (* if NOT ProcessIntList() *)
  1282.  
  1283.     if aliasString<>'' then begin
  1284.       writeln(#7'Alias string not found:'#13#10+'  "',aliasString,'"');
  1285.       if aliasP<>NIL then
  1286.     wl('One or more alias strings not processed.');
  1287.     end; (* if aliasP<>NIL *)
  1288.     if tableAliasString<>'' then begin
  1289.       writeln(#7'Table alias string not found:'#13#10+'  "',
  1290.     tableAliasString,'"');
  1291.       if tableAliasP<>NIL then
  1292.     wl('One or more table alias strings not processed.');
  1293.     end; (* if tableAliasP<>NIL *)
  1294.  
  1295.     if indexColumns=1 then insertQueued
  1296.     else INTsToIndex;
  1297.  
  1298.     NewHlpPage(IndexFile, 'INTERRUP.1ST File', 'id1st','f:0', invalidClassification);
  1299.       { the program adds all following entries }
  1300.     ProcessFile('interrup.1st', 'INTERRUP.1ST File');
  1301.     if filtered then processFilter;
  1302.  
  1303.     closeRTF(IntFile);
  1304.     closeRTF(SubIntFile);
  1305.     if tables then closeRTF(TableFile);
  1306.  
  1307.     processPages(windows); (* process Ports, Memory etc. *)
  1308.  
  1309.     if firstAliasP<>NIL then begin
  1310.       writeln(HPJ,#13#10'[ALIAS]');
  1311.       processAliasList(firstAliasP);
  1312.     end; (* if (firstAliasP<>NIL)... *)
  1313.     closeRTF(IndexFile);
  1314.     close(HPJ);
  1315.     if missingTableCounter>=missingTableLimit then
  1316.       writeln(missingTableCounter,' missing tables encountered.');
  1317.     ProcessTime:=memL[$40:$6C]-ProcessTime;
  1318.     writeln('The processing took ',(ProcessTime*10+91) DIV 182,' seconds.');
  1319.       (* 18.2 clock ticks per second, rounded *)
  1320.   end.
  1321.