home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / lxlt121s.zip / lxLite_src / lxLite_Objects.pas < prev    next >
Pascal/Delphi Source File  |  1997-06-08  |  39KB  |  1,171 lines

  1. {&AlignCode- ,AlignData-,AlignRec-,G3+,Speed-,Frame-}
  2. {$P+}
  3. Unit lxLite_Objects;
  4.  
  5. Interface uses use32, exe286, exe386, os2exe, miscUtil, sysLib,
  6.                strOp, Country, Collect, lxlite_Global;
  7.  
  8. type
  9.  pMyCmdLineParser = ^tMyCmdLineParser;
  10.  tMyCmdLineParser = object(tCommandLineParser)
  11.   function    ParmHandler(var ParmStr : string) : Word; virtual;
  12.   function    NameHandler(var ParmStr : string) : Word; virtual;
  13.   procedure   PreProcess(var ParmStr : string); virtual;
  14.   procedure   PostProcess; virtual;
  15.   destructor  Destroy; virtual;
  16.  end;
  17.  
  18.  pMyLX = ^tMyLX;
  19.  tMyLX = object(tLX)
  20.   procedure   DisplayExeInfo;
  21.  end;
  22.  
  23. var
  24.  LX        : pMyLX;
  25.  Parser    : pMyCmdLineParser;
  26.  pfNames,
  27.  cfgIDs    : pStringCollection;
  28.  cfgOpts,
  29.  extra,
  30.  extraOpts : pCollection;
  31.  totalGain : Longint;
  32.  allDone   : boolean;
  33.  oldExit   : Procedure;
  34.  logFile   : Text;
  35.  Cntry     : pCountry;
  36.  ModDef    : pModuleCollection;
  37.  
  38.  procedure PrintHeader;
  39.  procedure Stop(eCode : Word; const ParmStr : string);
  40.  function  FormatStr(Template : Longint; Params : array of const) : string;
  41.  procedure NL;
  42.  procedure LoadConfig;
  43.  procedure setConfig(const ID : string);
  44.  procedure ShowConfig;
  45.  
  46. Implementation uses Crt, Dos, Strings;
  47.  
  48. var
  49.  CmdLineStack : pStringCollection;
  50.  
  51. procedure SwitchStdOut(State : boolean);
  52. begin
  53.  if State
  54.   then begin
  55.         Move(StdOut, Output, sizeOf(Output));
  56.         Move(StdIn, Input, sizeOf(Input));
  57.        end
  58.   else begin
  59.         AssignCrt(Output);
  60.         Rewrite(Output);
  61.        end;
  62. end;
  63.  
  64. function FormatStr;
  65. var
  66.  nP : array[0..31] of Longint;
  67.  I  : Word;
  68. begin
  69.  For I := low(Params) to High(Params) do
  70.   nP[I - low(Params)] := pLong(@Params[I])^;
  71.  StrOp.FormatStr(Result, GetResourceString(Template), nP);
  72. end;
  73.  
  74. procedure PrintHeader;
  75. const
  76.  Already : boolean = FALSE;
  77. begin
  78.  if Already then Exit;
  79.  Already := TRUE;
  80.  Write(FormatStr(msgProgHeader1, [Version])); NL;
  81.  Write(GetResourceString(msgProgHeader2)); NL;
  82. end;
  83.  
  84. procedure NL;
  85. const
  86.  Rows : Longint = -1;
  87. var
  88.  Attr : Byte;
  89.  I    : Integer;
  90.  S    : string;
  91. begin
  92.  Attr := textAttr;
  93.  SetColor($07); Writeln;
  94.  if Rows = -1 then Rows := hi(WindMax);
  95.  Dec(Rows);
  96.  if Rows = 0
  97.   then if not (RedirOutput or RedirInput)
  98.         then begin
  99.               S := GetResourceString(msgMore);
  100.               SetColor($30); I := (80 - length(S)) div 2;
  101.               Write(Strg(' ', I), S); ClearToEOL;
  102.               repeat
  103.                I := 0;
  104.                case upCase(Readkey) of
  105.                 ' ' : Rows := hi(WindMax);
  106.                 #13 : Rows := 1;
  107.                 'Q',
  108.                 #27 : begin
  109.                        Write(#13); SetColor($07); ClearToEOL;
  110.                        SetColor($04);
  111.                        Writeln(GetResourceString(msgAborted));
  112.                        Halt(1);
  113.                       end;
  114.                 else I := 1;
  115.                end;
  116.               until I = 0;
  117.               Write(#13); SetColor($07); ClearToEOL;
  118.              end
  119.         else Rows := hi(WindMax);
  120.  textAttr := Attr;
  121. end;
  122.  
  123. Procedure Stop;
  124. var
  125.  I : Integer;
  126.  S : string;
  127.  B : boolean;
  128. begin
  129.  if WhereX > 1 then Write(#13);
  130.  PrintHeader;
  131.  SetColor($04);
  132.  case eCode of
  133.   0     : ;
  134.   1,2   : begin
  135.            if eCode = 2
  136.             then begin
  137.                   SetColor($0E);
  138.                   if (CmdLineStack <> nil) and (CmdLineStack^.Count > 0)
  139.                    then S := pString(CmdLineStack^.At(pred(CmdLineStack^.Count)))^
  140.                    else S := '';
  141.                   S := Copy(S, 1, length(S) - length(ParmStr));
  142.                   DelStartSpaces(S);
  143.                   Write(FormatStr(msgInvalidSwitch, [S]));
  144.                   SetColor($04);
  145.                   S := parmStr;
  146.                   DelTrailingSpaces(S);
  147.                   Write(S); NL;
  148.                  end;
  149.            B := TRUE;
  150.            For I := msgHelpFirst to msgHelpLast do
  151.             begin
  152.              S := GetResourceString(I);
  153.              case S[1] of
  154.               '│' : if B then SetColor($09);
  155.               '├' : case S[2] of
  156.                      '┤' : begin SetColor($03); B := FALSE; end;
  157.                      else SetColor($0B);
  158.                     end;
  159.               '└' : SetColor($08);
  160.              end;
  161.              Write(S); NL;
  162.             end;
  163.           end;
  164.   else Writeln(FormatStr(eCode, [parmStr]));
  165.  end;
  166.  Halt(eCode mod 100);
  167. end;
  168.  
  169. procedure tMyLX.DisplayExeInfo;
  170. const
  171.  txtGfx      : array[boolean] of array[1..6] of Char = ('││││││','└┴┘├┴┘');
  172.  atDefault   = $0B;
  173.  atInfo      = $0A;
  174.  atFlags     = $0C;
  175.  atHLinfo    = $0B;
  176.  atFixups    = $03;
  177.  atFixupOfs  = $02;
  178.  atSeparator = $0E;
  179. var
  180.  S,tmpS    : String;
  181.  oldAt,
  182.  I,J,K,L,M : Longint;
  183.  pFixOfs   : pWord16;
  184.  Fixups    : pFixupCollection;
  185.  oldPage   : Pointer;
  186.  oldPageMap: tObjMapRec;
  187.  
  188. procedure AddStr(const nS : string);
  189. begin
  190.  if (S <> '') and (nS <> '') then S := S + ', ';
  191.  S := S + nS;
  192. end;
  193.  
  194. procedure AddS(msgIndex : Longint);
  195. begin
  196.  AddStr(GetResourceString(msgIndex));
  197. end;
  198.  
  199. function txtOS(OS : Byte) : string;
  200. begin
  201.  if OS = 1
  202.   then txtOS := 'OS/2'
  203.   else txtOS := 'ID = ' + long2str(OS);
  204. end;
  205.  
  206. procedure Separator(S : string);
  207. begin
  208.  SetColor(atInfo);
  209.  Write('├');
  210.  SetColor(atSeparator);
  211.  Write(S + Strg('─', 59 - length(S))); NL;
  212.  SetColor(atInfo);
  213. end;
  214.  
  215. procedure ShowNamesTable(NT : pNamedEntryCollection);
  216. var
  217.  i : Integer;
  218. begin
  219.  if NT^.Count = 0
  220.   then begin Separator(''); Write(GetResourceString(msgEmpty)); NL; end
  221.   else Separator(GetResourceString(msgNameTableHdr));
  222.  For i := 1 to NT^.Count do
  223.   with pNameTblRec(NT^.At(pred(I)))^ do
  224.    begin
  225.     if i < NT^.Count then Write('│') else Write('├');
  226.     Write(' ', Sstr(Ord, 5, '0'), ' ');
  227.     if i < NT^.Count then Write('│') else Write('┴');
  228.     Write(' ', Name^); NL;
  229.    end;
  230. end;
  231.  
  232. procedure ShowImportTable(SC : pStringCollection);
  233. var
  234.  i,j : Integer;
  235.  pS  : pString;
  236. begin
  237.  if SC^.Count = 0
  238.   then begin Separator(''); Write(GetResourceString(msgEmpty)); NL; end
  239.   else Separator(GetResourceString(msgImpTableHdr));
  240.  j := 0;
  241.  for i := 1 to SC^.Count do
  242.   begin
  243.    pS := SC^.At(pred(I));
  244.    if i < SC^.Count then Write('│') else Write('├');
  245.    Write(' ', Sstr(i, 5, '0'), ' ');
  246.    if i < SC^.Count then Write('│') else Write('┴');
  247.    Write(' ', Sstr(j, 5, '0'), ' ');
  248.    if i < SC^.Count then Write('│') else Write('┴');
  249.    if pS <> nil
  250.     then begin
  251.           Write(' ', pS^);
  252.           Inc(j, succ(length(pS^)));
  253.          end
  254.     else Inc(j);
  255.    NL;
  256.   end;
  257. end;
  258.  
  259. function EntryName(ProcOrd : Longint) : String;
  260. var
  261.  pN : pNameTblRec;
  262.  tS : string;
  263.  I  : Integer;
  264.  MD : pModuleDef;
  265. begin
  266.  EntryName := '';
  267.  pN := ResNameTbl^.At(0);
  268.  if (pN = nil) or (pN^.Name = nil) then exit;
  269.  tmpS := upStrg(pN^.Name^);
  270.  I := ModDef^.IndexOf(@tmpS);
  271.  if I >= 0
  272.   then begin
  273.         MD := ModDef^.At(I);
  274.         if ProcOrd < MD^.defLength
  275.          then begin
  276.                tmpS := GetResourceString(MD^.defStart + ProcOrd);
  277.                if tmpS = '' then exit;
  278.               end
  279.          else exit;
  280.        end
  281.   else exit;
  282.  EntryName := '(' + tmpS + ')';
  283. end;
  284.  
  285. procedure AddF(F : Byte);
  286. begin
  287.  if F and lxExport <> 0
  288.   then AddS(msgExported);
  289.  if F and lxShared <> 0
  290.   then AddS(msgSharedData);
  291.  if F and lxParams <> 0
  292.   then AddStr(FormatStr(msgParamCount, [(F and lxParams) shr lxParamsShft]));
  293. end;
  294.  
  295. function ImpByOrd(ModIndx, ProcOrd : Longint) : pString;
  296. var
  297.  tS : string;
  298.  I  : Integer;
  299.  MD : pModuleDef;
  300. begin
  301.  tmpS := upStrg(pString(ImpModTbl^.At(pred(ModIndx)))^);
  302.  tS := '';
  303.  I := ModDef^.IndexOf(@tmpS);
  304.  if I >= 0
  305.   then begin
  306.         MD := ModDef^.At(I);
  307.         if ProcOrd < MD^.defLength
  308.          then tS := GetResourceString(MD^.defStart + ProcOrd);
  309.        end;
  310.  tmpS := tmpS + '.' + long2str(ProcOrd);
  311.  if tS <> '' then tmpS := tmpS + '(' + tS + ')';
  312.  ImpByOrd := @tmpS;
  313. end;
  314.  
  315. function ImpByName(ModIndx, ProcOfs : Longint) : pString;
  316. var
  317.  i,j : Integer;
  318.  pS  : pString;
  319. begin
  320.  j := 0;
  321.  For i := 1 to ImpProcTbl^.Count do
  322.   begin
  323.    pS := ImpProcTbl^.At(pred(i));
  324.    if ProcOfs = j then break;
  325.    if pS <> nil then Inc(j, succ(length(pS^))) else Inc(j);
  326.    pS := nil;
  327.   end;
  328.  tmpS := pString(ImpModTbl^.At(pred(ModIndx)))^;
  329.  if pS <> nil
  330.   then tmpS := tmpS + '.' + pS^
  331.   else tmpS := tmpS + FormatStr(msgProcOffs, [ProcOfs]);
  332.  ImpByName := @tmpS;
  333. end;
  334.  
  335. function relOfs(O : Longint) : Longint;
  336. begin
  337.  if O <> 0 then Inc(O, stubSize);
  338.  relOfs := O;
  339. end;
  340.  
  341. begin
  342.  SetColor(atInfo);
  343.  S := '';
  344.  case Header.lxMFlags and lxModType of
  345.   lxEXE   : begin
  346.              case Header.lxMFlags and lxAppMask of
  347.               lxNoPMwin : AddS(msgFullScreen);
  348.               lxPMwin   : AddS(msgWindowed);
  349.               lxPMapi   : AddS(msgPMapplication);
  350.               else AddS(msgUnknownType);
  351.              end;
  352.              S := S + ' ' + GetResourceString(msgApplication);
  353.             end;
  354.   lxDLL,
  355.   lxPMDLL,
  356.   lxPDD,
  357.   lxVDD   : begin
  358.              case Header.lxMFlags and lxModType of
  359.               lxDLL   : AddS(msgDLL);
  360.               lxPMDLL : AddS(msgProtDLL);
  361.               lxPDD   : AddS(msgPDD);
  362.               lxVDD   : AddS(msgVDD);
  363.              end;
  364.              if Header.lxMFlags and lxLibInit <> 0
  365.               then AddS(msgPerProcInit);
  366.              if Header.lxMFlags and lxLibTerm <> 0
  367.               then AddS(msgPerProcTerm);
  368.             end;
  369.   else AddS(msgUnknownModType);
  370.  end;
  371.  if Header.lxMFlags and lxNoIntFix <> 0
  372.   then AddS(msgNoIntFixups);
  373.  if Header.lxMFlags and lxNoExtFix <> 0
  374.   then AddS(msgNoExtFixups);
  375.  if Header.lxMFlags and lxNoLoad <> 0
  376.   then AddS(msgNotLoadable);
  377.  if opt.Verbose and vfHeaderL0 <> 0
  378.   then begin
  379.         Write(FormatStr(msgModuleType, [S])); NL;
  380.         S := GetResourceString(msgCPU + Header.lxCpu - lxCPU286);
  381.         Write(FormatStr(msgReqCPU, [S, Header.lxVer shr 16, SmallWord(Header.lxVer)])); NL;
  382.        end;
  383.  if opt.Verbose and vfHeaderL1 <> 0
  384.   then begin
  385.         S := txtOS(Header.lxOS);
  386.         Write(FormatStr(msgReqOS, [S, Header.lxMPages])); NL;
  387.        end;
  388.  if opt.Verbose and vfHeaderL0 <> 0
  389.   then begin
  390.         Write(FormatStr(msgPageSize, [Header.lxPageSize, Header.lxPageShift])); NL;
  391.         Write(FormatStr(msgObjects, [Header.lxObjCnt, Header.lxRsrcCnt])); NL;
  392.        end;
  393.  if opt.Verbose and vfHeaderL3 <> 0
  394.   then begin
  395.         Write(FormatStr(msgObjTableOfs, [relOfs(Header.lxObjTabOfs), relOfs(Header.lxRsrcTabOfs)])); NL;
  396.         Write(FormatStr(msgMapTableOfs, [relOfs(Header.lxObjMapOfs), relOfs(Header.lxDirTabOfs)])); NL;
  397.         Write(FormatStr(msgNResTableOfs,[Header.lxNResTabOfs, Header.lxCbNResTabOfs])); NL;
  398.         Write(FormatStr(msgImpProcOfs,  [relOfs(Header.lxImpProcOfs), relOfs(Header.lxEntTabOfs)])); NL;
  399.        end;
  400.  if opt.Verbose and vfHeaderL2 <> 0
  401.   then begin
  402.         Write(FormatStr(msgPageDataOfs,  [Header.lxDataPageOfs, Header.lxIterMapOfs])); NL;
  403.         Write(FormatStr(msgPageFixOfs,  [relOfs(Header.lxFPageTabOfs), relOfs(Header.lxFRecTabOfs)])); NL;
  404.        end;
  405.  if opt.Verbose and vfHeaderL1 <> 0
  406.   then begin
  407.         Write(FormatStr(msgFixupSize,  [Header.lxFixupSize, Header.lxFixupSum])); NL;
  408.         Write(FormatStr(msgResidentSize,  [Header.lxLdrSize, Header.lxLdrSum])); NL;
  409.        end;
  410.  if opt.Verbose and vfHeaderL2 <> 0
  411.   then begin
  412.         Write(FormatStr(msgImpTableOfs,  [relOfs(Header.lxImpModOfs), Header.lxDebugInfoOfs])); NL;
  413.        end;
  414.  if opt.Verbose and vfHeaderL0 <> 0
  415.   then begin
  416.         Write(FormatStr(msgImpEntries,  [Header.lxImpModCnt, Header.lxDebugLen])); NL;
  417.         Write(FormatStr(msgStartEIP,  [Header.lxStartObj, Header.lxEIP, Header.lxStackObj, Header.lxESP])); NL;
  418.        end;
  419.  if opt.Verbose and vfHeaderL1 <> 0
  420.   then begin
  421.         Write(FormatStr(msgAutoData,  [Header.lxAutoData, Header.lxPreload])); NL;
  422.         Write(FormatStr(msgStackSize, [Header.lxStackSize, Header.lxHeapSize])); NL;
  423.        end;
  424.  if opt.Verbose and vfHeaderL0 <> 0
  425.   then begin
  426.         For i := 1 to ResNameTbl^.Count do
  427.          with pNameTblRec(ResNameTbl^.At(pred(I)))^ do
  428.           if Ord = 0
  429.            then begin Write(FormatStr(msgModuleName, [Name])); NL; break; end;
  430.         For i := 1 to NResNameTbl^.Count do
  431.          with pNameTblRec(NResNameTbl^.At(pred(I)))^ do
  432.           if Ord = 0
  433.            then begin Write(FormatStr(msgDescription, [Name])); NL; break; end;
  434.        end;
  435.  if opt.Verbose and vfObjects <> 0
  436.   then begin
  437.         Separator('');
  438.         Write(GetResourceString(msgObjectTable)); NL;
  439.         Separator('');
  440.         For I := 1 to Header.lxObjCnt do
  441.          with ObjTable^[I] do
  442.           begin
  443.            SetColor(atInfo);
  444.            if (I = 1) or (opt.Verbose and vfPageMap = vfPageMap)
  445.             then begin
  446.                   Write(GetResourceString(msgObjTableHdr));
  447.                   NL;
  448.                  end;
  449.            Write('│', I:3, ' ', Hex8(oBase), ' ', Hex8(oSize), ' ');
  450.            SetColor(atFlags);
  451.            For J := 0 to 14 do
  452.             begin
  453.              if J > 2 then Write(' ');
  454.              if (oFlags and (1 shl (J + byte(J > 10))) <> 0)
  455.               then Write('√ ') else Write('  ');
  456.              if J > 2 then Write(' ');
  457.             end;
  458.            NL;
  459.            if opt.Verbose and vfPageMap = vfPageMap
  460.             then begin
  461.                   if oMapSize > 0
  462.                    then begin
  463.                          SetColor(atInfo);
  464.                          Write('│  ');
  465.                          SetColor(atHLinfo);
  466.                          Write(GetResourceString(msgPageTableHdr)); NL;
  467.                         end;
  468.                   For J := 1 to oMapSize do
  469.                    with ObjMap^[pred(oPageMap + J)] do
  470.                     begin
  471.                      SetColor(atInfo);
  472.                      Write('│   ');
  473.                      SetColor(atHLinfo);
  474.                      Write(     txtGfx[J = oMapSize][1], ' ', Sstr(pred(oPageMap + J), 8, '0'),
  475.                            ' ', txtGfx[J = oMapSize][2], ' ');
  476.                      case PageFlags of
  477.                       pgIterData,
  478.                       pgIterData2:
  479.                        Write(Hex8(Header.lxIterMapOfs + PageDataOffset shl Header.lxPageShift));
  480.                       pgValid:
  481.                        Write(Hex8(Header.lxDataPageOfs + PageDataOffset shl Header.lxPageShift));
  482.                       else Write('--------');
  483.                      end;
  484.                      Write(' ', txtGfx[J = oMapSize][2], ' ', Hex4(PageSize),
  485.                            ' ', txtGfx[J = oMapSize][2], ' ');
  486.                      if PageFlags <= pgIterData2
  487.                       then Write(GetResourceString(msgPageFlags+PageFlags))
  488.                       else Write(GetResourceString(msgPageFlags+succ(pgIterData2)));
  489.                      Write(' ', txtGfx[J = oMapSize][3]);
  490.                      NL;
  491.                     end;
  492.                  end;
  493.           end;
  494.        end;
  495.  if (opt.Verbose and vfResName <> 0)
  496.   then begin
  497.         Separator('');
  498.         Write(GetResourceString(msgResTableHdr)); NL;
  499.         ShowNamesTable(ResNameTbl);
  500.       end;
  501.  if (opt.Verbose and vfNResName <> 0)
  502.   then begin
  503.         Separator('');
  504.         Write(GetResourceString(msgNResTableHdr)); NL;
  505.         ShowNamesTable(NResNameTbl);
  506.       end;
  507.  if (opt.Verbose and vfImpName <> 0)
  508.   then begin
  509.         Separator('');
  510.         Write(GetResourceString(msgImportTable)); NL;
  511.         ShowImportTable(ImpModTbl);
  512.        end;
  513.  if (opt.Verbose and vfImpProc <> 0)
  514.   then begin
  515.         Separator('');
  516.         Write(GetResourceString(msgImpProcHdr)); NL;
  517.         ShowImportTable(ImpProcTbl);
  518.        end;
  519.  if (opt.Verbose and vfEntTable <> 0)
  520.   then begin
  521.         Separator('');
  522.         Write(GetResourceString(msgEntryTable)); NL;
  523.         if EntryTbl^.Count = 0
  524.          then begin Separator(''); Write(GetResourceString(msgEmpty)); NL; end
  525.          else Separator(GetResourceString(msgEntryTblHdr));
  526.         For i := 1 to EntryTbl^.Count do
  527.          with pEntryPoint(EntryTbl^.At(pred(I)))^ do
  528.           begin
  529.            if BndType = btEmpty then Continue;
  530.            Write(txtGfx[i = EntryTbl^.Count][4], ' ',
  531.                  Sstr(Ordinal, 5, '0'), ' ', txtGfx[i = EntryTbl^.Count][5], ' ');
  532.            if BndType <= btEntryFwd
  533.             then Write(GetResourceString(msgEntryPoints + BndType))
  534.             else Write(GetResourceString(msgEntryPoints + succ(btEntryFwd)));
  535.            S := ' ' + txtGfx[i = EntryTbl^.Count][5];
  536.            Write(S);
  537.            case BndType of
  538.             btEntry16:
  539.              begin
  540.               S := long2str(Obj) + ':' + Hex4(Entry.e16Ofs);
  541.               AddF(Entry.e16Flags);
  542.              end;
  543.             btGate16:
  544.              begin
  545.               S := long2str(Obj) + ':' + Hex4(Entry.eGate16Ofs);
  546.               AddF(Entry.eGate16Flags);
  547.              end;
  548.             btEntry32:
  549.              begin
  550.               S := long2str(Obj) + ':' + Hex8(Entry.e32Ofs);
  551.               AddF(Entry.e32Flags);
  552.              end;
  553.             btEntryFwd:
  554.              begin
  555.               S := '-> ';
  556.               if Entry.eForwFlags and fwd_Ordinal <> 0
  557.                then S := S + ImpByOrd(Entry.eForwModOrd, Entry.eForwOfs)^
  558.                else S := S + ImpByName(Entry.eForwModOrd, Entry.eForwOfs)^;
  559.              end;
  560.             else S := '';
  561.            end;
  562.            AddStr(EntryName(I));
  563.            Write(' ', S); NL;
  564.           end;
  565.        end;
  566.  if (opt.Verbose and vfFixups <> 0)
  567.   then begin
  568.         Separator('');
  569.         Write(GetResourceString(msgRelocTable)); NL;
  570.         Separator('');
  571.         New(Fixups, Create(16, 16));
  572.         For I := 1 to Header.lxObjCnt do
  573.          with ObjTable^[I] do
  574.           For J := 1 to oMapSize do
  575.            begin
  576.             Write('├ ');
  577.             SetColor(atHLinfo);
  578.             Write(FormatStr(msgRelocTblHdr, [I, J, pred(oPageMap + J)])); NL;
  579.             SetColor(atInfo);
  580.  
  581.             oldPageMap := ObjMap^[pred(oPageMap + J)];
  582.             GetMem(oldPage, oldPageMap.PageSize);
  583.             Move(Pages^[oPageMap + J - 2]^, oldPage^, oldPageMap.PageSize);
  584.             Fixups^.FreeAll;
  585.             K := byte(GetFixups(pred(oPageMap + J), Fixups));
  586.  
  587.             FreeMem(Pages^[oPageMap + J - 2], ObjMap^[pred(oPageMap + J)].PageSize);
  588.             ObjMap^[pred(oPageMap + J)] := oldPageMap;
  589.             Pages^[oPageMap + J - 2] := oldPage;
  590.  
  591.             if K = 0 then Continue;
  592.  
  593.             For K := 1 to Fixups^.Count do
  594.              with pLXreloc(Fixups^.At(pred(K)))^ do
  595.               begin
  596.                case sType and nrSType of
  597.                 nrSByte:  S := GetResourceString(msgFixByte);
  598.                 nrSSeg:   S := GetResourceString(msgFixSelector);
  599.                 nrSPtr:   S := GetResourceString(msgFixPtr16);
  600.                 nrSOff:   S := GetResourceString(msgFixOfs16);
  601.                 nrPtr48:  S := GetResourceString(msgFixPtr48);
  602.                 nrOff32:  S := GetResourceString(msgFixOfs32);
  603.                 nrSoff32: S := GetResourceString(msgFixRelOfs32);
  604.                end;
  605.                S := S + GetResourceString(msgFixOf);
  606.                case Flags and nrRtype of
  607.                 nrRint: begin
  608.                          S := S + FormatStr(msgFixObject, [ObjMod]);
  609.                          if sType and nrSType <> nrSSeg
  610.                           then S := S + FormatStr(msgFixOffset, [Target.intRef]);
  611.                         end;
  612.                 nrRord: S := S + FormatStr(msgFixImport, [ImpByOrd(ObjMod, Target.extRef.Ord)]);
  613.                 nrRnam: S := S + FormatStr(msgFixImport, [ImpByName(ObjMod, Target.extRef.Ord)]);
  614.                 nrRent: S := S + FormatStr(msgFixModEntry, [ObjMod]);
  615.                end;
  616.                Write('│ ');
  617.                if (sType and nrChain <> 0)
  618.                 then begin
  619.                       L := targetCount;
  620.                       pFixOfs := @targets^;
  621.                      end
  622.                 else begin
  623.                       L := 1;
  624.                       pFixOfs := @sOffs;
  625.                      end;
  626.                SetColor(atFixups);
  627.                Write(S); NL;
  628.                SetColor(atInfo);
  629.                M := -1;
  630.                While L > 0 do
  631.                 begin
  632.                  if (M >= lo(WindMax) - 5) or (M = -1)
  633.                   then begin
  634.                         if M <> -1 then NL;
  635.                         M := 0; Write('│ ')
  636.                        end;
  637.                  SetColor(atFixupOfs);
  638.                  Write(Hex4(pFixOfs^), ' ');
  639.                  SetColor(atInfo);
  640.                  Inc(pFixOfs); Dec(L);
  641.                  Inc(M, 5);
  642.                 end;
  643.                if M > 0 then NL;
  644.               end;
  645.            end;
  646.         Dispose(Fixups, Destroy);
  647.        end;
  648.  if not RedirOutput
  649.   then begin SetColor(atDefault); Write('└  '); end;
  650. end;
  651.  
  652. Procedure ShowConfig;
  653. const
  654.  ONOFF : array[boolean] of string[3] = ('OFF', 'ON');
  655. var
  656.  S   : string;
  657.  I,J : Word;
  658.  
  659. function VerbLvl : pString;
  660. begin
  661.  if opt.Verbose = 0
  662.   then S := ONOFF[FALSE]
  663.   else S := '';
  664.  if opt.Verbose and vfHeaderL0 <> 0
  665.   then S := S + '0';
  666.  if opt.Verbose and vfHeaderL1 <> 0
  667.   then S := S + '1';
  668.  if opt.Verbose and vfHeaderL2 <> 0
  669.   then S := S + '2';
  670.  if opt.Verbose and vfHeaderL3 <> 0
  671.   then S := S + '3';
  672.  if opt.Verbose and vfObjects <> 0
  673.   then S := S + 'O';
  674.  if opt.Verbose and vfPageMap = vfPageMap
  675.   then S := S + 'C';
  676.  if opt.Verbose and vfResName <> 0
  677.   then S := S + 'R';
  678.  if opt.Verbose and vfNResName <> 0
  679.   then S := S + 'N';
  680.  if opt.Verbose and vfImpName <> 0
  681.   then S := S + 'M';
  682.  if opt.Verbose and vfImpProc <> 0
  683.   then S := S + 'P';
  684.  if opt.Verbose and vfEntTable <> 0
  685.   then S := S + 'E';
  686.  if opt.Verbose and vfFixups <> 0
  687.   then S := S + 'F';
  688.  VerbLvl := @S;
  689. end;
  690.  
  691. function BackupLvl : pString;
  692. begin
  693.  if opt.Backup and bkfAlways = bkfAlways
  694.   then BackupLvl := @ONOFF[TRUE]
  695.   else begin
  696.         if (opt.Backup and bkfAlways) and (not (bkfIfDebug+bkfIfXtra+bkfIfNE)) <> 0
  697.          then S := 'A'
  698.          else begin
  699.                S := '';
  700.                if opt.Backup and bkfIfDebug <> 0
  701.                 then S := S + 'D';
  702.                if opt.Backup and bkfIfXtra <> 0
  703.                 then S := S + 'X';
  704.                if opt.Backup and bkfIfNE <> 0
  705.                 then S := S + 'N';
  706.               end;
  707.         if S = ''
  708.          then BackupLvl := @ONOFF[FALSE]
  709.          else BackupLvl := @S;
  710.        end;
  711. end;
  712.  
  713. begin
  714.  SetColor($0B);
  715.  Write(GetResourceString(msgConfigHeader)); NL;
  716.  SetColor($03);
  717.  Write(FormatStr(msgShowInfo, [VerbLvl])); NL;
  718.  Write(FormatStr(msgForceIdle, [ONOFF[opt.ForceIdle]])); NL;
  719.  Write(FormatStr(msgUnpack, [ONOFF[opt.Unpack]])); NL;
  720.  Write(FormatStr(msgBackup, [BackupLvl])); NL;
  721.  Write(FormatStr(msgPause, [ONOFF[opt.Pause]])); NL;
  722.  if opt.tresholdStub > 0
  723.   then begin
  724.         if opt.stubName <> ''
  725.          then S := opt.stubName
  726.          else S := GetResourceString(msgRemoveStub);
  727.         Write(FormatStr(msgReplaceStub, [S])); NL;
  728.        end;
  729.  case opt.SaveMode and svfAlignFirstObj of
  730.   svfFOalnNone   : I := msgAlignFONone;
  731.   svfFOalnShift  : I := msgAlignFOShift;
  732.   svfFOalnSector : I := msgAlignFOSect;
  733.  end;
  734.  S := GetResourceString(I);
  735.  Write(FormatStr(msgAlignFO, [S])); NL;
  736.  
  737.  case opt.SaveMode and svfAlignEachObj of
  738.   svfEOalnShift  : I := msgAlignObjShift;
  739.   svfEOalnSector : I := msgAlignObjSect;
  740.  end;
  741.  S := GetResourceString(I);
  742.  Write(FormatStr(msgAlignObj, [S])); NL;
  743.  
  744.  if opt.Realign = 255
  745.   then S := GetResourceString(msgDontChange)
  746.   else S := long2str(1 shl opt.Realign);
  747.  Write(FormatStr(msgSetPageShift, [S])); NL;
  748.  if not opt.doUnpack
  749.   then begin
  750.         if opt.PackMode and pkfRunLength = 0
  751.          then I := msgRLoff
  752.          else case opt.PackMode and pkfRunLengthLvl of
  753.                pkfRunLengthMin : I := msgRLmin;
  754.                pkfRunLengthMid : I := msgRLmed;
  755.                pkfRunLengthMax : I := msgRLmax;
  756.               end;
  757.         if opt.PackMode and pkfFixups = 0
  758.          then J := msgFXoff
  759.          else case opt.PackMode and pkfFixupsLvl of
  760.                pkfFixupsVer2 : J := msgFXv2;
  761.                pkfFixupsVer4 : J := msgFXv4;
  762.                pkfFixupsMax  : J := msgFXmax;
  763.               end;
  764.         Write(FormatStr(msgRunLength, [GetResourceString(I)])); NL;
  765.         Write(FormatStr(msgLempelZiv, [ONOFF[opt.PackMode and pkfLempelZiv <> 0]])); NL;
  766.         Write(FormatStr(msgFixupsPack, [GetResourceString(J)])); NL;
  767.        end;
  768.  S := '';
  769.  For I := 1 to exclude^.matchStrings^.Count do
  770.   begin
  771.    if S <> '' then S := S + ':';
  772.    S := S + strPas(pChar(exclude^.matchStrings^.At(pred(I))));
  773.   end;
  774.  if S <> ''
  775.   then Writeln(FormatStr(msgExcludedFiles, [S]));
  776. end;
  777.  
  778. function tMyCmdLineParser.ParmHandler;
  779. const
  780.  optSep : string[4] = #9' /-';
  781. var
  782.  I,J,K : Longint;
  783.  S     : string;
  784.  
  785. Function isEnabled : boolean;
  786. begin
  787.  isEnabled := TRUE;
  788.  if length(parmStr) < 2 then exit;
  789.  case parmStr[2] of
  790.   '+','-' : parmHandler := 2;
  791.   ' ','/' : exit;
  792.   else Stop(2, parmStr);
  793.  end;
  794.  if parmStr[2] = '-' then isEnabled := FALSE;
  795. end;
  796.  
  797. function ColonGetWord(Start : Word; var S : string) : Word;
  798. begin
  799.  ColonGetWord := GetWord(ParmStr, Start, S);
  800.  if (S <> '') and (S[1] <> ':')
  801.   then Stop(2, parmStr);
  802.  Delete(S, 1, 1);
  803. end;
  804.  
  805. procedure SetNewPageShift(StartChar : Word);
  806. begin
  807.  S := Copy(ParmStr, StartChar, 255);
  808.  J := length(S); I := DecVal(S);
  809.  if I <> 0
  810.   then opt.Realign := BitSR(I)
  811.   else opt.Realign := 255;
  812.  if not (opt.Realign in [0..12,255]) then Stop(2, parmStr);
  813.  parmHandler := pred(StartChar + J - length(S));
  814. end;
  815.  
  816. procedure SetRC(parmLen : Word);
  817. begin
  818.  parmHandler := parmLen;
  819.  if (length(parmStr) > parmLen) and (First(parmStr[succ(parmLen)], OptSep) = 0)
  820.   then Stop(2, parmStr);
  821. end;
  822.  
  823. procedure SetForceOut(Mask, Flag : Longint; var fileMask : string);
  824. begin
  825.  Mask := Mask or Flag;
  826.  if J and Mask = 0
  827.   then begin
  828.         fileMask := '';
  829.         opt.ForceOut := opt.ForceOut and (not Flag);
  830.        end
  831.   else
  832.  if J and Mask = Mask
  833.   then begin
  834.         fileMask := S; S := '';
  835.         if fileMask = ''
  836.          then Stop(2, parmStr);
  837.         if J and fofAlways <> 0
  838.          then opt.ForceOut := opt.ForceOut or Flag
  839.          else opt.ForceOut := opt.ForceOut and (not Flag);
  840.        end;
  841. end;
  842.  
  843. procedure SetTreshold(var Treshold : longint);
  844. begin
  845.  Delete(ParmStr, 1, 2);
  846.  if ParmStr[1] <> ':'
  847.   then begin Treshold := $7FFFFFFF; exit; end;
  848.  Delete(ParmStr, 1, 1);
  849.  if (ParmStr <> '') and (ParmStr[1] in ['0'..'9'])
  850.   then Treshold := DecVal(ParmStr)
  851.   else Treshold := $7FFFFFFF;
  852. end;
  853.  
  854. begin
  855.  parmHandler := 1;
  856.  case upCase(ParmStr[1]) of
  857.   'A' : if length(ParmStr) > 1
  858.          then begin
  859.                case upCase(ParmStr[2]) of
  860.                 'N' : opt.SaveMode := (opt.SaveMode and (not svfAlignFirstObj)) or svfFOalnNone;
  861.                 'P' : opt.SaveMode := (opt.SaveMode and (not svfAlignFirstObj)) or svfFOalnShift;
  862.                 'S' : opt.SaveMode := (opt.SaveMode and (not svfAlignFirstObj)) or svfFOalnSector;
  863.                 ':' : begin SetNewPageShift(3); exit; end;
  864.                 else Stop(2, parmStr);
  865.                end;
  866.                parmHandler := 2;
  867.                if length(ParmStr) > 2
  868.                 then begin
  869.                       case upCase(ParmStr[3]) of
  870.                        'P' : opt.SaveMode := (opt.SaveMode and (not svfAlignEachObj)) or svfEOalnShift;
  871.                        'S' : opt.SaveMode := (opt.SaveMode and (not svfAlignEachObj)) or svfEOalnSector;
  872.                        ':' : begin SetNewPageShift(4); exit; end;
  873.                        else exit;
  874.                       end;
  875.                       parmHandler := 3;
  876.                       if (length(ParmStr) > 3) and (ParmStr[4] = ':')
  877.                        then begin
  878.                              SetNewPageShift(5);
  879.                              exit;
  880.                             end;
  881.                      end;
  882.               end;
  883.   'B' : begin
  884.          I := 1 + GetOpt(parmStr, 2, 'DXN', [bkfIfDebug, bkfIfXtra, bkfIfNE, bkfAlways], opt.Backup);
  885.          if I < length(parmStr)
  886.           then if ParmStr[succ(I)] = ':'
  887.                 then parmHandler := I + ColonGetWord(succ(I), opt.backupDir)
  888.                 else SetRC(I)
  889.           else parmHandler := I;
  890.          if opt.backupDir <> ''
  891.           then if not (opt.backupDir[length(opt.backupDir)] in ['/','\'])
  892.                 then opt.backupDir := opt.backupDir + '\';
  893.         end;
  894.   'C' : case UpCase(parmStr[2]) of
  895.          ':' : begin
  896.                 parmHandler := 1 + ColonGetWord(2, S);
  897.                 if S <> ''
  898.                  then setConfig(S)
  899.                  else Stop(2, parmStr);
  900.                end;
  901.          'S' : begin
  902.                 Delete(parmStr, 1, 1);
  903.                 opt.UseStdOut := isEnabled;
  904.                 SwitchStdOut(opt.UseStdOut);
  905.                end;
  906.          else opt.ColoredOutput := isEnabled;
  907.         end;
  908.   'D' : opt.DiscardXOpts := isEnabled;
  909.   'E' : begin
  910.          parmHandler := 1 + ColonGetWord(2, S);
  911.          if S = ''
  912.           then exclude^.matchStrings^.FreeAll
  913.           else exclude^.AddMask(S);
  914.         end;
  915.   'F' : opt.ForceRepack := isEnabled;
  916.   '?',
  917.   'H' : Stop(1, '');
  918.   'I' : opt.ForceIdle := isEnabled;
  919.   'J' : if length(ParmStr) > 1
  920.          then begin
  921.                case upCase(ParmStr[2]) of
  922.                 'A' : opt.NewType := -1;
  923.                 'E' : opt.NewType := lxEXE;
  924.                 'L' : opt.NewType := lxDLL;
  925.                 'P' : opt.NewType := lxPDD;
  926.                 'V' : opt.NewType := lxVDD;
  927.                 else Stop(2, ParmStr);
  928.                end;
  929.                SetRC(2 + GetOpt(parmStr, 3, 'ELPVNX', [ntfExecutable, ntfLibrary, ntfPhysDriver,
  930.                 ntfVirtDriver, ntfNEmodule, ntfLXmodule, ntfAlways], opt.NewTypeCond));
  931.                if opt.NewType = -1 then opt.NewTypeCond := 0;
  932.               end
  933.          else Stop(2, parmStr);
  934.   'L' : begin
  935.          I := 1 + GetOpt(parmStr, 2, 'SUA', [lcfSucc, lcfUnsucc, lcfAlways], opt.Log);
  936.          if I < length(parmStr)
  937.           then if ParmStr[succ(I)] = ':'
  938.                 then parmHandler := I + ColonGetWord(succ(I), opt.logFileName)
  939.                 else SetRC(I)
  940.           else parmHandler := I;
  941.          if (opt.Log <> 0) and (opt.logFileName = '')
  942.           then opt.logFileName := sourcePath + logFname;
  943.         end;
  944.   'M' : if length(ParmStr) > 1
  945.          then case upCase(ParmStr[2]) of
  946.                'R' : begin
  947.                       parmHandler := 3;
  948.                       opt.PackMode := opt.PackMode and not (pkfRunLength or pkfRunLengthLvl);
  949.                       if length(ParmStr) > 2
  950.                        then case upCase(ParmStr[3]) of
  951.                              '1' : opt.PackMode := opt.PackMode or pkfRunLength or pkfRunLengthMin;
  952.                              '2' : opt.PackMode := opt.PackMode or pkfRunLength or pkfRunLengthMid;
  953.                              '3' : opt.PackMode := opt.PackMode or pkfRunLength or pkfRunLengthMax;
  954.                              'N' : ;
  955.                              else Stop(2, parmStr);
  956.                             end
  957.                        else Stop(2, parmStr);
  958.                      end;
  959.                'L' : begin
  960.                       parmHandler := 3;
  961.                       if length(ParmStr) > 2
  962.                        then case upCase(ParmStr[3]) of
  963.                              '1' : opt.PackMode := opt.PackMode or pkfLempelZiv;
  964.                              'N' : opt.PackMode := opt.PackMode and not pkfLempelZiv;
  965.                              else Stop(2, parmStr);
  966.                             end
  967.                        else Stop(2, parmStr);
  968.                      end;
  969.                'F' : begin
  970.                       parmHandler := 3;
  971.                       opt.PackMode := opt.PackMode ;
  972.                       if length(ParmStr) > 2
  973.                        then case upCase(ParmStr[3]) of
  974.                              '1' : opt.PackMode := (opt.PackMode and (not pkfFixupsLvl)) or pkfFixups or pkfFixupsVer2;
  975.                              '2' : opt.PackMode := (opt.PackMode and (not pkfFixupsLvl)) or pkfFixups or pkfFixupsVer4;
  976.                              '3' : opt.PackMode := (opt.PackMode and (not pkfFixupsLvl)) or pkfFixups or pkfFixupsMax;
  977.                              'N' : opt.PackMode := (opt.PackMode and (not (pkfFixups or pkfFixupsLvl)));
  978.                              'A' : begin
  979.                                     Delete(ParmStr, 1, 2);
  980.                                     opt.ApplyFixups := isEnabled;
  981.                                    end;
  982.                              else Stop(2, parmStr);
  983.                             end
  984.                        else Stop(2, parmStr);
  985.                      end;
  986.                else Stop(2, parmStr);
  987.               end
  988.          else Stop(2, parmStr);
  989.   'N' : SetRC(1 + GetOpt(parmStr, 2, 'BLRA', [lneIgnoreBound, lneIgnoreLngName, lneIgnoreRsrc, lneAlways], opt.NEloadMode));
  990.   'O' : begin
  991.          J := fofDebug + fofXtra + fofStub;
  992.          I := 1 + GetOpt(parmStr, 2, 'DXSA', [fofDebug + $10, fofXtra + $20,
  993.                fofStub + $40, fofAlways, fofAnything], J);
  994.          parmHandler := I + ColonGetWord(succ(I), S);
  995.          SetForceOut($10, fofDebug, opt.ddFileMask);
  996.          SetForceOut($20, fofXtra,  opt.xdFileMask);
  997.          SetForceOut($40, fofStub,  opt.sdFileMask);
  998.          if S <> '' then Stop(2, parmStr);
  999.         end;
  1000.   'P' : opt.Pause := isEnabled;
  1001.   'Q' : opt.QueryCfgList := isEnabled;
  1002.   'R' : opt.RecurSearch := isEnabled;
  1003.   'S' : opt.ShowConfig := isEnabled;
  1004.   'T' : parmHandler := 1 + ColonGetWord(2, opt.stubName);
  1005.   'U' : opt.Unpack := isEnabled;
  1006.   'V' : SetRC(1 + GetOpt(parmStr, 2, '0123OCRNMPEF', [vfHeaderL0, vfHeaderL1,
  1007.          vfHeaderL2, vfHeaderL3, vfObjects, vfPageMap, vfResName, vfNResName,
  1008.          vfImpName, vfImpProc, vfEntTable, vfFixups, vfAnything], opt.Verbose));
  1009.   'W' : begin
  1010.          opt.FinalWrite := 0;
  1011.          SetRC(1 + GetOpt(parmStr, 2, 'SW', [fwfSimulate, fwfWrite, fwfAlways], opt.FinalWrite));
  1012.          if opt.FinalWrite and fwfWrite <> 0
  1013.           then opt.FinalWrite := fwfWrite;
  1014.         end;
  1015.   'X' : begin
  1016.          opt.doUnpack := isEnabled;
  1017.          if opt.doUnpack then setConfig('unpack');
  1018.         end;
  1019.   'Y' : if (length(ParmStr) > 1) and (ParmStr[2] > ' ')
  1020.          then begin
  1021.                parmHandler := 2;
  1022.                For I := askFirst to askLast do {Enable all queries}
  1023.                 with opt.AskStatus[I] do
  1024.                  if UpCase(ParmStr[2]) = ID
  1025.                   then begin
  1026.                         if (length(ParmStr) > 2) and (ParmStr[3] > ' ')
  1027.                          then begin
  1028.                                Reply := ParmStr[3];
  1029.                                parmHandler := 3;
  1030.                               end
  1031.                          else Reply := #0;
  1032.                         exit;
  1033.                        end;
  1034.                Stop(2, parmStr);
  1035.               end
  1036.          else For I := askFirst to askLast do {Enable all queries}
  1037.                opt.AskStatus[I].Reply := #0;
  1038.   'Z' : if length(ParmStr) > 1
  1039.          then case upCase(ParmStr[2]) of
  1040.                'D' : SetTreshold(opt.tresholdDbug);
  1041.                'S' : SetTreshold(opt.tresholdStub);
  1042.                'X' : SetTreshold(opt.tresholdXtra);
  1043.               end
  1044.          else Stop(2, parmStr);
  1045.   else Stop(2, parmStr);
  1046.  end;
  1047. end;
  1048.  
  1049. function tMyCmdLineParser.NameHandler;
  1050. var
  1051.  S : string;
  1052. begin
  1053.  NameHandler := GetWord(ParmStr, 1, S);
  1054.  if S <> '' then fNames^.AtInsert(fNames^.Count, NewStr(S));
  1055. end;
  1056.  
  1057. procedure tMyCmdLineParser.PreProcess;
  1058. begin
  1059.  if CmdLineStack = nil then New(CmdLineStack, Create(8, 8));
  1060.  CmdLineStack^.AtInsert(CmdLineStack^.Count, NewStr(ParmStr));
  1061. end;
  1062.  
  1063. procedure tMyCmdLineParser.PostProcess;
  1064. begin
  1065.  CmdLineStack^.AtFree(pred(CmdLineStack^.Count));
  1066. end;
  1067.  
  1068. destructor tMyCmdLineParser.Destroy;
  1069. begin
  1070.  if CmdLineStack <> nil
  1071.   then Dispose(CmdLineStack, Destroy);
  1072.  inherited Destroy;
  1073. end;
  1074.  
  1075. procedure LoadConfig;
  1076. label
  1077.  newID;
  1078. var
  1079.  T    : text;
  1080.  I    : Integer;
  1081.  Mode : Byte;
  1082.  iPos : pCollection;
  1083.  pSC  : pStringCollection;
  1084.  S    : string;
  1085. begin
  1086.  S := sourcePath + cfgFname;
  1087.  Assign(T, S); Reset(T);
  1088.  if ioResult <> 0 then Stop(msgCannotLoadCFG, S);
  1089.  New(iPos, Create(4, 4));
  1090.  Mode := 0;
  1091.  While (ioResult = 0) and (not SeekEOF(T)) do
  1092.   begin
  1093.    Readln(T, S);
  1094.    DelTrailingSpaces(S);
  1095.    if First(';', S) <> 0
  1096.     then Delete(S, First(';', S), 255);
  1097.    While S <> '' do
  1098.     begin
  1099.      case Mode of
  1100.       0 : if S[1] = '['
  1101.            then begin
  1102. newID:           Delete(S, 1, 1); Mode := 1;
  1103.                  iPos^.DeleteAll;
  1104.                 end
  1105.            else S := '';
  1106.       1 : begin
  1107.            if S[length(S)] = ']'
  1108.             then begin
  1109.                   Dec(byte(S[0])); Mode := 2;
  1110.                   DelTrailingSpaces(S);
  1111.                  end;
  1112.            UpStr(S);
  1113.            I := cfgIDs^.Insert(NewStr(S));
  1114.            pSC := New(pStringCollection, Create(16, 16));
  1115.            iPos^.Insert(pSC);
  1116.            cfgOpts^.AtInsert(I, pSC);
  1117.            S := '';
  1118.           end;
  1119.       2 : begin
  1120.            if S[1] = '[' then Goto newID;
  1121.            For I := 1 to iPos^.Count do
  1122.             pStringCollection(iPos^.At(pred(I)))^.Insert(NewStr(S));
  1123.            S := '';
  1124.           end;
  1125.      end;
  1126.      DelStartSpaces(S);
  1127.     end;
  1128.   end;
  1129.  Close(T);
  1130.  iPos^.DeleteAll;
  1131.  Dispose(iPos, Destroy);
  1132.  for I := cfgIDs^.Count downto 1 do
  1133.   begin
  1134.    S := pString(cfgIDs^.At(pred(I)))^;
  1135.    if S[1] = '/'
  1136.     then begin
  1137.           Delete(S, 1, 1);
  1138.           extra^.AtInsert(extra^.Count, New(pFileMatch, Create(S)));
  1139.           extraOpts^.AtInsert(extraOpts^.Count, cfgOpts^.At(pred(I)));
  1140.           cfgIDs^.AtFree(pred(I));
  1141.           cfgOpts^.AtDelete(pred(I));
  1142.          end;
  1143.   end;
  1144. end;
  1145.  
  1146. procedure setConfig;
  1147. var
  1148.  S   : String;
  1149.  I   : Longint;
  1150.  pSC : pStringCollection;
  1151. begin
  1152.  s := upStrg(ID);
  1153.  if loadCFG^.IndexOf(@s) <> -1 then exit;
  1154.  loadCFG^.Insert(NewStr(s));
  1155.  I := cfgIDs^.IndexOf(@s);
  1156.  if I = -1
  1157.   then begin
  1158.         SetColor($0C);
  1159.         Stop(msgCfgLoadFailed, ID);
  1160.        end;
  1161.  pSC := cfgOpts^.At(I);
  1162.  if pSC <> nil
  1163.   then For I := 1 to pSC^.Count do
  1164.         begin
  1165.          S := pString(pSC^.At(pred(I)))^;
  1166.          Parser^.Parse(S);
  1167.         end;
  1168. end;
  1169.  
  1170. end.
  1171.