sysutils.pp 36 KB

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