dos.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. Dos unit for BP7 compatible RTL
  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. {$inline on}
  12. unit dos;
  13. interface
  14. Type
  15. searchrec = packed record
  16. fill : array[1..21] of byte;
  17. attr : byte;
  18. time : longint;
  19. { reserved : word; not in DJGPP V2 }
  20. size : longint;
  21. name : string[255]; { LFN Name, DJGPP uses only [12] but more can't hurt (PFV) }
  22. end;
  23. {$DEFINE HAS_REGISTERS}
  24. {$I registers.inc}
  25. {$i dosh.inc}
  26. {$IfDef SYSTEM_DEBUG_STARTUP}
  27. {$DEFINE FORCE_PROXY}
  28. {$endif SYSTEM_DEBUG_STARTUP}
  29. Const
  30. { This variable can be set to true
  31. to force use of !proxy command lines even for short
  32. strings, for debugging purposes mainly, as
  33. this might have negative impact if trying to
  34. call non-go32v2 programs }
  35. force_go32v2_proxy : boolean =
  36. {$ifdef FORCE_PROXY}
  37. true;
  38. {$DEFINE DEBUG_PROXY}
  39. {$else not FORCE_PROXY}
  40. false;
  41. {$endif not FORCE_PROXY}
  42. { This variable allows to use !proxy if command line is
  43. longer than 126 characters.
  44. This will only work if the called program knows how to handle
  45. those command lines.
  46. Luckily this is the case for Free Pascal compiled
  47. programs (even old versions)
  48. and go32v2 DJGPP programs.
  49. You can set this to false to get a warning to stderr
  50. if command line is too long. }
  51. Use_go32v2_proxy : boolean = true;
  52. { Added to interface so that there is no need to implement it
  53. both in dos and sysutils units }
  54. procedure exec_ansistring(path : string;comline : ansistring);
  55. procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';
  56. procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
  57. implementation
  58. uses
  59. strings;
  60. {$DEFINE HAS_GETMSCOUNT}
  61. {$DEFINE HAS_INTR}
  62. {$DEFINE HAS_SETCBREAK}
  63. {$DEFINE HAS_GETCBREAK}
  64. {$DEFINE HAS_SETVERIFY}
  65. {$DEFINE HAS_GETVERIFY}
  66. {$DEFINE HAS_SWAPVECTORS}
  67. {$DEFINE HAS_GETSHORTNAME}
  68. {$DEFINE HAS_GETLONGNAME}
  69. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  70. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  71. {$I dos.inc}
  72. {******************************************************************************
  73. --- Dos Interrupt ---
  74. ******************************************************************************}
  75. var
  76. dosregs : registers;
  77. procedure LoadDosError;
  78. var
  79. r : registers;
  80. SimpleDosError : word;
  81. begin
  82. if (dosregs.flags and fcarry) <> 0 then
  83. begin
  84. { I got a extended error = 0
  85. while CarryFlag was set from Exec function }
  86. SimpleDosError:=dosregs.ax;
  87. r.ax:=$5900;
  88. r.bx:=$0;
  89. intr($21,r);
  90. { conversion from word to integer !!
  91. gave a Bound check error if ax is $FFFF !! PM }
  92. doserror:=integer(r.ax);
  93. case doserror of
  94. 0 : DosError:=integer(SimpleDosError);
  95. 19 : DosError:=150;
  96. 21 : DosError:=152;
  97. end;
  98. end
  99. else
  100. doserror:=0;
  101. end;
  102. {******************************************************************************
  103. --- Info / Date / Time ---
  104. ******************************************************************************}
  105. function dosversion : word;
  106. begin
  107. dosregs.ax:=$3000;
  108. msdos(dosregs);
  109. dosversion:=dosregs.ax;
  110. end;
  111. procedure getdate(var year,month,mday,wday : word);
  112. begin
  113. dosregs.ax:=$2a00;
  114. msdos(dosregs);
  115. wday:=dosregs.al;
  116. year:=dosregs.cx;
  117. month:=dosregs.dh;
  118. mday:=dosregs.dl;
  119. end;
  120. procedure setdate(year,month,day : word);
  121. begin
  122. dosregs.cx:=year;
  123. dosregs.dh:=month;
  124. dosregs.dl:=day;
  125. dosregs.ah:=$2b;
  126. msdos(dosregs);
  127. end;
  128. procedure gettime(var hour,minute,second,sec100 : word);
  129. begin
  130. dosregs.ah:=$2c;
  131. msdos(dosregs);
  132. hour:=dosregs.ch;
  133. minute:=dosregs.cl;
  134. second:=dosregs.dh;
  135. sec100:=dosregs.dl;
  136. end;
  137. procedure settime(hour,minute,second,sec100 : word);
  138. begin
  139. dosregs.ch:=hour;
  140. dosregs.cl:=minute;
  141. dosregs.dh:=second;
  142. dosregs.dl:=sec100;
  143. dosregs.ah:=$2d;
  144. msdos(dosregs);
  145. end;
  146. function GetMsCount: int64;
  147. begin
  148. GetMsCount := int64 (MemL [$40:$6c]) * 55;
  149. end;
  150. {******************************************************************************
  151. --- Exec ---
  152. ******************************************************************************}
  153. const
  154. DOS_MAX_COMMAND_LINE_LENGTH = 126;
  155. procedure exec_ansistring(path : string;comline : ansistring);
  156. begin
  157. {TODO: implement}
  158. runerror(304);
  159. end;
  160. procedure exec(const path : pathstr;const comline : comstr);
  161. begin
  162. exec_ansistring(path, comline);
  163. end;
  164. procedure getcbreak(var breakvalue : boolean);
  165. begin
  166. dosregs.ax:=$3300;
  167. msdos(dosregs);
  168. breakvalue:=dosregs.dl<>0;
  169. end;
  170. procedure setcbreak(breakvalue : boolean);
  171. begin
  172. dosregs.ax:=$3301;
  173. dosregs.dl:=ord(breakvalue);
  174. msdos(dosregs);
  175. end;
  176. procedure getverify(var verify : boolean);
  177. begin
  178. dosregs.ah:=$54;
  179. msdos(dosregs);
  180. verify:=dosregs.al<>0;
  181. end;
  182. procedure setverify(verify : boolean);
  183. begin
  184. dosregs.ah:=$2e;
  185. dosregs.al:=ord(verify);
  186. msdos(dosregs);
  187. end;
  188. {******************************************************************************
  189. --- Disk ---
  190. ******************************************************************************}
  191. type
  192. ExtendedFat32FreeSpaceRec = packed record
  193. RetSize : word; { $00 }
  194. Strucversion : word; { $02 }
  195. SecPerClus, { $04 }
  196. BytePerSec, { $08 }
  197. AvailClusters, { $0C }
  198. TotalClusters, { $10 }
  199. AvailPhysSect, { $14 }
  200. TotalPhysSect, { $18 }
  201. AvailAllocUnits, { $1C }
  202. TotalAllocUnits : longword; { $20 }
  203. Dummy, { $24 }
  204. Dummy2 : longword; { $28 }
  205. end; { $2C }
  206. const
  207. IOCTL_INPUT = 3; //For request header command field
  208. CDFUNC_SECTSIZE = 7; //For cdrom control block func field
  209. CDFUNC_VOLSIZE = 8; //For cdrom control block func field
  210. type
  211. TRequestHeader = packed record
  212. length : byte; { $00 }
  213. subunit : byte; { $01 }
  214. command : byte; { $02 }
  215. status : word; { $03 }
  216. reserved1 : longword; { $05 }
  217. reserved2 : longword; { $09 }
  218. media_desc : byte; { $0D }
  219. transf_ofs : word; { $0E }
  220. transf_seg : word; { $10 }
  221. numbytes : word; { $12 }
  222. end; { $14 }
  223. TCDSectSizeReq = packed record
  224. func : byte; { $00 }
  225. mode : byte; { $01 }
  226. secsize : word; { $02 }
  227. end; { $04 }
  228. TCDVolSizeReq = packed record
  229. func : byte; { $00 }
  230. size : longword; { $01 }
  231. end; { $05 }
  232. function do_diskdata(drive : byte; Free : boolean) : Int64;
  233. begin
  234. {TODO: implement}
  235. runerror(304);
  236. end;
  237. function diskfree(drive : byte) : int64;
  238. begin
  239. diskfree:=Do_DiskData(drive,TRUE);
  240. end;
  241. function disksize(drive : byte) : int64;
  242. begin
  243. disksize:=Do_DiskData(drive,false);
  244. end;
  245. {******************************************************************************
  246. --- LFNFindfirst LFNFindNext ---
  247. ******************************************************************************}
  248. type
  249. LFNSearchRec=packed record
  250. attr,
  251. crtime,
  252. crtimehi,
  253. actime,
  254. actimehi,
  255. lmtime,
  256. lmtimehi,
  257. sizehi,
  258. size : longint;
  259. reserved : array[0..7] of byte;
  260. name : array[0..259] of byte;
  261. shortname : array[0..13] of byte;
  262. end;
  263. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec;from_findfirst : boolean);
  264. var
  265. Len : longint;
  266. begin
  267. With w do
  268. begin
  269. FillChar(d,sizeof(SearchRec),0);
  270. if DosError=0 then
  271. len:=StrLen(@Name)
  272. else
  273. len:=0;
  274. d.Name[0]:=chr(len);
  275. Move(Name[0],d.Name[1],Len);
  276. d.Time:=lmTime;
  277. d.Size:=Size;
  278. d.Attr:=Attr and $FF;
  279. if (DosError<>0) and from_findfirst then
  280. hdl:=-1;
  281. Move(hdl,d.Fill,4);
  282. end;
  283. end;
  284. {$ifdef DEBUG_LFN}
  285. const
  286. LFNFileName : string = 'LFN.log';
  287. LFNOpenNb : longint = 0;
  288. LogLFN : boolean = false;
  289. var
  290. lfnfile : text;
  291. {$endif DEBUG_LFN}
  292. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  293. begin
  294. {TODO: implement}
  295. runerror(304);
  296. end;
  297. procedure LFNFindNext(var s:searchrec);
  298. begin
  299. {TODO: implement}
  300. runerror(304);
  301. end;
  302. procedure LFNFindClose(var s:searchrec);
  303. begin
  304. {TODO: implement}
  305. runerror(304);
  306. end;
  307. {******************************************************************************
  308. --- DosFindfirst DosFindNext ---
  309. ******************************************************************************}
  310. procedure dossearchrec2searchrec(var f : searchrec);
  311. var
  312. len : longint;
  313. begin
  314. { Check is necessary!! OS/2's VDM doesn't clear the name with #0 if the }
  315. { file doesn't exist! (JM) }
  316. if dosError = 0 then
  317. len:=StrLen(@f.Name)
  318. else len := 0;
  319. Move(f.Name[0],f.Name[1],Len);
  320. f.Name[0]:=chr(len);
  321. end;
  322. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  323. begin
  324. {TODO: implement}
  325. runerror(304);
  326. end;
  327. procedure Dosfindnext(var f : searchrec);
  328. begin
  329. {TODO: implement}
  330. runerror(304);
  331. end;
  332. {******************************************************************************
  333. --- Findfirst FindNext ---
  334. ******************************************************************************}
  335. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  336. var
  337. path0 : array[0..255] of char;
  338. begin
  339. doserror:=0;
  340. strpcopy(path0,path);
  341. if LFNSupport then
  342. LFNFindFirst(path0,attr,f)
  343. else
  344. Dosfindfirst(path0,attr,f);
  345. end;
  346. procedure findnext(var f : searchRec);
  347. begin
  348. doserror:=0;
  349. if LFNSupport then
  350. LFNFindnext(f)
  351. else
  352. Dosfindnext(f);
  353. end;
  354. Procedure FindClose(Var f: SearchRec);
  355. begin
  356. DosError:=0;
  357. if LFNSupport then
  358. LFNFindClose(f);
  359. end;
  360. type swap_proc = procedure;
  361. var
  362. _swap_in : swap_proc;external name '_swap_in';
  363. _swap_out : swap_proc;external name '_swap_out';
  364. _exception_exit : pointer;external name '_exception_exit';
  365. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  366. procedure swapvectors;
  367. begin
  368. if _exception_exit<>nil then
  369. if _v2prt0_exceptions_on then
  370. _swap_out()
  371. else
  372. _swap_in();
  373. end;
  374. {******************************************************************************
  375. --- File ---
  376. ******************************************************************************}
  377. Function FSearch(path: pathstr; dirlist: string): pathstr;
  378. var
  379. i,p1 : longint;
  380. s : searchrec;
  381. newdir : pathstr;
  382. begin
  383. { check if the file specified exists }
  384. findfirst(path,anyfile and not(directory),s);
  385. if doserror=0 then
  386. begin
  387. findclose(s);
  388. fsearch:=path;
  389. exit;
  390. end;
  391. { No wildcards allowed in these things }
  392. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  393. fsearch:=''
  394. else
  395. begin
  396. { allow slash as backslash }
  397. DoDirSeparators(dirlist);
  398. repeat
  399. p1:=pos(';',dirlist);
  400. if p1<>0 then
  401. begin
  402. newdir:=copy(dirlist,1,p1-1);
  403. delete(dirlist,1,p1);
  404. end
  405. else
  406. begin
  407. newdir:=dirlist;
  408. dirlist:='';
  409. end;
  410. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  411. newdir:=newdir+'\';
  412. findfirst(newdir+path,anyfile and not(directory),s);
  413. if doserror=0 then
  414. newdir:=newdir+path
  415. else
  416. newdir:='';
  417. until (dirlist='') or (newdir<>'');
  418. fsearch:=newdir;
  419. end;
  420. findclose(s);
  421. end;
  422. { change to short filename if successful DOS call PM }
  423. function GetShortName(var p : String) : boolean;
  424. begin
  425. {TODO: implement}
  426. runerror(304);
  427. end;
  428. { change to long filename if successful DOS call PM }
  429. function GetLongName(var p : String) : boolean;
  430. begin
  431. {TODO: implement}
  432. runerror(304);
  433. end;
  434. {******************************************************************************
  435. --- Get/Set File Time,Attr ---
  436. ******************************************************************************}
  437. procedure getftime(var f;var time : longint);
  438. begin
  439. dosregs.bx:=textrec(f).handle;
  440. dosregs.ax:=$5700;
  441. msdos(dosregs);
  442. loaddoserror;
  443. time:=(dosregs.dx shl 16)+dosregs.cx;
  444. end;
  445. procedure setftime(var f;time : longint);
  446. begin
  447. dosregs.bx:=textrec(f).handle;
  448. dosregs.cx:=time and $ffff;
  449. dosregs.dx:=time shr 16;
  450. dosregs.ax:=$5701;
  451. msdos(dosregs);
  452. loaddoserror;
  453. end;
  454. procedure getfattr(var f;var attr : word);
  455. begin
  456. {TODO: implement}
  457. runerror(304);
  458. end;
  459. procedure setfattr(var f;attr : word);
  460. begin
  461. {TODO: implement}
  462. runerror(304);
  463. end;
  464. {******************************************************************************
  465. --- Environment ---
  466. ******************************************************************************}
  467. function envcount : longint;
  468. var
  469. hp : ppchar;
  470. begin
  471. hp:=envp;
  472. envcount:=0;
  473. while assigned(hp^) do
  474. begin
  475. inc(envcount);
  476. inc(hp);
  477. end;
  478. end;
  479. function envstr (Index: longint): string;
  480. begin
  481. if (index<=0) or (index>envcount) then
  482. envstr:=''
  483. else
  484. envstr:=strpas(ppchar(pointer(envp)+SizeOf(PChar)*(index-1))^);
  485. end;
  486. Function GetEnv(envvar: string): string;
  487. var
  488. hp : ppchar;
  489. hs : string;
  490. eqpos : longint;
  491. begin
  492. envvar:=upcase(envvar);
  493. hp:=envp;
  494. getenv:='';
  495. while assigned(hp^) do
  496. begin
  497. hs:=strpas(hp^);
  498. eqpos:=pos('=',hs);
  499. if upcase(copy(hs,1,eqpos-1))=envvar then
  500. begin
  501. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  502. break;
  503. end;
  504. inc(hp);
  505. end;
  506. end;
  507. {$ifdef DEBUG_LFN}
  508. begin
  509. LogLFN:=(GetEnv('LOGLFN')<>'');
  510. assign(lfnfile,LFNFileName);
  511. {$I-}
  512. Reset(lfnfile);
  513. if IOResult<>0 then
  514. begin
  515. Rewrite(lfnfile);
  516. Writeln(lfnfile,'New lfn.log');
  517. end;
  518. close(lfnfile);
  519. {$endif DEBUG_LFN}
  520. end.