dos.pp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115
  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. { contrary to DOS - all normal files have the archive bits set }
  512. { under POSIX. }
  513. fmode:=archive;
  514. if (st.st_mode and S_IWUSR)=0 then
  515. fmode:=fmode or readonly;
  516. If ((FMode and f.searchattr)<>0) or ((Fmode and Archive)<>0) Then
  517. Begin
  518. FSplit(s,Dir,Name,Ext);
  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. f.SearchAttr := Attr;
  601. {Wildcards?}
  602. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  603. begin
  604. if FindGetFileInfo(Path,f) then
  605. DosError:=0
  606. else
  607. begin
  608. if ErrNo=Sys_ENOENT then
  609. DosError:=3
  610. else
  611. DosError:=18;
  612. end;
  613. f.DirPtr:=nil;
  614. end
  615. else
  616. {Find Entry}
  617. begin
  618. FSplit(Path,Dir,Name,Ext);
  619. if Ext <> '' then
  620. res := Name + Ext
  621. else
  622. res := Name;
  623. f.SearchSpec := res;
  624. { if dir is an empty string }
  625. { then this indicates that }
  626. { use the current working }
  627. { directory. }
  628. if dir = '' then
  629. dir := './';
  630. f.SearchDir := Dir;
  631. { add terminating null character }
  632. Dir := Dir + #0;
  633. f.dirptr := sys_opendir(@Dir[1]);
  634. if not assigned(f.dirptr) then
  635. begin
  636. DosError := 8;
  637. exit;
  638. end;
  639. FindNext(f);
  640. end;
  641. End;
  642. {******************************************************************************
  643. --- File ---
  644. ******************************************************************************}
  645. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  646. Var
  647. DotPos,SlashPos,i : longint;
  648. Begin
  649. SlashPos:=0;
  650. DotPos:=256;
  651. i:=Length(Path);
  652. While (i>0) and (SlashPos=0) Do
  653. Begin
  654. If (DotPos=256) and (Path[i]='.') Then
  655. begin
  656. DotPos:=i;
  657. end;
  658. If (Path[i]='/') Then
  659. SlashPos:=i;
  660. Dec(i);
  661. End;
  662. Ext:=Copy(Path,DotPos,255);
  663. Dir:=Copy(Path,1,SlashPos);
  664. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  665. End;
  666. {
  667. function FExpand (const Path: PathStr): PathStr;
  668. - declared in fexpand.inc
  669. }
  670. (*
  671. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  672. *)
  673. const
  674. LFNSupport = true;
  675. FileNameCaseSensitive = true;
  676. {$I fexpand.inc}
  677. Function FSearch(const path:pathstr;dirlist:string):pathstr;
  678. {
  679. Searches for a file 'path' in the list of direcories in 'dirlist'.
  680. returns an empty string if not found. Wildcards are NOT allowed.
  681. If dirlist is empty, it is set to '.'
  682. }
  683. Var
  684. NewDir : PathStr;
  685. p1 : Longint;
  686. Info : Stat;
  687. buffer : array[0..FileNameLen+1] of char;
  688. Begin
  689. Move(path[1], Buffer, Length(path));
  690. Buffer[Length(path)]:=#0;
  691. if (length(Path)>0) and (path[1]='/') and (sys_stat(pchar(@Buffer),info)=0) then
  692. begin
  693. FSearch:=path;
  694. exit;
  695. end;
  696. {Replace ':' with ';'}
  697. for p1:=1to length(dirlist) do
  698. if dirlist[p1]=':' then
  699. dirlist[p1]:=';';
  700. {Check for WildCards}
  701. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  702. FSearch:='' {No wildcards allowed in these things.}
  703. Else
  704. Begin
  705. Dirlist:='.;'+dirlist;{Make sure current dir is first to be searched.}
  706. Repeat
  707. p1:=Pos(';',DirList);
  708. If p1=0 Then
  709. p1:=255;
  710. NewDir:=Copy(DirList,1,P1 - 1);
  711. if NewDir[Length(NewDir)]<>'/' then
  712. NewDir:=NewDir+'/';
  713. NewDir:=NewDir+Path;
  714. Delete(DirList,1,p1);
  715. Move(NewDir[1], Buffer, Length(NewDir));
  716. Buffer[Length(NewDir)]:=#0;
  717. if sys_stat(pchar(@Buffer),Info)=0 then
  718. Begin
  719. If Pos('./',NewDir)=1 Then
  720. Delete(NewDir,1,2);
  721. {DOS strips off an initial .\}
  722. End
  723. Else
  724. NewDir:='';
  725. Until (DirList='') or (Length(NewDir) > 0);
  726. FSearch:=NewDir;
  727. End;
  728. End;
  729. Procedure GetFAttr(var f; var attr : word);
  730. Var
  731. info : stat;
  732. LinAttr : mode_t;
  733. Begin
  734. DosError:=0;
  735. if sys_stat(@textrec(f).name,info)<>0 then
  736. begin
  737. Attr:=0;
  738. DosError:=3;
  739. exit;
  740. end
  741. else
  742. LinAttr:=Info.st_Mode;
  743. if S_ISDIR(LinAttr) then
  744. Attr:=directory
  745. else
  746. Attr:=archive;
  747. if sys_Access(@textrec(f).name,W_OK)<>0 then
  748. Attr:=Attr or readonly;
  749. if (not S_ISDIR(LinAttr)) and (filerec(f).name[0]='.') then
  750. Attr:=Attr or hidden;
  751. end;
  752. Procedure getftime (var f; var time : longint);
  753. Var
  754. Info: stat;
  755. DT: DateTime;
  756. Begin
  757. doserror:=0;
  758. if sys_fstat(filerec(f).handle,info)<>0 then
  759. begin
  760. Time:=0;
  761. doserror:=3;
  762. exit
  763. end
  764. else
  765. UnixDateToDT(Info.st_mtime,DT);
  766. PackTime(DT,Time);
  767. End;
  768. {******************************************************************************
  769. --- Environment ---
  770. ******************************************************************************}
  771. Function EnvCount: Longint;
  772. var
  773. envcnt : longint;
  774. p : ppchar;
  775. Begin
  776. envcnt:=0;
  777. p:=envp; {defined in syslinux}
  778. while (p^<>nil) do
  779. begin
  780. inc(envcnt);
  781. inc(p);
  782. end;
  783. EnvCount := envcnt
  784. End;
  785. Function EnvStr(Index: Integer): String;
  786. Var
  787. i : longint;
  788. p : ppchar;
  789. Begin
  790. p:=envp; {defined in syslinux}
  791. i:=1;
  792. envstr:='';
  793. if (index < 1) or (index > EnvCount) then
  794. exit;
  795. while (i<Index) and (p^<>nil) do
  796. begin
  797. inc(i);
  798. inc(p);
  799. end;
  800. if p<>nil then
  801. envstr:=strpas(p^)
  802. End;
  803. Function GetEnv(EnvVar:string):string;
  804. {
  805. Searches the environment for a string with name p and
  806. returns a pchar to it's value.
  807. A pchar is used to accomodate for strings of length > 255
  808. }
  809. var
  810. ep : ppchar;
  811. found : boolean;
  812. p1 : pchar;
  813. Begin
  814. EnvVar:=EnvVar+'='; {Else HOST will also find HOSTNAME, etc}
  815. ep:=envp;
  816. found:=false;
  817. if ep<>nil then
  818. begin
  819. while (not found) and (ep^<>nil) do
  820. begin
  821. if strlcomp(@EnvVar[1],(ep^),length(EnvVar))=0 then
  822. found:=true
  823. else
  824. inc(ep);
  825. end;
  826. end;
  827. if found then
  828. p1:=ep^+length(EnvVar)
  829. else
  830. p1:=nil;
  831. if p1 = nil then
  832. GetEnv := ''
  833. else
  834. GetEnv := StrPas(p1);
  835. end;
  836. {******************************************************************************
  837. --- Do Nothing Procedures/Functions ---
  838. ******************************************************************************}
  839. Procedure Intr (intno: byte; var regs: registers);
  840. Begin
  841. {! No POSIX equivalent !}
  842. End;
  843. Procedure msdos(var regs : registers);
  844. Begin
  845. {! No POSIX equivalent !}
  846. End;
  847. Procedure getintvec(intno : byte;var vector : pointer);
  848. Begin
  849. {! No POSIX equivalent !}
  850. End;
  851. Procedure setintvec(intno : byte;vector : pointer);
  852. Begin
  853. {! No POSIX equivalent !}
  854. End;
  855. Procedure SwapVectors;
  856. Begin
  857. {! No POSIX equivalent !}
  858. End;
  859. Procedure keep(exitcode : word);
  860. Begin
  861. {! No POSIX equivalent !}
  862. End;
  863. Procedure setftime(var f; time : longint);
  864. Begin
  865. {! No POSIX equivalent !}
  866. End;
  867. Procedure setfattr (var f;attr : word);
  868. Begin
  869. {! No POSIX equivalent !}
  870. End;
  871. Procedure GetCBreak(Var BreakValue: Boolean);
  872. Begin
  873. {! No POSIX equivalent !}
  874. breakvalue:=true
  875. End;
  876. Procedure SetCBreak(BreakValue: Boolean);
  877. Begin
  878. {! No POSIX equivalent !}
  879. End;
  880. Procedure GetVerify(Var Verify: Boolean);
  881. Begin
  882. {! No POSIX equivalent !}
  883. Verify:=true;
  884. End;
  885. Procedure SetVerify(Verify: Boolean);
  886. Begin
  887. {! No POSIX equivalent !}
  888. End;
  889. { Include timezone routines }
  890. {$i timezone.inc}
  891. {******************************************************************************
  892. --- Initialization ---
  893. ******************************************************************************}
  894. Initialization
  895. InitLocalTime;
  896. finalization
  897. DoneLocalTime;
  898. end.
  899. {
  900. $Log$
  901. Revision 1.4 2003-01-08 22:32:28 marco
  902. * Small fixes and quick merge with 1.0.x. At least the compiler builds now,
  903. but it could crash hard, since there are lots of unimplemented funcs.
  904. Revision 1.1.2.14 2001/12/09 03:31:35 carl
  905. * Exec() fixed (was full of bugs) : No DosError=2 report fixed, status code error fixed.
  906. + MAX_DRIVES constant added
  907. Revision 1.1.2.13 2001/12/03 03:12:28 carl
  908. * update for new posix prototype (caused problem with other OS)
  909. readdir / closedir
  910. Revision 1.1.2.12 2001/09/28 01:11:14 carl
  911. * bugfix of pchar move in FSearch() (would give wrong results)
  912. Revision 1.1.2.11 2001/08/21 10:48:46 carl
  913. + add goto on
  914. Revision 1.1.2.10 2001/08/15 01:04:38 carl
  915. * instead include posix unit
  916. * corrected bug in DateNum type (should be time_t)
  917. Revision 1.1.2.9 2001/08/13 09:37:17 carl
  918. * changed prototype of sys_readdir
  919. Revision 1.1.2.8 2001/08/12 15:12:30 carl
  920. + added timezone information
  921. * bugfix of overflow in conversion of epoch to local
  922. * bugfix of index verification in getenv
  923. Revision 1.1.2.7 2001/08/08 01:58:18 carl
  924. * bugfix of problem with FindFirst() / FindNext()
  925. Revision 1.1.2.5 2001/08/04 05:24:21 carl
  926. + implemented FindFirst / FindNext (untested)
  927. + Exec()
  928. + split
  929. + Timezone support reinstated
  930. Revision 1.1.2.4 2001/07/08 04:46:01 carl
  931. * waitpid is now portable
  932. + fnmatch()
  933. Revision 1.1.2.3 2001/07/07 15:42:29 carl
  934. * compiler error corrections
  935. Revision 1.1.2.2 2001/07/07 03:49:53 carl
  936. + more POSIX compliance stuff
  937. Revision 1.1.2.1 2001/07/06 11:21:49 carl
  938. + add files for POSIX
  939. }