2
0

dos.pas 33 KB

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