dos.pp 21 KB

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