dos.pp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993,97 by the Free Pascal development team.
  5. Dos unit for BP7 compatible RTL
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit dos;
  13. interface
  14. Uses
  15. Go32;
  16. Const
  17. {Bitmasks for CPU Flags}
  18. fcarry = $0001;
  19. fparity = $0004;
  20. fauxiliary = $0010;
  21. fzero = $0040;
  22. fsign = $0080;
  23. foverflow = $0800;
  24. {Bitmasks for file attribute}
  25. readonly = $01;
  26. hidden = $02;
  27. sysfile = $04;
  28. volumeid = $08;
  29. directory = $10;
  30. archive = $20;
  31. anyfile = $3F;
  32. {File Status}
  33. fmclosed = $D7B0;
  34. fminput = $D7B1;
  35. fmoutput = $D7B2;
  36. fminout = $D7B3;
  37. Type
  38. { Needed for LFN Support }
  39. ComStr = String[255];
  40. PathStr = String[255];
  41. DirStr = String[255];
  42. NameStr = String[255];
  43. ExtStr = String[255];
  44. {
  45. filerec.inc contains the definition of the filerec.
  46. textrec.inc contains the definition of the textrec.
  47. It is in a separate file to make it available in other units without
  48. having to use the DOS unit for it.
  49. }
  50. {$i filerec.inc}
  51. {$i textrec.inc}
  52. DateTime = packed record
  53. Year,
  54. Month,
  55. Day,
  56. Hour,
  57. Min,
  58. Sec : word;
  59. End;
  60. searchrec = packed record
  61. fill : array[1..21] of byte;
  62. attr : byte;
  63. time : longint;
  64. { reserved : word; not in DJGPP V2 }
  65. size : longint;
  66. name : string[255]; { LFN Name, DJGPP uses only [12] but more can't hurt (PFV) }
  67. end;
  68. Registers = Go32.Registers;
  69. Var
  70. DosError : integer;
  71. {Interrupt}
  72. Procedure Intr(intno: byte; var regs: registers);
  73. Procedure MSDos(var regs: registers);
  74. {Info/Date/Time}
  75. Function DosVersion: Word;
  76. Procedure GetDate(var year, month, mday, wday: word);
  77. Procedure GetTime(var hour, minute, second, sec100: word);
  78. procedure SetDate(year,month,day: word);
  79. Procedure SetTime(hour,minute,second,sec100: word);
  80. Procedure UnpackTime(p: longint; var t: datetime);
  81. Procedure PackTime(var t: datetime; var p: longint);
  82. {Exec}
  83. Procedure Exec(const path: pathstr; const comline: comstr);
  84. Function DosExitCode: word;
  85. {Disk}
  86. Function DiskFree(drive: byte) : longint;
  87. Function DiskSize(drive: byte) : longint;
  88. Procedure FindFirst(const path: pathstr; attr: word; var f: searchRec);
  89. Procedure FindNext(var f: searchRec);
  90. Procedure FindClose(Var f: SearchRec);
  91. {File}
  92. Procedure GetFAttr(var f; var attr: word);
  93. Procedure GetFTime(var f; var time: longint);
  94. Function FSearch(path: pathstr; dirlist: string): pathstr;
  95. Function FExpand(const path: pathstr): pathstr;
  96. Procedure FSplit(path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
  97. {Environment}
  98. Function EnvCount: longint;
  99. Function EnvStr(index: integer): string;
  100. Function GetEnv(envvar: string): string;
  101. {Misc}
  102. Procedure SetFAttr(var f; attr: word);
  103. Procedure SetFTime(var f; time: longint);
  104. Procedure GetCBreak(var breakvalue: boolean);
  105. Procedure SetCBreak(breakvalue: boolean);
  106. Procedure GetVerify(var verify: boolean);
  107. Procedure SetVerify(verify: boolean);
  108. {Do Nothing Functions}
  109. Procedure SwapVectors;
  110. Procedure GetIntVec(intno: byte; var vector: pointer);
  111. Procedure SetIntVec(intno: byte; vector: pointer);
  112. Procedure Keep(exitcode: word);
  113. implementation
  114. uses
  115. strings;
  116. {$ASMMODE ATT}
  117. {******************************************************************************
  118. --- Dos Interrupt ---
  119. ******************************************************************************}
  120. var
  121. dosregs : registers;
  122. procedure LoadDosError;
  123. begin
  124. if (dosregs.flags and carryflag) <> 0 then
  125. { conversion from word to integer !!
  126. gave a Bound check error if ax is $FFFF !! PM }
  127. doserror:=integer(dosregs.ax)
  128. else
  129. doserror:=0;
  130. end;
  131. procedure intr(intno : byte;var regs : registers);
  132. begin
  133. realintr(intno,regs);
  134. end;
  135. procedure msdos(var regs : registers);
  136. begin
  137. intr($21,regs);
  138. end;
  139. {******************************************************************************
  140. --- Info / Date / Time ---
  141. ******************************************************************************}
  142. function dosversion : word;
  143. begin
  144. dosregs.ax:=$3000;
  145. msdos(dosregs);
  146. dosversion:=dosregs.ax;
  147. end;
  148. procedure getdate(var year,month,mday,wday : word);
  149. begin
  150. dosregs.ax:=$2a00;
  151. msdos(dosregs);
  152. wday:=dosregs.al;
  153. year:=dosregs.cx;
  154. month:=dosregs.dh;
  155. mday:=dosregs.dl;
  156. end;
  157. procedure setdate(year,month,day : word);
  158. begin
  159. dosregs.cx:=year;
  160. dosregs.dh:=month;
  161. dosregs.dl:=day;
  162. dosregs.ah:=$2b;
  163. msdos(dosregs);
  164. DosError:=0;
  165. end;
  166. procedure gettime(var hour,minute,second,sec100 : word);
  167. begin
  168. dosregs.ah:=$2c;
  169. msdos(dosregs);
  170. hour:=dosregs.ch;
  171. minute:=dosregs.cl;
  172. second:=dosregs.dh;
  173. sec100:=dosregs.dl;
  174. DosError:=0;
  175. end;
  176. procedure settime(hour,minute,second,sec100 : word);
  177. begin
  178. dosregs.ch:=hour;
  179. dosregs.cl:=minute;
  180. dosregs.dh:=second;
  181. dosregs.dl:=sec100;
  182. dosregs.ah:=$2d;
  183. msdos(dosregs);
  184. DosError:=0;
  185. end;
  186. Procedure packtime(var t : datetime;var p : longint);
  187. Begin
  188. p:=(t.sec shr 1)+(t.min shl 5)+(t.hour shl 11)+(t.day shl 16)+(t.month shl 21)+((t.year-1980) shl 25);
  189. End;
  190. Procedure unpacktime(p : longint;var t : datetime);
  191. Begin
  192. with t do
  193. begin
  194. sec:=(p and 31) shl 1;
  195. min:=(p shr 5) and 63;
  196. hour:=(p shr 11) and 31;
  197. day:=(p shr 16) and 31;
  198. month:=(p shr 21) and 15;
  199. year:=(p shr 25)+1980;
  200. end;
  201. End;
  202. {******************************************************************************
  203. --- Exec ---
  204. ******************************************************************************}
  205. var
  206. lastdosexitcode : word;
  207. procedure exec(const path : pathstr;const comline : comstr);
  208. type
  209. realptr = packed record
  210. ofs,seg : word;
  211. end;
  212. texecblock = packed record
  213. envseg : word;
  214. comtail : realptr;
  215. firstFCB : realptr;
  216. secondFCB : realptr;
  217. iniStack : realptr;
  218. iniCSIP : realptr;
  219. end;
  220. var
  221. current_dos_buffer_pos,
  222. arg_ofs,
  223. i,la_env,
  224. la_p,la_c,la_e,
  225. fcb1_la,fcb2_la : longint;
  226. execblock : texecblock;
  227. c,p : string;
  228. function paste_to_dos(src : string) : boolean;
  229. var
  230. c : array[0..255] of char;
  231. begin
  232. paste_to_dos:=false;
  233. if current_dos_buffer_pos+length(src)+1>transfer_buffer+tb_size then
  234. RunError(217);
  235. move(src[1],c[0],length(src));
  236. c[length(src)]:=#0;
  237. seg_move(get_ds,longint(@c),dosmemselector,current_dos_buffer_pos,length(src)+1);
  238. current_dos_buffer_pos:=current_dos_buffer_pos+length(src)+1;
  239. paste_to_dos:=true;
  240. end;
  241. begin
  242. { create command line }
  243. move(comline[0],c[1],length(comline)+1);
  244. c[length(comline)+2]:=#13;
  245. c[0]:=char(length(comline)+2);
  246. { create path }
  247. p:=path;
  248. for i:=1 to length(p) do
  249. if p[i]='/' then
  250. p[i]:='\';
  251. { create buffer }
  252. la_env:=transfer_buffer;
  253. while (la_env and 15)<>0 do
  254. inc(la_env);
  255. current_dos_buffer_pos:=la_env;
  256. { copy environment }
  257. for i:=1 to envcount do
  258. paste_to_dos(envstr(i));
  259. paste_to_dos(''); { adds a double zero at the end }
  260. { allow slash as backslash }
  261. la_p:=current_dos_buffer_pos;
  262. paste_to_dos(p);
  263. la_c:=current_dos_buffer_pos;
  264. paste_to_dos(c);
  265. la_e:=current_dos_buffer_pos;
  266. fcb1_la:=la_e;
  267. la_e:=la_e+16;
  268. fcb2_la:=la_e;
  269. la_e:=la_e+16;
  270. { allocate FCB see dosexec code }
  271. arg_ofs:=1;
  272. while (c[arg_ofs] in [' ',#9]) do
  273. inc(arg_ofs);
  274. dosregs.ax:=$2901;
  275. dosregs.ds:=(la_c+arg_ofs) shr 4;
  276. dosregs.esi:=(la_c+arg_ofs) and 15;
  277. dosregs.es:=fcb1_la shr 4;
  278. dosregs.edi:=fcb1_la and 15;
  279. msdos(dosregs);
  280. { allocate second FCB see dosexec code }
  281. repeat
  282. inc(arg_ofs);
  283. until (c[arg_ofs] in [' ',#9,#13]);
  284. if c[arg_ofs]<>#13 then
  285. begin
  286. repeat
  287. inc(arg_ofs);
  288. until not (c[arg_ofs] in [' ',#9]);
  289. end;
  290. dosregs.ax:=$2901;
  291. dosregs.ds:=(la_c+arg_ofs) shr 4;
  292. dosregs.si:=(la_c+arg_ofs) and 15;
  293. dosregs.es:=fcb2_la shr 4;
  294. dosregs.di:=fcb2_la and 15;
  295. msdos(dosregs);
  296. with execblock do
  297. begin
  298. envseg:=la_env shr 4;
  299. comtail.seg:=la_c shr 4;
  300. comtail.ofs:=la_c and 15;
  301. firstFCB.seg:=fcb1_la shr 4;
  302. firstFCB.ofs:=fcb1_la and 15;
  303. secondFCB.seg:=fcb2_la shr 4;
  304. secondFCB.ofs:=fcb2_la and 15;
  305. end;
  306. seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
  307. dosregs.edx:=la_p and 15;
  308. dosregs.ds:=la_p shr 4;
  309. dosregs.ebx:=la_e and 15;
  310. dosregs.es:=la_e shr 4;
  311. dosregs.ax:=$4b00;
  312. msdos(dosregs);
  313. LoadDosError;
  314. if DosError=0 then
  315. begin
  316. dosregs.ax:=$4d00;
  317. msdos(dosregs);
  318. LastDosExitCode:=DosRegs.al
  319. end
  320. else
  321. LastDosExitCode:=0;
  322. end;
  323. function dosexitcode : word;
  324. begin
  325. dosexitcode:=lastdosexitcode;
  326. end;
  327. procedure getcbreak(var breakvalue : boolean);
  328. begin
  329. DosError:=0;
  330. dosregs.ax:=$3300;
  331. msdos(dosregs);
  332. breakvalue:=dosregs.dl<>0;
  333. end;
  334. procedure setcbreak(breakvalue : boolean);
  335. begin
  336. DosError:=0;
  337. dosregs.ax:=$3301;
  338. dosregs.dl:=ord(breakvalue);
  339. msdos(dosregs);
  340. end;
  341. procedure getverify(var verify : boolean);
  342. begin
  343. DosError:=0;
  344. dosregs.ah:=$54;
  345. msdos(dosregs);
  346. verify:=dosregs.al<>0;
  347. end;
  348. procedure setverify(verify : boolean);
  349. begin
  350. DosError:=0;
  351. dosregs.ah:=$2e;
  352. dosregs.al:=ord(verify);
  353. msdos(dosregs);
  354. end;
  355. {******************************************************************************
  356. --- Disk ---
  357. ******************************************************************************}
  358. function diskfree(drive : byte) : longint;
  359. begin
  360. DosError:=0;
  361. dosregs.dl:=drive;
  362. dosregs.ah:=$36;
  363. msdos(dosregs);
  364. if dosregs.ax<>$FFFF then
  365. diskfree:=dosregs.ax*dosregs.bx*dosregs.cx
  366. else
  367. diskfree:=-1;
  368. end;
  369. function disksize(drive : byte) : longint;
  370. begin
  371. DosError:=0;
  372. dosregs.dl:=drive;
  373. dosregs.ah:=$36;
  374. msdos(dosregs);
  375. if dosregs.ax<>$FFFF then
  376. disksize:=dosregs.ax*dosregs.cx*dosregs.dx
  377. else
  378. disksize:=-1;
  379. end;
  380. {******************************************************************************
  381. --- LFNFindfirst LFNFindNext ---
  382. ******************************************************************************}
  383. type
  384. LFNSearchRec=packed record
  385. attr,
  386. crtime,
  387. crtimehi,
  388. actime,
  389. actimehi,
  390. lmtime,
  391. lmtimehi,
  392. sizehi,
  393. size : longint;
  394. reserved : array[0..7] of byte;
  395. name : array[0..259] of byte;
  396. shortname : array[0..13] of byte;
  397. end;
  398. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec);
  399. var
  400. Len : longint;
  401. begin
  402. With w do
  403. begin
  404. FillChar(d,sizeof(SearchRec),0);
  405. if DosError=0 then
  406. len:=StrLen(@Name)
  407. else
  408. len:=0;
  409. d.Name[0]:=chr(len);
  410. Move(Name[0],d.Name[1],Len);
  411. d.Time:=lmTime;
  412. d.Size:=Size;
  413. d.Attr:=Attr and $FF;
  414. Move(hdl,d.Fill,4);
  415. end;
  416. end;
  417. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  418. var
  419. i : longint;
  420. w : LFNSearchRec;
  421. begin
  422. { allow slash as backslash }
  423. for i:=0 to strlen(path) do
  424. if path[i]='/' then path[i]:='\';
  425. dosregs.si:=1; { use ms-dos time }
  426. dosregs.ecx:=attr;
  427. dosregs.edx:=tb_offset+Sizeof(LFNSearchrec)+1;
  428. dosmemput(tb_segment,tb_offset+Sizeof(LFNSearchrec)+1,path^,strlen(path)+1);
  429. dosregs.ds:=tb_segment;
  430. dosregs.edi:=tb_offset;
  431. dosregs.es:=tb_segment;
  432. dosregs.ax:=$714e;
  433. msdos(dosregs);
  434. LoadDosError;
  435. copyfromdos(w,sizeof(LFNSearchRec));
  436. LFNSearchRec2Dos(w,dosregs.ax,s);
  437. end;
  438. procedure LFNFindNext(var s:searchrec);
  439. var
  440. hdl : longint;
  441. w : LFNSearchRec;
  442. begin
  443. Move(s.Fill,hdl,4);
  444. dosregs.si:=1; { use ms-dos time }
  445. dosregs.edi:=tb_offset;
  446. dosregs.es:=tb_segment;
  447. dosregs.ebx:=hdl;
  448. dosregs.ax:=$714f;
  449. msdos(dosregs);
  450. LoadDosError;
  451. copyfromdos(w,sizeof(LFNSearchRec));
  452. LFNSearchRec2Dos(w,hdl,s);
  453. end;
  454. procedure LFNFindClose(var s:searchrec);
  455. var
  456. hdl : longint;
  457. begin
  458. Move(s.Fill,hdl,4);
  459. dosregs.ebx:=hdl;
  460. dosregs.ax:=$71a1;
  461. msdos(dosregs);
  462. LoadDosError;
  463. end;
  464. {******************************************************************************
  465. --- DosFindfirst DosFindNext ---
  466. ******************************************************************************}
  467. procedure dossearchrec2searchrec(var f : searchrec);
  468. var
  469. len : longint;
  470. begin
  471. len:=StrLen(@f.Name);
  472. Move(f.Name[0],f.Name[1],Len);
  473. f.Name[0]:=chr(len);
  474. end;
  475. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  476. var
  477. i : longint;
  478. begin
  479. { allow slash as backslash }
  480. for i:=0 to strlen(path) do
  481. if path[i]='/' then path[i]:='\';
  482. copytodos(f,sizeof(searchrec));
  483. dosregs.edx:=tb_offset;
  484. dosregs.ds:=tb_segment;
  485. dosregs.ah:=$1a;
  486. msdos(dosregs);
  487. dosregs.ecx:=attr;
  488. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  489. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  490. dosregs.ds:=tb_segment;
  491. dosregs.ah:=$4e;
  492. msdos(dosregs);
  493. copyfromdos(f,sizeof(searchrec));
  494. LoadDosError;
  495. dossearchrec2searchrec(f);
  496. end;
  497. procedure Dosfindnext(var f : searchrec);
  498. begin
  499. copytodos(f,sizeof(searchrec));
  500. dosregs.edx:=tb_offset;
  501. dosregs.ds:=tb_segment;
  502. dosregs.ah:=$1a;
  503. msdos(dosregs);
  504. dosregs.ah:=$4f;
  505. msdos(dosregs);
  506. copyfromdos(f,sizeof(searchrec));
  507. LoadDosError;
  508. dossearchrec2searchrec(f);
  509. end;
  510. {******************************************************************************
  511. --- Findfirst FindNext ---
  512. ******************************************************************************}
  513. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  514. var
  515. path0 : array[0..256] of char;
  516. begin
  517. doserror:=0;
  518. strpcopy(path0,path);
  519. if LFNSupport then
  520. LFNFindFirst(path0,attr,f)
  521. else
  522. Dosfindfirst(path0,attr,f);
  523. end;
  524. procedure findnext(var f : searchRec);
  525. begin
  526. doserror:=0;
  527. if LFNSupport then
  528. LFNFindnext(f)
  529. else
  530. Dosfindnext(f);
  531. end;
  532. Procedure FindClose(Var f: SearchRec);
  533. begin
  534. DosError:=0;
  535. if LFNSupport then
  536. LFNFindClose(f);
  537. end;
  538. {$ASMMODE DIRECT}
  539. procedure swapvectors;
  540. begin
  541. DosError:=0;
  542. asm
  543. { uses four global symbols from v2prt0.as to be able to know the current
  544. exception state without using dpmiexcp unit }
  545. movl _exception_exit,%eax
  546. orl %eax,%eax
  547. je .Lno_excep
  548. movl _v2prt0_exceptions_on,%eax
  549. orl %eax,%eax
  550. je .Lexceptions_off
  551. movl _swap_out,%eax
  552. call *%eax
  553. jmp .Lno_excep
  554. .Lexceptions_off:
  555. movl _swap_in,%eax
  556. call *%eax
  557. .Lno_excep:
  558. end;
  559. end;
  560. {$ASMMODE ATT}
  561. {******************************************************************************
  562. --- File ---
  563. ******************************************************************************}
  564. procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;var ext : extstr);
  565. var
  566. dotpos,p1,i : longint;
  567. begin
  568. { allow slash as backslash }
  569. for i:=1 to length(path) do
  570. if path[i]='/' then path[i]:='\';
  571. { get drive name }
  572. p1:=pos(':',path);
  573. if p1>0 then
  574. begin
  575. dir:=path[1]+':';
  576. delete(path,1,p1);
  577. end
  578. else
  579. dir:='';
  580. { split the path and the name, there are no more path informtions }
  581. { if path contains no backslashes }
  582. while true do
  583. begin
  584. p1:=pos('\',path);
  585. if p1=0 then
  586. break;
  587. dir:=dir+copy(path,1,p1);
  588. delete(path,1,p1);
  589. end;
  590. { try to find out a extension }
  591. if LFNSupport then
  592. begin
  593. Ext:='';
  594. i:=Length(Path);
  595. DotPos:=256;
  596. While (i>0) Do
  597. Begin
  598. If (Path[i]='.') Then
  599. begin
  600. DotPos:=i;
  601. break;
  602. end;
  603. Dec(i);
  604. end;
  605. Ext:=Copy(Path,DotPos,255);
  606. Name:=Copy(Path,1,DotPos - 1);
  607. end
  608. else
  609. begin
  610. p1:=pos('.',path);
  611. if p1>0 then
  612. begin
  613. ext:=copy(path,p1,4);
  614. delete(path,p1,length(path)-p1+1);
  615. end
  616. else
  617. ext:='';
  618. name:=path;
  619. end;
  620. end;
  621. function fexpand(const path : pathstr) : pathstr;
  622. var
  623. s,pa : pathstr;
  624. i,j : longint;
  625. begin
  626. getdir(0,s);
  627. if LFNSupport then
  628. begin
  629. pa:=path;
  630. { Always uppercase driveletter }
  631. if (length(pa)>1) and (pa[2]=':') and (pa[1] in ['a'..'z']) then
  632. pa[1]:=CHR(ORD(Pa[1])-32);
  633. end
  634. else
  635. pa:=upcase(path);
  636. { allow slash as backslash }
  637. for i:=1 to length(pa) do
  638. if pa[i]='/' then
  639. pa[i]:='\';
  640. if (length(pa)>1) and (pa[2]=':') and (pa[1] in ['A'..'Z']) then
  641. begin
  642. { we must get the right directory }
  643. getdir(ord(pa[1])-ord('A')+1,s);
  644. if (ord(pa[0])>2) and (pa[3]<>'\') then
  645. if pa[1]=s[1] then
  646. begin
  647. { remove ending slash if it already exists }
  648. if s[length(s)]='\' then
  649. dec(s[0]);
  650. pa:=s+'\'+copy (pa,3,length(pa));
  651. end
  652. else
  653. pa:=pa[1]+':\'+copy (pa,3,length(pa))
  654. end
  655. else
  656. if pa[1]='\' then
  657. pa:=s[1]+':'+pa
  658. else if s[0]=#3 then
  659. pa:=s+pa
  660. else
  661. pa:=s+'\'+pa;
  662. { Turbo Pascal gives current dir on drive if only drive given as parameter! }
  663. if length(pa) = 2 then
  664. begin
  665. getdir(byte(pa[1])-64,s);
  666. pa := s;
  667. end;
  668. {First remove all references to '\.\'}
  669. while pos ('\.\',pa)<>0 do
  670. delete (pa,pos('\.\',pa),2);
  671. {Now remove also all references to '\..\' + of course previous dirs..}
  672. repeat
  673. i:=pos('\..\',pa);
  674. if i<>0 then
  675. begin
  676. j:=i-1;
  677. while (j>1) and (pa[j]<>'\') do
  678. dec (j);
  679. if pa[j+1] = ':' then j := 3;
  680. delete (pa,j,i-j+3);
  681. end;
  682. until i=0;
  683. { Turbo Pascal gets rid of a \.. at the end of the path }
  684. { Now remove also any reference to '\..' at end of line
  685. + of course previous dir.. }
  686. i:=pos('\..',pa);
  687. if i<>0 then
  688. begin
  689. if i = length(pa) - 2 then
  690. begin
  691. j:=i-1;
  692. while (j>1) and (pa[j]<>'\') do
  693. dec (j);
  694. delete (pa,j,i-j+3);
  695. end;
  696. pa := pa + '\';
  697. end;
  698. { Remove End . and \}
  699. if (length(pa)>0) and (pa[length(pa)]='.') then
  700. dec(byte(pa[0]));
  701. { if only the drive + a '\' is left then the '\' should be left to prevtn the program
  702. accessing the current directory on the drive rather than the root!}
  703. { if the last char of path = '\' then leave it in as this is what TP does! }
  704. if ((length(pa)>3) and (pa[length(pa)]='\')) and (path[length(path)] <> '\') then
  705. dec(byte(pa[0]));
  706. { if only a drive is given in path then there should be a '\' at the
  707. end of the string given back }
  708. if length(pa) = 2 then pa := pa + '\';
  709. fexpand:=pa;
  710. end;
  711. Function FSearch(path: pathstr; dirlist: string): pathstr;
  712. var
  713. i,p1 : longint;
  714. s : searchrec;
  715. newdir : pathstr;
  716. begin
  717. { No wildcards allowed in these things }
  718. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  719. fsearch:=''
  720. else
  721. begin
  722. { allow slash as backslash }
  723. for i:=1 to length(dirlist) do
  724. if dirlist[i]='/' then dirlist[i]:='\';
  725. repeat
  726. p1:=pos(';',dirlist);
  727. if p1<>0 then
  728. begin
  729. newdir:=copy(dirlist,1,p1-1);
  730. delete(dirlist,1,p1);
  731. end
  732. else
  733. begin
  734. newdir:=dirlist;
  735. dirlist:='';
  736. end;
  737. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  738. newdir:=newdir+'\';
  739. findfirst(newdir+path,anyfile,s);
  740. if doserror=0 then
  741. newdir:=newdir+path
  742. else
  743. newdir:='';
  744. until (dirlist='') or (newdir<>'');
  745. fsearch:=newdir;
  746. end;
  747. end;
  748. {******************************************************************************
  749. --- Get/Set File Time,Attr ---
  750. ******************************************************************************}
  751. procedure getftime(var f;var time : longint);
  752. begin
  753. dosregs.bx:=textrec(f).handle;
  754. dosregs.ax:=$5700;
  755. msdos(dosregs);
  756. loaddoserror;
  757. time:=(dosregs.dx shl 16)+dosregs.cx;
  758. end;
  759. procedure setftime(var f;time : longint);
  760. begin
  761. dosregs.bx:=textrec(f).handle;
  762. dosregs.cx:=time and $ffff;
  763. dosregs.dx:=time shr 16;
  764. dosregs.ax:=$5701;
  765. msdos(dosregs);
  766. loaddoserror;
  767. end;
  768. procedure getfattr(var f;var attr : word);
  769. begin
  770. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  771. dosregs.edx:=tb_offset;
  772. dosregs.ds:=tb_segment;
  773. if LFNSupport then
  774. begin
  775. dosregs.ax:=$7143;
  776. dosregs.bx:=0;
  777. end
  778. else
  779. dosregs.ax:=$4300;
  780. msdos(dosregs);
  781. LoadDosError;
  782. Attr:=dosregs.cx;
  783. end;
  784. procedure setfattr(var f;attr : word);
  785. begin
  786. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  787. dosregs.edx:=tb_offset;
  788. dosregs.ds:=tb_segment;
  789. if LFNSupport then
  790. begin
  791. dosregs.ax:=$7143;
  792. dosregs.bx:=1;
  793. end
  794. else
  795. dosregs.ax:=$4301;
  796. dosregs.cx:=attr;
  797. msdos(dosregs);
  798. LoadDosError;
  799. end;
  800. {******************************************************************************
  801. --- Environment ---
  802. ******************************************************************************}
  803. function envcount : longint;
  804. var
  805. hp : ppchar;
  806. begin
  807. hp:=envp;
  808. envcount:=0;
  809. while assigned(hp^) do
  810. begin
  811. inc(envcount);
  812. hp:=hp+4;
  813. end;
  814. end;
  815. function envstr(index : integer) : string;
  816. begin
  817. if (index<=0) or (index>envcount) then
  818. begin
  819. envstr:='';
  820. exit;
  821. end;
  822. envstr:=strpas(ppchar(envp+4*(index-1))^);
  823. end;
  824. Function GetEnv(envvar: string): string;
  825. var
  826. hp : ppchar;
  827. hs : string;
  828. eqpos : longint;
  829. begin
  830. envvar:=upcase(envvar);
  831. hp:=envp;
  832. getenv:='';
  833. while assigned(hp^) do
  834. begin
  835. hs:=strpas(hp^);
  836. eqpos:=pos('=',hs);
  837. if copy(hs,1,eqpos-1)=envvar then
  838. begin
  839. getenv:=copy(hs,eqpos+1,255);
  840. exit;
  841. end;
  842. hp:=hp+4;
  843. end;
  844. end;
  845. {******************************************************************************
  846. --- Not Supported ---
  847. ******************************************************************************}
  848. Procedure keep(exitcode : word);
  849. Begin
  850. End;
  851. Procedure getintvec(intno : byte;var vector : pointer);
  852. Begin
  853. End;
  854. Procedure setintvec(intno : byte;vector : pointer);
  855. Begin
  856. End;
  857. end.
  858. {
  859. $Log$
  860. Revision 1.3 1999-01-22 15:44:59 pierre
  861. Daniel change removed : broke make cycle !!
  862. Revision 1.2 1999/01/22 10:07:03 daniel
  863. - Findclose removed: This is TP incompatible!!
  864. Revision 1.1 1998/12/21 13:07:02 peter
  865. * use -FE
  866. Revision 1.19 1998/11/23 13:53:59 peter
  867. * more fexpand fixes from marco van de voort
  868. Revision 1.18 1998/11/23 12:48:02 peter
  869. * fexpand('o:') fixed to return o:\ (from the mailinglist)
  870. Revision 1.17 1998/11/22 09:33:21 florian
  871. * fexpand bug (temp. strings were too shoort) fixed, was reported
  872. by Marco van de Voort
  873. Revision 1.16 1998/11/17 09:37:41 pierre
  874. * explicit conversion from word dosreg.ax to integer doserror
  875. Revision 1.15 1998/11/01 20:27:18 peter
  876. * fixed some doserror settings
  877. Revision 1.14 1998/10/22 15:05:28 pierre
  878. * fsplit adapted to long filenames
  879. Revision 1.13 1998/09/16 16:47:24 peter
  880. * merged fixes
  881. Revision 1.11.2.2 1998/09/16 16:16:04 peter
  882. * go32v1 compiles again
  883. Revision 1.12 1998/09/11 12:46:44 pierre
  884. * range check problem with LFN attr removed
  885. Revision 1.11.2.1 1998/09/11 12:38:41 pierre
  886. * conversion from LFN attr to Dos attr did not respect range checking
  887. Revision 1.11 1998/08/28 10:45:58 peter
  888. * fixed path buffer in findfirst
  889. Revision 1.10 1998/08/27 10:30:48 pierre
  890. * go32v1 RTL did not compile (LFNsupport outside go32v2 defines !)
  891. I renamed tb_selector to tb_segment because
  892. it is a real mode segment as opposed to
  893. a protected mode selector
  894. Fixed it for go32v1 (remove the $E0000000 offset !)
  895. Revision 1.9 1998/08/26 10:04:01 peter
  896. * new lfn check from mailinglist
  897. * renamed win95 -> LFNSupport
  898. + tb_selector, tb_offset for easier access to transferbuffer
  899. Revision 1.8 1998/08/16 20:39:49 peter
  900. + LFN Support
  901. Revision 1.7 1998/08/16 09:12:13 michael
  902. Corrected fexpand behaviour.
  903. Revision 1.6 1998/08/05 21:01:50 michael
  904. applied bugfix from maillist to fsearch
  905. Revision 1.5 1998/05/31 14:18:13 peter
  906. * force att or direct assembling
  907. * cleanup of some files
  908. Revision 1.4 1998/05/22 00:39:22 peter
  909. * go32v1, go32v2 recompiles with the new objects
  910. * remake3 works again with go32v2
  911. - removed some "optimizes" from daniel which were wrong
  912. Revision 1.3 1998/05/21 19:30:47 peter
  913. * objects compiles for linux
  914. + assign(pchar), assign(char), rename(pchar), rename(char)
  915. * fixed read_text_as_array
  916. + read_text_as_pchar which was not yet in the rtl
  917. }