dos.pas 32 KB

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