dos.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  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. tv.tv_usec:= Sec100 * 10000;
  214. fpSettimeofday(@tv,nil);
  215. end;
  216. procedure SetDate(Year,Month,Day:Word);
  217. var
  218. Hour, Min, Sec, Sec100 : Word;
  219. tv : timeval;
  220. begin
  221. GetTime ( Hour, Min, Sec, Sec100 );
  222. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Min, Sec ) ;
  223. tv.tv_usec:= Sec100 * 10000;
  224. fpSettimeofday(@tv,nil);
  225. end;
  226. Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  227. var
  228. tv : timeval;
  229. begin
  230. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) ;
  231. tv.tv_usec:= 0;
  232. SetDatetime:=fpSettimeofday(@tv,nil)=0;
  233. end;
  234. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  235. var
  236. tz:timeval;
  237. year,month,day : word;
  238. begin
  239. fpgettimeofday(@tz,nil);
  240. EpochToLocal(tz.tv_sec,year,month,day,hour,minute,second);
  241. sec100:=tz.tv_usec div 10000;
  242. end;
  243. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime);
  244. Begin
  245. EpochToLocal(SecsPast,dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  246. End;
  247. Function DTToUnixDate(DT: DateTime): LongInt;
  248. Begin
  249. DTToUnixDate:=LocalToEpoch(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  250. End;
  251. function GetMsCount: int64;
  252. var
  253. tv : TimeVal;
  254. { tz : TimeZone;}
  255. begin
  256. FPGetTimeOfDay (@tv, nil {,tz});
  257. GetMsCount := int64(tv.tv_Sec) * 1000 + tv.tv_uSec div 1000;
  258. end;
  259. {******************************************************************************
  260. --- Exec ---
  261. ******************************************************************************}
  262. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  263. var
  264. pid : longint; // pid_t?
  265. cmdline2 : ppchar;
  266. commandline : RawByteString;
  267. realpath : ansistring;
  268. // The Error-Checking in the previous Version failed, since halt($7F) gives an WaitPid-status of $7F00
  269. Begin
  270. LastDosExitCode:=0;
  271. if Path='' then
  272. begin
  273. doserror:=2;
  274. exit;
  275. end;
  276. pid:=fpFork;
  277. if pid=0 then
  278. begin
  279. cmdline2:=nil;
  280. realpath:=path;
  281. if Comline<>'' Then
  282. begin
  283. CommandLine:=ToSingleByteFileSystemEncodedFileName(ComLine); // conversion must live till after fpexec!
  284. cmdline2:=StringtoPPChar(CommandLine,1);
  285. cmdline2^:=pchar(realPath);
  286. end
  287. else
  288. begin
  289. getmem(cmdline2,2*sizeof(pchar));
  290. cmdline2^:=pchar(realPath);
  291. cmdline2[1]:=nil;
  292. end;
  293. {The child does the actual exec, and then exits}
  294. fpExecv(pchar(realPath),cmdline2);
  295. {If the execve fails, we return an exitvalue of 127, to let it be known}
  296. fpExit(127);
  297. end
  298. else
  299. if pid=-1 then {Fork failed}
  300. begin
  301. DosError:=8;
  302. exit
  303. end;
  304. {We're in the parent, let's wait.}
  305. LastDosExitCode:=WaitProcess(pid); // WaitPid and result-convert
  306. if (LastDosExitCode>=0) and (LastDosExitCode<>127) then
  307. DosError:=0
  308. else
  309. DosError:=8; // perhaps one time give an better error
  310. End;
  311. {******************************************************************************
  312. --- Disk ---
  313. ******************************************************************************}
  314. {
  315. The Diskfree and Disksize functions need a file on the specified drive, since this
  316. is required for the fpstatfs system call.
  317. These filenames are set in drivestr[0..26], and have been preset to :
  318. 0 - '.' (default drive - hence current dir is ok.)
  319. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  320. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  321. 3 - '/' (C: equivalent of dos is the root partition)
  322. 4..26 (can be set by you're own applications)
  323. ! Use AddDisk() to Add new drives !
  324. They both return -1 when a failure occurs.
  325. }
  326. Const
  327. FixDriveStr : array[0..3] of pchar=(
  328. '.',
  329. '/fd0/.',
  330. '/fd1/.',
  331. '/.'
  332. );
  333. const
  334. Drives : byte = 4;
  335. var
  336. DriveStr : array[4..26] of pchar;
  337. Function AddDisk(const path:string) : byte;
  338. begin
  339. if not (DriveStr[Drives]=nil) then
  340. FreeMem(DriveStr[Drives]);
  341. GetMem(DriveStr[Drives],length(Path)+1);
  342. StrPCopy(DriveStr[Drives],path);
  343. AddDisk:=Drives;
  344. inc(Drives);
  345. if Drives>26 then
  346. Drives:=4;
  347. end;
  348. Function DiskFree(Drive: Byte): int64;
  349. var
  350. fs : tstatfs;
  351. Begin
  352. if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  353. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  354. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  355. else
  356. Diskfree:=-1;
  357. End;
  358. Function DiskSize(Drive: Byte): int64;
  359. var
  360. fs : tstatfs;
  361. Begin
  362. if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  363. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  364. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  365. else
  366. DiskSize:=-1;
  367. End;
  368. Procedure FreeDriveStr;
  369. var
  370. i: longint;
  371. begin
  372. for i:=low(drivestr) to high(drivestr) do
  373. if assigned(drivestr[i]) then
  374. begin
  375. freemem(drivestr[i]);
  376. drivestr[i]:=nil;
  377. end;
  378. end;
  379. {******************************************************************************
  380. --- Findfirst FindNext ---
  381. ******************************************************************************}
  382. Function FNMatch(const Pattern,Name:string):Boolean;
  383. Var
  384. LenPat,LenName : longint;
  385. Function DoFNMatch(i,j:longint):Boolean;
  386. Var
  387. Found : boolean;
  388. Begin
  389. Found:=true;
  390. While Found and (i<=LenPat) Do
  391. Begin
  392. Case Pattern[i] of
  393. '?' : Found:=(j<=LenName);
  394. '*' : Begin
  395. {find the next character in pattern, different of ? and *}
  396. while Found do
  397. begin
  398. inc(i);
  399. if i>LenPat then Break;
  400. case Pattern[i] of
  401. '*' : ;
  402. '?' : begin
  403. if j>LenName then begin DoFNMatch:=false; Exit; end;
  404. inc(j);
  405. end;
  406. else
  407. Found:=false;
  408. end;
  409. end;
  410. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  411. {Now, find in name the character which i points to, if the * or ?
  412. wasn't the last character in the pattern, else, use up all the
  413. chars in name}
  414. Found:=false;
  415. if (i<=LenPat) then
  416. begin
  417. repeat
  418. {find a letter (not only first !) which maches pattern[i]}
  419. while (j<=LenName) and (name[j]<>pattern[i]) do
  420. inc (j);
  421. if (j<LenName) then
  422. begin
  423. if DoFnMatch(i+1,j+1) then
  424. begin
  425. i:=LenPat;
  426. j:=LenName;{we can stop}
  427. Found:=true;
  428. Break;
  429. end else
  430. inc(j);{We didn't find one, need to look further}
  431. end else
  432. if j=LenName then
  433. begin
  434. Found:=true;
  435. Break;
  436. end;
  437. { This 'until' condition must be j>LenName, not j>=LenName.
  438. That's because when we 'need to look further' and
  439. j = LenName then loop must not terminate. }
  440. until (j>LenName);
  441. end else
  442. begin
  443. j:=LenName;{we can stop}
  444. Found:=true;
  445. end;
  446. end;
  447. else {not a wildcard character in pattern}
  448. Found:=(j<=LenName) and (pattern[i]=name[j]);
  449. end;
  450. inc(i);
  451. inc(j);
  452. end;
  453. DoFnMatch:=Found and (j>LenName);
  454. end;
  455. Begin {start FNMatch}
  456. LenPat:=Length(Pattern);
  457. LenName:=Length(Name);
  458. FNMatch:=DoFNMatch(1,1);
  459. End;
  460. Const
  461. RtlFindSize = 15;
  462. Type
  463. RtlFindRecType = Record
  464. DirPtr : Pointer;
  465. SearchNum,
  466. LastUsed : LongInt;
  467. End;
  468. Var
  469. RtlFindRecs : Array[1..RtlFindSize] of RtlFindRecType;
  470. CurrSearchNum : LongInt;
  471. Procedure FindClose(Var f: SearchRec);
  472. {
  473. Closes dirptr if it is open
  474. }
  475. Var
  476. i : longint;
  477. Begin
  478. if f.SearchType=0 then
  479. begin
  480. i:=1;
  481. repeat
  482. if (RtlFindRecs[i].SearchNum=f.SearchNum) then
  483. break;
  484. inc(i);
  485. until (i>RtlFindSize);
  486. If i<=RtlFindSize Then
  487. Begin
  488. RtlFindRecs[i].SearchNum:=0;
  489. if f.dirptr<>nil then
  490. fpclosedir(pdir(f.dirptr)^);
  491. End;
  492. end;
  493. f.dirptr:=nil;
  494. End;
  495. Function FindGetFileInfo(const s:string;var f:SearchRec):boolean;
  496. var
  497. DT : DateTime;
  498. Info : RtlInfoType;
  499. st : baseunix.stat;
  500. begin
  501. FindGetFileInfo:=false;
  502. if not fpstat(s,st)>=0 then
  503. exit;
  504. info.FSize:=st.st_Size;
  505. info.FMTime:=st.st_mtime;
  506. if (st.st_mode and STAT_IFMT)=STAT_IFDIR then
  507. info.fmode:=$10
  508. else
  509. info.fmode:=$0;
  510. if (st.st_mode and STAT_IWUSR)=0 then
  511. info.fmode:=info.fmode or 1;
  512. if s[f.NamePos+1]='.' then
  513. info.fmode:=info.fmode or $2;
  514. If ((Info.FMode and Not(f.searchattr))=0) Then
  515. Begin
  516. f.Name:=Copy(s,f.NamePos+1,255);
  517. f.Attr:=Info.FMode;
  518. f.Size:=Info.FSize;
  519. f.mode:=st.st_mode;
  520. UnixDateToDT(Info.FMTime, DT);
  521. PackTime(DT,f.Time);
  522. FindGetFileInfo:=true;
  523. End;
  524. end;
  525. Function FindLastUsed: Longint;
  526. {
  527. Find unused or least recently used dirpointer slot in findrecs array
  528. }
  529. Var
  530. BestMatch,i : Longint;
  531. Found : Boolean;
  532. Begin
  533. BestMatch:=1;
  534. i:=1;
  535. Found:=False;
  536. While (i <= RtlFindSize) And (Not Found) Do
  537. Begin
  538. If (RtlFindRecs[i].SearchNum = 0) Then
  539. Begin
  540. BestMatch := i;
  541. Found := True;
  542. End
  543. Else
  544. Begin
  545. If RtlFindRecs[i].LastUsed > RtlFindRecs[BestMatch].LastUsed Then
  546. BestMatch := i;
  547. End;
  548. Inc(i);
  549. End;
  550. FindLastUsed := BestMatch;
  551. End;
  552. Procedure FindNext(Var f: SearchRec);
  553. {
  554. re-opens dir if not already in array and calls FindWorkProc
  555. }
  556. Var
  557. DirName : Array[0..256] of Char;
  558. i,
  559. ArrayPos : Longint;
  560. FName,
  561. SName : string;
  562. Found,
  563. Finished : boolean;
  564. p : pdirent;
  565. Begin
  566. If f.SearchType=0 Then
  567. Begin
  568. ArrayPos:=0;
  569. For i:=1 to RtlFindSize Do
  570. Begin
  571. If RtlFindRecs[i].SearchNum = f.SearchNum Then
  572. ArrayPos:=i;
  573. Inc(RtlFindRecs[i].LastUsed);
  574. End;
  575. If ArrayPos=0 Then
  576. Begin
  577. If f.NamePos = 0 Then
  578. Begin
  579. DirName[0] := '.';
  580. DirName[1] := '/';
  581. DirName[2] := #0;
  582. End
  583. Else
  584. Begin
  585. Move(f.SearchSpec[1], DirName[0], f.NamePos);
  586. DirName[f.NamePos] := #0;
  587. End;
  588. f.DirPtr := fpopendir(@DirName[0]);
  589. If f.DirPtr <> nil Then
  590. begin
  591. ArrayPos:=FindLastUsed;
  592. If RtlFindRecs[ArrayPos].SearchNum > 0 Then
  593. FpCloseDir((pdir(rtlfindrecs[arraypos].dirptr)^));
  594. RtlFindRecs[ArrayPos].SearchNum := f.SearchNum;
  595. RtlFindRecs[ArrayPos].DirPtr := f.DirPtr;
  596. if f.searchpos>0 then
  597. seekdir(pdir(f.dirptr), f.searchpos);
  598. end;
  599. End;
  600. if ArrayPos>0 then
  601. RtlFindRecs[ArrayPos].LastUsed:=0;
  602. end;
  603. {Main loop}
  604. SName:=Copy(f.SearchSpec,f.NamePos+1,255);
  605. Found:=False;
  606. Finished:=(f.dirptr=nil);
  607. While Not Finished Do
  608. Begin
  609. p:=fpreaddir(pdir(f.dirptr)^);
  610. if p=nil then
  611. FName:=''
  612. else
  613. FName:=Strpas(@p^.d_name[0]);
  614. If FName='' Then
  615. Finished:=True
  616. Else
  617. Begin
  618. If FNMatch(SName,FName) Then
  619. Begin
  620. Found:=FindGetFileInfo(Copy(f.SearchSpec,1,f.NamePos)+FName,f);
  621. if Found then
  622. Finished:=true;
  623. End;
  624. End;
  625. End;
  626. {Shutdown}
  627. If Found Then
  628. Begin
  629. f.searchpos:=telldir(pdir(f.dirptr));
  630. DosError:=0;
  631. End
  632. Else
  633. Begin
  634. FindClose(f);
  635. DosError:=18;
  636. End;
  637. End;
  638. Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
  639. {
  640. opens dir and calls FindWorkProc
  641. }
  642. Begin
  643. fillchar(f,sizeof(f),0);
  644. if Path='' then
  645. begin
  646. DosError:=3;
  647. exit;
  648. end;
  649. {Create Info}
  650. f.SearchSpec := Path;
  651. {We always also search for readonly and archive, regardless of Attr:}
  652. f.SearchAttr := Attr or archive or readonly;
  653. f.SearchPos := 0;
  654. f.NamePos := Length(f.SearchSpec);
  655. while (f.NamePos>0) and (f.SearchSpec[f.NamePos]<>'/') do
  656. dec(f.NamePos);
  657. {Wildcards?}
  658. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  659. begin
  660. if FindGetFileInfo(Path,f) then
  661. DosError:=0
  662. else
  663. begin
  664. { According to tdos2 test it should return 18
  665. if ErrNo=Sys_ENOENT then
  666. DosError:=3
  667. else }
  668. DosError:=18;
  669. end;
  670. f.DirPtr:=nil;
  671. f.SearchType:=1;
  672. f.searchnum:=-1;
  673. end
  674. else
  675. {Find Entry}
  676. begin
  677. Inc(CurrSearchNum);
  678. f.SearchNum:=CurrSearchNum;
  679. f.SearchType:=0;
  680. FindNext(f);
  681. end;
  682. End;
  683. {******************************************************************************
  684. --- File ---
  685. ******************************************************************************}
  686. Function FSearch(path : pathstr;dirlist : string) : pathstr;
  687. Var
  688. info : BaseUnix.stat;
  689. Begin
  690. if (length(Path)>0) and (path[1]='/') and (fpStat(path,info)>=0) and (not fpS_ISDIR(Info.st_Mode)) then
  691. FSearch:=path
  692. else
  693. FSearch:=Unix.FSearch(path,dirlist);
  694. End;
  695. Procedure GetFAttr(var f; var attr : word);
  696. Var
  697. info : baseunix.stat;
  698. LinAttr : longint;
  699. p : pchar;
  700. {$ifndef FPC_ANSI_TEXTFILEREC}
  701. r : RawByteString;
  702. {$endif not FPC_ANSI_TEXTFILEREC}
  703. Begin
  704. DosError:=0;
  705. {$ifdef FPC_ANSI_TEXTFILEREC}
  706. { encoding is already correct }
  707. p:=@textrec(f).name;
  708. {$else}
  709. r:=ToSingleByteFileSystemEncodedFileName(textrec(f).name);
  710. p:=pchar(r);
  711. {$endif}
  712. { use the pchar rather than the rawbytestring version so that we don't check
  713. a second time whether the string needs to be converted to the right code
  714. page
  715. }
  716. if FPStat(p,info)<0 then
  717. begin
  718. Attr:=0;
  719. DosError:=3;
  720. exit;
  721. end
  722. else
  723. LinAttr:=Info.st_Mode;
  724. if fpS_ISDIR(LinAttr) then
  725. Attr:=$10
  726. else
  727. Attr:=$0;
  728. if fpAccess(p,W_OK)<0 then
  729. Attr:=Attr or $1;
  730. if filerec(f).name[0]='.' then
  731. Attr:=Attr or $2;
  732. end;
  733. Procedure getftime (var f; var time : longint);
  734. Var
  735. Info: baseunix.stat;
  736. DT: DateTime;
  737. Begin
  738. doserror:=0;
  739. if fpfstat(filerec(f).handle,info)<0 then
  740. begin
  741. Time:=0;
  742. doserror:=6;
  743. exit
  744. end
  745. else
  746. UnixDateToDT(Info.st_mTime,DT);
  747. PackTime(DT,Time);
  748. End;
  749. Procedure setftime(var f; time : longint);
  750. Var
  751. utim: utimbuf;
  752. DT: DateTime;
  753. p : pchar;
  754. {$ifndef FPC_ANSI_TEXTFILEREC}
  755. r : Rawbytestring;
  756. {$endif not FPC_ANSI_TEXTFILEREC}
  757. Begin
  758. doserror:=0;
  759. with utim do
  760. begin
  761. actime:=fptime;
  762. UnPackTime(Time,DT);
  763. modtime:=DTToUnixDate(DT);
  764. end;
  765. {$ifdef FPC_ANSI_TEXTFILEREC}
  766. { encoding is already correct }
  767. p:=@textrec(f).name;
  768. {$else}
  769. r:=ToSingleByteFileSystemEncodedFileName(textrec(f).name);
  770. p:=pchar(r);
  771. {$endif}
  772. { use the pchar rather than the rawbytestring version so that we don't check
  773. a second time whether the string needs to be converted to the right code
  774. page
  775. }
  776. if fputime(p,@utim)<0 then
  777. begin
  778. Time:=0;
  779. doserror:=3;
  780. end;
  781. End;
  782. {******************************************************************************
  783. --- Environment ---
  784. ******************************************************************************}
  785. Function EnvCount: Longint;
  786. var
  787. envcnt : longint;
  788. p : ppchar;
  789. Begin
  790. envcnt:=0;
  791. p:=envp; {defined in syslinux}
  792. while (p^<>nil) do
  793. begin
  794. inc(envcnt);
  795. inc(p);
  796. end;
  797. EnvCount := envcnt
  798. End;
  799. Function EnvStr (Index: longint): String;
  800. Var
  801. i : longint;
  802. p : ppchar;
  803. Begin
  804. if Index <= 0 then
  805. envstr:=''
  806. else
  807. begin
  808. p:=envp; {defined in syslinux}
  809. i:=1;
  810. while (i<Index) and (p^<>nil) do
  811. begin
  812. inc(i);
  813. inc(p);
  814. end;
  815. if p=nil then
  816. envstr:=''
  817. else
  818. envstr:=strpas(p^)
  819. end;
  820. end;
  821. Function GetEnv(EnvVar: String): String;
  822. var
  823. p : pchar;
  824. Begin
  825. p:=BaseUnix.fpGetEnv(EnvVar);
  826. if p=nil then
  827. GetEnv:=''
  828. else
  829. GetEnv:=StrPas(p);
  830. End;
  831. Procedure setfattr (var f;attr : word);
  832. Begin
  833. {! No Unix equivalent !}
  834. { Fail for setting VolumeId }
  835. if (attr and VolumeID)<>0 then
  836. doserror:=5;
  837. End;
  838. {******************************************************************************
  839. --- Initialization ---
  840. ******************************************************************************}
  841. Finalization
  842. FreeDriveStr;
  843. End.