dos.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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. SearchPos : UInt64; {directory position}
  23. SearchNum : LongInt; {to track which search this is}
  24. DirFD : LongInt; {directory fd handle 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. Mode : Word;
  28. Fill : Array[1..1] 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; platform;
  42. Procedure WasiDateToDt(NanoSecsPast: UInt64; Var Dt: DateTime); platform;
  43. Function DTToWasiDate(DT: DateTime): UInt64; platform;
  44. {Disk}
  45. //Function AddDisk(const path:string) : byte; platform;
  46. Implementation
  47. Uses
  48. WasiAPI, WasiUtil;
  49. {$DEFINE HAS_GETMSCOUNT}
  50. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  51. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  52. {$I dos.inc}
  53. {******************************************************************************
  54. --- Link C Lib if set ---
  55. ******************************************************************************}
  56. {******************************************************************************
  57. --- Info / Date / Time ---
  58. ******************************************************************************}
  59. Function DosVersion:Word;
  60. Begin
  61. End;
  62. function WeekDay (y,m,d:longint):longint;
  63. {
  64. Calculates th day of the week. returns -1 on error
  65. }
  66. var
  67. u,v : longint;
  68. begin
  69. if (m<1) or (m>12) or (y<1600) or (y>4000) or
  70. (d<1) or (d>30+((m+ord(m>7)) and 1)-ord(m=2)) or
  71. ((m*d=58) and (((y mod 4>0) or (y mod 100=0)) and (y mod 400>0))) then
  72. WeekDay:=-1
  73. else
  74. begin
  75. u:=m;
  76. v:=y;
  77. if m<3 then
  78. begin
  79. inc(u,12);
  80. dec(v);
  81. end;
  82. WeekDay:=(d+2*u+((3*(u+1)) div 5)+v+(v div 4)-(v div 100)+(v div 400)+1) mod 7;
  83. end;
  84. end;
  85. Procedure GetDate(Var Year, Month, MDay, WDay: Word);
  86. var
  87. NanoSecsPast: __wasi_timestamp_t;
  88. DT: DateTime;
  89. begin
  90. if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,10000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then
  91. begin
  92. { todo: convert UTC to local time, as soon as we can get the local timezone
  93. from WASI: https://github.com/WebAssembly/WASI/issues/239 }
  94. WasiDateToDT(NanoSecsPast,DT);
  95. Year:=DT.Year;
  96. Month:=DT.Month;
  97. MDay:=DT.Day;
  98. WDay:=weekday(DT.Year,DT.Month,DT.Day);
  99. end
  100. else
  101. begin
  102. Year:=0;
  103. Month:=0;
  104. MDay:=0;
  105. WDay:=0;
  106. end;
  107. end;
  108. procedure SetTime(Hour,Minute,Second,sec100:word);
  109. begin
  110. end;
  111. procedure SetDate(Year,Month,Day:Word);
  112. begin
  113. end;
  114. Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  115. begin
  116. end;
  117. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  118. var
  119. NanoSecsPast: __wasi_timestamp_t;
  120. begin
  121. if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,10000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then
  122. begin
  123. { todo: convert UTC to local time, as soon as we can get the local timezone
  124. from WASI: https://github.com/WebAssembly/WASI/issues/239 }
  125. NanoSecsPast:=NanoSecsPast div 10000000;
  126. Sec100:=NanoSecsPast mod 100;
  127. NanoSecsPast:=NanoSecsPast div 100;
  128. Second:=NanoSecsPast mod 60;
  129. NanoSecsPast:=NanoSecsPast div 60;
  130. Minute:=NanoSecsPast mod 60;
  131. NanoSecsPast:=NanoSecsPast div 60;
  132. Hour:=NanoSecsPast mod 24;
  133. end
  134. else
  135. begin
  136. Hour:=0;
  137. Minute:=0;
  138. Second:=0;
  139. Sec100:=0;
  140. end;
  141. end;
  142. Function DTToWasiDate(DT: DateTime): UInt64;
  143. const
  144. days_in_month: array [boolean, 1..12] of Byte =
  145. ((31,28,31,30,31,30,31,31,30,31,30,31),
  146. (31,29,31,30,31,30,31,31,30,31,30,31));
  147. days_before_month: array [boolean, 1..12] of Word =
  148. ((0,
  149. 0+31,
  150. 0+31+28,
  151. 0+31+28+31,
  152. 0+31+28+31+30,
  153. 0+31+28+31+30+31,
  154. 0+31+28+31+30+31+30,
  155. 0+31+28+31+30+31+30+31,
  156. 0+31+28+31+30+31+30+31+31,
  157. 0+31+28+31+30+31+30+31+31+30,
  158. 0+31+28+31+30+31+30+31+31+30+31,
  159. 0+31+28+31+30+31+30+31+31+30+31+30),
  160. (0,
  161. 0+31,
  162. 0+31+29,
  163. 0+31+29+31,
  164. 0+31+29+31+30,
  165. 0+31+29+31+30+31,
  166. 0+31+29+31+30+31+30,
  167. 0+31+29+31+30+31+30+31,
  168. 0+31+29+31+30+31+30+31+31,
  169. 0+31+29+31+30+31+30+31+31+30,
  170. 0+31+29+31+30+31+30+31+31+30+31,
  171. 0+31+29+31+30+31+30+31+31+30+31+30));
  172. var
  173. leap: Boolean;
  174. days_in_year: LongInt;
  175. y,m: LongInt;
  176. begin
  177. if (DT.year<1970) or (DT.month<1) or (DT.month>12) or (DT.day<1) or (DT.day>31) or
  178. (DT.hour>=24) or (DT.min>=60) or (DT.sec>=60) then
  179. begin
  180. DTToWasiDate:=0;
  181. exit;
  182. end;
  183. leap:=((DT.year mod 4)=0) and (((DT.year mod 100)<>0) or ((DT.year mod 400)=0));
  184. if DT.day>days_in_month[leap,DT.month] then
  185. begin
  186. DTToWasiDate:=0;
  187. exit;
  188. end;
  189. DTToWasiDate:=0;
  190. for y:=1970 to DT.year-1 do
  191. if ((y mod 4)=0) and (((y mod 100)<>0) or ((y mod 400)=0)) then
  192. Inc(DTToWasiDate,366)
  193. else
  194. Inc(DTToWasiDate,365);
  195. Inc(DTToWasiDate,days_before_month[leap,DT.month]);
  196. Inc(DTToWasiDate,DT.day-1);
  197. DTToWasiDate:=((((DTToWasiDate*24+DT.hour)*60+DT.min)*60)+DT.sec)*1000000000;
  198. end;
  199. Procedure WasiDateToDt(NanoSecsPast: UInt64; Var Dt: DateTime);
  200. const
  201. days_in_month: array [boolean, 1..12] of Byte =
  202. ((31,28,31,30,31,30,31,31,30,31,30,31),
  203. (31,29,31,30,31,30,31,31,30,31,30,31));
  204. var
  205. leap: Boolean;
  206. days_in_year: LongInt;
  207. Begin
  208. { todo: convert UTC to local time, as soon as we can get the local timezone
  209. from WASI: https://github.com/WebAssembly/WASI/issues/239 }
  210. NanoSecsPast:=NanoSecsPast div 1000000000;
  211. Dt.Sec:=NanoSecsPast mod 60;
  212. NanoSecsPast:=NanoSecsPast div 60;
  213. Dt.Min:=NanoSecsPast mod 60;
  214. NanoSecsPast:=NanoSecsPast div 60;
  215. Dt.Hour:=NanoSecsPast mod 24;
  216. NanoSecsPast:=NanoSecsPast div 24;
  217. Dt.Year:=1970;
  218. leap:=false;
  219. days_in_year:=365;
  220. while NanoSecsPast>=days_in_year do
  221. begin
  222. Dec(NanoSecsPast,days_in_year);
  223. Inc(Dt.Year);
  224. leap:=((Dt.Year mod 4)=0) and (((Dt.Year mod 100)<>0) or ((Dt.Year mod 400)=0));
  225. if leap then
  226. days_in_year:=366
  227. else
  228. days_in_year:=365;
  229. end;
  230. Dt.Month:=1;
  231. Inc(NanoSecsPast);
  232. while NanoSecsPast>days_in_month[leap,Dt.Month] do
  233. begin
  234. Dec(NanoSecsPast,days_in_month[leap,Dt.Month]);
  235. Inc(Dt.Month);
  236. end;
  237. Dt.Day:=Word(NanoSecsPast);
  238. End;
  239. function GetMsCount: int64;
  240. var
  241. NanoSecsPast: __wasi_timestamp_t;
  242. begin
  243. if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,1000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then
  244. GetMsCount:=NanoSecsPast div 1000000
  245. else
  246. GetMsCount:=0;
  247. end;
  248. {******************************************************************************
  249. --- Exec ---
  250. ******************************************************************************}
  251. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  252. Begin
  253. End;
  254. {******************************************************************************
  255. --- Disk ---
  256. ******************************************************************************}
  257. {
  258. The Diskfree and Disksize functions need a file on the specified drive, since this
  259. is required for the fpstatfs system call.
  260. These filenames are set in drivestr[0..26], and have been preset to :
  261. 0 - '.' (default drive - hence current dir is ok.)
  262. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  263. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  264. 3 - '/' (C: equivalent of dos is the root partition)
  265. 4..26 (can be set by you're own applications)
  266. ! Use AddDisk() to Add new drives !
  267. They both return -1 when a failure occurs.
  268. }
  269. Const
  270. FixDriveStr : array[0..3] of pchar=(
  271. '.',
  272. '/fd0/.',
  273. '/fd1/.',
  274. '/.'
  275. );
  276. const
  277. Drives : byte = 4;
  278. var
  279. DriveStr : array[4..26] of pchar;
  280. Function AddDisk(const path:string) : byte;
  281. begin
  282. { if not (DriveStr[Drives]=nil) then
  283. FreeMem(DriveStr[Drives]);
  284. GetMem(DriveStr[Drives],length(Path)+1);
  285. StrPCopy(DriveStr[Drives],path);
  286. AddDisk:=Drives;
  287. inc(Drives);
  288. if Drives>26 then
  289. Drives:=4;}
  290. end;
  291. Function DiskFree(Drive: Byte): int64;
  292. {var
  293. fs : tstatfs;}
  294. Begin
  295. { if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  296. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  297. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  298. else
  299. Diskfree:=-1;}
  300. End;
  301. Function DiskSize(Drive: Byte): int64;
  302. {var
  303. fs : tstatfs;}
  304. Begin
  305. { if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  306. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  307. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  308. else
  309. DiskSize:=-1;}
  310. End;
  311. Procedure FreeDriveStr;
  312. {var
  313. i: longint;}
  314. begin
  315. { for i:=low(drivestr) to high(drivestr) do
  316. if assigned(drivestr[i]) then
  317. begin
  318. freemem(drivestr[i]);
  319. drivestr[i]:=nil;
  320. end;}
  321. end;
  322. {******************************************************************************
  323. --- Findfirst FindNext ---
  324. ******************************************************************************}
  325. procedure SearchRec2WasiSearchRec(const i: SearchRec; var o: TWasiSearchRec);
  326. var
  327. DT: DateTime;
  328. begin
  329. FillChar(o,SizeOf(o),0);
  330. o.SearchPos:=i.SearchPos;
  331. o.SearchNum:=i.SearchNum;
  332. o.DirFD:=i.DirFD;
  333. o.SearchType:=i.SearchType;
  334. o.SearchAttr:=i.SearchAttr;
  335. o.Attr:=i.Attr;
  336. UnpackTime(i.Time,DT);
  337. o.Time:=DTToWasiDate(DT);
  338. o.Size:=i.Size;
  339. o.Name:=i.Name;
  340. o.SearchSpec:=i.SearchSpec;
  341. o.NamePos:=i.NamePos;
  342. end;
  343. procedure WasiSearchRec2SearchRec(const i: TWasiSearchRec; var o: SearchRec);
  344. var
  345. DT: DateTime;
  346. begin
  347. FillChar(o,SizeOf(o),0);
  348. o.SearchPos:=i.SearchPos;
  349. o.SearchNum:=i.SearchNum;
  350. o.DirFD:=i.DirFD;
  351. o.SearchType:=i.SearchType;
  352. o.SearchAttr:=i.SearchAttr;
  353. o.Attr:=i.Attr;
  354. WasiDateToDt(i.Time,DT);
  355. PackTime(DT,o.Time);
  356. o.Size:=i.Size;
  357. o.Name:=i.Name;
  358. o.SearchSpec:=i.SearchSpec;
  359. o.NamePos:=i.NamePos;
  360. end;
  361. Procedure FindClose(Var f: SearchRec);
  362. var
  363. wf: TWasiSearchRec;
  364. Begin
  365. SearchRec2WasiSearchRec(f,wf);
  366. WasiFindClose(wf);
  367. WasiSearchRec2SearchRec(wf,f);
  368. End;
  369. Procedure FindNext(Var f: SearchRec);
  370. var
  371. wf: TWasiSearchRec;
  372. Begin
  373. SearchRec2WasiSearchRec(f,wf);
  374. doserror:=WasiFindNext(wf);
  375. WasiSearchRec2SearchRec(wf,f);
  376. End;
  377. Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
  378. var
  379. wf: TWasiSearchRec;
  380. Begin
  381. SearchRec2WasiSearchRec(f,wf);
  382. doserror:=WasiFindFirst(Path,Attr,wf);
  383. WasiSearchRec2SearchRec(wf,f);
  384. End;
  385. {******************************************************************************
  386. --- File ---
  387. ******************************************************************************}
  388. Function FSearch(path: pathstr; dirlist: string): pathstr;
  389. var
  390. p1 : longint;
  391. s : searchrec;
  392. newdir : pathstr;
  393. begin
  394. { No wildcards allowed in these things }
  395. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  396. begin
  397. fsearch:='';
  398. exit;
  399. end;
  400. { check if the file specified exists }
  401. findfirst(path,anyfile and not(directory),s);
  402. if doserror=0 then
  403. begin
  404. findclose(s);
  405. fsearch:=path;
  406. exit;
  407. end;
  408. findclose(s);
  409. //{ allow slash as backslash }
  410. //DoDirSeparators(dirlist);
  411. repeat
  412. p1:=pos(';',dirlist);
  413. if p1<>0 then
  414. begin
  415. newdir:=copy(dirlist,1,p1-1);
  416. delete(dirlist,1,p1);
  417. end
  418. else
  419. begin
  420. newdir:=dirlist;
  421. dirlist:='';
  422. end;
  423. if (newdir<>'') and (not (newdir[length(newdir)] in (AllowDirectorySeparators+[':']))) then
  424. newdir:=newdir+DirectorySeparator;
  425. findfirst(newdir+path,anyfile and not(directory),s);
  426. if doserror=0 then
  427. newdir:=newdir+path
  428. else
  429. newdir:='';
  430. findclose(s);
  431. until (dirlist='') or (newdir<>'');
  432. fsearch:=newdir;
  433. end;
  434. Procedure GetFAttr(var f; var attr : word);
  435. Var
  436. pr: RawByteString;
  437. fd: __wasi_fd_t;
  438. Info: __wasi_filestat_t;
  439. Begin
  440. DosError:=0;
  441. Attr:=0;
  442. if ConvertToFdRelativePath(textrec(f).name,fd,pr)<>0 then
  443. begin
  444. DosError:=3;
  445. exit;
  446. end;
  447. if __wasi_path_filestat_get(fd,__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,PChar(pr),length(pr),@Info)<>__WASI_ERRNO_SUCCESS then
  448. begin
  449. DosError:=3;
  450. exit;
  451. end;
  452. if Info.filetype=__WASI_FILETYPE_DIRECTORY then
  453. Attr:=$10;
  454. if filerec(f).name[0]='.' then
  455. Attr:=Attr or $2;
  456. end;
  457. Procedure getftime (var f; var time : longint);
  458. Var
  459. res: __wasi_errno_t;
  460. Info: __wasi_filestat_t;
  461. DT: DateTime;
  462. Begin
  463. doserror:=0;
  464. res:=__wasi_fd_filestat_get(filerec(f).handle,@Info);
  465. if res<>__WASI_ERRNO_SUCCESS then
  466. begin
  467. Time:=0;
  468. case res of
  469. __WASI_ERRNO_ACCES,
  470. __WASI_ERRNO_NOTCAPABLE:
  471. doserror:=5;
  472. else
  473. doserror:=6;
  474. end;
  475. exit
  476. end
  477. else
  478. WasiDateToDt(Info.mtim,DT);
  479. PackTime(DT,Time);
  480. End;
  481. Procedure setftime(var f; time : longint);
  482. Var
  483. DT: DateTime;
  484. modtime: UInt64;
  485. pr: RawByteString;
  486. fd: __wasi_fd_t;
  487. Begin
  488. doserror:=0;
  489. UnPackTime(Time,DT);
  490. modtime:=DTToWasiDate(DT);
  491. if ConvertToFdRelativePath(textrec(f).name,fd,pr)<>0 then
  492. begin
  493. doserror:=3;
  494. exit;
  495. end;
  496. if __wasi_path_filestat_set_times(fd,0,PChar(pr),length(pr),0,modtime,
  497. __WASI_FSTFLAGS_MTIM or __WASI_FSTFLAGS_ATIM_NOW)<>__WASI_ERRNO_SUCCESS then
  498. doserror:=3;
  499. End;
  500. {******************************************************************************
  501. --- Environment ---
  502. ******************************************************************************}
  503. Function EnvCount: Longint;
  504. var
  505. envcnt : longint;
  506. p : ppchar;
  507. Begin
  508. envcnt:=0;
  509. p:=envp; {defined in system}
  510. if p<>nil then
  511. while p^<>nil do
  512. begin
  513. inc(envcnt);
  514. inc(p);
  515. end;
  516. EnvCount := envcnt
  517. End;
  518. Function EnvStr (Index: longint): String;
  519. Var
  520. i : longint;
  521. p : ppchar;
  522. Begin
  523. if (Index <= 0) or (envp=nil) then
  524. envstr:=''
  525. else
  526. begin
  527. p:=envp; {defined in system}
  528. i:=1;
  529. while (i<Index) and (p^<>nil) do
  530. begin
  531. inc(i);
  532. inc(p);
  533. end;
  534. if p^=nil then
  535. envstr:=''
  536. else
  537. envstr:=strpas(p^)
  538. end;
  539. end;
  540. Function GetEnv(EnvVar: String): String;
  541. var
  542. hp : ppchar;
  543. hs : string;
  544. eqpos : longint;
  545. Begin
  546. getenv:='';
  547. hp:=envp;
  548. if hp<>nil then
  549. while assigned(hp^) do
  550. begin
  551. hs:=strpas(hp^);
  552. eqpos:=pos('=',hs);
  553. if copy(hs,1,eqpos-1)=envvar then
  554. begin
  555. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  556. break;
  557. end;
  558. inc(hp);
  559. end;
  560. End;
  561. Procedure setfattr (var f;attr : word);
  562. Begin
  563. {! No WASI equivalent !}
  564. { Fail for setting VolumeId }
  565. if (attr and VolumeID)<>0 then
  566. doserror:=5;
  567. End;
  568. {******************************************************************************
  569. --- Initialization ---
  570. ******************************************************************************}
  571. //Finalization
  572. // FreeDriveStr;
  573. End.