dos.pp 24 KB

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