// SPDX-License-Identifier: LGPL-3.0-linking-exception unit ConstFile; {$mode objfpc}{$H+} interface uses Classes, SysUtils, ReleaserTypes; type { TConstFile } TConstFile = class(TReleaserObject) private FFilename, FConstname: String; FSourceCode: string; FChanged: boolean; procedure AnalyzeVersionLine(ALine: string; out AValueStart, AValueLength: integer); public constructor Create(AParameters: TStringList; ALogicDir: string); override; destructor Destroy; override; procedure Save; override; function TryVersion(out AValue: TVersion): boolean; procedure GetVersions(AVersionList: TStringList); override; procedure UpdateVersion(AVersion: TVersion); override; end; implementation { TConstFile } procedure TConstFile.AnalyzeVersionLine(ALine: string; out AValueStart, AValueLength: integer); var s: String; p: integer; begin AValueStart := 0; AValueLength:= 0; s := ALine; p := pos(FConstname+' ',s); if (p<> 0) and ((p=1) or (s[p-1] in[#0..#32])) then begin inc(p, length(FConstName)); while (p <= length(s)) and (s[p] in[#0..#32]) do inc(p); if (p <= length(s)) and (s[p] = '=') then begin inc(p); while (p <= length(s)) and (s[p] in[#0..#32]) do inc(p); AValueStart := p; while (p <= length(s)) and (s[p] in['0'..'9']) do inc(p); AValueLength:= p-AValueStart; exit; end; end; end; constructor TConstFile.Create(AParameters: TStringList; ALogicDir: string); var ver: TVersion; str: TStringStream; stream: TFileStream; begin inherited Create(AParameters, ALogicDir); ExpectParamCount(2); FFilename := ExpandFileName(ReplaceVariables(Param[0])); FConstname := Param[1]; stream := nil; str := nil; try stream := TFileStream.Create(FFilename, fmOpenRead); str := TStringStream.Create(''); if str.CopyFrom(stream, stream.Size)<>stream.Size then raise exception.Create('Unable to read file'); FSourceCode := str.DataString; finally str.Free; stream.Free; end; if TryVersion(ver) then writeln('Code file "',ExtractFileName(FFilename),'" version ',VersionToStr(ver)) else writeln('Code file "',ExtractFileName(FFilename),'" undefined version'); end; destructor TConstFile.Destroy; begin inherited Destroy; end; procedure TConstFile.Save; var stream: TFileStream; begin if FChanged then begin writeln('Updating code file "',ExtractFileName(FFilename),'"'); stream := TFileStream.Create(FFilename, fmCreate); try if FSourceCode <> '' then stream.WriteBuffer(FSourceCode[1], length(FSourceCode)); finally stream.Free; end; end; end; function TConstFile.TryVersion(out AValue: TVersion): boolean; var valueStart,valueLen,errPos: integer; verValue: LongWord; begin AValue.Major:= 0; AValue.Minor:= 0; AValue.Release:= 0; AValue.Build:= 0; AnalyzeVersionLine(FSourceCode, valueStart, valueLen); if valueStart > 0 then begin val(copy(FSourceCode, valueStart, valueLen), verValue, errPos); if errPos = 0 then begin AValue.Major:= verValue div 1000000; AValue.Minor := (verValue div 10000) mod 100; AValue.Release := (verValue div 100) mod 100; AValue.Build := verValue mod 100; exit(true); end; end; result := false; end; procedure TConstFile.GetVersions(AVersionList: TStringList); var ver: TVersion; verStr: String; begin if TryVersion(ver) then begin verStr := VersionToStr(ver); if AVersionList.IndexOf(verStr)=-1 then AVersionList.Add(verStr); end; end; procedure TConstFile.UpdateVersion(AVersion: TVersion); var ver: TVersion; newValue, valueStart, valueLength: Integer; s: String; begin newValue := AVersion.Major*1000000 + AVersion.Minor*10000 + AVersion.Release*100 + AVersion.Build; if TryVersion(ver) then begin if AVersion<>ver then begin AnalyzeVersionLine(FSourceCode, valueStart,valueLength); if valueStart <> 0 then begin s := FSourceCode; delete(s, valueStart,valueLength); insert(IntToStr(newValue), s,valueStart); FSourceCode := s; FChanged:= true; end; end; end else writeln('Please add manually a constant ',FConstname,' = ',newValue,' in "',ExtractFileName(FFilename),'"'); end; end.