sysutils.pp 36 KB

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