dos.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  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. {$ifdef DEBUG_LFN}
  429. if (DosError=0) and LogLFN then
  430. begin
  431. Append(lfnfile);
  432. inc(LFNOpenNb);
  433. Writeln(lfnfile,LFNOpenNb,' LFNFindFirst called ',path);
  434. close(lfnfile);
  435. end;
  436. {$endif DEBUG_LFN}
  437. copyfromdos(w,sizeof(LFNSearchRec));
  438. LFNSearchRec2Dos(w,dosregs.ax,s,true);
  439. end;
  440. procedure LFNFindNext(var s:searchrec);
  441. var
  442. hdl : longint;
  443. w : LFNSearchRec;
  444. begin
  445. Move(s.Fill,hdl,4);
  446. dosregs.si:=1; { use ms-dos time }
  447. dosregs.edi:=tb_offset;
  448. dosregs.es:=tb_segment;
  449. dosregs.ebx:=hdl;
  450. dosregs.ax:=$714f;
  451. msdos(dosregs);
  452. LoadDosError;
  453. copyfromdos(w,sizeof(LFNSearchRec));
  454. LFNSearchRec2Dos(w,hdl,s,false);
  455. end;
  456. procedure LFNFindClose(var s:searchrec);
  457. var
  458. hdl : longint;
  459. begin
  460. Move(s.Fill,hdl,4);
  461. { Do not call MsDos if FindFirst returned with an error }
  462. if hdl=-1 then
  463. begin
  464. DosError:=0;
  465. exit;
  466. end;
  467. dosregs.ebx:=hdl;
  468. dosregs.ax:=$71a1;
  469. msdos(dosregs);
  470. LoadDosError;
  471. {$ifdef DEBUG_LFN}
  472. if (DosError=0) and LogLFN then
  473. begin
  474. Append(lfnfile);
  475. Writeln(lfnfile,LFNOpenNb,' LFNFindClose called ');
  476. close(lfnfile);
  477. if LFNOpenNb>0 then
  478. dec(LFNOpenNb);
  479. end;
  480. {$endif DEBUG_LFN}
  481. end;
  482. {******************************************************************************
  483. --- DosFindfirst DosFindNext ---
  484. ******************************************************************************}
  485. procedure dossearchrec2searchrec(var f : searchrec);
  486. var
  487. len : longint;
  488. begin
  489. { Check is necessary!! OS/2's VDM doesn't clear the name with #0 if the }
  490. { file doesn't exist! (JM) }
  491. if dosError = 0 then
  492. len:=StrLen(@f.Name)
  493. else len := 0;
  494. Move(f.Name[0],f.Name[1],Len);
  495. f.Name[0]:=chr(len);
  496. end;
  497. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  498. var
  499. i : longint;
  500. begin
  501. { allow slash as backslash }
  502. DoDirSeparators(path);
  503. copytodos(f,sizeof(searchrec));
  504. dosregs.edx:=tb_offset;
  505. dosregs.ds:=tb_segment;
  506. dosregs.ah:=$1a;
  507. msdos(dosregs);
  508. dosregs.ecx:=attr;
  509. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  510. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  511. dosregs.ds:=tb_segment;
  512. dosregs.ah:=$4e;
  513. msdos(dosregs);
  514. copyfromdos(f,sizeof(searchrec));
  515. LoadDosError;
  516. dossearchrec2searchrec(f);
  517. end;
  518. procedure Dosfindnext(var f : searchrec);
  519. begin
  520. copytodos(f,sizeof(searchrec));
  521. dosregs.edx:=tb_offset;
  522. dosregs.ds:=tb_segment;
  523. dosregs.ah:=$1a;
  524. msdos(dosregs);
  525. dosregs.ah:=$4f;
  526. msdos(dosregs);
  527. copyfromdos(f,sizeof(searchrec));
  528. LoadDosError;
  529. dossearchrec2searchrec(f);
  530. end;
  531. {******************************************************************************
  532. --- Findfirst FindNext ---
  533. ******************************************************************************}
  534. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  535. var
  536. path0 : array[0..255] of char;
  537. begin
  538. doserror:=0;
  539. strpcopy(path0,path);
  540. if LFNSupport then
  541. LFNFindFirst(path0,attr,f)
  542. else
  543. Dosfindfirst(path0,attr,f);
  544. end;
  545. procedure findnext(var f : searchRec);
  546. begin
  547. doserror:=0;
  548. if LFNSupport then
  549. LFNFindnext(f)
  550. else
  551. Dosfindnext(f);
  552. end;
  553. Procedure FindClose(Var f: SearchRec);
  554. begin
  555. DosError:=0;
  556. if LFNSupport then
  557. LFNFindClose(f);
  558. end;
  559. type swap_proc = procedure;
  560. var
  561. _swap_in : swap_proc;external name '_swap_in';
  562. _swap_out : swap_proc;external name '_swap_out';
  563. _exception_exit : pointer;external name '_exception_exit';
  564. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  565. procedure swapvectors;
  566. begin
  567. if _exception_exit<>nil then
  568. if _v2prt0_exceptions_on then
  569. _swap_out()
  570. else
  571. _swap_in();
  572. end;
  573. {******************************************************************************
  574. --- File ---
  575. ******************************************************************************}
  576. Function FSearch(path: pathstr; dirlist: string): pathstr;
  577. var
  578. i,p1 : longint;
  579. s : searchrec;
  580. newdir : pathstr;
  581. begin
  582. { check if the file specified exists }
  583. findfirst(path,anyfile and not(directory),s);
  584. if doserror=0 then
  585. begin
  586. findclose(s);
  587. fsearch:=path;
  588. exit;
  589. end;
  590. { No wildcards allowed in these things }
  591. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  592. fsearch:=''
  593. else
  594. begin
  595. { allow slash as backslash }
  596. DoDirSeparators(dirlist);
  597. repeat
  598. p1:=pos(';',dirlist);
  599. if p1<>0 then
  600. begin
  601. newdir:=copy(dirlist,1,p1-1);
  602. delete(dirlist,1,p1);
  603. end
  604. else
  605. begin
  606. newdir:=dirlist;
  607. dirlist:='';
  608. end;
  609. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  610. newdir:=newdir+'\';
  611. findfirst(newdir+path,anyfile and not(directory),s);
  612. if doserror=0 then
  613. newdir:=newdir+path
  614. else
  615. newdir:='';
  616. until (dirlist='') or (newdir<>'');
  617. fsearch:=newdir;
  618. end;
  619. findclose(s);
  620. end;
  621. { change to short filename if successful DOS call PM }
  622. function GetShortName(var p : String) : boolean;
  623. var
  624. c : array[0..255] of char;
  625. begin
  626. move(p[1],c[0],length(p));
  627. c[length(p)]:=#0;
  628. copytodos(c,length(p)+1);
  629. dosregs.ax:=$7160;
  630. dosregs.cx:=1;
  631. dosregs.ds:=tb_segment;
  632. dosregs.si:=tb_offset;
  633. dosregs.es:=tb_segment;
  634. dosregs.di:=tb_offset;
  635. msdos(dosregs);
  636. LoadDosError;
  637. if DosError=0 then
  638. begin
  639. copyfromdos(c,256);
  640. move(c[0],p[1],strlen(c));
  641. p[0]:=char(strlen(c));
  642. GetShortName:=true;
  643. end
  644. else
  645. GetShortName:=false;
  646. end;
  647. { change to long filename if successful DOS call PM }
  648. function GetLongName(var p : String) : boolean;
  649. var
  650. c : array[0..255] of char;
  651. begin
  652. move(p[1],c[0],length(p));
  653. c[length(p)]:=#0;
  654. copytodos(c,length(p)+1);
  655. dosregs.ax:=$7160;
  656. dosregs.cx:=2;
  657. dosregs.ds:=tb_segment;
  658. dosregs.si:=tb_offset;
  659. dosregs.es:=tb_segment;
  660. dosregs.di:=tb_offset;
  661. msdos(dosregs);
  662. LoadDosError;
  663. if DosError=0 then
  664. begin
  665. copyfromdos(c,256);
  666. move(c[0],p[1],strlen(c));
  667. p[0]:=char(strlen(c));
  668. GetLongName:=true;
  669. end
  670. else
  671. GetLongName:=false;
  672. end;
  673. {******************************************************************************
  674. --- Get/Set File Time,Attr ---
  675. ******************************************************************************}
  676. procedure getftime(var f;var time : longint);
  677. begin
  678. dosregs.bx:=textrec(f).handle;
  679. dosregs.ax:=$5700;
  680. msdos(dosregs);
  681. loaddoserror;
  682. time:=(dosregs.dx shl 16)+dosregs.cx;
  683. end;
  684. procedure setftime(var f;time : longint);
  685. begin
  686. dosregs.bx:=textrec(f).handle;
  687. dosregs.cx:=time and $ffff;
  688. dosregs.dx:=time shr 16;
  689. dosregs.ax:=$5701;
  690. msdos(dosregs);
  691. loaddoserror;
  692. end;
  693. procedure getfattr(var f;var attr : word);
  694. begin
  695. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  696. dosregs.edx:=tb_offset;
  697. dosregs.ds:=tb_segment;
  698. if LFNSupport then
  699. begin
  700. dosregs.ax:=$7143;
  701. dosregs.bx:=0;
  702. end
  703. else
  704. dosregs.ax:=$4300;
  705. msdos(dosregs);
  706. LoadDosError;
  707. Attr:=dosregs.cx;
  708. end;
  709. procedure setfattr(var f;attr : word);
  710. begin
  711. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  712. dosregs.edx:=tb_offset;
  713. dosregs.ds:=tb_segment;
  714. if LFNSupport then
  715. begin
  716. dosregs.ax:=$7143;
  717. dosregs.bx:=1;
  718. end
  719. else
  720. dosregs.ax:=$4301;
  721. dosregs.cx:=attr;
  722. msdos(dosregs);
  723. LoadDosError;
  724. end;
  725. {******************************************************************************
  726. --- Environment ---
  727. ******************************************************************************}
  728. function envcount : longint;
  729. var
  730. hp : ppchar;
  731. begin
  732. hp:=envp;
  733. envcount:=0;
  734. while assigned(hp^) do
  735. begin
  736. inc(envcount);
  737. inc(hp);
  738. end;
  739. end;
  740. function envstr (Index: longint): string;
  741. begin
  742. if (index<=0) or (index>envcount) then
  743. envstr:=''
  744. else
  745. envstr:=strpas(ppchar(pointer(envp)+SizeOf(PChar)*(index-1))^);
  746. end;
  747. Function GetEnv(envvar: string): string;
  748. var
  749. hp : ppchar;
  750. hs : string;
  751. eqpos : longint;
  752. begin
  753. envvar:=upcase(envvar);
  754. hp:=envp;
  755. getenv:='';
  756. while assigned(hp^) do
  757. begin
  758. hs:=strpas(hp^);
  759. eqpos:=pos('=',hs);
  760. if upcase(copy(hs,1,eqpos-1))=envvar then
  761. begin
  762. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  763. break;
  764. end;
  765. inc(hp);
  766. end;
  767. end;
  768. {$ifdef DEBUG_LFN}
  769. begin
  770. LogLFN:=(GetEnv('LOGLFN')<>'');
  771. assign(lfnfile,LFNFileName);
  772. {$I-}
  773. Reset(lfnfile);
  774. if IOResult<>0 then
  775. begin
  776. Rewrite(lfnfile);
  777. Writeln(lfnfile,'New lfn.log');
  778. end;
  779. close(lfnfile);
  780. {$endif DEBUG_LFN}
  781. end.