dos.pp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  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. pa:=s[1]+':'+pa
  761. else if s[0]=#3 then
  762. pa:=s+pa
  763. else
  764. pa:=s+'\'+pa;
  765. { Turbo Pascal gives current dir on drive if only drive given as parameter! }
  766. if length(pa) = 2 then
  767. begin
  768. getdir(byte(pa[1])-64,s);
  769. pa := s;
  770. end;
  771. {First remove all references to '\.\'}
  772. while pos ('\.\',pa)<>0 do
  773. delete (pa,pos('\.\',pa),2);
  774. {Now remove also all references to '\..\' + of course previous dirs..}
  775. repeat
  776. i:=pos('\..\',pa);
  777. if i<>0 then
  778. begin
  779. j:=i-1;
  780. while (j>1) and (pa[j]<>'\') do
  781. dec (j);
  782. if pa[j+1] = ':' then j := 3;
  783. delete (pa,j,i-j+3);
  784. end;
  785. until i=0;
  786. { Turbo Pascal gets rid of a \.. at the end of the path }
  787. { Now remove also any reference to '\..' at end of line
  788. + of course previous dir.. }
  789. i:=pos('\..',pa);
  790. if i<>0 then
  791. begin
  792. if i = length(pa) - 2 then
  793. begin
  794. j:=i-1;
  795. while (j>1) and (pa[j]<>'\') do
  796. dec (j);
  797. delete (pa,j,i-j+3);
  798. end;
  799. pa := pa + '\';
  800. end;
  801. { Remove End . and \}
  802. if (length(pa)>0) and (pa[length(pa)]='.') then
  803. dec(byte(pa[0]));
  804. { if only the drive + a '\' is left then the '\' should be left to prevtn the program
  805. accessing the current directory on the drive rather than the root!}
  806. { if the last char of path = '\' then leave it in as this is what TP does! }
  807. if ((length(pa)>3) and (pa[length(pa)]='\')) and (path[length(path)] <> '\') then
  808. dec(byte(pa[0]));
  809. { if only a drive is given in path then there should be a '\' at the
  810. end of the string given back }
  811. if length(pa) = 2 then pa := pa + '\';
  812. fexpand:=pa;
  813. end;
  814. Function FSearch(path: pathstr; dirlist: string): pathstr;
  815. var
  816. i,p1 : longint;
  817. s : searchrec;
  818. newdir : pathstr;
  819. begin
  820. { check if the file specified exists }
  821. findfirst(path,anyfile,s);
  822. if doserror=0 then
  823. begin
  824. findclose(s);
  825. fsearch:=path;
  826. exit;
  827. end;
  828. { No wildcards allowed in these things }
  829. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  830. fsearch:=''
  831. else
  832. begin
  833. { allow slash as backslash }
  834. for i:=1 to length(dirlist) do
  835. if dirlist[i]='/' then dirlist[i]:='\';
  836. repeat
  837. p1:=pos(';',dirlist);
  838. if p1<>0 then
  839. begin
  840. newdir:=copy(dirlist,1,p1-1);
  841. delete(dirlist,1,p1);
  842. end
  843. else
  844. begin
  845. newdir:=dirlist;
  846. dirlist:='';
  847. end;
  848. if (newdir<>'') and (not (newdir[length(newdir)] in ['\',':'])) then
  849. newdir:=newdir+'\';
  850. findfirst(newdir+path,anyfile,s);
  851. if doserror=0 then
  852. newdir:=newdir+path
  853. else
  854. newdir:='';
  855. until (dirlist='') or (newdir<>'');
  856. fsearch:=newdir;
  857. end;
  858. findclose(s);
  859. end;
  860. { change to short filename if successful DOS call PM }
  861. function GetShortName(var p : String) : boolean;
  862. var
  863. c : array[0..255] of char;
  864. begin
  865. move(p[1],c[0],length(p));
  866. c[length(p)]:=#0;
  867. copytodos(@c,length(p)+1);
  868. dosregs.ax:=$7160;
  869. dosregs.cx:=1;
  870. dosregs.ds:=tb_segment;
  871. dosregs.si:=tb_offset;
  872. dosregs.es:=tb_segment;
  873. dosregs.di:=tb_offset;
  874. msdos(dosregs);
  875. LoadDosError;
  876. if DosError=0 then
  877. begin
  878. copyfromdos(@c,255);
  879. move(c[0],p[1],strlen(c));
  880. p[0]:=char(strlen(c));
  881. GetShortName:=true;
  882. end
  883. else
  884. GetShortName:=false;
  885. end;
  886. { change to long filename if successful DOS call PM }
  887. function GetLongName(var p : String) : boolean;
  888. var
  889. c : array[0..255] of char;
  890. begin
  891. move(p[1],c[0],length(p));
  892. c[length(p)]:=#0;
  893. copytodos(@c,length(p)+1);
  894. dosregs.ax:=$7160;
  895. dosregs.cx:=2;
  896. dosregs.ds:=tb_segment;
  897. dosregs.si:=tb_offset;
  898. dosregs.es:=tb_segment;
  899. dosregs.di:=tb_offset;
  900. msdos(dosregs);
  901. LoadDosError;
  902. if DosError=0 then
  903. begin
  904. copyfromdos(@c,255);
  905. move(c[0],p[1],strlen(c));
  906. p[0]:=char(strlen(c));
  907. GetLongName:=true;
  908. end
  909. else
  910. GetLongName:=false;
  911. end;
  912. {******************************************************************************
  913. --- Get/Set File Time,Attr ---
  914. ******************************************************************************}
  915. procedure getftime(var f;var time : longint);
  916. begin
  917. dosregs.bx:=textrec(f).handle;
  918. dosregs.ax:=$5700;
  919. msdos(dosregs);
  920. loaddoserror;
  921. time:=(dosregs.dx shl 16)+dosregs.cx;
  922. end;
  923. procedure setftime(var f;time : longint);
  924. begin
  925. dosregs.bx:=textrec(f).handle;
  926. dosregs.cx:=time and $ffff;
  927. dosregs.dx:=time shr 16;
  928. dosregs.ax:=$5701;
  929. msdos(dosregs);
  930. loaddoserror;
  931. end;
  932. procedure getfattr(var f;var attr : word);
  933. begin
  934. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  935. dosregs.edx:=tb_offset;
  936. dosregs.ds:=tb_segment;
  937. if LFNSupport then
  938. begin
  939. dosregs.ax:=$7143;
  940. dosregs.bx:=0;
  941. end
  942. else
  943. dosregs.ax:=$4300;
  944. msdos(dosregs);
  945. LoadDosError;
  946. Attr:=dosregs.cx;
  947. end;
  948. procedure setfattr(var f;attr : word);
  949. begin
  950. copytodos(filerec(f).name,strlen(filerec(f).name)+1);
  951. dosregs.edx:=tb_offset;
  952. dosregs.ds:=tb_segment;
  953. if LFNSupport then
  954. begin
  955. dosregs.ax:=$7143;
  956. dosregs.bx:=1;
  957. end
  958. else
  959. dosregs.ax:=$4301;
  960. dosregs.cx:=attr;
  961. msdos(dosregs);
  962. LoadDosError;
  963. end;
  964. {******************************************************************************
  965. --- Environment ---
  966. ******************************************************************************}
  967. function envcount : longint;
  968. var
  969. hp : ppchar;
  970. begin
  971. hp:=envp;
  972. envcount:=0;
  973. while assigned(hp^) do
  974. begin
  975. inc(envcount);
  976. inc(hp);
  977. end;
  978. end;
  979. function envstr(index : integer) : string;
  980. begin
  981. if (index<=0) or (index>envcount) then
  982. begin
  983. envstr:='';
  984. exit;
  985. end;
  986. envstr:=strpas(ppchar(pointer(envp)+4*(index-1))^);
  987. end;
  988. Function GetEnv(envvar: string): string;
  989. var
  990. hp : ppchar;
  991. hs : string;
  992. eqpos : longint;
  993. begin
  994. envvar:=upcase(envvar);
  995. hp:=envp;
  996. getenv:='';
  997. while assigned(hp^) do
  998. begin
  999. hs:=strpas(hp^);
  1000. eqpos:=pos('=',hs);
  1001. if copy(hs,1,eqpos-1)=envvar then
  1002. begin
  1003. getenv:=copy(hs,eqpos+1,255);
  1004. exit;
  1005. end;
  1006. inc(hp);
  1007. end;
  1008. end;
  1009. {******************************************************************************
  1010. --- Not Supported ---
  1011. ******************************************************************************}
  1012. Procedure keep(exitcode : word);
  1013. Begin
  1014. End;
  1015. Procedure getintvec(intno : byte;var vector : pointer);
  1016. Begin
  1017. End;
  1018. Procedure setintvec(intno : byte;vector : pointer);
  1019. Begin
  1020. End;
  1021. end.
  1022. {
  1023. $Log$
  1024. Revision 1.22 2000-02-09 16:59:28 peter
  1025. * truncated log
  1026. Revision 1.21 2000/02/09 13:00:32 peter
  1027. + getlongname
  1028. Revision 1.20 2000/02/02 17:34:49 pierre
  1029. * use int64 typecast to avoid overflows in diskfree and disksize
  1030. Revision 1.19 2000/01/23 16:31:23 peter
  1031. * hasint64diskspace define changed to int64 so it's default now
  1032. Revision 1.18 2000/01/23 12:28:38 marco
  1033. * Added diskfree and disksize with AH=71 dos functions (LFN/Fat32)
  1034. Revision 1.17 2000/01/07 16:41:30 daniel
  1035. * copyright 2000
  1036. Revision 1.16 2000/01/07 16:32:23 daniel
  1037. * copyright 2000 added
  1038. Revision 1.15 1999/12/06 18:26:49 peter
  1039. * fpcmake updated for win32 commandline
  1040. Revision 1.14 1999/11/09 11:07:50 pierre
  1041. * SwapVectors does not reset DosError anymore
  1042. + DosError is set to ax regsiter value if extended doserror function
  1043. retruns zero.
  1044. + Support for LFN in EXEC function using
  1045. function 7160 to get short filename counterpart
  1046. Revision 1.13 1999/11/06 14:38:23 peter
  1047. * truncated log
  1048. Revision 1.12 1999/09/10 17:14:09 peter
  1049. * better errorcode returning using int21h,5900
  1050. Revision 1.11 1999/09/08 18:55:49 peter
  1051. * pointer fixes
  1052. Revision 1.10 1999/08/13 21:23:15 peter
  1053. * fsearch checks first if the specified file exists and returns that
  1054. if it was found
  1055. }