2
0

dos.pp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  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. type
  157. realptr = packed record
  158. ofs,seg : word;
  159. end;
  160. texecblock = packed record
  161. envseg : word;
  162. comtail : realptr;
  163. firstFCB : realptr;
  164. secondFCB : realptr;
  165. { iniStack : realptr;
  166. iniCSIP : realptr;}
  167. end;
  168. var
  169. current_dos_buffer_pos,
  170. arg_ofs,
  171. i,la_env,
  172. la_p,la_c,la_e,
  173. fcb1_la,fcb2_la : longint;
  174. use_proxy : boolean;
  175. proxy_argc : longint;
  176. execblock : texecblock;
  177. c : ansistring;
  178. p : string;
  179. function paste_to_dos(src : string;add_cr_at_end, include_string_length : boolean) : boolean;
  180. {Changed by Laaca - added parameter N}
  181. var
  182. c : pchar;
  183. CLen : cardinal;
  184. start_pos,ls : longint;
  185. begin
  186. paste_to_dos:=false;
  187. if include_string_length then
  188. start_pos:=0
  189. else
  190. start_pos:=1;
  191. ls:=Length(src)-start_pos;
  192. if current_dos_buffer_pos+ls+3>transfer_buffer+tb_size then
  193. RunError(217);
  194. getmem(c,ls+3);
  195. move(src[start_pos],c^,ls+1);
  196. if add_cr_at_end then
  197. begin
  198. c[ls+1]:=#13;
  199. c[ls+2]:=#0;
  200. end
  201. else
  202. c[ls+1]:=#0;
  203. CLen := StrLen (C) + 1;
  204. seg_move(get_ds,longint(c),dosmemselector,current_dos_buffer_pos,CLen);
  205. current_dos_buffer_pos:=current_dos_buffer_pos+CLen;
  206. freemem(c,ls+3);
  207. paste_to_dos:=true;
  208. end;
  209. procedure setup_proxy_cmdline;
  210. const
  211. MAX_ARGS = 128;
  212. var
  213. i : longint;
  214. quote : char;
  215. end_of_arg, skip_char : boolean;
  216. la_proxy_seg : word;
  217. la_proxy_ofs : longint;
  218. current_arg : string;
  219. la_argv_ofs : array [0..MAX_ARGS] of word;
  220. begin
  221. quote:=#0;
  222. current_arg:='';
  223. proxy_argc:=0;
  224. end_of_arg:=false;
  225. while current_dos_buffer_pos mod 16 <> 0 do
  226. inc(current_dos_buffer_pos);
  227. la_proxy_seg:=current_dos_buffer_pos shr 4;
  228. { Also copy parameter 0 }
  229. la_argv_ofs[0]:=current_dos_buffer_pos-la_proxy_seg*16;
  230. { Note that this should be done before
  231. alteriing p value }
  232. paste_to_dos(p,false,false);
  233. inc(proxy_argc);
  234. for i:=1 to length(c) do
  235. begin
  236. skip_char:=false;
  237. case c[i] of
  238. #1..#32:
  239. begin
  240. if quote=#0 then
  241. end_of_arg:=true;
  242. end;
  243. '"' :
  244. begin
  245. if quote=#0 then
  246. begin
  247. quote:='"';
  248. skip_char:=true;
  249. end
  250. else if quote='"' then
  251. end_of_arg:=true;
  252. end;
  253. '''' :
  254. begin
  255. if quote=#0 then
  256. begin
  257. quote:='''';
  258. skip_char:=true;
  259. end
  260. else if quote='''' then
  261. end_of_arg:=true;
  262. end;
  263. end;
  264. if not end_of_arg and not skip_char then
  265. current_arg:=current_arg+c[i];
  266. if i=length(c) then
  267. end_of_arg:=true;
  268. if end_of_arg then
  269. begin
  270. { Allow empty args using "" or '' }
  271. if (current_arg<>'') or (quote<>#0) then
  272. begin
  273. if proxy_argc>MAX_ARGS then
  274. begin
  275. writeln(stderr,'Too many arguments in Dos.exec');
  276. RunError(217);
  277. end;
  278. la_argv_ofs[proxy_argc]:=current_dos_buffer_pos-la_proxy_seg*16;
  279. {$ifdef DEBUG_PROXY}
  280. writeln(stderr,'arg ',proxy_argc,'="',current_arg,'"');
  281. {$endif DEBUG_PROXY}
  282. paste_to_dos(current_arg,false,false);
  283. inc(proxy_argc);
  284. quote:=#0;
  285. current_arg:='';
  286. end;
  287. { Always reset end_of_arg boolean }
  288. end_of_arg:=false;
  289. end;
  290. end;
  291. la_proxy_ofs:=current_dos_buffer_pos - la_proxy_seg*16;
  292. seg_move(get_ds,longint(@la_argv_ofs),dosmemselector,
  293. current_dos_buffer_pos,proxy_argc*sizeof(word));
  294. current_dos_buffer_pos:=current_dos_buffer_pos + proxy_argc*sizeof(word);
  295. c:='!proxy '+hexstr(proxy_argc,4)+' '+hexstr(la_proxy_seg,4)
  296. +' '+hexstr(la_proxy_ofs,4);
  297. {$ifdef DEBUG_PROXY}
  298. writeln(stderr,'Using comline "',c,'"');
  299. {$endif DEBUG_PROXY}
  300. end;
  301. begin
  302. { create command line }
  303. c:=comline;
  304. use_proxy:=false;
  305. if force_go32v2_proxy then
  306. Use_proxy:=true
  307. else if length(c)>DOS_MAX_COMMAND_LINE_LENGTH then
  308. begin
  309. if Use_go32v2_proxy then
  310. begin
  311. Use_Proxy:=true;
  312. end
  313. else
  314. begin
  315. writeln(stderr,'Dos.exec command line truncated to ',
  316. DOS_MAX_COMMAND_LINE_LENGTH,' chars');
  317. writeln(stderr,'Before: "',c,'"');
  318. setlength(c, DOS_MAX_COMMAND_LINE_LENGTH);
  319. writeln(stderr,'After: "',c,'"');
  320. end;
  321. end;
  322. { create path }
  323. {$ifdef DEBUG_PROXY}
  324. writeln(stderr,'Dos.exec path="',path,'"');
  325. {$endif DEBUG_PROXY}
  326. p:=path;
  327. { create buffer }
  328. la_env:=transfer_buffer;
  329. while (la_env and 15)<>0 do
  330. inc(la_env);
  331. current_dos_buffer_pos:=la_env;
  332. { copy environment }
  333. for i:=1 to envcount do
  334. paste_to_dos(envstr(i),false,false);
  335. {the behaviour is still suboptimal because variable COMMAND is stripped out}
  336. paste_to_dos(chr(0),false,false); { adds a double zero at the end }
  337. if use_proxy then
  338. setup_proxy_cmdline;
  339. { allow slash as backslash }
  340. DoDirSeparators(p);
  341. if LFNSupport then
  342. GetShortName(p);
  343. { Add program to DosBuffer with
  344. length at start }
  345. la_p:=current_dos_buffer_pos;
  346. paste_to_dos(p,false,true);
  347. { Add command line args to DosBuffer with
  348. length at start and Carriage Return at end }
  349. la_c:=current_dos_buffer_pos;
  350. paste_to_dos(c,true,true);
  351. la_e:=current_dos_buffer_pos;
  352. fcb1_la:=la_e;
  353. la_e:=la_e+16;
  354. fcb2_la:=la_e;
  355. la_e:=la_e+16;
  356. { allocate FCB see dosexec code }
  357. arg_ofs:=1;
  358. while (c[arg_ofs] in [' ',#9]) and
  359. (arg_ofs<length(c)) do
  360. inc(arg_ofs);
  361. dosregs.ax:=$2901;
  362. dosregs.ds:=(la_c+arg_ofs) shr 4;
  363. dosregs.esi:=(la_c+arg_ofs) and 15;
  364. dosregs.es:=fcb1_la shr 4;
  365. dosregs.edi:=fcb1_la and 15;
  366. msdos(dosregs);
  367. { allocate second FCB see dosexec code }
  368. dosregs.ax:=$2901;
  369. dosregs.ds:=(la_c+arg_ofs) shr 4;
  370. dosregs.esi:=(la_c+arg_ofs) and 15;
  371. dosregs.es:=fcb2_la shr 4;
  372. dosregs.edi:=fcb2_la and 15;
  373. {$ifdef DEBUG_PROXY}
  374. flush(stderr);
  375. {$endif DEBUG_PROXY}
  376. msdos(dosregs);
  377. with execblock do
  378. begin
  379. envseg:=la_env shr 4;
  380. comtail.seg:=la_c shr 4;
  381. comtail.ofs:=la_c and 15;
  382. firstFCB.seg:=fcb1_la shr 4;
  383. firstFCB.ofs:=fcb1_la and 15;
  384. secondFCB.seg:=fcb2_la shr 4;
  385. secondFCB.ofs:=fcb2_la and 15;
  386. end;
  387. seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
  388. dosregs.edx:=la_p and 15+1;
  389. dosregs.ds:=la_p shr 4;
  390. dosregs.ebx:=la_p and 15+la_e-la_p;
  391. dosregs.es:=la_p shr 4;
  392. dosregs.ax:=$4b00;
  393. msdos(dosregs);
  394. LoadDosError;
  395. if DosError=0 then
  396. begin
  397. dosregs.ax:=$4d00;
  398. msdos(dosregs);
  399. LastDosExitCode:=DosRegs.al
  400. end
  401. else
  402. LastDosExitCode:=0;
  403. end;
  404. procedure exec(const path : pathstr;const comline : comstr);
  405. begin
  406. exec_ansistring(path, comline);
  407. end;
  408. procedure getcbreak(var breakvalue : boolean);
  409. begin
  410. dosregs.ax:=$3300;
  411. msdos(dosregs);
  412. breakvalue:=dosregs.dl<>0;
  413. end;
  414. procedure setcbreak(breakvalue : boolean);
  415. begin
  416. dosregs.ax:=$3301;
  417. dosregs.dl:=ord(breakvalue);
  418. msdos(dosregs);
  419. end;
  420. procedure getverify(var verify : boolean);
  421. begin
  422. dosregs.ah:=$54;
  423. msdos(dosregs);
  424. verify:=dosregs.al<>0;
  425. end;
  426. procedure setverify(verify : boolean);
  427. begin
  428. dosregs.ah:=$2e;
  429. dosregs.al:=ord(verify);
  430. msdos(dosregs);
  431. end;
  432. {******************************************************************************
  433. --- Disk ---
  434. ******************************************************************************}
  435. type
  436. ExtendedFat32FreeSpaceRec = packed record
  437. RetSize : word; { $00 }
  438. Strucversion : word; { $02 }
  439. SecPerClus, { $04 }
  440. BytePerSec, { $08 }
  441. AvailClusters, { $0C }
  442. TotalClusters, { $10 }
  443. AvailPhysSect, { $14 }
  444. TotalPhysSect, { $18 }
  445. AvailAllocUnits, { $1C }
  446. TotalAllocUnits : longword; { $20 }
  447. Dummy, { $24 }
  448. Dummy2 : longword; { $28 }
  449. end; { $2C }
  450. const
  451. IOCTL_INPUT = 3; //For request header command field
  452. CDFUNC_SECTSIZE = 7; //For cdrom control block func field
  453. CDFUNC_VOLSIZE = 8; //For cdrom control block func field
  454. type
  455. TRequestHeader = packed record
  456. length : byte; { $00 }
  457. subunit : byte; { $01 }
  458. command : byte; { $02 }
  459. status : word; { $03 }
  460. reserved1 : longword; { $05 }
  461. reserved2 : longword; { $09 }
  462. media_desc : byte; { $0D }
  463. transf_ofs : word; { $0E }
  464. transf_seg : word; { $10 }
  465. numbytes : word; { $12 }
  466. end; { $14 }
  467. TCDSectSizeReq = packed record
  468. func : byte; { $00 }
  469. mode : byte; { $01 }
  470. secsize : word; { $02 }
  471. end; { $04 }
  472. TCDVolSizeReq = packed record
  473. func : byte; { $00 }
  474. size : longword; { $01 }
  475. end; { $05 }
  476. function do_diskdata(drive : byte; Free : boolean) : Int64;
  477. var
  478. blocksize, freeblocks, totblocks : longword;
  479. { Get disk data via old int21/36 (GET FREE DISK SPACE). It's always supported
  480. even if it returns wrong values for volumes > 2GB and for cdrom drives when
  481. in pure DOS. Note that it's also the only way to get some data on WinNTs. }
  482. function DiskData_36 : boolean;
  483. begin
  484. DiskData_36:=false;
  485. dosregs.dl:=drive;
  486. dosregs.ah:=$36;
  487. msdos(dosregs);
  488. if dosregs.ax=$FFFF then exit;
  489. blocksize:=dosregs.ax*dosregs.cx;
  490. freeblocks:=dosregs.bx;
  491. totblocks:=dosregs.dx;
  492. Diskdata_36:=true;
  493. end;
  494. { Get disk data via int21/7303 (FAT32 - GET EXTENDED FREE SPACE ON DRIVE).
  495. It is supported by win9x even in pure DOS }
  496. function DiskData_7303 : boolean;
  497. var
  498. s : shortstring;
  499. rec : ExtendedFat32FreeSpaceRec;
  500. begin
  501. DiskData_7303:=false;
  502. s:=chr(drive+$40)+':\'+#0;
  503. rec.Strucversion:=0;
  504. rec.RetSize := 0;
  505. dosmemput(tb_segment,tb_offset,Rec,sizeof(ExtendedFat32FreeSpaceRec));
  506. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,s[1],4);
  507. dosregs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  508. dosregs.ds:=tb_segment;
  509. dosregs.di:=tb_offset;
  510. dosregs.es:=tb_segment;
  511. dosregs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  512. dosregs.ax:=$7303;
  513. msdos(dosregs);
  514. if (dosregs.flags and fcarry) <> 0 then
  515. exit;
  516. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  517. if Rec.RetSize = 0 then
  518. exit;
  519. blocksize:=rec.SecPerClus*rec.BytePerSec;
  520. freeblocks:=rec.AvailAllocUnits;
  521. totblocks:=rec.TotalAllocUnits;
  522. DiskData_7303:=true;
  523. end;
  524. { Get disk data asking to MSCDEX. Pure DOS returns wrong values with
  525. int21/7303 or int21/36 if the drive is a CDROM drive }
  526. function DiskData_CDROM : boolean;
  527. var req : TRequestHeader;
  528. sectreq : TCDSectSizeReq;
  529. sizereq : TCDVolSizeReq;
  530. i : integer;
  531. status,byteswritten : word;
  532. drnum : byte;
  533. begin
  534. DiskData_CDROM:=false;
  535. drnum:=drive-1; //for MSCDEX, 0 = a, 1 = b etc, unlike int21/36
  536. { Is this a CDROM drive? }
  537. dosregs.ax:=$150b;
  538. dosregs.cx:=drnum;
  539. realintr($2f,dosregs);
  540. if (dosregs.bx<>$ADAD) or (dosregs.ax=0) then
  541. exit; // no, it isn't
  542. { Prepare the request header to send to the cdrom driver }
  543. FillByte(req,sizeof(req),0);
  544. req.length:=sizeof(req);
  545. req.command:=IOCTL_INPUT;
  546. req.transf_ofs:=tb_offset+sizeof(req); //CDROM control block will follow
  547. req.transf_seg:=tb_segment; //the request header
  548. req.numbytes:=sizeof(sectreq);
  549. { We're asking the sector size }
  550. sectreq.func:=CDFUNC_SECTSIZE;
  551. sectreq.mode:=0; //cooked
  552. sectreq.secsize:=0;
  553. for i:=1 to 2 do
  554. begin
  555. { Send the request to the cdrom driver }
  556. dosmemput(tb_segment,tb_offset,req,sizeof(req));
  557. dosmemput(tb_segment,tb_offset+sizeof(req),sectreq,sizeof(sectreq));
  558. dosregs.ax:=$1510;
  559. dosregs.cx:=drnum;
  560. dosregs.es:=tb_segment;
  561. dosregs.bx:=tb_offset;
  562. realintr($2f,dosregs);
  563. dosmemget(tb_segment,tb_offset+3,status,2);
  564. { status = $800F means "disk changed". Try once more. }
  565. if (status and $800F) <> $800F then break;
  566. end;
  567. dosmemget(tb_segment,tb_offset+$12,byteswritten,2);
  568. if (status<>$0100) or (byteswritten<>sizeof(sectreq)) then
  569. exit; //An error occurred
  570. dosmemget(tb_segment,tb_offset+sizeof(req),sectreq,sizeof(sectreq));
  571. { Update the request header for the next request }
  572. req.numbytes:=sizeof(sizereq);
  573. { We're asking the volume size (in blocks) }
  574. sizereq.func:=CDFUNC_VOLSIZE;
  575. sizereq.size:=0;
  576. { Send the request to the cdrom driver }
  577. dosmemput(tb_segment,tb_offset,req,sizeof(req));
  578. dosmemput(tb_segment,tb_offset+sizeof(req),sizereq,sizeof(sizereq));
  579. dosregs.ax:=$1510;
  580. dosregs.cx:=drnum;
  581. dosregs.es:=tb_segment;
  582. dosregs.bx:=tb_offset;
  583. realintr($2f,dosregs);
  584. dosmemget(tb_segment,tb_offset,req,sizeof(req));
  585. if (req.status<>$0100) or (req.numbytes<>sizeof(sizereq)) then
  586. exit; //An error occurred
  587. dosmemget(tb_segment,tb_offset+sizeof(req)+1,sizereq.size,4);
  588. blocksize:=sectreq.secsize;
  589. freeblocks:=0; //always 0 for a cdrom
  590. totblocks:=sizereq.size;
  591. DiskData_CDROM:=true;
  592. end;
  593. begin
  594. if drive=0 then
  595. begin
  596. dosregs.ax:=$1900; //get current default drive
  597. msdos(dosregs);
  598. drive:=dosregs.al+1;
  599. end;
  600. if not DiskData_CDROM then
  601. if not DiskData_7303 then
  602. if not DiskData_36 then
  603. begin
  604. do_diskdata:=-1;
  605. exit;
  606. end;
  607. do_diskdata:=blocksize;
  608. if free then
  609. do_diskdata:=do_diskdata*freeblocks
  610. else
  611. do_diskdata:=do_diskdata*totblocks;
  612. end;
  613. function diskfree(drive : byte) : int64;
  614. begin
  615. diskfree:=Do_DiskData(drive,TRUE);
  616. end;
  617. function disksize(drive : byte) : int64;
  618. begin
  619. disksize:=Do_DiskData(drive,false);
  620. end;
  621. {******************************************************************************
  622. --- LFNFindfirst LFNFindNext ---
  623. ******************************************************************************}
  624. type
  625. LFNSearchRec=packed record
  626. attr,
  627. crtime,
  628. crtimehi,
  629. actime,
  630. actimehi,
  631. lmtime,
  632. lmtimehi,
  633. sizehi,
  634. size : longint;
  635. reserved : array[0..7] of byte;
  636. name : array[0..259] of byte;
  637. shortname : array[0..13] of byte;
  638. end;
  639. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec;from_findfirst : boolean);
  640. var
  641. Len : longint;
  642. begin
  643. With w do
  644. begin
  645. FillChar(d,sizeof(SearchRec),0);
  646. if DosError=0 then
  647. len:=StrLen(@Name)
  648. else
  649. len:=0;
  650. d.Name[0]:=chr(len);
  651. Move(Name[0],d.Name[1],Len);
  652. d.Time:=lmTime;
  653. d.Size:=Size;
  654. d.Attr:=Attr and $FF;
  655. if (DosError<>0) and from_findfirst then
  656. hdl:=-1;
  657. Move(hdl,d.Fill,4);
  658. end;
  659. end;
  660. {$ifdef DEBUG_LFN}
  661. const
  662. LFNFileName : string = 'LFN.log';
  663. LFNOpenNb : longint = 0;
  664. LogLFN : boolean = false;
  665. var
  666. lfnfile : text;
  667. {$endif DEBUG_LFN}
  668. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  669. var
  670. i : longint;
  671. w : LFNSearchRec;
  672. begin
  673. { allow slash as backslash }
  674. DoDirSeparators(path);
  675. dosregs.si:=1; { use ms-dos time }
  676. { don't include the label if not asked for it, needed for network drives }
  677. if attr=$8 then
  678. dosregs.ecx:=8
  679. else
  680. dosregs.ecx:=attr and (not 8);
  681. dosregs.edx:=tb_offset+Sizeof(LFNSearchrec)+1;
  682. dosmemput(tb_segment,tb_offset+Sizeof(LFNSearchrec)+1,path^,strlen(path)+1);
  683. dosregs.ds:=tb_segment;
  684. dosregs.edi:=tb_offset;
  685. dosregs.es:=tb_segment;
  686. dosregs.ax:=$714e;
  687. msdos(dosregs);
  688. LoadDosError;
  689. if DosError=2 then
  690. DosError:=18;
  691. {$ifdef DEBUG_LFN}
  692. if (DosError=0) and LogLFN then
  693. begin
  694. Append(lfnfile);
  695. inc(LFNOpenNb);
  696. Writeln(lfnfile,LFNOpenNb,' LFNFindFirst called ',path);
  697. close(lfnfile);
  698. end;
  699. {$endif DEBUG_LFN}
  700. copyfromdos(w,sizeof(LFNSearchRec));
  701. LFNSearchRec2Dos(w,dosregs.ax,s,true);
  702. end;
  703. procedure LFNFindNext(var s:searchrec);
  704. var
  705. hdl : longint;
  706. w : LFNSearchRec;
  707. begin
  708. Move(s.Fill,hdl,4);
  709. dosregs.si:=1; { use ms-dos time }
  710. dosregs.edi:=tb_offset;
  711. dosregs.es:=tb_segment;
  712. dosregs.ebx:=hdl;
  713. dosregs.ax:=$714f;
  714. msdos(dosregs);
  715. LoadDosError;
  716. copyfromdos(w,sizeof(LFNSearchRec));
  717. LFNSearchRec2Dos(w,hdl,s,false);
  718. end;
  719. procedure LFNFindClose(var s:searchrec);
  720. var
  721. hdl : longint;
  722. begin
  723. Move(s.Fill,hdl,4);
  724. { Do not call MsDos if FindFirst returned with an error }
  725. if hdl=-1 then
  726. begin
  727. DosError:=0;
  728. exit;
  729. end;
  730. dosregs.ebx:=hdl;
  731. dosregs.ax:=$71a1;
  732. msdos(dosregs);
  733. LoadDosError;
  734. {$ifdef DEBUG_LFN}
  735. if (DosError=0) and LogLFN then
  736. begin
  737. Append(lfnfile);
  738. Writeln(lfnfile,LFNOpenNb,' LFNFindClose called ');
  739. close(lfnfile);
  740. if LFNOpenNb>0 then
  741. dec(LFNOpenNb);
  742. end;
  743. {$endif DEBUG_LFN}
  744. end;
  745. {******************************************************************************
  746. --- DosFindfirst DosFindNext ---
  747. ******************************************************************************}
  748. procedure dossearchrec2searchrec(var f : searchrec);
  749. var
  750. len : longint;
  751. begin
  752. { Check is necessary!! OS/2's VDM doesn't clear the name with #0 if the }
  753. { file doesn't exist! (JM) }
  754. if dosError = 0 then
  755. len:=StrLen(@f.Name)
  756. else len := 0;
  757. Move(f.Name[0],f.Name[1],Len);
  758. f.Name[0]:=chr(len);
  759. end;
  760. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  761. var
  762. i : longint;
  763. begin
  764. { allow slash as backslash }
  765. DoDirSeparators(path);
  766. copytodos(f,sizeof(searchrec));
  767. dosregs.edx:=tb_offset;
  768. dosregs.ds:=tb_segment;
  769. dosregs.ah:=$1a;
  770. msdos(dosregs);
  771. dosregs.ecx:=attr;
  772. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  773. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  774. dosregs.ds:=tb_segment;
  775. dosregs.ah:=$4e;
  776. msdos(dosregs);
  777. copyfromdos(f,sizeof(searchrec));
  778. LoadDosError;
  779. dossearchrec2searchrec(f);
  780. end;
  781. procedure Dosfindnext(var f : searchrec);
  782. begin
  783. copytodos(f,sizeof(searchrec));
  784. dosregs.edx:=tb_offset;
  785. dosregs.ds:=tb_segment;
  786. dosregs.ah:=$1a;
  787. msdos(dosregs);
  788. dosregs.ah:=$4f;
  789. msdos(dosregs);
  790. copyfromdos(f,sizeof(searchrec));
  791. LoadDosError;
  792. dossearchrec2searchrec(f);
  793. end;
  794. {******************************************************************************
  795. --- Findfirst FindNext ---
  796. ******************************************************************************}
  797. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  798. var
  799. path0 : array[0..255] of char;
  800. begin
  801. doserror:=0;
  802. strpcopy(path0,path);
  803. if LFNSupport then
  804. LFNFindFirst(path0,attr,f)
  805. else
  806. Dosfindfirst(path0,attr,f);
  807. end;
  808. procedure findnext(var f : searchRec);
  809. begin
  810. doserror:=0;
  811. if LFNSupport then
  812. LFNFindnext(f)
  813. else
  814. Dosfindnext(f);
  815. end;
  816. Procedure FindClose(Var f: SearchRec);
  817. begin
  818. DosError:=0;
  819. if LFNSupport then
  820. LFNFindClose(f);
  821. end;
  822. type swap_proc = procedure;
  823. var
  824. _swap_in : swap_proc;external name '_swap_in';
  825. _swap_out : swap_proc;external name '_swap_out';
  826. _exception_exit : pointer;external name '_exception_exit';
  827. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  828. procedure swapvectors;
  829. begin
  830. if _exception_exit<>nil then
  831. if _v2prt0_exceptions_on then
  832. _swap_out()
  833. else
  834. _swap_in();
  835. end;
  836. {******************************************************************************
  837. --- File ---
  838. ******************************************************************************}
  839. Function FSearch(path: pathstr; dirlist: string): pathstr;
  840. var
  841. i,p1 : longint;
  842. s : searchrec;
  843. newdir : pathstr;
  844. begin
  845. { check if the file specified exists }
  846. findfirst(path,anyfile and not(directory),s);
  847. if doserror=0 then
  848. begin
  849. findclose(s);
  850. fsearch:=path;
  851. exit;
  852. end;
  853. { No wildcards allowed in these things }
  854. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  855. fsearch:=''
  856. else
  857. begin
  858. { allow slash as backslash }
  859. DoDirSeparators(dirlist);
  860. repeat
  861. p1:=pos(';',dirlist);
  862. if p1<>0 then
  863. begin
  864. newdir:=copy(dirlist,1,p1-1);
  865. delete(dirlist,1,p1);
  866. end
  867. else
  868. begin
  869. newdir:=dirlist;
  870. dirlist:='';
  871. end;
  872. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  873. newdir:=newdir+'\';
  874. findfirst(newdir+path,anyfile and not(directory),s);
  875. if doserror=0 then
  876. newdir:=newdir+path
  877. else
  878. newdir:='';
  879. until (dirlist='') or (newdir<>'');
  880. fsearch:=newdir;
  881. end;
  882. findclose(s);
  883. end;
  884. { change to short filename if successful DOS call PM }
  885. function GetShortName(var p : String) : boolean;
  886. var
  887. c : array[0..255] of char;
  888. begin
  889. move(p[1],c[0],length(p));
  890. c[length(p)]:=#0;
  891. copytodos(c,length(p)+1);
  892. dosregs.ax:=$7160;
  893. dosregs.cx:=1;
  894. dosregs.ds:=tb_segment;
  895. dosregs.si:=tb_offset;
  896. dosregs.es:=tb_segment;
  897. dosregs.di:=tb_offset;
  898. msdos(dosregs);
  899. LoadDosError;
  900. if DosError=0 then
  901. begin
  902. copyfromdos(c,256);
  903. move(c[0],p[1],strlen(c));
  904. p[0]:=char(strlen(c));
  905. GetShortName:=true;
  906. end
  907. else
  908. GetShortName:=false;
  909. end;
  910. { change to long filename if successful DOS call PM }
  911. function GetLongName(var p : String) : boolean;
  912. var
  913. c : array[0..255] of char;
  914. begin
  915. move(p[1],c[0],length(p));
  916. c[length(p)]:=#0;
  917. copytodos(c,length(p)+1);
  918. dosregs.ax:=$7160;
  919. dosregs.cx:=2;
  920. dosregs.ds:=tb_segment;
  921. dosregs.si:=tb_offset;
  922. dosregs.es:=tb_segment;
  923. dosregs.di:=tb_offset;
  924. msdos(dosregs);
  925. LoadDosError;
  926. if DosError=0 then
  927. begin
  928. copyfromdos(c,256);
  929. move(c[0],p[1],strlen(c));
  930. p[0]:=char(strlen(c));
  931. GetLongName:=true;
  932. end
  933. else
  934. GetLongName:=false;
  935. end;
  936. {******************************************************************************
  937. --- Get/Set File Time,Attr ---
  938. ******************************************************************************}
  939. procedure getftime(var f;var time : longint);
  940. begin
  941. dosregs.bx:=textrec(f).handle;
  942. dosregs.ax:=$5700;
  943. msdos(dosregs);
  944. loaddoserror;
  945. time:=(dosregs.dx shl 16)+dosregs.cx;
  946. end;
  947. procedure setftime(var f;time : longint);
  948. begin
  949. dosregs.bx:=textrec(f).handle;
  950. dosregs.cx:=time and $ffff;
  951. dosregs.dx:=time shr 16;
  952. dosregs.ax:=$5701;
  953. msdos(dosregs);
  954. loaddoserror;
  955. end;
  956. procedure getfattr(var f;var attr : word);
  957. begin
  958. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  959. dosregs.edx:=tb_offset;
  960. dosregs.ds:=tb_segment;
  961. if LFNSupport then
  962. begin
  963. dosregs.ax:=$7143;
  964. dosregs.bx:=0;
  965. end
  966. else
  967. dosregs.ax:=$4300;
  968. msdos(dosregs);
  969. LoadDosError;
  970. Attr:=dosregs.cx;
  971. end;
  972. procedure setfattr(var f;attr : word);
  973. begin
  974. { Fail for setting VolumeId. }
  975. if ((attr and VolumeID)<>0) then
  976. begin
  977. doserror:=5;
  978. exit;
  979. end;
  980. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  981. dosregs.edx:=tb_offset;
  982. dosregs.ds:=tb_segment;
  983. if LFNSupport then
  984. begin
  985. dosregs.ax:=$7143;
  986. dosregs.bx:=1;
  987. end
  988. else
  989. dosregs.ax:=$4301;
  990. dosregs.cx:=attr;
  991. msdos(dosregs);
  992. LoadDosError;
  993. end;
  994. {******************************************************************************
  995. --- Environment ---
  996. ******************************************************************************}
  997. function envcount : longint;
  998. var
  999. hp : ppchar;
  1000. begin
  1001. hp:=envp;
  1002. envcount:=0;
  1003. while assigned(hp^) do
  1004. begin
  1005. inc(envcount);
  1006. inc(hp);
  1007. end;
  1008. end;
  1009. function envstr (Index: longint): string;
  1010. begin
  1011. if (index<=0) or (index>envcount) then
  1012. envstr:=''
  1013. else
  1014. envstr:=strpas(ppchar(pointer(envp)+SizeOf(PChar)*(index-1))^);
  1015. end;
  1016. Function GetEnv(envvar: string): string;
  1017. var
  1018. hp : ppchar;
  1019. hs : string;
  1020. eqpos : longint;
  1021. begin
  1022. envvar:=upcase(envvar);
  1023. hp:=envp;
  1024. getenv:='';
  1025. while assigned(hp^) do
  1026. begin
  1027. hs:=strpas(hp^);
  1028. eqpos:=pos('=',hs);
  1029. if upcase(copy(hs,1,eqpos-1))=envvar then
  1030. begin
  1031. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  1032. break;
  1033. end;
  1034. inc(hp);
  1035. end;
  1036. end;
  1037. {$ifdef DEBUG_LFN}
  1038. begin
  1039. LogLFN:=(GetEnv('LOGLFN')<>'');
  1040. assign(lfnfile,LFNFileName);
  1041. {$I-}
  1042. Reset(lfnfile);
  1043. if IOResult<>0 then
  1044. begin
  1045. Rewrite(lfnfile);
  1046. Writeln(lfnfile,'New lfn.log');
  1047. end;
  1048. close(lfnfile);
  1049. {$endif DEBUG_LFN}
  1050. end.