sysutils.pp 29 KB

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