dos.pp 29 KB

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