dos.pp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2001 by members of the Free Pascal
  5. development team
  6. DOS unit template based on POSIX
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. Unit Dos;
  14. Interface
  15. {$goto on}
  16. Const
  17. {Max FileName Length for files}
  18. FileNameLen=255;
  19. {Bitmasks for CPU Flags}
  20. fcarry = $0001;
  21. fparity = $0004;
  22. fauxiliary = $0010;
  23. fzero = $0040;
  24. fsign = $0080;
  25. foverflow = $0800;
  26. {Bitmasks for file attribute}
  27. readonly = $01;
  28. hidden = $02;
  29. sysfile = $04;
  30. volumeid = $08;
  31. directory = $10;
  32. archive = $20;
  33. anyfile = $3F;
  34. {File Status}
  35. fmclosed = $D7B0;
  36. fminput = $D7B1;
  37. fmoutput = $D7B2;
  38. fminout = $D7B3;
  39. Type
  40. ComStr = String[FileNameLen];
  41. PathStr = String[FileNameLen];
  42. DirStr = String[FileNameLen];
  43. NameStr = String[FileNameLen];
  44. ExtStr = String[FileNameLen];
  45. SearchRec = packed Record
  46. {Fill : array[1..21] of byte; Fill replaced with below}
  47. DirPtr : pointer; {directory pointer for reading directory}
  48. SearchAttr : Byte; {attribute we are searching for}
  49. Fill : Array[1..16] of Byte; {future use}
  50. {End of fill}
  51. Attr : Byte; {attribute of found file}
  52. Time : LongInt; {last modify date of found file}
  53. Size : LongInt; {file size of found file}
  54. Reserved : Word; {future use}
  55. Name : String[FileNameLen]; {name of found file}
  56. SearchSpec : String[FileNameLen]; {search pattern}
  57. SearchDir : String[FileNameLen]; { path we are searching in }
  58. End;
  59. {
  60. filerec.inc contains the definition of the filerec.
  61. textrec.inc contains the definition of the textrec.
  62. It is in a separate file to make it available in other units without
  63. having to use the DOS unit for it.
  64. }
  65. {$i filerec.inc}
  66. {$i textrec.inc}
  67. Registers = packed record
  68. case i : integer of
  69. 0 : (ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,f8,flags,fs,gs : word);
  70. 1 : (al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh : byte);
  71. 2 : (eax, ebx, ecx, edx, ebp, esi, edi : longint);
  72. End;
  73. DateTime = packed record
  74. Year,
  75. Month,
  76. Day,
  77. Hour,
  78. Min,
  79. Sec : word;
  80. End;
  81. Var
  82. DosError : integer;
  83. {Info/Date/Time}
  84. Function DosVersion: Word;
  85. Procedure GetDate(var year, month, mday, wday: word);
  86. Procedure GetTime(var hour, minute, second, sec100: word);
  87. procedure SetDate(year,month,day: word);
  88. Procedure SetTime(hour,minute,second,sec100: word);
  89. Procedure UnpackTime(p: longint; var t: datetime);
  90. Procedure PackTime(var t: datetime; var p: longint);
  91. {Exec}
  92. Procedure Exec(const path: pathstr; const comline: comstr);
  93. Function DosExitCode: word;
  94. {Disk}
  95. Procedure AddDisk(const path:string);
  96. Function DiskFree(drive: byte) : int64;
  97. Function DiskSize(drive: byte) : int64;
  98. Procedure FindFirst(const path: pathstr; attr: word; var f: searchRec);
  99. Procedure FindNext(var f: searchRec);
  100. Procedure FindClose(Var f: SearchRec);
  101. {File}
  102. Procedure GetFAttr(var f; var attr: word);
  103. Procedure GetFTime(var f; var time: longint);
  104. Function FSearch(const path: pathstr; dirlist: string): pathstr;
  105. Function FExpand(const path: pathstr): pathstr;
  106. Procedure FSplit(const path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
  107. {Environment}
  108. Function EnvCount: longint;
  109. Function EnvStr(index: integer): string;
  110. Function GetEnv (envvar: string): string;
  111. {Do Nothing Functions, no POSIX version}
  112. Procedure Intr(intno: byte; var regs: registers);
  113. Procedure MSDos(var regs: registers);
  114. Procedure SwapVectors;
  115. Procedure GetIntVec(intno: byte; var vector: pointer);
  116. Procedure SetIntVec(intno: byte; vector: pointer);
  117. Procedure Keep(exitcode: word);
  118. Procedure SetFAttr(var f; attr: word);
  119. Procedure SetFTime(var f; time: longint);
  120. Procedure GetCBreak(var breakvalue: boolean);
  121. Procedure SetCBreak(breakvalue: boolean);
  122. Procedure GetVerify(var verify: boolean);
  123. Procedure SetVerify(verify: boolean);
  124. Implementation
  125. Uses
  126. Strings,posix;
  127. { Used by AddDisk(), DiskFree() and DiskSize() }
  128. const
  129. Drives : byte = 4;
  130. MAX_DRIVES = 26;
  131. var
  132. DriveStr : array[4..MAX_DRIVES] of pchar;
  133. Function StringToPPChar(Var S:STring; var count : longint):ppchar;
  134. {
  135. Create a PPChar to structure of pchars which are the arguments specified
  136. in the string S. Especially usefull for creating an ArgV for Exec-calls
  137. }
  138. var
  139. nr : longint;
  140. Buf : ^char;
  141. p : ppchar;
  142. begin
  143. s:=s+#0;
  144. buf:=@s[1];
  145. nr:=0;
  146. while(buf^<>#0) do
  147. begin
  148. while (buf^ in [' ',#8,#10]) do
  149. inc(buf);
  150. inc(nr);
  151. while not (buf^ in [' ',#0,#8,#10]) do
  152. inc(buf);
  153. end;
  154. getmem(p,nr*4);
  155. StringToPPChar:=p;
  156. if p=nil then
  157. begin
  158. Errno:=sys_enomem;
  159. count := 0;
  160. exit;
  161. end;
  162. buf:=@s[1];
  163. while (buf^<>#0) do
  164. begin
  165. while (buf^ in [' ',#8,#10]) do
  166. begin
  167. buf^:=#0;
  168. inc(buf);
  169. end;
  170. p^:=buf;
  171. inc(p);
  172. p^:=nil;
  173. while not (buf^ in [' ',#0,#8,#10]) do
  174. inc(buf);
  175. end;
  176. count := nr;
  177. end;
  178. {$i dos.inc} { include OS specific stuff }
  179. {******************************************************************************
  180. --- Info / Date / Time ---
  181. ******************************************************************************}
  182. var
  183. TZSeconds : longint; { offset to add/ subtract from Epoch to get local time }
  184. tzdaylight : boolean;
  185. tzname : array[boolean] of pchar;
  186. type
  187. GTRec = packed Record
  188. Year,
  189. Month,
  190. MDay,
  191. WDay,
  192. Hour,
  193. Minute,
  194. Second : Word;
  195. End;
  196. Const
  197. {Date Calculation}
  198. C1970 = 2440588;
  199. D0 = 1461;
  200. D1 = 146097;
  201. D2 = 1721119;
  202. function WeekDay (y,m,d:longint):longint;
  203. {
  204. Calculates th day of the week. returns -1 on error
  205. }
  206. var
  207. u,v : longint;
  208. begin
  209. if (m<1) or (m>12) or (y<1600) or (y>4000) or
  210. (d<1) or (d>30+((m+ord(m>7)) and 1)-ord(m=2)) or
  211. ((m*d=58) and (((y mod 4>0) or (y mod 100=0)) and (y mod 400>0))) then
  212. WeekDay:=-1
  213. else
  214. begin
  215. u:=m;
  216. v:=y;
  217. if m<3 then
  218. begin
  219. inc(u,12);
  220. dec(v);
  221. end;
  222. WeekDay:=(d+2*u+((3*(u+1)) div 5)+v+(v div 4)-(v div 100)+(v div 400)+1) mod 7;
  223. end;
  224. end;
  225. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  226. Var
  227. YYear,XYear,Temp,TempMonth : LongInt;
  228. Begin
  229. Temp:=((JulianDN-D2) shl 2)-1;
  230. JulianDN:=Temp Div D1;
  231. XYear:=(Temp Mod D1) or 3;
  232. YYear:=(XYear Div D0);
  233. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  234. Day:=((Temp Mod 153)+5) Div 5;
  235. TempMonth:=Temp Div 153;
  236. If TempMonth>=10 Then
  237. Begin
  238. inc(YYear);
  239. dec(TempMonth,12);
  240. End;
  241. inc(TempMonth,3);
  242. Month := TempMonth;
  243. Year:=YYear+(JulianDN*100);
  244. end;
  245. Procedure EpochToLocal(epoch:time_t;var year,month,day,hour,minute,second:Word);
  246. {
  247. Transforms Epoch time into local time (hour, minute,seconds)
  248. }
  249. Var
  250. DateNum: time_t;
  251. Begin
  252. Epoch:=Epoch+TZSeconds;
  253. Datenum:=(Epoch Div 86400) + c1970;
  254. JulianToGregorian(DateNum,Year,Month,day);
  255. Epoch:=Abs(Epoch Mod 86400);
  256. Hour:=Epoch Div 3600;
  257. Epoch:=Epoch Mod 3600;
  258. Minute:=Epoch Div 60;
  259. Second:=Epoch Mod 60;
  260. End;
  261. Procedure GetDate(Var Year, Month, MDay, WDay: Word);
  262. var
  263. hour,minute,second : word;
  264. timeval : time_t;
  265. Begin
  266. timeval := sys_time(timeval);
  267. { convert the GMT time to local time }
  268. EpochToLocal(timeval,year,month,mday,hour,minute,second);
  269. Wday:=weekday(Year,Month,MDay);
  270. end;
  271. Procedure SetDate(Year, Month, Day: Word);
  272. Begin
  273. {!!}
  274. End;
  275. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  276. var
  277. timeval : time_t;
  278. year,month,day: word;
  279. Begin
  280. timeval := sys_time(timeval);
  281. EpochToLocal(timeval,year,month,day,hour,minute,second);
  282. Sec100 := 0;
  283. end;
  284. Procedure SetTime(Hour, Minute, Second, Sec100: Word);
  285. Begin
  286. {!!}
  287. End;
  288. Procedure packtime(var t : datetime;var p : longint);
  289. Begin
  290. p:=(t.sec shr 1)+(t.min shl 5)+(t.hour shl 11)+(t.day shl 16)+(t.month shl 21)+((t.year-1980) shl 25);
  291. End;
  292. Procedure unpacktime(p : longint;var t : datetime);
  293. Begin
  294. t.sec:=(p and 31) shl 1;
  295. t.min:=(p shr 5) and 63;
  296. t.hour:=(p shr 11) and 31;
  297. t.day:=(p shr 16) and 31;
  298. t.month:=(p shr 21) and 15;
  299. t.year:=(p shr 25)+1980;
  300. End;
  301. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime);
  302. Begin
  303. EpochToLocal(SecsPast,dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  304. End;
  305. {$ifndef DOS_HAS_EXEC}
  306. {******************************************************************************
  307. --- Exec ---
  308. ******************************************************************************}
  309. var
  310. LastDosExitCode: word;
  311. Function InternalWaitProcess(Pid:pid_t):Longint; { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  312. var r,s : cint;
  313. begin
  314. repeat
  315. s:=$7F00;
  316. r:=sys_WaitPid(Pid,s,0);
  317. until (r<>-1) or (Errno<>Sys_EINTR);
  318. { When r = -1 or r = 0, no status is available, so there was an error. }
  319. if (r=-1) or (r=0) then
  320. InternalWaitProcess:=-1 { return -1 to indicate an error }
  321. else
  322. begin
  323. { process terminated normally }
  324. if wifexited(s)<>0 then
  325. begin
  326. { get status code }
  327. InternalWaitProcess := wexitstatus(s);
  328. exit;
  329. end;
  330. { process terminated due to a signal }
  331. if wifsignaled(s)<>0 then
  332. begin
  333. { get signal number }
  334. InternalWaitProcess := wstopsig(s);
  335. exit;
  336. end;
  337. InternalWaitProcess:=-1;
  338. end;
  339. end;
  340. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  341. var
  342. pid : pid_t;
  343. tmp : string;
  344. p : ppchar;
  345. count: longint;
  346. // The Error-Checking in the previous Version failed, since halt($7F) gives an WaitPid-status of $7F00
  347. F: File;
  348. Begin
  349. {$IFOPT I+}
  350. {$DEFINE IOCHECK}
  351. {$ENDIF}
  352. {$I-}
  353. { verify if the file to execute exists }
  354. Assign(F,Path);
  355. Reset(F,1);
  356. if IOResult <> 0 then
  357. { file not found }
  358. begin
  359. DosError := 2;
  360. exit;
  361. end
  362. else
  363. Close(F);
  364. {$IFDEF IOCHECK}
  365. {$I+}
  366. {$UNDEF IOCHECK}
  367. {$ENDIF}
  368. LastDosExitCode:=0;
  369. { Fork the process }
  370. pid:=sys_Fork;
  371. if pid=0 then
  372. begin
  373. {The child does the actual execution, and then exits}
  374. tmp := Path+' '+ComLine;
  375. p:=StringToPPChar(tmp,count);
  376. if (p<>nil) and (p^<>nil) then
  377. begin
  378. sys_Execve(p^,p,Envp);
  379. end;
  380. {If the execve fails, we return an exitvalue of 127, to let it be known}
  381. sys_exit(127);
  382. end
  383. else
  384. if pid=-1 then {Fork failed - parent only}
  385. begin
  386. DosError:=8;
  387. exit
  388. end;
  389. {We're in the parent, let's wait.}
  390. LastDosExitCode:=InternalWaitProcess(pid); // WaitPid and result-convert
  391. if (LastDosExitCode>=0) and (LastDosExitCode<>127) then DosError:=0 else
  392. DosError:=8; // perhaps one time give an better error
  393. End;
  394. Function DosExitCode: Word;
  395. Begin
  396. DosExitCode:=LastDosExitCode;
  397. End;
  398. {$ENDIF}
  399. {******************************************************************************
  400. --- Disk ---
  401. ******************************************************************************}
  402. Procedure AddDisk(const path:string);
  403. begin
  404. if not (DriveStr[Drives]=nil) then
  405. FreeMem(DriveStr[Drives],StrLen(DriveStr[Drives])+1);
  406. GetMem(DriveStr[Drives],length(Path)+1);
  407. StrPCopy(DriveStr[Drives],path);
  408. inc(Drives);
  409. if Drives>26 then
  410. Drives:=4;
  411. end;
  412. {******************************************************************************
  413. --- Findfirst FindNext ---
  414. ******************************************************************************}
  415. Function FNMatch(const Pattern,Name:string):Boolean;
  416. Var
  417. LenPat,LenName : longint;
  418. Function DoFNMatch(i,j:longint):Boolean;
  419. Var
  420. Found : boolean;
  421. Begin
  422. Found:=true;
  423. While Found and (i<=LenPat) Do
  424. Begin
  425. Case Pattern[i] of
  426. '?' : Found:=(j<=LenName);
  427. '*' : Begin
  428. {find the next character in pattern, different of ? and *}
  429. while Found and (i<LenPat) do
  430. begin
  431. inc(i);
  432. case Pattern[i] of
  433. '*' : ;
  434. '?' : begin
  435. inc(j);
  436. Found:=(j<=LenName);
  437. end;
  438. else
  439. Found:=false;
  440. end;
  441. end;
  442. {Now, find in name the character which i points to, if the * or ?
  443. wasn't the last character in the pattern, else, use up all the
  444. chars in name}
  445. Found:=true;
  446. if (i<=LenPat) then
  447. begin
  448. repeat
  449. {find a letter (not only first !) which maches pattern[i]}
  450. while (j<=LenName) and (name[j]<>pattern[i]) do
  451. inc (j);
  452. if (j<LenName) then
  453. begin
  454. if DoFnMatch(i+1,j+1) then
  455. begin
  456. i:=LenPat;
  457. j:=LenName;{we can stop}
  458. Found:=true;
  459. end
  460. else
  461. inc(j);{We didn't find one, need to look further}
  462. end;
  463. until (j>=LenName);
  464. end
  465. else
  466. j:=LenName;{we can stop}
  467. end;
  468. else {not a wildcard character in pattern}
  469. Found:=(j<=LenName) and (pattern[i]=name[j]);
  470. end;
  471. inc(i);
  472. inc(j);
  473. end;
  474. DoFnMatch:=Found and (j>LenName);
  475. end;
  476. Begin {start FNMatch}
  477. LenPat:=Length(Pattern);
  478. LenName:=Length(Name);
  479. FNMatch:=DoFNMatch(1,1);
  480. End;
  481. Procedure FindClose(Var f: SearchRec);
  482. {
  483. Closes dirptr if it is open
  484. }
  485. Begin
  486. { could already have been closed }
  487. if assigned(f.dirptr) then
  488. sys_closedir(pdir(f.dirptr));
  489. f.dirptr := nil;
  490. End;
  491. { Returns a filled in searchRec structure }
  492. { and TRUE if the specified file in s is }
  493. { found. }
  494. Function FindGetFileInfo(s:string;var f:SearchRec):boolean;
  495. var
  496. DT : DateTime;
  497. st : stat;
  498. Fmode : byte;
  499. res: string; { overlaid variable }
  500. Dir : DirsTr;
  501. Name : NameStr;
  502. Ext: ExtStr;
  503. begin
  504. FindGetFileInfo:=false;
  505. res := s + #0;
  506. if sys_stat(@res[1],st)<>0 then
  507. exit;
  508. if S_ISDIR(st.st_mode) then
  509. fmode:=directory
  510. else
  511. fmode:=0;
  512. if (st.st_mode and S_IWUSR)=0 then
  513. fmode:=fmode or readonly;
  514. FSplit(s,Dir,Name,Ext);
  515. if Name[1]='.' then
  516. fmode:=fmode or hidden;
  517. If ((FMode and Not(f.searchattr))=0) Then
  518. Begin
  519. if Ext <> '' then
  520. res := Name + Ext
  521. else
  522. res := Name;
  523. f.Name:=res;
  524. f.Attr:=FMode;
  525. f.Size:=longint(st.st_size);
  526. UnixDateToDT(st.st_mtime, DT);
  527. PackTime(DT,f.Time);
  528. FindGetFileInfo:=true;
  529. End;
  530. end;
  531. Procedure FindNext(Var f: SearchRec);
  532. {
  533. re-opens dir if not already in array and calls FindWorkProc
  534. }
  535. Var
  536. FName,
  537. SName : string;
  538. Found,
  539. Finished : boolean;
  540. p : PDirEnt;
  541. Begin
  542. {Main loop}
  543. SName:=f.SearchSpec;
  544. Found:=False;
  545. Finished:=(f.dirptr=nil);
  546. While Not Finished Do
  547. Begin
  548. p:=sys_readdir(pdir(f.dirptr));
  549. if p=nil then
  550. begin
  551. FName:=''
  552. end
  553. else
  554. FName:=Strpas(@p^.d_name);
  555. If FName='' Then
  556. Finished:=True
  557. Else
  558. Begin
  559. If FNMatch(SName,FName) Then
  560. Begin
  561. Found:=FindGetFileInfo(f.SearchDir+FName,f);
  562. if Found then
  563. begin
  564. Finished:=true;
  565. end;
  566. End;
  567. End;
  568. End;
  569. {Shutdown}
  570. If Found Then
  571. Begin
  572. DosError:=0;
  573. End
  574. Else
  575. Begin
  576. FindClose(f);
  577. { FindClose() might be called thereafter also... }
  578. f.dirptr := nil;
  579. DosError:=18;
  580. End;
  581. End;
  582. Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
  583. {
  584. opens dir
  585. }
  586. var
  587. res: string;
  588. Dir : DirsTr;
  589. Name : NameStr;
  590. Ext: ExtStr;
  591. Begin
  592. { initialize f.dirptr because it is used }
  593. { to see if we need to close the dir stream }
  594. f.dirptr := nil;
  595. if Path='' then
  596. begin
  597. DosError:=3;
  598. exit;
  599. end;
  600. {We always also search for readonly and archive, regardless of Attr:}
  601. f.SearchAttr := Attr or archive or readonly;
  602. {Wildcards?}
  603. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  604. begin
  605. if FindGetFileInfo(Path,f) then
  606. DosError:=0
  607. else
  608. begin
  609. if ErrNo=Sys_ENOENT then
  610. DosError:=3
  611. else
  612. DosError:=18;
  613. end;
  614. f.DirPtr:=nil;
  615. end
  616. else
  617. {Find Entry}
  618. begin
  619. FSplit(Path,Dir,Name,Ext);
  620. if Ext <> '' then
  621. res := Name + Ext
  622. else
  623. res := Name;
  624. f.SearchSpec := res;
  625. { if dir is an empty string }
  626. { then this indicates that }
  627. { use the current working }
  628. { directory. }
  629. if dir = '' then
  630. dir := './';
  631. f.SearchDir := Dir;
  632. { add terminating null character }
  633. Dir := Dir + #0;
  634. f.dirptr := sys_opendir(@Dir[1]);
  635. if not assigned(f.dirptr) then
  636. begin
  637. DosError := 8;
  638. exit;
  639. end;
  640. FindNext(f);
  641. end;
  642. End;
  643. {******************************************************************************
  644. --- File ---
  645. ******************************************************************************}
  646. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  647. Var
  648. DotPos,SlashPos,i : longint;
  649. Begin
  650. SlashPos:=0;
  651. DotPos:=256;
  652. i:=Length(Path);
  653. While (i>0) and (SlashPos=0) Do
  654. Begin
  655. If (DotPos=256) and (Path[i]='.') Then
  656. begin
  657. DotPos:=i;
  658. end;
  659. If (Path[i]='/') Then
  660. SlashPos:=i;
  661. Dec(i);
  662. End;
  663. Ext:=Copy(Path,DotPos,255);
  664. Dir:=Copy(Path,1,SlashPos);
  665. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  666. End;
  667. {
  668. function FExpand (const Path: PathStr): PathStr;
  669. - declared in fexpand.inc
  670. }
  671. (*
  672. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  673. *)
  674. const
  675. LFNSupport = true;
  676. FileNameCaseSensitive = true;
  677. {$I fexpand.inc}
  678. Function FSearch(const path:pathstr;dirlist:string):pathstr;
  679. {
  680. Searches for a file 'path' in the list of direcories in 'dirlist'.
  681. returns an empty string if not found. Wildcards are NOT allowed.
  682. If dirlist is empty, it is set to '.'
  683. }
  684. Var
  685. NewDir : PathStr;
  686. p1 : Longint;
  687. Info : Stat;
  688. buffer : array[0..FileNameLen+1] of char;
  689. Begin
  690. Move(path[1], Buffer, Length(path));
  691. Buffer[Length(path)]:=#0;
  692. if (length(Path)>0) and (path[1]='/') and (sys_stat(pchar(@Buffer),info)=0) then
  693. begin
  694. FSearch:=path;
  695. exit;
  696. end;
  697. {Replace ':' with ';'}
  698. for p1:=1to length(dirlist) do
  699. if dirlist[p1]=':' then
  700. dirlist[p1]:=';';
  701. {Check for WildCards}
  702. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  703. FSearch:='' {No wildcards allowed in these things.}
  704. Else
  705. Begin
  706. Dirlist:='.;'+dirlist;{Make sure current dir is first to be searched.}
  707. Repeat
  708. p1:=Pos(';',DirList);
  709. If p1=0 Then
  710. p1:=255;
  711. NewDir:=Copy(DirList,1,P1 - 1);
  712. if NewDir[Length(NewDir)]<>'/' then
  713. NewDir:=NewDir+'/';
  714. NewDir:=NewDir+Path;
  715. Delete(DirList,1,p1);
  716. Move(NewDir[1], Buffer, Length(NewDir));
  717. Buffer[Length(NewDir)]:=#0;
  718. if sys_stat(pchar(@Buffer),Info)=0 then
  719. Begin
  720. If Pos('./',NewDir)=1 Then
  721. Delete(NewDir,1,2);
  722. {DOS strips off an initial .\}
  723. End
  724. Else
  725. NewDir:='';
  726. Until (DirList='') or (Length(NewDir) > 0);
  727. FSearch:=NewDir;
  728. End;
  729. End;
  730. Procedure GetFAttr(var f; var attr : word);
  731. Var
  732. info : stat;
  733. LinAttr : mode_t;
  734. Begin
  735. DosError:=0;
  736. if sys_stat(@textrec(f).name,info)<>0 then
  737. begin
  738. Attr:=0;
  739. DosError:=3;
  740. exit;
  741. end
  742. else
  743. LinAttr:=Info.st_Mode;
  744. if S_ISDIR(LinAttr) then
  745. Attr:=directory
  746. else
  747. Attr:=0;
  748. if sys_Access(@textrec(f).name,W_OK)<>0 then
  749. Attr:=Attr or readonly;
  750. if (filerec(f).name[0]='.') then
  751. Attr:=Attr or hidden;
  752. end;
  753. Procedure getftime (var f; var time : longint);
  754. Var
  755. Info: stat;
  756. DT: DateTime;
  757. Begin
  758. doserror:=0;
  759. if sys_fstat(filerec(f).handle,info)<>0 then
  760. begin
  761. Time:=0;
  762. doserror:=3;
  763. exit
  764. end
  765. else
  766. UnixDateToDT(Info.st_mtime,DT);
  767. PackTime(DT,Time);
  768. End;
  769. {******************************************************************************
  770. --- Environment ---
  771. ******************************************************************************}
  772. Function EnvCount: Longint;
  773. var
  774. envcnt : longint;
  775. p : ppchar;
  776. Begin
  777. envcnt:=0;
  778. p:=envp; {defined in syslinux}
  779. while (p^<>nil) do
  780. begin
  781. inc(envcnt);
  782. inc(p);
  783. end;
  784. EnvCount := envcnt
  785. End;
  786. Function EnvStr(Index: Integer): String;
  787. Var
  788. i : longint;
  789. p : ppchar;
  790. Begin
  791. p:=envp; {defined in syslinux}
  792. i:=1;
  793. envstr:='';
  794. if (index < 1) or (index > EnvCount) then
  795. exit;
  796. while (i<Index) and (p^<>nil) do
  797. begin
  798. inc(i);
  799. inc(p);
  800. end;
  801. if p<>nil then
  802. envstr:=strpas(p^)
  803. End;
  804. Function GetEnv(EnvVar:string):string;
  805. {
  806. Searches the environment for a string with name p and
  807. returns a pchar to it's value.
  808. A pchar is used to accomodate for strings of length > 255
  809. }
  810. var
  811. ep : ppchar;
  812. found : boolean;
  813. p1 : pchar;
  814. Begin
  815. EnvVar:=EnvVar+'='; {Else HOST will also find HOSTNAME, etc}
  816. ep:=envp;
  817. found:=false;
  818. if ep<>nil then
  819. begin
  820. while (not found) and (ep^<>nil) do
  821. begin
  822. if strlcomp(@EnvVar[1],(ep^),length(EnvVar))=0 then
  823. found:=true
  824. else
  825. inc(ep);
  826. end;
  827. end;
  828. if found then
  829. p1:=ep^+length(EnvVar)
  830. else
  831. p1:=nil;
  832. if p1 = nil then
  833. GetEnv := ''
  834. else
  835. GetEnv := StrPas(p1);
  836. end;
  837. {******************************************************************************
  838. --- Do Nothing Procedures/Functions ---
  839. ******************************************************************************}
  840. Procedure Intr (intno: byte; var regs: registers);
  841. Begin
  842. {! No POSIX equivalent !}
  843. End;
  844. Procedure msdos(var regs : registers);
  845. Begin
  846. {! No POSIX equivalent !}
  847. End;
  848. Procedure getintvec(intno : byte;var vector : pointer);
  849. Begin
  850. {! No POSIX equivalent !}
  851. End;
  852. Procedure setintvec(intno : byte;vector : pointer);
  853. Begin
  854. {! No POSIX equivalent !}
  855. End;
  856. Procedure SwapVectors;
  857. Begin
  858. {! No POSIX equivalent !}
  859. End;
  860. Procedure keep(exitcode : word);
  861. Begin
  862. {! No POSIX equivalent !}
  863. End;
  864. Procedure setftime(var f; time : longint);
  865. Begin
  866. {! No POSIX equivalent !}
  867. End;
  868. Procedure setfattr (var f;attr : word);
  869. Begin
  870. {! No POSIX equivalent !}
  871. End;
  872. Procedure GetCBreak(Var BreakValue: Boolean);
  873. Begin
  874. {! No POSIX equivalent !}
  875. breakvalue:=true
  876. End;
  877. Procedure SetCBreak(BreakValue: Boolean);
  878. Begin
  879. {! No POSIX equivalent !}
  880. End;
  881. Procedure GetVerify(Var Verify: Boolean);
  882. Begin
  883. {! No POSIX equivalent !}
  884. Verify:=true;
  885. End;
  886. Procedure SetVerify(Verify: Boolean);
  887. Begin
  888. {! No POSIX equivalent !}
  889. End;
  890. { Include timezone routines }
  891. {$i timezone.inc}
  892. {******************************************************************************
  893. --- Initialization ---
  894. ******************************************************************************}
  895. Initialization
  896. InitLocalTime;
  897. finalization
  898. DoneLocalTime;
  899. end.
  900. {
  901. $Log$
  902. Revision 1.5 2003-12-03 20:53:22 olle
  903. * files are not pretended to have attr ARCHIVE anymore
  904. * files with attr READONLY and ARCHIVE are always returned by FindFirst etc
  905. * made code more conformant with unix/dos.pp
  906. Revision 1.4 2003/01/08 22:32:28 marco
  907. * Small fixes and quick merge with 1.0.x. At least the compiler builds now,
  908. but it could crash hard, since there are lots of unimplemented funcs.
  909. Revision 1.1.2.14 2001/12/09 03:31:35 carl
  910. * Exec() fixed (was full of bugs) : No DosError=2 report fixed, status code error fixed.
  911. + MAX_DRIVES constant added
  912. Revision 1.1.2.13 2001/12/03 03:12:28 carl
  913. * update for new posix prototype (caused problem with other OS)
  914. readdir / closedir
  915. Revision 1.1.2.12 2001/09/28 01:11:14 carl
  916. * bugfix of pchar move in FSearch() (would give wrong results)
  917. Revision 1.1.2.11 2001/08/21 10:48:46 carl
  918. + add goto on
  919. Revision 1.1.2.10 2001/08/15 01:04:38 carl
  920. * instead include posix unit
  921. * corrected bug in DateNum type (should be time_t)
  922. Revision 1.1.2.9 2001/08/13 09:37:17 carl
  923. * changed prototype of sys_readdir
  924. Revision 1.1.2.8 2001/08/12 15:12:30 carl
  925. + added timezone information
  926. * bugfix of overflow in conversion of epoch to local
  927. * bugfix of index verification in getenv
  928. Revision 1.1.2.7 2001/08/08 01:58:18 carl
  929. * bugfix of problem with FindFirst() / FindNext()
  930. Revision 1.1.2.5 2001/08/04 05:24:21 carl
  931. + implemented FindFirst / FindNext (untested)
  932. + Exec()
  933. + split
  934. + Timezone support reinstated
  935. Revision 1.1.2.4 2001/07/08 04:46:01 carl
  936. * waitpid is now portable
  937. + fnmatch()
  938. Revision 1.1.2.3 2001/07/07 15:42:29 carl
  939. * compiler error corrections
  940. Revision 1.1.2.2 2001/07/07 03:49:53 carl
  941. + more POSIX compliance stuff
  942. Revision 1.1.2.1 2001/07/06 11:21:49 carl
  943. + add files for POSIX
  944. }