dos.pp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 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. {$ifdef Int64}
  87. Function DiskFree(drive: byte) : int64;
  88. Function DiskSize(drive: byte) : int64;
  89. {$else}
  90. Function DiskFree(drive: byte) : longint;
  91. Function DiskSize(drive: byte) : longint;
  92. {$endif}
  93. Procedure FindFirst(const path: pathstr; attr: word; var f: searchRec);
  94. Procedure FindNext(var f: searchRec);
  95. Procedure FindClose(Var f: SearchRec);
  96. {File}
  97. Procedure GetFAttr(var f; var attr: word);
  98. Procedure GetFTime(var f; var time: longint);
  99. Function FSearch(path: pathstr; dirlist: string): pathstr;
  100. Function FExpand(const path: pathstr): pathstr;
  101. Procedure FSplit(path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
  102. function GetShortName(var p : String) : boolean;
  103. {Environment}
  104. Function EnvCount: longint;
  105. Function EnvStr(index: integer): string;
  106. Function GetEnv(envvar: string): string;
  107. {Misc}
  108. Procedure SetFAttr(var f; attr: word);
  109. Procedure SetFTime(var f; time: longint);
  110. Procedure GetCBreak(var breakvalue: boolean);
  111. Procedure SetCBreak(breakvalue: boolean);
  112. Procedure GetVerify(var verify: boolean);
  113. Procedure SetVerify(verify: boolean);
  114. {Do Nothing Functions}
  115. Procedure SwapVectors;
  116. Procedure GetIntVec(intno: byte; var vector: pointer);
  117. Procedure SetIntVec(intno: byte; vector: pointer);
  118. Procedure Keep(exitcode: word);
  119. implementation
  120. uses
  121. strings;
  122. {$ASMMODE ATT}
  123. {******************************************************************************
  124. --- Dos Interrupt ---
  125. ******************************************************************************}
  126. var
  127. dosregs : registers;
  128. procedure LoadDosError;
  129. var
  130. r : registers;
  131. SimpleDosError : word;
  132. begin
  133. if (dosregs.flags and carryflag) <> 0 then
  134. begin
  135. { I got a extended error = 0
  136. while CarryFlag was set from Exec function }
  137. SimpleDosError:=dosregs.ax;
  138. r.eax:=$5900;
  139. r.ebx:=$0;
  140. realintr($21,r);
  141. { conversion from word to integer !!
  142. gave a Bound check error if ax is $FFFF !! PM }
  143. doserror:=integer(r.ax);
  144. case doserror of
  145. 0 : DosError:=integer(SimpleDosError);
  146. 19 : DosError:=150;
  147. 21 : DosError:=152;
  148. end;
  149. end
  150. else
  151. doserror:=0;
  152. end;
  153. procedure intr(intno : byte;var regs : registers);
  154. begin
  155. realintr(intno,regs);
  156. end;
  157. procedure msdos(var regs : registers);
  158. begin
  159. intr($21,regs);
  160. end;
  161. {******************************************************************************
  162. --- Info / Date / Time ---
  163. ******************************************************************************}
  164. function dosversion : word;
  165. begin
  166. dosregs.ax:=$3000;
  167. msdos(dosregs);
  168. dosversion:=dosregs.ax;
  169. end;
  170. procedure getdate(var year,month,mday,wday : word);
  171. begin
  172. dosregs.ax:=$2a00;
  173. msdos(dosregs);
  174. wday:=dosregs.al;
  175. year:=dosregs.cx;
  176. month:=dosregs.dh;
  177. mday:=dosregs.dl;
  178. end;
  179. procedure setdate(year,month,day : word);
  180. begin
  181. dosregs.cx:=year;
  182. dosregs.dh:=month;
  183. dosregs.dl:=day;
  184. dosregs.ah:=$2b;
  185. msdos(dosregs);
  186. DosError:=0;
  187. end;
  188. procedure gettime(var hour,minute,second,sec100 : word);
  189. begin
  190. dosregs.ah:=$2c;
  191. msdos(dosregs);
  192. hour:=dosregs.ch;
  193. minute:=dosregs.cl;
  194. second:=dosregs.dh;
  195. sec100:=dosregs.dl;
  196. DosError:=0;
  197. end;
  198. procedure settime(hour,minute,second,sec100 : word);
  199. begin
  200. dosregs.ch:=hour;
  201. dosregs.cl:=minute;
  202. dosregs.dh:=second;
  203. dosregs.dl:=sec100;
  204. dosregs.ah:=$2d;
  205. msdos(dosregs);
  206. DosError:=0;
  207. end;
  208. Procedure packtime(var t : datetime;var p : longint);
  209. Begin
  210. 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);
  211. End;
  212. Procedure unpacktime(p : longint;var t : datetime);
  213. Begin
  214. with t do
  215. begin
  216. sec:=(p and 31) shl 1;
  217. min:=(p shr 5) and 63;
  218. hour:=(p shr 11) and 31;
  219. day:=(p shr 16) and 31;
  220. month:=(p shr 21) and 15;
  221. year:=(p shr 25)+1980;
  222. end;
  223. End;
  224. {******************************************************************************
  225. --- Exec ---
  226. ******************************************************************************}
  227. var
  228. lastdosexitcode : word;
  229. procedure exec(const path : pathstr;const comline : comstr);
  230. type
  231. realptr = packed record
  232. ofs,seg : word;
  233. end;
  234. texecblock = packed record
  235. envseg : word;
  236. comtail : realptr;
  237. firstFCB : realptr;
  238. secondFCB : realptr;
  239. iniStack : realptr;
  240. iniCSIP : realptr;
  241. end;
  242. var
  243. current_dos_buffer_pos,
  244. arg_ofs,
  245. i,la_env,
  246. la_p,la_c,la_e,
  247. fcb1_la,fcb2_la : longint;
  248. execblock : texecblock;
  249. c,p : string;
  250. function paste_to_dos(src : string) : boolean;
  251. var
  252. c : array[0..255] of char;
  253. begin
  254. paste_to_dos:=false;
  255. if current_dos_buffer_pos+length(src)+1>transfer_buffer+tb_size then
  256. RunError(217);
  257. move(src[1],c[0],length(src));
  258. c[length(src)]:=#0;
  259. seg_move(get_ds,longint(@c),dosmemselector,current_dos_buffer_pos,length(src)+1);
  260. current_dos_buffer_pos:=current_dos_buffer_pos+length(src)+1;
  261. paste_to_dos:=true;
  262. end;
  263. begin
  264. { create command line }
  265. move(comline[0],c[1],length(comline)+1);
  266. c[length(comline)+2]:=#13;
  267. c[0]:=char(length(comline)+2);
  268. { create path }
  269. p:=path;
  270. for i:=1 to length(p) do
  271. if p[i]='/' then
  272. p[i]:='\';
  273. if LFNSupport then
  274. GetShortName(p);
  275. { create buffer }
  276. la_env:=transfer_buffer;
  277. while (la_env and 15)<>0 do
  278. inc(la_env);
  279. current_dos_buffer_pos:=la_env;
  280. { copy environment }
  281. for i:=1 to envcount do
  282. paste_to_dos(envstr(i));
  283. paste_to_dos(''); { adds a double zero at the end }
  284. { allow slash as backslash }
  285. la_p:=current_dos_buffer_pos;
  286. paste_to_dos(p);
  287. la_c:=current_dos_buffer_pos;
  288. paste_to_dos(c);
  289. la_e:=current_dos_buffer_pos;
  290. fcb1_la:=la_e;
  291. la_e:=la_e+16;
  292. fcb2_la:=la_e;
  293. la_e:=la_e+16;
  294. { allocate FCB see dosexec code }
  295. arg_ofs:=1;
  296. while (c[arg_ofs] in [' ',#9]) do
  297. inc(arg_ofs);
  298. dosregs.ax:=$2901;
  299. dosregs.ds:=(la_c+arg_ofs) shr 4;
  300. dosregs.esi:=(la_c+arg_ofs) and 15;
  301. dosregs.es:=fcb1_la shr 4;
  302. dosregs.edi:=fcb1_la and 15;
  303. msdos(dosregs);
  304. { allocate second FCB see dosexec code }
  305. repeat
  306. inc(arg_ofs);
  307. until (c[arg_ofs] in [' ',#9,#13]);
  308. if c[arg_ofs]<>#13 then
  309. begin
  310. repeat
  311. inc(arg_ofs);
  312. until not (c[arg_ofs] in [' ',#9]);
  313. end;
  314. dosregs.ax:=$2901;
  315. dosregs.ds:=(la_c+arg_ofs) shr 4;
  316. dosregs.si:=(la_c+arg_ofs) and 15;
  317. dosregs.es:=fcb2_la shr 4;
  318. dosregs.di:=fcb2_la and 15;
  319. msdos(dosregs);
  320. with execblock do
  321. begin
  322. envseg:=la_env shr 4;
  323. comtail.seg:=la_c shr 4;
  324. comtail.ofs:=la_c and 15;
  325. firstFCB.seg:=fcb1_la shr 4;
  326. firstFCB.ofs:=fcb1_la and 15;
  327. secondFCB.seg:=fcb2_la shr 4;
  328. secondFCB.ofs:=fcb2_la and 15;
  329. end;
  330. seg_move(get_ds,longint(@execblock),dosmemselector,la_e,sizeof(texecblock));
  331. dosregs.edx:=la_p and 15;
  332. dosregs.ds:=la_p shr 4;
  333. dosregs.ebx:=la_e and 15;
  334. dosregs.es:=la_e shr 4;
  335. dosregs.ax:=$4b00;
  336. msdos(dosregs);
  337. LoadDosError;
  338. if DosError=0 then
  339. begin
  340. dosregs.ax:=$4d00;
  341. msdos(dosregs);
  342. LastDosExitCode:=DosRegs.al
  343. end
  344. else
  345. LastDosExitCode:=0;
  346. end;
  347. function dosexitcode : word;
  348. begin
  349. dosexitcode:=lastdosexitcode;
  350. end;
  351. procedure getcbreak(var breakvalue : boolean);
  352. begin
  353. DosError:=0;
  354. dosregs.ax:=$3300;
  355. msdos(dosregs);
  356. breakvalue:=dosregs.dl<>0;
  357. end;
  358. procedure setcbreak(breakvalue : boolean);
  359. begin
  360. DosError:=0;
  361. dosregs.ax:=$3301;
  362. dosregs.dl:=ord(breakvalue);
  363. msdos(dosregs);
  364. end;
  365. procedure getverify(var verify : boolean);
  366. begin
  367. DosError:=0;
  368. dosregs.ah:=$54;
  369. msdos(dosregs);
  370. verify:=dosregs.al<>0;
  371. end;
  372. procedure setverify(verify : boolean);
  373. begin
  374. DosError:=0;
  375. dosregs.ah:=$2e;
  376. dosregs.al:=ord(verify);
  377. msdos(dosregs);
  378. end;
  379. {******************************************************************************
  380. --- Disk ---
  381. ******************************************************************************}
  382. {$ifdef Int64}
  383. TYPE ExtendedFat32FreeSpaceRec=packed Record
  384. RetSize : WORD; { (ret) size of returned structure}
  385. Strucversion : WORD; {(call) structure version (0000h)
  386. (ret) actual structure version (0000h)}
  387. SecPerClus, {number of sectors per cluster}
  388. BytePerSec, {number of bytes per sector}
  389. AvailClusters, {number of available clusters}
  390. TotalClusters, {total number of clusters on the drive}
  391. AvailPhysSect, {physical sectors available on the drive}
  392. TotalPhysSect, {total physical sectors on the drive}
  393. AvailAllocUnits, {Available allocation units}
  394. TotalAllocUnits : DWORD; {Total allocation units}
  395. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  396. END;
  397. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  398. VAR S : String;
  399. Rec : ExtendedFat32FreeSpaceRec;
  400. BEGIN
  401. if (swap(dosversion)>=$070A) AND LFNSupport then
  402. begin
  403. DosError:=0;
  404. S:='C:\'#0;
  405. if Drive=0 then
  406. begin
  407. GetDir(Drive,S);
  408. Setlength(S,4);
  409. S[4]:=#0;
  410. end
  411. else
  412. S[1]:=chr(Drive+64);
  413. Rec.Strucversion:=0;
  414. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  415. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  416. dosregs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  417. dosregs.ds:=tb_segment;
  418. dosregs.di:=tb_offset;
  419. dosregs.es:=tb_segment;
  420. dosregs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  421. dosregs.ax:=$7303;
  422. msdos(dosregs);
  423. LoadDosError;
  424. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  425. if Free then
  426. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  427. else
  428. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  429. if doserror<>0 THEN {No error clausule in int except cf}
  430. Do_DiskData:=-1;
  431. end
  432. else
  433. begin
  434. DosError:=0;
  435. dosregs.dl:=drive;
  436. dosregs.ah:=$36;
  437. msdos(dosregs);
  438. if dosregs.ax<>$FFFF then
  439. begin
  440. if Free then
  441. Do_DiskData:=dosregs.ax*dosregs.bx*dosregs.cx
  442. else
  443. Do_DiskData:=dosregs.ax*dosregs.cx*dosregs.dx;
  444. end
  445. else
  446. do_diskdata:=-1;
  447. end;
  448. end;
  449. function diskfree(drive : byte) : int64;
  450. begin
  451. diskfree:=Do_DiskData(drive,TRUE);
  452. end;
  453. function disksize(drive : byte) : int64;
  454. begin
  455. disksize:=Do_DiskData(drive,false);
  456. end;
  457. {$else}
  458. function diskfree(drive : byte) : longint;
  459. begin
  460. DosError:=0;
  461. dosregs.dl:=drive;
  462. dosregs.ah:=$36;
  463. msdos(dosregs);
  464. if dosregs.ax<>$FFFF then
  465. diskfree:=dosregs.ax*dosregs.bx*dosregs.cx
  466. else
  467. diskfree:=-1;
  468. end;
  469. function disksize(drive : byte) : longint;
  470. begin
  471. DosError:=0;
  472. dosregs.dl:=drive;
  473. dosregs.ah:=$36;
  474. msdos(dosregs);
  475. if dosregs.ax<>$FFFF then
  476. disksize:=dosregs.ax*dosregs.cx*dosregs.dx
  477. else
  478. disksize:=-1;
  479. end;
  480. {$endif}
  481. {******************************************************************************
  482. --- LFNFindfirst LFNFindNext ---
  483. ******************************************************************************}
  484. type
  485. LFNSearchRec=packed record
  486. attr,
  487. crtime,
  488. crtimehi,
  489. actime,
  490. actimehi,
  491. lmtime,
  492. lmtimehi,
  493. sizehi,
  494. size : longint;
  495. reserved : array[0..7] of byte;
  496. name : array[0..259] of byte;
  497. shortname : array[0..13] of byte;
  498. end;
  499. procedure LFNSearchRec2Dos(const w:LFNSearchRec;hdl:longint;var d:Searchrec);
  500. var
  501. Len : longint;
  502. begin
  503. With w do
  504. begin
  505. FillChar(d,sizeof(SearchRec),0);
  506. if DosError=0 then
  507. len:=StrLen(@Name)
  508. else
  509. len:=0;
  510. d.Name[0]:=chr(len);
  511. Move(Name[0],d.Name[1],Len);
  512. d.Time:=lmTime;
  513. d.Size:=Size;
  514. d.Attr:=Attr and $FF;
  515. Move(hdl,d.Fill,4);
  516. end;
  517. end;
  518. procedure LFNFindFirst(path:pchar;attr:longint;var s:searchrec);
  519. var
  520. i : longint;
  521. w : LFNSearchRec;
  522. begin
  523. { allow slash as backslash }
  524. for i:=0 to strlen(path) do
  525. if path[i]='/' then path[i]:='\';
  526. dosregs.si:=1; { use ms-dos time }
  527. { don't include the label if not asked for it, needed for network drives }
  528. if attr=$8 then
  529. dosregs.ecx:=8
  530. else
  531. dosregs.ecx:=attr and (not 8);
  532. dosregs.edx:=tb_offset+Sizeof(LFNSearchrec)+1;
  533. dosmemput(tb_segment,tb_offset+Sizeof(LFNSearchrec)+1,path^,strlen(path)+1);
  534. dosregs.ds:=tb_segment;
  535. dosregs.edi:=tb_offset;
  536. dosregs.es:=tb_segment;
  537. dosregs.ax:=$714e;
  538. msdos(dosregs);
  539. LoadDosError;
  540. copyfromdos(w,sizeof(LFNSearchRec));
  541. LFNSearchRec2Dos(w,dosregs.ax,s);
  542. end;
  543. procedure LFNFindNext(var s:searchrec);
  544. var
  545. hdl : longint;
  546. w : LFNSearchRec;
  547. begin
  548. Move(s.Fill,hdl,4);
  549. dosregs.si:=1; { use ms-dos time }
  550. dosregs.edi:=tb_offset;
  551. dosregs.es:=tb_segment;
  552. dosregs.ebx:=hdl;
  553. dosregs.ax:=$714f;
  554. msdos(dosregs);
  555. LoadDosError;
  556. copyfromdos(w,sizeof(LFNSearchRec));
  557. LFNSearchRec2Dos(w,hdl,s);
  558. end;
  559. procedure LFNFindClose(var s:searchrec);
  560. var
  561. hdl : longint;
  562. begin
  563. Move(s.Fill,hdl,4);
  564. dosregs.ebx:=hdl;
  565. dosregs.ax:=$71a1;
  566. msdos(dosregs);
  567. LoadDosError;
  568. end;
  569. {******************************************************************************
  570. --- DosFindfirst DosFindNext ---
  571. ******************************************************************************}
  572. procedure dossearchrec2searchrec(var f : searchrec);
  573. var
  574. len : longint;
  575. begin
  576. len:=StrLen(@f.Name);
  577. Move(f.Name[0],f.Name[1],Len);
  578. f.Name[0]:=chr(len);
  579. end;
  580. procedure DosFindfirst(path : pchar;attr : word;var f : searchrec);
  581. var
  582. i : longint;
  583. begin
  584. { allow slash as backslash }
  585. for i:=0 to strlen(path) do
  586. if path[i]='/' then path[i]:='\';
  587. copytodos(f,sizeof(searchrec));
  588. dosregs.edx:=tb_offset;
  589. dosregs.ds:=tb_segment;
  590. dosregs.ah:=$1a;
  591. msdos(dosregs);
  592. dosregs.ecx:=attr;
  593. dosregs.edx:=tb_offset+Sizeof(searchrec)+1;
  594. dosmemput(tb_segment,tb_offset+Sizeof(searchrec)+1,path^,strlen(path)+1);
  595. dosregs.ds:=tb_segment;
  596. dosregs.ah:=$4e;
  597. msdos(dosregs);
  598. copyfromdos(f,sizeof(searchrec));
  599. LoadDosError;
  600. dossearchrec2searchrec(f);
  601. end;
  602. procedure Dosfindnext(var f : searchrec);
  603. begin
  604. copytodos(f,sizeof(searchrec));
  605. dosregs.edx:=tb_offset;
  606. dosregs.ds:=tb_segment;
  607. dosregs.ah:=$1a;
  608. msdos(dosregs);
  609. dosregs.ah:=$4f;
  610. msdos(dosregs);
  611. copyfromdos(f,sizeof(searchrec));
  612. LoadDosError;
  613. dossearchrec2searchrec(f);
  614. end;
  615. {******************************************************************************
  616. --- Findfirst FindNext ---
  617. ******************************************************************************}
  618. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  619. var
  620. path0 : array[0..256] of char;
  621. begin
  622. doserror:=0;
  623. strpcopy(path0,path);
  624. if LFNSupport then
  625. LFNFindFirst(path0,attr,f)
  626. else
  627. Dosfindfirst(path0,attr,f);
  628. end;
  629. procedure findnext(var f : searchRec);
  630. begin
  631. doserror:=0;
  632. if LFNSupport then
  633. LFNFindnext(f)
  634. else
  635. Dosfindnext(f);
  636. end;
  637. Procedure FindClose(Var f: SearchRec);
  638. begin
  639. DosError:=0;
  640. if LFNSupport then
  641. LFNFindClose(f);
  642. end;
  643. type swap_proc = procedure;
  644. var
  645. _swap_in : swap_proc;external name '_swap_in';
  646. _swap_out : swap_proc;external name '_swap_out';
  647. _exception_exit : pointer;external name '_exception_exit';
  648. _v2prt0_exceptions_on : longbool;external name '_v2prt0_exceptions_on';
  649. procedure swapvectors;
  650. begin
  651. { DosError:=0; Who added this !!!!! }
  652. if _exception_exit<>nil then
  653. if _v2prt0_exceptions_on then
  654. _swap_in()
  655. else
  656. _swap_out();
  657. end;
  658. {******************************************************************************
  659. --- File ---
  660. ******************************************************************************}
  661. procedure fsplit(path : pathstr;var dir : dirstr;var name : namestr;var ext : extstr);
  662. var
  663. dotpos,p1,i : longint;
  664. begin
  665. { allow slash as backslash }
  666. for i:=1 to length(path) do
  667. if path[i]='/' then path[i]:='\';
  668. { get drive name }
  669. p1:=pos(':',path);
  670. if p1>0 then
  671. begin
  672. dir:=path[1]+':';
  673. delete(path,1,p1);
  674. end
  675. else
  676. dir:='';
  677. { split the path and the name, there are no more path informtions }
  678. { if path contains no backslashes }
  679. while true do
  680. begin
  681. p1:=pos('\',path);
  682. if p1=0 then
  683. break;
  684. dir:=dir+copy(path,1,p1);
  685. delete(path,1,p1);
  686. end;
  687. { try to find out a extension }
  688. if LFNSupport then
  689. begin
  690. Ext:='';
  691. i:=Length(Path);
  692. DotPos:=256;
  693. While (i>0) Do
  694. Begin
  695. If (Path[i]='.') Then
  696. begin
  697. DotPos:=i;
  698. break;
  699. end;
  700. Dec(i);
  701. end;
  702. Ext:=Copy(Path,DotPos,255);
  703. Name:=Copy(Path,1,DotPos - 1);
  704. end
  705. else
  706. begin
  707. p1:=pos('.',path);
  708. if p1>0 then
  709. begin
  710. ext:=copy(path,p1,4);
  711. delete(path,p1,length(path)-p1+1);
  712. end
  713. else
  714. ext:='';
  715. name:=path;
  716. end;
  717. end;
  718. function fexpand(const path : pathstr) : pathstr;
  719. var
  720. s,pa : pathstr;
  721. i,j : longint;
  722. begin
  723. getdir(0,s);
  724. i:=ioresult;
  725. if LFNSupport then
  726. begin
  727. pa:=path;
  728. end
  729. else
  730. if FileNameCaseSensitive then
  731. pa:=path
  732. else
  733. pa:=upcase(path);
  734. { allow slash as backslash }
  735. for i:=1 to length(pa) do
  736. if pa[i]='/' then
  737. pa[i]:='\';
  738. if (length(pa)>1) and (pa[2]=':') and (pa[1] in ['A'..'Z','a'..'z']) then
  739. begin
  740. { Always uppercase driveletter }
  741. if (pa[1] in ['a'..'z']) then
  742. pa[1]:=Chr(Ord(Pa[1])-32);
  743. { we must get the right directory }
  744. getdir(ord(pa[1])-ord('A')+1,s);
  745. i:=ioresult;
  746. if (ord(pa[0])>2) and (pa[3]<>'\') then
  747. if pa[1]=s[1] then
  748. begin
  749. { remove ending slash if it already exists }
  750. if s[length(s)]='\' then
  751. dec(s[0]);
  752. pa:=s+'\'+copy (pa,3,length(pa));
  753. end
  754. else
  755. pa:=pa[1]+':\'+copy (pa,3,length(pa))
  756. end
  757. else
  758. if pa[1]='\' then
  759. pa:=s[1]+':'+pa
  760. else if s[0]=#3 then
  761. pa:=s+pa
  762. else
  763. pa:=s+'\'+pa;
  764. { Turbo Pascal gives current dir on drive if only drive given as parameter! }
  765. if length(pa) = 2 then
  766. begin
  767. getdir(byte(pa[1])-64,s);
  768. pa := s;
  769. end;
  770. {First remove all references to '\.\'}
  771. while pos ('\.\',pa)<>0 do
  772. delete (pa,pos('\.\',pa),2);
  773. {Now remove also all references to '\..\' + of course previous dirs..}
  774. repeat
  775. i:=pos('\..\',pa);
  776. if i<>0 then
  777. begin
  778. j:=i-1;
  779. while (j>1) and (pa[j]<>'\') do
  780. dec (j);
  781. if pa[j+1] = ':' then j := 3;
  782. delete (pa,j,i-j+3);
  783. end;
  784. until i=0;
  785. { Turbo Pascal gets rid of a \.. at the end of the path }
  786. { Now remove also any reference to '\..' at end of line
  787. + of course previous dir.. }
  788. i:=pos('\..',pa);
  789. if i<>0 then
  790. begin
  791. if i = length(pa) - 2 then
  792. begin
  793. j:=i-1;
  794. while (j>1) and (pa[j]<>'\') do
  795. dec (j);
  796. delete (pa,j,i-j+3);
  797. end;
  798. pa := pa + '\';
  799. end;
  800. { Remove End . and \}
  801. if (length(pa)>0) and (pa[length(pa)]='.') then
  802. dec(byte(pa[0]));
  803. { if only the drive + a '\' is left then the '\' should be left to prevtn the program
  804. accessing the current directory on the drive rather than the root!}
  805. { if the last char of path = '\' then leave it in as this is what TP does! }
  806. if ((length(pa)>3) and (pa[length(pa)]='\')) and (path[length(path)] <> '\') then
  807. dec(byte(pa[0]));
  808. { if only a drive is given in path then there should be a '\' at the
  809. end of the string given back }
  810. if length(pa) = 2 then pa := pa + '\';
  811. fexpand:=pa;
  812. end;
  813. Function FSearch(path: pathstr; dirlist: string): pathstr;
  814. var
  815. i,p1 : longint;
  816. s : searchrec;
  817. newdir : pathstr;
  818. begin
  819. { check if the file specified exists }
  820. findfirst(path,anyfile,s);
  821. if doserror=0 then
  822. begin
  823. findclose(s);
  824. fsearch:=path;
  825. exit;
  826. end;
  827. { No wildcards allowed in these things }
  828. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  829. fsearch:=''
  830. else
  831. begin
  832. { allow slash as backslash }
  833. for i:=1 to length(dirlist) do
  834. if dirlist[i]='/' then dirlist[i]:='\';
  835. repeat
  836. p1:=pos(';',dirlist);
  837. if p1<>0 then
  838. begin
  839. newdir:=copy(dirlist,1,p1-1);
  840. delete(dirlist,1,p1);
  841. end
  842. else
  843. begin
  844. newdir:=dirlist;
  845. dirlist:='';
  846. end;
  847. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  848. newdir:=newdir+'\';
  849. findfirst(newdir+path,anyfile,s);
  850. if doserror=0 then
  851. newdir:=newdir+path
  852. else
  853. newdir:='';
  854. until (dirlist='') or (newdir<>'');
  855. fsearch:=newdir;
  856. end;
  857. findclose(s);
  858. end;
  859. { change to short filename if successful DOS call PM }
  860. function GetShortName(var p : String) : boolean;
  861. var
  862. c : array[0..255] of char;
  863. begin
  864. move(p[1],c[0],length(p));
  865. c[length(p)]:=#0;
  866. copytodos(@c,length(p)+1);
  867. dosregs.ax:=$7160;
  868. dosregs.cx:=1;
  869. dosregs.ds:=tb_segment;
  870. dosregs.si:=tb_offset;
  871. dosregs.es:=tb_segment;
  872. dosregs.di:=tb_offset;
  873. msdos(dosregs);
  874. LoadDosError;
  875. if DosError=0 then
  876. begin
  877. copyfromdos(@c,255);
  878. move(c[0],p[1],strlen(c));
  879. p[0]:=char(strlen(c));
  880. GetShortName:=true;
  881. end
  882. else
  883. GetShortName:=false;
  884. end;
  885. {******************************************************************************
  886. --- Get/Set File Time,Attr ---
  887. ******************************************************************************}
  888. procedure getftime(var f;var time : longint);
  889. begin
  890. dosregs.bx:=textrec(f).handle;
  891. dosregs.ax:=$5700;
  892. msdos(dosregs);
  893. loaddoserror;
  894. time:=(dosregs.dx shl 16)+dosregs.cx;
  895. end;
  896. procedure setftime(var f;time : longint);
  897. begin
  898. dosregs.bx:=textrec(f).handle;
  899. dosregs.cx:=time and $ffff;
  900. dosregs.dx:=time shr 16;
  901. dosregs.ax:=$5701;
  902. msdos(dosregs);
  903. loaddoserror;
  904. end;
  905. procedure getfattr(var f;var attr : word);
  906. begin
  907. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  908. dosregs.edx:=tb_offset;
  909. dosregs.ds:=tb_segment;
  910. if LFNSupport then
  911. begin
  912. dosregs.ax:=$7143;
  913. dosregs.bx:=0;
  914. end
  915. else
  916. dosregs.ax:=$4300;
  917. msdos(dosregs);
  918. LoadDosError;
  919. Attr:=dosregs.cx;
  920. end;
  921. procedure setfattr(var f;attr : word);
  922. begin
  923. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  924. dosregs.edx:=tb_offset;
  925. dosregs.ds:=tb_segment;
  926. if LFNSupport then
  927. begin
  928. dosregs.ax:=$7143;
  929. dosregs.bx:=1;
  930. end
  931. else
  932. dosregs.ax:=$4301;
  933. dosregs.cx:=attr;
  934. msdos(dosregs);
  935. LoadDosError;
  936. end;
  937. {******************************************************************************
  938. --- Environment ---
  939. ******************************************************************************}
  940. function envcount : longint;
  941. var
  942. hp : ppchar;
  943. begin
  944. hp:=envp;
  945. envcount:=0;
  946. while assigned(hp^) do
  947. begin
  948. inc(envcount);
  949. inc(hp);
  950. end;
  951. end;
  952. function envstr(index : integer) : string;
  953. begin
  954. if (index<=0) or (index>envcount) then
  955. begin
  956. envstr:='';
  957. exit;
  958. end;
  959. envstr:=strpas(ppchar(pointer(envp)+4*(index-1))^);
  960. end;
  961. Function GetEnv(envvar: string): string;
  962. var
  963. hp : ppchar;
  964. hs : string;
  965. eqpos : longint;
  966. begin
  967. envvar:=upcase(envvar);
  968. hp:=envp;
  969. getenv:='';
  970. while assigned(hp^) do
  971. begin
  972. hs:=strpas(hp^);
  973. eqpos:=pos('=',hs);
  974. if copy(hs,1,eqpos-1)=envvar then
  975. begin
  976. getenv:=copy(hs,eqpos+1,255);
  977. exit;
  978. end;
  979. inc(hp);
  980. end;
  981. end;
  982. {******************************************************************************
  983. --- Not Supported ---
  984. ******************************************************************************}
  985. Procedure keep(exitcode : word);
  986. Begin
  987. End;
  988. Procedure getintvec(intno : byte;var vector : pointer);
  989. Begin
  990. End;
  991. Procedure setintvec(intno : byte;vector : pointer);
  992. Begin
  993. End;
  994. end.
  995. {
  996. $Log$
  997. Revision 1.19 2000-01-23 16:31:23 peter
  998. * hasint64diskspace define changed to int64 so it's default now
  999. Revision 1.18 2000/01/23 12:28:38 marco
  1000. * Added diskfree and disksize with AH=71 dos functions (LFN/Fat32)
  1001. Revision 1.17 2000/01/07 16:41:30 daniel
  1002. * copyright 2000
  1003. Revision 1.16 2000/01/07 16:32:23 daniel
  1004. * copyright 2000 added
  1005. Revision 1.15 1999/12/06 18:26:49 peter
  1006. * fpcmake updated for win32 commandline
  1007. Revision 1.14 1999/11/09 11:07:50 pierre
  1008. * SwapVectors does not reset DosError anymore
  1009. + DosError is set to ax regsiter value if extended doserror function
  1010. retruns zero.
  1011. + Support for LFN in EXEC function using
  1012. function 7160 to get short filename counterpart
  1013. Revision 1.13 1999/11/06 14:38:23 peter
  1014. * truncated log
  1015. Revision 1.12 1999/09/10 17:14:09 peter
  1016. * better errorcode returning using int21h,5900
  1017. Revision 1.11 1999/09/08 18:55:49 peter
  1018. * pointer fixes
  1019. Revision 1.10 1999/08/13 21:23:15 peter
  1020. * fsearch checks first if the specified file exists and returns that
  1021. if it was found
  1022. Revision 1.9 1999/05/16 17:08:58 peter
  1023. * fixed driveletter checking
  1024. Revision 1.8 1999/05/08 19:47:22 peter
  1025. * check ioresult after getdir calls
  1026. Revision 1.7 1999/05/04 23:55:50 pierre
  1027. * unneeded assembler code converted to pascal
  1028. Revision 1.6 1999/04/28 11:42:44 peter
  1029. + FileNameCaseSensetive boolean
  1030. Revision 1.5 1999/04/02 00:01:29 peter
  1031. * fixed LFNFindfirst on network drives
  1032. Revision 1.4 1999/03/01 15:40:48 peter
  1033. * use external names
  1034. * removed all direct assembler modes
  1035. Revision 1.3 1999/01/22 15:44:59 pierre
  1036. Daniel change removed : broke make cycle !!
  1037. Revision 1.2 1999/01/22 10:07:03 daniel
  1038. - Findclose removed: This is TP incompatible!!
  1039. Revision 1.1 1998/12/21 13:07:02 peter
  1040. * use -FE
  1041. Revision 1.19 1998/11/23 13:53:59 peter
  1042. * more fexpand fixes from marco van de voort
  1043. Revision 1.18 1998/11/23 12:48:02 peter
  1044. * fexpand('o:') fixed to return o:\ (from the mailinglist)
  1045. Revision 1.17 1998/11/22 09:33:21 florian
  1046. * fexpand bug (temp. strings were too shoort) fixed, was reported
  1047. by Marco van de Voort
  1048. Revision 1.16 1998/11/17 09:37:41 pierre
  1049. * explicit conversion from word dosreg.ax to integer doserror
  1050. Revision 1.15 1998/11/01 20:27:18 peter
  1051. * fixed some doserror settings
  1052. Revision 1.14 1998/10/22 15:05:28 pierre
  1053. * fsplit adapted to long filenames
  1054. Revision 1.13 1998/09/16 16:47:24 peter
  1055. * merged fixes
  1056. Revision 1.11.2.2 1998/09/16 16:16:04 peter
  1057. * go32v1 compiles again
  1058. }