dos.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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. { don't include the label if not asked for it, needed for network drives }
  427. if attr=$8 then
  428. dosregs.ecx:=8
  429. else
  430. dosregs.ecx:=attr and (not 8);
  431. dosregs.edx:=tb_offset+Sizeof(LFNSearchrec)+1;
  432. dosmemput(tb_segment,tb_offset+Sizeof(LFNSearchrec)+1,path^,strlen(path)+1);
  433. dosregs.ds:=tb_segment;
  434. dosregs.edi:=tb_offset;
  435. dosregs.es:=tb_segment;
  436. dosregs.ax:=$714e;
  437. msdos(dosregs);
  438. LoadDosError;
  439. copyfromdos(w,sizeof(LFNSearchRec));
  440. LFNSearchRec2Dos(w,dosregs.ax,s);
  441. end;
  442. procedure LFNFindNext(var s:searchrec);
  443. var
  444. hdl : longint;
  445. w : LFNSearchRec;
  446. begin
  447. Move(s.Fill,hdl,4);
  448. dosregs.si:=1; { use ms-dos time }
  449. dosregs.edi:=tb_offset;
  450. dosregs.es:=tb_segment;
  451. dosregs.ebx:=hdl;
  452. dosregs.ax:=$714f;
  453. msdos(dosregs);
  454. LoadDosError;
  455. copyfromdos(w,sizeof(LFNSearchRec));
  456. LFNSearchRec2Dos(w,hdl,s);
  457. end;
  458. procedure LFNFindClose(var s:searchrec);
  459. var
  460. hdl : longint;
  461. begin
  462. Move(s.Fill,hdl,4);
  463. dosregs.ebx:=hdl;
  464. dosregs.ax:=$71a1;
  465. msdos(dosregs);
  466. LoadDosError;
  467. end;
  468. {******************************************************************************
  469. --- DosFindfirst DosFindNext ---
  470. ******************************************************************************}
  471. procedure dossearchrec2searchrec(var f : searchrec);
  472. var
  473. len : longint;
  474. begin
  475. len:=StrLen(@f.Name);
  476. Move(f.Name[0],f.Name[1],Len);
  477. f.Name[0]:=chr(len);
  478. end;
  479. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  480. var
  481. i : longint;
  482. begin
  483. { allow slash as backslash }
  484. for i:=0 to strlen(path) do
  485. if path[i]='/' then path[i]:='\';
  486. copytodos(f,sizeof(searchrec));
  487. dosregs.edx:=tb_offset;
  488. dosregs.ds:=tb_segment;
  489. dosregs.ah:=$1a;
  490. msdos(dosregs);
  491. dosregs.ecx:=attr;
  492. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  493. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  494. dosregs.ds:=tb_segment;
  495. dosregs.ah:=$4e;
  496. msdos(dosregs);
  497. copyfromdos(f,sizeof(searchrec));
  498. LoadDosError;
  499. dossearchrec2searchrec(f);
  500. end;
  501. procedure Dosfindnext(var f : searchrec);
  502. begin
  503. copytodos(f,sizeof(searchrec));
  504. dosregs.edx:=tb_offset;
  505. dosregs.ds:=tb_segment;
  506. dosregs.ah:=$1a;
  507. msdos(dosregs);
  508. dosregs.ah:=$4f;
  509. msdos(dosregs);
  510. copyfromdos(f,sizeof(searchrec));
  511. LoadDosError;
  512. dossearchrec2searchrec(f);
  513. end;
  514. {******************************************************************************
  515. --- Findfirst FindNext ---
  516. ******************************************************************************}
  517. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  518. var
  519. path0 : array[0..256] of char;
  520. begin
  521. doserror:=0;
  522. strpcopy(path0,path);
  523. if LFNSupport then
  524. LFNFindFirst(path0,attr,f)
  525. else
  526. Dosfindfirst(path0,attr,f);
  527. end;
  528. procedure findnext(var f : searchRec);
  529. begin
  530. doserror:=0;
  531. if LFNSupport then
  532. LFNFindnext(f)
  533. else
  534. Dosfindnext(f);
  535. end;
  536. Procedure FindClose(Var f: SearchRec);
  537. begin
  538. DosError:=0;
  539. if LFNSupport then
  540. LFNFindClose(f);
  541. end;
  542. type swap_proc = procedure;
  543. var
  544. _swap_in : swap_proc;external name '_swap_in';
  545. _swap_out : swap_proc;external name '_swap_out';
  546. _exception_exit : pointer;external name '_exception_exit';
  547. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  548. procedure swapvectors;
  549. begin
  550. DosError:=0;
  551. if _exception_exit<>nil then
  552. if _v2prt0_exceptions_on then
  553. _swap_in()
  554. else
  555. _swap_out();
  556. (* asm
  557. { uses four global symbols from v2prt0.as to be able to know the current
  558. exception state without using dpmiexcp unit }
  559. movl _exception_exit,%eax
  560. orl %eax,%eax
  561. je .Lno_excep
  562. movl _v2prt0_exceptions_on,%eax
  563. orl %eax,%eax
  564. je .Lexceptions_off
  565. call *_swap_out
  566. jmp .Lno_excep
  567. .Lexceptions_off:
  568. call *_swap_in
  569. .Lno_excep:
  570. end; *)
  571. end;
  572. {******************************************************************************
  573. --- File ---
  574. ******************************************************************************}
  575. procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;var ext : extstr);
  576. var
  577. dotpos,p1,i : longint;
  578. begin
  579. { allow slash as backslash }
  580. for i:=1 to length(path) do
  581. if path[i]='/' then path[i]:='\';
  582. { get drive name }
  583. p1:=pos(':',path);
  584. if p1>0 then
  585. begin
  586. dir:=path[1]+':';
  587. delete(path,1,p1);
  588. end
  589. else
  590. dir:='';
  591. { split the path and the name, there are no more path informtions }
  592. { if path contains no backslashes }
  593. while true do
  594. begin
  595. p1:=pos('\',path);
  596. if p1=0 then
  597. break;
  598. dir:=dir+copy(path,1,p1);
  599. delete(path,1,p1);
  600. end;
  601. { try to find out a extension }
  602. if LFNSupport then
  603. begin
  604. Ext:='';
  605. i:=Length(Path);
  606. DotPos:=256;
  607. While (i>0) Do
  608. Begin
  609. If (Path[i]='.') Then
  610. begin
  611. DotPos:=i;
  612. break;
  613. end;
  614. Dec(i);
  615. end;
  616. Ext:=Copy(Path,DotPos,255);
  617. Name:=Copy(Path,1,DotPos - 1);
  618. end
  619. else
  620. begin
  621. p1:=pos('.',path);
  622. if p1>0 then
  623. begin
  624. ext:=copy(path,p1,4);
  625. delete(path,p1,length(path)-p1+1);
  626. end
  627. else
  628. ext:='';
  629. name:=path;
  630. end;
  631. end;
  632. function fexpand(const path : pathstr) : pathstr;
  633. var
  634. s,pa : pathstr;
  635. i,j : longint;
  636. begin
  637. getdir(0,s);
  638. i:=ioresult;
  639. if LFNSupport then
  640. begin
  641. pa:=path;
  642. end
  643. else
  644. if FileNameCaseSensitive then
  645. pa:=path
  646. else
  647. pa:=upcase(path);
  648. { allow slash as backslash }
  649. for i:=1 to length(pa) do
  650. if pa[i]='/' then
  651. pa[i]:='\';
  652. if (length(pa)>1) and (pa[2]=':') and (pa[1] in ['A'..'Z','a'..'z']) then
  653. begin
  654. { Always uppercase driveletter }
  655. if (pa[1] in ['a'..'z']) then
  656. pa[1]:=Chr(Ord(Pa[1])-32);
  657. { we must get the right directory }
  658. getdir(ord(pa[1])-ord('A')+1,s);
  659. i:=ioresult;
  660. if (ord(pa[0])>2) and (pa[3]<>'\') then
  661. if pa[1]=s[1] then
  662. begin
  663. { remove ending slash if it already exists }
  664. if s[length(s)]='\' then
  665. dec(s[0]);
  666. pa:=s+'\'+copy (pa,3,length(pa));
  667. end
  668. else
  669. pa:=pa[1]+':\'+copy (pa,3,length(pa))
  670. end
  671. else
  672. if pa[1]='\' then
  673. pa:=s[1]+':'+pa
  674. else if s[0]=#3 then
  675. pa:=s+pa
  676. else
  677. pa:=s+'\'+pa;
  678. { Turbo Pascal gives current dir on drive if only drive given as parameter! }
  679. if length(pa) = 2 then
  680. begin
  681. getdir(byte(pa[1])-64,s);
  682. pa := s;
  683. end;
  684. {First remove all references to '\.\'}
  685. while pos ('\.\',pa)<>0 do
  686. delete (pa,pos('\.\',pa),2);
  687. {Now remove also all references to '\..\' + of course previous dirs..}
  688. repeat
  689. i:=pos('\..\',pa);
  690. if i<>0 then
  691. begin
  692. j:=i-1;
  693. while (j>1) and (pa[j]<>'\') do
  694. dec (j);
  695. if pa[j+1] = ':' then j := 3;
  696. delete (pa,j,i-j+3);
  697. end;
  698. until i=0;
  699. { Turbo Pascal gets rid of a \.. at the end of the path }
  700. { Now remove also any reference to '\..' at end of line
  701. + of course previous dir.. }
  702. i:=pos('\..',pa);
  703. if i<>0 then
  704. begin
  705. if i = length(pa) - 2 then
  706. begin
  707. j:=i-1;
  708. while (j>1) and (pa[j]<>'\') do
  709. dec (j);
  710. delete (pa,j,i-j+3);
  711. end;
  712. pa := pa + '\';
  713. end;
  714. { Remove End . and \}
  715. if (length(pa)>0) and (pa[length(pa)]='.') then
  716. dec(byte(pa[0]));
  717. { if only the drive + a '\' is left then the '\' should be left to prevtn the program
  718. accessing the current directory on the drive rather than the root!}
  719. { if the last char of path = '\' then leave it in as this is what TP does! }
  720. if ((length(pa)>3) and (pa[length(pa)]='\')) and (path[length(path)] <> '\') then
  721. dec(byte(pa[0]));
  722. { if only a drive is given in path then there should be a '\' at the
  723. end of the string given back }
  724. if length(pa) = 2 then pa := pa + '\';
  725. fexpand:=pa;
  726. end;
  727. Function FSearch(path: pathstr; dirlist: string): pathstr;
  728. var
  729. i,p1 : longint;
  730. s : searchrec;
  731. newdir : pathstr;
  732. begin
  733. { check if the file specified exists }
  734. findfirst(path,anyfile,s);
  735. if doserror=0 then
  736. begin
  737. findclose(s);
  738. fsearch:=path;
  739. exit;
  740. end;
  741. { No wildcards allowed in these things }
  742. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  743. fsearch:=''
  744. else
  745. begin
  746. { allow slash as backslash }
  747. for i:=1 to length(dirlist) do
  748. if dirlist[i]='/' then dirlist[i]:='\';
  749. repeat
  750. p1:=pos(';',dirlist);
  751. if p1<>0 then
  752. begin
  753. newdir:=copy(dirlist,1,p1-1);
  754. delete(dirlist,1,p1);
  755. end
  756. else
  757. begin
  758. newdir:=dirlist;
  759. dirlist:='';
  760. end;
  761. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  762. newdir:=newdir+'\';
  763. findfirst(newdir+path,anyfile,s);
  764. if doserror=0 then
  765. newdir:=newdir+path
  766. else
  767. newdir:='';
  768. until (dirlist='') or (newdir<>'');
  769. fsearch:=newdir;
  770. end;
  771. findclose(s);
  772. end;
  773. {******************************************************************************
  774. --- Get/Set File Time,Attr ---
  775. ******************************************************************************}
  776. procedure getftime(var f;var time : longint);
  777. begin
  778. dosregs.bx:=textrec(f).handle;
  779. dosregs.ax:=$5700;
  780. msdos(dosregs);
  781. loaddoserror;
  782. time:=(dosregs.dx shl 16)+dosregs.cx;
  783. end;
  784. procedure setftime(var f;time : longint);
  785. begin
  786. dosregs.bx:=textrec(f).handle;
  787. dosregs.cx:=time and $ffff;
  788. dosregs.dx:=time shr 16;
  789. dosregs.ax:=$5701;
  790. msdos(dosregs);
  791. loaddoserror;
  792. end;
  793. procedure getfattr(var f;var attr : word);
  794. begin
  795. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  796. dosregs.edx:=tb_offset;
  797. dosregs.ds:=tb_segment;
  798. if LFNSupport then
  799. begin
  800. dosregs.ax:=$7143;
  801. dosregs.bx:=0;
  802. end
  803. else
  804. dosregs.ax:=$4300;
  805. msdos(dosregs);
  806. LoadDosError;
  807. Attr:=dosregs.cx;
  808. end;
  809. procedure setfattr(var f;attr : word);
  810. begin
  811. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  812. dosregs.edx:=tb_offset;
  813. dosregs.ds:=tb_segment;
  814. if LFNSupport then
  815. begin
  816. dosregs.ax:=$7143;
  817. dosregs.bx:=1;
  818. end
  819. else
  820. dosregs.ax:=$4301;
  821. dosregs.cx:=attr;
  822. msdos(dosregs);
  823. LoadDosError;
  824. end;
  825. {******************************************************************************
  826. --- Environment ---
  827. ******************************************************************************}
  828. function envcount : longint;
  829. var
  830. hp : ppchar;
  831. begin
  832. hp:=envp;
  833. envcount:=0;
  834. while assigned(hp^) do
  835. begin
  836. inc(envcount);
  837. hp:=hp+4;
  838. end;
  839. end;
  840. function envstr(index : integer) : string;
  841. begin
  842. if (index<=0) or (index>envcount) then
  843. begin
  844. envstr:='';
  845. exit;
  846. end;
  847. envstr:=strpas(ppchar(envp+4*(index-1))^);
  848. end;
  849. Function GetEnv(envvar: string): string;
  850. var
  851. hp : ppchar;
  852. hs : string;
  853. eqpos : longint;
  854. begin
  855. envvar:=upcase(envvar);
  856. hp:=envp;
  857. getenv:='';
  858. while assigned(hp^) do
  859. begin
  860. hs:=strpas(hp^);
  861. eqpos:=pos('=',hs);
  862. if copy(hs,1,eqpos-1)=envvar then
  863. begin
  864. getenv:=copy(hs,eqpos+1,255);
  865. exit;
  866. end;
  867. hp:=hp+4;
  868. end;
  869. end;
  870. {******************************************************************************
  871. --- Not Supported ---
  872. ******************************************************************************}
  873. Procedure keep(exitcode : word);
  874. Begin
  875. End;
  876. Procedure getintvec(intno : byte;var vector : pointer);
  877. Begin
  878. End;
  879. Procedure setintvec(intno : byte;vector : pointer);
  880. Begin
  881. End;
  882. end.
  883. {
  884. $Log$
  885. Revision 1.10 1999-08-13 21:23:15 peter
  886. * fsearch checks first if the specified file exists and returns that
  887. if it was found
  888. Revision 1.9 1999/05/16 17:08:58 peter
  889. * fixed driveletter checking
  890. Revision 1.8 1999/05/08 19:47:22 peter
  891. * check ioresult after getdir calls
  892. Revision 1.7 1999/05/04 23:55:50 pierre
  893. * unneeded assembler code converted to pascal
  894. Revision 1.6 1999/04/28 11:42:44 peter
  895. + FileNameCaseSensetive boolean
  896. Revision 1.5 1999/04/02 00:01:29 peter
  897. * fixed LFNFindfirst on network drives
  898. Revision 1.4 1999/03/01 15:40:48 peter
  899. * use external names
  900. * removed all direct assembler modes
  901. Revision 1.3 1999/01/22 15:44:59 pierre
  902. Daniel change removed : broke make cycle !!
  903. Revision 1.2 1999/01/22 10:07:03 daniel
  904. - Findclose removed: This is TP incompatible!!
  905. Revision 1.1 1998/12/21 13:07:02 peter
  906. * use -FE
  907. Revision 1.19 1998/11/23 13:53:59 peter
  908. * more fexpand fixes from marco van de voort
  909. Revision 1.18 1998/11/23 12:48:02 peter
  910. * fexpand('o:') fixed to return o:\ (from the mailinglist)
  911. Revision 1.17 1998/11/22 09:33:21 florian
  912. * fexpand bug (temp. strings were too shoort) fixed, was reported
  913. by Marco van de Voort
  914. Revision 1.16 1998/11/17 09:37:41 pierre
  915. * explicit conversion from word dosreg.ax to integer doserror
  916. Revision 1.15 1998/11/01 20:27:18 peter
  917. * fixed some doserror settings
  918. Revision 1.14 1998/10/22 15:05:28 pierre
  919. * fsplit adapted to long filenames
  920. Revision 1.13 1998/09/16 16:47:24 peter
  921. * merged fixes
  922. Revision 1.11.2.2 1998/09/16 16:16:04 peter
  923. * go32v1 compiles again
  924. Revision 1.12 1998/09/11 12:46:44 pierre
  925. * range check problem with LFN attr removed
  926. Revision 1.11.2.1 1998/09/11 12:38:41 pierre
  927. * conversion from LFN attr to Dos attr did not respect range checking
  928. Revision 1.11 1998/08/28 10:45:58 peter
  929. * fixed path buffer in findfirst
  930. Revision 1.10 1998/08/27 10:30:48 pierre
  931. * go32v1 RTL did not compile (LFNsupport outside go32v2 defines !)
  932. I renamed tb_selector to tb_segment because
  933. it is a real mode segment as opposed to
  934. a protected mode selector
  935. Fixed it for go32v1 (remove the $E0000000 offset !)
  936. Revision 1.9 1998/08/26 10:04:01 peter
  937. * new lfn check from mailinglist
  938. * renamed win95 -> LFNSupport
  939. + tb_selector, tb_offset for easier access to transferbuffer
  940. Revision 1.8 1998/08/16 20:39:49 peter
  941. + LFN Support
  942. Revision 1.7 1998/08/16 09:12:13 michael
  943. Corrected fexpand behaviour.
  944. Revision 1.6 1998/08/05 21:01:50 michael
  945. applied bugfix from maillist to fsearch
  946. Revision 1.5 1998/05/31 14:18:13 peter
  947. * force att or direct assembling
  948. * cleanup of some files
  949. Revision 1.4 1998/05/22 00:39:22 peter
  950. * go32v1, go32v2 recompiles with the new objects
  951. * remake3 works again with go32v2
  952. - removed some "optimizes" from daniel which were wrong
  953. Revision 1.3 1998/05/21 19:30:47 peter
  954. * objects compiles for linux
  955. + assign(pchar), assign(char), rename(pchar), rename(char)
  956. * fixed read_text_as_array
  957. + read_text_as_pchar which was not yet in the rtl
  958. }