sysutils.pp 26 KB

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