dos.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt and Peter Vreman,
  4. members of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. Unit Dos;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. Interface
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. uses UnixApi.Base;
  17. {$ELSE FPC_DOTTEDUNITS}
  18. uses baseunix;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. {$MACRO ON}
  21. {$IFNDEF FPC_DOTTEDUNITS}
  22. {$DEFINE SUT:=sysutils}
  23. {$DEFINE BU:=baseunix}
  24. {$DEFINE UA:=unix}
  25. {$ELSE}
  26. {$DEFINE SUT:=System.SysUtils}
  27. {$DEFINE BU:=UnixApi.Base}
  28. {$DEFINE UA:=UnixApi.Unix}
  29. {$ENDIF}
  30. Const
  31. FileNameLen = 255;
  32. Type
  33. SearchRec =
  34. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  35. packed
  36. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  37. Record
  38. {Fill : array[1..21] of byte; Fill replaced with below}
  39. SearchPos : TOff; {directory position}
  40. SearchNum : LongInt; {to track which search this is}
  41. DirPtr : Pointer; {directory pointer for reading directory}
  42. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  43. SearchAttr : Byte; {attribute we are searching for}
  44. Mode : Word;
  45. Fill : Array[1..1] of Byte; {future use}
  46. {End of fill}
  47. Attr : Byte; {attribute of found file}
  48. Time : LongInt; {last modify date of found file}
  49. Size : LongInt; {file size of found file}
  50. Reserved : Word; {future use}
  51. Name : String[FileNameLen]; {name of found file}
  52. SearchSpec : String[FileNameLen]; {search pattern}
  53. NamePos : Word; {end of path, start of name position}
  54. End;
  55. {$DEFINE HAS_FILENAMELEN}
  56. {$i dosh.inc}
  57. {Extra Utils}
  58. function weekday(y,m,d : longint) : longint; platform;
  59. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime); platform;
  60. Function DTToUnixDate(DT: DateTime): LongInt; platform;
  61. {Disk}
  62. Function AddDisk(const path:string) : byte; platform;
  63. Implementation
  64. {$IFDEF FPC_DOTTEDUNITS}
  65. Uses
  66. UnixApi.Utils,
  67. System.Strings,
  68. UnixApi.Unix,
  69. {$ifdef FPC_USE_LIBC}System.InitC{$ELSE}UnixApi.SysCall{$ENDIF};
  70. {$ELSE FPC_DOTTEDUNITS}
  71. Uses
  72. UnixUtil,
  73. Strings,
  74. Unix,
  75. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF};
  76. {$ENDIF FPC_DOTTEDUNITS}
  77. {$DEFINE HAS_GETMSCOUNT}
  78. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  79. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PAnsiChar }
  80. {$I dos.inc}
  81. {******************************************************************************
  82. --- Link C Lib if set ---
  83. ******************************************************************************}
  84. type
  85. RtlInfoType = Record
  86. FMode,
  87. FInode,
  88. FUid,
  89. FGid,
  90. FSize,
  91. FMTime : LongInt;
  92. End;
  93. {******************************************************************************
  94. --- Info / Date / Time ---
  95. ******************************************************************************}
  96. Function DosVersion:Word;
  97. Var
  98. Buffer : Array[0..255] of AnsiChar;
  99. Tmp2,
  100. TmpStr : String[40];
  101. TmpPos,
  102. SubRel,
  103. Rel : LongInt;
  104. info : utsname;
  105. Begin
  106. FPUName(info);
  107. Move(info.release,buffer[0],40);
  108. TmpStr:=StrPas(Buffer);
  109. SubRel:=0;
  110. TmpPos:=Pos('.',TmpStr);
  111. if TmpPos>0 then
  112. begin
  113. Tmp2:=Copy(TmpStr,TmpPos+1,40);
  114. Delete(TmpStr,TmpPos,40);
  115. end;
  116. TmpPos:=Pos('.',Tmp2);
  117. if TmpPos>0 then
  118. Delete(Tmp2,TmpPos,40);
  119. Val(TmpStr,Rel);
  120. Val(Tmp2,SubRel);
  121. DosVersion:=Rel+(SubRel shl 8);
  122. End;
  123. function WeekDay (y,m,d:longint):longint;
  124. {
  125. Calculates th day of the week. returns -1 on error
  126. }
  127. var
  128. u,v : longint;
  129. begin
  130. if (m<1) or (m>12) or (y<1600) or (y>4000) or
  131. (d<1) or (d>30+((m+ord(m>7)) and 1)-ord(m=2)) or
  132. ((m*d=58) and (((y mod 4>0) or (y mod 100=0)) and (y mod 400>0))) then
  133. WeekDay:=-1
  134. else
  135. begin
  136. u:=m;
  137. v:=y;
  138. if m<3 then
  139. begin
  140. inc(u,12);
  141. dec(v);
  142. end;
  143. WeekDay:=(d+2*u+((3*(u+1)) div 5)+v+(v div 4)-(v div 100)+(v div 400)+1) mod 7;
  144. end;
  145. end;
  146. Procedure GetDate(Var Year, Month, MDay, WDay: Word);
  147. var
  148. tz:timeval;
  149. hour,min,sec : word;
  150. begin
  151. fpgettimeofday(@tz,nil);
  152. EpochToLocal(tz.tv_sec,year,month,mday,hour,min,sec);
  153. Wday:=weekday(Year,Month,MDay);
  154. end;
  155. procedure SetTime(Hour,Minute,Second,sec100:word);
  156. var
  157. dow,Year, Month, Day : Word;
  158. tv : timeval;
  159. begin
  160. GetDate (Year, Month, Day,dow);
  161. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) ;
  162. tv.tv_usec:= Sec100 * 10000;
  163. fpSettimeofday(@tv,nil);
  164. end;
  165. procedure SetDate(Year,Month,Day:Word);
  166. var
  167. Hour, Min, Sec, Sec100 : Word;
  168. tv : timeval;
  169. begin
  170. GetTime ( Hour, Min, Sec, Sec100 );
  171. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Min, Sec ) ;
  172. tv.tv_usec:= Sec100 * 10000;
  173. fpSettimeofday(@tv,nil);
  174. end;
  175. Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  176. var
  177. tv : timeval;
  178. begin
  179. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) ;
  180. tv.tv_usec:= 0;
  181. SetDatetime:=fpSettimeofday(@tv,nil)=0;
  182. end;
  183. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  184. var
  185. tz:timeval;
  186. year,month,day : word;
  187. begin
  188. fpgettimeofday(@tz,nil);
  189. EpochToLocal(tz.tv_sec,year,month,day,hour,minute,second);
  190. sec100:=tz.tv_usec div 10000;
  191. end;
  192. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime);
  193. Begin
  194. EpochToLocal(SecsPast,dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  195. End;
  196. Function DTToUnixDate(DT: DateTime): LongInt;
  197. Begin
  198. DTToUnixDate:=LocalToEpoch(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  199. End;
  200. function GetMsCount: int64;
  201. var
  202. tv : TimeVal;
  203. { tz : TimeZone;}
  204. begin
  205. FPGetTimeOfDay (@tv, nil {,tz});
  206. GetMsCount := int64(tv.tv_Sec) * 1000 + tv.tv_uSec div 1000;
  207. end;
  208. {******************************************************************************
  209. --- Exec ---
  210. ******************************************************************************}
  211. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  212. var
  213. pid : longint; // pid_t?
  214. cmdline2 : PPAnsiChar;
  215. commandline : RawByteString;
  216. realpath : ansistring;
  217. // The Error-Checking in the previous Version failed, since halt($7F) gives an WaitPid-status of $7F00
  218. Begin
  219. LastDosExitCode:=0;
  220. if Path='' then
  221. begin
  222. doserror:=2;
  223. exit;
  224. end;
  225. pid:=fpFork;
  226. if pid=0 then
  227. begin
  228. cmdline2:=nil;
  229. realpath:=path;
  230. if Comline<>'' Then
  231. begin
  232. CommandLine:=ToSingleByteFileSystemEncodedFileName(ComLine); // conversion must live till after fpexec!
  233. cmdline2:=StringtoPPChar(CommandLine,1);
  234. cmdline2^:=PAnsiChar(realPath);
  235. end
  236. else
  237. begin
  238. getmem(cmdline2,2*sizeof(PAnsiChar));
  239. cmdline2^:=PAnsiChar(realPath);
  240. cmdline2[1]:=nil;
  241. end;
  242. {The child does the actual exec, and then exits}
  243. fpExecv(PAnsiChar(realPath),cmdline2);
  244. {If the execve fails, we return an exitvalue of 127, to let it be known}
  245. fpExit(127);
  246. end
  247. else
  248. if pid=-1 then {Fork failed}
  249. begin
  250. DosError:=8;
  251. exit
  252. end;
  253. {We're in the parent, let's wait.}
  254. LastDosExitCode:=WaitProcess(pid); // WaitPid and result-convert
  255. if (LastDosExitCode>=0) and (LastDosExitCode<>127) then
  256. DosError:=0
  257. else
  258. DosError:=8; // perhaps one time give an better error
  259. End;
  260. {******************************************************************************
  261. --- Disk ---
  262. ******************************************************************************}
  263. {
  264. The Diskfree and Disksize functions need a file on the specified drive, since this
  265. is required for the fpstatfs system call.
  266. These filenames are set in drivestr[0..26], and have been preset to :
  267. 0 - '.' (default drive - hence current dir is ok.)
  268. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  269. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  270. 3 - '/' (C: equivalent of dos is the root partition)
  271. 4..26 (can be set by you're own applications)
  272. ! Use AddDisk() to Add new drives !
  273. They both return -1 when a failure occurs.
  274. }
  275. Const
  276. FixDriveStr : array[0..3] of PAnsiChar=(
  277. '.',
  278. '/fd0/.',
  279. '/fd1/.',
  280. '/.'
  281. );
  282. const
  283. Drives : byte = 4;
  284. var
  285. DriveStr : array[4..26] of PAnsiChar;
  286. Function AddDisk(const path:string) : byte;
  287. begin
  288. if not (DriveStr[Drives]=nil) then
  289. FreeMem(DriveStr[Drives]);
  290. GetMem(DriveStr[Drives],length(Path)+1);
  291. StrPCopy(DriveStr[Drives],path);
  292. AddDisk:=Drives;
  293. inc(Drives);
  294. if Drives>26 then
  295. Drives:=4;
  296. end;
  297. Function DiskFree(Drive: Byte): int64;
  298. var
  299. fs : tstatfs;
  300. Begin
  301. if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  302. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  303. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  304. else
  305. Diskfree:=-1;
  306. End;
  307. Function DiskSize(Drive: Byte): int64;
  308. var
  309. fs : tstatfs;
  310. Begin
  311. if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  312. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  313. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  314. else
  315. DiskSize:=-1;
  316. End;
  317. Procedure FreeDriveStr;
  318. var
  319. i: longint;
  320. begin
  321. for i:=low(drivestr) to high(drivestr) do
  322. if assigned(drivestr[i]) then
  323. begin
  324. freemem(drivestr[i]);
  325. drivestr[i]:=nil;
  326. end;
  327. end;
  328. {******************************************************************************
  329. --- Findfirst FindNext ---
  330. ******************************************************************************}
  331. Function FNMatch(const Pattern,Name:string):Boolean;
  332. Var
  333. LenPat,LenName : longint;
  334. Function DoFNMatch(i,j:longint):Boolean;
  335. Var
  336. Found : boolean;
  337. Begin
  338. Found:=true;
  339. While Found and (i<=LenPat) Do
  340. Begin
  341. Case Pattern[i] of
  342. '?' : Found:=(j<=LenName);
  343. '*' : Begin
  344. {find the next character in pattern, different of ? and *}
  345. while Found do
  346. begin
  347. inc(i);
  348. if i>LenPat then Break;
  349. case Pattern[i] of
  350. '*' : ;
  351. '?' : begin
  352. if j>LenName then begin DoFNMatch:=false; Exit; end;
  353. inc(j);
  354. end;
  355. else
  356. Found:=false;
  357. end;
  358. end;
  359. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  360. {Now, find in name the character which i points to, if the * or ?
  361. wasn't the last character in the pattern, else, use up all the
  362. chars in name}
  363. Found:=false;
  364. if (i<=LenPat) then
  365. begin
  366. repeat
  367. {find a letter (not only first !) which maches pattern[i]}
  368. while (j<=LenName) and (name[j]<>pattern[i]) do
  369. inc (j);
  370. if (j<LenName) then
  371. begin
  372. if DoFnMatch(i+1,j+1) then
  373. begin
  374. i:=LenPat;
  375. j:=LenName;{we can stop}
  376. Found:=true;
  377. Break;
  378. end else
  379. inc(j);{We didn't find one, need to look further}
  380. end else
  381. if j=LenName then
  382. begin
  383. Found:=true;
  384. Break;
  385. end;
  386. { This 'until' condition must be j>LenName, not j>=LenName.
  387. That's because when we 'need to look further' and
  388. j = LenName then loop must not terminate. }
  389. until (j>LenName);
  390. end else
  391. begin
  392. j:=LenName;{we can stop}
  393. Found:=true;
  394. end;
  395. end;
  396. else {not a wildcard character in pattern}
  397. Found:=(j<=LenName) and (pattern[i]=name[j]);
  398. end;
  399. inc(i);
  400. inc(j);
  401. end;
  402. DoFnMatch:=Found and (j>LenName);
  403. end;
  404. Begin {start FNMatch}
  405. LenPat:=Length(Pattern);
  406. LenName:=Length(Name);
  407. FNMatch:=DoFNMatch(1,1);
  408. End;
  409. Const
  410. RtlFindSize = 15;
  411. Type
  412. RtlFindRecType = Record
  413. DirPtr : Pointer;
  414. SearchNum,
  415. LastUsed : LongInt;
  416. End;
  417. Var
  418. RtlFindRecs : Array[1..RtlFindSize] of RtlFindRecType;
  419. CurrSearchNum : LongInt;
  420. Procedure FindClose(Var f: SearchRec);
  421. {
  422. Closes dirptr if it is open
  423. }
  424. Var
  425. i : longint;
  426. Begin
  427. if f.SearchType=0 then
  428. begin
  429. i:=1;
  430. repeat
  431. if (RtlFindRecs[i].SearchNum=f.SearchNum) then
  432. break;
  433. inc(i);
  434. until (i>RtlFindSize);
  435. If i<=RtlFindSize Then
  436. Begin
  437. RtlFindRecs[i].SearchNum:=0;
  438. if f.dirptr<>nil then
  439. fpclosedir(pdir(f.dirptr)^);
  440. End;
  441. end;
  442. f.dirptr:=nil;
  443. End;
  444. Function FindGetFileInfo(const s:string;var f:SearchRec):boolean;
  445. var
  446. DT : DateTime;
  447. Info : RtlInfoType;
  448. st : BU.stat;
  449. begin
  450. FindGetFileInfo:=false;
  451. if not fpstat(s,st)>=0 then
  452. exit;
  453. info.FSize:=st.st_Size;
  454. info.FMTime:=st.st_mtime;
  455. if (st.st_mode and STAT_IFMT)=STAT_IFDIR then
  456. info.fmode:=$10
  457. else
  458. info.fmode:=$0;
  459. if (st.st_mode and STAT_IWUSR)=0 then
  460. info.fmode:=info.fmode or 1;
  461. if s[f.NamePos+1]='.' then
  462. info.fmode:=info.fmode or $2;
  463. If ((Info.FMode and Not(f.searchattr))=0) Then
  464. Begin
  465. f.Name:=Copy(s,f.NamePos+1,255);
  466. f.Attr:=Info.FMode;
  467. f.Size:=Info.FSize;
  468. { At least on AIX OS, st_mode has high bits (outside 16-bit word range)
  469. which are used for specific extensions.
  470. Add explicit typecast to avoid Range check error. }
  471. f.mode:=Word(st.st_mode);
  472. UnixDateToDT(Info.FMTime, DT);
  473. PackTime(DT,f.Time);
  474. FindGetFileInfo:=true;
  475. End;
  476. end;
  477. Function FindLastUsed: Longint;
  478. {
  479. Find unused or least recently used dirpointer slot in findrecs array
  480. }
  481. Var
  482. BestMatch,i : Longint;
  483. Found : Boolean;
  484. Begin
  485. BestMatch:=1;
  486. i:=1;
  487. Found:=False;
  488. While (i <= RtlFindSize) And (Not Found) Do
  489. Begin
  490. If (RtlFindRecs[i].SearchNum = 0) Then
  491. Begin
  492. BestMatch := i;
  493. Found := True;
  494. End
  495. Else
  496. Begin
  497. If RtlFindRecs[i].LastUsed > RtlFindRecs[BestMatch].LastUsed Then
  498. BestMatch := i;
  499. End;
  500. Inc(i);
  501. End;
  502. FindLastUsed := BestMatch;
  503. End;
  504. Procedure FindNext(Var f: SearchRec);
  505. {
  506. re-opens dir if not already in array and calls FindWorkProc
  507. }
  508. Var
  509. DirName : Array[0..256] of AnsiChar;
  510. i,
  511. ArrayPos : Longint;
  512. FName,
  513. SName : string;
  514. Found,
  515. Finished : boolean;
  516. p : pdirent;
  517. Begin
  518. If f.SearchType=0 Then
  519. Begin
  520. ArrayPos:=0;
  521. For i:=1 to RtlFindSize Do
  522. Begin
  523. If RtlFindRecs[i].SearchNum = f.SearchNum Then
  524. ArrayPos:=i;
  525. Inc(RtlFindRecs[i].LastUsed);
  526. End;
  527. If ArrayPos=0 Then
  528. Begin
  529. If f.NamePos = 0 Then
  530. Begin
  531. DirName[0] := '.';
  532. DirName[1] := '/';
  533. DirName[2] := #0;
  534. End
  535. Else
  536. Begin
  537. Move(f.SearchSpec[1], DirName[0], f.NamePos);
  538. DirName[f.NamePos] := #0;
  539. End;
  540. f.DirPtr := fpopendir(@DirName[0]);
  541. If f.DirPtr <> nil Then
  542. begin
  543. ArrayPos:=FindLastUsed;
  544. If RtlFindRecs[ArrayPos].SearchNum > 0 Then
  545. FpCloseDir((pdir(rtlfindrecs[arraypos].dirptr)^));
  546. RtlFindRecs[ArrayPos].SearchNum := f.SearchNum;
  547. RtlFindRecs[ArrayPos].DirPtr := f.DirPtr;
  548. if f.searchpos>0 then
  549. seekdir(pdir(f.dirptr), f.searchpos);
  550. end;
  551. End;
  552. if ArrayPos>0 then
  553. RtlFindRecs[ArrayPos].LastUsed:=0;
  554. end;
  555. {Main loop}
  556. SName:=Copy(f.SearchSpec,f.NamePos+1,255);
  557. Found:=False;
  558. Finished:=(f.dirptr=nil);
  559. While Not Finished Do
  560. Begin
  561. p:=fpreaddir(pdir(f.dirptr)^);
  562. if p=nil then
  563. FName:=''
  564. else
  565. FName:=Strpas(@p^.d_name[0]);
  566. If FName='' Then
  567. Finished:=True
  568. Else
  569. Begin
  570. If FNMatch(SName,FName) Then
  571. Begin
  572. Found:=FindGetFileInfo(Copy(f.SearchSpec,1,f.NamePos)+FName,f);
  573. if Found then
  574. Finished:=true;
  575. End;
  576. End;
  577. End;
  578. {Shutdown}
  579. If Found Then
  580. Begin
  581. f.searchpos:=telldir(pdir(f.dirptr));
  582. DosError:=0;
  583. End
  584. Else
  585. Begin
  586. FindClose(f);
  587. DosError:=18;
  588. End;
  589. End;
  590. Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
  591. {
  592. opens dir and calls FindWorkProc
  593. }
  594. Begin
  595. fillchar(f,sizeof(f),0);
  596. if Path='' then
  597. begin
  598. DosError:=3;
  599. exit;
  600. end;
  601. {Create Info}
  602. f.SearchSpec := Path;
  603. {We always also search for readonly and archive, regardless of Attr:}
  604. f.SearchAttr := Attr or archive or readonly;
  605. f.SearchPos := 0;
  606. f.NamePos := Length(f.SearchSpec);
  607. while (f.NamePos>0) and (f.SearchSpec[f.NamePos]<>'/') do
  608. dec(f.NamePos);
  609. {Wildcards?}
  610. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  611. begin
  612. if FindGetFileInfo(Path,f) then
  613. DosError:=0
  614. else
  615. begin
  616. { According to tdos2 test it should return 18
  617. if ErrNo=Sys_ENOENT then
  618. DosError:=3
  619. else }
  620. DosError:=18;
  621. end;
  622. f.DirPtr:=nil;
  623. f.SearchType:=1;
  624. f.searchnum:=-1;
  625. end
  626. else
  627. {Find Entry}
  628. begin
  629. Inc(CurrSearchNum);
  630. f.SearchNum:=CurrSearchNum;
  631. f.SearchType:=0;
  632. FindNext(f);
  633. end;
  634. End;
  635. {******************************************************************************
  636. --- File ---
  637. ******************************************************************************}
  638. Function FSearch(path : pathstr;dirlist : shortstring) : pathstr;
  639. Var
  640. info : BU.stat;
  641. Begin
  642. if (length(Path)>0) and (path[1]='/') and (fpStat(path,info)>=0) and (not fpS_ISDIR(Info.st_Mode)) then
  643. FSearch:=path
  644. else
  645. FSearch:=UA.FSearch(path,dirlist);
  646. End;
  647. Procedure GetFAttr(var f; var attr : word);
  648. Var
  649. info : BU.stat;
  650. LinAttr : TMode;
  651. p : PAnsiChar;
  652. {$ifndef FPC_ANSI_TEXTFILEREC}
  653. r : RawByteString;
  654. {$endif not FPC_ANSI_TEXTFILEREC}
  655. Begin
  656. DosError:=0;
  657. {$ifdef FPC_ANSI_TEXTFILEREC}
  658. { encoding is already correct }
  659. p:=@textrec(f).name;
  660. {$else}
  661. r:=ToSingleByteFileSystemEncodedFileName(textrec(f).name);
  662. p:=PAnsiChar(r);
  663. {$endif}
  664. { use the PAnsiChar rather than the rawbytestring version so that we don't check
  665. a second time whether the string needs to be converted to the right code
  666. page
  667. }
  668. if FPStat(p,info)<0 then
  669. begin
  670. Attr:=0;
  671. DosError:=3;
  672. exit;
  673. end
  674. else
  675. LinAttr:=TMode(Info.st_Mode);
  676. if fpS_ISDIR(LinAttr) then
  677. Attr:=$10
  678. else
  679. Attr:=$0;
  680. if fpAccess(p,W_OK)<0 then
  681. Attr:=Attr or $1;
  682. if filerec(f).name[0]='.' then
  683. Attr:=Attr or $2;
  684. end;
  685. Procedure getftime (var f; var time : longint);
  686. Var
  687. Info: BU.stat;
  688. DT: DateTime;
  689. Begin
  690. doserror:=0;
  691. if fpfstat(filerec(f).handle,info)<0 then
  692. begin
  693. Time:=0;
  694. doserror:=6;
  695. exit
  696. end
  697. else
  698. UnixDateToDT(Info.st_mTime,DT);
  699. PackTime(DT,Time);
  700. End;
  701. Procedure setftime(var f; time : longint);
  702. Var
  703. utim: utimbuf;
  704. DT: DateTime;
  705. p : PAnsiChar;
  706. {$ifndef FPC_ANSI_TEXTFILEREC}
  707. r : Rawbytestring;
  708. {$endif not FPC_ANSI_TEXTFILEREC}
  709. Begin
  710. doserror:=0;
  711. with utim do
  712. begin
  713. actime:=fptime;
  714. UnPackTime(Time,DT);
  715. modtime:=DTToUnixDate(DT);
  716. end;
  717. {$ifdef FPC_ANSI_TEXTFILEREC}
  718. { encoding is already correct }
  719. p:=@textrec(f).name;
  720. {$else}
  721. r:=ToSingleByteFileSystemEncodedFileName(textrec(f).name);
  722. p:=PAnsiChar(r);
  723. {$endif}
  724. { use the PAnsiChar rather than the rawbytestring version so that we don't check
  725. a second time whether the string needs to be converted to the right code
  726. page
  727. }
  728. if fputime(p,@utim)<0 then
  729. begin
  730. Time:=0;
  731. doserror:=3;
  732. end;
  733. End;
  734. {******************************************************************************
  735. --- Environment ---
  736. ******************************************************************************}
  737. Function EnvCount: Longint;
  738. var
  739. envcnt : longint;
  740. p : PPAnsiChar;
  741. Begin
  742. envcnt:=0;
  743. p:=envp; {defined in system unit}
  744. while (p^<>nil) do
  745. begin
  746. inc(envcnt);
  747. inc(p);
  748. end;
  749. EnvCount := envcnt
  750. End;
  751. Function EnvStr (Index: longint): ShortString;
  752. Var
  753. i : longint;
  754. p : PPAnsiChar;
  755. Begin
  756. if Index <= 0 then
  757. envstr:=''
  758. else
  759. begin
  760. p:=envp; {defined in system unit}
  761. i:=1;
  762. while (i<Index) and (p^<>nil) do
  763. begin
  764. inc(i);
  765. inc(p);
  766. end;
  767. if p=nil then
  768. envstr:=''
  769. else
  770. envstr:=strpas(p^)
  771. end;
  772. end;
  773. Function GetEnv(EnvVar: ShortString): ShortString;
  774. var
  775. p : PAnsiChar;
  776. Begin
  777. p:=BU.fpGetEnv(EnvVar);
  778. if p=nil then
  779. GetEnv:=''
  780. else
  781. GetEnv:=StrPas(p);
  782. End;
  783. Procedure setfattr (var f;attr : word);
  784. Begin
  785. {! No Unix equivalent !}
  786. { Fail for setting VolumeId }
  787. if (attr and VolumeID)<>0 then
  788. doserror:=5;
  789. End;
  790. {******************************************************************************
  791. --- Initialization ---
  792. ******************************************************************************}
  793. Finalization
  794. FreeDriveStr;
  795. End.