dos.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  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. var
  124. r : registers;
  125. begin
  126. if (dosregs.flags and carryflag) <> 0 then
  127. begin
  128. r.eax:=$5900;
  129. r.ebx:=$0;
  130. realintr($21,r);
  131. { conversion from word to integer !!
  132. gave a Bound check error if ax is $FFFF !! PM }
  133. doserror:=integer(r.ax);
  134. case doserror of
  135. 19 : DosError:=150;
  136. 21 : DosError:=152;
  137. end;
  138. end
  139. else
  140. doserror:=0;
  141. end;
  142. procedure intr(intno : byte;var regs : registers);
  143. begin
  144. realintr(intno,regs);
  145. end;
  146. procedure msdos(var regs : registers);
  147. begin
  148. intr($21,regs);
  149. end;
  150. {******************************************************************************
  151. --- Info / Date / Time ---
  152. ******************************************************************************}
  153. function dosversion : word;
  154. begin
  155. dosregs.ax:=$3000;
  156. msdos(dosregs);
  157. dosversion:=dosregs.ax;
  158. end;
  159. procedure getdate(var year,month,mday,wday : word);
  160. begin
  161. dosregs.ax:=$2a00;
  162. msdos(dosregs);
  163. wday:=dosregs.al;
  164. year:=dosregs.cx;
  165. month:=dosregs.dh;
  166. mday:=dosregs.dl;
  167. end;
  168. procedure setdate(year,month,day : word);
  169. begin
  170. dosregs.cx:=year;
  171. dosregs.dh:=month;
  172. dosregs.dl:=day;
  173. dosregs.ah:=$2b;
  174. msdos(dosregs);
  175. DosError:=0;
  176. end;
  177. procedure gettime(var hour,minute,second,sec100 : word);
  178. begin
  179. dosregs.ah:=$2c;
  180. msdos(dosregs);
  181. hour:=dosregs.ch;
  182. minute:=dosregs.cl;
  183. second:=dosregs.dh;
  184. sec100:=dosregs.dl;
  185. DosError:=0;
  186. end;
  187. procedure settime(hour,minute,second,sec100 : word);
  188. begin
  189. dosregs.ch:=hour;
  190. dosregs.cl:=minute;
  191. dosregs.dh:=second;
  192. dosregs.dl:=sec100;
  193. dosregs.ah:=$2d;
  194. msdos(dosregs);
  195. DosError:=0;
  196. end;
  197. Procedure packtime(var t : datetime;var p : longint);
  198. Begin
  199. 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);
  200. End;
  201. Procedure unpacktime(p : longint;var t : datetime);
  202. Begin
  203. with t do
  204. begin
  205. sec:=(p and 31) shl 1;
  206. min:=(p shr 5) and 63;
  207. hour:=(p shr 11) and 31;
  208. day:=(p shr 16) and 31;
  209. month:=(p shr 21) and 15;
  210. year:=(p shr 25)+1980;
  211. end;
  212. End;
  213. {******************************************************************************
  214. --- Exec ---
  215. ******************************************************************************}
  216. var
  217. lastdosexitcode : word;
  218. procedure exec(const path : pathstr;const comline : comstr);
  219. type
  220. realptr = packed record
  221. ofs,seg : word;
  222. end;
  223. texecblock = packed record
  224. envseg : word;
  225. comtail : realptr;
  226. firstFCB : realptr;
  227. secondFCB : realptr;
  228. iniStack : realptr;
  229. iniCSIP : realptr;
  230. end;
  231. var
  232. current_dos_buffer_pos,
  233. arg_ofs,
  234. i,la_env,
  235. la_p,la_c,la_e,
  236. fcb1_la,fcb2_la : longint;
  237. execblock : texecblock;
  238. c,p : string;
  239. function paste_to_dos(src : string) : boolean;
  240. var
  241. c : array[0..255] of char;
  242. begin
  243. paste_to_dos:=false;
  244. if current_dos_buffer_pos+length(src)+1>transfer_buffer+tb_size then
  245. RunError(217);
  246. move(src[1],c[0],length(src));
  247. c[length(src)]:=#0;
  248. seg_move(get_ds,longint(@c),dosmemselector,current_dos_buffer_pos,length(src)+1);
  249. current_dos_buffer_pos:=current_dos_buffer_pos+length(src)+1;
  250. paste_to_dos:=true;
  251. end;
  252. begin
  253. { create command line }
  254. move(comline[0],c[1],length(comline)+1);
  255. c[length(comline)+2]:=#13;
  256. c[0]:=char(length(comline)+2);
  257. { create path }
  258. p:=path;
  259. for i:=1 to length(p) do
  260. if p[i]='/' then
  261. p[i]:='\';
  262. { create buffer }
  263. la_env:=transfer_buffer;
  264. while (la_env and 15)<>0 do
  265. inc(la_env);
  266. current_dos_buffer_pos:=la_env;
  267. { copy environment }
  268. for i:=1 to envcount do
  269. paste_to_dos(envstr(i));
  270. paste_to_dos(''); { adds a double zero at the end }
  271. { allow slash as backslash }
  272. la_p:=current_dos_buffer_pos;
  273. paste_to_dos(p);
  274. la_c:=current_dos_buffer_pos;
  275. paste_to_dos(c);
  276. la_e:=current_dos_buffer_pos;
  277. fcb1_la:=la_e;
  278. la_e:=la_e+16;
  279. fcb2_la:=la_e;
  280. la_e:=la_e+16;
  281. { allocate FCB see dosexec code }
  282. arg_ofs:=1;
  283. while (c[arg_ofs] in [' ',#9]) do
  284. inc(arg_ofs);
  285. dosregs.ax:=$2901;
  286. dosregs.ds:=(la_c+arg_ofs) shr 4;
  287. dosregs.esi:=(la_c+arg_ofs) and 15;
  288. dosregs.es:=fcb1_la shr 4;
  289. dosregs.edi:=fcb1_la and 15;
  290. msdos(dosregs);
  291. { allocate second FCB see dosexec code }
  292. repeat
  293. inc(arg_ofs);
  294. until (c[arg_ofs] in [' ',#9,#13]);
  295. if c[arg_ofs]<>#13 then
  296. begin
  297. repeat
  298. inc(arg_ofs);
  299. until not (c[arg_ofs] in [' ',#9]);
  300. end;
  301. dosregs.ax:=$2901;
  302. dosregs.ds:=(la_c+arg_ofs) shr 4;
  303. dosregs.si:=(la_c+arg_ofs) and 15;
  304. dosregs.es:=fcb2_la shr 4;
  305. dosregs.di:=fcb2_la and 15;
  306. msdos(dosregs);
  307. with execblock do
  308. begin
  309. envseg:=la_env shr 4;
  310. comtail.seg:=la_c shr 4;
  311. comtail.ofs:=la_c and 15;
  312. firstFCB.seg:=fcb1_la shr 4;
  313. firstFCB.ofs:=fcb1_la and 15;
  314. secondFCB.seg:=fcb2_la shr 4;
  315. secondFCB.ofs:=fcb2_la and 15;
  316. end;
  317. seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
  318. dosregs.edx:=la_p and 15;
  319. dosregs.ds:=la_p shr 4;
  320. dosregs.ebx:=la_e and 15;
  321. dosregs.es:=la_e shr 4;
  322. dosregs.ax:=$4b00;
  323. msdos(dosregs);
  324. LoadDosError;
  325. if DosError=0 then
  326. begin
  327. dosregs.ax:=$4d00;
  328. msdos(dosregs);
  329. LastDosExitCode:=DosRegs.al
  330. end
  331. else
  332. LastDosExitCode:=0;
  333. end;
  334. function dosexitcode : word;
  335. begin
  336. dosexitcode:=lastdosexitcode;
  337. end;
  338. procedure getcbreak(var breakvalue : boolean);
  339. begin
  340. DosError:=0;
  341. dosregs.ax:=$3300;
  342. msdos(dosregs);
  343. breakvalue:=dosregs.dl<>0;
  344. end;
  345. procedure setcbreak(breakvalue : boolean);
  346. begin
  347. DosError:=0;
  348. dosregs.ax:=$3301;
  349. dosregs.dl:=ord(breakvalue);
  350. msdos(dosregs);
  351. end;
  352. procedure getverify(var verify : boolean);
  353. begin
  354. DosError:=0;
  355. dosregs.ah:=$54;
  356. msdos(dosregs);
  357. verify:=dosregs.al<>0;
  358. end;
  359. procedure setverify(verify : boolean);
  360. begin
  361. DosError:=0;
  362. dosregs.ah:=$2e;
  363. dosregs.al:=ord(verify);
  364. msdos(dosregs);
  365. end;
  366. {******************************************************************************
  367. --- Disk ---
  368. ******************************************************************************}
  369. function diskfree(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. diskfree:=dosregs.ax*dosregs.bx*dosregs.cx
  377. else
  378. diskfree:=-1;
  379. end;
  380. function disksize(drive : byte) : longint;
  381. begin
  382. DosError:=0;
  383. dosregs.dl:=drive;
  384. dosregs.ah:=$36;
  385. msdos(dosregs);
  386. if dosregs.ax<>$FFFF then
  387. disksize:=dosregs.ax*dosregs.cx*dosregs.dx
  388. else
  389. disksize:=-1;
  390. end;
  391. {******************************************************************************
  392. --- LFNFindfirst LFNFindNext ---
  393. ******************************************************************************}
  394. type
  395. LFNSearchRec=packed record
  396. attr,
  397. crtime,
  398. crtimehi,
  399. actime,
  400. actimehi,
  401. lmtime,
  402. lmtimehi,
  403. sizehi,
  404. size : longint;
  405. reserved : array[0..7] of byte;
  406. name : array[0..259] of byte;
  407. shortname : array[0..13] of byte;
  408. end;
  409. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec);
  410. var
  411. Len : longint;
  412. begin
  413. With w do
  414. begin
  415. FillChar(d,sizeof(SearchRec),0);
  416. if DosError=0 then
  417. len:=StrLen(@Name)
  418. else
  419. len:=0;
  420. d.Name[0]:=chr(len);
  421. Move(Name[0],d.Name[1],Len);
  422. d.Time:=lmTime;
  423. d.Size:=Size;
  424. d.Attr:=Attr and $FF;
  425. Move(hdl,d.Fill,4);
  426. end;
  427. end;
  428. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  429. var
  430. i : longint;
  431. w : LFNSearchRec;
  432. begin
  433. { allow slash as backslash }
  434. for i:=0 to strlen(path) do
  435. if path[i]='/' then path[i]:='\';
  436. dosregs.si:=1; { use ms-dos time }
  437. { don't include the label if not asked for it, needed for network drives }
  438. if attr=$8 then
  439. dosregs.ecx:=8
  440. else
  441. dosregs.ecx:=attr and (not 8);
  442. dosregs.edx:=tb_offset+Sizeof(LFNSearchrec)+1;
  443. dosmemput(tb_segment,tb_offset+Sizeof(LFNSearchrec)+1,path^,strlen(path)+1);
  444. dosregs.ds:=tb_segment;
  445. dosregs.edi:=tb_offset;
  446. dosregs.es:=tb_segment;
  447. dosregs.ax:=$714e;
  448. msdos(dosregs);
  449. LoadDosError;
  450. copyfromdos(w,sizeof(LFNSearchRec));
  451. LFNSearchRec2Dos(w,dosregs.ax,s);
  452. end;
  453. procedure LFNFindNext(var s:searchrec);
  454. var
  455. hdl : longint;
  456. w : LFNSearchRec;
  457. begin
  458. Move(s.Fill,hdl,4);
  459. dosregs.si:=1; { use ms-dos time }
  460. dosregs.edi:=tb_offset;
  461. dosregs.es:=tb_segment;
  462. dosregs.ebx:=hdl;
  463. dosregs.ax:=$714f;
  464. msdos(dosregs);
  465. LoadDosError;
  466. copyfromdos(w,sizeof(LFNSearchRec));
  467. LFNSearchRec2Dos(w,hdl,s);
  468. end;
  469. procedure LFNFindClose(var s:searchrec);
  470. var
  471. hdl : longint;
  472. begin
  473. Move(s.Fill,hdl,4);
  474. dosregs.ebx:=hdl;
  475. dosregs.ax:=$71a1;
  476. msdos(dosregs);
  477. LoadDosError;
  478. end;
  479. {******************************************************************************
  480. --- DosFindfirst DosFindNext ---
  481. ******************************************************************************}
  482. procedure dossearchrec2searchrec(var f : searchrec);
  483. var
  484. len : longint;
  485. begin
  486. len:=StrLen(@f.Name);
  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..256] 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. DosError:=0;
  562. if _exception_exit<>nil then
  563. if _v2prt0_exceptions_on then
  564. _swap_in()
  565. else
  566. _swap_out();
  567. (* asm
  568. { uses four global symbols from v2prt0.as to be able to know the current
  569. exception state without using dpmiexcp unit }
  570. movl _exception_exit,%eax
  571. orl %eax,%eax
  572. je .Lno_excep
  573. movl _v2prt0_exceptions_on,%eax
  574. orl %eax,%eax
  575. je .Lexceptions_off
  576. call *_swap_out
  577. jmp .Lno_excep
  578. .Lexceptions_off:
  579. call *_swap_in
  580. .Lno_excep:
  581. end; *)
  582. end;
  583. {******************************************************************************
  584. --- File ---
  585. ******************************************************************************}
  586. procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;var ext : extstr);
  587. var
  588. dotpos,p1,i : longint;
  589. begin
  590. { allow slash as backslash }
  591. for i:=1 to length(path) do
  592. if path[i]='/' then path[i]:='\';
  593. { get drive name }
  594. p1:=pos(':',path);
  595. if p1>0 then
  596. begin
  597. dir:=path[1]+':';
  598. delete(path,1,p1);
  599. end
  600. else
  601. dir:='';
  602. { split the path and the name, there are no more path informtions }
  603. { if path contains no backslashes }
  604. while true do
  605. begin
  606. p1:=pos('\',path);
  607. if p1=0 then
  608. break;
  609. dir:=dir+copy(path,1,p1);
  610. delete(path,1,p1);
  611. end;
  612. { try to find out a extension }
  613. if LFNSupport then
  614. begin
  615. Ext:='';
  616. i:=Length(Path);
  617. DotPos:=256;
  618. While (i>0) Do
  619. Begin
  620. If (Path[i]='.') Then
  621. begin
  622. DotPos:=i;
  623. break;
  624. end;
  625. Dec(i);
  626. end;
  627. Ext:=Copy(Path,DotPos,255);
  628. Name:=Copy(Path,1,DotPos - 1);
  629. end
  630. else
  631. begin
  632. p1:=pos('.',path);
  633. if p1>0 then
  634. begin
  635. ext:=copy(path,p1,4);
  636. delete(path,p1,length(path)-p1+1);
  637. end
  638. else
  639. ext:='';
  640. name:=path;
  641. end;
  642. end;
  643. function fexpand(const path : pathstr) : pathstr;
  644. var
  645. s,pa : pathstr;
  646. i,j : longint;
  647. begin
  648. getdir(0,s);
  649. i:=ioresult;
  650. if LFNSupport then
  651. begin
  652. pa:=path;
  653. end
  654. else
  655. if FileNameCaseSensitive then
  656. pa:=path
  657. else
  658. pa:=upcase(path);
  659. { allow slash as backslash }
  660. for i:=1 to length(pa) do
  661. if pa[i]='/' then
  662. pa[i]:='\';
  663. if (length(pa)>1) and (pa[2]=':') and (pa[1] in ['A'..'Z','a'..'z']) then
  664. begin
  665. { Always uppercase driveletter }
  666. if (pa[1] in ['a'..'z']) then
  667. pa[1]:=Chr(Ord(Pa[1])-32);
  668. { we must get the right directory }
  669. getdir(ord(pa[1])-ord('A')+1,s);
  670. i:=ioresult;
  671. if (ord(pa[0])>2) and (pa[3]<>'\') then
  672. if pa[1]=s[1] then
  673. begin
  674. { remove ending slash if it already exists }
  675. if s[length(s)]='\' then
  676. dec(s[0]);
  677. pa:=s+'\'+copy (pa,3,length(pa));
  678. end
  679. else
  680. pa:=pa[1]+':\'+copy (pa,3,length(pa))
  681. end
  682. else
  683. if pa[1]='\' then
  684. pa:=s[1]+':'+pa
  685. else if s[0]=#3 then
  686. pa:=s+pa
  687. else
  688. pa:=s+'\'+pa;
  689. { Turbo Pascal gives current dir on drive if only drive given as parameter! }
  690. if length(pa) = 2 then
  691. begin
  692. getdir(byte(pa[1])-64,s);
  693. pa := s;
  694. end;
  695. {First remove all references to '\.\'}
  696. while pos ('\.\',pa)<>0 do
  697. delete (pa,pos('\.\',pa),2);
  698. {Now remove also all references to '\..\' + of course previous dirs..}
  699. repeat
  700. i:=pos('\..\',pa);
  701. if i<>0 then
  702. begin
  703. j:=i-1;
  704. while (j>1) and (pa[j]<>'\') do
  705. dec (j);
  706. if pa[j+1] = ':' then j := 3;
  707. delete (pa,j,i-j+3);
  708. end;
  709. until i=0;
  710. { Turbo Pascal gets rid of a \.. at the end of the path }
  711. { Now remove also any reference to '\..' at end of line
  712. + of course previous dir.. }
  713. i:=pos('\..',pa);
  714. if i<>0 then
  715. begin
  716. if i = length(pa) - 2 then
  717. begin
  718. j:=i-1;
  719. while (j>1) and (pa[j]<>'\') do
  720. dec (j);
  721. delete (pa,j,i-j+3);
  722. end;
  723. pa := pa + '\';
  724. end;
  725. { Remove End . and \}
  726. if (length(pa)>0) and (pa[length(pa)]='.') then
  727. dec(byte(pa[0]));
  728. { if only the drive + a '\' is left then the '\' should be left to prevtn the program
  729. accessing the current directory on the drive rather than the root!}
  730. { if the last char of path = '\' then leave it in as this is what TP does! }
  731. if ((length(pa)>3) and (pa[length(pa)]='\')) and (path[length(path)] <> '\') then
  732. dec(byte(pa[0]));
  733. { if only a drive is given in path then there should be a '\' at the
  734. end of the string given back }
  735. if length(pa) = 2 then pa := pa + '\';
  736. fexpand:=pa;
  737. end;
  738. Function FSearch(path: pathstr; dirlist: string): pathstr;
  739. var
  740. i,p1 : longint;
  741. s : searchrec;
  742. newdir : pathstr;
  743. begin
  744. { check if the file specified exists }
  745. findfirst(path,anyfile,s);
  746. if doserror=0 then
  747. begin
  748. findclose(s);
  749. fsearch:=path;
  750. exit;
  751. end;
  752. { No wildcards allowed in these things }
  753. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  754. fsearch:=''
  755. else
  756. begin
  757. { allow slash as backslash }
  758. for i:=1 to length(dirlist) do
  759. if dirlist[i]='/' then dirlist[i]:='\';
  760. repeat
  761. p1:=pos(';',dirlist);
  762. if p1<>0 then
  763. begin
  764. newdir:=copy(dirlist,1,p1-1);
  765. delete(dirlist,1,p1);
  766. end
  767. else
  768. begin
  769. newdir:=dirlist;
  770. dirlist:='';
  771. end;
  772. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  773. newdir:=newdir+'\';
  774. findfirst(newdir+path,anyfile,s);
  775. if doserror=0 then
  776. newdir:=newdir+path
  777. else
  778. newdir:='';
  779. until (dirlist='') or (newdir<>'');
  780. fsearch:=newdir;
  781. end;
  782. findclose(s);
  783. end;
  784. {******************************************************************************
  785. --- Get/Set File Time,Attr ---
  786. ******************************************************************************}
  787. procedure getftime(var f;var time : longint);
  788. begin
  789. dosregs.bx:=textrec(f).handle;
  790. dosregs.ax:=$5700;
  791. msdos(dosregs);
  792. loaddoserror;
  793. time:=(dosregs.dx shl 16)+dosregs.cx;
  794. end;
  795. procedure setftime(var f;time : longint);
  796. begin
  797. dosregs.bx:=textrec(f).handle;
  798. dosregs.cx:=time and $ffff;
  799. dosregs.dx:=time shr 16;
  800. dosregs.ax:=$5701;
  801. msdos(dosregs);
  802. loaddoserror;
  803. end;
  804. procedure getfattr(var f;var attr : word);
  805. begin
  806. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  807. dosregs.edx:=tb_offset;
  808. dosregs.ds:=tb_segment;
  809. if LFNSupport then
  810. begin
  811. dosregs.ax:=$7143;
  812. dosregs.bx:=0;
  813. end
  814. else
  815. dosregs.ax:=$4300;
  816. msdos(dosregs);
  817. LoadDosError;
  818. Attr:=dosregs.cx;
  819. end;
  820. procedure setfattr(var f;attr : word);
  821. begin
  822. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  823. dosregs.edx:=tb_offset;
  824. dosregs.ds:=tb_segment;
  825. if LFNSupport then
  826. begin
  827. dosregs.ax:=$7143;
  828. dosregs.bx:=1;
  829. end
  830. else
  831. dosregs.ax:=$4301;
  832. dosregs.cx:=attr;
  833. msdos(dosregs);
  834. LoadDosError;
  835. end;
  836. {******************************************************************************
  837. --- Environment ---
  838. ******************************************************************************}
  839. function envcount : longint;
  840. var
  841. hp : ppchar;
  842. begin
  843. hp:=envp;
  844. envcount:=0;
  845. while assigned(hp^) do
  846. begin
  847. inc(envcount);
  848. inc(hp);
  849. end;
  850. end;
  851. function envstr(index : integer) : string;
  852. begin
  853. if (index<=0) or (index>envcount) then
  854. begin
  855. envstr:='';
  856. exit;
  857. end;
  858. envstr:=strpas(ppchar(pointer(envp)+4*(index-1))^);
  859. end;
  860. Function GetEnv(envvar: string): string;
  861. var
  862. hp : ppchar;
  863. hs : string;
  864. eqpos : longint;
  865. begin
  866. envvar:=upcase(envvar);
  867. hp:=envp;
  868. getenv:='';
  869. while assigned(hp^) do
  870. begin
  871. hs:=strpas(hp^);
  872. eqpos:=pos('=',hs);
  873. if copy(hs,1,eqpos-1)=envvar then
  874. begin
  875. getenv:=copy(hs,eqpos+1,255);
  876. exit;
  877. end;
  878. inc(hp);
  879. end;
  880. end;
  881. {******************************************************************************
  882. --- Not Supported ---
  883. ******************************************************************************}
  884. Procedure keep(exitcode : word);
  885. Begin
  886. End;
  887. Procedure getintvec(intno : byte;var vector : pointer);
  888. Begin
  889. End;
  890. Procedure setintvec(intno : byte;vector : pointer);
  891. Begin
  892. End;
  893. end.
  894. {
  895. $Log$
  896. Revision 1.13 1999-11-06 14:38:23 peter
  897. * truncated log
  898. Revision 1.12 1999/09/10 17:14:09 peter
  899. * better errorcode returning using int21h,5900
  900. Revision 1.11 1999/09/08 18:55:49 peter
  901. * pointer fixes
  902. Revision 1.10 1999/08/13 21:23:15 peter
  903. * fsearch checks first if the specified file exists and returns that
  904. if it was found
  905. Revision 1.9 1999/05/16 17:08:58 peter
  906. * fixed driveletter checking
  907. Revision 1.8 1999/05/08 19:47:22 peter
  908. * check ioresult after getdir calls
  909. Revision 1.7 1999/05/04 23:55:50 pierre
  910. * unneeded assembler code converted to pascal
  911. Revision 1.6 1999/04/28 11:42:44 peter
  912. + FileNameCaseSensetive boolean
  913. Revision 1.5 1999/04/02 00:01:29 peter
  914. * fixed LFNFindfirst on network drives
  915. Revision 1.4 1999/03/01 15:40:48 peter
  916. * use external names
  917. * removed all direct assembler modes
  918. Revision 1.3 1999/01/22 15:44:59 pierre
  919. Daniel change removed : broke make cycle !!
  920. Revision 1.2 1999/01/22 10:07:03 daniel
  921. - Findclose removed: This is TP incompatible!!
  922. Revision 1.1 1998/12/21 13:07:02 peter
  923. * use -FE
  924. Revision 1.19 1998/11/23 13:53:59 peter
  925. * more fexpand fixes from marco van de voort
  926. Revision 1.18 1998/11/23 12:48:02 peter
  927. * fexpand('o:') fixed to return o:\ (from the mailinglist)
  928. Revision 1.17 1998/11/22 09:33:21 florian
  929. * fexpand bug (temp. strings were too shoort) fixed, was reported
  930. by Marco van de Voort
  931. Revision 1.16 1998/11/17 09:37:41 pierre
  932. * explicit conversion from word dosreg.ax to integer doserror
  933. Revision 1.15 1998/11/01 20:27:18 peter
  934. * fixed some doserror settings
  935. Revision 1.14 1998/10/22 15:05:28 pierre
  936. * fsplit adapted to long filenames
  937. Revision 1.13 1998/09/16 16:47:24 peter
  938. * merged fixes
  939. Revision 1.11.2.2 1998/09/16 16:16:04 peter
  940. * go32v1 compiles again
  941. }