dos.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2004 by the Free Pascal development team.
  4. Dos unit for BP7 compatible RTL (novell netware libc)
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit dos;
  12. interface
  13. uses libc;
  14. Type
  15. searchrec = packed record
  16. DirP : POINTER; { used for opendir }
  17. EntryP: POINTER; { and readdir }
  18. Magic : WORD;
  19. fill : array[1..11] of byte;
  20. attr : byte;
  21. time : longint;
  22. size : longint;
  23. name : string[255];
  24. { Internals used by netware port only: }
  25. _mask : string[255];
  26. _dir : string[255];
  27. _attr : word;
  28. end;
  29. {$i dosh.inc}
  30. {Extra Utils}
  31. function weekday(y,m,d : longint) : longint;
  32. implementation
  33. uses
  34. strings;
  35. {$DEFINE HAS_GETMSCOUNT}
  36. {$DEFINE HAS_KEEP}
  37. {$DEFINE FPC_FEXPAND_DRIVES}
  38. {$DEFINE FPC_FEXPAND_VOLUMES}
  39. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  40. {$i dos.inc}
  41. {$ASMMODE ATT}
  42. {*****************************************************************************
  43. --- Info / Date / Time ---
  44. ******************************************************************************}
  45. {$PACKRECORDS 4}
  46. function dosversion : word;
  47. var i : Tutsname;
  48. begin
  49. if Fpuname (i) >= 0 then
  50. dosversion := WORD (i.netware_minor) SHL 8 + i.netware_major
  51. else dosversion := $0005;
  52. end;
  53. function WeekDay (y,m,d:longint):longint;
  54. {
  55. Calculates th day of the week. returns -1 on error
  56. }
  57. var
  58. u,v : longint;
  59. begin
  60. if (m<1) or (m>12) or (y<1600) or (y>4000) or
  61. (d<1) or (d>30+((m+ord(m>7)) and 1)-ord(m=2)) or
  62. ((m*d=58) and (((y mod 4>0) or (y mod 100=0)) and (y mod 400>0))) then
  63. WeekDay:=-1
  64. else
  65. begin
  66. u:=m;
  67. v:=y;
  68. if m<3 then
  69. begin
  70. inc(u,12);
  71. dec(v);
  72. end;
  73. WeekDay:=(d+2*u+((3*(u+1)) div 5)+v+(v div 4)-(v div 100)+(v div 400)+1) mod 7;
  74. end;
  75. end;
  76. procedure getdate(var year,month,mday,wday : word);
  77. var
  78. t : TTime_t;
  79. tm : Ttm;
  80. begin
  81. time(t); localtime_r(t,tm);
  82. with tm do
  83. begin
  84. year := tm_year+1900;
  85. month := tm_mon+1;
  86. mday := tm_mday;
  87. wday := tm_wday;
  88. end;
  89. end;
  90. procedure setdate(year,month,day : word);
  91. begin
  92. end;
  93. procedure gettime(var hour,minute,second,sec100 : word);
  94. var
  95. t : TTime_t;
  96. tm : Ttm;
  97. begin
  98. time(t); localtime_r(t,tm);
  99. with tm do
  100. begin
  101. hour := tm_hour;
  102. minute := tm_min;
  103. second := tm_sec;
  104. sec100 := 0;
  105. end;
  106. end;
  107. procedure settime(hour,minute,second,sec100 : word);
  108. begin
  109. end;
  110. function GetMsCount: int64;
  111. var
  112. tv : TimeVal;
  113. tz : TimeZone;
  114. begin
  115. FPGetTimeOfDay (tv, tz);
  116. GetMsCount := int64 (tv.tv_Sec) * 1000 + tv.tv_uSec div 1000;
  117. end;
  118. {******************************************************************************
  119. --- Exec ---
  120. ******************************************************************************}
  121. const maxargs=256;
  122. procedure exec(const path : pathstr;const comline : comstr);
  123. var c : comstr;
  124. i : integer;
  125. args : array[0..maxargs] of pchar;
  126. arg0 : pathstr;
  127. numargs,wstat : integer;
  128. Wiring : TWiring;
  129. begin
  130. if pos ('.',path) = 0 then
  131. arg0 := fexpand(path+'.nlm'#0) else
  132. arg0 := fexpand (path)+#0;
  133. //writeln (stderr,'dos.exec (',path,',',comline,') arg0:"',copy(arg0,1,length(arg0)-1),'"');
  134. args[0] := @arg0[1];
  135. numargs := 0;
  136. c:=comline;
  137. i:=1;
  138. while i<=length(c) do
  139. begin
  140. if c[i]<>' ' then
  141. begin
  142. {Commandline argument found. append #0 and set pointer in args }
  143. inc(numargs);
  144. args[numargs]:=@c[i];
  145. while (i<=length(c)) and (c[i]<>' ') do
  146. inc(i);
  147. c[i] := #0;
  148. end;
  149. inc(i);
  150. end;
  151. args[numargs+1] := nil;
  152. // i := spawnvp (P_WAIT,args[0],@args);
  153. Wiring.infd := StdInputHandle; //textrec(Stdin).Handle;
  154. Wiring.outfd:= textrec(stdout).Handle;
  155. Wiring.errfd:= textrec(stderr).Handle;
  156. //writeln (stderr,'calling procve');
  157. i := procve(args[0],
  158. PROC_CURRENT_SPACE+PROC_INHERIT_CWD,
  159. envP, // const char * env[] If passed as NULL, the child process inherits the parent.s environment at the time of the call.
  160. @Wiring, // wiring_t *wiring, Pass NULL to inherit system defaults for wiring.
  161. nil, // struct fd_set *fds, Not currently implemented. Pass in NULL.
  162. nil, // void *appdata, Not currently implemented. Pass in NULL.
  163. 0, // size_t appdata_size, Not currently implemented. Pass in 0
  164. nil, // void *reserved, Reserved. Pass NULL.
  165. @args); // const char *argv[]
  166. //writeln (stderr,'Ok');
  167. if i <> -1 then
  168. begin
  169. Fpwaitpid(i,@wstat,0);
  170. doserror := 0;
  171. lastdosexitcode := wstat;
  172. end else
  173. begin
  174. doserror := 8; // for now, what about errno ?
  175. end;
  176. end;
  177. {******************************************************************************
  178. --- Disk ---
  179. ******************************************************************************}
  180. function getvolnum (drive : byte) : longint;
  181. {var dir : STRING[255];
  182. P,PS,
  183. V : LONGINT;}
  184. begin
  185. {if drive = 0 then
  186. begin // get volume name from current directory (i.e. SERVER-NAME/VOL2:TEST)
  187. getdir (0,dir);
  188. p := pos (':', dir);
  189. if p = 0 then
  190. begin
  191. getvolnum := -1;
  192. exit;
  193. end;
  194. byte (dir[0]) := p-1;
  195. dir[p] := #0;
  196. PS := pos ('/', dir);
  197. INC (PS);
  198. if _GetVolumeNumber (@dir[PS], V) <> 0 then
  199. getvolnum := -1
  200. else
  201. getvolnum := V;
  202. end else
  203. getvolnum := drive-1;}
  204. getvolnum := -1;
  205. end;
  206. function diskfree(drive : byte) : int64;
  207. {VAR Buf : ARRAY [0..255] OF CHAR;
  208. TotalBlocks : WORD;
  209. SectorsPerBlock : WORD;
  210. availableBlocks : WORD;
  211. totalDirectorySlots : WORD;
  212. availableDirSlots : WORD;
  213. volumeisRemovable : WORD;
  214. volumeNumber : LONGINT;}
  215. begin
  216. // volumeNumber := getvolnum (drive);
  217. (*
  218. if volumeNumber >= 0 then
  219. begin
  220. {i think thats not the right function but for others i need a connection handle}
  221. if _GetVolumeInfoWithNumber (byte(volumeNumber),@Buf,
  222. TotalBlocks,
  223. SectorsPerBlock,
  224. availableBlocks,
  225. totalDirectorySlots,
  226. availableDirSlots,
  227. volumeisRemovable) = 0 THEN
  228. begin
  229. diskfree := int64 (availableBlocks) * int64 (SectorsPerBlock) * 512;
  230. end else
  231. diskfree := 0;
  232. end else*)
  233. diskfree := 0;
  234. end;
  235. function disksize(drive : byte) : int64;
  236. {VAR Buf : ARRAY [0..255] OF CHAR;
  237. TotalBlocks : WORD;
  238. SectorsPerBlock : WORD;
  239. availableBlocks : WORD;
  240. totalDirectorySlots : WORD;
  241. availableDirSlots : WORD;
  242. volumeisRemovable : WORD;
  243. volumeNumber : LONGINT;}
  244. begin
  245. (*
  246. volumeNumber := getvolnum (drive);
  247. if volumeNumber >= 0 then
  248. begin
  249. {i think thats not the right function but for others i need a connection handle}
  250. if _GetVolumeInfoWithNumber (byte(volumeNumber),@Buf,
  251. TotalBlocks,
  252. SectorsPerBlock,
  253. availableBlocks,
  254. totalDirectorySlots,
  255. availableDirSlots,
  256. volumeisRemovable) = 0 THEN
  257. begin
  258. disksize := int64 (TotalBlocks) * int64 (SectorsPerBlock) * 512;
  259. end else
  260. disksize := 0;
  261. end else*)
  262. disksize := 0;
  263. end;
  264. {******************************************************************************
  265. --- Utils ---
  266. ******************************************************************************}
  267. procedure timet2dostime (timet:longint; var dostime : longint);
  268. var tm : Ttm;
  269. begin
  270. localtime_r(timet,tm);
  271. dostime:=(tm.tm_sec shr 1)+(tm.tm_min shl 5)+(tm.tm_hour shl 11)+(tm.tm_mday shl 16)+((tm.tm_mon+1) shl 21)+((tm.tm_year+1900-1980) shl 25);
  272. end;
  273. function nwattr2dosattr (nwattr : longint) : word;
  274. begin
  275. nwattr2dosattr := 0;
  276. if nwattr and M_A_RDONLY > 0 then nwattr2dosattr := nwattr2dosattr + readonly;
  277. if nwattr and M_A_HIDDEN > 0 then nwattr2dosattr := nwattr2dosattr + hidden;
  278. if nwattr and M_A_SYSTEM > 0 then nwattr2dosattr := nwattr2dosattr + sysfile;
  279. if nwattr and M_A_SUBDIR > 0 then nwattr2dosattr := nwattr2dosattr + directory;
  280. if nwattr and M_A_ARCH > 0 then nwattr2dosattr := nwattr2dosattr + archive;
  281. end;
  282. {******************************************************************************
  283. --- Findfirst FindNext ---
  284. ******************************************************************************}
  285. {returns true if attributes match}
  286. function find_setfields (var f : searchRec) : boolean;
  287. var
  288. StatBuf : TStat;
  289. fname : string[255];
  290. begin
  291. find_setfields := false;
  292. with F do
  293. begin
  294. if Magic = $AD01 then
  295. begin
  296. attr := nwattr2dosattr (Pdirent(EntryP)^.d_mode);
  297. size := Pdirent(EntryP)^.d_size;
  298. name := strpas (Pdirent(EntryP)^.d_name);
  299. doserror := 0;
  300. fname := f._dir + f.name;
  301. if length (fname) = 255 then dec (byte(fname[0]));
  302. fname := fname + #0;
  303. if Fpstat (@fname[1],StatBuf) = 0 then
  304. timet2dostime (StatBuf.st_mtim.tv_sec, time)
  305. else
  306. time := 0;
  307. if (f._attr and hidden) = 0 then
  308. if attr and hidden > 0 then exit;
  309. if (f._attr and Directory) = 0 then
  310. if attr and Directory > 0 then exit;
  311. if (f._attr and SysFile) = 0 then
  312. if attr and SysFile > 0 then exit;
  313. find_setfields := true;
  314. end else
  315. begin
  316. FillChar (f,sizeof(f),0);
  317. doserror := 18;
  318. end;
  319. end;
  320. end;
  321. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  322. var
  323. path0 : array[0..256] of char;
  324. p : longint;
  325. begin
  326. IF path = '' then
  327. begin
  328. doserror := 18;
  329. exit;
  330. end;
  331. f._attr := attr;
  332. p := length (path);
  333. while (p > 0) and (not (path[p] in AllowDirectorySeparators)) do
  334. dec (p);
  335. if p > 0 then
  336. begin
  337. f._mask := copy (path,p+1,255);
  338. f._dir := copy (path,1,p);
  339. strpcopy(path0,f._dir);
  340. end else
  341. begin
  342. f._mask := path;
  343. getdir (0,f._dir);
  344. if (f._dir[length(f._dir)] <> '/') and
  345. (f._dir[length(f._dir)] <> '\') then
  346. f._dir := f._dir + '/';
  347. strpcopy(path0,f._dir);
  348. end;
  349. if f._mask = '*' then f._mask := '';
  350. if f._mask = '*.*' then f._mask := '';
  351. //writeln (stderr,'mask: "',f._mask,'" dir:"',path0,'"');
  352. f._mask := f._mask + #0;
  353. Pdirent(f.DirP) := opendir (path0);
  354. if f.DirP = nil then
  355. doserror := 18
  356. else begin
  357. F.Magic := $AD01;
  358. findnext (f);
  359. end;
  360. end;
  361. procedure findnext(var f : searchRec);
  362. begin
  363. if F.Magic <> $AD01 then
  364. begin
  365. doserror := 18;
  366. exit;
  367. end;
  368. doserror:=0;
  369. repeat
  370. Pdirent(f.EntryP) := readdir (Pdirent(f.DirP));
  371. if F.EntryP = nil then
  372. doserror := 18
  373. else
  374. if find_setfields (f) then
  375. begin
  376. if f._mask = #0 then exit;
  377. if fnmatch(@f._mask[1],Pdirent(f.EntryP)^.d_name,FNM_CASEFOLD) = 0 then
  378. exit;
  379. end;
  380. until doserror <> 0;
  381. end;
  382. Procedure FindClose(Var f: SearchRec);
  383. begin
  384. if F.Magic <> $AD01 then
  385. begin
  386. doserror := 18;
  387. EXIT;
  388. end;
  389. doserror:=0;
  390. closedir (Pdirent(f.DirP));
  391. f.Magic := 0;
  392. f.DirP := NIL;
  393. f.EntryP := NIL;
  394. end;
  395. {******************************************************************************
  396. --- File ---
  397. ******************************************************************************}
  398. Function FSearch(path: pathstr; dirlist: string): pathstr;
  399. var
  400. p1 : longint;
  401. s : searchrec;
  402. newdir : pathstr;
  403. begin
  404. { No wildcards allowed in these things }
  405. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  406. begin
  407. fsearch:='';
  408. exit;
  409. end;
  410. { check if the file specified exists }
  411. findfirst(path,anyfile and not(directory),s);
  412. if doserror=0 then
  413. begin
  414. findclose(s);
  415. fsearch:=path;
  416. exit;
  417. end;
  418. findclose(s);
  419. { allow backslash as slash }
  420. DoDirSeparators(dirlist);
  421. repeat
  422. p1:=pos(';',dirlist);
  423. if p1<>0 then
  424. begin
  425. newdir:=copy(dirlist,1,p1-1);
  426. delete(dirlist,1,p1);
  427. end
  428. else
  429. begin
  430. newdir:=dirlist;
  431. dirlist:='';
  432. end;
  433. if (newdir<>'') and (not (newdir[length(newdir)] in [DirectorySeparator,DriveSeparator])) then
  434. newdir:=newdir+DirectorySeparator;
  435. findfirst(newdir+path,anyfile and not(directory),s);
  436. if doserror=0 then
  437. newdir:=newdir+path
  438. else
  439. newdir:='';
  440. findclose(s);
  441. until (dirlist='') or (newdir<>'');
  442. fsearch:=newdir;
  443. end;
  444. {******************************************************************************
  445. --- Get/Set File Time,Attr ---
  446. ******************************************************************************}
  447. procedure getftime(var f;var time : longint);
  448. var
  449. StatBuf : TStat;
  450. begin
  451. doserror := 0;
  452. if Fpfstat (filerec (f).handle, StatBuf) = 0 then
  453. timet2dostime (StatBuf.st_mtim.tv_sec,time)
  454. else begin
  455. time := 0;
  456. doserror := ___errno^;
  457. end;
  458. end;
  459. procedure setftime(var f;time : longint);
  460. Var
  461. utim: utimbuf;
  462. DT: DateTime;
  463. path: pathstr;
  464. tm : TTm;
  465. Begin
  466. doserror:=0;
  467. with utim do
  468. begin
  469. actime:=libc.time(nil); // getepochtime;
  470. UnPackTime(Time,DT);
  471. with tm do
  472. begin
  473. tm_sec := DT.Sec; // seconds after the minute [0..59]
  474. tm_min := DT.Min; // minutes after the hour [0..59]
  475. tm_hour := DT.hour; // hours since midnight [0..23]
  476. tm_mday := DT.Day; // days of the month [1..31]
  477. tm_mon := DT.month-1; // months since January [0..11]
  478. tm_year := DT.year-1900;
  479. tm_wday := -1;
  480. tm_yday := -1;
  481. tm_isdst := -1;
  482. end;
  483. modtime:=mktime(tm);
  484. end;
  485. if utime(@filerec(f).name,utim)<0 then
  486. begin
  487. Time:=0;
  488. doserror:=3;
  489. end;
  490. end;
  491. procedure getfattr(var f;var attr : word);
  492. var
  493. StatBuf : TStat;
  494. {$ifndef FPC_ANSI_TEXTFILEREC}
  495. r: rawbytestring;
  496. {$endif not FPC_ANSI_TEXTFILEREC}
  497. p: pchar;
  498. begin
  499. doserror := 0;
  500. {$ifdef FPC_ANSI_TEXTFILEREC}
  501. p := @filerec(f).name;
  502. {$else FPC_ANSI_TEXTFILEREC}
  503. r := ToSingleByteFileSystemEncodedFileName(filerec(f).name);
  504. p := pchar(r);
  505. {$endif FPC_ANSI_TEXTFILEREC}
  506. if Fpstat (p, StatBuf) = 0 then
  507. attr := nwattr2dosattr (StatBuf.st_mode)
  508. else
  509. begin
  510. attr := 0;
  511. doserror := ___errno^;
  512. end;
  513. end;
  514. procedure setfattr(var f;attr : word);
  515. var
  516. StatBuf : TStat;
  517. newMode : longint;
  518. {$ifndef FPC_ANSI_TEXTFILEREC}
  519. r: rawbytestring;
  520. {$endif not FPC_ANSI_TEXTFILEREC}
  521. p: pchar;
  522. begin
  523. {$ifdef FPC_ANSI_TEXTFILEREC}
  524. p := @filerec(f).name;
  525. {$else FPC_ANSI_TEXTFILEREC}
  526. r := ToSingleByteFileSystemEncodedFileName(filerec(f).name);
  527. p := pchar(r);
  528. {$endif FPC_ANSI_TEXTFILEREC}
  529. if Fpstat (p,StatBuf) = 0 then
  530. begin
  531. newmode := StatBuf.st_mode and ($FFFF0000 - M_A_RDONLY-M_A_HIDDEN-M_A_SYSTEM-M_A_ARCH); {only this can be set by dos unit}
  532. newmode := newmode or M_A_BITS_SIGNIFICANT; {set netware attributes}
  533. if attr and readonly > 0 then
  534. newmode := newmode or M_A_RDONLY;
  535. if attr and hidden > 0 then
  536. newmode := newmode or M_A_HIDDEN;
  537. if attr and sysfile > 0 then
  538. newmode := newmode or M_A_SYSTEM;
  539. if attr and archive > 0 then
  540. newmode := newmode or M_A_ARCH;
  541. if Fpchmod (@textrec(f).name,newMode) < 0 then
  542. doserror := ___errno^ else
  543. doserror := 0;
  544. end else
  545. doserror := ___errno^;
  546. end;
  547. {******************************************************************************
  548. --- Environment ---
  549. ******************************************************************************}
  550. Function EnvCount: Longint;
  551. var
  552. envcnt : longint;
  553. p : ppchar;
  554. Begin
  555. envcnt:=0;
  556. p:=envp; {defined in system}
  557. while (p^<>nil) do
  558. begin
  559. inc(envcnt);
  560. inc(p);
  561. end;
  562. EnvCount := envcnt
  563. End;
  564. Function EnvStr (Index: longint): String;
  565. Var
  566. i : longint;
  567. p : ppchar;
  568. Begin
  569. if Index <= 0 then
  570. envstr:=''
  571. else
  572. begin
  573. p:=envp; {defined in system}
  574. i:=1;
  575. while (i<Index) and (p^<>nil) do
  576. begin
  577. inc(i);
  578. inc(p);
  579. end;
  580. if p=nil then
  581. envstr:=''
  582. else
  583. envstr:=strpas(p^)
  584. end;
  585. end;
  586. { works fine (at least with netware 6.5) }
  587. Function GetEnv(envvar: string): string;
  588. var envvar0 : array[0..512] of char;
  589. p : pchar;
  590. SearchElement : string[255];
  591. i,isDosPath,res : longint;
  592. begin
  593. if upcase(envvar) = 'PATH' then
  594. begin // netware does not have search paths in the environment var PATH
  595. // return it here (needed for the compiler)
  596. GetEnv := '';
  597. i := 1;
  598. res := GetSearchPathElement (i, isdosPath, @SearchElement[0]);
  599. while res = 0 do
  600. begin
  601. if isDosPath = 0 then
  602. begin
  603. if GetEnv <> '' then GetEnv := GetEnv + ';';
  604. GetEnv := GetEnv + SearchElement;
  605. end;
  606. inc (i);
  607. res := GetSearchPathElement (i, isdosPath, @SearchElement[0]);
  608. end;
  609. DoDirSeparators(getenv);
  610. end else
  611. begin
  612. strpcopy(envvar0,envvar);
  613. p := libc.getenv (envvar0);
  614. if p = NIL then
  615. GetEnv := ''
  616. else
  617. GetEnv := strpas (p);
  618. end;
  619. end;
  620. {******************************************************************************
  621. --- Not Supported ---
  622. ******************************************************************************}
  623. Procedure keep(exitcode : word);
  624. Begin
  625. { simply wait until nlm will be unloaded }
  626. while true do delay (60000);
  627. End;
  628. end.