sysutils.pp 38 KB

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