dos.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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;
  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;
  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. volumeNumber := getvolnum (drive);
  246. (*
  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 ['\','/'])) 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. i,p1 : longint;
  401. s : searchrec;
  402. newdir : pathstr;
  403. begin
  404. { check if the file specified exists }
  405. findfirst(path,anyfile,s);
  406. if doserror=0 then
  407. begin
  408. findclose(s);
  409. fsearch:=path;
  410. exit;
  411. end;
  412. { No wildcards allowed in these things }
  413. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  414. fsearch:=''
  415. else
  416. begin
  417. { allow backslash as slash }
  418. for i:=1 to length(dirlist) do
  419. if dirlist[i]='\' then dirlist[i]:='/';
  420. repeat
  421. p1:=pos(';',dirlist);
  422. if p1<>0 then
  423. begin
  424. newdir:=copy(dirlist,1,p1-1);
  425. delete(dirlist,1,p1);
  426. end
  427. else
  428. begin
  429. newdir:=dirlist;
  430. dirlist:='';
  431. end;
  432. if (newdir<>'') and (not (newdir[length(newdir)] in ['/',':'])) then
  433. newdir:=newdir+'/';
  434. findfirst(newdir+path,anyfile,s);
  435. if doserror=0 then
  436. newdir:=newdir+path
  437. else
  438. newdir:='';
  439. until (dirlist='') or (newdir<>'');
  440. fsearch:=newdir;
  441. end;
  442. findclose(s);
  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 StatBuf : TStat;
  493. begin
  494. doserror := 0;
  495. if Fpstat (@textrec(f).name, StatBuf) = 0 then
  496. attr := nwattr2dosattr (StatBuf.st_mode)
  497. else
  498. begin
  499. attr := 0;
  500. doserror := ___errno^;
  501. end;
  502. end;
  503. procedure setfattr(var f;attr : word);
  504. var
  505. StatBuf : TStat;
  506. newMode : longint;
  507. begin
  508. if Fpstat (@textrec(f).name,StatBuf) = 0 then
  509. begin
  510. 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}
  511. newmode := newmode or M_A_BITS_SIGNIFICANT; {set netware attributes}
  512. if attr and readonly > 0 then
  513. newmode := newmode or M_A_RDONLY;
  514. if attr and hidden > 0 then
  515. newmode := newmode or M_A_HIDDEN;
  516. if attr and sysfile > 0 then
  517. newmode := newmode or M_A_SYSTEM;
  518. if attr and archive > 0 then
  519. newmode := newmode or M_A_ARCH;
  520. if Fpchmod (@textrec(f).name,newMode) < 0 then
  521. doserror := ___errno^ else
  522. doserror := 0;
  523. end else
  524. doserror := ___errno^;
  525. end;
  526. {******************************************************************************
  527. --- Environment ---
  528. ******************************************************************************}
  529. Function EnvCount: Longint;
  530. var
  531. envcnt : longint;
  532. p : ppchar;
  533. Begin
  534. envcnt:=0;
  535. p:=envp; {defined in system}
  536. while (p^<>nil) do
  537. begin
  538. inc(envcnt);
  539. inc(p);
  540. end;
  541. EnvCount := envcnt
  542. End;
  543. Function EnvStr (Index: longint): String;
  544. Var
  545. i : longint;
  546. p : ppchar;
  547. Begin
  548. if Index <= 0 then
  549. envstr:=''
  550. else
  551. begin
  552. p:=envp; {defined in system}
  553. i:=1;
  554. while (i<Index) and (p^<>nil) do
  555. begin
  556. inc(i);
  557. inc(p);
  558. end;
  559. if p=nil then
  560. envstr:=''
  561. else
  562. envstr:=strpas(p^)
  563. end;
  564. end;
  565. { works fine (at least with netware 6.5) }
  566. Function GetEnv(envvar: string): string;
  567. var envvar0 : array[0..512] of char;
  568. p : pchar;
  569. SearchElement : string[255];
  570. i,isDosPath,res : longint;
  571. begin
  572. if upcase(envvar) = 'PATH' then
  573. begin // netware does not have search paths in the environment var PATH
  574. // return it here (needed for the compiler)
  575. GetEnv := '';
  576. i := 1;
  577. res := GetSearchPathElement (i, isdosPath, @SearchElement[0]);
  578. while res = 0 do
  579. begin
  580. if isDosPath = 0 then
  581. begin
  582. if GetEnv <> '' then GetEnv := GetEnv + ';';
  583. GetEnv := GetEnv + SearchElement;
  584. end;
  585. inc (i);
  586. res := GetSearchPathElement (i, isdosPath, @SearchElement[0]);
  587. end;
  588. for i := 1 to length(GetEnv) do
  589. if GetEnv[i] = '\' then
  590. GetEnv[i] := '/';
  591. end else
  592. begin
  593. strpcopy(envvar0,envvar);
  594. p := libc.getenv (envvar0);
  595. if p = NIL then
  596. GetEnv := ''
  597. else
  598. GetEnv := strpas (p);
  599. end;
  600. end;
  601. {******************************************************************************
  602. --- Not Supported ---
  603. ******************************************************************************}
  604. Procedure keep(exitcode : word);
  605. Begin
  606. { simply wait until nlm will be unloaded }
  607. while true do delay (60000);
  608. End;
  609. end.