dos.pas 28 KB

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