2
0

dos.pp 25 KB

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