dos.pas 32 KB

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