sysutils.pp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555
  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. {$modeswitch typehelpers}
  19. {$modeswitch advancedrecords}
  20. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  21. {$define USE_VFORK}
  22. {$endif}
  23. {$DEFINE OS_FILESETDATEBYNAME}
  24. {$DEFINE HAS_SLEEP}
  25. {$DEFINE HAS_OSERROR}
  26. {$DEFINE HAS_OSCONFIG}
  27. {$DEFINE HAS_TEMPDIR}
  28. {$DEFINE HASUNIX}
  29. {$DEFINE HASCREATEGUID}
  30. {$DEFINE HAS_OSUSERDIR}
  31. {$DEFINE HAS_LOCALTIMEZONEOFFSET}
  32. {$DEFINE HAS_GETTICKCOUNT64}
  33. { used OS file system APIs use ansistring }
  34. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  35. { OS has an ansistring/single byte environment variable API }
  36. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  37. uses
  38. {$IFDEF LINUX}linux,{$ENDIF}
  39. {$IFDEF FreeBSD}freebsd,{$ENDIF}
  40. Unix,errors,sysconst,Unixtype;
  41. {$IF defined(LINUX) or defined(FreeBSD)}
  42. {$DEFINE HAVECLOCKGETTIME}
  43. {$ENDIF}
  44. { Include platform independent interface part }
  45. {$i sysutilh.inc}
  46. Function AddDisk(const path:string) : Byte;
  47. { the following is Kylix compatibility stuff, it should be moved to a
  48. special compatibilty unit (FK) }
  49. const
  50. RTL_SIGINT = 0;
  51. RTL_SIGFPE = 1;
  52. RTL_SIGSEGV = 2;
  53. RTL_SIGILL = 3;
  54. RTL_SIGBUS = 4;
  55. RTL_SIGQUIT = 5;
  56. RTL_SIGLAST = RTL_SIGQUIT;
  57. RTL_SIGDEFAULT = -1;
  58. type
  59. TSignalState = (ssNotHooked, ssHooked, ssOverridden);
  60. function InquireSignal(RtlSigNum: Integer): TSignalState;
  61. procedure AbandonSignalHandler(RtlSigNum: Integer);
  62. procedure HookSignal(RtlSigNum: Integer);
  63. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  64. implementation
  65. Uses
  66. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
  67. type
  68. tsiginfo = record
  69. oldsiginfo: sigactionrec;
  70. hooked: boolean;
  71. end;
  72. const
  73. rtlsig2ossig: array[RTL_SIGINT..RTL_SIGLAST] of byte =
  74. (SIGINT,SIGFPE,SIGSEGV,SIGILL,SIGBUS,SIGQUIT);
  75. { to avoid linking in all this stuff in every program,
  76. as it's unlikely to be used by anything but libraries
  77. }
  78. signalinfoinited: boolean = false;
  79. var
  80. siginfo: array[RTL_SIGINT..RTL_SIGLAST] of tsiginfo;
  81. oldsigfpe: SigActionRec; external name '_FPC_OLDSIGFPE';
  82. oldsigsegv: SigActionRec; external name '_FPC_OLDSIGSEGV';
  83. oldsigbus: SigActionRec; external name '_FPC_OLDSIGBUS';
  84. oldsigill: SigActionRec; external name '_FPC_OLDSIGILL';
  85. procedure defaultsighandler; external name '_FPC_DEFAULTSIGHANDLER';
  86. procedure installdefaultsignalhandler(signum: Integer; out oldact: SigActionRec); external name '_FPC_INSTALLDEFAULTSIGHANDLER';
  87. function InternalInquireSignal(RtlSigNum: Integer; out act: SigActionRec; frominit: boolean): TSignalState;
  88. begin
  89. result:=ssNotHooked;
  90. if (RtlSigNum<>RTL_SIGDEFAULT) and
  91. (RtlSigNum<RTL_SIGLAST) then
  92. begin
  93. if (frominit or
  94. siginfo[RtlSigNum].hooked) and
  95. (fpsigaction(rtlsig2ossig[RtlSigNum],nil,@act)=0) then
  96. begin
  97. if not frominit then
  98. begin
  99. { check whether the installed signal handler is still ours }
  100. {$if not defined(aix) and (not defined(linux) or not defined(cpupowerpc64) or (defined(_call_elf) and (_call_elf = 2)))}
  101. if (pointer(act.sa_handler)=pointer(@defaultsighandler)) then
  102. {$else}
  103. { on aix and linux/ppc64 (ELFv1), procedure addresses are
  104. actually descriptors -> check whether the code addresses
  105. inside the descriptors match, rather than the descriptors
  106. themselves }
  107. if (ppointer(act.sa_handler)^=ppointer(@defaultsighandler)^) then
  108. {$endif}
  109. result:=ssHooked
  110. else
  111. result:=ssOverridden;
  112. end
  113. else if IsLibrary then
  114. begin
  115. { library -> signals have not been hooked by system init code }
  116. exit
  117. end
  118. else
  119. begin
  120. { program -> signals have been hooked by system init code }
  121. if (byte(RtlSigNum) in [RTL_SIGFPE,RTL_SIGSEGV,RTL_SIGILL,RTL_SIGBUS]) then
  122. begin
  123. {$if not defined(aix) and (not defined(linux) or not defined(cpupowerpc64) or (defined(_call_elf) and (_call_elf = 2)))}
  124. if (pointer(act.sa_handler)=pointer(@defaultsighandler)) then
  125. {$else}
  126. if (ppointer(act.sa_handler)^=ppointer(@defaultsighandler)^) then
  127. {$endif}
  128. result:=ssHooked
  129. else
  130. result:=ssOverridden;
  131. { return the original handlers as saved by the system unit
  132. (the current call to sigaction simply returned our
  133. system unit's installed handlers)
  134. }
  135. case RtlSigNum of
  136. RTL_SIGFPE:
  137. act:=oldsigfpe;
  138. RTL_SIGSEGV:
  139. act:=oldsigsegv;
  140. RTL_SIGILL:
  141. act:=oldsigill;
  142. RTL_SIGBUS:
  143. act:=oldsigbus;
  144. end;
  145. end
  146. else
  147. begin
  148. { these are not hooked in the startup code }
  149. result:=ssNotHooked;
  150. end
  151. end
  152. end
  153. end;
  154. end;
  155. procedure initsignalinfo;
  156. var
  157. i: Integer;
  158. begin
  159. for i:=RTL_SIGINT to RTL_SIGLAST do
  160. siginfo[i].hooked:=(InternalInquireSignal(i,siginfo[i].oldsiginfo,true)=ssHooked);
  161. signalinfoinited:=true;
  162. end;
  163. function InquireSignal(RtlSigNum: Integer): TSignalState;
  164. var
  165. act: SigActionRec;
  166. begin
  167. if not signalinfoinited then
  168. initsignalinfo;
  169. result:=InternalInquireSignal(RtlSigNum,act,false);
  170. end;
  171. procedure AbandonSignalHandler(RtlSigNum: Integer);
  172. begin
  173. if not signalinfoinited then
  174. initsignalinfo;
  175. if (RtlSigNum<>RTL_SIGDEFAULT) and
  176. (RtlSigNum<RTL_SIGLAST) then
  177. siginfo[RtlSigNum].hooked:=false;
  178. end;
  179. procedure HookSignal(RtlSigNum: Integer);
  180. var
  181. lowsig, highsig, i: Integer;
  182. begin
  183. if not signalinfoinited then
  184. initsignalinfo;
  185. if (RtlSigNum<>RTL_SIGDEFAULT) then
  186. begin
  187. lowsig:=RtlSigNum;
  188. highsig:=RtlSigNum;
  189. end
  190. else
  191. begin
  192. { we don't hook SIGINT and SIGQUIT by default }
  193. lowsig:=RTL_SIGFPE;
  194. highsig:=RTL_SIGBUS;
  195. end;
  196. { install the default rtl signal handler for the selected signal(s) }
  197. for i:=lowsig to highsig do
  198. begin
  199. installdefaultsignalhandler(rtlsig2ossig[i],siginfo[i].oldsiginfo);
  200. siginfo[i].hooked:=true;
  201. end;
  202. end;
  203. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  204. var
  205. act: SigActionRec;
  206. lowsig, highsig, i: Integer;
  207. begin
  208. if not signalinfoinited then
  209. initsignalinfo;
  210. if (RtlSigNum<>RTL_SIGDEFAULT) then
  211. begin
  212. lowsig:=RtlSigNum;
  213. highsig:=RtlSigNum;
  214. end
  215. else
  216. begin
  217. { we don't hook SIGINT and SIGQUIT by default }
  218. lowsig:=RTL_SIGFPE;
  219. highsig:=RTL_SIGBUS;
  220. end;
  221. for i:=lowsig to highsig do
  222. begin
  223. if not OnlyIfHooked or
  224. (InquireSignal(i)=ssHooked) then
  225. begin
  226. { restore the handler that was present when we hooked the signal,
  227. if we hooked it at one time or another. If the user doesn't
  228. want this, they have to call AbandonSignalHandler() first
  229. }
  230. if siginfo[i].hooked then
  231. act:=siginfo[i].oldsiginfo
  232. else
  233. begin
  234. fillchar(act,sizeof(act),0);
  235. pointer(act.sa_handler):=pointer(SIG_DFL);
  236. end;
  237. if (fpsigaction(rtlsig2ossig[RtlSigNum],@act,nil)=0) then
  238. siginfo[i].hooked:=false;
  239. end;
  240. end;
  241. end;
  242. {$Define OS_FILEISREADONLY} // Specific implementation for Unix.
  243. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  244. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  245. { Include platform independent implementation part }
  246. {$define executeprocuni}
  247. {$i sysutils.inc}
  248. { Include SysCreateGUID function }
  249. {$i suuid.inc}
  250. Const
  251. {Date Translation}
  252. C1970=2440588;
  253. D0 = 1461;
  254. D1 = 146097;
  255. D2 =1721119;
  256. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  257. Var
  258. YYear,XYear,Temp,TempMonth : LongInt;
  259. Begin
  260. Temp:=((JulianDN-D2) shl 2)-1;
  261. JulianDN:=Temp Div D1;
  262. XYear:=(Temp Mod D1) or 3;
  263. YYear:=(XYear Div D0);
  264. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  265. Day:=((Temp Mod 153)+5) Div 5;
  266. TempMonth:=Temp Div 153;
  267. If TempMonth>=10 Then
  268. Begin
  269. inc(YYear);
  270. dec(TempMonth,12);
  271. End;
  272. inc(TempMonth,3);
  273. Month := TempMonth;
  274. Year:=YYear+(JulianDN*100);
  275. end;
  276. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  277. {
  278. Transforms Epoch time into local time (hour, minute,seconds)
  279. }
  280. Var
  281. DateNum: LongInt;
  282. Begin
  283. inc(Epoch,TZSeconds);
  284. Datenum:=(Epoch Div 86400) + c1970;
  285. JulianToGregorian(DateNum,Year,Month,day);
  286. Epoch:=Abs(Epoch Mod 86400);
  287. Hour:=Epoch Div 3600;
  288. Epoch:=Epoch Mod 3600;
  289. Minute:=Epoch Div 60;
  290. Second:=Epoch Mod 60;
  291. End;
  292. function GetTickCount64: QWord;
  293. var
  294. tp: TTimeVal;
  295. {$IFDEF HAVECLOCKGETTIME}
  296. ts: TTimeSpec;
  297. {$ENDIF}
  298. begin
  299. {$IFDEF HAVECLOCKGETTIME}
  300. if clock_gettime(CLOCK_MONOTONIC, @ts)=0 then
  301. begin
  302. Result := (Int64(ts.tv_sec) * 1000) + (ts.tv_nsec div 1000000);
  303. exit;
  304. end;
  305. {$ENDIF}
  306. fpgettimeofday(@tp, nil);
  307. Result := (Int64(tp.tv_sec) * 1000) + (tp.tv_usec div 1000);
  308. end;
  309. {****************************************************************************
  310. File Functions
  311. ****************************************************************************}
  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. fmShareDenyNone:
  347. lockop:=LOCK_SH or LOCK_NB;
  348. else
  349. begin
  350. { fmShareDenyRead does not exit under *nix, only shared access
  351. (similar to fmShareDenyWrite) and exclusive access (same as
  352. fmShareExclusive)
  353. }
  354. repeat
  355. closeres:=FpClose(Handle);
  356. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  357. DoFileLocking:=-1;
  358. exit;
  359. end;
  360. end;
  361. repeat
  362. lockres:=fpflock(Handle,lockop);
  363. until (lockres=0) or
  364. (fpgeterrno<>ESysEIntr);
  365. lockerr:=fpgeterrno;
  366. { Only return an error if locks are working and the file was already
  367. locked. Not if locks are simply unsupported (e.g., on Angstrom Linux
  368. you always get ESysNOLCK in the default configuration) }
  369. if (lockres<>0) and
  370. ((lockerr=ESysEAGAIN) or
  371. (lockerr=EsysEDEADLK)) then
  372. begin
  373. repeat
  374. closeres:=FpClose(Handle);
  375. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  376. DoFileLocking:=-1;
  377. exit;
  378. end;
  379. end;
  380. {$endif not beos}
  381. end;
  382. Function FileOpenNoLocking (Const FileName : RawbyteString; Mode : Integer) : Longint;
  383. Var
  384. SystemFileName: RawByteString;
  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. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  394. repeat
  395. FileOpenNoLocking:=fpOpen (pointer(SystemFileName),LinuxFlags);
  396. until (FileOpenNoLocking<>-1) or (fpgeterrno<>ESysEINTR);
  397. end;
  398. Function FileOpen (Const FileName : RawbyteString; Mode : Integer) : Longint;
  399. begin
  400. FileOpen:=FileOpenNoLocking(FileName, Mode);
  401. FileOpen:=DoFileLocking(FileOpen, Mode);
  402. end;
  403. Function FileCreate (Const FileName : RawByteString) : Longint;
  404. Var
  405. SystemFileName: RawByteString;
  406. begin
  407. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  408. repeat
  409. FileCreate:=fpOpen(pointer(SystemFileName),O_RdWr or O_Creat or O_Trunc);
  410. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  411. end;
  412. Function FileCreate (Const FileName : RawByteString;Rights : Longint) : Longint;
  413. Var
  414. SystemFileName: RawByteString;
  415. begin
  416. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  417. repeat
  418. FileCreate:=fpOpen(pointer(SystemFileName),O_RdWr or O_Creat or O_Trunc,Rights);
  419. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  420. end;
  421. Function FileCreate (Const FileName : RawByteString; ShareMode : Longint; Rights:LongInt ) : Longint;
  422. Var
  423. fd: Longint;
  424. begin
  425. { if the file already exists and we can't open it using the requested
  426. ShareMode (e.g. exclusive sharing), exit immediately so that we don't
  427. first empty the file and then check whether we can lock this new file
  428. (which we can by definition) }
  429. fd:=FileOpenNoLocking(FileName,ShareMode);
  430. { the file exists, check whether our locking request is compatible }
  431. if fd>=0 then
  432. begin
  433. Result:=DoFileLocking(fd,ShareMode);
  434. FileClose(fd);
  435. { Can't lock -> abort }
  436. if Result<0 then
  437. exit;
  438. end;
  439. { now create the file }
  440. Result:=FileCreate(FileName,Rights);
  441. Result:=DoFileLocking(Result,ShareMode);
  442. end;
  443. Function FileRead (Handle : Longint; out Buffer; Count : longint) : Longint;
  444. begin
  445. repeat
  446. FileRead:=fpRead (Handle,Buffer,Count);
  447. until (FileRead<>-1) or (fpgeterrno<>ESysEINTR);
  448. end;
  449. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  450. begin
  451. repeat
  452. FileWrite:=fpWrite (Handle,Buffer,Count);
  453. until (FileWrite<>-1) or (fpgeterrno<>ESysEINTR);
  454. end;
  455. Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
  456. begin
  457. result:=longint(FileSeek(Handle,int64(FOffset),Origin));
  458. end;
  459. Function FileSeek (Handle : Longint; FOffset : Int64; Origin : Longint) : Int64;
  460. begin
  461. FileSeek:=fplSeek (Handle,FOffset,Origin);
  462. end;
  463. Procedure FileClose (Handle : Longint);
  464. var
  465. res: cint;
  466. begin
  467. repeat
  468. res:=fpclose(Handle);
  469. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  470. end;
  471. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  472. var
  473. res: cint;
  474. begin
  475. if (SizeOf (TOff) < 8) (* fpFTruncate only supporting signed 32-bit size *)
  476. and (Size > high (longint)) then
  477. FileTruncate := false
  478. else
  479. begin
  480. repeat
  481. res:=fpftruncate(Handle,Size);
  482. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  483. FileTruncate:=res>=0;
  484. end;
  485. end;
  486. Function FileAge (Const FileName : RawByteString): Longint;
  487. Var
  488. Info : Stat;
  489. SystemFileName: RawByteString;
  490. begin
  491. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  492. If (fpstat(pchar(SystemFileName),Info)<0) or fpS_ISDIR(info.st_mode) then
  493. exit(-1)
  494. else
  495. Result:=info.st_mtime;
  496. end;
  497. Function FileExists (Const FileName : RawByteString) : Boolean;
  498. var
  499. SystemFileName: RawByteString;
  500. begin
  501. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  502. // Don't use stat. It fails on files >2 GB.
  503. // Access obeys the same access rules, so the result should be the same.
  504. FileExists:=fpAccess(pointer(SystemFileName),F_OK)=0;
  505. end;
  506. Function DirectoryExists (Const Directory : RawByteString) : Boolean;
  507. Var
  508. Info : Stat;
  509. SystemFileName: RawByteString;
  510. begin
  511. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Directory);
  512. DirectoryExists:=(fpstat(pointer(SystemFileName),Info)>=0) and fpS_ISDIR(Info.st_mode);
  513. end;
  514. Function LinuxToWinAttr (const FN : RawByteString; Const Info : Stat) : Longint;
  515. Var
  516. LinkInfo : Stat;
  517. nm : RawByteString;
  518. begin
  519. Result:=faArchive;
  520. If fpS_ISDIR(Info.st_mode) then
  521. Result:=Result or faDirectory;
  522. nm:=ExtractFileName(FN);
  523. If (Length(nm)>=2) and
  524. (nm[1]='.') and
  525. (nm[2]<>'.') then
  526. Result:=Result or faHidden;
  527. If (Info.st_Mode and S_IWUSR)=0 Then
  528. Result:=Result or faReadOnly;
  529. 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
  530. Result:=Result or faSysFile;
  531. If fpS_ISLNK(Info.st_mode) Then
  532. begin
  533. Result:=Result or faSymLink;
  534. // Windows reports if the link points to a directory.
  535. if (fpstat(pchar(FN),LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then
  536. Result := Result or faDirectory;
  537. end;
  538. end;
  539. { assumes that pattern and name have the same code page }
  540. Function FNMatch(const Pattern,Name:string):Boolean;
  541. Var
  542. LenPat,LenName : longint;
  543. function NameUtf8CodePointLen(index: longint): longint;
  544. var
  545. MaxLookAhead: longint;
  546. begin
  547. MaxLookAhead:=LenName-Index+1;
  548. { abs so that in case of an invalid sequence, we count this as one
  549. codepoint }
  550. NameUtf8CodePointLen:=abs(Utf8CodePointLen(pansichar(@Name[index]),MaxLookAhead,true));
  551. { if the sequence was incomplete, use the incomplete sequence as
  552. codepoint }
  553. if NameUtf8CodePointLen=0 then
  554. NameUtf8CodePointLen:=MaxLookAhead;
  555. end;
  556. procedure GoToLastByteOfUtf8CodePoint(var j: longint);
  557. begin
  558. inc(j,NameUtf8CodePointLen(j)-1);
  559. end;
  560. { input:
  561. i: current position in pattern (start of utf-8 code point)
  562. j: current position in name (start of utf-8 code point)
  563. update_i_j: should i and j be changed by the routine or not
  564. output:
  565. i: if update_i_j, then position of last matching part of code point in
  566. pattern, or first non-matching code point in pattern. Otherwise the
  567. same value as on input.
  568. j: if update_i_j, then position of last matching part of code point in
  569. name, or first non-matching code point in name. Otherwise the
  570. same value as on input.
  571. result: true if match, false if no match
  572. }
  573. function CompareUtf8CodePoint(var i,j: longint; update_i_j: boolean): Boolean;
  574. var
  575. bytes,
  576. new_i,
  577. new_j: longint;
  578. begin
  579. bytes:=NameUtf8CodePointLen(j);
  580. new_i:=i;
  581. new_j:=j;
  582. { ensure that a part of an UTF-8 codepoint isn't interpreted
  583. as '*' or '?' }
  584. repeat
  585. dec(bytes);
  586. Result:=
  587. (new_j<=LenName) and
  588. (new_i<=LenPat) and
  589. (Pattern[new_i]=Name[new_j]);
  590. inc(new_i);
  591. inc(new_j);
  592. until not(Result) or
  593. (bytes=0);
  594. if update_i_j then
  595. begin
  596. i:=new_i;
  597. j:=new_j;
  598. end;
  599. end;
  600. Function DoFNMatch(i,j:longint):Boolean;
  601. Var
  602. UTF8, Found : boolean;
  603. Begin
  604. Found:=true;
  605. { ensure that we don't skip partial characters in UTF-8-encoded strings }
  606. UTF8:=StringCodePage(Name)=CP_UTF8;
  607. While Found and (i<=LenPat) Do
  608. Begin
  609. Case Pattern[i] of
  610. '?' :
  611. begin
  612. Found:=(j<=LenName);
  613. if UTF8 then
  614. GoToLastByteOfUtf8CodePoint(j);
  615. end;
  616. '*' : Begin
  617. {find the next character in pattern, different of ? and *}
  618. while Found do
  619. begin
  620. inc(i);
  621. if i>LenPat then
  622. Break;
  623. case Pattern[i] of
  624. '*' : ;
  625. '?' : begin
  626. if j>LenName then
  627. begin
  628. DoFNMatch:=false;
  629. Exit;
  630. end;
  631. if UTF8 then
  632. GoToLastByteOfUtf8CodePoint(j);
  633. inc(j);
  634. end;
  635. else
  636. Found:=false;
  637. end;
  638. end;
  639. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  640. { Now, find in name the character which i points to, if the * or
  641. ? wasn't the last character in the pattern, else, use up all
  642. the chars in name }
  643. Found:=false;
  644. if (i<=LenPat) then
  645. begin
  646. repeat
  647. {find a letter (not only first !) which maches pattern[i]}
  648. if UTF8 then
  649. begin
  650. while (j<=LenName) and
  651. ((name[j]<>pattern[i]) or
  652. not CompareUtf8CodePoint(i,j,false)) do
  653. begin
  654. GoToLastByteOfUtf8CodePoint(j);
  655. inc(j);
  656. end;
  657. end
  658. else
  659. begin
  660. while (j<=LenName) and (name[j]<>pattern[i]) do
  661. inc (j);
  662. end;
  663. if (j<LenName) then
  664. begin
  665. { while positions i/j have already been checked, in
  666. case of UTF-8 we have to ensure that we don't split
  667. a code point. Otherwise we can skip over comparing
  668. the same characters twice }
  669. if DoFnMatch(i+ord(not UTF8),j+ord(not UTF8)) then
  670. begin
  671. i:=LenPat;
  672. j:=LenName;{we can stop}
  673. Found:=true;
  674. Break;
  675. end
  676. { We didn't find one, need to look further }
  677. else
  678. begin
  679. if UTF8 then
  680. GoToLastByteOfUtf8CodePoint(j);
  681. inc(j);
  682. end;
  683. end
  684. else if j=LenName then
  685. begin
  686. Found:=true;
  687. Break;
  688. end;
  689. { This 'until' condition must be j>LenName, not j>=LenName.
  690. That's because when we 'need to look further' and
  691. j = LenName then loop must not terminate. }
  692. until (j>LenName);
  693. end
  694. else
  695. begin
  696. j:=LenName;{we can stop}
  697. Found:=true;
  698. end;
  699. end;
  700. #128..#255:
  701. begin
  702. Found:=(j<=LenName) and (pattern[i]=name[j]);
  703. if Found and UTF8 then
  704. begin
  705. { ensure that a part of an UTF-8 codepoint isn't matched with
  706. '*' or '?' }
  707. Found:=CompareUtf8CodePoint(i,j,true);
  708. { at this point, either Found is false (and we'll stop), or
  709. both pattern[i] and name[j] are the end of the current code
  710. point and equal }
  711. end
  712. end
  713. else {not a wildcard character in pattern}
  714. Found:=(j<=LenName) and (pattern[i]=name[j]);
  715. end;
  716. inc(i);
  717. inc(j);
  718. end;
  719. DoFnMatch:=Found and (j>LenName);
  720. end;
  721. Begin {start FNMatch}
  722. LenPat:=Length(Pattern);
  723. LenName:=Length(Name);
  724. FNMatch:=DoFNMatch(1,1);
  725. End;
  726. Type
  727. TUnixFindData = Record
  728. NamePos : LongInt; {to track which search this is}
  729. DirPtr : Pointer; {directory pointer for reading directory}
  730. SearchSpec : RawbyteString;
  731. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  732. SearchAttr : Byte; {attribute we are searching for}
  733. End;
  734. PUnixFindData = ^TUnixFindData;
  735. Procedure InternalFindClose(var Handle: Pointer);
  736. var
  737. D: PUnixFindData absolute Handle;
  738. begin
  739. If D=Nil then
  740. Exit;
  741. if D^.SearchType=0 then
  742. begin
  743. if D^.dirptr<>nil then
  744. fpclosedir(pdir(D^.dirptr)^);
  745. end;
  746. Dispose(D);
  747. D:=nil;
  748. end;
  749. Function FindGetFileInfo(const s: RawByteString; var f: TAbstractSearchRec; var Name: RawByteString):boolean;
  750. Var
  751. st : baseunix.stat;
  752. WinAttr : longint;
  753. begin
  754. if Assigned(f.FindHandle) and ( (PUnixFindData(F.FindHandle)^.searchattr and faSymlink) > 0) then
  755. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  756. else
  757. FindGetFileInfo:=(fpstat(pointer(s),st)=0);
  758. if not FindGetFileInfo then
  759. exit;
  760. WinAttr:=LinuxToWinAttr(s,st);
  761. FindGetFileInfo:=(WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0;
  762. if FindGetFileInfo then
  763. begin
  764. Name:=ExtractFileName(s);
  765. f.Attr:=WinAttr;
  766. f.Size:=st.st_Size;
  767. f.Mode:=st.st_mode;
  768. f.Time:=st.st_mtime;
  769. FindGetFileInfo:=true;
  770. end;
  771. end;
  772. // Returns the FOUND filename. Error code <> 0 if no file found
  773. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  774. Var
  775. DirName : RawByteString;
  776. FName,
  777. SName : RawBytestring;
  778. Found,
  779. Finished : boolean;
  780. p : pdirent;
  781. UnixFindData : PUnixFindData;
  782. Begin
  783. Result:=-1;
  784. UnixFindData:=PUnixFindData(Rslt.FindHandle);
  785. { SearchSpec='' means that there were no wild cards, so only one file to
  786. find.
  787. }
  788. If (UnixFindData=Nil) or (UnixFindData^.SearchSpec='') then
  789. exit;
  790. if (UnixFindData^.SearchType=0) and
  791. (UnixFindData^.Dirptr=nil) then
  792. begin
  793. If UnixFindData^.NamePos = 0 Then
  794. DirName:='./'
  795. Else
  796. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  797. UnixFindData^.DirPtr := fpopendir(Pchar(DirName));
  798. end;
  799. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  800. Found:=False;
  801. Finished:=(UnixFindData^.dirptr=nil);
  802. While Not Finished Do
  803. Begin
  804. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  805. if p=nil then
  806. FName:=''
  807. else
  808. FName:=p^.d_name;
  809. If FName='' Then
  810. Finished:=True
  811. Else
  812. Begin
  813. SetCodePage(FName,DefaultFileSystemCodePage,false);
  814. If FNMatch(SName,FName) Then
  815. Begin
  816. Found:=FindGetFileInfo(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Rslt,Name);
  817. if Found then
  818. begin
  819. Result:=0;
  820. exit;
  821. end;
  822. End;
  823. End;
  824. End;
  825. End;
  826. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  827. {
  828. opens dir and calls FindNext if needed.
  829. }
  830. var
  831. UnixFindData : PUnixFindData;
  832. Begin
  833. Result:=-1;
  834. { this is safe even though Rslt actually contains a refcounted field, because
  835. it is declared as "out" and hence has already been initialised }
  836. fillchar(Rslt,sizeof(Rslt),0);
  837. if Path='' then
  838. exit;
  839. { Allocate UnixFindData (we always need it, for the search attributes) }
  840. New(UnixFindData);
  841. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  842. Rslt.FindHandle:=UnixFindData;
  843. {We always also search for readonly and archive, regardless of Attr:}
  844. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  845. {Wildcards?}
  846. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  847. begin
  848. if FindGetFileInfo(ToSingleByteFileSystemEncodedFileName(Path),Rslt,Name) then
  849. Result:=0;
  850. end
  851. else
  852. begin
  853. {Create Info}
  854. UnixFindData^.SearchSpec := ToSingleByteFileSystemEncodedFileName(Path);
  855. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  856. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  857. dec(UnixFindData^.NamePos);
  858. Result:=InternalFindNext(Rslt,Name);
  859. end;
  860. If (Result<>0) then
  861. InternalFindClose(Rslt.FindHandle);
  862. End;
  863. Function FileGetDate (Handle : Longint) : Longint;
  864. Var Info : Stat;
  865. begin
  866. If (fpFStat(Handle,Info))<0 then
  867. Result:=-1
  868. else
  869. Result:=Info.st_Mtime;
  870. end;
  871. Function FileSetDate (Handle,Age : Longint) : Longint;
  872. begin
  873. // Impossible under Linux from FileHandle !!
  874. FileSetDate:=-1;
  875. end;
  876. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  877. Var
  878. SystemFileName: RawByteString;
  879. Info : Stat;
  880. res : Integer;
  881. begin
  882. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  883. res:=FpLStat(pointer(SystemFileName),Info);
  884. if res<0 then
  885. res:=FpStat(pointer(SystemFileName),Info);
  886. if res<0 then
  887. Result:=-1
  888. Else
  889. Result:=LinuxToWinAttr(SystemFileName,Info);
  890. end;
  891. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  892. begin
  893. Result:=-1;
  894. end;
  895. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  896. var
  897. SystemFileName: RawByteString;
  898. begin
  899. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  900. Result:=fpUnLink (pchar(SystemFileName))>=0;
  901. end;
  902. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  903. var
  904. SystemOldName, SystemNewName: RawByteString;
  905. begin
  906. SystemOldName:=ToSingleByteFileSystemEncodedFileName(OldName);
  907. SystemNewName:=ToSingleByteFileSystemEncodedFileName(NewName);
  908. RenameFile:=BaseUnix.FpRename(pointer(SystemOldName),pointer(SystemNewName))>=0;
  909. end;
  910. Function FileIsReadOnly(const FileName: RawByteString): Boolean;
  911. var
  912. SystemFileName: RawByteString;
  913. begin
  914. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  915. Result:=fpAccess(PChar(SystemFileName),W_OK)<>0;
  916. end;
  917. Function FileSetDate (Const FileName : RawByteString; Age : Longint) : Longint;
  918. var
  919. SystemFileName: RawByteString;
  920. t: TUTimBuf;
  921. begin
  922. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  923. Result:=0;
  924. t.actime:= Age;
  925. t.modtime:=Age;
  926. if fputime(PChar(SystemFileName), @t) = -1 then
  927. Result:=fpgeterrno;
  928. end;
  929. {****************************************************************************
  930. Disk Functions
  931. ****************************************************************************}
  932. {
  933. The Diskfree and Disksize functions need a file on the specified drive, since this
  934. is required for the fpstatfs system call.
  935. These filenames are set in drivestr[0..26], and have been preset to :
  936. 0 - '.' (default drive - hence current dir is ok.)
  937. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  938. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  939. 3 - '/' (C: equivalent of dos is the root partition)
  940. 4..26 (can be set by you're own applications)
  941. ! Use AddDisk() to Add new drives !
  942. They both return -1 when a failure occurs.
  943. }
  944. Const
  945. FixDriveStr : array[0..3] of pchar=(
  946. '.',
  947. '/fd0/.',
  948. '/fd1/.',
  949. '/.'
  950. );
  951. var
  952. Drives : byte = 4;
  953. DriveStr : array[4..26] of pchar;
  954. Function AddDisk(const path:string) : Byte;
  955. begin
  956. if not (DriveStr[Drives]=nil) then
  957. FreeMem(DriveStr[Drives]);
  958. GetMem(DriveStr[Drives],length(Path)+1);
  959. StrPCopy(DriveStr[Drives],path);
  960. Result:=Drives;
  961. inc(Drives);
  962. if Drives>26 then
  963. Drives:=4;
  964. end;
  965. Function DiskFree(Drive: Byte): int64;
  966. var
  967. fs : tstatfs;
  968. Begin
  969. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (fpstatfs(StrPas(fixdrivestr[drive]),@fs)<>-1)) or
  970. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (fpstatfs(StrPas(drivestr[drive]),@fs)<>-1)) then
  971. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  972. else
  973. Diskfree:=-1;
  974. End;
  975. Function DiskSize(Drive: Byte): int64;
  976. var
  977. fs : tstatfs;
  978. Begin
  979. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (fpstatfs(StrPas(fixdrivestr[drive]),@fs)<>-1)) or
  980. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (fpstatfs(StrPas(drivestr[drive]),@fs)<>-1)) then
  981. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  982. else
  983. DiskSize:=-1;
  984. End;
  985. Procedure FreeDriveStr;
  986. var
  987. i: longint;
  988. begin
  989. for i:=low(drivestr) to high(drivestr) do
  990. if assigned(drivestr[i]) then
  991. begin
  992. freemem(drivestr[i]);
  993. drivestr[i]:=nil;
  994. end;
  995. end;
  996. {****************************************************************************
  997. Misc Functions
  998. ****************************************************************************}
  999. {****************************************************************************
  1000. Locale Functions
  1001. ****************************************************************************}
  1002. Function GetEpochTime: cint;
  1003. {
  1004. Get the number of seconds since 00:00, January 1 1970, GMT
  1005. the time NOT corrected any way
  1006. }
  1007. begin
  1008. GetEpochTime:=fptime;
  1009. end;
  1010. // Now, adjusted to local time.
  1011. Procedure DoGetLocalDateTime(var year, month, day, hour, min, sec, msec, usec : word);
  1012. var
  1013. tz:timeval;
  1014. begin
  1015. fpgettimeofday(@tz,nil);
  1016. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  1017. msec:=tz.tv_usec div 1000;
  1018. usec:=tz.tv_usec mod 1000;
  1019. end;
  1020. procedure GetTime(var hour,min,sec,msec,usec:word);
  1021. Var
  1022. year,day,month:Word;
  1023. begin
  1024. DoGetLocalDateTime(year,month,day,hour,min,sec,msec,usec);
  1025. end;
  1026. procedure GetTime(var hour,min,sec,sec100:word);
  1027. {
  1028. Gets the current time, adjusted to local time
  1029. }
  1030. var
  1031. year,day,month,usec : word;
  1032. begin
  1033. DoGetLocalDateTime(year,month,day,hour,min,sec,sec100,usec);
  1034. sec100:=sec100 div 10;
  1035. end;
  1036. Procedure GetTime(Var Hour,Min,Sec:Word);
  1037. {
  1038. Gets the current time, adjusted to local time
  1039. }
  1040. var
  1041. year,day,month,msec,usec : Word;
  1042. Begin
  1043. DoGetLocalDateTime(year,month,day,hour,min,sec,msec,usec);
  1044. End;
  1045. Procedure GetDate(Var Year,Month,Day:Word);
  1046. {
  1047. Gets the current date, adjusted to local time
  1048. }
  1049. var
  1050. hour,minute,second,msec,usec : word;
  1051. Begin
  1052. DoGetLocalDateTime(year,month,day,hour,minute,second,msec,usec);
  1053. End;
  1054. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  1055. {
  1056. Gets the current date, adjusted to local time
  1057. }
  1058. Var
  1059. usec,msec : word;
  1060. Begin
  1061. DoGetLocalDateTime(year,month,day,hour,minute,second,msec,usec);
  1062. End;
  1063. {$ifndef FPUNONE}
  1064. Procedure GetLocalTime(var SystemTime: TSystemTime);
  1065. var
  1066. usecs : Word;
  1067. begin
  1068. DoGetLocalDateTime(SystemTime.Year, SystemTime.Month, SystemTime.Day,SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  1069. end ;
  1070. {$endif}
  1071. Procedure InitAnsi;
  1072. Var
  1073. i : longint;
  1074. begin
  1075. { Fill table entries 0 to 127 }
  1076. for i := 0 to 96 do
  1077. UpperCaseTable[i] := chr(i);
  1078. for i := 97 to 122 do
  1079. UpperCaseTable[i] := chr(i - 32);
  1080. for i := 123 to 191 do
  1081. UpperCaseTable[i] := chr(i);
  1082. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  1083. for i := 0 to 64 do
  1084. LowerCaseTable[i] := chr(i);
  1085. for i := 65 to 90 do
  1086. LowerCaseTable[i] := chr(i + 32);
  1087. for i := 91 to 191 do
  1088. LowerCaseTable[i] := chr(i);
  1089. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  1090. end;
  1091. Procedure InitInternational;
  1092. begin
  1093. InitInternationalGeneric;
  1094. InitAnsi;
  1095. end;
  1096. function SysErrorMessage(ErrorCode: Integer): String;
  1097. begin
  1098. Result:=StrError(ErrorCode);
  1099. end;
  1100. {****************************************************************************
  1101. OS utility functions
  1102. ****************************************************************************}
  1103. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  1104. begin
  1105. { no need to adjust the code page of EnvVar to DefaultSystemCodePage, as only
  1106. ASCII identifiers are supported }
  1107. Result:=BaseUnix.FPGetenv(PChar(pointer(EnvVar)));
  1108. end;
  1109. Function GetEnvironmentVariableCount : Integer;
  1110. begin
  1111. Result:=FPCCountEnvVar(EnvP);
  1112. end;
  1113. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  1114. begin
  1115. Result:=FPCGetEnvStrFromP(Envp,Index);
  1116. end;
  1117. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  1118. var
  1119. pid : longint;
  1120. e : EOSError;
  1121. CommandLine: RawByteString;
  1122. LPath : RawByteString;
  1123. cmdline2 : ppchar;
  1124. Begin
  1125. { always surround the name of the application by quotes
  1126. so that long filenames will always be accepted. But don't
  1127. do it if there are already double quotes!
  1128. }
  1129. // Only place we still parse
  1130. cmdline2:=nil;
  1131. LPath:=Path;
  1132. UniqueString(LPath);
  1133. SetCodePage(LPath,DefaultFileSystemCodePage,true);
  1134. if Comline<>'' Then
  1135. begin
  1136. CommandLine:=ComLine;
  1137. { Make an unique copy because stringtoppchar modifies the
  1138. string, and force conversion to intended fscp }
  1139. UniqueString(CommandLine);
  1140. SetCodePage(CommandLine,DefaultFileSystemCodePage,true);
  1141. cmdline2:=StringtoPPChar(CommandLine,1);
  1142. cmdline2^:=pchar(pointer(LPath));
  1143. end
  1144. else
  1145. begin
  1146. getmem(cmdline2,2*sizeof(pchar));
  1147. cmdline2^:=pchar(LPath);
  1148. cmdline2[1]:=nil;
  1149. end;
  1150. {$ifdef USE_VFORK}
  1151. pid:=fpvFork;
  1152. {$else USE_VFORK}
  1153. pid:=fpFork;
  1154. {$endif USE_VFORK}
  1155. if pid=0 then
  1156. begin
  1157. {The child does the actual exec, and then exits}
  1158. fpexecv(pchar(pointer(LPath)),Cmdline2);
  1159. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1160. fpExit(127);
  1161. end
  1162. else
  1163. if pid=-1 then {Fork failed}
  1164. begin
  1165. e:=EOSError.CreateFmt(SExecuteProcessFailed,[LPath,-1]);
  1166. e.ErrorCode:=-1;
  1167. raise e;
  1168. end;
  1169. { We're in the parent, let's wait. }
  1170. result:=WaitProcess(pid); // WaitPid and result-convert
  1171. if Comline<>'' Then
  1172. freemem(cmdline2);
  1173. if (result<0) or (result=127) then
  1174. begin
  1175. E:=EOSError.CreateFmt(SExecuteProcessFailed,[LPath,result]);
  1176. E.ErrorCode:=result;
  1177. Raise E;
  1178. end;
  1179. End;
  1180. function ExecuteProcess(Const Path: RawByteString; Const ComLine: Array Of RawByteString;Flags:TExecuteFlags=[]):integer;
  1181. var
  1182. pid : longint;
  1183. e : EOSError;
  1184. Begin
  1185. pid:=fpFork;
  1186. if pid=0 then
  1187. begin
  1188. {The child does the actual exec, and then exits}
  1189. fpexecl(Path,Comline);
  1190. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1191. fpExit(127);
  1192. end
  1193. else
  1194. if pid=-1 then {Fork failed}
  1195. begin
  1196. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1197. e.ErrorCode:=-1;
  1198. raise e;
  1199. end;
  1200. { We're in the parent, let's wait. }
  1201. result:=WaitProcess(pid); // WaitPid and result-convert
  1202. if (result<0) or (result=127) then
  1203. begin
  1204. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1205. E.ErrorCode:=result;
  1206. raise E;
  1207. end;
  1208. End;
  1209. procedure Sleep(milliseconds: Cardinal);
  1210. Var
  1211. timeout,timeoutresult : TTimespec;
  1212. res: cint;
  1213. begin
  1214. timeout.tv_sec:=milliseconds div 1000;
  1215. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  1216. repeat
  1217. res:=fpnanosleep(@timeout,@timeoutresult);
  1218. timeout:=timeoutresult;
  1219. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  1220. end;
  1221. Function GetLastOSError : Integer;
  1222. begin
  1223. Result:=fpgetErrNo;
  1224. end;
  1225. { ---------------------------------------------------------------------
  1226. Application config files
  1227. ---------------------------------------------------------------------}
  1228. Function GetHomeDir : String;
  1229. begin
  1230. Result:=GetEnvironmentVariable('HOME');
  1231. If (Result<>'') then
  1232. Result:=IncludeTrailingPathDelimiter(Result);
  1233. end;
  1234. { Follows base-dir spec,
  1235. see [http://freedesktop.org/Standards/basedir-spec].
  1236. Always ends with PathDelim. }
  1237. Function XdgConfigHome : String;
  1238. begin
  1239. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  1240. if (Result='') then
  1241. Result:=GetHomeDir + '.config/'
  1242. else
  1243. Result:=IncludeTrailingPathDelimiter(Result);
  1244. end;
  1245. Function GetAppConfigDir(Global : Boolean) : String;
  1246. begin
  1247. If Global then
  1248. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1249. else
  1250. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1251. if VendorName<>'' then
  1252. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1253. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1254. end;
  1255. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  1256. begin
  1257. If Global then
  1258. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1259. else
  1260. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1261. if SubDir then
  1262. begin
  1263. if VendorName<>'' then
  1264. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1265. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1266. end;
  1267. Result:=Result+ApplicationName+ConfigExtension;
  1268. end;
  1269. {****************************************************************************
  1270. GetTempDir
  1271. ****************************************************************************}
  1272. Function GetTempDir(Global : Boolean) : String;
  1273. begin
  1274. If Assigned(OnGetTempDir) then
  1275. Result:=OnGetTempDir(Global)
  1276. else
  1277. begin
  1278. Result:=GetEnvironmentVariable('TEMP');
  1279. If (Result='') Then
  1280. Result:=GetEnvironmentVariable('TMP');
  1281. If (Result='') Then
  1282. Result:=GetEnvironmentVariable('TMPDIR');
  1283. if (Result='') then
  1284. begin
  1285. // fallback.
  1286. {$ifdef android}
  1287. Result:='/data/local/tmp/';
  1288. {$else}
  1289. Result:='/tmp/';
  1290. {$endif android}
  1291. end;
  1292. end;
  1293. if (Result<>'') then
  1294. Result:=IncludeTrailingPathDelimiter(Result);
  1295. end;
  1296. {****************************************************************************
  1297. GetUserDir
  1298. ****************************************************************************}
  1299. Var
  1300. TheUserDir : String;
  1301. Function GetUserDir : String;
  1302. begin
  1303. If (TheUserDir='') then
  1304. begin
  1305. TheUserDir:=GetEnvironmentVariable('HOME');
  1306. if (TheUserDir<>'') then
  1307. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  1308. else
  1309. TheUserDir:=GetTempDir(False);
  1310. end;
  1311. Result:=TheUserDir;
  1312. end;
  1313. Procedure SysBeep;
  1314. begin
  1315. Write(#7);
  1316. Flush(Output);
  1317. end;
  1318. function GetLocalTimeOffset: Integer;
  1319. begin
  1320. Result := -Tzseconds div 60;
  1321. end;
  1322. {****************************************************************************
  1323. Initialization code
  1324. ****************************************************************************}
  1325. Initialization
  1326. InitExceptions; { Initialize exceptions. OS independent }
  1327. InitInternational; { Initialize internationalization settings }
  1328. SysConfigDir:='/etc'; { Initialize system config dir }
  1329. OnBeep:=@SysBeep;
  1330. Finalization
  1331. FreeDriveStr;
  1332. DoneExceptions;
  1333. end.