| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 | {$MODE FPC}{    This file is part of Free Pascal build tools    Copyright (c) 2014-2015 by Tomas Hajny, member of the FPC core team.    This program takes processes one or more listing files created with    fpmake (e.g. using 'fpmake pkglist --target=<FPC_target> -zp units-'    for unit packages or without the '-zp <prefix>' for utils), compares    them to the text-mode installer configuration file install.dat and    creates file install.add which provides information about packages    missing in install.dat in a form allowing copy&paste of individual    lines into install.dat.    If the original description of a certain package as found in fpmake.pp    is too long for install.dat, the maximum length is marked    in the respective line in install.add using a pipe character ('|').    See the file COPYING.FPC, included in this distribution,    for details about the copyright.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************}program mkinsadd;uses dos, objects;const MaxTarget = 5; TargetListShort: array [1..MaxTarget] of string [3] = ('dos', 'emx', 'os2', 'w32', 'src'); TargetListLong: array [1..MaxTarget] of string = ('dos', 'emx', 'os2', '.i386-win32', '.source'); DefDiffFN = 'install.add'; PackageStr = 'package='; UnitsStr = 'units-'; ZipExt = '.zip';type PPackageRec = ^TPackageRec; TPackageRec = object (TObject)  Name, ShortName, Desc: PString;  Target: byte;  constructor Init (ALine: string);  function GetKeyStr: string;  function GetLine: string;  function GetSrcLine: string;  destructor Done; virtual; end; PPackageCollection = ^TPackageCollection; TPackageCollection = object (TSortedCollection)  constructor Load (FN: string);  function LoadFile (FN: string; DupSrc: PPackageCollection): boolean;  function WriteFile (FN: string): boolean;  function Compare (Key1, Key2: pointer): sw_integer; virtual; end; PDatFile = ^TDatFile; TDatFile = object (TObject)  DatCollection, LstCollection: PPackageCollection;  constructor LoadDat (FN: string);  function ReadLstFile (FN: string): boolean;  function WriteNew (FN: string): boolean;  destructor Done; virtual; end;function LoCase (S: string): string;var I: longint;begin for I := 1 to Length (S) do  if S [I] in ['A'..'Z'] then   S [I] := char (Ord (S [I]) + 32); LoCase := S;end;constructor TPackageRec.Init (ALine: string);var I: longint; J: byte; N, SN, D, TS: string; ALine2: string;begin inherited Init; N := ''; SN := ''; D := ''; TS := ''; ALine2 := LoCase (ALine); if Copy (ALine2, 1, Length (PackageStr)) = PackageStr then  begin   Delete (ALine, 1, Length (PackageStr));   I := Pos ('[', ALine);   if I = 0 then    begin     I := Pos (',', ALine);     if I = 0 then      I := Succ (Length (ALine));    end   else    begin     SN := Copy (ALine, Succ (I), Pos (',', ALine) - I - 2);     Delete (ALine, I, Length (SN) + 2);    end;   N := Copy (ALine, 1, Pred (I));   if Length (N) <= 12 then    SN := N   else if (Copy (N, 1, Length (UnitsStr)) = UnitsStr) and                                    (Length (N) - Length (UnitsStr) <= 11) then    SN := 'u' + Copy (N, Succ (Length (UnitsStr)),                                               Length (N) - Length (UnitsStr));   D := Copy (ALine, Succ (I), Length (ALine) - I);  end; Name := NewStr (N); if SN <> '' then  ShortName := NewStr (SN) else  ShortName := nil; Desc := NewStr (D); Target := 0; if SN <> '' then  begin   TS := LoCase (Copy (SN, Length (SN) - Length (ZipExt) - 2, 3));   if Length (TS) <> 3 then    TS := ''   else    for J := 1 to MaxTarget do     if TS = TargetListShort [J] then      begin       Target := J;       Break;      end;  end else  begin   I := Length (N) - Length (ZipExt);   while (I > 0) and (N [I] <> '.') do    Dec (I);   if I = 0 then    TS := LoCase (Copy (N, Length (SN) - Length (ZipExt) - 2, 3))   else    TS := LoCase (Copy (N, I, Length (N) - Length (ZipExt) - I + 1));   for J := 1 to MaxTarget do    if TS = TargetListLong [J] then     begin      Target := J;      Break;     end;  end; if N = '' then  begin   WriteLn ('Err: Init failed (', ALine, ')!');   Fail;  end;end;destructor TPackageRec.Done;begin DisposeStr (Name); if ShortName <> nil then  DisposeStr (ShortName); DisposeStr (Desc); inherited Done;end;function TPackageRec.GetKeyStr: string;var G: string;begin if ShortName <> nil then  begin   if Target = 0 then    G := LoCase (Copy (ShortName^, 1, Length (ShortName^) - Length (ZipExt)))   else    G := LoCase (Copy (ShortName^, 1, Length (ShortName^) - Length (ZipExt) - 3));  end else  begin   if Name = nil then    begin     GetKeyStr := '';     WriteLn ('Err - GetKeyStr (nil)!');     Exit;    end;   if Target = 0 then    G := LoCase (Copy (Name^, 1, Length (Name^) - Length (ZipExt)))   else    begin     if Copy (LoCase (Name^), 1, Length (UnitsStr)) = UnitsStr then      G := 'u' + LoCase (Copy (Name^, Succ (Length (UnitsStr)),         Length (Name^) - Length (UnitsStr) - Length (TargetListLong [Target])                                                            - Length (ZipExt)))     else      G := LoCase (Copy (Name^, 1,         Length (Name^) - Length (TargetListLong [Target]) - Length (ZipExt)));    end;  end; G := G + '.'; if Target <> 0 then  G := G + TargetListShort [Target]; GetKeyStr := G;end;function TPackageRec.GetLine: string;var G: string;begin G := PackageStr + Name^; if ShortName <> nil then  G := G + '[' + ShortName^ + ']'; if Length (Desc^) <= 45 then  G := G + ',' + Desc^ else  G := G + ',' + Copy (Desc^, 1, 45) + '|' +                                         Copy (Desc^, 46, Length (Desc^) - 45); GetLine := G;end;function TPackageRec.GetSrcLine: string;var GS: string;begin if Target = 0 then  GS := '' else  begin   GS := PackageStr + Copy (Name^, 1,     Length (Name^) - Length (TargetListLong [Target]) - Length (ZipExt)) +                                           TargetListLong [MaxTarget] + ZipExt;   if ShortName <> nil then    GS := GS + '[' + Copy (ShortName^, 1, Length (ShortName^)                    - Length (TargetListShort [Target]) - Length (ZipExt)) +                                    TargetListShort [MaxTarget] + ZipExt + ']';   GS := GS + ',' + Desc^;  end; GetSrcLine := GS;end;constructor TDatFile.LoadDat (FN: string);begin Init; New (DatCollection, Load (FN)); New (LstCollection, Init (100, 50)); (* false? *)end;function TDatFile.ReadLstFile (FN: string): boolean;begin ReadLstFile := LstCollection^.LoadFile (FN, DatCollection);end;function TDatFile.WriteNew (FN: string): boolean;begin WriteNew := LstCollection^.WriteFile (FN);end;destructor TDatFile.Done;begin Dispose (DatCollection, Done); Dispose (LstCollection, Done); inherited Done;end;constructor TPackageCollection.Load (FN: string);begin Init (100, 50); if not (LoadFile (FN, nil)) then  Fail;end;function TPackageCollection.LoadFile (FN: string; DupSrc: PPackageCollection): boolean;var F: text; S: ansistring; S2: string; P, Q: PPackageRec; I: SW_Integer;begin{$I-} Assign (F, FN); Reset (F); while not (Eof (F)) {and (LastErr = 0)} do  begin   S := '';   ReadLn (F, S);   if (Length (S) > 255) then    begin     WriteLn ('Error: Line too long!');     WriteLn (S);     Halt (255); (* Change error handling *)    end;   if Copy (LoCase (S), 1, Length (PackageStr)) = PackageStr then    begin     New (P, Init (S));     if DupSrc = nil then      S2 := ''     else      S2 := P^.GetSrcLine;     if (DupSrc = nil) or not (DupSrc^.Search (P, I)) then      Insert (P)     else      Dispose (P, Done);     if S2 <> '' then      begin       New (Q, Init (S2));       if (Q <> nil) and not (Search (Q, I)) and                           ((DupSrc = nil) or not (DupSrc^.Search (Q, I))) then        Insert (Q)       else        Dispose (Q, Done);      end;    end;  end; Close (F); LoadFile := IOResult = 0;{ if P = nil then Fail else begin  if P^.LastErr <> 0 then  begin   Dispose (P, Done);   Fail;  end else  begin   P^.ReadIni (@Self);   Dispose (P, Done);  end; end;}end;function TPackageCollection.WriteFile (FN: string): boolean;var F: text; S: string; P: PPackageRec; I: SW_Integer; J: byte;begin Assign (F, FN); Rewrite (F); for J := 0 to MaxTarget do  for I := 0 to Count - 1 do   begin    P := At (I);    if (P <> nil) and (P^.Target = J) then     begin{ Write (P^.Name^, '|');   if P^.ShortName <> nil then    Write (P^.ShortName^, '|')   else    Write ('x|');   WriteLn (P^.Desc^, '|', P^.Target); WriteLn (P^.GetKeyStr);}      S := P^.GetLine;(* Signalize too long description *)      WriteLn (F, S);     end;   end; Close (F); WriteFile := IOResult = 0;end;function TPackageCollection.Compare (Key1, Key2: pointer): SW_Integer;var S1, S2: string;begin S1 := LoCase (PPackageRec (Key1)^.GetKeyStr); S2 := LoCase (PPackageRec (Key2)^.GetKeyStr); if S1 < S2 then  Compare := -1 else if S1 > S2 then  Compare := 1 else  Compare := 0;end;function Base (const S: string): string;var D: DirStr; N: NameStr; E: ExtStr;begin FSplit (S, D, N, E); Base := N;end;procedure Error (const S: string; B: byte);begin WriteLn; WriteLn ('Error: ', S, '!!'); Halt (B);end;procedure Syntax;begin WriteLn; WriteLn ('Syntax: ', Base (ParamStr (0)),                          ' <path_to_install.dat> <LstFile1> [<LstFile2>...]'); WriteLn; WriteLn ('<LstFileN> files are expected to be in the format produced by fpmake'); WriteLn ('(e.g. using ''fpmake pkglist --target=<FPC_target> -zp units-'''); WriteLn ('for unit packages or without the ''-zp <prefix>'' parameter for utils).'); WriteLn; WriteLn ('Program compares their content to the list of packages in the text-mode'); WriteLn ('installer configuration file install.dat and creates file install.add'); WriteLn ('with information about packages missing in install.dat in a form allowing'); WriteLn ('copy&paste of individual lines into install.dat.'); WriteLn; WriteLn ('If the original description of a certain package as found in fpmake.pp is'); WriteLn ('too long for install.dat, the maximum length is marked in the respective line'); WriteLn ('in install.add using a pipe character (''|'') to give hint for manual editing.'); Halt;end;var I, J: byte; DAT: TDatFile; PrevCount: SW_Integer;begin J := ParamCount; if J < 2 then  begin   WriteLn;   WriteLn ('Error: Too few parameters!!');   Syntax;  end; DAT.LoadDat (ParamStr (1)); if DAT.DatCollection <> nil then  WriteLn (LineEnding +            'Source install.dat file (', ParamStr (1), ') loaded correctly: ',                                          DAT.DatCollection^.Count, ' records') else  Error ('Failure while loading source install.dat file (' + ParamStr (1) +                                                                       ')', 1); for I := 2 to J do  begin   PrevCount := DAT.LstCollection^.Count;   if DAT.ReadLstFile (ParamStr (I)) then    WriteLn ('Package listing #', Pred (I), ' (', ParamStr (I),      ') loaded correctly: ', DAT.LstCollection^.Count - PrevCount,                                                                ' new records')   else    Error ('Failure while loading package listing (' + ParamStr (I) + ')', I);  end; WriteLn ('Total: ', DAT.LstCollection^.Count, ' new records'); if DAT.WriteNew (DefDiffFN) then  WriteLn ('Output file (' + DefDiffFN + ') created successfully.') else  Error ('Failure while trying to write records to the output file (' +                                                    DefDiffFN + ')', Succ (J)); DAT.Done;end.
 |