dos.pp 21 KB

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