dos.pp 24 KB

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