sysutils.pp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Sysutils unit for linux
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sysutils;
  13. interface
  14. {$MODE objfpc}
  15. {$MODESWITCH OUT}
  16. { force ansistrings }
  17. {$H+}
  18. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  19. {$define USE_VFORK}
  20. {$endif}
  21. {$DEFINE OS_FILESETDATEBYNAME}
  22. {$DEFINE HAS_SLEEP}
  23. {$DEFINE HAS_OSERROR}
  24. {$DEFINE HAS_OSCONFIG}
  25. {$DEFINE HAS_TEMPDIR}
  26. {$DEFINE HASUNIX}
  27. {$DEFINE HASCREATEGUID}
  28. {$DEFINE HAS_OSUSERDIR}
  29. {$DEFINE HAS_LOCALTIMEZONEOFFSET}
  30. {$DEFINE HAS_GETTICKCOUNT64}
  31. { used OS file system APIs use ansistring }
  32. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  33. { OS has an ansistring/single byte environment variable API }
  34. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  35. uses
  36. Unix,errors,sysconst,Unixtype;
  37. { Include platform independent interface part }
  38. {$i sysutilh.inc}
  39. Function AddDisk(const path:string) : Byte;
  40. { the following is Kylix compatibility stuff, it should be moved to a
  41. special compatibilty unit (FK) }
  42. const
  43. RTL_SIGINT = 0;
  44. RTL_SIGFPE = 1;
  45. RTL_SIGSEGV = 2;
  46. RTL_SIGILL = 3;
  47. RTL_SIGBUS = 4;
  48. RTL_SIGQUIT = 5;
  49. RTL_SIGLAST = RTL_SIGQUIT;
  50. RTL_SIGDEFAULT = -1;
  51. type
  52. TSignalState = (ssNotHooked, ssHooked, ssOverridden);
  53. function InquireSignal(RtlSigNum: Integer): TSignalState;
  54. procedure AbandonSignalHandler(RtlSigNum: Integer);
  55. procedure HookSignal(RtlSigNum: Integer);
  56. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  57. implementation
  58. Uses
  59. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
  60. type
  61. tsiginfo = record
  62. oldsiginfo: sigactionrec;
  63. hooked: boolean;
  64. end;
  65. const
  66. rtlsig2ossig: array[RTL_SIGINT..RTL_SIGLAST] of byte =
  67. (SIGINT,SIGFPE,SIGSEGV,SIGILL,SIGBUS,SIGQUIT);
  68. { to avoid linking in all this stuff in every program,
  69. as it's unlikely to be used by anything but libraries
  70. }
  71. signalinfoinited: boolean = false;
  72. var
  73. siginfo: array[RTL_SIGINT..RTL_SIGLAST] of tsiginfo;
  74. oldsigfpe: SigActionRec; external name '_FPC_OLDSIGFPE';
  75. oldsigsegv: SigActionRec; external name '_FPC_OLDSIGSEGV';
  76. oldsigbus: SigActionRec; external name '_FPC_OLDSIGBUS';
  77. oldsigill: SigActionRec; external name '_FPC_OLDSIGILL';
  78. procedure defaultsighandler; external name '_FPC_DEFAULTSIGHANDLER';
  79. procedure installdefaultsignalhandler(signum: Integer; out oldact: SigActionRec); external name '_FPC_INSTALLDEFAULTSIGHANDLER';
  80. function InternalInquireSignal(RtlSigNum: Integer; out act: SigActionRec; frominit: boolean): TSignalState;
  81. begin
  82. result:=ssNotHooked;
  83. if (RtlSigNum<>RTL_SIGDEFAULT) and
  84. (RtlSigNum<RTL_SIGLAST) then
  85. begin
  86. if (frominit or
  87. siginfo[RtlSigNum].hooked) and
  88. (fpsigaction(rtlsig2ossig[RtlSigNum],nil,@act)=0) then
  89. begin
  90. if not frominit then
  91. begin
  92. { check whether the installed signal handler is still ours }
  93. {$if not defined(aix) and (not defined(linux) or not defined(cpupowerpc64))}
  94. if (pointer(act.sa_handler)=pointer(@defaultsighandler)) then
  95. {$else}
  96. { on aix and linux/ppc64, procedure addresses are actually
  97. descriptors -> check whether the code addresses inside the
  98. descriptors match, rather than the descriptors themselves }
  99. if (ppointer(act.sa_handler)^=ppointer(@defaultsighandler)^) then
  100. {$endif}
  101. result:=ssHooked
  102. else
  103. result:=ssOverridden;
  104. end
  105. else if IsLibrary then
  106. begin
  107. { library -> signals have not been hooked by system init code }
  108. exit
  109. end
  110. else
  111. begin
  112. { program -> signals have been hooked by system init code }
  113. if (byte(RtlSigNum) in [RTL_SIGFPE,RTL_SIGSEGV,RTL_SIGILL,RTL_SIGBUS]) then
  114. begin
  115. {$if not defined(aix) and (not defined(linux) or not defined(cpupowerpc64))}
  116. if (pointer(act.sa_handler)=pointer(@defaultsighandler)) then
  117. {$else}
  118. if (ppointer(act.sa_handler)^=ppointer(@defaultsighandler)^) then
  119. {$endif}
  120. result:=ssHooked
  121. else
  122. result:=ssOverridden;
  123. { return the original handlers as saved by the system unit
  124. (the current call to sigaction simply returned our
  125. system unit's installed handlers)
  126. }
  127. case RtlSigNum of
  128. RTL_SIGFPE:
  129. act:=oldsigfpe;
  130. RTL_SIGSEGV:
  131. act:=oldsigsegv;
  132. RTL_SIGILL:
  133. act:=oldsigill;
  134. RTL_SIGBUS:
  135. act:=oldsigbus;
  136. end;
  137. end
  138. else
  139. begin
  140. { these are not hooked in the startup code }
  141. result:=ssNotHooked;
  142. end
  143. end
  144. end
  145. end;
  146. end;
  147. procedure initsignalinfo;
  148. var
  149. i: Integer;
  150. begin
  151. for i:=RTL_SIGINT to RTL_SIGLAST do
  152. siginfo[i].hooked:=(InternalInquireSignal(i,siginfo[i].oldsiginfo,true)=ssHooked);
  153. signalinfoinited:=true;
  154. end;
  155. function InquireSignal(RtlSigNum: Integer): TSignalState;
  156. var
  157. act: SigActionRec;
  158. begin
  159. if not signalinfoinited then
  160. initsignalinfo;
  161. result:=InternalInquireSignal(RtlSigNum,act,false);
  162. end;
  163. procedure AbandonSignalHandler(RtlSigNum: Integer);
  164. begin
  165. if not signalinfoinited then
  166. initsignalinfo;
  167. if (RtlSigNum<>RTL_SIGDEFAULT) and
  168. (RtlSigNum<RTL_SIGLAST) then
  169. siginfo[RtlSigNum].hooked:=false;
  170. end;
  171. procedure HookSignal(RtlSigNum: Integer);
  172. var
  173. lowsig, highsig, i: Integer;
  174. begin
  175. if not signalinfoinited then
  176. initsignalinfo;
  177. if (RtlSigNum<>RTL_SIGDEFAULT) then
  178. begin
  179. lowsig:=RtlSigNum;
  180. highsig:=RtlSigNum;
  181. end
  182. else
  183. begin
  184. { we don't hook SIGINT and SIGQUIT by default }
  185. lowsig:=RTL_SIGFPE;
  186. highsig:=RTL_SIGBUS;
  187. end;
  188. { install the default rtl signal handler for the selected signal(s) }
  189. for i:=lowsig to highsig do
  190. begin
  191. installdefaultsignalhandler(rtlsig2ossig[i],siginfo[i].oldsiginfo);
  192. siginfo[i].hooked:=true;
  193. end;
  194. end;
  195. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  196. var
  197. act: SigActionRec;
  198. lowsig, highsig, i: Integer;
  199. state: TSignalState;
  200. begin
  201. if not signalinfoinited then
  202. initsignalinfo;
  203. if (RtlSigNum<>RTL_SIGDEFAULT) then
  204. begin
  205. lowsig:=RtlSigNum;
  206. highsig:=RtlSigNum;
  207. end
  208. else
  209. begin
  210. { we don't hook SIGINT and SIGQUIT by default }
  211. lowsig:=RTL_SIGFPE;
  212. highsig:=RTL_SIGBUS;
  213. end;
  214. for i:=lowsig to highsig do
  215. begin
  216. if not OnlyIfHooked or
  217. (InquireSignal(i)=ssHooked) then
  218. begin
  219. { restore the handler that was present when we hooked the signal,
  220. if we hooked it at one time or another. If the user doesn't
  221. want this, they have to call AbandonSignalHandler() first
  222. }
  223. if siginfo[i].hooked then
  224. act:=siginfo[i].oldsiginfo
  225. else
  226. begin
  227. fillchar(act,sizeof(act),0);
  228. pointer(act.sa_handler):=pointer(SIG_DFL);
  229. end;
  230. if (fpsigaction(rtlsig2ossig[RtlSigNum],@act,nil)=0) then
  231. siginfo[i].hooked:=false;
  232. end;
  233. end;
  234. end;
  235. {$Define OS_FILEISREADONLY} // Specific implementation for Unix.
  236. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  237. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  238. { Include platform independent implementation part }
  239. {$i sysutils.inc}
  240. { Include SysCreateGUID function }
  241. {$i suuid.inc}
  242. Const
  243. {Date Translation}
  244. C1970=2440588;
  245. D0 = 1461;
  246. D1 = 146097;
  247. D2 =1721119;
  248. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  249. Var
  250. YYear,XYear,Temp,TempMonth : LongInt;
  251. Begin
  252. Temp:=((JulianDN-D2) shl 2)-1;
  253. JulianDN:=Temp Div D1;
  254. XYear:=(Temp Mod D1) or 3;
  255. YYear:=(XYear Div D0);
  256. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  257. Day:=((Temp Mod 153)+5) Div 5;
  258. TempMonth:=Temp Div 153;
  259. If TempMonth>=10 Then
  260. Begin
  261. inc(YYear);
  262. dec(TempMonth,12);
  263. End;
  264. inc(TempMonth,3);
  265. Month := TempMonth;
  266. Year:=YYear+(JulianDN*100);
  267. end;
  268. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  269. {
  270. Transforms Epoch time into local time (hour, minute,seconds)
  271. }
  272. Var
  273. DateNum: LongInt;
  274. Begin
  275. inc(Epoch,TZSeconds);
  276. Datenum:=(Epoch Div 86400) + c1970;
  277. JulianToGregorian(DateNum,Year,Month,day);
  278. Epoch:=Abs(Epoch Mod 86400);
  279. Hour:=Epoch Div 3600;
  280. Epoch:=Epoch Mod 3600;
  281. Minute:=Epoch Div 60;
  282. Second:=Epoch Mod 60;
  283. End;
  284. function GetTickCount64: QWord;
  285. var
  286. tp: TTimeVal;
  287. begin
  288. fpgettimeofday(@tp, nil);
  289. Result := (Int64(tp.tv_sec) * 1000) + (tp.tv_usec div 1000);
  290. end;
  291. {****************************************************************************
  292. File Functions
  293. ****************************************************************************}
  294. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  295. Var
  296. DotPos,SlashPos,i : longint;
  297. Begin
  298. SlashPos:=0;
  299. DotPos:=256;
  300. i:=Length(Path);
  301. While (i>0) and (SlashPos=0) Do
  302. Begin
  303. If (DotPos=256) and (Path[i]='.') Then
  304. begin
  305. DotPos:=i;
  306. end;
  307. If (Path[i]='/') Then
  308. SlashPos:=i;
  309. Dec(i);
  310. End;
  311. Ext:=Copy(Path,DotPos,255);
  312. Dir:=Copy(Path,1,SlashPos);
  313. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  314. End;
  315. Function DoFileLocking(Handle: Longint; Mode: Integer) : Longint;
  316. var
  317. lockop: cint;
  318. lockres: cint;
  319. closeres: cint;
  320. lockerr: cint;
  321. begin
  322. DoFileLocking:=Handle;
  323. {$ifdef beos}
  324. {$else}
  325. if (Handle>=0) then
  326. begin
  327. {$if defined(solaris) or defined(aix)}
  328. { Solaris' & AIX' flock is based on top of fcntl, which does not allow
  329. exclusive locks for files only opened for reading nor shared locks
  330. for files opened only for writing.
  331. If no locking is specified, we normally need an exclusive lock.
  332. So create an exclusive lock for fmOpenWrite and fmOpenReadWrite,
  333. but only a shared lock for fmOpenRead (since an exclusive lock
  334. is not possible in that case)
  335. }
  336. if ((mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) = 0) then
  337. begin
  338. if ((mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) = fmOpenRead) then
  339. mode := mode or fmShareDenyWrite
  340. else
  341. mode := mode or fmShareExclusive;
  342. end;
  343. {$endif solaris}
  344. case (mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) of
  345. fmShareCompat,
  346. fmShareExclusive:
  347. lockop:=LOCK_EX or LOCK_NB;
  348. fmShareDenyWrite:
  349. lockop:=LOCK_SH or LOCK_NB;
  350. fmShareDenyNone:
  351. exit;
  352. else
  353. begin
  354. { fmShareDenyRead does not exit under *nix, only shared access
  355. (similar to fmShareDenyWrite) and exclusive access (same as
  356. fmShareExclusive)
  357. }
  358. repeat
  359. closeres:=FpClose(Handle);
  360. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  361. DoFileLocking:=-1;
  362. exit;
  363. end;
  364. end;
  365. repeat
  366. lockres:=fpflock(Handle,lockop);
  367. until (lockres=0) or
  368. (fpgeterrno<>ESysEIntr);
  369. lockerr:=fpgeterrno;
  370. { Only return an error if locks are working and the file was already
  371. locked. Not if locks are simply unsupported (e.g., on Angstrom Linux
  372. you always get ESysNOLCK in the default configuration) }
  373. if (lockres<>0) and
  374. ((lockerr=ESysEAGAIN) or
  375. (lockerr=EsysEDEADLK)) then
  376. begin
  377. repeat
  378. closeres:=FpClose(Handle);
  379. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  380. DoFileLocking:=-1;
  381. exit;
  382. end;
  383. end;
  384. {$endif not beos}
  385. end;
  386. Function FileOpen (Const FileName : RawbyteString; Mode : Integer) : Longint;
  387. Var
  388. SystemFileName: RawByteString;
  389. LinuxFlags : longint;
  390. begin
  391. LinuxFlags:=0;
  392. case (Mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) of
  393. fmOpenRead : LinuxFlags:=LinuxFlags or O_RdOnly;
  394. fmOpenWrite : LinuxFlags:=LinuxFlags or O_WrOnly;
  395. fmOpenReadWrite : LinuxFlags:=LinuxFlags or O_RdWr;
  396. end;
  397. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  398. repeat
  399. FileOpen:=fpOpen (pointer(SystemFileName),LinuxFlags);
  400. until (FileOpen<>-1) or (fpgeterrno<>ESysEINTR);
  401. FileOpen:=DoFileLocking(FileOpen, Mode);
  402. end;
  403. Function FileCreate (Const FileName : RawByteString) : Longint;
  404. Var
  405. SystemFileName: RawByteString;
  406. begin
  407. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  408. repeat
  409. FileCreate:=fpOpen(pointer(SystemFileName),O_RdWr or O_Creat or O_Trunc);
  410. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  411. end;
  412. Function FileCreate (Const FileName : RawByteString;Rights : Longint) : Longint;
  413. Var
  414. SystemFileName: RawByteString;
  415. begin
  416. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  417. repeat
  418. FileCreate:=fpOpen(pointer(SystemFileName),O_RdWr or O_Creat or O_Trunc,Rights);
  419. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  420. end;
  421. Function FileCreate (Const FileName : RawByteString; ShareMode : Longint; Rights:LongInt ) : Longint;
  422. begin
  423. Result:=FileCreate( FileName, Rights );
  424. Result:=DoFileLocking(Result,ShareMode);
  425. end;
  426. Function FileRead (Handle : Longint; out Buffer; Count : longint) : Longint;
  427. begin
  428. repeat
  429. FileRead:=fpRead (Handle,Buffer,Count);
  430. until (FileRead<>-1) or (fpgeterrno<>ESysEINTR);
  431. end;
  432. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  433. begin
  434. repeat
  435. FileWrite:=fpWrite (Handle,Buffer,Count);
  436. until (FileWrite<>-1) or (fpgeterrno<>ESysEINTR);
  437. end;
  438. Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
  439. begin
  440. result:=longint(FileSeek(Handle,int64(FOffset),Origin));
  441. end;
  442. Function FileSeek (Handle : Longint; FOffset : Int64; Origin : Longint) : Int64;
  443. begin
  444. FileSeek:=fplSeek (Handle,FOffset,Origin);
  445. end;
  446. Procedure FileClose (Handle : Longint);
  447. var
  448. res: cint;
  449. begin
  450. repeat
  451. res:=fpclose(Handle);
  452. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  453. end;
  454. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  455. var
  456. res: cint;
  457. begin
  458. if (SizeOf (TOff) < 8) (* fpFTruncate only supporting signed 32-bit size *)
  459. and (Size > high (longint)) then
  460. FileTruncate := false
  461. else
  462. begin
  463. repeat
  464. res:=fpftruncate(Handle,Size);
  465. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  466. FileTruncate:=res>=0;
  467. end;
  468. end;
  469. Function FileAge (Const FileName : String): Longint;
  470. Var Info : Stat;
  471. begin
  472. If (fpstat (pointer(FileName),Info)<0) or fpS_ISDIR(info.st_mode) then
  473. exit(-1)
  474. else
  475. Result:=info.st_mtime;
  476. end;
  477. Function FileExists (Const FileName : RawByteString) : Boolean;
  478. var
  479. SystemFileName: RawByteString;
  480. begin
  481. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  482. // Don't use stat. It fails on files >2 GB.
  483. // Access obeys the same access rules, so the result should be the same.
  484. FileExists:=fpAccess(pointer(SystemFileName),F_OK)=0;
  485. end;
  486. Function DirectoryExists (Const Directory : RawByteString) : Boolean;
  487. Var
  488. Info : Stat;
  489. SystemFileName: RawByteString;
  490. begin
  491. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Directory);
  492. DirectoryExists:=(fpstat(pointer(SystemFileName),Info)>=0) and fpS_ISDIR(Info.st_mode);
  493. end;
  494. Function LinuxToWinAttr (const FN : RawByteString; Const Info : Stat) : Longint;
  495. Var
  496. LinkInfo : Stat;
  497. nm : RawByteString;
  498. begin
  499. Result:=faArchive;
  500. If fpS_ISDIR(Info.st_mode) then
  501. Result:=Result or faDirectory;
  502. nm:=ExtractFileName(FN);
  503. If (Length(nm)>=2) and
  504. (nm[1]='.') and
  505. (nm[2]<>'.') then
  506. Result:=Result or faHidden;
  507. If (Info.st_Mode and S_IWUSR)=0 Then
  508. Result:=Result or faReadOnly;
  509. If fpS_ISSOCK(Info.st_mode) or fpS_ISBLK(Info.st_mode) or fpS_ISCHR(Info.st_mode) or fpS_ISFIFO(Info.st_mode) Then
  510. Result:=Result or faSysFile;
  511. If fpS_ISLNK(Info.st_mode) Then
  512. begin
  513. Result:=Result or faSymLink;
  514. // Windows reports if the link points to a directory.
  515. if (fpstat(pchar(FN),LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then
  516. Result := Result or faDirectory;
  517. end;
  518. end;
  519. Function FNMatch(const Pattern,Name:string):Boolean;
  520. Var
  521. LenPat,LenName : longint;
  522. Function DoFNMatch(i,j:longint):Boolean;
  523. Var
  524. Found : boolean;
  525. Begin
  526. Found:=true;
  527. While Found and (i<=LenPat) Do
  528. Begin
  529. Case Pattern[i] of
  530. '?' : Found:=(j<=LenName);
  531. '*' : Begin
  532. {find the next character in pattern, different of ? and *}
  533. while Found do
  534. begin
  535. inc(i);
  536. if i>LenPat then Break;
  537. case Pattern[i] of
  538. '*' : ;
  539. '?' : begin
  540. if j>LenName then begin DoFNMatch:=false; Exit; end;
  541. inc(j);
  542. end;
  543. else
  544. Found:=false;
  545. end;
  546. end;
  547. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  548. {Now, find in name the character which i points to, if the * or ?
  549. wasn't the last character in the pattern, else, use up all the
  550. chars in name}
  551. Found:=false;
  552. if (i<=LenPat) then
  553. begin
  554. repeat
  555. {find a letter (not only first !) which maches pattern[i]}
  556. while (j<=LenName) and (name[j]<>pattern[i]) do
  557. inc (j);
  558. if (j<LenName) then
  559. begin
  560. if DoFnMatch(i+1,j+1) then
  561. begin
  562. i:=LenPat;
  563. j:=LenName;{we can stop}
  564. Found:=true;
  565. Break;
  566. end else
  567. inc(j);{We didn't find one, need to look further}
  568. end else
  569. if j=LenName then
  570. begin
  571. Found:=true;
  572. Break;
  573. end;
  574. { This 'until' condition must be j>LenName, not j>=LenName.
  575. That's because when we 'need to look further' and
  576. j = LenName then loop must not terminate. }
  577. until (j>LenName);
  578. end else
  579. begin
  580. j:=LenName;{we can stop}
  581. Found:=true;
  582. end;
  583. end;
  584. else {not a wildcard character in pattern}
  585. Found:=(j<=LenName) and (pattern[i]=name[j]);
  586. end;
  587. inc(i);
  588. inc(j);
  589. end;
  590. DoFnMatch:=Found and (j>LenName);
  591. end;
  592. Begin {start FNMatch}
  593. LenPat:=Length(Pattern);
  594. LenName:=Length(Name);
  595. FNMatch:=DoFNMatch(1,1);
  596. End;
  597. Type
  598. TUnixFindData = Record
  599. NamePos : LongInt; {to track which search this is}
  600. DirPtr : Pointer; {directory pointer for reading directory}
  601. SearchSpec : String;
  602. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  603. SearchAttr : Byte; {attribute we are searching for}
  604. End;
  605. PUnixFindData = ^TUnixFindData;
  606. Procedure FindClose(Var f: TSearchRec);
  607. var
  608. UnixFindData : PUnixFindData;
  609. Begin
  610. UnixFindData:=PUnixFindData(f.FindHandle);
  611. If (UnixFindData=Nil) then
  612. Exit;
  613. if UnixFindData^.SearchType=0 then
  614. begin
  615. if UnixFindData^.dirptr<>nil then
  616. fpclosedir(pdir(UnixFindData^.dirptr)^);
  617. end;
  618. Dispose(UnixFindData);
  619. f.FindHandle:=nil;
  620. End;
  621. Function FindGetFileInfo(const s:string;var f:TSearchRec):boolean;
  622. var
  623. st : baseunix.stat;
  624. WinAttr : longint;
  625. begin
  626. FindGetFileInfo:=false;
  627. If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  628. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  629. else
  630. FindGetFileInfo:=(fpstat(pointer(s),st)=0);
  631. If not FindGetFileInfo then
  632. exit;
  633. WinAttr:=LinuxToWinAttr(s,st);
  634. If ((WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0) Then
  635. Begin
  636. f.Name:=ExtractFileName(s);
  637. f.Attr:=WinAttr;
  638. f.Size:=st.st_Size;
  639. f.Mode:=st.st_mode;
  640. f.Time:=st.st_mtime;
  641. FindGetFileInfo:=true;
  642. End
  643. else
  644. FindGetFileInfo:=false;
  645. end;
  646. Function FindNext (Var Rslt : TSearchRec) : Longint;
  647. {
  648. re-opens dir if not already in array and calls FindGetFileInfo
  649. }
  650. Var
  651. DirName : String;
  652. FName,
  653. SName : string;
  654. Found,
  655. Finished : boolean;
  656. p : pdirent;
  657. UnixFindData : PUnixFindData;
  658. Begin
  659. Result:=-1;
  660. UnixFindData:=PUnixFindData(Rslt.FindHandle);
  661. { SearchSpec='' means that there were no wild cards, so only one file to
  662. find.
  663. }
  664. If (UnixFindData=Nil) then
  665. exit;
  666. if UnixFindData^.SearchSpec='' then
  667. exit;
  668. if (UnixFindData^.SearchType=0) and
  669. (UnixFindData^.Dirptr=nil) then
  670. begin
  671. If UnixFindData^.NamePos = 0 Then
  672. DirName:='./'
  673. Else
  674. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  675. UnixFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  676. end;
  677. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  678. Found:=False;
  679. Finished:=(UnixFindData^.dirptr=nil);
  680. While Not Finished Do
  681. Begin
  682. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  683. if p=nil then
  684. FName:=''
  685. else
  686. FName:=p^.d_name;
  687. If FName='' Then
  688. Finished:=True
  689. Else
  690. Begin
  691. If FNMatch(SName,FName) Then
  692. Begin
  693. Found:=FindGetFileInfo(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Rslt);
  694. if Found then
  695. begin
  696. Result:=0;
  697. exit;
  698. end;
  699. End;
  700. End;
  701. End;
  702. End;
  703. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  704. {
  705. opens dir and calls FindNext if needed.
  706. }
  707. var
  708. UnixFindData : PUnixFindData;
  709. Begin
  710. Result:=-1;
  711. fillchar(Rslt,sizeof(Rslt),0);
  712. if Path='' then
  713. exit;
  714. { Allocate UnixFindData (we always need it, for the search attributes) }
  715. New(UnixFindData);
  716. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  717. Rslt.FindHandle:=UnixFindData;
  718. {We always also search for readonly and archive, regardless of Attr:}
  719. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  720. {Wildcards?}
  721. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  722. begin
  723. if FindGetFileInfo(Path,Rslt) then
  724. Result:=0;
  725. end
  726. else
  727. begin
  728. {Create Info}
  729. UnixFindData^.SearchSpec := Path;
  730. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  731. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  732. dec(UnixFindData^.NamePos);
  733. Result:=FindNext(Rslt);
  734. end;
  735. If (Result<>0) then
  736. FindClose(Rslt);
  737. End;
  738. Function FileGetDate (Handle : Longint) : Longint;
  739. Var Info : Stat;
  740. begin
  741. If (fpFStat(Handle,Info))<0 then
  742. Result:=-1
  743. else
  744. Result:=Info.st_Mtime;
  745. end;
  746. Function FileSetDate (Handle,Age : Longint) : Longint;
  747. begin
  748. // Impossible under Linux from FileHandle !!
  749. FileSetDate:=-1;
  750. end;
  751. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  752. Var
  753. SystemFileName: RawByteString;
  754. Info : Stat;
  755. res : Integer;
  756. begin
  757. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  758. res:=FpLStat(pointer(SystemFileName),Info);
  759. if res<0 then
  760. res:=FpStat(pointer(SystemFileName),Info);
  761. if res<0 then
  762. Result:=-1
  763. Else
  764. Result:=LinuxToWinAttr(SystemFileName,Info);
  765. end;
  766. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  767. begin
  768. Result:=-1;
  769. end;
  770. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  771. var
  772. SystemFileName: RawByteString;
  773. begin
  774. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  775. Result:=fpUnLink (pchar(SystemFileName))>=0;
  776. end;
  777. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  778. var
  779. SystemOldName, SystemNewName: RawByteString;
  780. begin
  781. SystemOldName:=ToSingleByteFileSystemEncodedFileName(OldName);
  782. SystemNewName:=ToSingleByteFileSystemEncodedFileName(NewName);
  783. RenameFile:=BaseUnix.FpRename(pointer(SystemOldNAme),pointer(SystemNewName))>=0;
  784. end;
  785. Function FileIsReadOnly(const FileName: RawByteString): Boolean;
  786. var
  787. SystemFileName: RawByteString;
  788. begin
  789. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  790. Result:=fpAccess(PChar(SystemFileName),W_OK)<>0;
  791. end;
  792. Function FileSetDate (Const FileName : RawByteString; Age : Longint) : Longint;
  793. var
  794. SystemFileName: RawByteString;
  795. t: TUTimBuf;
  796. begin
  797. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  798. Result:=0;
  799. t.actime:= Age;
  800. t.modtime:=Age;
  801. if fputime(PChar(SystemFileName), @t) = -1 then
  802. Result:=fpgeterrno;
  803. end;
  804. {****************************************************************************
  805. Disk Functions
  806. ****************************************************************************}
  807. {
  808. The Diskfree and Disksize functions need a file on the specified drive, since this
  809. is required for the fpstatfs system call.
  810. These filenames are set in drivestr[0..26], and have been preset to :
  811. 0 - '.' (default drive - hence current dir is ok.)
  812. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  813. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  814. 3 - '/' (C: equivalent of dos is the root partition)
  815. 4..26 (can be set by you're own applications)
  816. ! Use AddDisk() to Add new drives !
  817. They both return -1 when a failure occurs.
  818. }
  819. Const
  820. FixDriveStr : array[0..3] of pchar=(
  821. '.',
  822. '/fd0/.',
  823. '/fd1/.',
  824. '/.'
  825. );
  826. var
  827. Drives : byte = 4;
  828. DriveStr : array[4..26] of pchar;
  829. Function AddDisk(const path:string) : Byte;
  830. begin
  831. if not (DriveStr[Drives]=nil) then
  832. FreeMem(DriveStr[Drives]);
  833. GetMem(DriveStr[Drives],length(Path)+1);
  834. StrPCopy(DriveStr[Drives],path);
  835. Result:=Drives;
  836. inc(Drives);
  837. if Drives>26 then
  838. Drives:=4;
  839. end;
  840. Function DiskFree(Drive: Byte): int64;
  841. var
  842. fs : tstatfs;
  843. Begin
  844. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (fpstatfs(StrPas(fixdrivestr[drive]),@fs)<>-1)) or
  845. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (fpstatfs(StrPas(drivestr[drive]),@fs)<>-1)) then
  846. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  847. else
  848. Diskfree:=-1;
  849. End;
  850. Function DiskSize(Drive: Byte): int64;
  851. var
  852. fs : tstatfs;
  853. Begin
  854. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (fpstatfs(StrPas(fixdrivestr[drive]),@fs)<>-1)) or
  855. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (fpstatfs(StrPas(drivestr[drive]),@fs)<>-1)) then
  856. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  857. else
  858. DiskSize:=-1;
  859. End;
  860. Procedure FreeDriveStr;
  861. var
  862. i: longint;
  863. begin
  864. for i:=low(drivestr) to high(drivestr) do
  865. if assigned(drivestr[i]) then
  866. begin
  867. freemem(drivestr[i]);
  868. drivestr[i]:=nil;
  869. end;
  870. end;
  871. {****************************************************************************
  872. Misc Functions
  873. ****************************************************************************}
  874. {****************************************************************************
  875. Locale Functions
  876. ****************************************************************************}
  877. Function GetEpochTime: cint;
  878. {
  879. Get the number of seconds since 00:00, January 1 1970, GMT
  880. the time NOT corrected any way
  881. }
  882. begin
  883. GetEpochTime:=fptime;
  884. end;
  885. // Now, adjusted to local time.
  886. Procedure DoGetLocalDateTime(var year, month, day, hour, min, sec, msec, usec : word);
  887. var
  888. tz:timeval;
  889. begin
  890. fpgettimeofday(@tz,nil);
  891. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  892. msec:=tz.tv_usec div 1000;
  893. usec:=tz.tv_usec mod 1000;
  894. end;
  895. procedure GetTime(var hour,min,sec,msec,usec:word);
  896. Var
  897. year,day,month:Word;
  898. begin
  899. DoGetLocalDateTime(year,month,day,hour,min,sec,msec,usec);
  900. end;
  901. procedure GetTime(var hour,min,sec,sec100:word);
  902. {
  903. Gets the current time, adjusted to local time
  904. }
  905. var
  906. year,day,month,usec : word;
  907. begin
  908. DoGetLocalDateTime(year,month,day,hour,min,sec,sec100,usec);
  909. sec100:=sec100 div 10;
  910. end;
  911. Procedure GetTime(Var Hour,Min,Sec:Word);
  912. {
  913. Gets the current time, adjusted to local time
  914. }
  915. var
  916. year,day,month,msec,usec : Word;
  917. Begin
  918. DoGetLocalDateTime(year,month,day,hour,min,sec,msec,usec);
  919. End;
  920. Procedure GetDate(Var Year,Month,Day:Word);
  921. {
  922. Gets the current date, adjusted to local time
  923. }
  924. var
  925. hour,minute,second,msec,usec : word;
  926. Begin
  927. DoGetLocalDateTime(year,month,day,hour,minute,second,msec,usec);
  928. End;
  929. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  930. {
  931. Gets the current date, adjusted to local time
  932. }
  933. Var
  934. usec,msec : word;
  935. Begin
  936. DoGetLocalDateTime(year,month,day,hour,minute,second,msec,usec);
  937. End;
  938. {$ifndef FPUNONE}
  939. Procedure GetLocalTime(var SystemTime: TSystemTime);
  940. var
  941. usecs : Word;
  942. begin
  943. DoGetLocalDateTime(SystemTime.Year, SystemTime.Month, SystemTime.Day,SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  944. end ;
  945. {$endif}
  946. Procedure InitAnsi;
  947. Var
  948. i : longint;
  949. begin
  950. { Fill table entries 0 to 127 }
  951. for i := 0 to 96 do
  952. UpperCaseTable[i] := chr(i);
  953. for i := 97 to 122 do
  954. UpperCaseTable[i] := chr(i - 32);
  955. for i := 123 to 191 do
  956. UpperCaseTable[i] := chr(i);
  957. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  958. for i := 0 to 64 do
  959. LowerCaseTable[i] := chr(i);
  960. for i := 65 to 90 do
  961. LowerCaseTable[i] := chr(i + 32);
  962. for i := 91 to 191 do
  963. LowerCaseTable[i] := chr(i);
  964. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  965. end;
  966. Procedure InitInternational;
  967. begin
  968. InitInternationalGeneric;
  969. InitAnsi;
  970. end;
  971. function SysErrorMessage(ErrorCode: Integer): String;
  972. begin
  973. Result:=StrError(ErrorCode);
  974. end;
  975. {****************************************************************************
  976. OS utility functions
  977. ****************************************************************************}
  978. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  979. begin
  980. { no need to adjust the code page of EnvVar to DefaultSystemCodePage, as only
  981. ASCII identifiers are supported }
  982. Result:=BaseUnix.FPGetenv(PChar(pointer(EnvVar)));
  983. end;
  984. Function GetEnvironmentVariableCount : Integer;
  985. begin
  986. Result:=FPCCountEnvVar(EnvP);
  987. end;
  988. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  989. begin
  990. Result:=FPCGetEnvStrFromP(Envp,Index);
  991. end;
  992. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  993. var
  994. pid : longint;
  995. e : EOSError;
  996. CommandLine: AnsiString;
  997. cmdline2 : ppchar;
  998. Begin
  999. { always surround the name of the application by quotes
  1000. so that long filenames will always be accepted. But don't
  1001. do it if there are already double quotes!
  1002. }
  1003. // Only place we still parse
  1004. cmdline2:=nil;
  1005. if Comline<>'' Then
  1006. begin
  1007. CommandLine:=ComLine;
  1008. { Make an unique copy because stringtoppchar modifies the
  1009. string }
  1010. UniqueString(CommandLine);
  1011. cmdline2:=StringtoPPChar(CommandLine,1);
  1012. cmdline2^:=pchar(pointer(Path));
  1013. end
  1014. else
  1015. begin
  1016. getmem(cmdline2,2*sizeof(pchar));
  1017. cmdline2^:=pchar(Path);
  1018. cmdline2[1]:=nil;
  1019. end;
  1020. {$ifdef USE_VFORK}
  1021. pid:=fpvFork;
  1022. {$else USE_VFORK}
  1023. pid:=fpFork;
  1024. {$endif USE_VFORK}
  1025. if pid=0 then
  1026. begin
  1027. {The child does the actual exec, and then exits}
  1028. fpexecv(pchar(pointer(Path)),Cmdline2);
  1029. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1030. fpExit(127);
  1031. end
  1032. else
  1033. if pid=-1 then {Fork failed}
  1034. begin
  1035. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1036. e.ErrorCode:=-1;
  1037. raise e;
  1038. end;
  1039. { We're in the parent, let's wait. }
  1040. result:=WaitProcess(pid); // WaitPid and result-convert
  1041. if Comline<>'' Then
  1042. freemem(cmdline2);
  1043. if (result<0) or (result=127) then
  1044. begin
  1045. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1046. E.ErrorCode:=result;
  1047. Raise E;
  1048. end;
  1049. End;
  1050. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString;Flags:TExecuteFlags=[]):integer;
  1051. var
  1052. pid : longint;
  1053. e : EOSError;
  1054. Begin
  1055. pid:=fpFork;
  1056. if pid=0 then
  1057. begin
  1058. {The child does the actual exec, and then exits}
  1059. fpexecl(Path,Comline);
  1060. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1061. fpExit(127);
  1062. end
  1063. else
  1064. if pid=-1 then {Fork failed}
  1065. begin
  1066. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1067. e.ErrorCode:=-1;
  1068. raise e;
  1069. end;
  1070. { We're in the parent, let's wait. }
  1071. result:=WaitProcess(pid); // WaitPid and result-convert
  1072. if (result<0) or (result=127) then
  1073. begin
  1074. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1075. E.ErrorCode:=result;
  1076. raise E;
  1077. end;
  1078. End;
  1079. procedure Sleep(milliseconds: Cardinal);
  1080. Var
  1081. timeout,timeoutresult : TTimespec;
  1082. res: cint;
  1083. begin
  1084. timeout.tv_sec:=milliseconds div 1000;
  1085. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  1086. repeat
  1087. res:=fpnanosleep(@timeout,@timeoutresult);
  1088. timeout:=timeoutresult;
  1089. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  1090. end;
  1091. Function GetLastOSError : Integer;
  1092. begin
  1093. Result:=fpgetErrNo;
  1094. end;
  1095. { ---------------------------------------------------------------------
  1096. Application config files
  1097. ---------------------------------------------------------------------}
  1098. Function GetHomeDir : String;
  1099. begin
  1100. Result:=GetEnvironmentVariable('HOME');
  1101. If (Result<>'') then
  1102. Result:=IncludeTrailingPathDelimiter(Result);
  1103. end;
  1104. { Follows base-dir spec,
  1105. see [http://freedesktop.org/Standards/basedir-spec].
  1106. Always ends with PathDelim. }
  1107. Function XdgConfigHome : String;
  1108. begin
  1109. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  1110. if (Result='') then
  1111. Result:=GetHomeDir + '.config/'
  1112. else
  1113. Result:=IncludeTrailingPathDelimiter(Result);
  1114. end;
  1115. Function GetAppConfigDir(Global : Boolean) : String;
  1116. begin
  1117. If Global then
  1118. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1119. else
  1120. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1121. if VendorName<>'' then
  1122. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1123. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1124. end;
  1125. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  1126. begin
  1127. If Global then
  1128. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1129. else
  1130. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1131. if SubDir then
  1132. begin
  1133. if VendorName<>'' then
  1134. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1135. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1136. end;
  1137. Result:=Result+ApplicationName+ConfigExtension;
  1138. end;
  1139. {****************************************************************************
  1140. GetTempDir
  1141. ****************************************************************************}
  1142. Function GetTempDir(Global : Boolean) : String;
  1143. begin
  1144. If Assigned(OnGetTempDir) then
  1145. Result:=OnGetTempDir(Global)
  1146. else
  1147. begin
  1148. Result:=GetEnvironmentVariable('TEMP');
  1149. If (Result='') Then
  1150. Result:=GetEnvironmentVariable('TMP');
  1151. If (Result='') Then
  1152. Result:=GetEnvironmentVariable('TMPDIR');
  1153. if (Result='') then
  1154. Result:='/tmp/' // fallback.
  1155. end;
  1156. if (Result<>'') then
  1157. Result:=IncludeTrailingPathDelimiter(Result);
  1158. end;
  1159. {****************************************************************************
  1160. GetUserDir
  1161. ****************************************************************************}
  1162. Var
  1163. TheUserDir : String;
  1164. Function GetUserDir : String;
  1165. begin
  1166. If (TheUserDir='') then
  1167. begin
  1168. TheUserDir:=GetEnvironmentVariable('HOME');
  1169. if (TheUserDir<>'') then
  1170. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  1171. else
  1172. TheUserDir:=GetTempDir(False);
  1173. end;
  1174. Result:=TheUserDir;
  1175. end;
  1176. Procedure SysBeep;
  1177. begin
  1178. Write(#7);
  1179. Flush(Output);
  1180. end;
  1181. function GetLocalTimeOffset: Integer;
  1182. begin
  1183. Result := -Tzseconds div 60;
  1184. end;
  1185. {****************************************************************************
  1186. Initialization code
  1187. ****************************************************************************}
  1188. Initialization
  1189. InitExceptions; { Initialize exceptions. OS independent }
  1190. InitInternational; { Initialize internationalization settings }
  1191. SysConfigDir:='/etc'; { Initialize system config dir }
  1192. OnBeep:=@SysBeep;
  1193. Finalization
  1194. FreeDriveStr;
  1195. DoneExceptions;
  1196. end.