dos.pp 28 KB

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