1{ 2 /*************************************************************************** 3 lazconf.pp 4 ------------------- 5 Lazarus Config Functions 6 Initial Revision : Tue Apr 18 22:10:00 CET 2000 7 8 ***************************************************************************/ 9 10 *************************************************************************** 11 * * 12 * This source is free software; you can redistribute it and/or modify * 13 * it under the terms of the GNU General Public License as published by * 14 * the Free Software Foundation; either version 2 of the License, or * 15 * (at your option) any later version. * 16 * * 17 * This code is distributed in the hope that it will be useful, but * 18 * WITHOUT ANY WARRANTY; without even the implied warranty of * 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 20 * General Public License for more details. * 21 * * 22 * A copy of the GNU General Public License is available on the World * 23 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also * 24 * obtain it by writing to the Free Software Foundation, * 25 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * 26 * * 27 *************************************************************************** 28} 29 30{ 31@author(Config Path Functions - Curtis White <cwhite@aracnet.com>) 32@created(18-Apr-2000) 33@lastmod(18-Apr-2000) 34 35This unit contains functions to manage OS specific configuration path 36information from within Lazarus. 37} 38unit LazConf; 39 40{$mode objfpc}{$H+} 41 42interface 43 44{$ifdef Trace} 45 {$ASSERTIONS ON} 46{$endif} 47 48uses 49 SysUtils, Classes, 50 // LazUtils 51 FileUtil, LazFileUtils, LazUTF8, LazLoggerBase, 52 // Codetools 53 DefineTemplates; 54 55const 56 LazarusVersionStr = {$I version.inc}; 57 58function CompareLazarusVersion(V1, V2: string): integer; 59 60{ Config Path Functions } 61 62{ The primary config path is the local or user specific path. 63 If the primary config path does not exist, it will automatically be 64 created by the IDE. 65 The secondary config path is for templates. The IDE will never write to it. 66 If a config file is not found in the primary config file, Lazarus will 67 copy the template file from the secondary config file. If there is no 68 template file, the IDE will use defaults. 69} 70function GetPrimaryConfigPath: String; 71function GetSecondaryConfigPath: String; 72function CreatePrimaryConfigPath: boolean; 73procedure SetPrimaryConfigPath(const NewValue: String); 74procedure SetSecondaryConfigPath(const NewValue: String); 75procedure CopySecondaryConfigFile(const ShortFilename: String); 76function GetProjectSessionsConfigPath: String; 77 78function GetDefaultTestBuildDirectory: string; 79procedure GetDefaultTestBuildDirs(List: TStrings); 80// create a pascal file, which can be used to test the compiler 81function CreateCompilerTestPascalFilename: string; 82 83function FindDefaultExecutablePath(const Executable: string): string; 84procedure GetDefaultCompilerFilenames(List: TStrings); // list of standard paths of compiler on various distributions 85function FindDefaultCompilerPath: string; // full path of GetDefaultCompilerFilename 86function FindDefaultMakePath: string; // full path of "make" 87procedure GetDefaultMakeFilenames(List: TStrings); // list of standard paths of "make" on various distributions 88function GetDefaultFPCSrcDirectories: TStringList; 89function GetDefaultLazarusSrcDirectories: TStringList; 90 91// returns the standard executable extension (e.g '.exe') 92function GetExecutableExt(TargetOS: string = ''): string; 93function MakeStandardExeFilename(TargetOS, Filename: string): string; 94// returns the standard library extension (e.g '.dll' or '.dylib') 95function GetLibraryExt(TargetOS: string = ''): string; 96// returns the standard library prefix (e.g 'lib') 97function GetLibraryPrefix(TargetOS: string = ''): string; 98function MakeStandardLibFilename(TargetOS, Filename: string): string; 99 100// returns the standard file extension for compiled units (e.g '.ppu') 101function GetDefaultCompiledUnitExt({%H-}FPCVersion, {%H-}FPCRelease: integer): string; 102 103function OSLocksExecutables: boolean; 104 105// returns the default browser 106procedure GetDefaultBrowser(var Browser, Params: string); 107 108// Replace OnGetApplicationName, so that Application.Title 109// doesn't interfere with GetAppConfigDir and related. 110function GetLazarusApplicationName: string; 111 112type 113 TLazConfMacroFunc = procedure(var s: string); 114var 115 LazConfMacroFunc: TLazConfMacroFunc = nil; 116procedure LazConfSubstituteMacros(var s: string); 117procedure AddFilenameToList(List: TStrings; const Filename: string; 118 SkipEmpty: boolean = true); 119 120const 121 ExitCodeRestartLazarus = 99; 122 123implementation 124 125{$I lazconf.inc} 126 127procedure AddFilenameToList(List: TStrings; const Filename: string; 128 SkipEmpty: boolean); 129var 130 i: Integer; 131begin 132 if SkipEmpty and (Filename='') then exit; 133 for i:=0 to List.Count-1 do 134 if CompareFilenames(List[i],Filename)=0 then exit; 135 List.Add(Filename); 136end; 137 138function GetLazarusApplicationName: string; 139begin 140 Result := 'lazarus'; 141end; 142 143procedure LazConfSubstituteMacros(var s: string); 144begin 145 if Assigned(LazConfMacroFunc) then 146 LazConfMacroFunc(s); 147end; 148 149{--------------------------------------------------------------------------- 150 function CreateCompilerTestPascalFilename: string; 151 ---------------------------------------------------------------------------} 152function CreateCompilerTestPascalFilename: string; 153 154 function CreateFile(const Filename: string): boolean; 155 var 156 fs: TFileStream; 157 begin 158 if FileExistsUTF8(Filename) then exit(true); 159 Result:=false; 160 try 161 fs:=TFileStream.Create(Filename,fmCreate); 162 fs.Free; 163 Result:=true; 164 except 165 end; 166 end; 167 168begin 169 Result:=AppendPathDelim(GetPrimaryConfigPath)+'compilertest.pas'; 170 if CreateFile(Result) then exit; 171 Result:=AppendPathDelim(ExpandFileNameUTF8(GetTempDir))+'compilertest.pas'; 172 if CreateFile(Result) then exit; 173 Debugln('unable to create temporary file ',Result); 174 Result:=''; 175end; 176 177function FindDefaultExecutablePath(const Executable: string): string; 178begin 179 if FilenameIsAbsolute(Executable) then 180 Result:=Executable 181 else 182 Result:=SearchFileInPath(Executable,'', 183 GetEnvironmentVariableUTF8('PATH'),PathSeparator, 184 sffFindProgramInPath); 185 Result:=TrimFilename(Result); 186end; 187 188function CompareLazarusVersion(V1, V2: string): integer; 189// compare decimal numbers in strings 190// For example 191// '0.9.30' < '1.0' 192// '1.0 RC1' < '1.0 RC2' 193// '1.0 RC2' < '1.0' 194// '1.0' < '1.1' 195// '1.0' < '1.0-0' 196// '1.0 RC2' < '1.0.1' 197// '1.0-2' < '1.0.0' 198 199// Rules: 'RC' < EndOfString < '-' < '.' 200 201 function ReadNumber(var p: PChar): integer; 202 begin 203 if p^=#0 then exit(-1); 204 205 if p^ in ['0'..'9'] then begin 206 Result:=0; 207 while (p^ in ['0'..'9']) do begin 208 if Result<100000 then 209 Result:=Result*10+ord(p^)-ord('0'); 210 inc(p); 211 end; 212 end else begin 213 while (p^ in [' ',#9]) do inc(p); 214 case p^ of 215 '-': Result:=1; 216 '.': Result:=2; 217 else Result:=-2; // for example 'RC' 218 end; 219 while not (p^ in [#0,'0'..'9']) do inc(p); 220 end; 221 end; 222 223var 224 p1: PChar; 225 p2: PChar; 226 Number1: Integer; 227 Number2: Integer; 228begin 229 if V1='' then begin 230 if V2='' then 231 exit(0) 232 else 233 exit(-1); 234 end else begin 235 if V2='' then 236 exit(1); 237 end; 238 p1:=PChar(V1); 239 p2:=PChar(V2); 240 while (p1^<>#0) or (p2^<>#0) do begin 241 Number1:=ReadNumber(p1); 242 Number2:=ReadNumber(p2); 243 if Number1>Number2 then exit(1); 244 if Number1<Number2 then exit(-1); 245 end; 246 Result:=0; 247end; 248 249{--------------------------------------------------------------------------- 250 getPrimaryConfigPath function 251 ---------------------------------------------------------------------------} 252function GetPrimaryConfigPath: String; 253begin 254 Result := PrimaryConfigPath; 255end; 256 257{--------------------------------------------------------------------------- 258 getSecondaryConfigPath function 259 ---------------------------------------------------------------------------} 260function GetSecondaryConfigPath: String; 261begin 262 Result := SecondaryConfigPath; 263end; 264 265{--------------------------------------------------------------------------- 266 createPrimaryConfigPath procedure 267 ---------------------------------------------------------------------------} 268function CreatePrimaryConfigPath: boolean; 269begin 270 Result:=ForceDirectoriesUTF8(GetPrimaryConfigPath); 271end; 272 273{--------------------------------------------------------------------------- 274 SetPrimaryConfigPath procedure 275 ---------------------------------------------------------------------------} 276procedure SetPrimaryConfigPath(const NewValue: String); 277var 278 NewExpValue: String; 279begin 280 NewExpValue:=ChompPathDelim(ExpandFileNameUTF8(NewValue)); 281 if NewExpValue=PrimaryConfigPath then exit; 282 debugln('SetPrimaryConfigPath NewValue="',UTF8ToConsole(NewValue),'" -> "',UTF8ToConsole(NewExpValue),'"'); 283 PrimaryConfigPath := NewExpValue; 284end; 285 286{--------------------------------------------------------------------------- 287 SetSecondaryConfigPath procedure 288 ---------------------------------------------------------------------------} 289procedure SetSecondaryConfigPath(const NewValue: String); 290begin 291 debugln('SetSecondaryConfigPath NewValue="',UTF8ToConsole(NewValue),'" -> "',UTF8ToConsole(ExpandFileNameUTF8(NewValue)),'"'); 292 SecondaryConfigPath := ChompPathDelim(ExpandFileNameUTF8(NewValue)); 293end; 294 295{--------------------------------------------------------------------------- 296 CopySecondaryConfigFile procedure 297 ---------------------------------------------------------------------------} 298procedure CopySecondaryConfigFile(const ShortFilename: String); 299var 300 PrimaryFilename, SecondaryFilename: string; 301begin 302 if ShortFilename='' then exit; 303 PrimaryFilename:=AppendPathDelim(GetPrimaryConfigPath)+ShortFilename; 304 SecondaryFilename:=AppendPathDelim(GetSecondaryConfigPath)+ShortFilename; 305 if (not FileExistsUTF8(PrimaryFilename)) 306 and (FileExistsUTF8(SecondaryFilename)) then begin 307 debugln(['CopySecondaryConfigFile ',SecondaryFilename,' -> ',PrimaryFilename]); 308 if not CreatePrimaryConfigPath then begin 309 debugln(['WARNING: unable to create primary config directory "',GetPrimaryConfigPath,'"']); 310 exit; 311 end; 312 if not CopyFile(SecondaryFilename,PrimaryFilename) then begin 313 debugln(['WARNING: unable to copy config "',SecondaryFilename,'" to "',PrimaryFilename,'"']); 314 exit; 315 end; 316 InvalidateFileStateCache; // we have to invalidate cache in order FileExistsCached finds the new primary config file 317 end; 318end; 319 320function GetProjectSessionsConfigPath: String; 321begin 322 Result:=AppendPathDelim(GetPrimaryConfigPath)+'projectsessions'; 323end; 324 325function GetExecutableExt(TargetOS: string): string; 326begin 327 if TargetOS='' then 328 TargetOS:=GetCompiledTargetOS; 329 if (CompareText(copy(TargetOS,1,3), 'win') = 0) 330 or (CompareText(copy(TargetOS,1,3), 'dos') = 0) then 331 Result:='.exe' 332 else if SameText(TargetOS, 'browser') or SameText(TargetOS,'nodejs') then 333 Result:='.js' 334 else if SameText(TargetOS, 'embedded') then 335 Result:='.elf' 336 else 337 Result:=''; 338end; 339 340function MakeStandardExeFilename(TargetOS, Filename: string): string; 341var 342 StdExt: String; 343begin 344 Result:=Filename; 345 if TargetOS='' then 346 TargetOS:=GetCompiledTargetOS; 347 StdExt:=GetExecutableExt(TargetOS); 348 if StdExt='' then exit; 349 Result:=ChangeFileExt(Result,StdExt); 350end; 351 352function GetLibraryExt(TargetOS: string): string; 353begin 354 if TargetOS='' then 355 TargetOS:=GetCompiledTargetOS; 356 if CompareText(copy(TargetOS,1,3), 'win') = 0 then 357 Result:='.dll' 358 else if CompareText(TargetOS, 'darwin') = 0 then 359 Result:='.dylib' 360 else if CompareText(TargetOS, 'ios') = 0 then 361 Result:='.dylib' 362 else if (CompareText(TargetOS, 'linux') = 0) 363 or (CompareText(TargetOS, 'android') = 0) 364 or (CompareText(TargetOS, 'freebsd') = 0) 365 or (CompareText(TargetOS, 'openbsd') = 0) 366 or (CompareText(TargetOS, 'netbsd') = 0) 367 or (CompareText(TargetOS, 'dragonfly') = 0) 368 or (CompareText(TargetOS, 'haiku') = 0) then 369 Result:='.so' 370 else 371 Result:=''; 372end; 373 374function GetLibraryPrefix(TargetOS: string): string; 375var 376 SrcOS: String; 377begin 378 if TargetOS='' then 379 TargetOS:=GetCompiledTargetOS; 380 Result:=''; 381 if SameText(TargetOS, 'browser') or SameText(TargetOS,'nodejs') then 382 exit('.js'); 383 SrcOS:=GetDefaultSrcOSForTargetOS(TargetOS); 384 if CompareText(SrcOS, 'unix') = 0 then 385 Result:='lib'; 386end; 387 388function MakeStandardLibFilename(TargetOS, Filename: string): string; 389var 390 StdExt: String; 391 StdPrefix: String; 392begin 393 Result:=Filename; 394 if TargetOS='' then 395 TargetOS:=GetCompiledTargetOS; 396 // change extension 397 StdExt:=GetLibraryExt(TargetOS); 398 if StdExt<>'' then 399 Result:=ChangeFileExt(Result,StdExt); 400 // change prefix 401 StdPrefix:=GetLibraryPrefix(TargetOS); 402 if StdPrefix<>'' then 403 Result:=ExtractFilePath(Result)+StdPrefix+ExtractFileName(Result); 404 // lowercase 405 if (CompareText(TargetOS,'linux')=0) 406 or (CompareText(TargetOS,'freebsd')=0) 407 or (CompareText(TargetOS,'netbsd')=0) 408 or (CompareText(TargetOS,'openbsd')=0) 409 or (CompareText(TargetOS,'dragonfly')=0) 410 then 411 Result:=ExtractFilePath(Result)+lowercase(ExtractFileName(Result)); 412end; 413 414function GetDefaultLazarusSrcDirectories: TStringList; 415var 416 i: Integer; 417begin 418 Result:=TStringList.Create; 419 for i:=low(DefaultLazarusSrcDirs) to high(DefaultLazarusSrcDirs) do 420 Result.Add(DefaultLazarusSrcDirs[i]); 421end; 422 423function GetDefaultFPCSrcDirectories: TStringList; 424var 425 i: Integer; 426begin 427 Result:=TStringList.Create; 428 for i:=low(DefaultFPCSrcDirs) to high(DefaultFPCSrcDirs) do 429 Result.Add(DefaultFPCSrcDirs[i]); 430end; 431 432initialization 433 Randomize; 434 InternalInit; 435 436end. 437 438 439