2
0

sysutils.pp 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  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. { force ansistrings }
  16. {$H+}
  17. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  18. {$define USE_VFORK}
  19. {$endif}
  20. {$DEFINE OS_FILESETDATEBYNAME}
  21. {$DEFINE HAS_SLEEP}
  22. {$DEFINE HAS_OSERROR}
  23. {$DEFINE HAS_OSCONFIG}
  24. {$DEFINE HAS_TEMPDIR}
  25. {$DEFINE HASUNIX}
  26. {$DEFINE HASCREATEGUID}
  27. {$DEFINE HAS_OSUSERDIR}
  28. uses
  29. Unix,errors,sysconst,Unixtype;
  30. { Include platform independent interface part }
  31. {$i sysutilh.inc}
  32. Function AddDisk(const path:string) : Byte;
  33. { the following is Kylix compatibility stuff, it should be moved to a
  34. special compatibilty unit (FK) }
  35. const
  36. RTL_SIGINT = 0;
  37. RTL_SIGFPE = 1;
  38. RTL_SIGSEGV = 2;
  39. RTL_SIGILL = 3;
  40. RTL_SIGBUS = 4;
  41. RTL_SIGQUIT = 5;
  42. RTL_SIGLAST = RTL_SIGQUIT;
  43. RTL_SIGDEFAULT = -1;
  44. type
  45. TSignalState = (ssNotHooked, ssHooked, ssOverridden);
  46. function InquireSignal(RtlSigNum: Integer): TSignalState;
  47. procedure AbandonSignalHandler(RtlSigNum: Integer);
  48. procedure HookSignal(RtlSigNum: Integer);
  49. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  50. implementation
  51. Uses
  52. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
  53. function InquireSignal(RtlSigNum: Integer): TSignalState;
  54. begin
  55. end;
  56. procedure AbandonSignalHandler(RtlSigNum: Integer);
  57. begin
  58. end;
  59. procedure HookSignal(RtlSigNum: Integer);
  60. begin
  61. end;
  62. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  63. begin
  64. end;
  65. {$Define OS_FILEISREADONLY} // Specific implementation for Unix.
  66. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  67. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  68. { Include platform independent implementation part }
  69. {$i sysutils.inc}
  70. { Include SysCreateGUID function }
  71. {$i suuid.inc}
  72. Const
  73. {Date Translation}
  74. C1970=2440588;
  75. D0 = 1461;
  76. D1 = 146097;
  77. D2 =1721119;
  78. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  79. Var
  80. YYear,XYear,Temp,TempMonth : LongInt;
  81. Begin
  82. Temp:=((JulianDN-D2) shl 2)-1;
  83. JulianDN:=Temp Div D1;
  84. XYear:=(Temp Mod D1) or 3;
  85. YYear:=(XYear Div D0);
  86. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  87. Day:=((Temp Mod 153)+5) Div 5;
  88. TempMonth:=Temp Div 153;
  89. If TempMonth>=10 Then
  90. Begin
  91. inc(YYear);
  92. dec(TempMonth,12);
  93. End;
  94. inc(TempMonth,3);
  95. Month := TempMonth;
  96. Year:=YYear+(JulianDN*100);
  97. end;
  98. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  99. {
  100. Transforms Epoch time into local time (hour, minute,seconds)
  101. }
  102. Var
  103. DateNum: LongInt;
  104. Begin
  105. inc(Epoch,TZSeconds);
  106. Datenum:=(Epoch Div 86400) + c1970;
  107. JulianToGregorian(DateNum,Year,Month,day);
  108. Epoch:=Abs(Epoch Mod 86400);
  109. Hour:=Epoch Div 3600;
  110. Epoch:=Epoch Mod 3600;
  111. Minute:=Epoch Div 60;
  112. Second:=Epoch Mod 60;
  113. End;
  114. {****************************************************************************
  115. File Functions
  116. ****************************************************************************}
  117. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  118. Var
  119. DotPos,SlashPos,i : longint;
  120. Begin
  121. SlashPos:=0;
  122. DotPos:=256;
  123. i:=Length(Path);
  124. While (i>0) and (SlashPos=0) Do
  125. Begin
  126. If (DotPos=256) and (Path[i]='.') Then
  127. begin
  128. DotPos:=i;
  129. end;
  130. If (Path[i]='/') Then
  131. SlashPos:=i;
  132. Dec(i);
  133. End;
  134. Ext:=Copy(Path,DotPos,255);
  135. Dir:=Copy(Path,1,SlashPos);
  136. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  137. End;
  138. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  139. Var LinuxFlags : longint;
  140. BEGIN
  141. LinuxFlags:=0;
  142. Case (Mode and 3) of
  143. 0 : LinuxFlags:=LinuxFlags or O_RdOnly;
  144. 1 : LinuxFlags:=LinuxFlags or O_WrOnly;
  145. 2 : LinuxFlags:=LinuxFlags or O_RdWr;
  146. end;
  147. FileOpen:=fpOpen (pointer(FileName),LinuxFlags);
  148. //!! We need to set locking based on Mode !!
  149. end;
  150. Function FileCreate (Const FileName : String) : Longint;
  151. begin
  152. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc);
  153. end;
  154. Function FileCreate (Const FileName : String;Mode : Longint) : Longint;
  155. BEGIN
  156. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc,Mode);
  157. end;
  158. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  159. begin
  160. FileRead:=fpRead (Handle,Buffer,Count);
  161. end;
  162. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  163. begin
  164. FileWrite:=fpWrite (Handle,Buffer,Count);
  165. end;
  166. Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
  167. begin
  168. result:=longint(FileSeek(Handle,int64(FOffset),Origin));
  169. end;
  170. Function FileSeek (Handle : Longint; FOffset : Int64; Origin : Longint) : Int64;
  171. begin
  172. FileSeek:=fplSeek (Handle,FOffset,Origin);
  173. end;
  174. Procedure FileClose (Handle : Longint);
  175. begin
  176. fpclose(Handle);
  177. end;
  178. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  179. begin
  180. if (SizeOf (TOff) < 8) (* fpFTruncate only supporting signed 32-bit size *)
  181. and (Size > high (longint)) then
  182. FileTruncate := false
  183. else
  184. FileTruncate:=fpftruncate(Handle,Size)>=0;
  185. end;
  186. Function UnixToWinAge(UnixAge : time_t): Longint;
  187. Var
  188. Y,M,D,hh,mm,ss : word;
  189. begin
  190. EpochToLocal(UnixAge,y,m,d,hh,mm,ss);
  191. Result:=DateTimeToFileDate(EncodeDate(y,m,d)+EncodeTime(hh,mm,ss,0));
  192. end;
  193. Function FileAge (Const FileName : String): Longint;
  194. Var Info : Stat;
  195. begin
  196. If fpstat (pointer(FileName),Info)<0 then
  197. exit(-1)
  198. else
  199. Result:=UnixToWinAge(info.st_mtime);
  200. end;
  201. Function FileExists (Const FileName : String) : Boolean;
  202. begin
  203. // Don't use stat. It fails on files >2 GB.
  204. // Access obeys the same access rules, so the result should be the same.
  205. FileExists:=fpAccess(pointer(filename),F_OK)=0;
  206. end;
  207. Function DirectoryExists (Const Directory : String) : Boolean;
  208. Var Info : Stat;
  209. begin
  210. DirectoryExists:=(fpstat(pointer(Directory),Info)>=0) and fpS_ISDIR(Info.st_mode);
  211. end;
  212. Function LinuxToWinAttr (FN : Pchar; Const Info : Stat) : Longint;
  213. Var
  214. FNL : String;
  215. LinkInfo : Stat;
  216. begin
  217. Result:=faArchive;
  218. If fpS_ISDIR(Info.st_mode) then
  219. Result:=Result or faDirectory;
  220. If (FN[0]='.') and (not (FN[1] in [#0,'.'])) then
  221. Result:=Result or faHidden;
  222. If (Info.st_Mode and S_IWUSR)=0 Then
  223. Result:=Result or faReadOnly;
  224. 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
  225. Result:=Result or faSysFile;
  226. If fpS_ISLNK(Info.st_mode) Then
  227. begin
  228. Result:=Result or faSymLink;
  229. // Windows reports if the link points to a directory.
  230. FNL:=StrPas(FN);
  231. if (fpstat(FNL,LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then
  232. Result := Result or faDirectory;
  233. end;
  234. end;
  235. Function FNMatch(const Pattern,Name:string):Boolean;
  236. Var
  237. LenPat,LenName : longint;
  238. Function DoFNMatch(i,j:longint):Boolean;
  239. Var
  240. Found : boolean;
  241. Begin
  242. Found:=true;
  243. While Found and (i<=LenPat) Do
  244. Begin
  245. Case Pattern[i] of
  246. '?' : Found:=(j<=LenName);
  247. '*' : Begin
  248. {find the next character in pattern, different of ? and *}
  249. while Found do
  250. begin
  251. inc(i);
  252. if i>LenPat then Break;
  253. case Pattern[i] of
  254. '*' : ;
  255. '?' : begin
  256. if j>LenName then begin DoFNMatch:=false; Exit; end;
  257. inc(j);
  258. end;
  259. else
  260. Found:=false;
  261. end;
  262. end;
  263. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  264. {Now, find in name the character which i points to, if the * or ?
  265. wasn't the last character in the pattern, else, use up all the
  266. chars in name}
  267. Found:=false;
  268. if (i<=LenPat) then
  269. begin
  270. repeat
  271. {find a letter (not only first !) which maches pattern[i]}
  272. while (j<=LenName) and (name[j]<>pattern[i]) do
  273. inc (j);
  274. if (j<LenName) then
  275. begin
  276. if DoFnMatch(i+1,j+1) then
  277. begin
  278. i:=LenPat;
  279. j:=LenName;{we can stop}
  280. Found:=true;
  281. Break;
  282. end else
  283. inc(j);{We didn't find one, need to look further}
  284. end else
  285. if j=LenName then
  286. begin
  287. Found:=true;
  288. Break;
  289. end;
  290. { This 'until' condition must be j>LenName, not j>=LenName.
  291. That's because when we 'need to look further' and
  292. j = LenName then loop must not terminate. }
  293. until (j>LenName);
  294. end else
  295. begin
  296. j:=LenName;{we can stop}
  297. Found:=true;
  298. end;
  299. end;
  300. else {not a wildcard character in pattern}
  301. Found:=(j<=LenName) and (pattern[i]=name[j]);
  302. end;
  303. inc(i);
  304. inc(j);
  305. end;
  306. DoFnMatch:=Found and (j>LenName);
  307. end;
  308. Begin {start FNMatch}
  309. LenPat:=Length(Pattern);
  310. LenName:=Length(Name);
  311. FNMatch:=DoFNMatch(1,1);
  312. End;
  313. Type
  314. TUnixFindData = Record
  315. NamePos : LongInt; {to track which search this is}
  316. DirPtr : Pointer; {directory pointer for reading directory}
  317. SearchSpec : String;
  318. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  319. SearchAttr : Byte; {attribute we are searching for}
  320. End;
  321. PUnixFindData = ^TUnixFindData;
  322. Var
  323. CurrSearchNum : LongInt;
  324. Procedure FindClose(Var f: TSearchRec);
  325. var
  326. UnixFindData : PUnixFindData;
  327. Begin
  328. UnixFindData:=PUnixFindData(f.FindHandle);
  329. if UnixFindData=nil then
  330. exit;
  331. if UnixFindData^.SearchType=0 then
  332. begin
  333. if UnixFindData^.dirptr<>nil then
  334. fpclosedir(pdir(UnixFindData^.dirptr)^);
  335. end;
  336. Dispose(UnixFindData);
  337. f.FindHandle:=nil;
  338. End;
  339. Function FindGetFileInfo(const s:string;var f:TSearchRec):boolean;
  340. var
  341. st : baseunix.stat;
  342. WinAttr : longint;
  343. begin
  344. FindGetFileInfo:=false;
  345. If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  346. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  347. else
  348. FindGetFileInfo:=(fpstat(pointer(s),st)=0);
  349. If not FindGetFileInfo then
  350. exit;
  351. WinAttr:=LinuxToWinAttr(PChar(pointer(s)),st);
  352. If (f.FindHandle = nil) or ((WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0) Then
  353. Begin
  354. f.Name:=ExtractFileName(s);
  355. f.Attr:=WinAttr;
  356. f.Size:=st.st_Size;
  357. f.Mode:=st.st_mode;
  358. f.Time:=UnixToWinAge(st.st_mtime);
  359. result:=true;
  360. End;
  361. end;
  362. Function FindNext (Var Rslt : TSearchRec) : Longint;
  363. {
  364. re-opens dir if not already in array and calls FindGetFileInfo
  365. }
  366. Var
  367. DirName : String;
  368. FName,
  369. SName : string;
  370. Found,
  371. Finished : boolean;
  372. p : pdirent;
  373. UnixFindData : PUnixFindData;
  374. Begin
  375. Result:=-1;
  376. UnixFindData:=PUnixFindData(Rslt.FindHandle);
  377. if UnixFindData=nil then
  378. exit;
  379. if (UnixFindData^.SearchType=0) and
  380. (UnixFindData^.Dirptr=nil) then
  381. begin
  382. If UnixFindData^.NamePos = 0 Then
  383. DirName:='./'
  384. Else
  385. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  386. UnixFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  387. end;
  388. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  389. Found:=False;
  390. Finished:=(UnixFindData^.dirptr=nil);
  391. While Not Finished Do
  392. Begin
  393. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  394. if p=nil then
  395. FName:=''
  396. else
  397. FName:=p^.d_name;
  398. If FName='' Then
  399. Finished:=True
  400. Else
  401. Begin
  402. If FNMatch(SName,FName) Then
  403. Begin
  404. Found:=FindGetFileInfo(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Rslt);
  405. if Found then
  406. begin
  407. Result:=0;
  408. exit;
  409. end;
  410. End;
  411. End;
  412. End;
  413. End;
  414. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  415. {
  416. opens dir and calls FindNext if needed.
  417. }
  418. var
  419. UnixFindData : PUnixFindData;
  420. Begin
  421. Result:=-1;
  422. fillchar(Rslt,sizeof(Rslt),0);
  423. if Path='' then
  424. exit;
  425. {Wildcards?}
  426. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  427. begin
  428. if FindGetFileInfo(Path,Rslt) then
  429. Result:=0;
  430. end
  431. else
  432. begin
  433. { Allocate UnixFindData }
  434. New(UnixFindData);
  435. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  436. Rslt.FindHandle:=UnixFindData;
  437. {Create Info}
  438. UnixFindData^.SearchSpec := Path;
  439. {We always also search for readonly and archive, regardless of Attr:}
  440. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  441. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  442. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  443. dec(UnixFindData^.NamePos);
  444. Result:=FindNext(Rslt);
  445. end;
  446. End;
  447. Function FileGetDate (Handle : Longint) : Longint;
  448. Var Info : Stat;
  449. begin
  450. If (fpFStat(Handle,Info))<0 then
  451. Result:=-1
  452. else
  453. Result:=Info.st_Mtime;
  454. end;
  455. Function FileSetDate (Handle,Age : Longint) : Longint;
  456. begin
  457. // Impossible under Linux from FileHandle !!
  458. FileSetDate:=-1;
  459. end;
  460. Function FileGetAttr (Const FileName : String) : Longint;
  461. Var Info : Stat;
  462. begin
  463. If FpStat (pointer(FileName),Info)<0 then
  464. Result:=-1
  465. Else
  466. Result:=LinuxToWinAttr(Pchar(ExtractFileName(FileName)),Info);
  467. end;
  468. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  469. begin
  470. Result:=-1;
  471. end;
  472. Function DeleteFile (Const FileName : String) : Boolean;
  473. begin
  474. Result:=fpUnLink (pointer(FileName))>=0;
  475. end;
  476. Function RenameFile (Const OldName, NewName : String) : Boolean;
  477. begin
  478. RenameFile:=BaseUnix.FpRename(pointer(OldNAme),pointer(NewName))>=0;
  479. end;
  480. Function FileIsReadOnly(const FileName: String): Boolean;
  481. begin
  482. Result := fpAccess(PChar(pointer(FileName)),W_OK)<>0;
  483. end;
  484. Function FileSetDate (Const FileName : String;Age : Longint) : Longint;
  485. var
  486. t: TUTimBuf;
  487. begin
  488. Result := 0;
  489. t.actime := Age;
  490. t.modtime := Age;
  491. if fputime(PChar(pointer(FileName)), @t) = -1 then
  492. Result := fpgeterrno;
  493. end;
  494. {****************************************************************************
  495. Disk Functions
  496. ****************************************************************************}
  497. {
  498. The Diskfree and Disksize functions need a file on the specified drive, since this
  499. is required for the statfs system call.
  500. These filenames are set in drivestr[0..26], and have been preset to :
  501. 0 - '.' (default drive - hence current dir is ok.)
  502. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  503. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  504. 3 - '/' (C: equivalent of dos is the root partition)
  505. 4..26 (can be set by you're own applications)
  506. ! Use AddDisk() to Add new drives !
  507. They both return -1 when a failure occurs.
  508. }
  509. Const
  510. FixDriveStr : array[0..3] of pchar=(
  511. '.',
  512. '/fd0/.',
  513. '/fd1/.',
  514. '/.'
  515. );
  516. var
  517. Drives : byte;
  518. DriveStr : array[4..26] of pchar;
  519. Function AddDisk(const path:string) : Byte;
  520. begin
  521. if not (DriveStr[Drives]=nil) then
  522. FreeMem(DriveStr[Drives],StrLen(DriveStr[Drives])+1);
  523. GetMem(DriveStr[Drives],length(Path)+1);
  524. StrPCopy(DriveStr[Drives],path);
  525. inc(Drives);
  526. if Drives>26 then
  527. Drives:=4;
  528. Result:=Drives;
  529. end;
  530. Function DiskFree(Drive: Byte): int64;
  531. var
  532. fs : tstatfs;
  533. Begin
  534. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  535. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  536. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  537. else
  538. Diskfree:=-1;
  539. End;
  540. Function DiskSize(Drive: Byte): int64;
  541. var
  542. fs : tstatfs;
  543. Begin
  544. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  545. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  546. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  547. else
  548. DiskSize:=-1;
  549. End;
  550. Function GetCurrentDir : String;
  551. begin
  552. GetDir (0,Result);
  553. end;
  554. Function SetCurrentDir (Const NewDir : String) : Boolean;
  555. begin
  556. {$I-}
  557. ChDir(NewDir);
  558. {$I+}
  559. result := (IOResult = 0);
  560. end;
  561. Function CreateDir (Const NewDir : String) : Boolean;
  562. begin
  563. {$I-}
  564. MkDir(NewDir);
  565. {$I+}
  566. result := (IOResult = 0);
  567. end;
  568. Function RemoveDir (Const Dir : String) : Boolean;
  569. begin
  570. {$I-}
  571. RmDir(Dir);
  572. {$I+}
  573. result := (IOResult = 0);
  574. end;
  575. {****************************************************************************
  576. Misc Functions
  577. ****************************************************************************}
  578. procedure Beep;
  579. begin
  580. end;
  581. {****************************************************************************
  582. Locale Functions
  583. ****************************************************************************}
  584. Function GetEpochTime: cint;
  585. {
  586. Get the number of seconds since 00:00, January 1 1970, GMT
  587. the time NOT corrected any way
  588. }
  589. begin
  590. GetEpochTime:=fptime;
  591. end;
  592. procedure GetTime(var hour,min,sec,msec,usec:word);
  593. {
  594. Gets the current time, adjusted to local time
  595. }
  596. var
  597. year,day,month:Word;
  598. tz:timeval;
  599. begin
  600. fpgettimeofday(@tz,nil);
  601. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  602. msec:=tz.tv_usec div 1000;
  603. usec:=tz.tv_usec mod 1000;
  604. end;
  605. procedure GetTime(var hour,min,sec,sec100:word);
  606. {
  607. Gets the current time, adjusted to local time
  608. }
  609. var
  610. usec : word;
  611. begin
  612. gettime(hour,min,sec,sec100,usec);
  613. sec100:=sec100 div 10;
  614. end;
  615. Procedure GetTime(Var Hour,Min,Sec:Word);
  616. {
  617. Gets the current time, adjusted to local time
  618. }
  619. var
  620. msec,usec : Word;
  621. Begin
  622. gettime(hour,min,sec,msec,usec);
  623. End;
  624. Procedure GetDate(Var Year,Month,Day:Word);
  625. {
  626. Gets the current date, adjusted to local time
  627. }
  628. var
  629. hour,minute,second : word;
  630. Begin
  631. EpochToLocal(fptime,year,month,day,hour,minute,second);
  632. End;
  633. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  634. {
  635. Gets the current date, adjusted to local time
  636. }
  637. Begin
  638. EpochToLocal(fptime,year,month,day,hour,minute,second);
  639. End;
  640. Procedure GetLocalTime(var SystemTime: TSystemTime);
  641. var
  642. usecs : Word;
  643. begin
  644. GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  645. GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
  646. // SystemTime.MilliSecond := 0;
  647. end ;
  648. Procedure InitAnsi;
  649. Var
  650. i : longint;
  651. begin
  652. { Fill table entries 0 to 127 }
  653. for i := 0 to 96 do
  654. UpperCaseTable[i] := chr(i);
  655. for i := 97 to 122 do
  656. UpperCaseTable[i] := chr(i - 32);
  657. for i := 123 to 191 do
  658. UpperCaseTable[i] := chr(i);
  659. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  660. for i := 0 to 64 do
  661. LowerCaseTable[i] := chr(i);
  662. for i := 65 to 90 do
  663. LowerCaseTable[i] := chr(i + 32);
  664. for i := 91 to 191 do
  665. LowerCaseTable[i] := chr(i);
  666. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  667. end;
  668. Procedure InitInternational;
  669. begin
  670. InitInternationalGeneric;
  671. InitAnsi;
  672. end;
  673. function SysErrorMessage(ErrorCode: Integer): String;
  674. begin
  675. Result:=StrError(ErrorCode);
  676. end;
  677. {****************************************************************************
  678. OS utility functions
  679. ****************************************************************************}
  680. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  681. begin
  682. Result:=StrPas(BaseUnix.FPGetenv(PChar(pointer(EnvVar))));
  683. end;
  684. Function GetEnvironmentVariableCount : Integer;
  685. begin
  686. Result:=FPCCountEnvVar(EnvP);
  687. end;
  688. Function GetEnvironmentString(Index : Integer) : String;
  689. begin
  690. Result:=FPCGetEnvStrFromP(Envp,Index);
  691. end;
  692. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
  693. var
  694. pid : longint;
  695. e : EOSError;
  696. CommandLine: AnsiString;
  697. cmdline2 : ppchar;
  698. Begin
  699. { always surround the name of the application by quotes
  700. so that long filenames will always be accepted. But don't
  701. do it if there are already double quotes!
  702. }
  703. // Only place we still parse
  704. cmdline2:=nil;
  705. if Comline<>'' Then
  706. begin
  707. CommandLine:=ComLine;
  708. { Make an unique copy because stringtoppchar modifies the
  709. string }
  710. UniqueString(CommandLine);
  711. cmdline2:=StringtoPPChar(CommandLine,1);
  712. cmdline2^:=pchar(pointer(Path));
  713. end
  714. else
  715. begin
  716. getmem(cmdline2,2*sizeof(pchar));
  717. cmdline2^:=pchar(Path);
  718. cmdline2[1]:=nil;
  719. end;
  720. {$ifdef USE_VFORK}
  721. pid:=fpvFork;
  722. {$else USE_VFORK}
  723. pid:=fpFork;
  724. {$endif USE_VFORK}
  725. if pid=0 then
  726. begin
  727. {The child does the actual exec, and then exits}
  728. fpexecv(pchar(pointer(Path)),Cmdline2);
  729. { If the execve fails, we return an exitvalue of 127, to let it be known}
  730. fpExit(127);
  731. end
  732. else
  733. if pid=-1 then {Fork failed}
  734. begin
  735. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  736. e.ErrorCode:=-1;
  737. raise e;
  738. end;
  739. { We're in the parent, let's wait. }
  740. result:=WaitProcess(pid); // WaitPid and result-convert
  741. if Comline<>'' Then
  742. freemem(cmdline2);
  743. if (result<0) or (result=127) then
  744. begin
  745. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  746. E.ErrorCode:=result;
  747. Raise E;
  748. end;
  749. End;
  750. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString):integer;
  751. var
  752. pid : longint;
  753. e : EOSError;
  754. Begin
  755. pid:=fpFork;
  756. if pid=0 then
  757. begin
  758. {The child does the actual exec, and then exits}
  759. fpexecl(Path,Comline);
  760. { If the execve fails, we return an exitvalue of 127, to let it be known}
  761. fpExit(127);
  762. end
  763. else
  764. if pid=-1 then {Fork failed}
  765. begin
  766. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  767. e.ErrorCode:=-1;
  768. raise e;
  769. end;
  770. { We're in the parent, let's wait. }
  771. result:=WaitProcess(pid); // WaitPid and result-convert
  772. if (result<0) or (result=127) then
  773. begin
  774. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  775. E.ErrorCode:=result;
  776. raise E;
  777. end;
  778. End;
  779. procedure Sleep(milliseconds: Cardinal);
  780. Var
  781. timeout,timeoutresult : TTimespec;
  782. begin
  783. timeout.tv_sec:=milliseconds div 1000;
  784. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  785. fpnanosleep(@timeout,@timeoutresult);
  786. end;
  787. Function GetLastOSError : Integer;
  788. begin
  789. Result:=fpgetErrNo;
  790. end;
  791. { ---------------------------------------------------------------------
  792. Application config files
  793. ---------------------------------------------------------------------}
  794. Function GetHomeDir : String;
  795. begin
  796. Result:=GetEnvironmentVariable('HOME');
  797. If (Result<>'') then
  798. Result:=IncludeTrailingPathDelimiter(Result);
  799. end;
  800. { Follows base-dir spec,
  801. see [http://freedesktop.org/Standards/basedir-spec].
  802. Always ends with PathDelim. }
  803. Function XdgConfigHome : String;
  804. begin
  805. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  806. if (Result='') then
  807. Result:=GetHomeDir + '.config/'
  808. else
  809. Result:=IncludeTrailingPathDelimiter(Result);
  810. end;
  811. Function GetAppConfigDir(Global : Boolean) : String;
  812. begin
  813. If Global then
  814. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  815. else
  816. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  817. if VendorName<>'' then
  818. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  819. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  820. end;
  821. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  822. begin
  823. If Global then
  824. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  825. else
  826. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  827. if SubDir then
  828. begin
  829. if VendorName<>'' then
  830. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  831. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  832. end;
  833. Result:=Result+ApplicationName+ConfigExtension;
  834. end;
  835. {****************************************************************************
  836. GetTempDir
  837. ****************************************************************************}
  838. Function GetTempDir(Global : Boolean) : String;
  839. begin
  840. If Assigned(OnGetTempDir) then
  841. Result:=OnGetTempDir(Global)
  842. else
  843. begin
  844. Result:=GetEnvironmentVariable('TEMP');
  845. If (Result='') Then
  846. Result:=GetEnvironmentVariable('TMP');
  847. if (Result='') then
  848. Result:='/tmp/' // fallback.
  849. end;
  850. if (Result<>'') then
  851. Result:=IncludeTrailingPathDelimiter(Result);
  852. end;
  853. {****************************************************************************
  854. GetUserDir
  855. ****************************************************************************}
  856. Var
  857. TheUserDir : String;
  858. Function GetUserDir : String;
  859. begin
  860. If (TheUserDir='') then
  861. begin
  862. TheUserDir:=GetEnvironmentVariable('HOME');
  863. if (TheUserDir<>'') then
  864. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  865. else
  866. TheUserDir:=GetTempDir(False);
  867. end;
  868. Result:=TheUserDir;
  869. end;
  870. {****************************************************************************
  871. Initialization code
  872. ****************************************************************************}
  873. Initialization
  874. InitExceptions; { Initialize exceptions. OS independent }
  875. InitInternational; { Initialize internationalization settings }
  876. SysConfigDir:='/etc'; { Initialize system config dir }
  877. Finalization
  878. DoneExceptions;
  879. end.