dos.pp 22 KB

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