dos.pas 26 KB

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