dos.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  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. {$asmmode intel}
  13. unit dos;
  14. interface
  15. Type
  16. searchrec = packed record
  17. fill : array[1..21] of byte;
  18. attr : byte;
  19. time : longint;
  20. { reserved : word; not in DJGPP V2 }
  21. size : longint;
  22. name : string[255]; { LFN Name, DJGPP uses only [12] but more can't hurt (PFV) }
  23. end;
  24. {$DEFINE HAS_REGISTERS}
  25. {$I registers.inc}
  26. {$i dosh.inc}
  27. {$IfDef SYSTEM_DEBUG_STARTUP}
  28. {$DEFINE FORCE_PROXY}
  29. {$endif SYSTEM_DEBUG_STARTUP}
  30. Const
  31. { This variable can be set to true
  32. to force use of !proxy command lines even for short
  33. strings, for debugging purposes mainly, as
  34. this might have negative impact if trying to
  35. call non-go32v2 programs }
  36. force_go32v2_proxy : boolean =
  37. {$ifdef FORCE_PROXY}
  38. true;
  39. {$DEFINE DEBUG_PROXY}
  40. {$else not FORCE_PROXY}
  41. false;
  42. {$endif not FORCE_PROXY}
  43. { This variable allows to use !proxy if command line is
  44. longer than 126 characters.
  45. This will only work if the called program knows how to handle
  46. those command lines.
  47. Luckily this is the case for Free Pascal compiled
  48. programs (even old versions)
  49. and go32v2 DJGPP programs.
  50. You can set this to false to get a warning to stderr
  51. if command line is too long. }
  52. Use_go32v2_proxy : boolean = true;
  53. { Added to interface so that there is no need to implement it
  54. both in dos and sysutils units }
  55. procedure exec_ansistring(path : string;comline : ansistring);
  56. procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';
  57. procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
  58. implementation
  59. uses
  60. strings;
  61. type
  62. PFarByte = ^Byte;far;
  63. PFarChar = ^Char;far;
  64. PFarWord = ^Word;far;
  65. {$DEFINE HAS_GETMSCOUNT}
  66. {$DEFINE HAS_INTR}
  67. {$DEFINE HAS_SETCBREAK}
  68. {$DEFINE HAS_GETCBREAK}
  69. {$DEFINE HAS_SETVERIFY}
  70. {$DEFINE HAS_GETVERIFY}
  71. {$DEFINE HAS_SWAPVECTORS}
  72. {$DEFINE HAS_GETINTVEC}
  73. {$DEFINE HAS_SETINTVEC}
  74. {$DEFINE HAS_KEEP}
  75. {$DEFINE HAS_GETSHORTNAME}
  76. {$DEFINE HAS_GETLONGNAME}
  77. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  78. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  79. {$I dos.inc}
  80. {******************************************************************************
  81. --- Dos Interrupt ---
  82. ******************************************************************************}
  83. var
  84. dosregs : registers;
  85. procedure LoadDosError;
  86. var
  87. r : registers;
  88. SimpleDosError : word;
  89. begin
  90. if (dosregs.flags and fcarry) <> 0 then
  91. begin
  92. { I got a extended error = 0
  93. while CarryFlag was set from Exec function }
  94. SimpleDosError:=dosregs.ax;
  95. r.ax:=$5900;
  96. r.bx:=$0;
  97. intr($21,r);
  98. { conversion from word to integer !!
  99. gave a Bound check error if ax is $FFFF !! PM }
  100. doserror:=integer(r.ax);
  101. case doserror of
  102. 0 : DosError:=integer(SimpleDosError);
  103. 19 : DosError:=150;
  104. 21 : DosError:=152;
  105. end;
  106. end
  107. else
  108. doserror:=0;
  109. end;
  110. {******************************************************************************
  111. --- Info / Date / Time ---
  112. ******************************************************************************}
  113. function dosversion : word;
  114. begin
  115. dosregs.ax:=$3000;
  116. msdos(dosregs);
  117. dosversion:=dosregs.ax;
  118. end;
  119. procedure getdate(var year,month,mday,wday : word);
  120. begin
  121. dosregs.ax:=$2a00;
  122. msdos(dosregs);
  123. wday:=dosregs.al;
  124. year:=dosregs.cx;
  125. month:=dosregs.dh;
  126. mday:=dosregs.dl;
  127. end;
  128. procedure setdate(year,month,day : word);
  129. begin
  130. dosregs.cx:=year;
  131. dosregs.dh:=month;
  132. dosregs.dl:=day;
  133. dosregs.ah:=$2b;
  134. msdos(dosregs);
  135. end;
  136. procedure gettime(var hour,minute,second,sec100 : word);
  137. begin
  138. dosregs.ah:=$2c;
  139. msdos(dosregs);
  140. hour:=dosregs.ch;
  141. minute:=dosregs.cl;
  142. second:=dosregs.dh;
  143. sec100:=dosregs.dl;
  144. end;
  145. procedure settime(hour,minute,second,sec100 : word);
  146. begin
  147. dosregs.ch:=hour;
  148. dosregs.cl:=minute;
  149. dosregs.dh:=second;
  150. dosregs.dl:=sec100;
  151. dosregs.ah:=$2d;
  152. msdos(dosregs);
  153. end;
  154. function GetMsCount: int64;
  155. begin
  156. GetMsCount := int64 (MemL [$40:$6c]) * 55;
  157. end;
  158. {******************************************************************************
  159. --- Exec ---
  160. ******************************************************************************}
  161. const
  162. DOS_MAX_COMMAND_LINE_LENGTH = 126;
  163. procedure exec_ansistring(path : string;comline : ansistring);
  164. begin
  165. {TODO: implement}
  166. runerror(304);
  167. end;
  168. procedure exec(const path : pathstr;const comline : comstr);
  169. begin
  170. exec_ansistring(path, comline);
  171. end;
  172. procedure getcbreak(var breakvalue : boolean);
  173. begin
  174. dosregs.ax:=$3300;
  175. msdos(dosregs);
  176. breakvalue:=dosregs.dl<>0;
  177. end;
  178. procedure setcbreak(breakvalue : boolean);
  179. begin
  180. dosregs.ax:=$3301;
  181. dosregs.dl:=ord(breakvalue);
  182. msdos(dosregs);
  183. end;
  184. procedure getverify(var verify : boolean);
  185. begin
  186. dosregs.ah:=$54;
  187. msdos(dosregs);
  188. verify:=dosregs.al<>0;
  189. end;
  190. procedure setverify(verify : boolean);
  191. begin
  192. dosregs.ah:=$2e;
  193. dosregs.al:=ord(verify);
  194. msdos(dosregs);
  195. end;
  196. {******************************************************************************
  197. --- Disk ---
  198. ******************************************************************************}
  199. type
  200. ExtendedFat32FreeSpaceRec = packed record
  201. RetSize : word; { $00 }
  202. Strucversion : word; { $02 }
  203. SecPerClus, { $04 }
  204. BytePerSec, { $08 }
  205. AvailClusters, { $0C }
  206. TotalClusters, { $10 }
  207. AvailPhysSect, { $14 }
  208. TotalPhysSect, { $18 }
  209. AvailAllocUnits, { $1C }
  210. TotalAllocUnits : longword; { $20 }
  211. Dummy, { $24 }
  212. Dummy2 : longword; { $28 }
  213. end; { $2C }
  214. const
  215. IOCTL_INPUT = 3; //For request header command field
  216. CDFUNC_SECTSIZE = 7; //For cdrom control block func field
  217. CDFUNC_VOLSIZE = 8; //For cdrom control block func field
  218. type
  219. TRequestHeader = packed record
  220. length : byte; { $00 }
  221. subunit : byte; { $01 }
  222. command : byte; { $02 }
  223. status : word; { $03 }
  224. reserved1 : longword; { $05 }
  225. reserved2 : longword; { $09 }
  226. media_desc : byte; { $0D }
  227. transf_ofs : word; { $0E }
  228. transf_seg : word; { $10 }
  229. numbytes : word; { $12 }
  230. end; { $14 }
  231. TCDSectSizeReq = packed record
  232. func : byte; { $00 }
  233. mode : byte; { $01 }
  234. secsize : word; { $02 }
  235. end; { $04 }
  236. TCDVolSizeReq = packed record
  237. func : byte; { $00 }
  238. size : longword; { $01 }
  239. end; { $05 }
  240. function do_diskdata(drive : byte; Free : boolean) : Int64;
  241. var
  242. blocksize, freeblocks, totblocks : longword;
  243. { Get disk data via old int21/36 (GET FREE DISK SPACE). It's always supported
  244. even if it returns wrong values for volumes > 2GB and for cdrom drives when
  245. in pure DOS. Note that it's also the only way to get some data on WinNTs. }
  246. function DiskData_36 : boolean;
  247. begin
  248. DiskData_36:=false;
  249. dosregs.dl:=drive;
  250. dosregs.ah:=$36;
  251. msdos(dosregs);
  252. if dosregs.ax=$FFFF then exit;
  253. blocksize:=dosregs.ax*dosregs.cx;
  254. freeblocks:=dosregs.bx;
  255. totblocks:=dosregs.dx;
  256. Diskdata_36:=true;
  257. end;
  258. { Get disk data via int21/7303 (FAT32 - GET EXTENDED FREE SPACE ON DRIVE).
  259. It is supported by win9x even in pure DOS }
  260. function DiskData_7303 : boolean;
  261. var
  262. s : shortstring;
  263. rec : ExtendedFat32FreeSpaceRec;
  264. begin
  265. DiskData_7303:=false;
  266. s:=chr(drive+$40)+':\'+#0;
  267. rec.Strucversion:=0;
  268. rec.RetSize := 0;
  269. dosregs.dx:=Ofs(s[1]);
  270. dosregs.ds:=Seg(s[1]);
  271. dosregs.di:=Ofs(Rec);
  272. dosregs.es:=Seg(Rec);
  273. dosregs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  274. dosregs.ax:=$7303;
  275. msdos(dosregs);
  276. if (dosregs.flags and fcarry) <> 0 then
  277. exit;
  278. if Rec.RetSize = 0 then
  279. exit;
  280. blocksize:=rec.SecPerClus*rec.BytePerSec;
  281. freeblocks:=rec.AvailAllocUnits;
  282. totblocks:=rec.TotalAllocUnits;
  283. DiskData_7303:=true;
  284. end;
  285. { Get disk data asking to MSCDEX. Pure DOS returns wrong values with
  286. int21/7303 or int21/36 if the drive is a CDROM drive }
  287. function DiskData_CDROM : boolean;
  288. var req : TRequestHeader;
  289. sectreq : TCDSectSizeReq;
  290. sizereq : TCDVolSizeReq;
  291. i : integer;
  292. status,byteswritten : word;
  293. drnum : byte;
  294. begin
  295. DiskData_CDROM:=false;
  296. exit;
  297. { TODO: implement }
  298. (* drnum:=drive-1; //for MSCDEX, 0 = a, 1 = b etc, unlike int21/36
  299. { Is this a CDROM drive? }
  300. dosregs.ax:=$150b;
  301. dosregs.cx:=drnum;
  302. realintr($2f,dosregs);
  303. if (dosregs.bx<>$ADAD) or (dosregs.ax=0) then
  304. exit; // no, it isn't
  305. { Prepare the request header to send to the cdrom driver }
  306. FillByte(req,sizeof(req),0);
  307. req.length:=sizeof(req);
  308. req.command:=IOCTL_INPUT;
  309. req.transf_ofs:=tb_offset+sizeof(req); //CDROM control block will follow
  310. req.transf_seg:=tb_segment; //the request header
  311. req.numbytes:=sizeof(sectreq);
  312. { We're asking the sector size }
  313. sectreq.func:=CDFUNC_SECTSIZE;
  314. sectreq.mode:=0; //cooked
  315. sectreq.secsize:=0;
  316. for i:=1 to 2 do
  317. begin
  318. { Send the request to the cdrom driver }
  319. dosmemput(tb_segment,tb_offset,req,sizeof(req));
  320. dosmemput(tb_segment,tb_offset+sizeof(req),sectreq,sizeof(sectreq));
  321. dosregs.ax:=$1510;
  322. dosregs.cx:=drnum;
  323. dosregs.es:=tb_segment;
  324. dosregs.bx:=tb_offset;
  325. realintr($2f,dosregs);
  326. dosmemget(tb_segment,tb_offset+3,status,2);
  327. { status = $800F means "disk changed". Try once more. }
  328. if (status and $800F) <> $800F then break;
  329. end;
  330. dosmemget(tb_segment,tb_offset+$12,byteswritten,2);
  331. if (status<>$0100) or (byteswritten<>sizeof(sectreq)) then
  332. exit; //An error occurred
  333. dosmemget(tb_segment,tb_offset+sizeof(req),sectreq,sizeof(sectreq));
  334. { Update the request header for the next request }
  335. req.numbytes:=sizeof(sizereq);
  336. { We're asking the volume size (in blocks) }
  337. sizereq.func:=CDFUNC_VOLSIZE;
  338. sizereq.size:=0;
  339. { Send the request to the cdrom driver }
  340. dosmemput(tb_segment,tb_offset,req,sizeof(req));
  341. dosmemput(tb_segment,tb_offset+sizeof(req),sizereq,sizeof(sizereq));
  342. dosregs.ax:=$1510;
  343. dosregs.cx:=drnum;
  344. dosregs.es:=tb_segment;
  345. dosregs.bx:=tb_offset;
  346. realintr($2f,dosregs);
  347. dosmemget(tb_segment,tb_offset,req,sizeof(req));
  348. if (req.status<>$0100) or (req.numbytes<>sizeof(sizereq)) then
  349. exit; //An error occurred
  350. dosmemget(tb_segment,tb_offset+sizeof(req)+1,sizereq.size,4);
  351. blocksize:=sectreq.secsize;
  352. freeblocks:=0; //always 0 for a cdrom
  353. totblocks:=sizereq.size;
  354. DiskData_CDROM:=true;*)
  355. end;
  356. begin
  357. if drive=0 then
  358. begin
  359. dosregs.ax:=$1900; //get current default drive
  360. msdos(dosregs);
  361. drive:=dosregs.al+1;
  362. end;
  363. if not DiskData_CDROM then
  364. if not DiskData_7303 then
  365. if not DiskData_36 then
  366. begin
  367. do_diskdata:=-1;
  368. exit;
  369. end;
  370. do_diskdata:=blocksize;
  371. if free then
  372. do_diskdata:=do_diskdata*freeblocks
  373. else
  374. do_diskdata:=do_diskdata*totblocks;
  375. end;
  376. function diskfree(drive : byte) : int64;
  377. begin
  378. diskfree:=Do_DiskData(drive,TRUE);
  379. end;
  380. function disksize(drive : byte) : int64;
  381. begin
  382. disksize:=Do_DiskData(drive,false);
  383. end;
  384. {******************************************************************************
  385. --- LFNFindfirst LFNFindNext ---
  386. ******************************************************************************}
  387. type
  388. LFNSearchRec=packed record
  389. attr,
  390. crtime,
  391. crtimehi,
  392. actime,
  393. actimehi,
  394. lmtime,
  395. lmtimehi,
  396. sizehi,
  397. size : longint;
  398. reserved : array[0..7] of byte;
  399. name : array[0..259] of byte;
  400. shortname : array[0..13] of byte;
  401. end;
  402. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec;from_findfirst : boolean);
  403. var
  404. Len : longint;
  405. begin
  406. With w do
  407. begin
  408. FillChar(d,sizeof(SearchRec),0);
  409. if DosError=0 then
  410. len:=StrLen(@Name)
  411. else
  412. len:=0;
  413. d.Name[0]:=chr(len);
  414. Move(Name[0],d.Name[1],Len);
  415. d.Time:=lmTime;
  416. d.Size:=Size;
  417. d.Attr:=Attr and $FF;
  418. if (DosError<>0) and from_findfirst then
  419. hdl:=-1;
  420. Move(hdl,d.Fill,4);
  421. end;
  422. end;
  423. {$ifdef DEBUG_LFN}
  424. const
  425. LFNFileName : string = 'LFN.log';
  426. LFNOpenNb : longint = 0;
  427. LogLFN : boolean = false;
  428. var
  429. lfnfile : text;
  430. {$endif DEBUG_LFN}
  431. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  432. var
  433. i : longint;
  434. w : LFNSearchRec;
  435. begin
  436. { allow slash as backslash }
  437. DoDirSeparators(path);
  438. dosregs.si:=1; { use ms-dos time }
  439. { don't include the label if not asked for it, needed for network drives }
  440. if attr=$8 then
  441. dosregs.cx:=8
  442. else
  443. dosregs.cx:=attr and (not 8);
  444. dosregs.dx:=Ofs(path^);
  445. dosregs.ds:=Seg(path^);
  446. dosregs.di:=Ofs(w);
  447. dosregs.es:=Seg(w);
  448. dosregs.ax:=$714e;
  449. msdos(dosregs);
  450. LoadDosError;
  451. if DosError=2 then
  452. DosError:=18;
  453. {$ifdef DEBUG_LFN}
  454. if (DosError=0) and LogLFN then
  455. begin
  456. Append(lfnfile);
  457. inc(LFNOpenNb);
  458. Writeln(lfnfile,LFNOpenNb,' LFNFindFirst called ',path);
  459. close(lfnfile);
  460. end;
  461. {$endif DEBUG_LFN}
  462. LFNSearchRec2Dos(w,dosregs.ax,s,true);
  463. end;
  464. procedure LFNFindNext(var s:searchrec);
  465. var
  466. hdl : longint;
  467. w : LFNSearchRec;
  468. begin
  469. Move(s.Fill,hdl,4);
  470. dosregs.si:=1; { use ms-dos time }
  471. dosregs.di:=Ofs(w);
  472. dosregs.es:=Seg(w);
  473. dosregs.bx:=hdl;
  474. dosregs.ax:=$714f;
  475. msdos(dosregs);
  476. LoadDosError;
  477. LFNSearchRec2Dos(w,hdl,s,false);
  478. end;
  479. procedure LFNFindClose(var s:searchrec);
  480. var
  481. hdl : longint;
  482. begin
  483. Move(s.Fill,hdl,4);
  484. { Do not call MsDos if FindFirst returned with an error }
  485. if hdl=-1 then
  486. begin
  487. DosError:=0;
  488. exit;
  489. end;
  490. dosregs.bx:=hdl;
  491. dosregs.ax:=$71a1;
  492. msdos(dosregs);
  493. LoadDosError;
  494. {$ifdef DEBUG_LFN}
  495. if (DosError=0) and LogLFN then
  496. begin
  497. Append(lfnfile);
  498. Writeln(lfnfile,LFNOpenNb,' LFNFindClose called ');
  499. close(lfnfile);
  500. if LFNOpenNb>0 then
  501. dec(LFNOpenNb);
  502. end;
  503. {$endif DEBUG_LFN}
  504. end;
  505. {******************************************************************************
  506. --- DosFindfirst DosFindNext ---
  507. ******************************************************************************}
  508. procedure dossearchrec2searchrec(var f : searchrec);
  509. var
  510. len : longint;
  511. begin
  512. { Check is necessary!! OS/2's VDM doesn't clear the name with #0 if the }
  513. { file doesn't exist! (JM) }
  514. if dosError = 0 then
  515. len:=StrLen(@f.Name)
  516. else len := 0;
  517. Move(f.Name[0],f.Name[1],Len);
  518. f.Name[0]:=chr(len);
  519. end;
  520. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  521. begin
  522. { allow slash as backslash }
  523. DoDirSeparators(path);
  524. dosregs.dx:=Ofs(f);
  525. dosregs.ds:=Seg(f);
  526. dosregs.ah:=$1a;
  527. msdos(dosregs);
  528. dosregs.cx:=attr;
  529. dosregs.dx:=Ofs(path^);
  530. dosregs.ds:=Seg(path^);
  531. dosregs.ah:=$4e;
  532. msdos(dosregs);
  533. LoadDosError;
  534. dossearchrec2searchrec(f);
  535. end;
  536. procedure Dosfindnext(var f : searchrec);
  537. begin
  538. dosregs.dx:=Ofs(f);
  539. dosregs.ds:=Seg(f);
  540. dosregs.ah:=$1a;
  541. msdos(dosregs);
  542. dosregs.ah:=$4f;
  543. msdos(dosregs);
  544. LoadDosError;
  545. dossearchrec2searchrec(f);
  546. end;
  547. {******************************************************************************
  548. --- Findfirst FindNext ---
  549. ******************************************************************************}
  550. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  551. var
  552. path0 : array[0..255] of char;
  553. begin
  554. doserror:=0;
  555. strpcopy(path0,path);
  556. if LFNSupport then
  557. LFNFindFirst(path0,attr,f)
  558. else
  559. Dosfindfirst(path0,attr,f);
  560. end;
  561. procedure findnext(var f : searchRec);
  562. begin
  563. doserror:=0;
  564. if LFNSupport then
  565. LFNFindnext(f)
  566. else
  567. Dosfindnext(f);
  568. end;
  569. Procedure FindClose(Var f: SearchRec);
  570. begin
  571. DosError:=0;
  572. if LFNSupport then
  573. LFNFindClose(f);
  574. end;
  575. type swap_proc = procedure;
  576. var
  577. _swap_in : swap_proc;external name '_swap_in';
  578. _swap_out : swap_proc;external name '_swap_out';
  579. _exception_exit : pointer;external name '_exception_exit';
  580. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  581. procedure swapvectors;
  582. begin
  583. if _exception_exit<>nil then
  584. if _v2prt0_exceptions_on then
  585. _swap_out()
  586. else
  587. _swap_in();
  588. end;
  589. {******************************************************************************
  590. --- File ---
  591. ******************************************************************************}
  592. Function FSearch(path: pathstr; dirlist: string): pathstr;
  593. var
  594. i,p1 : longint;
  595. s : searchrec;
  596. newdir : pathstr;
  597. begin
  598. { check if the file specified exists }
  599. findfirst(path,anyfile and not(directory),s);
  600. if doserror=0 then
  601. begin
  602. findclose(s);
  603. fsearch:=path;
  604. exit;
  605. end;
  606. { No wildcards allowed in these things }
  607. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  608. fsearch:=''
  609. else
  610. begin
  611. { allow slash as backslash }
  612. DoDirSeparators(dirlist);
  613. repeat
  614. p1:=pos(';',dirlist);
  615. if p1<>0 then
  616. begin
  617. newdir:=copy(dirlist,1,p1-1);
  618. delete(dirlist,1,p1);
  619. end
  620. else
  621. begin
  622. newdir:=dirlist;
  623. dirlist:='';
  624. end;
  625. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  626. newdir:=newdir+'\';
  627. findfirst(newdir+path,anyfile and not(directory),s);
  628. if doserror=0 then
  629. newdir:=newdir+path
  630. else
  631. newdir:='';
  632. until (dirlist='') or (newdir<>'');
  633. fsearch:=newdir;
  634. end;
  635. findclose(s);
  636. end;
  637. { change to short filename if successful DOS call PM }
  638. function GetShortName(var p : String) : boolean;
  639. var
  640. c : array[0..255] of char;
  641. begin
  642. move(p[1],c[0],length(p));
  643. c[length(p)]:=#0;
  644. dosregs.ax:=$7160;
  645. dosregs.cx:=1;
  646. dosregs.ds:=Seg(c);
  647. dosregs.si:=Ofs(c);
  648. dosregs.es:=Seg(c);
  649. dosregs.di:=Ofs(c);
  650. msdos(dosregs);
  651. LoadDosError;
  652. if DosError=0 then
  653. begin
  654. move(c[0],p[1],strlen(c));
  655. p[0]:=char(strlen(c));
  656. GetShortName:=true;
  657. end
  658. else
  659. GetShortName:=false;
  660. end;
  661. { change to long filename if successful DOS call PM }
  662. function GetLongName(var p : String) : boolean;
  663. var
  664. c : array[0..260] of char;
  665. begin
  666. move(p[1],c[0],length(p));
  667. c[length(p)]:=#0;
  668. dosregs.ax:=$7160;
  669. dosregs.cx:=2;
  670. dosregs.ds:=Seg(c);
  671. dosregs.si:=Ofs(c);
  672. dosregs.es:=Seg(c);
  673. dosregs.di:=Ofs(c);
  674. msdos(dosregs);
  675. LoadDosError;
  676. if DosError=0 then
  677. begin
  678. c[255]:=#0;
  679. move(c[0],p[1],strlen(c));
  680. p[0]:=char(strlen(c));
  681. GetLongName:=true;
  682. end
  683. else
  684. GetLongName:=false;
  685. end;
  686. {******************************************************************************
  687. --- Get/Set File Time,Attr ---
  688. ******************************************************************************}
  689. procedure getftime(var f;var time : longint);
  690. begin
  691. dosregs.bx:=textrec(f).handle;
  692. dosregs.ax:=$5700;
  693. msdos(dosregs);
  694. loaddoserror;
  695. time:=(dosregs.dx shl 16)+dosregs.cx;
  696. end;
  697. procedure setftime(var f;time : longint);
  698. begin
  699. dosregs.bx:=textrec(f).handle;
  700. dosregs.cx:=time and $ffff;
  701. dosregs.dx:=time shr 16;
  702. dosregs.ax:=$5701;
  703. msdos(dosregs);
  704. loaddoserror;
  705. end;
  706. procedure getfattr(var f;var attr : word);
  707. begin
  708. dosregs.dx:=Ofs(filerec(f).name);
  709. dosregs.ds:=Seg(filerec(f).name);
  710. if LFNSupport then
  711. begin
  712. dosregs.ax:=$7143;
  713. dosregs.bx:=0;
  714. end
  715. else
  716. dosregs.ax:=$4300;
  717. msdos(dosregs);
  718. LoadDosError;
  719. Attr:=dosregs.cx;
  720. end;
  721. procedure setfattr(var f;attr : word);
  722. begin
  723. { Fail for setting VolumeId. }
  724. if ((attr and VolumeID)<>0) then
  725. begin
  726. doserror:=5;
  727. exit;
  728. end;
  729. dosregs.dx:=Ofs(filerec(f).name);
  730. dosregs.ds:=Seg(filerec(f).name);
  731. if LFNSupport then
  732. begin
  733. dosregs.ax:=$7143;
  734. dosregs.bx:=1;
  735. end
  736. else
  737. dosregs.ax:=$4301;
  738. dosregs.cx:=attr;
  739. msdos(dosregs);
  740. LoadDosError;
  741. end;
  742. {******************************************************************************
  743. --- Environment ---
  744. ******************************************************************************}
  745. function GetEnvStr(EnvNo: Integer; var OutEnvStr: string): integer;
  746. var
  747. dos_env_seg: Word;
  748. ofs: Word;
  749. Ch, Ch2: Char;
  750. begin
  751. dos_env_seg := PFarWord(Ptr(dos_psp, $2C))^;
  752. GetEnvStr := 1;
  753. OutEnvStr := '';
  754. ofs := 0;
  755. repeat
  756. Ch := PFarChar(Ptr(dos_env_seg,ofs))^;
  757. Ch2 := PFarChar(Ptr(dos_env_seg,ofs + 1))^;
  758. if (Ch = #0) and (Ch2 = #0) then
  759. exit;
  760. if Ch = #0 then
  761. Inc(GetEnvStr);
  762. if (Ch <> #0) and (GetEnvStr = EnvNo) then
  763. OutEnvStr := OutEnvStr + Ch;
  764. Inc(ofs);
  765. if ofs = 0 then
  766. exit;
  767. until false;
  768. end;
  769. function envcount : longint;
  770. var
  771. tmpstr: string;
  772. begin
  773. envcount := GetEnvStr(-1, tmpstr);
  774. end;
  775. function envstr (Index: longint): string;
  776. begin
  777. GetEnvStr(Index, envstr);
  778. end;
  779. Function GetEnv(envvar: string): string;
  780. var
  781. hs : string;
  782. eqpos : longint;
  783. I : integer;
  784. begin
  785. envvar:=upcase(envvar);
  786. getenv:='';
  787. for I := 1 to envcount do
  788. begin
  789. hs:=envstr(I);
  790. eqpos:=pos('=',hs);
  791. if upcase(copy(hs,1,eqpos-1))=envvar then
  792. begin
  793. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  794. break;
  795. end;
  796. end;
  797. end;
  798. {******************************************************************************
  799. --- Get/SetIntVec ---
  800. ******************************************************************************}
  801. procedure GetIntVec(intno: Byte; var vector: farpointer); assembler;
  802. asm
  803. mov al, intno
  804. mov ah, 35h
  805. int 21h
  806. xchg ax, bx
  807. mov bx, vector
  808. mov [bx], ax
  809. mov ax, es
  810. mov [bx + 2], ax
  811. end;
  812. procedure SetIntVec(intno: Byte; vector: farpointer); assembler;
  813. asm
  814. push ds
  815. mov al, intno
  816. mov ah, 25h
  817. lds dx, word [vector]
  818. int 21h
  819. pop ds
  820. end;
  821. {******************************************************************************
  822. --- Keep ---
  823. ******************************************************************************}
  824. Procedure Keep(exitcode: word); assembler;
  825. asm
  826. mov bx, dos_psp
  827. dec bx
  828. mov es, bx
  829. mov dx, es:[3]
  830. mov al, exitcode
  831. mov ah, 31h
  832. int 21h
  833. end;
  834. {$ifdef DEBUG_LFN}
  835. begin
  836. LogLFN:=(GetEnv('LOGLFN')<>'');
  837. assign(lfnfile,LFNFileName);
  838. {$I-}
  839. Reset(lfnfile);
  840. if IOResult<>0 then
  841. begin
  842. Rewrite(lfnfile);
  843. Writeln(lfnfile,'New lfn.log');
  844. end;
  845. close(lfnfile);
  846. {$endif DEBUG_LFN}
  847. end.