dos.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  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. Uses
  15. Go32;
  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. Registers = Go32.Registers;
  27. {$i dosh.inc}
  28. implementation
  29. uses
  30. strings;
  31. {$DEFINE HAS_GETMSCOUNT}
  32. {$DEFINE HAS_INTR}
  33. {$DEFINE HAS_SETCBREAK}
  34. {$DEFINE HAS_GETCBREAK}
  35. {$DEFINE HAS_SETVERIFY}
  36. {$DEFINE HAS_GETVERIFY}
  37. {$DEFINE HAS_SWAPVECTORS}
  38. {$DEFINE HAS_GETSHORTNAME}
  39. {$DEFINE HAS_GETLONGNAME}
  40. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  41. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  42. {$I dos.inc}
  43. {******************************************************************************
  44. --- Dos Interrupt ---
  45. ******************************************************************************}
  46. var
  47. dosregs : registers;
  48. procedure LoadDosError;
  49. var
  50. r : registers;
  51. SimpleDosError : word;
  52. begin
  53. if (dosregs.flags and fcarry) <> 0 then
  54. begin
  55. { I got a extended error = 0
  56. while CarryFlag was set from Exec function }
  57. SimpleDosError:=dosregs.ax;
  58. r.eax:=$5900;
  59. r.ebx:=$0;
  60. realintr($21,r);
  61. { conversion from word to integer !!
  62. gave a Bound check error if ax is $FFFF !! PM }
  63. doserror:=integer(r.ax);
  64. case doserror of
  65. 0 : DosError:=integer(SimpleDosError);
  66. 19 : DosError:=150;
  67. 21 : DosError:=152;
  68. end;
  69. end
  70. else
  71. doserror:=0;
  72. end;
  73. procedure intr(intno : byte;var regs : registers);
  74. begin
  75. realintr(intno,regs);
  76. end;
  77. {******************************************************************************
  78. --- Info / Date / Time ---
  79. ******************************************************************************}
  80. function dosversion : word;
  81. begin
  82. dosregs.ax:=$3000;
  83. msdos(dosregs);
  84. dosversion:=dosregs.ax;
  85. end;
  86. procedure getdate(var year,month,mday,wday : word);
  87. begin
  88. dosregs.ax:=$2a00;
  89. msdos(dosregs);
  90. wday:=dosregs.al;
  91. year:=dosregs.cx;
  92. month:=dosregs.dh;
  93. mday:=dosregs.dl;
  94. end;
  95. procedure setdate(year,month,day : word);
  96. begin
  97. dosregs.cx:=year;
  98. dosregs.dh:=month;
  99. dosregs.dl:=day;
  100. dosregs.ah:=$2b;
  101. msdos(dosregs);
  102. end;
  103. procedure gettime(var hour,minute,second,sec100 : word);
  104. begin
  105. dosregs.ah:=$2c;
  106. msdos(dosregs);
  107. hour:=dosregs.ch;
  108. minute:=dosregs.cl;
  109. second:=dosregs.dh;
  110. sec100:=dosregs.dl;
  111. end;
  112. procedure settime(hour,minute,second,sec100 : word);
  113. begin
  114. dosregs.ch:=hour;
  115. dosregs.cl:=minute;
  116. dosregs.dh:=second;
  117. dosregs.dl:=sec100;
  118. dosregs.ah:=$2d;
  119. msdos(dosregs);
  120. end;
  121. function GetMsCount: int64;
  122. begin
  123. GetMsCount := int64 (MemL [$40:$6c]) * 55;
  124. end;
  125. {******************************************************************************
  126. --- Exec ---
  127. ******************************************************************************}
  128. const
  129. DOS_MAX_COMMAND_LINE_LENGTH = 126;
  130. procedure exec(const path : pathstr;const comline : comstr);
  131. type
  132. realptr = packed record
  133. ofs,seg : word;
  134. end;
  135. texecblock = packed record
  136. envseg : word;
  137. comtail : realptr;
  138. firstFCB : realptr;
  139. secondFCB : realptr;
  140. { iniStack : realptr;
  141. iniCSIP : realptr;}
  142. end;
  143. var
  144. current_dos_buffer_pos,
  145. arg_ofs,
  146. i,la_env,
  147. la_p,la_c,la_e,
  148. fcb1_la,fcb2_la : longint;
  149. execblock : texecblock;
  150. c,p : string;
  151. function paste_to_dos(src : string;cr : boolean; n : longint) : boolean;
  152. {Changed by Laaca - added parameter N}
  153. var
  154. c : pchar;
  155. CLen : cardinal;
  156. ls : longint;
  157. begin
  158. paste_to_dos:=false;
  159. ls:=Length(src)-n;
  160. if current_dos_buffer_pos+ls+3>transfer_buffer+tb_size then
  161. RunError(217);
  162. getmem(c,ls+3);
  163. move(src[n],c^,ls+1);
  164. if cr then
  165. begin
  166. c[ls+1]:=#13;
  167. c[ls+2]:=#0;
  168. end
  169. else
  170. c[ls+1]:=#0;
  171. CLen := StrLen (C) + 1;
  172. seg_move(get_ds,longint(c),dosmemselector,current_dos_buffer_pos,CLen);
  173. current_dos_buffer_pos:=current_dos_buffer_pos+CLen;
  174. freemem(c,ls+3);
  175. paste_to_dos:=true;
  176. end;
  177. begin
  178. { create command line }
  179. c:=comline;
  180. if length(c)>DOS_MAX_COMMAND_LINE_LENGTH then
  181. c[0]:=chr(DOS_MAX_COMMAND_LINE_LENGTH);
  182. { create path }
  183. p:=path;
  184. { allow slash as backslash }
  185. DoDirSeparators(p);
  186. if LFNSupport then
  187. GetShortName(p);
  188. { create buffer }
  189. la_env:=transfer_buffer;
  190. while (la_env and 15)<>0 do
  191. inc(la_env);
  192. current_dos_buffer_pos:=la_env;
  193. { copy environment }
  194. for i:=1 to envcount do
  195. paste_to_dos(envstr(i),false,1);
  196. {the behaviour is still suboptimal because variable COMMAND is stripped out}
  197. paste_to_dos(chr(0),false,1); { adds a double zero at the end }
  198. la_p:=current_dos_buffer_pos;
  199. paste_to_dos(p,false,0);
  200. la_c:=current_dos_buffer_pos;
  201. paste_to_dos(c,true,0);
  202. la_e:=current_dos_buffer_pos;
  203. fcb1_la:=la_e;
  204. la_e:=la_e+16;
  205. fcb2_la:=la_e;
  206. la_e:=la_e+16;
  207. { allocate FCB see dosexec code }
  208. arg_ofs:=1;
  209. while (c[arg_ofs] in [' ',#9]) and
  210. (arg_ofs<length(c)) do
  211. inc(arg_ofs);
  212. dosregs.ax:=$2901;
  213. dosregs.ds:=(la_c+arg_ofs) shr 4;
  214. dosregs.esi:=(la_c+arg_ofs) and 15;
  215. dosregs.es:=fcb1_la shr 4;
  216. dosregs.edi:=fcb1_la and 15;
  217. msdos(dosregs);
  218. { allocate second FCB see dosexec code }
  219. dosregs.ax:=$2901;
  220. dosregs.ds:=(la_c+arg_ofs) shr 4;
  221. dosregs.esi:=(la_c+arg_ofs) and 15;
  222. dosregs.es:=fcb2_la shr 4;
  223. dosregs.edi:=fcb2_la and 15;
  224. msdos(dosregs);
  225. with execblock do
  226. begin
  227. envseg:=la_env shr 4;
  228. comtail.seg:=la_c shr 4;
  229. comtail.ofs:=la_c and 15;
  230. firstFCB.seg:=fcb1_la shr 4;
  231. firstFCB.ofs:=fcb1_la and 15;
  232. secondFCB.seg:=fcb2_la shr 4;
  233. secondFCB.ofs:=fcb2_la and 15;
  234. end;
  235. seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
  236. dosregs.edx:=la_p and 15+1;
  237. dosregs.ds:=la_p shr 4;
  238. dosregs.ebx:=la_p and 15+la_e-la_p;
  239. dosregs.es:=la_p shr 4;
  240. dosregs.ax:=$4b00;
  241. msdos(dosregs);
  242. LoadDosError;
  243. if DosError=0 then
  244. begin
  245. dosregs.ax:=$4d00;
  246. msdos(dosregs);
  247. LastDosExitCode:=DosRegs.al
  248. end
  249. else
  250. LastDosExitCode:=0;
  251. end;
  252. procedure getcbreak(var breakvalue : boolean);
  253. begin
  254. dosregs.ax:=$3300;
  255. msdos(dosregs);
  256. breakvalue:=dosregs.dl<>0;
  257. end;
  258. procedure setcbreak(breakvalue : boolean);
  259. begin
  260. dosregs.ax:=$3301;
  261. dosregs.dl:=ord(breakvalue);
  262. msdos(dosregs);
  263. end;
  264. procedure getverify(var verify : boolean);
  265. begin
  266. dosregs.ah:=$54;
  267. msdos(dosregs);
  268. verify:=dosregs.al<>0;
  269. end;
  270. procedure setverify(verify : boolean);
  271. begin
  272. dosregs.ah:=$2e;
  273. dosregs.al:=ord(verify);
  274. msdos(dosregs);
  275. end;
  276. {******************************************************************************
  277. --- Disk ---
  278. ******************************************************************************}
  279. TYPE ExtendedFat32FreeSpaceRec=packed Record
  280. RetSize : WORD; { (ret) size of returned structure}
  281. Strucversion : WORD; {(call) structure version (0000h)
  282. (ret) actual structure version (0000h)}
  283. SecPerClus, {number of sectors per cluster}
  284. BytePerSec, {number of bytes per sector}
  285. AvailClusters, {number of available clusters}
  286. TotalClusters, {total number of clusters on the drive}
  287. AvailPhysSect, {physical sectors available on the drive}
  288. TotalPhysSect, {total physical sectors on the drive}
  289. AvailAllocUnits, {Available allocation units}
  290. TotalAllocUnits : DWORD; {Total allocation units}
  291. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  292. END;
  293. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  294. VAR
  295. S : String;
  296. Rec : ExtendedFat32FreeSpaceRec;
  297. procedure OldDosDiskData; inline;
  298. begin
  299. dosregs.dl:=drive;
  300. dosregs.ah:=$36;
  301. msdos(dosregs);
  302. if dosregs.ax<>$FFFF then
  303. begin
  304. if Free then
  305. Do_DiskData:=int64(dosregs.ax)*dosregs.bx*dosregs.cx
  306. else
  307. Do_DiskData:=int64(dosregs.ax)*dosregs.cx*dosregs.dx;
  308. end
  309. else
  310. do_diskdata:=-1;
  311. end;
  312. BEGIN
  313. if LFNSupport then
  314. begin
  315. S:='C:\'#0;
  316. if Drive=0 then
  317. begin
  318. GetDir(Drive,S);
  319. Setlength(S,4);
  320. S[4]:=#0;
  321. end
  322. else
  323. S[1]:=chr(Drive+64);
  324. Rec.Strucversion:=0;
  325. Rec.RetSize := 0;
  326. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  327. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  328. dosregs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  329. dosregs.ds:=tb_segment;
  330. dosregs.di:=tb_offset;
  331. dosregs.es:=tb_segment;
  332. dosregs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  333. dosregs.ax:=$7303;
  334. msdos(dosregs);
  335. if (dosregs.flags and fcarry) = 0 then {No error clausule in int except cf}
  336. begin
  337. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  338. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  339. OldDosDiskData
  340. else
  341. if Free then
  342. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  343. else
  344. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  345. end
  346. else
  347. Do_DiskData:=-1;
  348. end
  349. else
  350. OldDosDiskData;
  351. end;
  352. function diskfree(drive : byte) : int64;
  353. begin
  354. diskfree:=Do_DiskData(drive,TRUE);
  355. end;
  356. function disksize(drive : byte) : int64;
  357. begin
  358. disksize:=Do_DiskData(drive,false);
  359. end;
  360. {******************************************************************************
  361. --- LFNFindfirst LFNFindNext ---
  362. ******************************************************************************}
  363. type
  364. LFNSearchRec=packed record
  365. attr,
  366. crtime,
  367. crtimehi,
  368. actime,
  369. actimehi,
  370. lmtime,
  371. lmtimehi,
  372. sizehi,
  373. size : longint;
  374. reserved : array[0..7] of byte;
  375. name : array[0..259] of byte;
  376. shortname : array[0..13] of byte;
  377. end;
  378. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec;from_findfirst : boolean);
  379. var
  380. Len : longint;
  381. begin
  382. With w do
  383. begin
  384. FillChar(d,sizeof(SearchRec),0);
  385. if DosError=0 then
  386. len:=StrLen(@Name)
  387. else
  388. len:=0;
  389. d.Name[0]:=chr(len);
  390. Move(Name[0],d.Name[1],Len);
  391. d.Time:=lmTime;
  392. d.Size:=Size;
  393. d.Attr:=Attr and $FF;
  394. if (DosError<>0) and from_findfirst then
  395. hdl:=-1;
  396. Move(hdl,d.Fill,4);
  397. end;
  398. end;
  399. {$ifdef DEBUG_LFN}
  400. const
  401. LFNFileName : string = 'LFN.log';
  402. LFNOpenNb : longint = 0;
  403. LogLFN : boolean = false;
  404. var
  405. lfnfile : text;
  406. {$endif DEBUG_LFN}
  407. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  408. var
  409. i : longint;
  410. w : LFNSearchRec;
  411. begin
  412. { allow slash as backslash }
  413. DoDirSeparators(path);
  414. dosregs.si:=1; { use ms-dos time }
  415. { don't include the label if not asked for it, needed for network drives }
  416. if attr=$8 then
  417. dosregs.ecx:=8
  418. else
  419. dosregs.ecx:=attr and (not 8);
  420. dosregs.edx:=tb_offset+Sizeof(LFNSearchrec)+1;
  421. dosmemput(tb_segment,tb_offset+Sizeof(LFNSearchrec)+1,path^,strlen(path)+1);
  422. dosregs.ds:=tb_segment;
  423. dosregs.edi:=tb_offset;
  424. dosregs.es:=tb_segment;
  425. dosregs.ax:=$714e;
  426. msdos(dosregs);
  427. LoadDosError;
  428. if DosError=2 then
  429. DosError:=18;
  430. {$ifdef DEBUG_LFN}
  431. if (DosError=0) and LogLFN then
  432. begin
  433. Append(lfnfile);
  434. inc(LFNOpenNb);
  435. Writeln(lfnfile,LFNOpenNb,' LFNFindFirst called ',path);
  436. close(lfnfile);
  437. end;
  438. {$endif DEBUG_LFN}
  439. copyfromdos(w,sizeof(LFNSearchRec));
  440. LFNSearchRec2Dos(w,dosregs.ax,s,true);
  441. end;
  442. procedure LFNFindNext(var s:searchrec);
  443. var
  444. hdl : longint;
  445. w : LFNSearchRec;
  446. begin
  447. Move(s.Fill,hdl,4);
  448. dosregs.si:=1; { use ms-dos time }
  449. dosregs.edi:=tb_offset;
  450. dosregs.es:=tb_segment;
  451. dosregs.ebx:=hdl;
  452. dosregs.ax:=$714f;
  453. msdos(dosregs);
  454. LoadDosError;
  455. copyfromdos(w,sizeof(LFNSearchRec));
  456. LFNSearchRec2Dos(w,hdl,s,false);
  457. end;
  458. procedure LFNFindClose(var s:searchrec);
  459. var
  460. hdl : longint;
  461. begin
  462. Move(s.Fill,hdl,4);
  463. { Do not call MsDos if FindFirst returned with an error }
  464. if hdl=-1 then
  465. begin
  466. DosError:=0;
  467. exit;
  468. end;
  469. dosregs.ebx:=hdl;
  470. dosregs.ax:=$71a1;
  471. msdos(dosregs);
  472. LoadDosError;
  473. {$ifdef DEBUG_LFN}
  474. if (DosError=0) and LogLFN then
  475. begin
  476. Append(lfnfile);
  477. Writeln(lfnfile,LFNOpenNb,' LFNFindClose called ');
  478. close(lfnfile);
  479. if LFNOpenNb>0 then
  480. dec(LFNOpenNb);
  481. end;
  482. {$endif DEBUG_LFN}
  483. end;
  484. {******************************************************************************
  485. --- DosFindfirst DosFindNext ---
  486. ******************************************************************************}
  487. procedure dossearchrec2searchrec(var f : searchrec);
  488. var
  489. len : longint;
  490. begin
  491. { Check is necessary!! OS/2's VDM doesn't clear the name with #0 if the }
  492. { file doesn't exist! (JM) }
  493. if dosError = 0 then
  494. len:=StrLen(@f.Name)
  495. else len := 0;
  496. Move(f.Name[0],f.Name[1],Len);
  497. f.Name[0]:=chr(len);
  498. end;
  499. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  500. var
  501. i : longint;
  502. begin
  503. { allow slash as backslash }
  504. DoDirSeparators(path);
  505. copytodos(f,sizeof(searchrec));
  506. dosregs.edx:=tb_offset;
  507. dosregs.ds:=tb_segment;
  508. dosregs.ah:=$1a;
  509. msdos(dosregs);
  510. dosregs.ecx:=attr;
  511. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  512. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  513. dosregs.ds:=tb_segment;
  514. dosregs.ah:=$4e;
  515. msdos(dosregs);
  516. copyfromdos(f,sizeof(searchrec));
  517. LoadDosError;
  518. dossearchrec2searchrec(f);
  519. end;
  520. procedure Dosfindnext(var f : searchrec);
  521. begin
  522. copytodos(f,sizeof(searchrec));
  523. dosregs.edx:=tb_offset;
  524. dosregs.ds:=tb_segment;
  525. dosregs.ah:=$1a;
  526. msdos(dosregs);
  527. dosregs.ah:=$4f;
  528. msdos(dosregs);
  529. copyfromdos(f,sizeof(searchrec));
  530. LoadDosError;
  531. dossearchrec2searchrec(f);
  532. end;
  533. {******************************************************************************
  534. --- Findfirst FindNext ---
  535. ******************************************************************************}
  536. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  537. var
  538. path0 : array[0..255] of char;
  539. begin
  540. doserror:=0;
  541. strpcopy(path0,path);
  542. if LFNSupport then
  543. LFNFindFirst(path0,attr,f)
  544. else
  545. Dosfindfirst(path0,attr,f);
  546. end;
  547. procedure findnext(var f : searchRec);
  548. begin
  549. doserror:=0;
  550. if LFNSupport then
  551. LFNFindnext(f)
  552. else
  553. Dosfindnext(f);
  554. end;
  555. Procedure FindClose(Var f: SearchRec);
  556. begin
  557. DosError:=0;
  558. if LFNSupport then
  559. LFNFindClose(f);
  560. end;
  561. type swap_proc = procedure;
  562. var
  563. _swap_in : swap_proc;external name '_swap_in';
  564. _swap_out : swap_proc;external name '_swap_out';
  565. _exception_exit : pointer;external name '_exception_exit';
  566. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  567. procedure swapvectors;
  568. begin
  569. if _exception_exit<>nil then
  570. if _v2prt0_exceptions_on then
  571. _swap_out()
  572. else
  573. _swap_in();
  574. end;
  575. {******************************************************************************
  576. --- File ---
  577. ******************************************************************************}
  578. Function FSearch(path: pathstr; dirlist: string): pathstr;
  579. var
  580. i,p1 : longint;
  581. s : searchrec;
  582. newdir : pathstr;
  583. begin
  584. { check if the file specified exists }
  585. findfirst(path,anyfile and not(directory),s);
  586. if doserror=0 then
  587. begin
  588. findclose(s);
  589. fsearch:=path;
  590. exit;
  591. end;
  592. { No wildcards allowed in these things }
  593. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  594. fsearch:=''
  595. else
  596. begin
  597. { allow slash as backslash }
  598. DoDirSeparators(dirlist);
  599. repeat
  600. p1:=pos(';',dirlist);
  601. if p1<>0 then
  602. begin
  603. newdir:=copy(dirlist,1,p1-1);
  604. delete(dirlist,1,p1);
  605. end
  606. else
  607. begin
  608. newdir:=dirlist;
  609. dirlist:='';
  610. end;
  611. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  612. newdir:=newdir+'\';
  613. findfirst(newdir+path,anyfile and not(directory),s);
  614. if doserror=0 then
  615. newdir:=newdir+path
  616. else
  617. newdir:='';
  618. until (dirlist='') or (newdir<>'');
  619. fsearch:=newdir;
  620. end;
  621. findclose(s);
  622. end;
  623. { change to short filename if successful DOS call PM }
  624. function GetShortName(var p : String) : boolean;
  625. var
  626. c : array[0..255] of char;
  627. begin
  628. move(p[1],c[0],length(p));
  629. c[length(p)]:=#0;
  630. copytodos(c,length(p)+1);
  631. dosregs.ax:=$7160;
  632. dosregs.cx:=1;
  633. dosregs.ds:=tb_segment;
  634. dosregs.si:=tb_offset;
  635. dosregs.es:=tb_segment;
  636. dosregs.di:=tb_offset;
  637. msdos(dosregs);
  638. LoadDosError;
  639. if DosError=0 then
  640. begin
  641. copyfromdos(c,256);
  642. move(c[0],p[1],strlen(c));
  643. p[0]:=char(strlen(c));
  644. GetShortName:=true;
  645. end
  646. else
  647. GetShortName:=false;
  648. end;
  649. { change to long filename if successful DOS call PM }
  650. function GetLongName(var p : String) : boolean;
  651. var
  652. c : array[0..255] of char;
  653. begin
  654. move(p[1],c[0],length(p));
  655. c[length(p)]:=#0;
  656. copytodos(c,length(p)+1);
  657. dosregs.ax:=$7160;
  658. dosregs.cx:=2;
  659. dosregs.ds:=tb_segment;
  660. dosregs.si:=tb_offset;
  661. dosregs.es:=tb_segment;
  662. dosregs.di:=tb_offset;
  663. msdos(dosregs);
  664. LoadDosError;
  665. if DosError=0 then
  666. begin
  667. copyfromdos(c,256);
  668. move(c[0],p[1],strlen(c));
  669. p[0]:=char(strlen(c));
  670. GetLongName:=true;
  671. end
  672. else
  673. GetLongName:=false;
  674. end;
  675. {******************************************************************************
  676. --- Get/Set File Time,Attr ---
  677. ******************************************************************************}
  678. procedure getftime(var f;var time : longint);
  679. begin
  680. dosregs.bx:=textrec(f).handle;
  681. dosregs.ax:=$5700;
  682. msdos(dosregs);
  683. loaddoserror;
  684. time:=(dosregs.dx shl 16)+dosregs.cx;
  685. end;
  686. procedure setftime(var f;time : longint);
  687. begin
  688. dosregs.bx:=textrec(f).handle;
  689. dosregs.cx:=time and $ffff;
  690. dosregs.dx:=time shr 16;
  691. dosregs.ax:=$5701;
  692. msdos(dosregs);
  693. loaddoserror;
  694. end;
  695. procedure getfattr(var f;var attr : word);
  696. begin
  697. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  698. dosregs.edx:=tb_offset;
  699. dosregs.ds:=tb_segment;
  700. if LFNSupport then
  701. begin
  702. dosregs.ax:=$7143;
  703. dosregs.bx:=0;
  704. end
  705. else
  706. dosregs.ax:=$4300;
  707. msdos(dosregs);
  708. LoadDosError;
  709. Attr:=dosregs.cx;
  710. end;
  711. procedure setfattr(var f;attr : word);
  712. begin
  713. { Fail for setting VolumeId. }
  714. if ((attr and VolumeID)<>0) then
  715. begin
  716. doserror:=5;
  717. exit;
  718. end;
  719. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  720. dosregs.edx:=tb_offset;
  721. dosregs.ds:=tb_segment;
  722. if LFNSupport then
  723. begin
  724. dosregs.ax:=$7143;
  725. dosregs.bx:=1;
  726. end
  727. else
  728. dosregs.ax:=$4301;
  729. dosregs.cx:=attr;
  730. msdos(dosregs);
  731. LoadDosError;
  732. end;
  733. {******************************************************************************
  734. --- Environment ---
  735. ******************************************************************************}
  736. function envcount : longint;
  737. var
  738. hp : ppchar;
  739. begin
  740. hp:=envp;
  741. envcount:=0;
  742. while assigned(hp^) do
  743. begin
  744. inc(envcount);
  745. inc(hp);
  746. end;
  747. end;
  748. function envstr (Index: longint): string;
  749. begin
  750. if (index<=0) or (index>envcount) then
  751. envstr:=''
  752. else
  753. envstr:=strpas(ppchar(pointer(envp)+SizeOf(PChar)*(index-1))^);
  754. end;
  755. Function GetEnv(envvar: string): string;
  756. var
  757. hp : ppchar;
  758. hs : string;
  759. eqpos : longint;
  760. begin
  761. envvar:=upcase(envvar);
  762. hp:=envp;
  763. getenv:='';
  764. while assigned(hp^) do
  765. begin
  766. hs:=strpas(hp^);
  767. eqpos:=pos('=',hs);
  768. if upcase(copy(hs,1,eqpos-1))=envvar then
  769. begin
  770. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  771. break;
  772. end;
  773. inc(hp);
  774. end;
  775. end;
  776. {$ifdef DEBUG_LFN}
  777. begin
  778. LogLFN:=(GetEnv('LOGLFN')<>'');
  779. assign(lfnfile,LFNFileName);
  780. {$I-}
  781. Reset(lfnfile);
  782. if IOResult<>0 then
  783. begin
  784. Rewrite(lfnfile);
  785. Writeln(lfnfile,'New lfn.log');
  786. end;
  787. close(lfnfile);
  788. {$endif DEBUG_LFN}
  789. end.