dos.pas 32 KB

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