sysutils.pp 36 KB

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