dos.pas 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  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, DosCalls;
  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. FStat:PFileFindBuf3;
  52. fill2:array[1..21-SizeOf(longint)-SizeOf(pointer)] of byte;
  53. attr2:byte;
  54. time2:longint;
  55. size2:longint;
  56. name2:string); {Filenames can be long in OS/2!}
  57. true: (fill:array[1..21] of byte;
  58. attr:byte;
  59. time:longint;
  60. size:longint;
  61. name:string); {Filenames can be long in OS/2!}
  62. end;
  63. {$i filerec.inc}
  64. {$i textrec.inc}
  65. {Data structure for the registers needed by msdos and intr:}
  66. registers=packed record
  67. case i:integer of
  68. 0:(ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,
  69. f8,flags,fs,gs:word);
  70. 1:(al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh:byte);
  71. 2:(eax,ebx,ecx,edx,ebp,esi,edi:longint);
  72. end;
  73. {Record for date and time:}
  74. datetime=record
  75. year,month,day,hour,min,sec:word;
  76. end;
  77. {Flags for the exec procedure:
  78. Starting the program:
  79. efwait: Wait until program terminates.
  80. efno_wait: Don't wait until the program terminates. Does not work
  81. in dos, as DOS cannot multitask.
  82. efoverlay: Terminate this program, then execute the requested
  83. program. WARNING: Exit-procedures are not called!
  84. efdebug: Debug program. Details are unknown.
  85. efsession: Do not execute as child of this program. Use a seperate
  86. session instead.
  87. efdetach: Detached. Function unknown. Info wanted!
  88. efpm: Run as presentation manager program.
  89. Determining the window state of the program:
  90. efdefault: Run the pm program in it's default situation.
  91. efminimize: Run the pm program minimized.
  92. efmaximize: Run the pm program maximized.
  93. effullscreen: Run the non-pm program fullscreen.
  94. efwindowed: Run the non-pm program in a window.
  95. Other options are not implemented defined because lack of
  96. knowledge about what they do.}
  97. type execrunflags=(efwait,efno_wait,efoverlay,efdebug,efsession,
  98. efdetach,efpm);
  99. execwinflags=(efdefault,efminimize,efmaximize,effullscreen,
  100. efwindowed);
  101. const
  102. (* For compatibility with VP/2, used for runflags in Exec procedure. *)
  103. ExecFlags: cardinal = ord (efwait);
  104. var doserror:integer;
  105. dosexitcode:word;
  106. procedure getdate(var year,month,day,dayofweek:word);
  107. procedure gettime(var hour,minute,second,sec100:word);
  108. function dosversion:word;
  109. procedure setdate(year,month,day:word);
  110. procedure settime(hour,minute,second,sec100:word);
  111. procedure getcbreak(var breakvalue:boolean);
  112. procedure setcbreak(breakvalue:boolean);
  113. procedure getverify(var verify:boolean);
  114. procedure setverify(verify : boolean);
  115. function DiskFree (Drive: byte) : int64;
  116. function DiskSize (Drive: byte) : int64;
  117. procedure findfirst(const path:pathstr;attr:word;var f:searchRec);
  118. procedure findnext(var f:searchRec);
  119. procedure findclose(var f:searchRec);
  120. {Is a dummy:}
  121. procedure swapvectors;
  122. {Not supported:
  123. procedure getintvec(intno:byte;var vector:pointer);
  124. procedure setintvec(intno:byte;vector:pointer);
  125. procedure keep(exitcode:word);
  126. }
  127. procedure msdos(var regs:registers);
  128. procedure intr(intno : byte;var regs:registers);
  129. procedure getfattr(var f;var attr:word);
  130. procedure setfattr(var f;attr:word);
  131. function fsearch(path:pathstr;dirlist:string):pathstr;
  132. procedure getftime(var f;var time:longint);
  133. procedure setftime(var f;time:longint);
  134. procedure packtime (var d:datetime; var time:longint);
  135. procedure unpacktime (time:longint; var d:datetime);
  136. function fexpand(const path:pathstr):pathstr;
  137. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  138. var ext:extstr);
  139. procedure exec(const path:pathstr;const comline:comstr);
  140. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  141. const comline:comstr):longint;
  142. function envcount:longint;
  143. function envstr(index:longint) : string;
  144. function getenv(const envvar:string): string;
  145. implementation
  146. var LastSR: SearchRec;
  147. EnvC: longint; external name '_envc';
  148. EnvP: ppchar; external name '_environ';
  149. type TBA = array [1..SizeOf (SearchRec)] of byte;
  150. PBA = ^TBA;
  151. const FindResvdMask = $00003737; {Allowed bits in attribute
  152. specification for DosFindFirst call.}
  153. {Import syscall to call it nicely from assembler procedures.}
  154. procedure syscall;external name '___SYSCALL';
  155. function fsearch(path:pathstr;dirlist:string):pathstr;
  156. var i,p1:longint;
  157. newdir:pathstr;
  158. {$ASMMODE INTEL}
  159. function CheckFile (FN: ShortString):boolean; assembler;
  160. asm
  161. mov ax, 4300h
  162. mov edx, FN { get pointer to string }
  163. inc edx { avoid length byte }
  164. call syscall
  165. mov ax, 0
  166. jc @LCFstop
  167. test cx, 18h
  168. jnz @LCFstop
  169. inc ax
  170. @LCFstop:
  171. end;
  172. {$ASMMODE ATT}
  173. begin
  174. { check if the file specified exists }
  175. if CheckFile (Path + #0) then
  176. FSearch := Path
  177. else
  178. begin
  179. {No wildcards allowed in these things:}
  180. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  181. fsearch:=''
  182. else
  183. begin
  184. { allow slash as backslash }
  185. for i:=1 to length(dirlist) do
  186. if dirlist[i]='/' then dirlist[i]:='\';
  187. repeat
  188. p1:=pos(';',dirlist);
  189. if p1<>0 then
  190. begin
  191. newdir:=copy(dirlist,1,p1-1);
  192. delete(dirlist,1,p1);
  193. end
  194. else
  195. begin
  196. newdir:=dirlist;
  197. dirlist:='';
  198. end;
  199. if (newdir<>'') and
  200. not (newdir[length(newdir)] in ['\',':']) then
  201. newdir:=newdir+'\';
  202. if CheckFile (NewDir + Path + #0) then
  203. NewDir := NewDir + Path
  204. else
  205. NewDir := '';
  206. until (DirList = '') or (NewDir <> '');
  207. FSearch := NewDir;
  208. end;
  209. end;
  210. end;
  211. procedure getftime(var f;var time:longint);
  212. begin
  213. asm
  214. {Load handle}
  215. movl f,%ebx
  216. movl (%ebx),%ebx
  217. {Get date}
  218. movw $0x5700,%ax
  219. call syscall
  220. shll $16,%edx
  221. movw %cx,%dx
  222. movl time,%ebx
  223. movl %edx,(%ebx)
  224. xorb %ah,%ah
  225. movw %ax,doserror
  226. end;
  227. end;
  228. procedure SetFTime (var F; Time: longint);
  229. var FStat: PFileStatus3;
  230. RC: longint;
  231. begin
  232. if os_mode = osOS2 then
  233. begin
  234. New (FStat);
  235. RC := DosQueryFileInfo (FileRec (F).Handle, ilStandard, FStat,
  236. SizeOf (FStat^));
  237. if RC = 0 then
  238. begin
  239. FStat^.DateLastAccess := Hi (Time);
  240. FStat^.DateLastWrite := Hi (Time);
  241. FStat^.TimeLastAccess := Lo (Time);
  242. FStat^.TimeLastWrite := Lo (Time);
  243. RC := DosSetFileInfo (FileRec (F).Handle, ilStandard,
  244. FStat, SizeOf (FStat^));
  245. end;
  246. DosError := integer(RC);
  247. Dispose (FStat);
  248. end
  249. else
  250. asm
  251. {Load handle}
  252. movl f,%ebx
  253. movl (%ebx),%ebx
  254. movl time,%ecx
  255. shldl $16,%ecx,%edx
  256. {Set date}
  257. movw $0x5701,%ax
  258. call syscall
  259. xorb %ah,%ah
  260. movw %ax,doserror
  261. end;
  262. end;
  263. procedure msdos(var regs:registers);
  264. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  265. begin
  266. if os_mode in [osDPMI,osDOS] then
  267. intr($21,regs);
  268. end;
  269. procedure intr(intno:byte;var regs:registers);
  270. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  271. begin
  272. if os_mode = osos2 then exit;
  273. asm
  274. jmp .Lstart
  275. { .data}
  276. .Lint86:
  277. .byte 0xcd
  278. .Lint86_vec:
  279. .byte 0x03
  280. jmp .Lint86_retjmp
  281. { .text}
  282. .Lstart:
  283. movb intno,%al
  284. movb %al,.Lint86_vec
  285. {
  286. movl 10(%ebp),%eax
  287. incl %eax
  288. incl %eax
  289. }
  290. movl regs,%eax
  291. {Do not use first int}
  292. movl 4(%eax),%ebx
  293. movl 8(%eax),%ecx
  294. movl 12(%eax),%edx
  295. movl 16(%eax),%ebp
  296. movl 20(%eax),%esi
  297. movl 24(%eax),%edi
  298. movl (%eax),%eax
  299. jmp .Lint86
  300. .Lint86_retjmp:
  301. pushf
  302. pushl %ebp
  303. pushl %eax
  304. movl %esp,%ebp
  305. {Calc EBP new}
  306. addl $12,%ebp
  307. {
  308. movl 10(%ebp),%eax
  309. incl %eax
  310. incl %eax
  311. }
  312. {Do not use first int}
  313. movl regs,%eax
  314. popl (%eax)
  315. movl %ebx,4(%eax)
  316. movl %ecx,8(%eax)
  317. movl %edx,12(%eax)
  318. {Restore EBP}
  319. popl %edx
  320. movl %edx,16(%eax)
  321. movl %esi,20(%eax)
  322. movl %edi,24(%eax)
  323. {Ignore ES and DS}
  324. popl %ebx {Flags.}
  325. movl %ebx,32(%eax)
  326. {FS and GS too}
  327. end;
  328. end;
  329. procedure exec(const path:pathstr;const comline:comstr);
  330. {Execute a program.}
  331. begin
  332. dosexitcode:=word(exec(path,execrunflags(ExecFlags),efdefault,comline));
  333. end;
  334. function exec(path:pathstr;runflags:execrunflags;winflags:execwinflags;
  335. const comline:comstr):longint;
  336. {Execute a program. More suitable for OS/2 than the exec above.}
  337. type bytearray=array[0..8191] of byte;
  338. Pbytearray=^bytearray;
  339. execstruc=packed record
  340. argofs : pointer; { pointer to arguments (offset) }
  341. envofs : pointer; { pointer to environment (offset) }
  342. nameofs: pointer; { pointer to file name (offset) }
  343. argseg : word; { pointer to arguments (selector) }
  344. envseg : word; { pointer to environment (selector}
  345. nameseg: word; { pointer to file name (selector) }
  346. numarg : word; { number of arguments }
  347. sizearg : word; { size of arguments }
  348. numenv : word; { number of env strings }
  349. sizeenv:word; { size of environment }
  350. mode1,mode2:byte; { mode byte }
  351. end;
  352. var args:Pbytearray;
  353. env:Pbytearray;
  354. i,argsize:word;
  355. es:execstruc;
  356. esadr:pointer;
  357. d:dirstr;
  358. n:namestr;
  359. e:extstr;
  360. p : ppchar;
  361. j : integer;
  362. const
  363. ArgsSize = 2048; (* Amount of memory reserved for arguments in bytes. *)
  364. begin
  365. getmem(args,ArgsSize);
  366. GetMem(env, envc*sizeof(pchar)+16384);
  367. {Now setup the arguments. The first argument should be the program
  368. name without directory and extension.}
  369. fsplit(path,d,n,e);
  370. es.numarg:=1;
  371. args^[0]:=$80;
  372. argsize:=1;
  373. for i:=1 to length(n) do
  374. begin
  375. args^[argsize]:=byte(n[i]);
  376. inc(argsize);
  377. end;
  378. args^[argsize]:=0;
  379. inc(argsize);
  380. {Now do the real arguments.}
  381. i:=1;
  382. while i<=length(comline) do
  383. begin
  384. if comline[i]<>' ' then
  385. begin
  386. {Commandline argument found. Copy it.}
  387. inc(es.numarg);
  388. args^[argsize]:=$80;
  389. inc(argsize);
  390. while (i<=length(comline)) and (comline[i]<>' ') do
  391. begin
  392. args^[argsize]:=byte(comline[i]);
  393. inc(argsize);
  394. inc(i);
  395. end;
  396. args^[argsize]:=0;
  397. inc(argsize);
  398. end;
  399. inc(i);
  400. end;
  401. args^[argsize]:=0;
  402. inc(argsize);
  403. {Commandline ready, now build the environment.
  404. Oh boy, I always had the opinion that executing a program under Dos
  405. was a hard job!}
  406. asm
  407. movl env,%edi {Setup destination pointer.}
  408. movl envc,%ecx {Load number of arguments in edx.}
  409. movl envp,%esi {Load env. strings.}
  410. xorl %edx,%edx {Count environment size.}
  411. .Lexa1:
  412. lodsl {Load a Pchar.}
  413. xchgl %eax,%ebx
  414. .Lexa2:
  415. movb (%ebx),%al {Load a byte.}
  416. incl %ebx {Point to next byte.}
  417. stosb {Store it.}
  418. incl %edx {Increase counter.}
  419. cmpb $0,%al {Ready ?.}
  420. jne .Lexa2
  421. loop .Lexa1 {Next argument.}
  422. stosb {Store an extra 0 to finish. (AL is now 0).}
  423. incl %edx
  424. movw %dx,ES.SizeEnv {Store environment size.}
  425. end;
  426. {Environment ready, now set-up exec structure.}
  427. es.argofs:=args;
  428. es.envofs:=env;
  429. es.numenv:=envc;
  430. { set an error - path is too long }
  431. { since we must add a zero to the }
  432. { end. }
  433. if length(path) > 254 then
  434. begin
  435. exec := 8;
  436. exit;
  437. end;
  438. path[length(path)+1] := #0;
  439. es.nameofs:=pointer(longint(@path)+1);
  440. asm
  441. movw %ss,es.argseg
  442. movw %ss,es.envseg
  443. movw %ss,es.nameseg
  444. end;
  445. es.sizearg:=argsize;
  446. {Typecasting of sets in FPC is a bit hard.}
  447. es.mode1:=byte(runflags);
  448. es.mode2:=byte(winflags);
  449. {Now exec the program.}
  450. asm
  451. leal es,%edx
  452. movw $0x7f06,%ax
  453. call syscall
  454. movl $0,%edi
  455. jnc .Lexprg1
  456. xchgl %eax,%edi
  457. xorl %eax,%eax
  458. decl %eax
  459. .Lexprg1:
  460. movw %di,doserror
  461. movl %eax,__RESULT
  462. end;
  463. freemem(args,ArgsSize);
  464. FreeMem(env, envc*sizeof(pchar)+16384);
  465. {Phew! That's it. This was the most sophisticated procedure to call
  466. a system function I ever wrote!}
  467. end;
  468. function dosversion:word;assembler;
  469. {Returns DOS version in DOS and OS/2 version in OS/2}
  470. asm
  471. movb $0x30,%ah
  472. call syscall
  473. end;
  474. procedure GetDate (var Year, Month, Day, DayOfWeek: word);
  475. begin
  476. asm
  477. movb $0x2a, %ah
  478. call syscall
  479. xorb %ah, %ah
  480. movl DayOfWeek, %edi
  481. stosw
  482. movl Day, %edi
  483. movb %dl, %al
  484. stosw
  485. movl Month, %edi
  486. movb %dh, %al
  487. stosw
  488. movl Year, %edi
  489. xchgw %ecx, %eax
  490. stosw
  491. end;
  492. end;
  493. {$asmmode intel}
  494. procedure SetDate (Year, Month, Day: word);
  495. var DT: TDateTime;
  496. begin
  497. if os_mode = osOS2 then
  498. begin
  499. DosGetDateTime (DT);
  500. DT.Year := Year;
  501. DT.Month := byte (Month);
  502. DT.Day := byte (Day);
  503. DosSetDateTime (DT);
  504. end
  505. else
  506. asm
  507. mov cx, Year
  508. mov dh, byte ptr Month
  509. mov dl, byte ptr Day
  510. mov ah, 2Bh
  511. call syscall
  512. end;
  513. end;
  514. {$asmmode att}
  515. procedure GetTime (var Hour, Minute, Second, Sec100: word); assembler;
  516. asm
  517. movb $0x2c, %ah
  518. call syscall
  519. xorb %ah, %ah
  520. movl Sec100, %edi
  521. movb %dl, %al
  522. stosw
  523. movl Second, %edi
  524. movb %dh,%al
  525. stosw
  526. movl Minute, %edi
  527. movb %cl,%al
  528. stosw
  529. movl Hour, %edi
  530. movb %ch,%al
  531. stosw
  532. end;
  533. {$asmmode intel}
  534. procedure SetTime (Hour, Minute, Second, Sec100: word);
  535. var DT: TDateTime;
  536. begin
  537. if os_mode = osOS2 then
  538. begin
  539. DosGetDateTime (DT);
  540. DT.Hour := byte (Hour);
  541. DT.Minute := byte (Minute);
  542. DT.Second := byte (Second);
  543. DT.Sec100 := byte (Sec100);
  544. DosSetDateTime (DT);
  545. end
  546. else
  547. asm
  548. mov ch, byte ptr Hour
  549. mov cl, byte ptr Minute
  550. mov dh, byte ptr Second
  551. mov dl, byte ptr Sec100
  552. mov ah, 2Dh
  553. call syscall
  554. end;
  555. end;
  556. {$asmmode att}
  557. procedure getcbreak(var breakvalue:boolean);
  558. begin
  559. breakvalue := True;
  560. end;
  561. procedure setcbreak(breakvalue:boolean);
  562. begin
  563. {! Do not use in OS/2. Also not recommended in DOS. Use
  564. signal handling instead.
  565. asm
  566. movb 8(%ebp),%dl
  567. movw $0x3301,%ax
  568. call syscall
  569. end;
  570. }
  571. end;
  572. procedure getverify(var verify:boolean);
  573. begin
  574. {! Do not use in OS/2.}
  575. if os_mode in [osDOS,osDPMI] then
  576. asm
  577. movb $0x54,%ah
  578. call syscall
  579. movl verify,%edi
  580. stosb
  581. end
  582. else
  583. verify := true;
  584. end;
  585. procedure setverify(verify:boolean);
  586. begin
  587. {! Do not use in OS/2!}
  588. if os_mode in [osDOS,osDPMI] then
  589. asm
  590. movb verify,%al
  591. movb $0x2e,%ah
  592. call syscall
  593. end;
  594. end;
  595. function DiskFree (Drive: byte): int64;
  596. var FI: TFSinfo;
  597. RC: longint;
  598. begin
  599. if (os_mode = osDOS) or (os_mode = osDPMI) then
  600. {Function 36 is not supported in OS/2.}
  601. asm
  602. movb Drive,%dl
  603. movb $0x36,%ah
  604. call syscall
  605. cmpw $-1,%ax
  606. je .LDISKFREE1
  607. mulw %cx
  608. mulw %bx
  609. shll $16,%edx
  610. movw %ax,%dx
  611. movl $0,%eax
  612. xchgl %edx,%eax
  613. leave
  614. ret
  615. .LDISKFREE1:
  616. cltd
  617. leave
  618. ret
  619. end
  620. else
  621. {In OS/2, we use the filesystem information.}
  622. begin
  623. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  624. if RC = 0 then
  625. DiskFree := int64 (FI.Free_Clusters) *
  626. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  627. else
  628. DiskFree := -1;
  629. end;
  630. end;
  631. function DiskSize (Drive: byte): int64;
  632. var FI: TFSinfo;
  633. RC: longint;
  634. begin
  635. if (os_mode = osDOS) or (os_mode = osDPMI) then
  636. {Function 36 is not supported in OS/2.}
  637. asm
  638. movb Drive,%dl
  639. movb $0x36,%ah
  640. call syscall
  641. movw %dx,%bx
  642. cmpw $-1,%ax
  643. je .LDISKSIZE1
  644. mulw %cx
  645. mulw %bx
  646. shll $16,%edx
  647. movw %ax,%dx
  648. movl $0,%eax
  649. xchgl %edx,%eax
  650. leave
  651. ret
  652. .LDISKSIZE1:
  653. cltd
  654. leave
  655. ret
  656. end
  657. else
  658. {In OS/2, we use the filesystem information.}
  659. begin
  660. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  661. if RC = 0 then
  662. DiskSize := int64 (FI.Total_Clusters) *
  663. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  664. else
  665. DiskSize := -1;
  666. end;
  667. end;
  668. procedure SearchRec2DosSearchRec (var F: SearchRec);
  669. const NameSize = 255;
  670. var L, I: longint;
  671. begin
  672. if os_mode <> osOS2 then
  673. begin
  674. I := 1;
  675. while (I <= SizeOf (LastSR))
  676. and (PBA (@F)^ [I] = PBA (@LastSR)^ [I]) do Inc (I);
  677. { Raise "Invalid file handle" RTE if nested FindFirst calls were used. }
  678. if I <= SizeOf (LastSR) then RunError (6);
  679. l:=length(f.name);
  680. for i:=1 to namesize do
  681. f.name[i-1]:=f.name[i];
  682. f.name[l]:=#0;
  683. end;
  684. end;
  685. procedure DosSearchRec2SearchRec (var F: SearchRec);
  686. const NameSize=255;
  687. var L, I: longint;
  688. type TRec = record
  689. T, D: word;
  690. end;
  691. begin
  692. if os_mode = osOS2 then with F do
  693. begin
  694. Name := FStat^.Name;
  695. Size := FStat^.FileSize;
  696. Attr := byte(FStat^.AttrFile and $FF);
  697. TRec (Time).T := FStat^.TimeLastWrite;
  698. TRec (Time).D := FStat^.DateLastWrite;
  699. end else
  700. begin
  701. for i:=0 to namesize do
  702. if f.name[i]=#0 then
  703. begin
  704. l:=i;
  705. break;
  706. end;
  707. for i:=namesize-1 downto 0 do
  708. f.name[i+1]:=f.name[i];
  709. f.name[0]:=char(l);
  710. Move (F, LastSR, SizeOf (LastSR));
  711. end;
  712. end;
  713. procedure _findfirst(path:pchar;attr:word;var f:searchrec);
  714. begin
  715. asm
  716. movl path,%edx
  717. movw attr,%cx
  718. {No need to set DTA in EMX. Just give a pointer in ESI.}
  719. movl f,%esi
  720. movb $0x4e,%ah
  721. call syscall
  722. jnc .LFF
  723. movw %ax,doserror
  724. .LFF:
  725. end;
  726. end;
  727. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  728. var path0: array[0..255] of char;
  729. Count: longint;
  730. begin
  731. {No error.}
  732. DosError := 0;
  733. if os_mode = osOS2 then
  734. begin
  735. New (F.FStat);
  736. F.Handle := $FFFFFFFF;
  737. Count := 1;
  738. DosError := Integer(DosFindFirst (Path, F.Handle,
  739. Attr and FindResvdMask, F.FStat, SizeOf (F.FStat^),
  740. Count, ilStandard));
  741. if (DosError = 0) and (Count = 0) then DosError := 18;
  742. end else
  743. begin
  744. strPcopy(path0,path);
  745. _findfirst(path0,attr,f);
  746. end;
  747. DosSearchRec2SearchRec (F);
  748. end;
  749. procedure _findnext(var f : searchrec);
  750. begin
  751. asm
  752. movl f,%esi
  753. movb $0x4f,%ah
  754. call syscall
  755. jnc .LFN
  756. movw %ax,doserror
  757. .LFN:
  758. end;
  759. end;
  760. procedure FindNext (var F: SearchRec);
  761. var Count: longint;
  762. begin
  763. {No error}
  764. DosError := 0;
  765. SearchRec2DosSearchRec (F);
  766. if os_mode = osOS2 then
  767. begin
  768. Count := 1;
  769. DosError := Integer(DosFindNext (F.Handle, F.FStat, SizeOf (F.FStat^), Count));
  770. if (DosError = 0) and (Count = 0) then DosError := 18;
  771. end else _findnext (F);
  772. DosSearchRec2SearchRec (F);
  773. end;
  774. procedure FindClose (var F: SearchRec);
  775. begin
  776. if os_mode = osOS2 then
  777. begin
  778. if F.Handle <> $FFFFFFFF then DosError := DosFindClose (F.Handle);
  779. Dispose (F.FStat);
  780. end;
  781. end;
  782. procedure swapvectors;
  783. {For TP compatibility, this exists.}
  784. begin
  785. end;
  786. function envcount:longint;assembler;
  787. asm
  788. movl envc,%eax
  789. end ['EAX'];
  790. function envstr(index : longint) : string;
  791. var hp:Pchar;
  792. begin
  793. if (index<=0) or (index>envcount) then
  794. begin
  795. envstr:='';
  796. exit;
  797. end;
  798. hp:=EnvP[index-1];
  799. envstr:=strpas(hp);
  800. end;
  801. function GetEnv (const EnvVar: string): string;
  802. (* The assembler version is more than three times as fast as Pascal. *)
  803. var
  804. P: PChar;
  805. _EnvVar: string;
  806. begin
  807. _EnvVar := UpCase (EnvVar);
  808. {$ASMMODE INTEL}
  809. asm
  810. cld
  811. mov ecx, EnvC
  812. mov edi, EnvP
  813. mov edi, [edi]
  814. lea esi, _EnvVar
  815. xor eax, eax
  816. lodsb
  817. @NewVar:
  818. push ecx
  819. push eax
  820. push esi
  821. mov ecx, -1
  822. mov edx, edi
  823. mov al, '='
  824. repne
  825. scasb
  826. neg ecx
  827. dec ecx
  828. dec ecx
  829. pop esi
  830. pop eax
  831. push eax
  832. push esi
  833. cmp ecx, eax
  834. jnz @NotEqual
  835. xchg edx, edi
  836. repe
  837. cmpsb
  838. xchg edx, edi
  839. jz @Equal
  840. @NotEqual:
  841. xor eax, eax
  842. mov ecx, -1
  843. repne
  844. scasb
  845. pop esi
  846. pop eax
  847. pop ecx
  848. dec ecx
  849. jecxz @Stop
  850. jmp @NewVar
  851. @Stop:
  852. mov P, ecx
  853. jmp @End
  854. @Equal:
  855. pop esi
  856. pop eax
  857. pop ecx
  858. mov P, edi
  859. @End:
  860. end;
  861. GetEnv := StrPas (P);
  862. end;
  863. {$ASMMODE ATT}
  864. procedure fsplit(path:pathstr;var dir:dirstr;var name:namestr;
  865. var ext:extstr);
  866. var p1,i : longint;
  867. dotpos : integer;
  868. begin
  869. { allow slash as backslash }
  870. for i:=1 to length(path) do
  871. if path[i]='/' then path[i]:='\';
  872. {Get drive name}
  873. p1:=pos(':',path);
  874. if p1>0 then
  875. begin
  876. dir:=path[1]+':';
  877. delete(path,1,p1);
  878. end
  879. else
  880. dir:='';
  881. { split the path and the name, there are no more path informtions }
  882. { if path contains no backslashes }
  883. while true do
  884. begin
  885. p1:=pos('\',path);
  886. if p1=0 then
  887. break;
  888. dir:=dir+copy(path,1,p1);
  889. delete(path,1,p1);
  890. end;
  891. { try to find out a extension }
  892. Ext:='';
  893. i:=Length(Path);
  894. DotPos:=256;
  895. While (i>0) Do
  896. Begin
  897. If (Path[i]='.') Then
  898. begin
  899. DotPos:=i;
  900. break;
  901. end;
  902. Dec(i);
  903. end;
  904. Ext:=Copy(Path,DotPos,255);
  905. Name:=Copy(Path,1,DotPos - 1);
  906. end;
  907. (*
  908. function FExpand (const Path: PathStr): PathStr;
  909. - declared in fexpand.inc
  910. *)
  911. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  912. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  913. const
  914. LFNSupport = true;
  915. {$I fexpand.inc}
  916. {$UNDEF FPC_FEXPAND_DRIVES}
  917. {$UNDEF FPC_FEXPAND_UNC}
  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);
  950. { Under EMX, this routine requires }
  951. { the expanded path specification }
  952. { otherwise it will not function }
  953. { properly (CEC) }
  954. var
  955. path: pathstr;
  956. buffer:array[0..255] of char;
  957. begin
  958. DosError := 0;
  959. path:='';
  960. path := StrPas(filerec(f).Name);
  961. { Takes care of slash and backslash support }
  962. path:=FExpand(path);
  963. move(path[1],buffer,length(path));
  964. buffer[length(path)]:=#0;
  965. asm
  966. movw $0x4300,%ax
  967. leal buffer,%edx
  968. call syscall
  969. jnc .Lnoerror { is there an error ? }
  970. movw %ax,doserror
  971. .Lnoerror:
  972. movl attr,%ebx
  973. movw %cx,(%ebx)
  974. end;
  975. end;
  976. procedure setfattr(var f;attr : word);
  977. { Under EMX, this routine requires }
  978. { the expanded path specification }
  979. { otherwise it will not function }
  980. { properly (CEC) }
  981. var
  982. path: pathstr;
  983. buffer:array[0..255] of char;
  984. begin
  985. path:='';
  986. DosError := 0;
  987. path := StrPas(filerec(f).Name);
  988. { Takes care of slash and backslash support }
  989. path:=FExPand(path);
  990. move(path[1],buffer,length(path));
  991. buffer[length(path)]:=#0;
  992. asm
  993. movw $0x4301,%ax
  994. leal buffer,%edx
  995. movw attr,%cx
  996. call syscall
  997. jnc .Lnoerror
  998. movw %ax,doserror
  999. .Lnoerror:
  1000. end;
  1001. end;
  1002. procedure InitEnvironment;
  1003. var
  1004. cnt : integer;
  1005. ptr : pchar;
  1006. base : pchar;
  1007. i: integer;
  1008. tib : pprocessinfoblock;
  1009. begin
  1010. { We need to setup the environment }
  1011. { only in the case of OS/2 }
  1012. { otherwise everything is in the stack }
  1013. if os_Mode in [OsDOS,osDPMI] then
  1014. exit;
  1015. cnt := 0;
  1016. { count number of environment pointers }
  1017. dosgetinfoblocks (nil, PPProcessInfoBlock (@tib));
  1018. ptr := pchar(tib^.env);
  1019. { stringz,stringz...,#0 }
  1020. i := 0;
  1021. repeat
  1022. repeat
  1023. (inc(i));
  1024. until (ptr[i] = #0);
  1025. inc(i);
  1026. { here, it may be a double null, end of environment }
  1027. if ptr[i] <> #0 then
  1028. inc(cnt);
  1029. until (ptr[i] = #0);
  1030. { save environment count }
  1031. envc := cnt;
  1032. { got count of environment strings }
  1033. GetMem(envp, cnt*sizeof(pchar)+16384);
  1034. cnt := 0;
  1035. ptr := pchar(tib^.env);
  1036. i:=0;
  1037. repeat
  1038. envp[cnt] := ptr;
  1039. Inc(cnt);
  1040. { go to next string ... }
  1041. repeat
  1042. inc(ptr);
  1043. until (ptr^ = #0);
  1044. inc(ptr);
  1045. until ptr^ = #0;
  1046. envp[cnt] := #0;
  1047. end;
  1048. procedure DoneEnvironment;
  1049. begin
  1050. { it is allocated on the stack for DOS/DPMI }
  1051. if os_mode = osOs2 then
  1052. FreeMem(envp, envc*sizeof(pchar)+16384);
  1053. end;
  1054. var
  1055. oldexit : pointer;
  1056. begin
  1057. oldexit:=exitproc;
  1058. exitproc:=@doneenvironment;
  1059. InitEnvironment;
  1060. end.
  1061. {
  1062. $Log$
  1063. Revision 1.19 2002-09-07 16:01:24 peter
  1064. * old logs removed and tabs fixed
  1065. Revision 1.18 2002/07/11 16:00:05 hajny
  1066. * FindFirst fix (invalid attribute bits masked out)
  1067. Revision 1.17 2002/07/07 18:00:48 hajny
  1068. * DosGetInfoBlock modification to allow overloaded version (in DosCalls)
  1069. Revision 1.16 2002/03/03 11:19:20 hajny
  1070. * GetEnv rewritten to assembly - 3x faster now
  1071. }