dos.pas 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  1. {****************************************************************************
  2. $Id$
  3. Free Pascal Runtime-Library
  4. DOS unit for OS/2
  5. Copyright (c) 1997,1999-2000 by Daniel Mantione,
  6. member of the Free Pascal development team
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. ****************************************************************************}
  13. unit dos;
  14. {$ASMMODE ATT}
  15. {***************************************************************************}
  16. interface
  17. {***************************************************************************}
  18. {$PACKRECORDS 1}
  19. uses strings;
  20. const {Bit masks for CPU flags.}
  21. fcarry = $0001;
  22. fparity = $0004;
  23. fauxiliary = $0010;
  24. fzero = $0040;
  25. fsign = $0080;
  26. foverflow = $0800;
  27. {Bit masks for file attributes.}
  28. readonly = $01;
  29. hidden = $02;
  30. sysfile = $04;
  31. volumeid = $08;
  32. directory = $10;
  33. archive = $20;
  34. anyfile = $3F;
  35. fmclosed = $D7B0;
  36. fminput = $D7B1;
  37. fmoutput = $D7B2;
  38. fminout = $D7B3;
  39. type {Some string types:}
  40. comstr=string; {Filenames can be long in OS/2.}
  41. pathstr=string; {String for pathnames.}
  42. dirstr=string; {String for a directory}
  43. namestr=string; {String for a filename.}
  44. extstr=string[40]; {String for an extension. Can be 253
  45. characters long, in theory, but let's
  46. say fourty will be enough.}
  47. {Search record which is used by findfirst and findnext:}
  48. searchrec=record
  49. case boolean of
  50. false: (handle:longint; {Used in os_OS2 mode}
  51. fill2:array[1..21-SizeOf(longint)] of byte;
  52. attr2:byte;
  53. time2:longint;
  54. size2:longint;
  55. name2:string); {Filenames can be long in OS/2!}
  56. true: (fill:array[1..21] of byte;
  57. attr:byte;
  58. time:longint;
  59. size:longint;
  60. name:string); {Filenames can be long in OS/2!}
  61. end;
  62. {$i filerec.inc}
  63. {$i textrec.inc}
  64. {Data structure for the registers needed by msdos and intr:}
  65. registers=record
  66. case i:integer of
  67. 0:(ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,
  68. f8,flags,fs,gs:word);
  69. 1:(al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh:byte);
  70. 2:(eax,ebx,ecx,edx,ebp,esi,edi:longint);
  71. end;
  72. {Record for date and time:}
  73. datetime=record
  74. year,month,day,hour,min,sec:word;
  75. end;
  76. {Flags for the exec procedure:
  77. Starting the program:
  78. efwait: Wait until program terminates.
  79. efno_wait: Don't wait until the program terminates. Does not work
  80. in dos, as DOS cannot multitask.
  81. efoverlay: Terminate this program, then execute the requested
  82. program. WARNING: Exit-procedures are not called!
  83. efdebug: Debug program. Details are unknown.
  84. efsession: Do not execute as child of this program. Use a seperate
  85. session instead.
  86. efdetach: Detached. Function unknown. Info wanted!
  87. efpm: Run as presentation manager program.
  88. Determining the window state of the program:
  89. efdefault: Run the pm program in it's default situation.
  90. efminimize: Run the pm program minimized.
  91. efmaximize: Run the pm program maximized.
  92. effullscreen: Run the non-pm program fullscreen.
  93. efwindowed: Run the non-pm program in a window.
  94. Other options are not implemented defined because lack of
  95. knowledge about what they do.}
  96. type execrunflags=(efwait,efno_wait,efoverlay,efdebug,efsession,
  97. efdetach,efpm);
  98. execwinflags=(efdefault,efminimize,efmaximize,effullscreen,
  99. efwindowed);
  100. const
  101. (* For compatibility with VP/2, used for runflags in Exec procedure. *)
  102. ExecFlags: cardinal = ord (efwait);
  103. var doserror:integer;
  104. dosexitcode:word;
  105. procedure getdate(var year,month,day,dayofweek:word);
  106. procedure gettime(var hour,minute,second,sec100:word);
  107. function dosversion:word;
  108. procedure setdate(year,month,day:word);
  109. procedure settime(hour,minute,second,sec100:word);
  110. procedure getcbreak(var breakvalue:boolean);
  111. procedure setcbreak(breakvalue:boolean);
  112. procedure getverify(var verify:boolean);
  113. procedure setverify(verify : boolean);
  114. function DiskFree (Drive: byte) : int64;
  115. function DiskSize (Drive: byte) : int64;
  116. procedure findfirst(const path:pathstr;attr:word;var f:searchRec);
  117. procedure findnext(var f:searchRec);
  118. procedure findclose(var f:searchRec);
  119. {Is a dummy:}
  120. procedure swapvectors;
  121. {Not supported:
  122. procedure getintvec(intno:byte;var vector:pointer);
  123. procedure setintvec(intno:byte;vector:pointer);
  124. procedure keep(exitcode:word);
  125. }
  126. procedure msdos(var regs:registers);
  127. procedure intr(intno : byte;var regs:registers);
  128. procedure getfattr(var f;var attr:word);
  129. procedure setfattr(var f;attr:word);
  130. function fsearch(path:pathstr;dirlist:string):pathstr;
  131. procedure getftime(var f;var time:longint);
  132. procedure setftime(var f;time:longint);
  133. procedure packtime (var d:datetime; var time:longint);
  134. procedure unpacktime (time:longint; var d:datetime);
  135. function fexpand(const path:pathstr):pathstr;
  136. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  137. var ext:extstr);
  138. procedure exec(const path:pathstr;const comline:comstr);
  139. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  140. const comline:comstr):longint;
  141. function envcount:longint;
  142. function envstr(index:longint) : string;
  143. function getenv(const envvar:string): string;
  144. implementation
  145. uses DosCalls;
  146. var LastSR: SearchRec;
  147. type TBA = array [1..SizeOf (SearchRec)] of byte;
  148. PBA = ^TBA;
  149. {Import syscall to call it nicely from assembler procedures.}
  150. procedure syscall;external name '___SYSCALL';
  151. function fsearch(path:pathstr;dirlist:string):pathstr;
  152. var i,p1:longint;
  153. newdir:pathstr;
  154. {$ASMMODE INTEL}
  155. function CheckFile (FN: ShortString):boolean; assembler;
  156. asm
  157. mov ax, 4300h
  158. mov edx, FN
  159. inc edx
  160. call syscall
  161. mov ax, 0
  162. jc @LCFstop
  163. test cx, 18h
  164. jnz @LCFstop
  165. inc ax
  166. @LCFstop:
  167. end;
  168. {$ASMMODE ATT}
  169. begin
  170. { check if the file specified exists }
  171. if CheckFile (Path + #0) then
  172. FSearch := Path
  173. else
  174. begin
  175. {No wildcards allowed in these things:}
  176. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  177. fsearch:=''
  178. else
  179. begin
  180. { allow slash as backslash }
  181. for i:=1 to length(dirlist) do
  182. if dirlist[i]='/' then dirlist[i]:='\';
  183. repeat
  184. p1:=pos(';',dirlist);
  185. if p1<>0 then
  186. begin
  187. newdir:=copy(dirlist,1,p1-1);
  188. delete(dirlist,1,p1);
  189. end
  190. else
  191. begin
  192. newdir:=dirlist;
  193. dirlist:='';
  194. end;
  195. if (newdir<>'') and
  196. not (newdir[length(newdir)] in ['\',':']) then
  197. newdir:=newdir+'\';
  198. if CheckFile (NewDir + Path + #0) then
  199. NewDir := NewDir + Path
  200. else
  201. NewDir := '';
  202. until (DirList = '') or (NewDir <> '');
  203. FSearch := NewDir;
  204. end;
  205. end;
  206. end;
  207. procedure getftime(var f;var time:longint);
  208. begin
  209. asm
  210. {Load handle}
  211. movl f,%ebx
  212. movw (%ebx),%bx
  213. {Get date}
  214. movw $0x5700,%ax
  215. call syscall
  216. shll $16,%edx
  217. movw %cx,%dx
  218. movl time,%ebx
  219. movl %edx,(%ebx)
  220. xorb %ah,%ah
  221. movw %ax,doserror
  222. end;
  223. end;
  224. procedure SetFTime (var F; Time: longint);
  225. var FStat: PFileStatus0;
  226. RC: longint;
  227. begin
  228. if os_mode = osOS2 then
  229. begin
  230. New (FStat);
  231. RC := DosQueryFileInfo (TextRec (F).Handle, ilStandard, FStat,
  232. SizeOf (FStat^));
  233. if RC = 0 then
  234. begin
  235. FStat^.DateLastAccess := Hi (Time);
  236. FStat^.DateLastWrite := Hi (Time);
  237. FStat^.TimeLastAccess := Lo (Time);
  238. FStat^.TimeLastWrite := Lo (Time);
  239. RC := DosSetFileInfo (TextRec (F).Handle, ilStandard,
  240. FStat, SizeOf (FStat^));
  241. end;
  242. Dispose (FStat);
  243. end
  244. else
  245. asm
  246. {Load handle}
  247. movl f,%ebx
  248. movw (%ebx),%bx
  249. movl time,%ecx
  250. shldl $16,%ecx,%edx
  251. {Set date}
  252. movw $0x5701,%ax
  253. call syscall
  254. xorb %ah,%ah
  255. movw %ax,doserror
  256. end;
  257. end;
  258. procedure msdos(var regs:registers);
  259. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  260. begin
  261. intr($21,regs);
  262. end;
  263. {$ASMMODE DIRECT}
  264. procedure intr(intno:byte;var regs:registers);
  265. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  266. begin
  267. asm
  268. .data
  269. int86:
  270. .byte 0xcd
  271. int86_vec:
  272. .byte 0x03
  273. jmp int86_retjmp
  274. .text
  275. movl 8(%ebp),%eax
  276. movb %al,int86_vec
  277. movl 10(%ebp),%eax
  278. {Do not use first int}
  279. incl %eax
  280. incl %eax
  281. movl 4(%eax),%ebx
  282. movl 8(%eax),%ecx
  283. movl 12(%eax),%edx
  284. movl 16(%eax),%ebp
  285. movl 20(%eax),%esi
  286. movl 24(%eax),%edi
  287. movl (%eax),%eax
  288. jmp int86
  289. int86_retjmp:
  290. pushf
  291. pushl %ebp
  292. pushl %eax
  293. movl %esp,%ebp
  294. {Calc EBP new}
  295. addl $12,%ebp
  296. movl 10(%ebp),%eax
  297. {Do not use first int}
  298. incl %eax
  299. incl %eax
  300. popl (%eax)
  301. movl %ebx,4(%eax)
  302. movl %ecx,8(%eax)
  303. movl %edx,12(%eax)
  304. {Restore EBP}
  305. popl %edx
  306. movl %edx,16(%eax)
  307. movl %esi,20(%eax)
  308. movl %edi,24(%eax)
  309. {Ignore ES and DS}
  310. popl %ebx {Flags.}
  311. movl %ebx,32(%eax)
  312. {FS and GS too}
  313. end;
  314. end;
  315. {$ASMMODE ATT}
  316. procedure exec(const path:pathstr;const comline:comstr);
  317. {Execute a program.}
  318. begin
  319. dosexitcode:=exec(path,execrunflags(ExecFlags),efdefault,comline);
  320. end;
  321. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  322. const comline:comstr):longint;
  323. {Execute a program. More suitable for OS/2 than the exec above.}
  324. {512 bytes should be enough to contain the command-line.}
  325. type bytearray=array[0..8191] of byte;
  326. Pbytearray=^bytearray;
  327. execstruc=record
  328. argofs,envofs,nameofs:pointer;
  329. argseg,envseg,nameseg:word;
  330. numarg,sizearg,
  331. numenv,sizeenv:word;
  332. mode1,mode2:byte;
  333. end;
  334. var args:Pbytearray;
  335. env:Pbytearray;
  336. i,j:word;
  337. es:execstruc;
  338. esadr:pointer;
  339. d:dirstr;
  340. n:namestr;
  341. e:extstr;
  342. begin
  343. getmem(args,512);
  344. getmem(env,8192);
  345. j:=1;
  346. {Now setup the arguments. The first argument should be the program
  347. name without directory and extension.}
  348. fsplit(path,d,n,e);
  349. es.numarg:=1;
  350. args^[0]:=$80;
  351. for i:=1 to length(n) do
  352. begin
  353. args^[j]:=byte(n[i]);
  354. inc(j);
  355. end;
  356. args^[j]:=0;
  357. inc(j);
  358. {Now do the real arguments.}
  359. i:=1;
  360. while i<=length(comline) do
  361. begin
  362. if comline[i]<>' ' then
  363. begin
  364. {Commandline argument found. Copy it.}
  365. inc(es.numarg);
  366. args^[j]:=$80;
  367. inc(j);
  368. while (i<=length(comline)) and (comline[i]<>' ') do
  369. begin
  370. args^[j]:=byte(comline[i]);
  371. inc(j);
  372. inc(i);
  373. end;
  374. args^[j]:=0;
  375. inc(j);
  376. end;
  377. inc(i);
  378. end;
  379. args^[j]:=0;
  380. inc(j);
  381. {Commandline ready, now build the environment.
  382. Oh boy, I always had the opinion that executing a program under Dos
  383. was a hard job!}
  384. {$ASMMODE DIRECT}
  385. asm
  386. movl env,%edi {Setup destination pointer.}
  387. movl _envc,%ecx {Load number of arguments in edx.}
  388. movl _environ,%esi {Load env. strings.}
  389. xorl %edx,%edx {Count environment size.}
  390. exa1:
  391. lodsl {Load a Pchar.}
  392. xchgl %eax,%ebx
  393. exa2:
  394. movb (%ebx),%al {Load a byte.}
  395. incl %ebx {Point to next byte.}
  396. stosb {Store it.}
  397. incl %edx {Increase counter.}
  398. cmpb $0,%al {Ready ?.}
  399. jne exa2
  400. loop exa1 {Next argument.}
  401. stosb {Store an extra 0 to finish. (AL is now 0).}
  402. incl %edx
  403. movl %edx,(24)es {Store environment size.}
  404. end;
  405. {$ASMMODE ATT}
  406. {Environment ready, now set-up exec structure.}
  407. es.argofs:=args;
  408. es.envofs:=env;
  409. asm
  410. leal path,%esi
  411. lodsb
  412. movzbl %al,%eax
  413. addl %eax,%esi
  414. movb $0,(%esi)
  415. end;
  416. es.nameofs:=pointer(longint(@path)+1);
  417. asm
  418. movw %ss,es.argseg
  419. movw %ss,es.envseg
  420. movw %ss,es.nameseg
  421. end;
  422. es.sizearg:=j;
  423. es.numenv:=0;
  424. {Typecasting of sets in FPC is a bit hard.}
  425. es.mode1:=byte(runflags);
  426. es.mode2:=byte(winflags);
  427. {Now exec the program.}
  428. asm
  429. leal es,%edx
  430. mov $0x7f06,%ax
  431. call syscall
  432. xorl %edi,%edi
  433. jnc .Lexprg1
  434. xchgl %eax,%edi
  435. xorl %eax,%eax
  436. decl %eax
  437. .Lexprg1:
  438. movw %di,doserror
  439. movl %eax,__RESULT
  440. end;
  441. freemem(args,512);
  442. freemem(env,8192);
  443. {Phew! That's it. This was the most sophisticated procedure to call
  444. a system function I ever wrote!}
  445. end;
  446. function dosversion:word;assembler;
  447. {Returns DOS version in DOS and OS/2 version in OS/2}
  448. asm
  449. movb $0x30,%ah
  450. call syscall
  451. end;
  452. procedure GetDate (var Year, Month, Day, DayOfWeek: word);
  453. begin
  454. asm
  455. movb $0x2a, %ah
  456. call syscall
  457. xorb %ah, %ah
  458. movl DayOfWeek, %edi
  459. stosw
  460. movl Day, %edi
  461. movb %dl, %al
  462. stosw
  463. movl Month, %edi
  464. movb %dh, %al
  465. stosw
  466. movl Year, %edi
  467. xchgw %ecx, %eax
  468. stosw
  469. end;
  470. end;
  471. {$asmmode intel}
  472. procedure SetDate (Year, Month, Day: word);
  473. var DT: TDateTime;
  474. begin
  475. if os_mode = osOS2 then
  476. begin
  477. DosGetDateTime (DT);
  478. DT.Year := Year;
  479. DT.Month := Month;
  480. DT.Day := Day;
  481. DosSetDateTime (DT);
  482. end
  483. else
  484. asm
  485. mov cx, Year
  486. mov dh, byte ptr Month
  487. mov dl, byte ptr Day
  488. mov ah, $2b
  489. call syscall
  490. end;
  491. end;
  492. {$asmmode att}
  493. procedure GetTime (var Hour, Minute, Second, Sec100: word); assembler;
  494. asm
  495. movb $0x2c, %ah
  496. call syscall
  497. xorb %ah, %ah
  498. movl Sec100, %edi
  499. movb %dl, %al
  500. stosw
  501. movl Second, %edi
  502. movb %dh,%al
  503. stosw
  504. movl Minute, %edi
  505. movb %cl,%al
  506. stosw
  507. movl Hour, %edi
  508. movb %ch,%al
  509. stosw
  510. end;
  511. {$asmmode intel}
  512. procedure SetTime (Hour, Minute, Second, Sec100: word);
  513. var DT: TDateTime;
  514. begin
  515. if os_mode = osOS2 then
  516. begin
  517. DosGetDateTime (DT);
  518. DT.Hour := Hour;
  519. DT.Minute := Minute;
  520. DT.Second := Second;
  521. DT.Sec100 := Sec100;
  522. DosSetDateTime (DT);
  523. end
  524. else
  525. asm
  526. mov ch, byte ptr Hour
  527. mov cl, byte ptr Minute
  528. mov dh, byte ptr Second
  529. mov dl, byte ptr Sec100
  530. mov ah, $2d
  531. call syscall
  532. end;
  533. end;
  534. {$asmmode att}
  535. procedure getcbreak(var breakvalue:boolean);
  536. begin
  537. {! Do not use in OS/2. Also not recommended in DOS. Use
  538. signal handling instead.}
  539. asm
  540. movw $0x3300,%ax
  541. call syscall
  542. movl 8(%ebp),%eax
  543. movb %dl,(%eax)
  544. end;
  545. end;
  546. procedure setcbreak(breakvalue:boolean);
  547. begin
  548. {! Do not use in OS/2. Also not recommended in DOS. Use
  549. signal handling instead.}
  550. asm
  551. movb 8(%ebp),%dl
  552. movw $0x3301,%ax
  553. call syscall
  554. end;
  555. end;
  556. procedure getverify(var verify:boolean);
  557. begin
  558. {! Do not use in OS/2.}
  559. asm
  560. movb $0x54,%ah
  561. call syscall
  562. movl 8(%ebp),%edi
  563. stosb
  564. end;
  565. end;
  566. procedure setverify(verify:boolean);
  567. begin
  568. {! Do not use in OS/2.}
  569. asm
  570. movb 8(%ebp),%al
  571. movb $0x2e,%ah
  572. call syscall
  573. end;
  574. end;
  575. function DiskFree (Drive: byte): int64;
  576. var FI: TFSinfo;
  577. RC: longint;
  578. begin
  579. if (os_mode = osDOS) or (os_mode = osDPMI) then
  580. {Function 36 is not supported in OS/2.}
  581. asm
  582. movb 8(%ebp),%dl
  583. movb $0x36,%ah
  584. call syscall
  585. cmpw $-1,%ax
  586. je .LDISKFREE1
  587. mulw %cx
  588. mulw %bx
  589. shll $16,%edx
  590. movw %ax,%dx
  591. xchgl %edx,%eax
  592. leave
  593. ret
  594. .LDISKFREE1:
  595. cltd
  596. leave
  597. ret
  598. end
  599. else
  600. {In OS/2, we use the filesystem information.}
  601. begin
  602. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  603. if RC = 0 then
  604. DiskFree := int64 (FI.Free_Clusters) *
  605. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  606. else
  607. DiskFree := -1;
  608. end;
  609. end;
  610. function DiskSize (Drive: byte): int64;
  611. var FI: TFSinfo;
  612. RC: longint;
  613. begin
  614. if (os_mode = osDOS) or (os_mode = osDPMI) then
  615. {Function 36 is not supported in OS/2.}
  616. asm
  617. movb 8(%ebp),%dl
  618. movb $0x36,%ah
  619. call syscall
  620. movw %dx,%bx
  621. cmpw $-1,%ax
  622. je .LDISKSIZE1
  623. mulw %cx
  624. mulw %bx
  625. shll $16,%edx
  626. movw %ax,%dx
  627. xchgl %edx,%eax
  628. leave
  629. ret
  630. .LDISKSIZE1:
  631. cltd
  632. leave
  633. ret
  634. end
  635. else
  636. {In OS/2, we use the filesystem information.}
  637. begin
  638. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  639. if RC = 0 then
  640. DiskSize := int64 (FI.Total_Clusters) *
  641. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  642. else
  643. DiskSize := -1;
  644. end;
  645. end;
  646. procedure SearchRec2DosSearchRec (var F: SearchRec);
  647. const NameSize = 255;
  648. var L, I: longint;
  649. begin
  650. if os_mode <> osOS2 then
  651. begin
  652. I := 1;
  653. while (I <= SizeOf (LastSR))
  654. and (PBA (@F)^ [I] = PBA (@LastSR)^ [I]) do Inc (I);
  655. { Raise "Invalid file handle" RTE if nested FindFirst calls were used. }
  656. if I <= SizeOf (LastSR) then RunError (6);
  657. l:=length(f.name);
  658. for i:=1 to namesize do
  659. f.name[i-1]:=f.name[i];
  660. f.name[l]:=#0;
  661. end;
  662. end;
  663. procedure DosSearchRec2SearchRec (var F: SearchRec; FStat: PFileFindBuf3);
  664. const NameSize=255;
  665. var L, I: longint;
  666. type TRec = record
  667. T, D: word;
  668. end;
  669. begin
  670. if os_mode = osOS2 then with F do
  671. begin
  672. Name := FStat^.Name;
  673. Size := FStat^.FileSize;
  674. Attr := FStat^.AttrFile;
  675. TRec (Time).T := FStat^.TimeLastWrite;
  676. TRec (Time).D := FStat^.DateLastWrite;
  677. end else
  678. begin
  679. for i:=0 to namesize do
  680. if f.name[i]=#0 then
  681. begin
  682. l:=i;
  683. break;
  684. end;
  685. for i:=namesize-1 downto 0 do
  686. f.name[i+1]:=f.name[i];
  687. f.name[0]:=char(l);
  688. Move (F, LastSR, SizeOf (LastSR));
  689. end;
  690. end;
  691. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  692. procedure _findfirst(path:pchar;attr:word;var f:searchrec);
  693. begin
  694. asm
  695. movl 12(%esp),%edx
  696. movw 16(%esp),%cx
  697. {No need to set DTA in EMX. Just give a pointer in ESI.}
  698. movl 18(%ebp),%esi
  699. movb $0x4e,%ah
  700. call syscall
  701. jnc .LFF
  702. movw %ax,doserror
  703. .LFF:
  704. end;
  705. end;
  706. const
  707. FStat: PFileFindBuf3 = nil;
  708. var path0: array[0..255] of char;
  709. Count: longint;
  710. begin
  711. {No error.}
  712. DosError := 0;
  713. if os_mode = osOS2 then
  714. begin
  715. New (FStat);
  716. F.Handle := $FFFFFFFF;
  717. Count := 1;
  718. DosError := DosFindFirst (Path, F.Handle, Attr, FStat,
  719. SizeOf (FStat^), Count, ilStandard);
  720. if (DosError = 0) and (Count = 0) then DosError := 18;
  721. end else
  722. begin
  723. strPcopy(path0,path);
  724. _findfirst(path0,attr,f);
  725. end;
  726. DosSearchRec2SearchRec (F, FStat);
  727. if os_mode = osOS2 then Dispose (FStat);
  728. end;
  729. procedure FindNext (var F: SearchRec);
  730. var FStat: PFileFindBuf3;
  731. Count: longint;
  732. procedure _findnext(var f : searchrec);
  733. begin
  734. asm
  735. movl 12(%ebp),%esi
  736. movb $0x4f,%ah
  737. call syscall
  738. jnc .LFN
  739. movw %ax,doserror
  740. .LFN:
  741. end;
  742. end;
  743. begin
  744. {No error}
  745. DosError := 0;
  746. SearchRec2DosSearchRec (F);
  747. if os_mode = osOS2 then
  748. begin
  749. New (FStat);
  750. Count := 1;
  751. DosError := DosFindNext (F.Handle, FStat, SizeOf (FStat), Count);
  752. if (DosError = 0) and (Count = 0) then DosError := 18;
  753. end else _findnext (F);
  754. DosSearchRec2SearchRec (F, FStat);
  755. if os_mode = osOS2 then Dispose (FStat);
  756. end;
  757. procedure FindClose (var F: SearchRec);
  758. begin
  759. if os_mode = osOS2 then
  760. begin
  761. DosError := DosFindClose (F.Handle);
  762. end;
  763. end;
  764. procedure swapvectors;
  765. {For TP compatibility, this exists.}
  766. begin
  767. end;
  768. type PPchar=^Pchar;
  769. {$ASMMODE DIRECT}
  770. function envs:PPchar;assembler;
  771. asm
  772. movl _environ,%eax
  773. end ['EAX'];
  774. function envcount:longint;assembler;
  775. var hp : ppchar;
  776. asm
  777. movl _envc,%eax
  778. end ['EAX'];
  779. {$ASMMODE ATT}
  780. function envstr(index : longint) : string;
  781. var hp:PPchar;
  782. begin
  783. if (index<=0) or (index>envcount) then
  784. begin
  785. envstr:='';
  786. exit;
  787. end;
  788. hp:=PPchar(cardinal(envs)+4*(index-1));
  789. envstr:=strpas(hp^);
  790. end;
  791. function getenv(const envvar : string) : string;
  792. var hs,_envvar : string;
  793. eqpos,i : longint;
  794. begin
  795. _envvar:=upcase(envvar);
  796. getenv:='';
  797. for i:=1 to envcount do
  798. begin
  799. hs:=envstr(i);
  800. eqpos:=pos('=',hs);
  801. if copy(hs,1,eqpos-1)=_envvar then
  802. begin
  803. getenv:=copy(hs,eqpos+1,length(hs)-eqpos);
  804. exit;
  805. end;
  806. end;
  807. end;
  808. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  809. var ext:extstr);
  810. var p1,i : longint;
  811. begin
  812. {Get drive name}
  813. p1:=pos(':',path);
  814. if p1>0 then
  815. begin
  816. dir:=path[1]+':';
  817. delete(path,1,p1);
  818. end
  819. else
  820. dir:='';
  821. { split the path and the name, there are no more path informtions }
  822. { if path contains no backslashes }
  823. while true do
  824. begin
  825. p1:=pos('\',path);
  826. if p1=0 then
  827. p1:=pos('/',path);
  828. if p1=0 then
  829. break;
  830. dir:=dir+copy(path,1,p1);
  831. delete(path,1,p1);
  832. end;
  833. {Try to find an extension.}
  834. ext:='';
  835. for i:=length(path) downto 1 do
  836. if path[i]='.' then
  837. begin
  838. ext:=copy(path,i,high(extstr));
  839. delete(path,i,length(path)-i+1);
  840. break;
  841. end;
  842. name:=path;
  843. end;
  844. function fexpand(const path:pathstr):pathstr;
  845. function get_current_drive:byte;assembler;
  846. asm
  847. movb $0x19,%ah
  848. call syscall
  849. end;
  850. var s,pa:string;
  851. i,j:longint;
  852. begin
  853. getdir(0,s);
  854. i:=ioresult;
  855. if FileNameCaseSensitive then
  856. pa := path
  857. else
  858. pa:=upcase(path);
  859. {Allow slash as backslash}
  860. for i:=1 to length(pa) do
  861. if pa[i]='/' then
  862. pa[i]:='\';
  863. if (length(pa)>1) and (pa[1] in ['A'..'Z','a'..'z']) and (pa[2]=':') then
  864. begin
  865. { Always uppercase driveletter }
  866. if (pa[1] in ['a'..'z']) then
  867. pa[1]:=Chr(Ord(Pa[1])-32);
  868. {We must get the right directory}
  869. getdir(byte(pa[1])-byte('A')+1,s);
  870. i:=ioresult;
  871. if pa[0] = #2 then
  872. pa := s
  873. else
  874. if (byte(pa[0])>2) and (pa[3]<>'\') then
  875. if pa[1]=s[1] then
  876. begin
  877. { remove ending slash if it already exists }
  878. if s[length(s)]='\' then
  879. dec(s[0]);
  880. pa:=s+'\'+copy (pa,3,length(pa))
  881. end
  882. else
  883. pa:=pa[1]+':\'+copy (pa,3,length(pa))
  884. end
  885. else
  886. if pa[1]='\' then
  887. begin
  888. { Do not touch Network drive names }
  889. if not ((Length(pa)>1) and (pa[2]='\')) then
  890. pa:=s[1]+':'+pa
  891. end
  892. else if s[0]=#3 then
  893. pa:=s+pa
  894. else
  895. pa:=s+'\'+pa;
  896. {First remove all references to '\.\'}
  897. i:=pos('\.\',pa);
  898. while i<>0 do
  899. begin
  900. delete(pa,i,2);
  901. i:=pos('\.\',pa);
  902. end;
  903. {Now remove also all references to '\..\' + of course previous dirs..}
  904. repeat
  905. i:=pos('\..\',pa);
  906. if i<>0 then
  907. begin
  908. j:=i-1;
  909. while (j>1) and (pa[j]<>'\') do
  910. dec(j);
  911. if pa[j+1] = ':' then
  912. j := 3;
  913. delete (pa,j,i-j+3);
  914. end;
  915. until i=0;
  916. fexpand:=pa;
  917. end;
  918. procedure packtime(var d:datetime;var time:longint);
  919. var zs:longint;
  920. begin
  921. time:=-1980;
  922. time:=time+d.year and 127;
  923. time:=time shl 4;
  924. time:=time+d.month;
  925. time:=time shl 5;
  926. time:=time+d.day;
  927. time:=time shl 16;
  928. zs:=d.hour;
  929. zs:=zs shl 6;
  930. zs:=zs+d.min;
  931. zs:=zs shl 5;
  932. zs:=zs+d.sec div 2;
  933. time:=time+(zs and $ffff);
  934. end;
  935. procedure unpacktime (time:longint;var d:datetime);
  936. begin
  937. d.sec:=(time and 31) * 2;
  938. time:=time shr 5;
  939. d.min:=time and 63;
  940. time:=time shr 6;
  941. d.hour:=time and 31;
  942. time:=time shr 5;
  943. d.day:=time and 31;
  944. time:=time shr 5;
  945. d.month:=time and 15;
  946. time:=time shr 4;
  947. d.year:=time+1980;
  948. end;
  949. procedure getfattr(var f;var attr : word);assembler;
  950. asm
  951. movw $0x4300,%ax
  952. movl f,%edx
  953. {addl $filerec.name,%edx Doesn't work!!}
  954. addl $60,%edx
  955. call syscall
  956. movl attr,%ebx
  957. movw %cx,(%ebx)
  958. xorb %ah,%ah
  959. movw %ax,doserror
  960. end;
  961. procedure setfattr(var f;attr : word);assembler;
  962. asm
  963. movw $0x4301,%ax
  964. movl f,%edx
  965. {addl $filerec.name,%edx Doesn't work!!}
  966. addl $60,%edx
  967. movw attr,%cx
  968. call syscall
  969. xorb %ah,%ah
  970. movw %ax,doserror
  971. end;
  972. end.
  973. {
  974. $Log$
  975. Revision 1.4 2000-10-28 16:58:34 hajny
  976. * many FExpand fixes
  977. Revision 1.3 2000/09/29 21:49:41 jonas
  978. * removed warnings
  979. Revision 1.2 2000/07/14 10:33:10 michael
  980. + Conditionals fixed
  981. Revision 1.1 2000/07/13 06:31:04 michael
  982. + Initial import
  983. }