dos.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  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. procedure exec(const path : pathstr;const comline : comstr);
  129. type
  130. realptr = packed record
  131. ofs,seg : word;
  132. end;
  133. texecblock = packed record
  134. envseg : word;
  135. comtail : realptr;
  136. firstFCB : realptr;
  137. secondFCB : realptr;
  138. { iniStack : realptr;
  139. iniCSIP : realptr;}
  140. end;
  141. var
  142. current_dos_buffer_pos,
  143. arg_ofs,
  144. i,la_env,
  145. la_p,la_c,la_e,
  146. fcb1_la,fcb2_la : longint;
  147. execblock : texecblock;
  148. c,p : string;
  149. function paste_to_dos(src : string;cr : boolean; n : longint) : boolean;
  150. {Changed by Laaca - added parameter N}
  151. var
  152. c : pchar;
  153. CLen : cardinal;
  154. ls : longint;
  155. begin
  156. paste_to_dos:=false;
  157. ls:=Length(src)-n;
  158. if current_dos_buffer_pos+ls+3>transfer_buffer+tb_size then
  159. RunError(217);
  160. getmem(c,ls+3);
  161. move(src[n],c^,ls+1);
  162. if cr then
  163. begin
  164. c[ls+1]:=#13;
  165. c[ls+2]:=#0;
  166. end
  167. else
  168. c[ls+1]:=#0;
  169. CLen := StrLen (C) + 1;
  170. seg_move(get_ds,longint(c),dosmemselector,current_dos_buffer_pos,CLen);
  171. current_dos_buffer_pos:=current_dos_buffer_pos+CLen;
  172. freemem(c,ls+3);
  173. paste_to_dos:=true;
  174. end;
  175. begin
  176. { create command line }
  177. c:=comline;
  178. { create path }
  179. p:=path;
  180. { allow slash as backslash }
  181. for i:=1 to length(p) do
  182. if p[i]='/' then
  183. p[i]:='\';
  184. if LFNSupport then
  185. GetShortName(p);
  186. { create buffer }
  187. la_env:=transfer_buffer;
  188. while (la_env and 15)<>0 do
  189. inc(la_env);
  190. current_dos_buffer_pos:=la_env;
  191. { copy environment }
  192. for i:=1 to envcount do
  193. paste_to_dos(envstr(i),false,1);
  194. {the behaviour is still suboptimal because variable COMMAND is stripped out}
  195. paste_to_dos(chr(0),false,1); { adds a double zero at the end }
  196. { allow slash as backslash }
  197. la_p:=current_dos_buffer_pos;
  198. paste_to_dos(p,false,0);
  199. la_c:=current_dos_buffer_pos;
  200. paste_to_dos(c,true,0);
  201. la_e:=current_dos_buffer_pos;
  202. fcb1_la:=la_e;
  203. la_e:=la_e+16;
  204. fcb2_la:=la_e;
  205. la_e:=la_e+16;
  206. { allocate FCB see dosexec code }
  207. arg_ofs:=1;
  208. while (c[arg_ofs] in [' ',#9]) and
  209. (arg_ofs<length(c)) do
  210. inc(arg_ofs);
  211. dosregs.ax:=$2901;
  212. dosregs.ds:=(la_c+arg_ofs) shr 4;
  213. dosregs.esi:=(la_c+arg_ofs) and 15;
  214. dosregs.es:=fcb1_la shr 4;
  215. dosregs.edi:=fcb1_la and 15;
  216. msdos(dosregs);
  217. { allocate second FCB see dosexec code }
  218. dosregs.ax:=$2901;
  219. dosregs.ds:=(la_c+arg_ofs) shr 4;
  220. dosregs.esi:=(la_c+arg_ofs) and 15;
  221. dosregs.es:=fcb2_la shr 4;
  222. dosregs.edi:=fcb2_la and 15;
  223. msdos(dosregs);
  224. with execblock do
  225. begin
  226. envseg:=la_env shr 4;
  227. comtail.seg:=la_c shr 4;
  228. comtail.ofs:=la_c and 15;
  229. firstFCB.seg:=fcb1_la shr 4;
  230. firstFCB.ofs:=fcb1_la and 15;
  231. secondFCB.seg:=fcb2_la shr 4;
  232. secondFCB.ofs:=fcb2_la and 15;
  233. end;
  234. seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
  235. dosregs.edx:=la_p and 15+1;
  236. dosregs.ds:=la_p shr 4;
  237. dosregs.ebx:=la_p and 15+la_e-la_p;
  238. dosregs.es:=la_p shr 4;
  239. dosregs.ax:=$4b00;
  240. msdos(dosregs);
  241. LoadDosError;
  242. if DosError<>0 then
  243. begin
  244. dosregs.ax:=$4d00;
  245. msdos(dosregs);
  246. LastDosExitCode:=DosRegs.al
  247. end
  248. else
  249. LastDosExitCode:=0;
  250. end;
  251. procedure getcbreak(var breakvalue : boolean);
  252. begin
  253. dosregs.ax:=$3300;
  254. msdos(dosregs);
  255. breakvalue:=dosregs.dl<>0;
  256. end;
  257. procedure setcbreak(breakvalue : boolean);
  258. begin
  259. dosregs.ax:=$3301;
  260. dosregs.dl:=ord(breakvalue);
  261. msdos(dosregs);
  262. end;
  263. procedure getverify(var verify : boolean);
  264. begin
  265. dosregs.ah:=$54;
  266. msdos(dosregs);
  267. verify:=dosregs.al<>0;
  268. end;
  269. procedure setverify(verify : boolean);
  270. begin
  271. dosregs.ah:=$2e;
  272. dosregs.al:=ord(verify);
  273. msdos(dosregs);
  274. end;
  275. {******************************************************************************
  276. --- Disk ---
  277. ******************************************************************************}
  278. TYPE ExtendedFat32FreeSpaceRec=packed Record
  279. RetSize : WORD; { (ret) size of returned structure}
  280. Strucversion : WORD; {(call) structure version (0000h)
  281. (ret) actual structure version (0000h)}
  282. SecPerClus, {number of sectors per cluster}
  283. BytePerSec, {number of bytes per sector}
  284. AvailClusters, {number of available clusters}
  285. TotalClusters, {total number of clusters on the drive}
  286. AvailPhysSect, {physical sectors available on the drive}
  287. TotalPhysSect, {total physical sectors on the drive}
  288. AvailAllocUnits, {Available allocation units}
  289. TotalAllocUnits : DWORD; {Total allocation units}
  290. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  291. END;
  292. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  293. VAR
  294. S : String;
  295. Rec : ExtendedFat32FreeSpaceRec;
  296. procedure OldDosDiskData; inline;
  297. begin
  298. dosregs.dl:=drive;
  299. dosregs.ah:=$36;
  300. msdos(dosregs);
  301. if dosregs.ax<>$FFFF then
  302. begin
  303. if Free then
  304. Do_DiskData:=int64(dosregs.ax)*dosregs.bx*dosregs.cx
  305. else
  306. Do_DiskData:=int64(dosregs.ax)*dosregs.cx*dosregs.dx;
  307. end
  308. else
  309. do_diskdata:=-1;
  310. end;
  311. BEGIN
  312. if LFNSupport then
  313. begin
  314. S:='C:\'#0;
  315. if Drive=0 then
  316. begin
  317. GetDir(Drive,S);
  318. Setlength(S,4);
  319. S[4]:=#0;
  320. end
  321. else
  322. S[1]:=chr(Drive+64);
  323. Rec.Strucversion:=0;
  324. Rec.RetSize := 0;
  325. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  326. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  327. dosregs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  328. dosregs.ds:=tb_segment;
  329. dosregs.di:=tb_offset;
  330. dosregs.es:=tb_segment;
  331. dosregs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  332. dosregs.ax:=$7303;
  333. msdos(dosregs);
  334. if (dosregs.flags and fcarry) = 0 then {No error clausule in int except cf}
  335. begin
  336. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  337. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  338. OldDosDiskData
  339. else
  340. if Free then
  341. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  342. else
  343. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  344. end
  345. else
  346. Do_DiskData:=-1;
  347. end
  348. else
  349. OldDosDiskData;
  350. end;
  351. function diskfree(drive : byte) : int64;
  352. begin
  353. diskfree:=Do_DiskData(drive,TRUE);
  354. end;
  355. function disksize(drive : byte) : int64;
  356. begin
  357. disksize:=Do_DiskData(drive,false);
  358. end;
  359. {******************************************************************************
  360. --- LFNFindfirst LFNFindNext ---
  361. ******************************************************************************}
  362. type
  363. LFNSearchRec=packed record
  364. attr,
  365. crtime,
  366. crtimehi,
  367. actime,
  368. actimehi,
  369. lmtime,
  370. lmtimehi,
  371. sizehi,
  372. size : longint;
  373. reserved : array[0..7] of byte;
  374. name : array[0..259] of byte;
  375. shortname : array[0..13] of byte;
  376. end;
  377. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec;from_findfirst : boolean);
  378. var
  379. Len : longint;
  380. begin
  381. With w do
  382. begin
  383. FillChar(d,sizeof(SearchRec),0);
  384. if DosError=0 then
  385. len:=StrLen(@Name)
  386. else
  387. len:=0;
  388. d.Name[0]:=chr(len);
  389. Move(Name[0],d.Name[1],Len);
  390. d.Time:=lmTime;
  391. d.Size:=Size;
  392. d.Attr:=Attr and $FF;
  393. if (DosError<>0) and from_findfirst then
  394. hdl:=-1;
  395. Move(hdl,d.Fill,4);
  396. end;
  397. end;
  398. {$ifdef DEBUG_LFN}
  399. const
  400. LFNFileName : string = 'LFN.log';
  401. LFNOpenNb : longint = 0;
  402. LogLFN : boolean = false;
  403. var
  404. lfnfile : text;
  405. {$endif DEBUG_LFN}
  406. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  407. var
  408. i : longint;
  409. w : LFNSearchRec;
  410. begin
  411. { allow slash as backslash }
  412. for i:=0 to strlen(path) do
  413. if path[i]='/' then path[i]:='\';
  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. for i:=0 to strlen(path) do
  503. if path[i]='/' then path[i]:='\';
  504. copytodos(f,sizeof(searchrec));
  505. dosregs.edx:=tb_offset;
  506. dosregs.ds:=tb_segment;
  507. dosregs.ah:=$1a;
  508. msdos(dosregs);
  509. dosregs.ecx:=attr;
  510. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  511. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  512. dosregs.ds:=tb_segment;
  513. dosregs.ah:=$4e;
  514. msdos(dosregs);
  515. copyfromdos(f,sizeof(searchrec));
  516. LoadDosError;
  517. dossearchrec2searchrec(f);
  518. end;
  519. procedure Dosfindnext(var f : searchrec);
  520. begin
  521. copytodos(f,sizeof(searchrec));
  522. dosregs.edx:=tb_offset;
  523. dosregs.ds:=tb_segment;
  524. dosregs.ah:=$1a;
  525. msdos(dosregs);
  526. dosregs.ah:=$4f;
  527. msdos(dosregs);
  528. copyfromdos(f,sizeof(searchrec));
  529. LoadDosError;
  530. dossearchrec2searchrec(f);
  531. end;
  532. {******************************************************************************
  533. --- Findfirst FindNext ---
  534. ******************************************************************************}
  535. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  536. var
  537. path0 : array[0..255] of char;
  538. begin
  539. doserror:=0;
  540. strpcopy(path0,path);
  541. if LFNSupport then
  542. LFNFindFirst(path0,attr,f)
  543. else
  544. Dosfindfirst(path0,attr,f);
  545. end;
  546. procedure findnext(var f : searchRec);
  547. begin
  548. doserror:=0;
  549. if LFNSupport then
  550. LFNFindnext(f)
  551. else
  552. Dosfindnext(f);
  553. end;
  554. Procedure FindClose(Var f: SearchRec);
  555. begin
  556. DosError:=0;
  557. if LFNSupport then
  558. LFNFindClose(f);
  559. end;
  560. type swap_proc = procedure;
  561. var
  562. _swap_in : swap_proc;external name '_swap_in';
  563. _swap_out : swap_proc;external name '_swap_out';
  564. _exception_exit : pointer;external name '_exception_exit';
  565. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  566. procedure swapvectors;
  567. begin
  568. if _exception_exit<>nil then
  569. if _v2prt0_exceptions_on then
  570. _swap_out()
  571. else
  572. _swap_in();
  573. end;
  574. {******************************************************************************
  575. --- File ---
  576. ******************************************************************************}
  577. Function FSearch(path: pathstr; dirlist: string): pathstr;
  578. var
  579. i,p1 : longint;
  580. s : searchrec;
  581. newdir : pathstr;
  582. begin
  583. { check if the file specified exists }
  584. findfirst(path,anyfile and not(directory),s);
  585. if doserror=0 then
  586. begin
  587. findclose(s);
  588. fsearch:=path;
  589. exit;
  590. end;
  591. { No wildcards allowed in these things }
  592. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  593. fsearch:=''
  594. else
  595. begin
  596. { allow slash as backslash }
  597. for i:=1 to length(dirlist) do
  598. if dirlist[i]='/' then dirlist[i]:='\';
  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. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  714. dosregs.edx:=tb_offset;
  715. dosregs.ds:=tb_segment;
  716. if LFNSupport then
  717. begin
  718. dosregs.ax:=$7143;
  719. dosregs.bx:=1;
  720. end
  721. else
  722. dosregs.ax:=$4301;
  723. dosregs.cx:=attr;
  724. msdos(dosregs);
  725. LoadDosError;
  726. end;
  727. {******************************************************************************
  728. --- Environment ---
  729. ******************************************************************************}
  730. function envcount : longint;
  731. var
  732. hp : ppchar;
  733. begin
  734. hp:=envp;
  735. envcount:=0;
  736. while assigned(hp^) do
  737. begin
  738. inc(envcount);
  739. inc(hp);
  740. end;
  741. end;
  742. function envstr (Index: longint): string;
  743. begin
  744. if (index<=0) or (index>envcount) then
  745. envstr:=''
  746. else
  747. envstr:=strpas(ppchar(pointer(envp)+SizeOf(PChar)*(index-1))^);
  748. end;
  749. Function GetEnv(envvar: string): string;
  750. var
  751. hp : ppchar;
  752. hs : string;
  753. eqpos : longint;
  754. begin
  755. envvar:=upcase(envvar);
  756. hp:=envp;
  757. getenv:='';
  758. while assigned(hp^) do
  759. begin
  760. hs:=strpas(hp^);
  761. eqpos:=pos('=',hs);
  762. if upcase(copy(hs,1,eqpos-1))=envvar then
  763. begin
  764. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  765. break;
  766. end;
  767. inc(hp);
  768. end;
  769. end;
  770. {$ifdef DEBUG_LFN}
  771. begin
  772. LogLFN:=(GetEnv('LOGLFN')<>'');
  773. assign(lfnfile,LFNFileName);
  774. {$I-}
  775. Reset(lfnfile);
  776. if IOResult<>0 then
  777. begin
  778. Rewrite(lfnfile);
  779. Writeln(lfnfile,'New lfn.log');
  780. end;
  781. close(lfnfile);
  782. {$endif DEBUG_LFN}
  783. end.