sysutils.pp 36 KB

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