dos.pp 22 KB

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