dos.pas 32 KB

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