sysutils.pp 35 KB

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