dos.pp 25 KB

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