sysutils.pp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  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 DoFileLocking(Handle: Longint; Mode: Integer) : Longint;
  139. var
  140. lockop: cint;
  141. lockres: cint;
  142. begin
  143. DoFileLocking:=Handle;
  144. {$ifdef beos}
  145. {$else}
  146. if (Handle>=0) then
  147. begin
  148. {$ifdef solaris}
  149. { Solaris' flock is based on top of fcntl, which does not allow
  150. exclusive locks for files only opened for reading nor shared
  151. locks for files opened only for writing.
  152. If no locking is specified, we normally need an exclusive lock.
  153. So create an exclusive lock for fmOpenWrite and fmOpenReadWrite,
  154. but only a shared lock for fmOpenRead (since an exclusive lock
  155. is not possible in that case)
  156. }
  157. if ((mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) = 0) then
  158. begin
  159. if ((mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) = fmOpenRead) then
  160. mode := mode or fmShareDenyWrite
  161. else
  162. mode := mode or fmShareExclusive;
  163. end;
  164. {$endif solaris}
  165. case (mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) of
  166. fmShareCompat,
  167. fmShareExclusive:
  168. lockop:=LOCK_EX or LOCK_NB;
  169. fmShareDenyWrite:
  170. lockop:=LOCK_SH or LOCK_NB;
  171. fmShareDenyNone:
  172. exit;
  173. else
  174. begin
  175. { fmShareDenyRead does not exit under *nix, only shared access
  176. (similar to fmShareDenyWrite) and exclusive access (same as
  177. fmShareExclusive)
  178. }
  179. FpClose(Handle);
  180. DoFileLocking:=-1;
  181. exit;
  182. end;
  183. end;
  184. repeat
  185. lockres:=fpflock(Handle,lockop);
  186. until (lockres=0) or
  187. (fpgeterrno<>ESysEIntr);
  188. if (lockres<>0) then
  189. begin
  190. FpClose(Handle);
  191. DoFileLocking:=-1;
  192. exit;
  193. end;
  194. end;
  195. {$endif not beos}
  196. end;
  197. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  198. Var
  199. LinuxFlags : longint;
  200. begin
  201. LinuxFlags:=0;
  202. case (Mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) of
  203. fmOpenRead : LinuxFlags:=LinuxFlags or O_RdOnly;
  204. fmOpenWrite : LinuxFlags:=LinuxFlags or O_WrOnly;
  205. fmOpenReadWrite : LinuxFlags:=LinuxFlags or O_RdWr;
  206. end;
  207. FileOpen:=fpOpen (pointer(FileName),LinuxFlags);
  208. FileOpen:=DoFileLocking(FileOpen, Mode);
  209. end;
  210. Function FileCreate (Const FileName : String) : Longint;
  211. begin
  212. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc);
  213. end;
  214. Function FileCreate (Const FileName : String;Mode : Longint) : Longint;
  215. begin
  216. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc,Mode);
  217. end;
  218. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  219. begin
  220. FileRead:=fpRead (Handle,Buffer,Count);
  221. end;
  222. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  223. begin
  224. FileWrite:=fpWrite (Handle,Buffer,Count);
  225. end;
  226. Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
  227. begin
  228. result:=longint(FileSeek(Handle,int64(FOffset),Origin));
  229. end;
  230. Function FileSeek (Handle : Longint; FOffset : Int64; Origin : Longint) : Int64;
  231. begin
  232. FileSeek:=fplSeek (Handle,FOffset,Origin);
  233. end;
  234. Procedure FileClose (Handle : Longint);
  235. begin
  236. fpclose(Handle);
  237. end;
  238. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  239. begin
  240. if (SizeOf (TOff) < 8) (* fpFTruncate only supporting signed 32-bit size *)
  241. and (Size > high (longint)) then
  242. FileTruncate := false
  243. else
  244. FileTruncate:=fpftruncate(Handle,Size)>=0;
  245. end;
  246. {$ifndef FPUNONE}
  247. Function UnixToWinAge(UnixAge : time_t): Longint;
  248. Var
  249. Y,M,D,hh,mm,ss : word;
  250. begin
  251. EpochToLocal(UnixAge,y,m,d,hh,mm,ss);
  252. Result:=DateTimeToFileDate(EncodeDate(y,m,d)+EncodeTime(hh,mm,ss,0));
  253. end;
  254. Function FileAge (Const FileName : String): Longint;
  255. Var Info : Stat;
  256. begin
  257. If fpstat (pointer(FileName),Info)<0 then
  258. exit(-1)
  259. else
  260. Result:=UnixToWinAge(info.st_mtime);
  261. end;
  262. {$endif}
  263. Function FileExists (Const FileName : String) : Boolean;
  264. begin
  265. // Don't use stat. It fails on files >2 GB.
  266. // Access obeys the same access rules, so the result should be the same.
  267. FileExists:=fpAccess(pointer(filename),F_OK)=0;
  268. end;
  269. Function DirectoryExists (Const Directory : String) : Boolean;
  270. Var Info : Stat;
  271. begin
  272. DirectoryExists:=(fpstat(pointer(Directory),Info)>=0) and fpS_ISDIR(Info.st_mode);
  273. end;
  274. Function LinuxToWinAttr (FN : Pchar; Const Info : Stat) : Longint;
  275. Var
  276. FNL : String;
  277. LinkInfo : Stat;
  278. begin
  279. Result:=faArchive;
  280. If fpS_ISDIR(Info.st_mode) then
  281. Result:=Result or faDirectory;
  282. If (FN[0]='.') and (not (FN[1] in [#0,'.'])) then
  283. Result:=Result or faHidden;
  284. If (Info.st_Mode and S_IWUSR)=0 Then
  285. Result:=Result or faReadOnly;
  286. 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
  287. Result:=Result or faSysFile;
  288. If fpS_ISLNK(Info.st_mode) Then
  289. begin
  290. Result:=Result or faSymLink;
  291. // Windows reports if the link points to a directory.
  292. FNL:=StrPas(FN);
  293. if (fpstat(FNL,LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then
  294. Result := Result or faDirectory;
  295. end;
  296. end;
  297. Function FNMatch(const Pattern,Name:string):Boolean;
  298. Var
  299. LenPat,LenName : longint;
  300. Function DoFNMatch(i,j:longint):Boolean;
  301. Var
  302. Found : boolean;
  303. Begin
  304. Found:=true;
  305. While Found and (i<=LenPat) Do
  306. Begin
  307. Case Pattern[i] of
  308. '?' : Found:=(j<=LenName);
  309. '*' : Begin
  310. {find the next character in pattern, different of ? and *}
  311. while Found do
  312. begin
  313. inc(i);
  314. if i>LenPat then Break;
  315. case Pattern[i] of
  316. '*' : ;
  317. '?' : begin
  318. if j>LenName then begin DoFNMatch:=false; Exit; end;
  319. inc(j);
  320. end;
  321. else
  322. Found:=false;
  323. end;
  324. end;
  325. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  326. {Now, find in name the character which i points to, if the * or ?
  327. wasn't the last character in the pattern, else, use up all the
  328. chars in name}
  329. Found:=false;
  330. if (i<=LenPat) then
  331. begin
  332. repeat
  333. {find a letter (not only first !) which maches pattern[i]}
  334. while (j<=LenName) and (name[j]<>pattern[i]) do
  335. inc (j);
  336. if (j<LenName) then
  337. begin
  338. if DoFnMatch(i+1,j+1) then
  339. begin
  340. i:=LenPat;
  341. j:=LenName;{we can stop}
  342. Found:=true;
  343. Break;
  344. end else
  345. inc(j);{We didn't find one, need to look further}
  346. end else
  347. if j=LenName then
  348. begin
  349. Found:=true;
  350. Break;
  351. end;
  352. { This 'until' condition must be j>LenName, not j>=LenName.
  353. That's because when we 'need to look further' and
  354. j = LenName then loop must not terminate. }
  355. until (j>LenName);
  356. end else
  357. begin
  358. j:=LenName;{we can stop}
  359. Found:=true;
  360. end;
  361. end;
  362. else {not a wildcard character in pattern}
  363. Found:=(j<=LenName) and (pattern[i]=name[j]);
  364. end;
  365. inc(i);
  366. inc(j);
  367. end;
  368. DoFnMatch:=Found and (j>LenName);
  369. end;
  370. Begin {start FNMatch}
  371. LenPat:=Length(Pattern);
  372. LenName:=Length(Name);
  373. FNMatch:=DoFNMatch(1,1);
  374. End;
  375. Type
  376. TUnixFindData = Record
  377. NamePos : LongInt; {to track which search this is}
  378. DirPtr : Pointer; {directory pointer for reading directory}
  379. SearchSpec : String;
  380. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  381. SearchAttr : Byte; {attribute we are searching for}
  382. End;
  383. PUnixFindData = ^TUnixFindData;
  384. Var
  385. CurrSearchNum : LongInt;
  386. Procedure FindClose(Var f: TSearchRec);
  387. var
  388. UnixFindData : PUnixFindData;
  389. Begin
  390. UnixFindData:=PUnixFindData(f.FindHandle);
  391. if UnixFindData=nil then
  392. exit;
  393. if UnixFindData^.SearchType=0 then
  394. begin
  395. if UnixFindData^.dirptr<>nil then
  396. fpclosedir(pdir(UnixFindData^.dirptr)^);
  397. end;
  398. Dispose(UnixFindData);
  399. f.FindHandle:=nil;
  400. End;
  401. Function FindGetFileInfo(const s:string;var f:TSearchRec):boolean;
  402. var
  403. st : baseunix.stat;
  404. WinAttr : longint;
  405. begin
  406. FindGetFileInfo:=false;
  407. If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  408. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  409. else
  410. FindGetFileInfo:=(fpstat(pointer(s),st)=0);
  411. If not FindGetFileInfo then
  412. exit;
  413. WinAttr:=LinuxToWinAttr(PChar(pointer(s)),st);
  414. If (f.FindHandle = nil) or ((WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0) Then
  415. Begin
  416. f.Name:=ExtractFileName(s);
  417. f.Attr:=WinAttr;
  418. f.Size:=st.st_Size;
  419. f.Mode:=st.st_mode;
  420. {$ifndef FPUNONE}
  421. f.Time:=UnixToWinAge(st.st_mtime);
  422. {$endif}
  423. result:=true;
  424. End;
  425. end;
  426. Function FindNext (Var Rslt : TSearchRec) : Longint;
  427. {
  428. re-opens dir if not already in array and calls FindGetFileInfo
  429. }
  430. Var
  431. DirName : String;
  432. FName,
  433. SName : string;
  434. Found,
  435. Finished : boolean;
  436. p : pdirent;
  437. UnixFindData : PUnixFindData;
  438. Begin
  439. Result:=-1;
  440. UnixFindData:=PUnixFindData(Rslt.FindHandle);
  441. if UnixFindData=nil then
  442. exit;
  443. if (UnixFindData^.SearchType=0) and
  444. (UnixFindData^.Dirptr=nil) then
  445. begin
  446. If UnixFindData^.NamePos = 0 Then
  447. DirName:='./'
  448. Else
  449. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  450. UnixFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  451. end;
  452. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  453. Found:=False;
  454. Finished:=(UnixFindData^.dirptr=nil);
  455. While Not Finished Do
  456. Begin
  457. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  458. if p=nil then
  459. FName:=''
  460. else
  461. FName:=p^.d_name;
  462. If FName='' Then
  463. Finished:=True
  464. Else
  465. Begin
  466. If FNMatch(SName,FName) Then
  467. Begin
  468. Found:=FindGetFileInfo(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Rslt);
  469. if Found then
  470. begin
  471. Result:=0;
  472. exit;
  473. end;
  474. End;
  475. End;
  476. End;
  477. End;
  478. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  479. {
  480. opens dir and calls FindNext if needed.
  481. }
  482. var
  483. UnixFindData : PUnixFindData;
  484. Begin
  485. Result:=-1;
  486. fillchar(Rslt,sizeof(Rslt),0);
  487. if Path='' then
  488. exit;
  489. {Wildcards?}
  490. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  491. begin
  492. if FindGetFileInfo(Path,Rslt) then
  493. Result:=0;
  494. end
  495. else
  496. begin
  497. { Allocate UnixFindData }
  498. New(UnixFindData);
  499. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  500. Rslt.FindHandle:=UnixFindData;
  501. {Create Info}
  502. UnixFindData^.SearchSpec := Path;
  503. {We always also search for readonly and archive, regardless of Attr:}
  504. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  505. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  506. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  507. dec(UnixFindData^.NamePos);
  508. Result:=FindNext(Rslt);
  509. end;
  510. End;
  511. Function FileGetDate (Handle : Longint) : Longint;
  512. Var Info : Stat;
  513. begin
  514. If (fpFStat(Handle,Info))<0 then
  515. Result:=-1
  516. else
  517. Result:=Info.st_Mtime;
  518. end;
  519. Function FileSetDate (Handle,Age : Longint) : Longint;
  520. begin
  521. // Impossible under Linux from FileHandle !!
  522. FileSetDate:=-1;
  523. end;
  524. Function FileGetAttr (Const FileName : String) : Longint;
  525. Var Info : Stat;
  526. begin
  527. If FpStat (pointer(FileName),Info)<0 then
  528. Result:=-1
  529. Else
  530. Result:=LinuxToWinAttr(Pchar(ExtractFileName(FileName)),Info);
  531. end;
  532. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  533. begin
  534. Result:=-1;
  535. end;
  536. Function DeleteFile (Const FileName : String) : Boolean;
  537. begin
  538. Result:=fpUnLink (pointer(FileName))>=0;
  539. end;
  540. Function RenameFile (Const OldName, NewName : String) : Boolean;
  541. begin
  542. RenameFile:=BaseUnix.FpRename(pointer(OldNAme),pointer(NewName))>=0;
  543. end;
  544. Function FileIsReadOnly(const FileName: String): Boolean;
  545. begin
  546. Result := fpAccess(PChar(pointer(FileName)),W_OK)<>0;
  547. end;
  548. Function FileSetDate (Const FileName : String;Age : Longint) : Longint;
  549. var
  550. t: TUTimBuf;
  551. begin
  552. Result := 0;
  553. t.actime := Age;
  554. t.modtime := Age;
  555. if fputime(PChar(pointer(FileName)), @t) = -1 then
  556. Result := fpgeterrno;
  557. end;
  558. {****************************************************************************
  559. Disk Functions
  560. ****************************************************************************}
  561. {
  562. The Diskfree and Disksize functions need a file on the specified drive, since this
  563. is required for the statfs system call.
  564. These filenames are set in drivestr[0..26], and have been preset to :
  565. 0 - '.' (default drive - hence current dir is ok.)
  566. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  567. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  568. 3 - '/' (C: equivalent of dos is the root partition)
  569. 4..26 (can be set by you're own applications)
  570. ! Use AddDisk() to Add new drives !
  571. They both return -1 when a failure occurs.
  572. }
  573. Const
  574. FixDriveStr : array[0..3] of pchar=(
  575. '.',
  576. '/fd0/.',
  577. '/fd1/.',
  578. '/.'
  579. );
  580. var
  581. Drives : byte = 4;
  582. DriveStr : array[4..26] of pchar;
  583. Function AddDisk(const path:string) : Byte;
  584. begin
  585. if not (DriveStr[Drives]=nil) then
  586. FreeMem(DriveStr[Drives]);
  587. GetMem(DriveStr[Drives],length(Path)+1);
  588. StrPCopy(DriveStr[Drives],path);
  589. Result:=Drives;
  590. inc(Drives);
  591. if Drives>26 then
  592. Drives:=4;
  593. end;
  594. Function DiskFree(Drive: Byte): int64;
  595. var
  596. fs : tstatfs;
  597. Begin
  598. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  599. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  600. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  601. else
  602. Diskfree:=-1;
  603. End;
  604. Function DiskSize(Drive: Byte): int64;
  605. var
  606. fs : tstatfs;
  607. Begin
  608. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  609. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  610. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  611. else
  612. DiskSize:=-1;
  613. End;
  614. Procedure FreeDriveStr;
  615. var
  616. i: longint;
  617. begin
  618. for i:=low(drivestr) to high(drivestr) do
  619. if assigned(drivestr[i]) then
  620. begin
  621. freemem(drivestr[i]);
  622. drivestr[i]:=nil;
  623. end;
  624. end;
  625. Function GetCurrentDir : String;
  626. begin
  627. GetDir (0,Result);
  628. end;
  629. Function SetCurrentDir (Const NewDir : String) : Boolean;
  630. begin
  631. {$I-}
  632. ChDir(NewDir);
  633. {$I+}
  634. result := (IOResult = 0);
  635. end;
  636. Function CreateDir (Const NewDir : String) : Boolean;
  637. begin
  638. {$I-}
  639. MkDir(NewDir);
  640. {$I+}
  641. result := (IOResult = 0);
  642. end;
  643. Function RemoveDir (Const Dir : String) : Boolean;
  644. begin
  645. {$I-}
  646. RmDir(Dir);
  647. {$I+}
  648. result := (IOResult = 0);
  649. end;
  650. {****************************************************************************
  651. Misc Functions
  652. ****************************************************************************}
  653. procedure Beep;
  654. begin
  655. end;
  656. {****************************************************************************
  657. Locale Functions
  658. ****************************************************************************}
  659. Function GetEpochTime: cint;
  660. {
  661. Get the number of seconds since 00:00, January 1 1970, GMT
  662. the time NOT corrected any way
  663. }
  664. begin
  665. GetEpochTime:=fptime;
  666. end;
  667. procedure GetTime(var hour,min,sec,msec,usec:word);
  668. {
  669. Gets the current time, adjusted to local time
  670. }
  671. var
  672. year,day,month:Word;
  673. tz:timeval;
  674. begin
  675. fpgettimeofday(@tz,nil);
  676. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  677. msec:=tz.tv_usec div 1000;
  678. usec:=tz.tv_usec mod 1000;
  679. end;
  680. procedure GetTime(var hour,min,sec,sec100:word);
  681. {
  682. Gets the current time, adjusted to local time
  683. }
  684. var
  685. usec : word;
  686. begin
  687. gettime(hour,min,sec,sec100,usec);
  688. sec100:=sec100 div 10;
  689. end;
  690. Procedure GetTime(Var Hour,Min,Sec:Word);
  691. {
  692. Gets the current time, adjusted to local time
  693. }
  694. var
  695. msec,usec : Word;
  696. Begin
  697. gettime(hour,min,sec,msec,usec);
  698. End;
  699. Procedure GetDate(Var Year,Month,Day:Word);
  700. {
  701. Gets the current date, adjusted to local time
  702. }
  703. var
  704. hour,minute,second : word;
  705. Begin
  706. EpochToLocal(fptime,year,month,day,hour,minute,second);
  707. End;
  708. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  709. {
  710. Gets the current date, adjusted to local time
  711. }
  712. Begin
  713. EpochToLocal(fptime,year,month,day,hour,minute,second);
  714. End;
  715. {$ifndef FPUNONE}
  716. Procedure GetLocalTime(var SystemTime: TSystemTime);
  717. var
  718. usecs : Word;
  719. begin
  720. GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  721. GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
  722. // SystemTime.MilliSecond := 0;
  723. end ;
  724. {$endif}
  725. Procedure InitAnsi;
  726. Var
  727. i : longint;
  728. begin
  729. { Fill table entries 0 to 127 }
  730. for i := 0 to 96 do
  731. UpperCaseTable[i] := chr(i);
  732. for i := 97 to 122 do
  733. UpperCaseTable[i] := chr(i - 32);
  734. for i := 123 to 191 do
  735. UpperCaseTable[i] := chr(i);
  736. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  737. for i := 0 to 64 do
  738. LowerCaseTable[i] := chr(i);
  739. for i := 65 to 90 do
  740. LowerCaseTable[i] := chr(i + 32);
  741. for i := 91 to 191 do
  742. LowerCaseTable[i] := chr(i);
  743. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  744. end;
  745. Procedure InitInternational;
  746. begin
  747. InitInternationalGeneric;
  748. InitAnsi;
  749. end;
  750. function SysErrorMessage(ErrorCode: Integer): String;
  751. begin
  752. Result:=StrError(ErrorCode);
  753. end;
  754. {****************************************************************************
  755. OS utility functions
  756. ****************************************************************************}
  757. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  758. begin
  759. Result:=StrPas(BaseUnix.FPGetenv(PChar(pointer(EnvVar))));
  760. end;
  761. Function GetEnvironmentVariableCount : Integer;
  762. begin
  763. Result:=FPCCountEnvVar(EnvP);
  764. end;
  765. Function GetEnvironmentString(Index : Integer) : String;
  766. begin
  767. Result:=FPCGetEnvStrFromP(Envp,Index);
  768. end;
  769. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
  770. var
  771. pid : longint;
  772. e : EOSError;
  773. CommandLine: AnsiString;
  774. cmdline2 : ppchar;
  775. Begin
  776. { always surround the name of the application by quotes
  777. so that long filenames will always be accepted. But don't
  778. do it if there are already double quotes!
  779. }
  780. // Only place we still parse
  781. cmdline2:=nil;
  782. if Comline<>'' Then
  783. begin
  784. CommandLine:=ComLine;
  785. { Make an unique copy because stringtoppchar modifies the
  786. string }
  787. UniqueString(CommandLine);
  788. cmdline2:=StringtoPPChar(CommandLine,1);
  789. cmdline2^:=pchar(pointer(Path));
  790. end
  791. else
  792. begin
  793. getmem(cmdline2,2*sizeof(pchar));
  794. cmdline2^:=pchar(Path);
  795. cmdline2[1]:=nil;
  796. end;
  797. {$ifdef USE_VFORK}
  798. pid:=fpvFork;
  799. {$else USE_VFORK}
  800. pid:=fpFork;
  801. {$endif USE_VFORK}
  802. if pid=0 then
  803. begin
  804. {The child does the actual exec, and then exits}
  805. fpexecv(pchar(pointer(Path)),Cmdline2);
  806. { If the execve fails, we return an exitvalue of 127, to let it be known}
  807. fpExit(127);
  808. end
  809. else
  810. if pid=-1 then {Fork failed}
  811. begin
  812. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  813. e.ErrorCode:=-1;
  814. raise e;
  815. end;
  816. { We're in the parent, let's wait. }
  817. result:=WaitProcess(pid); // WaitPid and result-convert
  818. if Comline<>'' Then
  819. freemem(cmdline2);
  820. if (result<0) or (result=127) then
  821. begin
  822. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  823. E.ErrorCode:=result;
  824. Raise E;
  825. end;
  826. End;
  827. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString):integer;
  828. var
  829. pid : longint;
  830. e : EOSError;
  831. Begin
  832. pid:=fpFork;
  833. if pid=0 then
  834. begin
  835. {The child does the actual exec, and then exits}
  836. fpexecl(Path,Comline);
  837. { If the execve fails, we return an exitvalue of 127, to let it be known}
  838. fpExit(127);
  839. end
  840. else
  841. if pid=-1 then {Fork failed}
  842. begin
  843. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  844. e.ErrorCode:=-1;
  845. raise e;
  846. end;
  847. { We're in the parent, let's wait. }
  848. result:=WaitProcess(pid); // WaitPid and result-convert
  849. if (result<0) or (result=127) then
  850. begin
  851. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  852. E.ErrorCode:=result;
  853. raise E;
  854. end;
  855. End;
  856. procedure Sleep(milliseconds: Cardinal);
  857. Var
  858. timeout,timeoutresult : TTimespec;
  859. begin
  860. timeout.tv_sec:=milliseconds div 1000;
  861. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  862. fpnanosleep(@timeout,@timeoutresult);
  863. end;
  864. Function GetLastOSError : Integer;
  865. begin
  866. Result:=fpgetErrNo;
  867. end;
  868. { ---------------------------------------------------------------------
  869. Application config files
  870. ---------------------------------------------------------------------}
  871. Function GetHomeDir : String;
  872. begin
  873. Result:=GetEnvironmentVariable('HOME');
  874. If (Result<>'') then
  875. Result:=IncludeTrailingPathDelimiter(Result);
  876. end;
  877. { Follows base-dir spec,
  878. see [http://freedesktop.org/Standards/basedir-spec].
  879. Always ends with PathDelim. }
  880. Function XdgConfigHome : String;
  881. begin
  882. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  883. if (Result='') then
  884. Result:=GetHomeDir + '.config/'
  885. else
  886. Result:=IncludeTrailingPathDelimiter(Result);
  887. end;
  888. Function GetAppConfigDir(Global : Boolean) : String;
  889. begin
  890. If Global then
  891. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  892. else
  893. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  894. if VendorName<>'' then
  895. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  896. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  897. end;
  898. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  899. begin
  900. If Global then
  901. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  902. else
  903. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  904. if SubDir then
  905. begin
  906. if VendorName<>'' then
  907. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  908. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  909. end;
  910. Result:=Result+ApplicationName+ConfigExtension;
  911. end;
  912. {****************************************************************************
  913. GetTempDir
  914. ****************************************************************************}
  915. Function GetTempDir(Global : Boolean) : String;
  916. begin
  917. If Assigned(OnGetTempDir) then
  918. Result:=OnGetTempDir(Global)
  919. else
  920. begin
  921. Result:=GetEnvironmentVariable('TEMP');
  922. If (Result='') Then
  923. Result:=GetEnvironmentVariable('TMP');
  924. if (Result='') then
  925. Result:='/tmp/' // fallback.
  926. end;
  927. if (Result<>'') then
  928. Result:=IncludeTrailingPathDelimiter(Result);
  929. end;
  930. {****************************************************************************
  931. GetUserDir
  932. ****************************************************************************}
  933. Var
  934. TheUserDir : String;
  935. Function GetUserDir : String;
  936. begin
  937. If (TheUserDir='') then
  938. begin
  939. TheUserDir:=GetEnvironmentVariable('HOME');
  940. if (TheUserDir<>'') then
  941. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  942. else
  943. TheUserDir:=GetTempDir(False);
  944. end;
  945. Result:=TheUserDir;
  946. end;
  947. {****************************************************************************
  948. Initialization code
  949. ****************************************************************************}
  950. Initialization
  951. InitExceptions; { Initialize exceptions. OS independent }
  952. InitInternational; { Initialize internationalization settings }
  953. SysConfigDir:='/etc'; { Initialize system config dir }
  954. Finalization
  955. FreeDriveStr;
  956. DoneExceptions;
  957. end.