dos.pas 26 KB

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