dos.pp 20 KB

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