dos.pp 18 KB

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