dos.pp 21 KB

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