{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: Bpg2MakeUtils.pas, released on 2003-09-29. The Initial Developer of the Original Code is Andreas Hausladen (Andreas dott Hausladen att gmx dott de) Portions created by Andreas Hausladen are Copyright (C) 2004 Andreas Hausladen. All Rights Reserved. Contributor(s): - You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.sourceforge.net Known Issues: -----------------------------------------------------------------------------} // $Id: Bpg2MakeUtils.pas 11963 2008-10-16 09:12:52Z obones $ unit Bpg2MakeUtils; {$I jvcl.inc} interface procedure Run; function CreateMakeFile(const Filename: string): Boolean; implementation uses Windows, Classes, SysUtils, JvConsts, JvSimpleXml; const DefaultMakeFile = '#--------------------------------------------------------------------------------------------------#' + sLineBreak + '# #' + sLineBreak + '# autogenerated makefile for Package Groups #' + sLineBreak + '# #' + sLineBreak + '#--------------------------------------------------------------------------------------------------#' + sLineBreak + '' + sLineBreak + '!ifndef ROOT' + sLineBreak + 'ROOT = $(MAKEDIR)\..' + sLineBreak + '!endif' + sLineBreak + '#--------------------------------------------------------------------------------------------------#' + sLineBreak + 'MAKE = "$(ROOT)\bin\make.exe" -$(MAKEFLAGS) -f$**' + sLineBreak + 'BRCC = "$(ROOT)\bin\brcc32.exe" $**' + sLineBreak + '' + sLineBreak + '!ifndef DCCOPT' + sLineBreak + 'DCCOPT=-Q -M' + sLineBreak + '!endif' + sLineBreak + '' + sLineBreak + '!ifndef DCC' + sLineBreak + 'DCC = "$(ROOT)\bin\dcc32.exe" -U"$(DCPDIR)" -LE"$(DCPDIR)" -LN"$(DCPDIR)" $(DCCOPT) -Q -W -H -M $&.dpk' + sLineBreak + '!else' + sLineBreak + 'DCC = "$(ROOT)\bin\dcc32.exe" $(DCCOPT) $&.dpk' + sLineBreak + '!endif' + sLineBreak + '' + sLineBreak + '#--------------------------------------------------------------------------------------------------#' + sLineBreak; //-------------------------------------------------------------------------------------------------- function StrEqualText(Text: PChar; SearchText: PChar; MaxLen: Integer; IgnoreCase: Boolean): Boolean; var i: Integer; begin if IgnoreCase then Result := StrLIComp(Text, SearchText, MaxLen) = 0 else begin Result := False; for i := 0 to MaxLen - 1 do if (Text[i] = #0) or {(SearchText[i] = #0) or} (Text[i] <> SearchText[i]) then Exit; Result := True; end; end; function FastStringReplace(const Text, SearchText, ReplaceText: string; ReplaceAll, IgnoreCase: Boolean): string; var LenSearchText, LenReplaceText, LenText: Integer; Index, Len, StartIndex: Integer; begin LenSearchText := Length(SearchText); LenReplaceText := Length(ReplaceText); LenText := Length(Text); if LenSearchText = 0 then begin Result := Text; Exit; end; if ReplaceAll then begin if LenReplaceText - LenSearchText > 0 then SetLength(Result, LenText + (LenReplaceText - LenSearchText) * (LenText div LenSearchText)) else SetLength(Result, LenText); end else SetLength(Result, LenText + (LenReplaceText - LenSearchText)); Len := 0; StartIndex := 1; for Index := 1 to LenText do begin if StrEqualText(PChar(Pointer(Text)) + Index - 1, Pointer(SearchText), LenSearchText, IgnoreCase) then begin if Index > StartIndex then begin Move(Text[StartIndex], Result[Len + 1], (Index - StartIndex) * SizeOf(Char)); Inc(Len, Index - StartIndex); end; StartIndex := Index + LenSearchText; if LenReplaceText > 0 then begin Move(ReplaceText[1], Result[Len + 1], LenReplaceText * SizeOf(Char)); Inc(Len, LenReplaceText); end; if not ReplaceAll then Break; end; end; Index := LenText + 1; if Index > StartIndex then begin Move(Text[StartIndex], Result[Len + 1], (Index - StartIndex) * SizeOf(Char)); Inc(Len, Index - StartIndex); end; SetLength(Result, Len); end; procedure ShowHelp; begin writeln(''); writeln(''); writeln('Bpg2Make: Creates a MAKEFILE from a bpg/bdsgroup file'); writeln(''); writeln('Usage:'); writeln(ExtractFilename(ParamStr(0)),' '); writeln(''); writeln(#9' - the Borland Package Group file'); end; function GetReturnPath(const Dir: string): string; var i: Integer; begin Result := ''; if Dir <> '' then begin Result := '..'; for i := 1 to Length(Dir) do if Dir[i] = PathDelim then Result := Result + '\..'; end; end; {$IFDEF COMPILER5} type UTF8String = type string; {$ENDIF COMPILER5} function LoadUtf8File(const Filename: string): string; const BOM_UTF16_LSB: array [0..1] of Char = #$FF#$FE; BOM_UTF16_MSB: array [0..1] of Char = #$FE#$FF; BOM_UTF8: array [0..2] of Char = #$EF#$BB#$BF; var Content: UTF8String; Stream: TFileStream; begin Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite); try SetLength(Content, Stream.Size); Stream.Read(Content[1], Stream.Size); finally Stream.Free; end; if Copy(Content, 1, 3) = BOM_UTF8 then begin Delete(Content, 1, 3); {$IFDEF COMPILER6_UP} Result := Utf8ToAnsi(Content); {$ELSE} Result := Content; {$ENDIF COMPILER6_UP} end else Result := Content; end; procedure ProcessBdsgroupFile(const Filename: string; MkLines, Targets, Commands: TStrings); var xml: TJvSimpleXML; Options, Projects: TJvSimpleXMLElem; i, OptIndex, PrjIndex: Integer; Personality: string; TgName: string; begin xml := TJvSimpleXML.Create(nil); try xml.LoadFromString(LoadUtf8File(Filename)); for i := 0 to xml.Root.Items.Count - 1 do begin if (CompareText(xml.Root.Items[i].Name, 'PersonalityInfo') = 0) and // (xml.Root.Items[i].Items.Count > 0) then begin // find correct Personality Options := xml.Root.Items[i].Items[0]; if CompareText(Options.Name, 'Option') = 0 then begin for OptIndex := 0 to Options.Items.Count - 1 do if CompareText(Options.Items[OptIndex].Properties.Value('Name'), 'Personality') = 0 then begin Personality := Options.Items[OptIndex].Value; Break; end; end; end else if (CompareText(xml.Root.Items[i].Name, Personality) = 0) and (xml.Root.Items[i].Items.Count > 0) and (CompareText(xml.Root.Items[i].Items[0].Name, 'Projects') = 0) then begin // Read project list Projects := xml.Root.Items[i].Items[0]; for PrjIndex := 0 to Projects.Items.Count - 1 do begin TgName := Projects.Items[PrjIndex].Properties.Value('Name'); if CompareText(TgName, 'Targets') <> 0 then begin // change .bdsproj to .dpk and add the target Targets.Add(TgName + '=' + ChangeFileExt(Projects.Items[PrjIndex].Value, '.dpk')); Commands.Add(#9'$(DCC)'); end; end; end; end; if Targets.Count > 1 then begin MkLines.Add('PROJECTS = ' + Targets.Names[0] + ' \'); for i := 1 to Targets.Count - 2 do MkLines.Add(#9 + Targets.Names[i] + ' \'); MkLines.Add(#9 + Targets.Names[Targets.Count - 1]); end else if Targets.Count = 1 then MkLines.Add('PROJECTS = ' + Targets.Names[0]); finally xml.Free; end; end; procedure ProcessBpgFile(const Filename: string; MkLines, Targets, Commands: TStrings); var i, ps: Integer; List: TStringlist; S: string; ProjectCommands: string; begin List := TStringList.Create; try List.LoadFromFile(Filename); i := 0; while i < List.Count do begin S := List[i]; ps := Pos('bpl: ', S); if ps <> 0 then begin Targets.Add(Trim(Copy(S, 1, ps + 2)) + '=' + Trim(Copy(S, ps + 5, MaxInt))); ProjectCommands := ''; Inc(i); while (i < List.Count) and (List[i] <> '') do begin ProjectCommands := ProjectCommands + #9 + Trim(List[i]) + #13#10; Inc(i); end; SetLength(ProjectCommands, Length(ProjectCommands) - 2); Commands.Add(ProjectCommands); end; if StrLIComp('PROJECTS =', PChar(S), 10) = 0 then begin s := Trim(S); MkLines.Add(S); while (i < List.Count) and (S <> '') and (S[Length(S)] = '\') do begin Inc(i); S := Trim(List[i]); MkLines.Add(#9 + S); end; end; Inc(i); end; finally List.Free; end; end; function CreateMakeFile(const Filename: string): Boolean; var MkLines, Targets, Commands: TStrings; S, SourceFile, Dir, ProjectCommands: string; i, ps: Integer; begin Result := False; if not FileExists(Filename) then begin WriteLn('ERROR: ', Filename, ' not found!'); Exit; end; MkLines := TStringList.Create; Targets := TStringList.Create; Commands := TStringList.Create; try MkLines.Text := DefaultMakeFile; if CompareText(ExtractFileExt(Filename), '.bpg') = 0 then ProcessBpgFile(Filename, MkLines, Targets, Commands) else ProcessBdsgroupFile(Filename, MkLines, Targets, Commands); MkLines.Add(''); MkLines.Add('#---------------------------------------------------------------------------------------------------'); MkLines.Add('default: $(PROJECTS)'); MkLines.Add('#---------------------------------------------------------------------------------------------------'); MkLines.Add(''); for i := 0 to Targets.Count - 1 do begin S := Targets[i]; ps := Pos('=', S); SourceFile := Copy(S, ps + 1, MaxInt); SetLength(S, ps - 1); Dir := ExtractFileDir(SourceFile); MkLines.Add(S + ': ' + SourceFile); SourceFile := ExtractFileName(SourceFile); if Dir <> '' then MkLines.Add(#9'@cd ' + Dir); ProjectCommands := Commands[i]; ProjectCommands := FastStringReplace(ProjectCommands, '$**', SourceFile, True, False); ProjectCommands := FastStringReplace(ProjectCommands, '$*', Copy(SourceFile, 1, Length(SourceFile) - Length(ExtractFileExt(SourceFile))), True, False); // long path name support ProjectCommands := FastStringReplace(ProjectCommands, '$(ROOT)\bin\bpr2mak', '"$(ROOT)\bin\bpr2mak"', False, True); ProjectCommands := FastStringReplace(ProjectCommands, '$(ROOT)\bin\make', '"$(ROOT)\bin\make"', False, True); MkLines.Add(#9'@echo [Compiling: ' + S + ']'); MkLines.Add(ProjectCommands); MkLines.Add(#9'@echo.'); if Dir <> '' then MkLines.Add(#9'@cd ' + GetReturnPath(Dir)); MkLines.Add(''); end; MkLines.SaveToFile(ChangeFileExt(FileName, '.mak')); finally Commands.Free; Targets.Free; MkLines.Free; end; Result := True; end; procedure Run; var Ext: string; begin Ext := LowerCase(ExtractFileExt(ParamStr(1))); if (ParamCount <> 1) or ((Ext <> '.bpg') and (Ext <> '.bdsgroup')) then ShowHelp else try if CreateMakeFile(ExpandUNCFileName(ParamStr(1))) then WriteLn(' Makefile created'); except on E: Exception do WriteLn('ERROR: ', E.Message); end; end; end.