dos.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  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;
  43. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime);
  44. Function DTToUnixDate(DT: DateTime): LongInt;
  45. {Disk}
  46. Function AddDisk(const path:string) : byte;
  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 := 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 statfs 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],StrLen(DriveStr[Drives])+1);
  338. GetMem(DriveStr[Drives],length(Path)+1);
  339. StrPCopy(DriveStr[Drives],path);
  340. inc(Drives);
  341. if Drives>26 then
  342. Drives:=4;
  343. AddDisk:=Drives;
  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 (StatFS(fixdrivestr[drive],fs)<>-1)) or
  350. ((not (drivestr[Drive]=nil)) and (StatFS(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 (StatFS(fixdrivestr[drive],fs)<>-1)) or
  360. ((not (drivestr[Drive]=nil)) and (StatFS(drivestr[drive],fs)<>-1)) then
  361. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  362. else
  363. DiskSize:=-1;
  364. End;
  365. {******************************************************************************
  366. --- Findfirst FindNext ---
  367. ******************************************************************************}
  368. Function FNMatch(const Pattern,Name:string):Boolean;
  369. Var
  370. LenPat,LenName : longint;
  371. Function DoFNMatch(i,j:longint):Boolean;
  372. Var
  373. Found : boolean;
  374. Begin
  375. Found:=true;
  376. While Found and (i<=LenPat) Do
  377. Begin
  378. Case Pattern[i] of
  379. '?' : Found:=(j<=LenName);
  380. '*' : Begin
  381. {find the next character in pattern, different of ? and *}
  382. while Found do
  383. begin
  384. inc(i);
  385. if i>LenPat then Break;
  386. case Pattern[i] of
  387. '*' : ;
  388. '?' : begin
  389. if j>LenName then begin DoFNMatch:=false; Exit; end;
  390. inc(j);
  391. end;
  392. else
  393. Found:=false;
  394. end;
  395. end;
  396. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  397. {Now, find in name the character which i points to, if the * or ?
  398. wasn't the last character in the pattern, else, use up all the
  399. chars in name}
  400. Found:=false;
  401. if (i<=LenPat) then
  402. begin
  403. repeat
  404. {find a letter (not only first !) which maches pattern[i]}
  405. while (j<=LenName) and (name[j]<>pattern[i]) do
  406. inc (j);
  407. if (j<LenName) then
  408. begin
  409. if DoFnMatch(i+1,j+1) then
  410. begin
  411. i:=LenPat;
  412. j:=LenName;{we can stop}
  413. Found:=true;
  414. Break;
  415. end else
  416. inc(j);{We didn't find one, need to look further}
  417. end else
  418. if j=LenName then
  419. begin
  420. Found:=true;
  421. Break;
  422. end;
  423. { This 'until' condition must be j>LenName, not j>=LenName.
  424. That's because when we 'need to look further' and
  425. j = LenName then loop must not terminate. }
  426. until (j>LenName);
  427. end else
  428. begin
  429. j:=LenName;{we can stop}
  430. Found:=true;
  431. end;
  432. end;
  433. else {not a wildcard character in pattern}
  434. Found:=(j<=LenName) and (pattern[i]=name[j]);
  435. end;
  436. inc(i);
  437. inc(j);
  438. end;
  439. DoFnMatch:=Found and (j>LenName);
  440. end;
  441. Begin {start FNMatch}
  442. LenPat:=Length(Pattern);
  443. LenName:=Length(Name);
  444. FNMatch:=DoFNMatch(1,1);
  445. End;
  446. Const
  447. RtlFindSize = 15;
  448. Type
  449. RtlFindRecType = Record
  450. DirPtr : Pointer;
  451. SearchNum,
  452. LastUsed : LongInt;
  453. End;
  454. Var
  455. RtlFindRecs : Array[1..RtlFindSize] of RtlFindRecType;
  456. CurrSearchNum : LongInt;
  457. Procedure FindClose(Var f: SearchRec);
  458. {
  459. Closes dirptr if it is open
  460. }
  461. Var
  462. i : longint;
  463. Begin
  464. if f.SearchType=0 then
  465. begin
  466. i:=1;
  467. repeat
  468. if (RtlFindRecs[i].SearchNum=f.SearchNum) then
  469. break;
  470. inc(i);
  471. until (i>RtlFindSize);
  472. If i<=RtlFindSize Then
  473. Begin
  474. RtlFindRecs[i].SearchNum:=0;
  475. if f.dirptr<>nil then
  476. fpclosedir(pdir(f.dirptr)^);
  477. End;
  478. end;
  479. f.dirptr:=nil;
  480. End;
  481. Function FindGetFileInfo(const s:string;var f:SearchRec):boolean;
  482. var
  483. DT : DateTime;
  484. Info : RtlInfoType;
  485. st : baseunix.stat;
  486. begin
  487. FindGetFileInfo:=false;
  488. if not fpstat(s,st)>=0 then
  489. exit;
  490. info.FSize:=st.st_Size;
  491. info.FMTime:=st.st_mtime;
  492. if (st.st_mode and STAT_IFMT)=STAT_IFDIR then
  493. info.fmode:=$10
  494. else
  495. info.fmode:=$0;
  496. if (st.st_mode and STAT_IWUSR)=0 then
  497. info.fmode:=info.fmode or 1;
  498. if s[f.NamePos+1]='.' then
  499. info.fmode:=info.fmode or $2;
  500. If ((Info.FMode and Not(f.searchattr))=0) Then
  501. Begin
  502. f.Name:=Copy(s,f.NamePos+1,255);
  503. f.Attr:=Info.FMode;
  504. f.Size:=Info.FSize;
  505. f.mode:=st.st_mode;
  506. UnixDateToDT(Info.FMTime, DT);
  507. PackTime(DT,f.Time);
  508. FindGetFileInfo:=true;
  509. End;
  510. end;
  511. Function FindLastUsed: Longint;
  512. {
  513. Find unused or least recently used dirpointer slot in findrecs array
  514. }
  515. Var
  516. BestMatch,i : Longint;
  517. Found : Boolean;
  518. Begin
  519. BestMatch:=1;
  520. i:=1;
  521. Found:=False;
  522. While (i <= RtlFindSize) And (Not Found) Do
  523. Begin
  524. If (RtlFindRecs[i].SearchNum = 0) Then
  525. Begin
  526. BestMatch := i;
  527. Found := True;
  528. End
  529. Else
  530. Begin
  531. If RtlFindRecs[i].LastUsed > RtlFindRecs[BestMatch].LastUsed Then
  532. BestMatch := i;
  533. End;
  534. Inc(i);
  535. End;
  536. FindLastUsed := BestMatch;
  537. End;
  538. Procedure FindNext(Var f: SearchRec);
  539. {
  540. re-opens dir if not already in array and calls FindWorkProc
  541. }
  542. Var
  543. DirName : Array[0..256] of Char;
  544. i,
  545. ArrayPos : Longint;
  546. FName,
  547. SName : string;
  548. Found,
  549. Finished : boolean;
  550. p : pdirent;
  551. Begin
  552. If f.SearchType=0 Then
  553. Begin
  554. ArrayPos:=0;
  555. For i:=1 to RtlFindSize Do
  556. Begin
  557. If RtlFindRecs[i].SearchNum = f.SearchNum Then
  558. ArrayPos:=i;
  559. Inc(RtlFindRecs[i].LastUsed);
  560. End;
  561. If ArrayPos=0 Then
  562. Begin
  563. If f.NamePos = 0 Then
  564. Begin
  565. DirName[0] := '.';
  566. DirName[1] := '/';
  567. DirName[2] := #0;
  568. End
  569. Else
  570. Begin
  571. Move(f.SearchSpec[1], DirName[0], f.NamePos);
  572. DirName[f.NamePos] := #0;
  573. End;
  574. f.DirPtr := fpopendir(@DirName[0]);
  575. If f.DirPtr <> nil Then
  576. begin
  577. ArrayPos:=FindLastUsed;
  578. If RtlFindRecs[ArrayPos].SearchNum > 0 Then
  579. FpCloseDir((pdir(rtlfindrecs[arraypos].dirptr)^));
  580. RtlFindRecs[ArrayPos].SearchNum := f.SearchNum;
  581. RtlFindRecs[ArrayPos].DirPtr := f.DirPtr;
  582. if f.searchpos>0 then
  583. seekdir(pdir(f.dirptr), f.searchpos);
  584. end;
  585. End;
  586. if ArrayPos>0 then
  587. RtlFindRecs[ArrayPos].LastUsed:=0;
  588. end;
  589. {Main loop}
  590. SName:=Copy(f.SearchSpec,f.NamePos+1,255);
  591. Found:=False;
  592. Finished:=(f.dirptr=nil);
  593. While Not Finished Do
  594. Begin
  595. p:=fpreaddir(pdir(f.dirptr)^);
  596. if p=nil then
  597. FName:=''
  598. else
  599. FName:=Strpas(@p^.d_name[0]);
  600. If FName='' Then
  601. Finished:=True
  602. Else
  603. Begin
  604. If FNMatch(SName,FName) Then
  605. Begin
  606. Found:=FindGetFileInfo(Copy(f.SearchSpec,1,f.NamePos)+FName,f);
  607. if Found then
  608. Finished:=true;
  609. End;
  610. End;
  611. End;
  612. {Shutdown}
  613. If Found Then
  614. Begin
  615. f.searchpos:=telldir(pdir(f.dirptr));
  616. DosError:=0;
  617. End
  618. Else
  619. Begin
  620. FindClose(f);
  621. DosError:=18;
  622. End;
  623. End;
  624. Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
  625. {
  626. opens dir and calls FindWorkProc
  627. }
  628. Begin
  629. fillchar(f,sizeof(f),0);
  630. if Path='' then
  631. begin
  632. DosError:=3;
  633. exit;
  634. end;
  635. {Create Info}
  636. f.SearchSpec := Path;
  637. {We always also search for readonly and archive, regardless of Attr:}
  638. f.SearchAttr := Attr or archive or readonly;
  639. f.SearchPos := 0;
  640. f.NamePos := Length(f.SearchSpec);
  641. while (f.NamePos>0) and (f.SearchSpec[f.NamePos]<>'/') do
  642. dec(f.NamePos);
  643. {Wildcards?}
  644. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  645. begin
  646. if FindGetFileInfo(Path,f) then
  647. DosError:=0
  648. else
  649. begin
  650. { According to tdos2 test it should return 18
  651. if ErrNo=Sys_ENOENT then
  652. DosError:=3
  653. else }
  654. DosError:=18;
  655. end;
  656. f.DirPtr:=nil;
  657. f.SearchType:=1;
  658. f.searchnum:=-1;
  659. end
  660. else
  661. {Find Entry}
  662. begin
  663. Inc(CurrSearchNum);
  664. f.SearchNum:=CurrSearchNum;
  665. f.SearchType:=0;
  666. FindNext(f);
  667. end;
  668. End;
  669. {******************************************************************************
  670. --- File ---
  671. ******************************************************************************}
  672. Function FSearch(path : pathstr;dirlist : string) : pathstr;
  673. Var
  674. info : BaseUnix.stat;
  675. Begin
  676. if (length(Path)>0) and (path[1]='/') and (fpStat(path,info)>=0) and (not fpS_ISDIR(Info.st_Mode)) then
  677. FSearch:=path
  678. else
  679. FSearch:=Unix.FSearch(path,dirlist);
  680. End;
  681. Procedure GetFAttr(var f; var attr : word);
  682. Var
  683. info : baseunix.stat;
  684. LinAttr : longint;
  685. Begin
  686. DosError:=0;
  687. if FPStat(@textrec(f).name[0],info)<0 then
  688. begin
  689. Attr:=0;
  690. DosError:=3;
  691. exit;
  692. end
  693. else
  694. LinAttr:=Info.st_Mode;
  695. if fpS_ISDIR(LinAttr) then
  696. Attr:=$10
  697. else
  698. Attr:=$0;
  699. if fpAccess(@textrec(f).name[0],W_OK)<0 then
  700. Attr:=Attr or $1;
  701. if filerec(f).name[0]='.' then
  702. Attr:=Attr or $2;
  703. end;
  704. Procedure getftime (var f; var time : longint);
  705. Var
  706. Info: baseunix.stat;
  707. DT: DateTime;
  708. Begin
  709. doserror:=0;
  710. if fpfstat(filerec(f).handle,info)<0 then
  711. begin
  712. Time:=0;
  713. doserror:=6;
  714. exit
  715. end
  716. else
  717. UnixDateToDT(Info.st_mTime,DT);
  718. PackTime(DT,Time);
  719. End;
  720. Procedure setftime(var f; time : longint);
  721. Var
  722. utim: utimbuf;
  723. DT: DateTime;
  724. Begin
  725. doserror:=0;
  726. with utim do
  727. begin
  728. actime:=fptime;
  729. UnPackTime(Time,DT);
  730. modtime:=DTToUnixDate(DT);
  731. end;
  732. if fputime(@filerec(f).name[0],@utim)<0 then
  733. begin
  734. Time:=0;
  735. doserror:=3;
  736. end;
  737. End;
  738. {******************************************************************************
  739. --- Environment ---
  740. ******************************************************************************}
  741. Function EnvCount: Longint;
  742. var
  743. envcnt : longint;
  744. p : ppchar;
  745. Begin
  746. envcnt:=0;
  747. p:=envp; {defined in syslinux}
  748. while (p^<>nil) do
  749. begin
  750. inc(envcnt);
  751. inc(p);
  752. end;
  753. EnvCount := envcnt
  754. End;
  755. Function EnvStr (Index: longint): String;
  756. Var
  757. i : longint;
  758. p : ppchar;
  759. Begin
  760. if Index <= 0 then
  761. envstr:=''
  762. else
  763. begin
  764. p:=envp; {defined in syslinux}
  765. i:=1;
  766. while (i<Index) and (p^<>nil) do
  767. begin
  768. inc(i);
  769. inc(p);
  770. end;
  771. if p=nil then
  772. envstr:=''
  773. else
  774. envstr:=strpas(p^)
  775. end;
  776. end;
  777. Function GetEnv(EnvVar: String): String;
  778. var
  779. p : pchar;
  780. Begin
  781. p:=BaseUnix.fpGetEnv(EnvVar);
  782. if p=nil then
  783. GetEnv:=''
  784. else
  785. GetEnv:=StrPas(p);
  786. End;
  787. Procedure setfattr (var f;attr : word);
  788. Begin
  789. {! No Unix equivalent !}
  790. { Fail for setting VolumeId }
  791. if (attr and VolumeID)<>0 then
  792. doserror:=5;
  793. End;
  794. {******************************************************************************
  795. --- Initialization ---
  796. ******************************************************************************}
  797. End.