dos.pp 24 KB

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