2
0

sysutils.pp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500
  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. result:=(WinAttr and Not d^.searchattr)=0;
  621. end;
  622. Type
  623. PRawByteSearchRec = ^TRawByteSearchRec;
  624. Function FindGetFileInfoR(const s: RawByteString; P : Pointer):boolean;
  625. Var
  626. st : baseunix.stat;
  627. A : longint;
  628. F : PRawbyteSearchRec;
  629. begin
  630. F:=PRawbyteSearchRec(P);
  631. Result:=Do_FindGetFileInfo(S,PUnixFindData(f^.FindHandle),st,A);
  632. If Result Then
  633. Begin
  634. f^.Name:=ExtractFileName(s);
  635. f^.Attr:=A;
  636. f^.Size:=st.st_Size;
  637. f^.Mode:=st.st_mode;
  638. f^.Time:=st.st_mtime;
  639. End;
  640. end;
  641. Type
  642. PUnicodeSearchRec = ^TUnicodeSearchRec;
  643. Function FindGetFileInfoU(const s: RawByteString ; P : Pointer):boolean;
  644. Var
  645. st : baseunix.stat;
  646. A : longint;
  647. F : PUnicodeSearchRec;
  648. begin
  649. F:=PUnicodeSearchRec(P);
  650. Result:=Do_FindGetFileInfo(S,PUnixFindData(f^.FindHandle),st,A);
  651. If Result Then
  652. Begin
  653. f^.Name:=ExtractFileName(s);
  654. f^.Attr:=A;
  655. f^.Size:=st.st_Size;
  656. f^.Mode:=st.st_mode;
  657. f^.Time:=st.st_mtime;
  658. End;
  659. end;
  660. // Returns the FOUND filename. Empty if no result is found.
  661. // Uses CB to return file info
  662. Type
  663. TGetFileInfoCB = Function (const s: RawByteString ; P : Pointer):boolean;
  664. Function Do_FindNext (UnixFindData : PUnixFindData; CB : TGetFileInfoCB; Data : Pointer) : Longint;
  665. Var
  666. DirName : RawByteString;
  667. FName,
  668. SName : RawBytestring;
  669. Found,
  670. Finished : boolean;
  671. p : pdirent;
  672. Begin
  673. Result:=-1;
  674. If (UnixFindData=Nil) or (UnixFindData^.SearchSpec='') then
  675. exit;
  676. if (UnixFindData^.SearchType=0) and
  677. (UnixFindData^.Dirptr=nil) then
  678. begin
  679. If UnixFindData^.NamePos = 0 Then
  680. DirName:='./'
  681. Else
  682. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  683. UnixFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  684. end;
  685. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  686. Found:=False;
  687. Finished:=(UnixFindData^.dirptr=nil);
  688. While Not Finished Do
  689. Begin
  690. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  691. if p=nil then
  692. FName:=''
  693. else
  694. FName:=p^.d_name;
  695. If FName='' Then
  696. Finished:=True
  697. Else
  698. Begin
  699. If FNMatch(SName,FName) Then
  700. Begin
  701. Found:=CB(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Data);
  702. if Found then
  703. begin
  704. Result:=0;
  705. exit;
  706. end;
  707. End;
  708. End;
  709. End;
  710. End;
  711. Function FindNext (Var Rslt : TRawByteSearchRec) : Longint;
  712. begin
  713. FindNext:=Do_findNext(PUnixFindData(Rslt.FindHandle),@FindGetFileInfoR,@Rslt);
  714. end;
  715. Function FindNext (Var Rslt : TUnicodeSearchRec) : Longint;
  716. begin
  717. FindNext:=Do_findNext(PUnixFindData(Rslt.FindHandle),@FindGetFileInfoU,@Rslt);
  718. end;
  719. Function FindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TRawByteSearchRec) : Longint;
  720. {
  721. opens dir and calls FindNext if needed.
  722. }
  723. var
  724. UnixFindData : PUnixFindData;
  725. Begin
  726. Result:=-1;
  727. fillchar(Rslt,sizeof(Rslt),0);
  728. if Path='' then
  729. exit;
  730. { Allocate UnixFindData (we always need it, for the search attributes) }
  731. New(UnixFindData);
  732. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  733. Rslt.FindHandle:=UnixFindData;
  734. {We always also search for readonly and archive, regardless of Attr:}
  735. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  736. {Wildcards?}
  737. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  738. begin
  739. if FindGetFileInfoR(Path,@Rslt) then
  740. Result:=0;
  741. end
  742. else
  743. begin
  744. {Create Info}
  745. UnixFindData^.SearchSpec := Path;
  746. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  747. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  748. dec(UnixFindData^.NamePos);
  749. Result:=FindNext(Rslt);
  750. end;
  751. If (Result<>0) then
  752. FindClose(Rslt);
  753. End;
  754. Function FindFirst (Const Path : UnicodeString; Attr : Longint; out Rslt : TUnicodeSearchRec) : Longint;
  755. {
  756. opens dir and calls FindNext if needed.
  757. }
  758. var
  759. UnixFindData : PUnixFindData;
  760. P : RawByteString;
  761. Begin
  762. Result:=-1;
  763. fillchar(Rslt,sizeof(Rslt),0);
  764. if Path='' then
  765. exit;
  766. P:=ToSingleByteFileSystemEncodedFileName(Path);
  767. { Allocate UnixFindData (we always need it, for the search attributes) }
  768. New(UnixFindData);
  769. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  770. Rslt.FindHandle:=UnixFindData;
  771. {We always also search for readonly and archive, regardless of Attr:}
  772. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  773. {Wildcards?}
  774. if (Pos('?',P)=0) and (Pos('*',P)=0) then
  775. begin
  776. if FindGetFileInfoR(P,@Rslt) then
  777. Result:=0;
  778. end
  779. else
  780. begin
  781. {Create Info}
  782. UnixFindData^.SearchSpec := P;
  783. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  784. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  785. dec(UnixFindData^.NamePos);
  786. Result:=FindNext(Rslt);
  787. end;
  788. If (Result<>0) then
  789. FindClose(Rslt);
  790. End;
  791. Function FileGetDate (Handle : Longint) : Longint;
  792. Var Info : Stat;
  793. begin
  794. If (fpFStat(Handle,Info))<0 then
  795. Result:=-1
  796. else
  797. Result:=Info.st_Mtime;
  798. end;
  799. Function FileSetDate (Handle,Age : Longint) : Longint;
  800. begin
  801. // Impossible under Linux from FileHandle !!
  802. FileSetDate:=-1;
  803. end;
  804. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  805. Var Info : Stat;
  806. res : Integer;
  807. begin
  808. res:=FpLStat (pointer(FileName),Info);
  809. if res<0 then
  810. res:=FpStat (pointer(FileName),Info);
  811. if res<0 then
  812. Result:=-1
  813. Else
  814. Result:=LinuxToWinAttr(Pchar(FileName),Info);
  815. end;
  816. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  817. begin
  818. Result:=-1;
  819. end;
  820. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  821. begin
  822. Result:=fpUnLink (pchar(FileName))>=0;
  823. end;
  824. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  825. begin
  826. RenameFile:=BaseUnix.FpRename(pointer(OldNAme),pointer(NewName))>=0;
  827. end;
  828. Function FileIsReadOnly(const FileName: RawByteString): Boolean;
  829. begin
  830. Result := fpAccess(PChar(pointer(FileName)),W_OK)<>0;
  831. end;
  832. Function FileSetDate (Const FileName : RawByteString;Age : Longint) : Longint;
  833. var
  834. t: TUTimBuf;
  835. begin
  836. Result := 0;
  837. t.actime := Age;
  838. t.modtime := Age;
  839. if fputime(PChar(pointer(FileName)), @t) = -1 then
  840. Result := fpgeterrno;
  841. end;
  842. {****************************************************************************
  843. Disk Functions
  844. ****************************************************************************}
  845. {
  846. The Diskfree and Disksize functions need a file on the specified drive, since this
  847. is required for the fpstatfs system call.
  848. These filenames are set in drivestr[0..26], and have been preset to :
  849. 0 - '.' (default drive - hence current dir is ok.)
  850. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  851. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  852. 3 - '/' (C: equivalent of dos is the root partition)
  853. 4..26 (can be set by you're own applications)
  854. ! Use AddDisk() to Add new drives !
  855. They both return -1 when a failure occurs.
  856. }
  857. Const
  858. FixDriveStr : array[0..3] of pchar=(
  859. '.',
  860. '/fd0/.',
  861. '/fd1/.',
  862. '/.'
  863. );
  864. var
  865. Drives : byte = 4;
  866. DriveStr : array[4..26] of pchar;
  867. Function AddDisk(const path:string) : Byte;
  868. begin
  869. if not (DriveStr[Drives]=nil) then
  870. FreeMem(DriveStr[Drives]);
  871. GetMem(DriveStr[Drives],length(Path)+1);
  872. StrPCopy(DriveStr[Drives],path);
  873. Result:=Drives;
  874. inc(Drives);
  875. if Drives>26 then
  876. Drives:=4;
  877. end;
  878. Function DiskFree(Drive: Byte): int64;
  879. var
  880. fs : tstatfs;
  881. Begin
  882. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (fpstatfs(StrPas(fixdrivestr[drive]),@fs)<>-1)) or
  883. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (fpstatfs(StrPas(drivestr[drive]),@fs)<>-1)) then
  884. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  885. else
  886. Diskfree:=-1;
  887. End;
  888. Function DiskSize(Drive: Byte): int64;
  889. var
  890. fs : tstatfs;
  891. Begin
  892. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (fpstatfs(StrPas(fixdrivestr[drive]),@fs)<>-1)) or
  893. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (fpstatfs(StrPas(drivestr[drive]),@fs)<>-1)) then
  894. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  895. else
  896. DiskSize:=-1;
  897. End;
  898. Procedure FreeDriveStr;
  899. var
  900. i: longint;
  901. begin
  902. for i:=low(drivestr) to high(drivestr) do
  903. if assigned(drivestr[i]) then
  904. begin
  905. freemem(drivestr[i]);
  906. drivestr[i]:=nil;
  907. end;
  908. end;
  909. Function GetCurrentDir : String;
  910. begin
  911. GetDir (0,Result);
  912. end;
  913. Function SetCurrentDir (Const NewDir : String) : Boolean;
  914. begin
  915. {$I-}
  916. ChDir(NewDir);
  917. {$I+}
  918. result := (IOResult = 0);
  919. end;
  920. Function CreateDir (Const NewDir : String) : Boolean;
  921. begin
  922. {$I-}
  923. MkDir(NewDir);
  924. {$I+}
  925. result := (IOResult = 0);
  926. end;
  927. Function RemoveDir (Const Dir : String) : Boolean;
  928. begin
  929. {$I-}
  930. RmDir(Dir);
  931. {$I+}
  932. result := (IOResult = 0);
  933. end;
  934. {****************************************************************************
  935. Misc Functions
  936. ****************************************************************************}
  937. {****************************************************************************
  938. Locale Functions
  939. ****************************************************************************}
  940. Function GetEpochTime: cint;
  941. {
  942. Get the number of seconds since 00:00, January 1 1970, GMT
  943. the time NOT corrected any way
  944. }
  945. begin
  946. GetEpochTime:=fptime;
  947. end;
  948. // Now, adjusted to local time.
  949. Procedure DoGetLocalDateTime(var year, month, day, hour, min, sec, msec, usec : word);
  950. var
  951. tz:timeval;
  952. begin
  953. fpgettimeofday(@tz,nil);
  954. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  955. msec:=tz.tv_usec div 1000;
  956. usec:=tz.tv_usec mod 1000;
  957. end;
  958. procedure GetTime(var hour,min,sec,msec,usec:word);
  959. Var
  960. year,day,month:Word;
  961. begin
  962. DoGetLocalDateTime(year,month,day,hour,min,sec,msec,usec);
  963. end;
  964. procedure GetTime(var hour,min,sec,sec100:word);
  965. {
  966. Gets the current time, adjusted to local time
  967. }
  968. var
  969. year,day,month,usec : word;
  970. begin
  971. DoGetLocalDateTime(year,month,day,hour,min,sec,sec100,usec);
  972. sec100:=sec100 div 10;
  973. end;
  974. Procedure GetTime(Var Hour,Min,Sec:Word);
  975. {
  976. Gets the current time, adjusted to local time
  977. }
  978. var
  979. year,day,month,msec,usec : Word;
  980. Begin
  981. DoGetLocalDateTime(year,month,day,hour,min,sec,msec,usec);
  982. End;
  983. Procedure GetDate(Var Year,Month,Day:Word);
  984. {
  985. Gets the current date, adjusted to local time
  986. }
  987. var
  988. hour,minute,second,msec,usec : word;
  989. Begin
  990. DoGetLocalDateTime(year,month,day,hour,minute,second,msec,usec);
  991. End;
  992. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  993. {
  994. Gets the current date, adjusted to local time
  995. }
  996. Var
  997. usec,msec : word;
  998. Begin
  999. DoGetLocalDateTime(year,month,day,hour,minute,second,msec,usec);
  1000. End;
  1001. {$ifndef FPUNONE}
  1002. Procedure GetLocalTime(var SystemTime: TSystemTime);
  1003. var
  1004. usecs : Word;
  1005. begin
  1006. DoGetLocalDateTime(SystemTime.Year, SystemTime.Month, SystemTime.Day,SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  1007. end ;
  1008. {$endif}
  1009. Procedure InitAnsi;
  1010. Var
  1011. i : longint;
  1012. begin
  1013. { Fill table entries 0 to 127 }
  1014. for i := 0 to 96 do
  1015. UpperCaseTable[i] := chr(i);
  1016. for i := 97 to 122 do
  1017. UpperCaseTable[i] := chr(i - 32);
  1018. for i := 123 to 191 do
  1019. UpperCaseTable[i] := chr(i);
  1020. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  1021. for i := 0 to 64 do
  1022. LowerCaseTable[i] := chr(i);
  1023. for i := 65 to 90 do
  1024. LowerCaseTable[i] := chr(i + 32);
  1025. for i := 91 to 191 do
  1026. LowerCaseTable[i] := chr(i);
  1027. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  1028. end;
  1029. Procedure InitInternational;
  1030. begin
  1031. InitInternationalGeneric;
  1032. InitAnsi;
  1033. end;
  1034. function SysErrorMessage(ErrorCode: Integer): String;
  1035. begin
  1036. Result:=StrError(ErrorCode);
  1037. end;
  1038. {****************************************************************************
  1039. OS utility functions
  1040. ****************************************************************************}
  1041. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  1042. begin
  1043. Result:=StrPas(BaseUnix.FPGetenv(PChar(pointer(EnvVar))));
  1044. end;
  1045. Function GetEnvironmentVariableCount : Integer;
  1046. begin
  1047. Result:=FPCCountEnvVar(EnvP);
  1048. end;
  1049. Function GetEnvironmentString(Index : Integer) : String;
  1050. begin
  1051. Result:=FPCGetEnvStrFromP(Envp,Index);
  1052. end;
  1053. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  1054. var
  1055. pid : longint;
  1056. e : EOSError;
  1057. CommandLine: AnsiString;
  1058. cmdline2 : ppchar;
  1059. Begin
  1060. { always surround the name of the application by quotes
  1061. so that long filenames will always be accepted. But don't
  1062. do it if there are already double quotes!
  1063. }
  1064. // Only place we still parse
  1065. cmdline2:=nil;
  1066. if Comline<>'' Then
  1067. begin
  1068. CommandLine:=ComLine;
  1069. { Make an unique copy because stringtoppchar modifies the
  1070. string }
  1071. UniqueString(CommandLine);
  1072. cmdline2:=StringtoPPChar(CommandLine,1);
  1073. cmdline2^:=pchar(pointer(Path));
  1074. end
  1075. else
  1076. begin
  1077. getmem(cmdline2,2*sizeof(pchar));
  1078. cmdline2^:=pchar(Path);
  1079. cmdline2[1]:=nil;
  1080. end;
  1081. {$ifdef USE_VFORK}
  1082. pid:=fpvFork;
  1083. {$else USE_VFORK}
  1084. pid:=fpFork;
  1085. {$endif USE_VFORK}
  1086. if pid=0 then
  1087. begin
  1088. {The child does the actual exec, and then exits}
  1089. fpexecv(pchar(pointer(Path)),Cmdline2);
  1090. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1091. fpExit(127);
  1092. end
  1093. else
  1094. if pid=-1 then {Fork failed}
  1095. begin
  1096. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1097. e.ErrorCode:=-1;
  1098. raise e;
  1099. end;
  1100. { We're in the parent, let's wait. }
  1101. result:=WaitProcess(pid); // WaitPid and result-convert
  1102. if Comline<>'' Then
  1103. freemem(cmdline2);
  1104. if (result<0) or (result=127) then
  1105. begin
  1106. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1107. E.ErrorCode:=result;
  1108. Raise E;
  1109. end;
  1110. End;
  1111. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString;Flags:TExecuteFlags=[]):integer;
  1112. var
  1113. pid : longint;
  1114. e : EOSError;
  1115. Begin
  1116. pid:=fpFork;
  1117. if pid=0 then
  1118. begin
  1119. {The child does the actual exec, and then exits}
  1120. fpexecl(Path,Comline);
  1121. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1122. fpExit(127);
  1123. end
  1124. else
  1125. if pid=-1 then {Fork failed}
  1126. begin
  1127. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1128. e.ErrorCode:=-1;
  1129. raise e;
  1130. end;
  1131. { We're in the parent, let's wait. }
  1132. result:=WaitProcess(pid); // WaitPid and result-convert
  1133. if (result<0) or (result=127) then
  1134. begin
  1135. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1136. E.ErrorCode:=result;
  1137. raise E;
  1138. end;
  1139. End;
  1140. procedure Sleep(milliseconds: Cardinal);
  1141. Var
  1142. timeout,timeoutresult : TTimespec;
  1143. res: cint;
  1144. begin
  1145. timeout.tv_sec:=milliseconds div 1000;
  1146. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  1147. repeat
  1148. res:=fpnanosleep(@timeout,@timeoutresult);
  1149. timeout:=timeoutresult;
  1150. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  1151. end;
  1152. Function GetLastOSError : Integer;
  1153. begin
  1154. Result:=fpgetErrNo;
  1155. end;
  1156. { ---------------------------------------------------------------------
  1157. Application config files
  1158. ---------------------------------------------------------------------}
  1159. Function GetHomeDir : String;
  1160. begin
  1161. Result:=GetEnvironmentVariable('HOME');
  1162. If (Result<>'') then
  1163. Result:=IncludeTrailingPathDelimiter(Result);
  1164. end;
  1165. { Follows base-dir spec,
  1166. see [http://freedesktop.org/Standards/basedir-spec].
  1167. Always ends with PathDelim. }
  1168. Function XdgConfigHome : String;
  1169. begin
  1170. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  1171. if (Result='') then
  1172. Result:=GetHomeDir + '.config/'
  1173. else
  1174. Result:=IncludeTrailingPathDelimiter(Result);
  1175. end;
  1176. Function GetAppConfigDir(Global : Boolean) : String;
  1177. begin
  1178. If Global then
  1179. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1180. else
  1181. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1182. if VendorName<>'' then
  1183. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1184. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1185. end;
  1186. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  1187. begin
  1188. If Global then
  1189. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1190. else
  1191. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1192. if SubDir then
  1193. begin
  1194. if VendorName<>'' then
  1195. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1196. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1197. end;
  1198. Result:=Result+ApplicationName+ConfigExtension;
  1199. end;
  1200. {****************************************************************************
  1201. GetTempDir
  1202. ****************************************************************************}
  1203. Function GetTempDir(Global : Boolean) : String;
  1204. begin
  1205. If Assigned(OnGetTempDir) then
  1206. Result:=OnGetTempDir(Global)
  1207. else
  1208. begin
  1209. Result:=GetEnvironmentVariable('TEMP');
  1210. If (Result='') Then
  1211. Result:=GetEnvironmentVariable('TMP');
  1212. If (Result='') Then
  1213. Result:=GetEnvironmentVariable('TMPDIR');
  1214. if (Result='') then
  1215. Result:='/tmp/' // fallback.
  1216. end;
  1217. if (Result<>'') then
  1218. Result:=IncludeTrailingPathDelimiter(Result);
  1219. end;
  1220. {****************************************************************************
  1221. GetUserDir
  1222. ****************************************************************************}
  1223. Var
  1224. TheUserDir : String;
  1225. Function GetUserDir : String;
  1226. begin
  1227. If (TheUserDir='') then
  1228. begin
  1229. TheUserDir:=GetEnvironmentVariable('HOME');
  1230. if (TheUserDir<>'') then
  1231. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  1232. else
  1233. TheUserDir:=GetTempDir(False);
  1234. end;
  1235. Result:=TheUserDir;
  1236. end;
  1237. Procedure SysBeep;
  1238. begin
  1239. Write(#7);
  1240. Flush(Output);
  1241. end;
  1242. function GetLocalTimeOffset: Integer;
  1243. begin
  1244. Result := -Tzseconds div 60;
  1245. end;
  1246. {****************************************************************************
  1247. Initialization code
  1248. ****************************************************************************}
  1249. Initialization
  1250. InitExceptions; { Initialize exceptions. OS independent }
  1251. InitInternational; { Initialize internationalization settings }
  1252. SysConfigDir:='/etc'; { Initialize system config dir }
  1253. OnBeep:=@SysBeep;
  1254. Finalization
  1255. FreeDriveStr;
  1256. DoneExceptions;
  1257. end.