dos.pas 26 KB

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