dos.pas 26 KB

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