dos.pas 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  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. Type
  21. {Search record which is used by findfirst and findnext:}
  22. searchrec=record
  23. case boolean of
  24. false: (handle:THandle; {Used in os_OS2 mode}
  25. FStat:PFileFindBuf3;
  26. fill2:array[1..21-SizeOf(THandle)-SizeOf(pointer)] of byte;
  27. attr2:byte;
  28. time2:longint;
  29. size2:longint;
  30. name2:string); {Filenames can be long in OS/2!}
  31. true: (fill:array[1..21] of byte;
  32. attr:byte;
  33. time:longint;
  34. size:longint;
  35. name:string); {Filenames can be long in OS/2!}
  36. end;
  37. {$i dosh.inc}
  38. {Flags for the exec procedure:
  39. Starting the program:
  40. efwait: Wait until program terminates.
  41. efno_wait: Don't wait until the program terminates. Does not work
  42. in dos, as DOS cannot multitask.
  43. efoverlay: Terminate this program, then execute the requested
  44. program. WARNING: Exit-procedures are not called!
  45. efdebug: Debug program. Details are unknown.
  46. efsession: Do not execute as child of this program. Use a seperate
  47. session instead.
  48. efdetach: Detached. Function unknown. Info wanted!
  49. efpm: Run as presentation manager program.
  50. Not found info about execwinflags
  51. Determining the window state of the program:
  52. efdefault: Run the pm program in it's default situation.
  53. efminimize: Run the pm program minimized.
  54. efmaximize: Run the pm program maximized.
  55. effullscreen: Run the non-pm program fullscreen.
  56. efwindowed: Run the non-pm program in a window.
  57. }
  58. const
  59. efWait = 0; (* Spawn child, wait until terminated *)
  60. efNo_Wait = 1; (* Not implemented according to EMX documentation! *)
  61. efOverlay = 2; (* Exec child, kill current process *)
  62. efDebug = 3; (* Debug child - use with ptrace syscall *)
  63. efSession = 4; (* Run in a separate session *)
  64. efDetach = 5; (* Run detached *)
  65. efPM = 6; (* Run as a PM program *)
  66. efDefault = 0;
  67. efMinimize = $100;
  68. efMaximize = $200;
  69. efFullScreen = $300;
  70. efWindowed = $400;
  71. efBackground = $1000;
  72. efNoClose = $2000;
  73. efNoSession = $4000;
  74. efMoreFlags = $8000; (* Needed if any flags > $FFFF are supplied *)
  75. efQuote = $10000;
  76. efTilde = $20000;
  77. efDebugDesc = $40000;
  78. {OS/2 specific functions}
  79. function GetEnvPChar (EnvVar: string): PChar;
  80. {$ifdef HASTHREADVAR}
  81. threadvar
  82. {$else HASTHREADVAR}
  83. var
  84. {$endif HASTHREADVAR}
  85. (* For compatibility with VP/2, used for runflags in Exec procedure. *)
  86. ExecFlags: cardinal;
  87. implementation
  88. {$DEFINE HAS_INTR}
  89. {$DEFINE HAS_SETVERIFY}
  90. {$DEFINE HAS_GETVERIFY}
  91. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  92. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  93. const
  94. LFNSupport = true;
  95. {$I dos.inc}
  96. {$ifdef HASTHREADVAR}
  97. threadvar
  98. {$else HASTHREADVAR}
  99. var
  100. {$endif HASTHREADVAR}
  101. LastSR: SearchRec;
  102. var
  103. EnvC: longint; external name '_envc';
  104. EnvP: ppchar; external name '_environ';
  105. type
  106. TBA = array [1..SizeOf (SearchRec)] of byte;
  107. PBA = ^TBA;
  108. const
  109. FindResvdMask = $00003737; {Allowed bits in attribute
  110. specification for DosFindFirst call.}
  111. {Import syscall to call it nicely from assembler procedures.}
  112. procedure syscall;external name '___SYSCALL';
  113. function fsearch(path:pathstr;dirlist:string):pathstr;
  114. var i,p1:longint;
  115. newdir:pathstr;
  116. {$ASMMODE INTEL}
  117. function CheckFile (FN: ShortString):boolean; assembler;
  118. asm
  119. {$IFDEF REGCALL}
  120. mov edx, eax
  121. {$ELSE REGCALL}
  122. mov edx, FN { get pointer to string }
  123. {$ENDIF REGCALL}
  124. inc edx { avoid length byte }
  125. mov ax, 4300h
  126. call syscall
  127. mov ax, 0
  128. jc @LCFstop
  129. test cx, 18h
  130. jnz @LCFstop
  131. inc ax
  132. @LCFstop:
  133. end ['eax', 'ecx', 'edx'];
  134. {$ASMMODE ATT}
  135. begin
  136. { check if the file specified exists }
  137. if CheckFile (Path + #0) then
  138. FSearch := Path
  139. else
  140. begin
  141. {No wildcards allowed in these things:}
  142. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  143. fsearch:=''
  144. else
  145. begin
  146. { allow slash as backslash }
  147. for i:=1 to length(dirlist) do
  148. if dirlist[i]='/' then dirlist[i]:='\';
  149. repeat
  150. p1:=pos(';',dirlist);
  151. if p1<>0 then
  152. begin
  153. newdir:=copy(dirlist,1,p1-1);
  154. delete(dirlist,1,p1);
  155. end
  156. else
  157. begin
  158. newdir:=dirlist;
  159. dirlist:='';
  160. end;
  161. if (newdir<>'') and
  162. not (newdir[length(newdir)] in ['\',':']) then
  163. newdir:=newdir+'\';
  164. if CheckFile (NewDir + Path + #0) then
  165. NewDir := NewDir + Path
  166. else
  167. NewDir := '';
  168. until (DirList = '') or (NewDir <> '');
  169. FSearch := NewDir;
  170. end;
  171. end;
  172. end;
  173. procedure GetFTime (var F; var Time: longint); assembler;
  174. asm
  175. pushl %ebx
  176. {Load handle}
  177. {$IFDEF REGCALL}
  178. movl %eax,%ebx
  179. pushl %edx
  180. {$ELSE REGCALL}
  181. movl F,%ebx
  182. {$ENDIF REGCALL}
  183. movl (%ebx),%ebx
  184. {Get date}
  185. movw $0x5700,%ax
  186. call syscall
  187. shll $16,%edx
  188. movw %cx,%dx
  189. {$IFDEF REGCALL}
  190. popl %ebx
  191. {$ELSE REGCALL}
  192. movl Time,%ebx
  193. {$ENDIF REGCALL}
  194. movl %edx,(%ebx)
  195. movw %ax,DosError
  196. popl %ebx
  197. end {['eax', 'ecx', 'edx']};
  198. procedure SetFTime (var F; Time: longint);
  199. var FStat: TFileStatus3;
  200. RC: cardinal;
  201. begin
  202. if os_mode = osOS2 then
  203. begin
  204. RC := DosQueryFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  205. SizeOf (FStat));
  206. if RC = 0 then
  207. begin
  208. FStat.DateLastAccess := Hi (Time);
  209. FStat.DateLastWrite := Hi (Time);
  210. FStat.TimeLastAccess := Lo (Time);
  211. FStat.TimeLastWrite := Lo (Time);
  212. RC := DosSetFileInfo (FileRec (F).Handle, ilStandard,
  213. @FStat, SizeOf (FStat));
  214. end;
  215. DosError := integer (RC);
  216. end
  217. else
  218. asm
  219. pushl %ebx
  220. {Load handle}
  221. movl f,%ebx
  222. movl (%ebx),%ebx
  223. movl time,%ecx
  224. shldl $16,%ecx,%edx
  225. {Set date}
  226. movw $0x5701,%ax
  227. call syscall
  228. movw %ax,doserror
  229. popl %ebx
  230. end ['eax', 'ecx', 'edx'];
  231. end;
  232. procedure Intr (IntNo: byte; var Regs: Registers);
  233. {Not recommended for EMX. Only works in DOS mode, not in OS/2 mode.}
  234. begin
  235. if os_mode = osos2 then exit;
  236. asm
  237. jmp .Lstart
  238. { .data}
  239. .Lint86:
  240. .byte 0xcd
  241. .Lint86_vec:
  242. .byte 0x03
  243. jmp .Lint86_retjmp
  244. { .text}
  245. .Lstart:
  246. movb intno,%al
  247. movb %al,.Lint86_vec
  248. {
  249. movl 10(%ebp),%eax
  250. incl %eax
  251. incl %eax
  252. }
  253. movl regs,%eax
  254. {Do not use first int}
  255. movl 4(%eax),%ebx
  256. movl 8(%eax),%ecx
  257. movl 12(%eax),%edx
  258. movl 16(%eax),%ebp
  259. movl 20(%eax),%esi
  260. movl 24(%eax),%edi
  261. movl (%eax),%eax
  262. jmp .Lint86
  263. .Lint86_retjmp:
  264. pushf
  265. pushl %ebp
  266. pushl %eax
  267. movl %esp,%ebp
  268. {Calc EBP new}
  269. addl $12,%ebp
  270. {
  271. movl 10(%ebp),%eax
  272. incl %eax
  273. incl %eax
  274. }
  275. {Do not use first int}
  276. movl regs,%eax
  277. popl (%eax)
  278. movl %ebx,4(%eax)
  279. movl %ecx,8(%eax)
  280. movl %edx,12(%eax)
  281. {Restore EBP}
  282. popl %edx
  283. movl %edx,16(%eax)
  284. movl %esi,20(%eax)
  285. movl %edi,24(%eax)
  286. {Ignore ES and DS}
  287. popl %ebx {Flags.}
  288. movl %ebx,32(%eax)
  289. {FS and GS too}
  290. end ['eax','ebx','ecx','edx','esi','edi'];
  291. end;
  292. procedure exec(const path:pathstr;const comline:comstr);
  293. {Execute a program.}
  294. type bytearray=array[0..8191] of byte;
  295. Pbytearray=^bytearray;
  296. execstruc=packed record
  297. argofs : pointer; { pointer to arguments (offset) }
  298. envofs : pointer; { pointer to environment (offset) }
  299. nameofs: pointer; { pointer to file name (offset) }
  300. argseg : word; { pointer to arguments (selector) }
  301. envseg : word; { pointer to environment (selector}
  302. nameseg: word; { pointer to file name (selector) }
  303. numarg : word; { number of arguments }
  304. sizearg : word; { size of arguments }
  305. numenv : word; { number of env strings }
  306. sizeenv:word; { size of environment }
  307. mode:word; { mode word }
  308. end;
  309. var args:Pbytearray;
  310. env:Pbytearray;
  311. Path2:PByteArray;
  312. i,argsize:word;
  313. es:execstruc;
  314. esadr:pointer;
  315. d:dirstr;
  316. n:namestr;
  317. e:extstr;
  318. p : ppchar;
  319. j : integer;
  320. const
  321. ArgsSize = 2048; (* Amount of memory reserved for arguments in bytes. *)
  322. begin
  323. getmem(args,ArgsSize);
  324. GetMem(env, envc*sizeof(pchar)+16384);
  325. GetMem (Path2, 260);
  326. {Now setup the arguments. The first argument should be the program
  327. name without directory and extension.}
  328. fsplit(path,d,n,e);
  329. es.numarg:=1;
  330. args^[0]:=$80;
  331. argsize:=1;
  332. for i:=1 to length(n) do
  333. begin
  334. args^[argsize]:=byte(n[i]);
  335. inc(argsize);
  336. end;
  337. args^[argsize]:=0;
  338. inc(argsize);
  339. {Now do the real arguments.}
  340. i:=1;
  341. while i<=length(comline) do
  342. begin
  343. if comline[i]<>' ' then
  344. begin
  345. {Commandline argument found. Copy it.}
  346. inc(es.numarg);
  347. args^[argsize]:=$80;
  348. inc(argsize);
  349. while (i<=length(comline)) and (comline[i]<>' ') do
  350. begin
  351. args^[argsize]:=byte(comline[i]);
  352. inc(argsize);
  353. inc(i);
  354. end;
  355. args^[argsize]:=0;
  356. inc(argsize);
  357. end;
  358. inc(i);
  359. end;
  360. args^[argsize]:=0;
  361. inc(argsize);
  362. {Commandline ready, now build the environment.
  363. Oh boy, I always had the opinion that executing a program under Dos
  364. was a hard job!}
  365. asm
  366. movl env,%edi {Setup destination pointer.}
  367. movl envc,%ecx {Load number of arguments in edx.}
  368. movl envp,%esi {Load env. strings.}
  369. xorl %edx,%edx {Count environment size.}
  370. .Lexa1:
  371. lodsl {Load a Pchar.}
  372. xchgl %eax,%ebx
  373. .Lexa2:
  374. movb (%ebx),%al {Load a byte.}
  375. incl %ebx {Point to next byte.}
  376. stosb {Store it.}
  377. incl %edx {Increase counter.}
  378. cmpb $0,%al {Ready ?.}
  379. jne .Lexa2
  380. loop .Lexa1 {Next argument.}
  381. stosb {Store an extra 0 to finish. (AL is now 0).}
  382. incl %edx
  383. movw %dx,ES.SizeEnv {Store environment size.}
  384. end ['eax','ebx','ecx','edx','esi','edi'];
  385. {Environment ready, now set-up exec structure.}
  386. es.argofs:=args;
  387. es.envofs:=env;
  388. es.numenv:=envc;
  389. Move (Path [1], Path2^, Length (Path));
  390. Path2^ [Length (Path)] := 0;
  391. es.nameofs := Path2;
  392. asm
  393. movw %ss,es.argseg
  394. movw %ss,es.envseg
  395. movw %ss,es.nameseg
  396. end;
  397. es.sizearg:=argsize;
  398. es.mode := word (ExecFlags);
  399. {Now exec the program.}
  400. asm
  401. leal es,%edx
  402. movw $0x7f06,%ax
  403. call syscall
  404. movl $0,%edi
  405. jnc .Lexprg1
  406. xchgl %eax,%edi
  407. xorl %eax,%eax
  408. .Lexprg1:
  409. movw %di,doserror
  410. movl %eax, LastDosExitCode
  411. end ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi'];
  412. FreeMem (Path2, 260);
  413. FreeMem(env, envc*sizeof(pchar)+16384);
  414. freemem(args,ArgsSize);
  415. {Phew! That's it. This was the most sophisticated procedure to call
  416. a system function I ever wrote!}
  417. end;
  418. function dosversion:word;assembler;
  419. {Returns DOS version in DOS and OS/2 version in OS/2}
  420. asm
  421. movb $0x30,%ah
  422. call syscall
  423. end ['eax'];
  424. procedure GetDate (var Year, Month, MDay, WDay: word);
  425. begin
  426. asm
  427. movb $0x2a, %ah
  428. call syscall
  429. xorb %ah, %ah
  430. movl WDay, %edi
  431. stosw
  432. movl MDay, %edi
  433. movb %dl, %al
  434. stosw
  435. movl Month, %edi
  436. movb %dh, %al
  437. stosw
  438. movl Year, %edi
  439. xchgw %ecx, %eax
  440. stosw
  441. end ['eax', 'ecx', 'edx'];
  442. end;
  443. {$asmmode intel}
  444. procedure SetDate (Year, Month, Day: word);
  445. var DT: TDateTime;
  446. begin
  447. if os_mode = osOS2 then
  448. begin
  449. DosGetDateTime (DT);
  450. DT.Year := Year;
  451. DT.Month := byte (Month);
  452. DT.Day := byte (Day);
  453. DosSetDateTime (DT);
  454. end
  455. else
  456. asm
  457. mov cx, Year
  458. mov dh, byte ptr Month
  459. mov dl, byte ptr Day
  460. mov ah, 2Bh
  461. call syscall
  462. end ['eax', 'ecx', 'edx'];
  463. end;
  464. {$asmmode att}
  465. procedure GetTime (var Hour, Minute, Second, Sec100: word);
  466. {$IFDEF REGCALL}
  467. begin
  468. {$ELSE REGCALL}
  469. assembler;
  470. {$ENDIF REGCALL}
  471. asm
  472. movb $0x2c, %ah
  473. call syscall
  474. xorb %ah, %ah
  475. movl Sec100, %edi
  476. movb %dl, %al
  477. stosw
  478. movl Second, %edi
  479. movb %dh,%al
  480. stosw
  481. movl Minute, %edi
  482. movb %cl,%al
  483. stosw
  484. movl Hour, %edi
  485. movb %ch,%al
  486. stosw
  487. {$IFDEF REGCALL}
  488. end ['eax', 'ecx', 'edx'];
  489. end;
  490. {$ELSE REGCALL}
  491. end {['eax', 'ecx', 'edx']};
  492. {$ENDIF REGCALL}
  493. {$asmmode intel}
  494. procedure SetTime (Hour, Minute, Second, Sec100: word);
  495. var DT: TDateTime;
  496. begin
  497. if os_mode = osOS2 then
  498. begin
  499. DosGetDateTime (DT);
  500. DT.Hour := byte (Hour);
  501. DT.Minute := byte (Minute);
  502. DT.Second := byte (Second);
  503. DT.Sec100 := byte (Sec100);
  504. DosSetDateTime (DT);
  505. end
  506. else
  507. asm
  508. mov ch, byte ptr Hour
  509. mov cl, byte ptr Minute
  510. mov dh, byte ptr Second
  511. mov dl, byte ptr Sec100
  512. mov ah, 2Dh
  513. call syscall
  514. end ['eax', 'ecx', 'edx'];
  515. end;
  516. {$asmmode att}
  517. procedure getverify(var verify:boolean);
  518. begin
  519. {! Do not use in OS/2.}
  520. if os_mode in [osDOS,osDPMI] then
  521. asm
  522. movb $0x54,%ah
  523. call syscall
  524. movl verify,%edi
  525. stosb
  526. end ['eax', 'edi']
  527. else
  528. verify := true;
  529. end;
  530. procedure setverify(verify:boolean);
  531. begin
  532. {! Do not use in OS/2!}
  533. if os_mode in [osDOS,osDPMI] then
  534. asm
  535. movb verify,%al
  536. movb $0x2e,%ah
  537. call syscall
  538. end ['eax'];
  539. end;
  540. function DiskFree (Drive: byte): int64;
  541. var FI: TFSinfo;
  542. RC: cardinal;
  543. begin
  544. if (os_mode = osDOS) or (os_mode = osDPMI) then
  545. {Function 36 is not supported in OS/2.}
  546. asm
  547. pushl %ebx
  548. movb Drive,%dl
  549. movb $0x36,%ah
  550. call syscall
  551. cmpw $-1,%ax
  552. je .LDISKFREE1
  553. mulw %cx
  554. mulw %bx
  555. shll $16,%edx
  556. movw %ax,%dx
  557. movl $0,%eax
  558. xchgl %edx,%eax
  559. jmp .LDISKFREE2
  560. .LDISKFREE1:
  561. cltd
  562. .LDISKFREE2:
  563. popl %ebx
  564. leave
  565. ret
  566. end ['eax', 'ecx', 'edx']
  567. else
  568. {In OS/2, we use the filesystem information.}
  569. begin
  570. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  571. if RC = 0 then
  572. DiskFree := int64 (FI.Free_Clusters) *
  573. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  574. else
  575. DiskFree := -1;
  576. end;
  577. end;
  578. function DiskSize (Drive: byte): int64;
  579. var FI: TFSinfo;
  580. RC: cardinal;
  581. begin
  582. if (os_mode = osDOS) or (os_mode = osDPMI) then
  583. {Function 36 is not supported in OS/2.}
  584. asm
  585. pushl %ebx
  586. movb Drive,%dl
  587. movb $0x36,%ah
  588. call syscall
  589. movw %dx,%bx
  590. cmpw $-1,%ax
  591. je .LDISKSIZE1
  592. mulw %cx
  593. mulw %bx
  594. shll $16,%edx
  595. movw %ax,%dx
  596. movl $0,%eax
  597. xchgl %edx,%eax
  598. jmp .LDISKSIZE2
  599. .LDISKSIZE1:
  600. cltd
  601. .LDISKSIZE2:
  602. popl %ebx
  603. leave
  604. ret
  605. end ['eax', 'ecx', 'edx']
  606. else
  607. {In OS/2, we use the filesystem information.}
  608. begin
  609. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  610. if RC = 0 then
  611. DiskSize := int64 (FI.Total_Clusters) *
  612. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  613. else
  614. DiskSize := -1;
  615. end;
  616. end;
  617. procedure SearchRec2DosSearchRec (var F: SearchRec);
  618. const NameSize = 255;
  619. var L, I: longint;
  620. begin
  621. if os_mode <> osOS2 then
  622. begin
  623. I := 1;
  624. while (I <= SizeOf (LastSR))
  625. and (PBA (@F)^ [I] = PBA (@LastSR)^ [I]) do Inc (I);
  626. { Raise "Invalid file handle" RTE if nested FindFirst calls were used. }
  627. if I <= SizeOf (LastSR) then RunError (6);
  628. l:=length(f.name);
  629. for i:=1 to namesize do
  630. f.name[i-1]:=f.name[i];
  631. f.name[l]:=#0;
  632. end;
  633. end;
  634. procedure DosSearchRec2SearchRec (var F: SearchRec);
  635. const NameSize=255;
  636. var L, I: longint;
  637. type TRec = record
  638. T, D: word;
  639. end;
  640. begin
  641. if os_mode = osOS2 then with F do
  642. begin
  643. Name := FStat^.Name;
  644. Size := FStat^.FileSize;
  645. Attr := byte(FStat^.AttrFile and $FF);
  646. TRec (Time).T := FStat^.TimeLastWrite;
  647. TRec (Time).D := FStat^.DateLastWrite;
  648. end else
  649. begin
  650. for i:=0 to namesize do
  651. if f.name[i]=#0 then
  652. begin
  653. l:=i;
  654. break;
  655. end;
  656. for i:=namesize-1 downto 0 do
  657. f.name[i+1]:=f.name[i];
  658. f.name[0]:=char(l);
  659. Move (F, LastSR, SizeOf (LastSR));
  660. end;
  661. end;
  662. procedure _findfirst(path:pchar;attr:word;var f:searchrec);
  663. begin
  664. asm
  665. pushl %esi
  666. movl path,%edx
  667. movw attr,%cx
  668. {No need to set DTA in EMX. Just give a pointer in ESI.}
  669. movl f,%esi
  670. movb $0x4e,%ah
  671. call syscall
  672. jnc .LFF
  673. movw %ax,doserror
  674. .LFF:
  675. popl %esi
  676. end ['eax', 'ecx', 'edx'];
  677. end;
  678. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  679. var path0: array[0..255] of char;
  680. Count: cardinal;
  681. begin
  682. {No error.}
  683. DosError := 0;
  684. if os_mode = osOS2 then
  685. begin
  686. New (F.FStat);
  687. F.Handle := THandle ($FFFFFFFF);
  688. Count := 1;
  689. DosError := integer (DosFindFirst (Path, F.Handle,
  690. Attr and FindResvdMask, F.FStat, SizeOf (F.FStat^),
  691. Count, ilStandard));
  692. if (DosError = 0) and (Count = 0) then DosError := 18;
  693. end else
  694. begin
  695. strPcopy(path0,path);
  696. _findfirst(path0,attr,f);
  697. end;
  698. DosSearchRec2SearchRec (F);
  699. end;
  700. procedure _findnext(var f : searchrec);
  701. begin
  702. asm
  703. pushl %esi
  704. movl f,%esi
  705. movb $0x4f,%ah
  706. call syscall
  707. jnc .LFN
  708. movw %ax,doserror
  709. .LFN:
  710. popl %esi
  711. end ['eax'];
  712. end;
  713. procedure FindNext (var F: SearchRec);
  714. var Count: cardinal;
  715. begin
  716. {No error}
  717. DosError := 0;
  718. SearchRec2DosSearchRec (F);
  719. if os_mode = osOS2 then
  720. begin
  721. Count := 1;
  722. DosError := integer (DosFindNext (F.Handle, F.FStat, SizeOf (F.FStat^),
  723. Count));
  724. if (DosError = 0) and (Count = 0) then DosError := 18;
  725. end else _findnext (F);
  726. DosSearchRec2SearchRec (F);
  727. end;
  728. procedure FindClose (var F: SearchRec);
  729. begin
  730. if os_mode = osOS2 then
  731. begin
  732. if F.Handle <> THandle ($FFFFFFFF) then DosError := DosFindClose (F.Handle);
  733. Dispose (F.FStat);
  734. end;
  735. end;
  736. function envcount:longint;assembler;
  737. asm
  738. movl envc,%eax
  739. end ['EAX'];
  740. function envstr(index : longint) : string;
  741. var hp:Pchar;
  742. begin
  743. if (index<=0) or (index>envcount) then
  744. begin
  745. envstr:='';
  746. exit;
  747. end;
  748. hp:=EnvP[index-1];
  749. envstr:=strpas(hp);
  750. end;
  751. function GetEnvPChar (EnvVar: string): PChar;
  752. (* The assembler version is more than three times as fast as Pascal. *)
  753. var
  754. P: PChar;
  755. begin
  756. EnvVar := UpCase (EnvVar);
  757. {$ASMMODE INTEL}
  758. asm
  759. cld
  760. mov edi, Environment
  761. lea esi, EnvVar
  762. xor eax, eax
  763. lodsb
  764. @NewVar:
  765. cmp byte ptr [edi], 0
  766. jz @Stop
  767. push eax { eax contains length of searched variable name }
  768. push esi { esi points to the beginning of the variable name }
  769. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  770. mov edx, edi { pointer to beginning of variable name saved in edx }
  771. mov al, '=' { searching until '=' (end of variable name) }
  772. repne
  773. scasb { scan until '=' not found }
  774. neg ecx { what was the name length? }
  775. dec ecx { corrected }
  776. dec ecx { exclude the '=' character }
  777. pop esi { restore pointer to beginning of variable name }
  778. pop eax { restore length of searched variable name }
  779. push eax { and save both of them again for later use }
  780. push esi
  781. cmp ecx, eax { compare length of searched variable name with name }
  782. jnz @NotEqual { ... of currently found variable, jump if different }
  783. xchg edx, edi { pointer to current variable name restored in edi }
  784. repe
  785. cmpsb { compare till the end of variable name }
  786. xchg edx, edi { pointer to beginning of variable contents in edi }
  787. jz @Equal { finish if they're equal }
  788. @NotEqual:
  789. xor eax, eax { look for 00h }
  790. mov ecx, -1 { it _must_ be found }
  791. repne
  792. scasb { scan until found }
  793. pop esi { restore pointer to beginning of variable name }
  794. pop eax { restore length of searched variable name }
  795. jmp @NewVar { ... or continue with new variable otherwise }
  796. @Stop:
  797. xor eax, eax
  798. mov P, eax { Not found - return nil }
  799. jmp @End
  800. @Equal:
  801. pop esi { restore the stack position }
  802. pop eax
  803. mov P, edi { place pointer to variable contents in P }
  804. @End:
  805. end ['eax','ecx','edx','esi','edi'];
  806. GetEnvPChar := P;
  807. end;
  808. {$ASMMODE ATT}
  809. function GetEnv (EnvVar: string): string;
  810. begin
  811. GetEnv := StrPas (GetEnvPChar (EnvVar));
  812. end;
  813. procedure getfattr(var f;var attr : word);
  814. { Under EMX, this routine requires }
  815. { the expanded path specification }
  816. { otherwise it will not function }
  817. { properly (CEC) }
  818. var
  819. path: pathstr;
  820. buffer:array[0..255] of char;
  821. begin
  822. DosError := 0;
  823. path:='';
  824. path := StrPas(filerec(f).Name);
  825. { Takes care of slash and backslash support }
  826. path:=FExpand(path);
  827. move(path[1],buffer,length(path));
  828. buffer[length(path)]:=#0;
  829. asm
  830. pushl %ebx
  831. movw $0x4300,%ax
  832. leal buffer,%edx
  833. call syscall
  834. jnc .Lnoerror { is there an error ? }
  835. movw %ax,doserror
  836. .Lnoerror:
  837. movl attr,%ebx
  838. movw %cx,(%ebx)
  839. popl %ebx
  840. end ['eax', 'ecx', 'edx'];
  841. end;
  842. procedure setfattr(var f;attr : word);
  843. { Under EMX, this routine requires }
  844. { the expanded path specification }
  845. { otherwise it will not function }
  846. { properly (CEC) }
  847. var
  848. path: pathstr;
  849. buffer:array[0..255] of char;
  850. begin
  851. path:='';
  852. DosError := 0;
  853. path := StrPas(filerec(f).Name);
  854. { Takes care of slash and backslash support }
  855. path:=FExpand(path);
  856. move(path[1],buffer,length(path));
  857. buffer[length(path)]:=#0;
  858. asm
  859. movw $0x4301,%ax
  860. leal buffer,%edx
  861. movw attr,%cx
  862. call syscall
  863. jnc .Lnoerror
  864. movw %ax,doserror
  865. .Lnoerror:
  866. end ['eax', 'ecx', 'edx'];
  867. end;
  868. procedure InitEnvironment;
  869. var
  870. cnt : integer;
  871. ptr : pchar;
  872. base : pchar;
  873. i: integer;
  874. PIB: PProcessInfoBlock;
  875. TIB: PThreadInfoBlock;
  876. begin
  877. { We need to setup the environment }
  878. { only in the case of OS/2 }
  879. { otherwise everything is in the stack }
  880. if os_Mode in [OsDOS,osDPMI] then
  881. exit;
  882. cnt := 0;
  883. { count number of environment pointers }
  884. DosGetInfoBlocks (PPThreadInfoBlock (@TIB), PPProcessInfoBlock (@PIB));
  885. ptr := pchar(PIB^.env);
  886. { stringz,stringz...,#0 }
  887. i := 0;
  888. repeat
  889. repeat
  890. (inc(i));
  891. until (ptr[i] = #0);
  892. inc(i);
  893. { here, it may be a double null, end of environment }
  894. if ptr[i] <> #0 then
  895. inc(cnt);
  896. until (ptr[i] = #0);
  897. { save environment count }
  898. envc := cnt;
  899. { got count of environment strings }
  900. GetMem(envp, cnt*sizeof(pchar)+16384);
  901. cnt := 0;
  902. ptr := pchar(PIB^.env);
  903. i:=0;
  904. repeat
  905. envp[cnt] := ptr;
  906. Inc(cnt);
  907. { go to next string ... }
  908. repeat
  909. inc(ptr);
  910. until (ptr^ = #0);
  911. inc(ptr);
  912. until ptr^ = #0;
  913. envp[cnt] := #0;
  914. end;
  915. procedure DoneEnvironment;
  916. begin
  917. { it is allocated on the stack for DOS/DPMI }
  918. if os_mode = osOs2 then
  919. FreeMem(envp, envc*sizeof(pchar)+16384);
  920. end;
  921. var
  922. oldexit : pointer;
  923. {******************************************************************************
  924. --- Not Supported ---
  925. ******************************************************************************}
  926. begin
  927. oldexit:=exitproc;
  928. exitproc:=@doneenvironment;
  929. InitEnvironment;
  930. LastDosExitCode := 0;
  931. ExecFlags := 0;
  932. end.
  933. {
  934. $Log$
  935. Revision 1.16 2004-12-05 16:44:43 hajny
  936. * GetMsCount added, platform independent routines moved to single include file
  937. Revision 1.15 2004/03/21 20:35:24 hajny
  938. * Exec cleanup
  939. Revision 1.14 2004/03/08 22:31:00 hajny
  940. * exec fix
  941. Revision 1.13 2004/02/22 15:01:49 hajny
  942. * lots of fixes (regcall, THandle, string operations in sysutils, longint2cardinal according to OS/2 docs, dosh.inc, ...)
  943. Revision 1.12 2004/02/17 17:37:26 daniel
  944. * Enable threadvars again
  945. Revision 1.11 2004/02/16 22:16:58 hajny
  946. * LastDosExitCode changed back from threadvar temporarily
  947. Revision 1.10 2004/02/15 21:26:37 hajny
  948. * overloaded ExecuteProcess added, EnvStr param changed to longint
  949. Revision 1.9 2004/02/09 12:03:16 michael
  950. + Switched to single interface in dosh.inc
  951. Revision 1.8 2003/12/26 22:20:44 hajny
  952. * regcall fixes
  953. Revision 1.7 2003/10/25 22:45:37 hajny
  954. * file handling related fixes
  955. Revision 1.6 2003/10/07 21:33:24 hajny
  956. * stdcall fixes and asm routines cleanup
  957. Revision 1.5 2003/10/04 17:53:08 hajny
  958. * stdcall changes merged to EMX
  959. Revision 1.4 2003/06/26 17:12:29 yuri
  960. * pmbidi added
  961. * some cosmetic changes
  962. Revision 1.3 2003/03/23 23:11:17 hajny
  963. + emx target added
  964. Revision 1.2 2002/12/15 22:50:29 hajny
  965. * GetEnv fix merged from os2 target
  966. Revision 1.1 2002/11/17 16:22:53 hajny
  967. + RTL for emx target
  968. }