system.pas 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271
  1. {
  2. $Id$
  3. ****************************************************************************
  4. This file is part of the Free Pascal run time library.
  5. Copyright (c) 1999-2002 by Free Pascal development team
  6. Free Pascal - EMX runtime library
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. ****************************************************************************}
  13. unit {$ifdef VER1_0}sysemx{$else}System{$endif};
  14. {Changelog:
  15. People:
  16. DM - Daniel Mantione
  17. Date: Description of change: Changed by:
  18. - First released version 0.1. DM
  19. Coding style:
  20. My coding style is a bit unusual for Pascal. Nevertheless I friendly ask
  21. you to try to make your changes not look all to different. In general,
  22. set your IDE to use a tabsize of 4.}
  23. interface
  24. {Link the startup code.}
  25. {$ifdef VER1_0}
  26. {$l prt1.oo2}
  27. {$else}
  28. {$l prt1.o}
  29. {$endif}
  30. {$I systemh.inc}
  31. {$I heaph.inc}
  32. {Platform specific information}
  33. const
  34. LineEnding = #13#10;
  35. { LFNSupport is defined separately below!!! }
  36. DirectorySeparator = '\';
  37. DriveSeparator = ':';
  38. PathSeparator = ';';
  39. { FileNameCaseSensitive is defined separately below!!! }
  40. type Tos=(osDOS,osOS2,osDPMI);
  41. var os_mode:Tos;
  42. first_meg:pointer;
  43. type TByteArray = array [0..$ffff] of byte;
  44. PByteArray = ^TByteArray;
  45. TSysThreadIB = record
  46. TID,
  47. Priority,
  48. Version: cardinal;
  49. MCCount,
  50. MCForceFlag: word;
  51. end;
  52. PSysThreadIB = ^TSysThreadIB;
  53. TThreadInfoBlock = record
  54. PExChain,
  55. Stack,
  56. StackLimit: pointer;
  57. TIB2: PSysThreadIB;
  58. Version,
  59. Ordinal: cardinal;
  60. end;
  61. PThreadInfoBlock = ^TThreadInfoBlock;
  62. PPThreadInfoBlock = ^PThreadInfoBlock;
  63. TProcessInfoBlock = record
  64. PID,
  65. ParentPid,
  66. Handle: cardinal;
  67. Cmd,
  68. Env: PByteArray;
  69. Status,
  70. ProcType: cardinal;
  71. end;
  72. PProcessInfoBlock = ^TProcessInfoBlock;
  73. PPProcessInfoBlock = ^PProcessInfoBlock;
  74. const UnusedHandle=$ffff;
  75. StdInputHandle=0;
  76. StdOutputHandle=1;
  77. StdErrorHandle=2;
  78. LFNSupport: boolean = true;
  79. FileNameCaseSensitive: boolean = false;
  80. sLineBreak = LineEnding;
  81. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  82. var
  83. { C-compatible arguments and environment }
  84. argc : longint;external name '_argc';
  85. argv : ppchar;external name '_argv';
  86. envp : ppchar;external name '_environ';
  87. EnvC: cardinal; external name '_envc';
  88. (* Pointer to the block of environment variables - used e.g. in unit Dos. *)
  89. Environment: PChar;
  90. var
  91. (* Type / run mode of the current process: *)
  92. (* 0 .. full screen OS/2 session *)
  93. (* 1 .. DOS session *)
  94. (* 2 .. VIO windowable OS/2 session *)
  95. (* 3 .. Presentation Manager OS/2 session *)
  96. (* 4 .. detached (background) OS/2 process *)
  97. ApplicationType: cardinal;
  98. implementation
  99. {$I system.inc}
  100. var
  101. heap_base: pointer; external name '__heap_base';
  102. heap_brk: pointer; external name '__heap_brk';
  103. heap_end: pointer; external name '__heap_end';
  104. (* Maximum heap size - only used if heap is allocated as continuous block. *)
  105. {$IFDEF CONTHEAP}
  106. BrkLimit: cardinal;
  107. {$ENDIF CONTHEAP}
  108. procedure DosGetInfoBlocks (PATIB: PPThreadInfoBlock;
  109. PAPIB: PPProcessInfoBlock); cdecl;
  110. external 'DOSCALLS' index 312;
  111. function DosLoadModule (ObjName: PChar; ObjLen: cardinal; DLLName: PChar;
  112. var Handle: cardinal): longint; cdecl;
  113. external 'DOSCALLS' index 318;
  114. function DosQueryProcAddr (Handle, Ordinal: cardinal; ProcName: PChar;
  115. var Address: pointer): longint; cdecl;
  116. external 'DOSCALLS' index 321;
  117. function DosSetRelMaxFH (var ReqCount, CurMaxFH: longint): longint; cdecl;
  118. external 'DOSCALLS' index 382;
  119. function DosSetCurrentDir (Name:PChar): longint; cdecl;
  120. external 'DOSCALLS' index 255;
  121. function DosSetDefaultDisk (DiskNum:longint): longint; cdecl;
  122. external 'DOSCALLS' index 220;
  123. { This is not real prototype, but is close enough }
  124. { for us (the 2nd parameter is actually a pointer }
  125. { to a structure). }
  126. function DosCreateDir( Name : pchar; p : pointer): longint; cdecl;
  127. external 'DOSCALLS' index 270;
  128. function DosDeleteDir( Name : pchar) : longint; cdecl;
  129. external 'DOSCALLS' index 226;
  130. {This is the correct way to call external assembler procedures.}
  131. procedure syscall; external name '___SYSCALL';
  132. {
  133. procedure syscall; external 'EMX' index 2;
  134. procedure emx_init; external 'EMX' index 1;
  135. }
  136. { converts an OS/2 error code to a TP compatible error }
  137. { code. Same thing exists under most other supported }
  138. { systems. }
  139. { Only call for OS/2 DLL imported routines }
  140. Procedure Errno2InOutRes;
  141. Begin
  142. { errors 1..18 are the same as in DOS }
  143. case InOutRes of
  144. { simple offset to convert these error codes }
  145. { exactly like the error codes in Win32 }
  146. 19..31 : InOutRes := InOutRes + 131;
  147. { gets a bit more complicated ... }
  148. 32..33 : InOutRes := 5;
  149. 38 : InOutRes := 100;
  150. 39 : InOutRes := 101;
  151. 112 : InOutRes := 101;
  152. 110 : InOutRes := 5;
  153. 114 : InOutRes := 6;
  154. 290 : InOutRes := 290;
  155. end;
  156. { all other cases ... we keep the same error code }
  157. end;
  158. {****************************************************************************
  159. Miscellaneous related routines.
  160. ****************************************************************************}
  161. {$asmmode intel}
  162. procedure system_exit; assembler;
  163. asm
  164. mov ah, 04ch
  165. mov al, byte ptr exitcode
  166. call syscall
  167. end ['EAX'];
  168. {$ASMMODE ATT}
  169. function paramcount:longint;assembler;
  170. asm
  171. movl argc,%eax
  172. decl %eax
  173. end ['EAX'];
  174. function args:pointer;assembler;
  175. asm
  176. movl argv,%eax
  177. end ['EAX'];
  178. function paramstr(l:longint):string;
  179. var p:^Pchar;
  180. begin
  181. { There seems to be a problem with EMX for DOS when trying to }
  182. { access paramstr(0), and to avoid problems between DOS and }
  183. { OS/2 they have been separated. }
  184. if os_Mode = OsOs2 then
  185. begin
  186. if L = 0 then
  187. begin
  188. GetMem (P, 260);
  189. p[0] := #0; { in case of error, initialize to empty string }
  190. {$ASMMODE INTEL}
  191. asm
  192. mov edx, P
  193. mov ecx, 260
  194. mov eax, 7F33h
  195. call syscall { error handle already with empty string }
  196. end;
  197. ParamStr := StrPas (PChar (P));
  198. FreeMem (P, 260);
  199. end
  200. else
  201. if (l>0) and (l<=paramcount) then
  202. begin
  203. p:=args;
  204. paramstr:=strpas(p[l]);
  205. end
  206. else paramstr:='';
  207. end
  208. else
  209. begin
  210. p:=args;
  211. paramstr:=strpas(p[l]);
  212. end;
  213. end;
  214. procedure randomize; assembler;
  215. asm
  216. mov ah, 2Ch
  217. call syscall
  218. mov word ptr [randseed], cx
  219. mov word ptr [randseed + 2], dx
  220. end;
  221. {$ASMMODE ATT}
  222. {****************************************************************************
  223. Heap management releated routines.
  224. ****************************************************************************}
  225. { this function allows to extend the heap by calling
  226. syscall $7f00 resizes the brk area}
  227. function sbrk(size:longint):pointer;
  228. {$IFDEF DUMPGROW}
  229. var
  230. L: longword;
  231. begin
  232. WriteLn ('Trying to grow heap by ', Size, ' to ', HeapSize + Size);
  233. {$IFDEF CONTHEAP}
  234. WriteLn ('BrkLimit is ', BrkLimit);
  235. {$ENDIF CONTHEAP}
  236. asm
  237. movl size,%edx
  238. movw $0x7f00,%ax
  239. call syscall { result directly in EAX }
  240. mov %eax,L
  241. end;
  242. WriteLn ('New heap at ', L);
  243. Sbrk := pointer(L);
  244. end;
  245. {$ELSE DUMPGROW}
  246. assembler;
  247. asm
  248. movl size,%edx
  249. movw $0x7f00,%ax
  250. call syscall { result directly in EAX }
  251. end;
  252. {$ENDIF DUMPGROW}
  253. function getheapstart:pointer;assembler;
  254. asm
  255. movl heap_base,%eax
  256. end ['EAX'];
  257. function getheapsize:longint;assembler;
  258. asm
  259. movl heap_brk,%eax
  260. end ['EAX'];
  261. {$i heap.inc}
  262. {****************************************************************************
  263. Low Level File Routines
  264. ****************************************************************************}
  265. procedure allowslash(p:Pchar);
  266. {Allow slash as backslash.}
  267. var i:longint;
  268. begin
  269. for i:=0 to strlen(p) do
  270. if p[i]='/' then p[i]:='\';
  271. end;
  272. procedure do_close(h:longint);
  273. begin
  274. { Only three standard handles under real OS/2 }
  275. if (h > 4) or
  276. ((os_MODE = osOS2) and (h > 2)) then
  277. begin
  278. asm
  279. movb $0x3e,%ah
  280. movl h,%ebx
  281. call syscall
  282. jnc .Lnoerror { error code? }
  283. movw %ax, InOutRes { yes, then set InOutRes }
  284. .Lnoerror:
  285. end;
  286. end;
  287. end;
  288. procedure do_erase(p:Pchar);
  289. begin
  290. allowslash(p);
  291. asm
  292. movl P,%edx
  293. movb $0x41,%ah
  294. call syscall
  295. jnc .LERASE1
  296. movw %ax,inoutres;
  297. .LERASE1:
  298. end;
  299. end;
  300. procedure do_rename(p1,p2:Pchar);
  301. begin
  302. allowslash(p1);
  303. allowslash(p2);
  304. asm
  305. movl P1, %edx
  306. movl P2, %edi
  307. movb $0x56,%ah
  308. call syscall
  309. jnc .LRENAME1
  310. movw %ax,inoutres;
  311. .LRENAME1:
  312. end;
  313. end;
  314. function do_read(h,addr,len:longint):longint; assembler;
  315. asm
  316. movl len,%ecx
  317. movl addr,%edx
  318. movl h,%ebx
  319. movb $0x3f,%ah
  320. call syscall
  321. jnc .LDOSREAD1
  322. movw %ax,inoutres;
  323. xorl %eax,%eax
  324. .LDOSREAD1:
  325. end;
  326. function do_write(h,addr,len:longint) : longint; assembler;
  327. asm
  328. xorl %eax,%eax
  329. cmpl $0,len { 0 bytes to write is undefined behavior }
  330. jz .LDOSWRITE1
  331. movl len,%ecx
  332. movl addr,%edx
  333. movl h,%ebx
  334. movb $0x40,%ah
  335. call syscall
  336. jnc .LDOSWRITE1
  337. movw %ax,inoutres;
  338. .LDOSWRITE1:
  339. end;
  340. function do_filepos(handle:longint): longint; assembler;
  341. asm
  342. movw $0x4201,%ax
  343. movl handle,%ebx
  344. xorl %edx,%edx
  345. call syscall
  346. jnc .LDOSFILEPOS
  347. movw %ax,inoutres;
  348. xorl %eax,%eax
  349. .LDOSFILEPOS:
  350. end;
  351. procedure do_seek(handle,pos:longint); assembler;
  352. asm
  353. movw $0x4200,%ax
  354. movl handle,%ebx
  355. movl pos,%edx
  356. call syscall
  357. jnc .LDOSSEEK1
  358. movw %ax,inoutres;
  359. .LDOSSEEK1:
  360. end;
  361. function do_seekend(handle:longint):longint; assembler;
  362. asm
  363. movw $0x4202,%ax
  364. movl handle,%ebx
  365. xorl %edx,%edx
  366. call syscall
  367. jnc .Lset_at_end1
  368. movw %ax,inoutres;
  369. xorl %eax,%eax
  370. .Lset_at_end1:
  371. end;
  372. function do_filesize(handle:longint):longint;
  373. var aktfilepos:longint;
  374. begin
  375. aktfilepos:=do_filepos(handle);
  376. do_filesize:=do_seekend(handle);
  377. do_seek(handle,aktfilepos);
  378. end;
  379. procedure do_truncate(handle,pos:longint); assembler;
  380. asm
  381. (* DOS function 40h isn't safe for this according to EMX documentation *)
  382. movl $0x7F25,%eax
  383. movl Handle,%ebx
  384. movl Pos,%edx
  385. call syscall
  386. incl %eax
  387. movl %ecx, %eax
  388. jnz .LTruncate1 { compare the value of EAX to verify error }
  389. (* File position is undefined after truncation, move to the end. *)
  390. movl $0x4202,%eax
  391. movl Handle,%ebx
  392. movl $0,%edx
  393. call syscall
  394. jnc .LTruncate2
  395. .LTruncate1:
  396. movw %ax,inoutres;
  397. .LTruncate2:
  398. end;
  399. const
  400. FileHandleCount: longint = 20;
  401. function Increase_File_Handle_Count: boolean;
  402. var Err: word;
  403. L1, L2: longint;
  404. begin
  405. if os_mode = osOS2 then
  406. begin
  407. L1 := 10;
  408. if DosSetRelMaxFH (L1, L2) <> 0 then
  409. Increase_File_Handle_Count := false
  410. else
  411. if L2 > FileHandleCount then
  412. begin
  413. FileHandleCount := L2;
  414. Increase_File_Handle_Count := true;
  415. end
  416. else
  417. Increase_File_Handle_Count := false;
  418. end
  419. else
  420. begin
  421. Inc (FileHandleCount, 10);
  422. Err := 0;
  423. asm
  424. movl $0x6700, %eax
  425. movl FileHandleCount, %ebx
  426. call syscall
  427. jnc .LIncFHandles
  428. movw %ax, Err
  429. .LIncFHandles:
  430. end;
  431. if Err <> 0 then
  432. begin
  433. Increase_File_Handle_Count := false;
  434. Dec (FileHandleCount, 10);
  435. end
  436. else
  437. Increase_File_Handle_Count := true;
  438. end;
  439. end;
  440. procedure do_open(var f;p:pchar;flags:longint);
  441. {
  442. filerec and textrec have both handle and mode as the first items so
  443. they could use the same routine for opening/creating.
  444. when (flags and $100) the file will be append
  445. when (flags and $1000) the file will be truncate/rewritten
  446. when (flags and $10000) there is no check for close (needed for textfiles)
  447. }
  448. var Action: longint;
  449. begin
  450. allowslash(p);
  451. { close first if opened }
  452. if ((flags and $10000)=0) then
  453. begin
  454. case filerec(f).mode of
  455. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  456. fmclosed:;
  457. else
  458. begin
  459. inoutres:=102; {not assigned}
  460. exit;
  461. end;
  462. end;
  463. end;
  464. { reset file handle }
  465. filerec(f).handle := UnusedHandle;
  466. Action := 0;
  467. { convert filemode to filerec modes }
  468. case (flags and 3) of
  469. 0 : filerec(f).mode:=fminput;
  470. 1 : filerec(f).mode:=fmoutput;
  471. 2 : filerec(f).mode:=fminout;
  472. end;
  473. if (flags and $1000)<>0 then
  474. Action := $50000; (* Create / replace *)
  475. { empty name is special }
  476. if p[0]=#0 then
  477. begin
  478. case FileRec(f).mode of
  479. fminput :
  480. FileRec(f).Handle:=StdInputHandle;
  481. fminout, { this is set by rewrite }
  482. fmoutput :
  483. FileRec(f).Handle:=StdOutputHandle;
  484. fmappend :
  485. begin
  486. FileRec(f).Handle:=StdOutputHandle;
  487. FileRec(f).mode:=fmoutput; {fool fmappend}
  488. end;
  489. end;
  490. exit;
  491. end;
  492. Action := Action or (Flags and $FF);
  493. (* DenyNone if sharing not specified. *)
  494. if Flags and 112 = 0 then
  495. Action := Action or 64;
  496. asm
  497. movl $0x7f2b, %eax
  498. movl Action, %ecx
  499. movl p, %edx
  500. call syscall
  501. cmpl $0xffffffff, %eax
  502. jnz .LOPEN1
  503. movw %cx, InOutRes
  504. movw UnusedHandle, %ax
  505. .LOPEN1:
  506. movl f,%edx { Warning : This assumes Handle is first }
  507. movw %ax,(%edx) { field of FileRec }
  508. end;
  509. if (InOutRes = 4) and Increase_File_Handle_Count then
  510. (* Trying again after increasing amount of file handles *)
  511. asm
  512. movl $0x7f2b, %eax
  513. movl Action, %ecx
  514. movl p, %edx
  515. call syscall
  516. cmpl $0xffffffff, %eax
  517. jnz .LOPEN2
  518. movw %cx, InOutRes
  519. movw UnusedHandle, %ax
  520. .LOPEN2:
  521. movl f,%edx
  522. movw %ax,(%edx)
  523. end;
  524. { for systems that have more handles }
  525. if FileRec (F).Handle > FileHandleCount then
  526. FileHandleCount := FileRec (F).Handle;
  527. if ((Flags and $100) <> 0) and
  528. (FileRec (F).Handle <> UnusedHandle) then
  529. begin
  530. do_seekend (FileRec (F).Handle);
  531. FileRec (F).Mode := fmOutput; {fool fmappend}
  532. end;
  533. end;
  534. {$ASMMODE INTEL}
  535. function do_isdevice (Handle: longint): boolean; assembler;
  536. (*
  537. var HT, Attr: longint;
  538. begin
  539. if os_mode = osOS2 then
  540. begin
  541. if DosQueryHType (Handle, HT, Attr) <> 0 then HT := 1;
  542. end
  543. else
  544. *)
  545. asm
  546. mov ebx, Handle
  547. mov eax, 4400h
  548. call syscall
  549. mov eax, 1
  550. jc @IsDevEnd
  551. test edx, 80h { verify if it is a file }
  552. jnz @IsDevEnd
  553. dec eax { nope, so result is zero }
  554. @IsDevEnd:
  555. end;
  556. {$ASMMODE ATT}
  557. {*****************************************************************************
  558. UnTyped File Handling
  559. *****************************************************************************}
  560. {$i file.inc}
  561. {*****************************************************************************
  562. Typed File Handling
  563. *****************************************************************************}
  564. {$i typefile.inc}
  565. {*****************************************************************************
  566. Text File Handling
  567. *****************************************************************************}
  568. {$DEFINE EOF_CTRLZ}
  569. {$i text.inc}
  570. {****************************************************************************
  571. Directory related routines.
  572. ****************************************************************************}
  573. {*****************************************************************************
  574. Directory Handling
  575. *****************************************************************************}
  576. procedure dosdir(func:byte;const s:string);
  577. var buffer:array[0..255] of char;
  578. begin
  579. move(s[1],buffer,length(s));
  580. buffer[length(s)]:=#0;
  581. allowslash(Pchar(@buffer));
  582. asm
  583. leal buffer,%edx
  584. movb func,%ah
  585. call syscall
  586. jnc .LDOS_DIRS1
  587. movw %ax,inoutres
  588. .LDOS_DIRS1:
  589. end;
  590. end;
  591. procedure MkDir (const S: string);[IOCHECK];
  592. var buffer:array[0..255] of char;
  593. Rc : word;
  594. begin
  595. If (s='') or (InOutRes <> 0) then
  596. exit;
  597. if os_mode = osOs2 then
  598. begin
  599. move(s[1],buffer,length(s));
  600. buffer[length(s)]:=#0;
  601. allowslash(Pchar(@buffer));
  602. Rc := DosCreateDir(buffer,nil);
  603. if Rc <> 0 then
  604. begin
  605. InOutRes := Rc;
  606. Errno2Inoutres;
  607. end;
  608. end
  609. else
  610. begin
  611. { Under EMX 0.9d DOS this routine call may sometimes fail }
  612. { The syscall documentation indicates clearly that this }
  613. { routine was NOT tested. }
  614. DosDir ($39, S);
  615. end;
  616. end;
  617. procedure rmdir(const s : string);[IOCHECK];
  618. var buffer:array[0..255] of char;
  619. Rc : word;
  620. begin
  621. if (s = '.' ) then
  622. InOutRes := 16;
  623. If (s='') or (InOutRes <> 0) then
  624. exit;
  625. if os_mode = osOs2 then
  626. begin
  627. move(s[1],buffer,length(s));
  628. buffer[length(s)]:=#0;
  629. allowslash(Pchar(@buffer));
  630. Rc := DosDeleteDir(buffer);
  631. if Rc <> 0 then
  632. begin
  633. InOutRes := Rc;
  634. Errno2Inoutres;
  635. end;
  636. end
  637. else
  638. begin
  639. { Under EMX 0.9d DOS this routine call may sometimes fail }
  640. { The syscall documentation indicates clearly that this }
  641. { routine was NOT tested. }
  642. DosDir ($3A, S);
  643. end;
  644. end;
  645. {$ASMMODE INTEL}
  646. procedure ChDir (const S: string);[IOCheck];
  647. var RC: longint;
  648. Buffer: array [0..255] of char;
  649. begin
  650. If (s='') or (InOutRes <> 0) then
  651. exit;
  652. (* According to EMX documentation, EMX has only one current directory
  653. for all processes, so we'll use native calls under OS/2. *)
  654. if os_Mode = osOS2 then
  655. begin
  656. if (Length (S) >= 2) and (S [2] = ':') then
  657. begin
  658. RC := DosSetDefaultDisk ((Ord (S [1]) and
  659. not ($20)) - $40);
  660. if RC <> 0 then
  661. InOutRes := RC
  662. else
  663. if Length (S) > 2 then
  664. begin
  665. Move (S [1], Buffer, Length (S));
  666. Buffer [Length (S)] := #0;
  667. AllowSlash (PChar (@Buffer));
  668. RC := DosSetCurrentDir (@Buffer);
  669. if RC <> 0 then
  670. begin
  671. InOutRes := RC;
  672. Errno2InOutRes;
  673. end;
  674. end;
  675. end
  676. else
  677. begin
  678. Move (S [1], Buffer, Length (S));
  679. Buffer [Length (S)] := #0;
  680. AllowSlash (PChar (@Buffer));
  681. RC := DosSetCurrentDir (@Buffer);
  682. if RC <> 0 then
  683. begin
  684. InOutRes:= RC;
  685. Errno2InOutRes;
  686. end;
  687. end;
  688. end
  689. else
  690. if (Length (S) >= 2) and (S [2] = ':') then
  691. begin
  692. asm
  693. mov esi, S
  694. mov al, [esi + 1]
  695. and al, not (20h)
  696. sub al, 41h
  697. mov edx, eax
  698. mov ah, 0Eh
  699. call syscall
  700. mov ah, 19h
  701. call syscall
  702. cmp al, dl
  703. jz @LCHDIR
  704. mov InOutRes, 15
  705. @LCHDIR:
  706. end;
  707. if (Length (S) > 2) and (InOutRes <> 0) then
  708. { Under EMX 0.9d DOS this routine may sometime }
  709. { fail or crash the system. }
  710. DosDir ($3B, S);
  711. end
  712. else
  713. { Under EMX 0.9d DOS this routine may sometime }
  714. { fail or crash the system. }
  715. DosDir ($3B, S);
  716. end;
  717. {$ASMMODE ATT}
  718. procedure GetDir (DriveNr: byte; var Dir: ShortString);
  719. {Written by Michael Van Canneyt.}
  720. var sof:Pchar;
  721. i:byte;
  722. begin
  723. Dir [4] := #0;
  724. { Used in case the specified drive isn't available }
  725. sof:=pchar(@dir[4]);
  726. { dir[1..3] will contain '[drivenr]:\', but is not }
  727. { supplied by DOS, so we let dos string start at }
  728. { dir[4] }
  729. { Get dir from drivenr : 0=default, 1=A etc... }
  730. asm
  731. movb drivenr,%dl
  732. movl sof,%esi
  733. mov $0x47,%ah
  734. call syscall
  735. jnc .LGetDir
  736. movw %ax, InOutRes
  737. .LGetDir:
  738. end;
  739. { Now Dir should be filled with directory in ASCIIZ, }
  740. { starting from dir[4] }
  741. dir[0]:=#3;
  742. dir[2]:=':';
  743. dir[3]:='\';
  744. i:=4;
  745. {Conversion to Pascal string }
  746. while (dir[i]<>#0) do
  747. begin
  748. { convert path name to DOS }
  749. if dir[i]='/' then
  750. dir[i]:='\';
  751. dir[0]:=char(i);
  752. inc(i);
  753. end;
  754. { upcase the string (FPC function) }
  755. if drivenr<>0 then { Drive was supplied. We know it }
  756. dir[1]:=chr(64+drivenr)
  757. else
  758. begin
  759. { We need to get the current drive from DOS function 19H }
  760. { because the drive was the default, which can be unknown }
  761. asm
  762. movb $0x19,%ah
  763. call syscall
  764. addb $65,%al
  765. movb %al,i
  766. end;
  767. dir[1]:=char(i);
  768. end;
  769. if not (FileNameCaseSensitive) then dir:=upcase(dir);
  770. end;
  771. {*****************************************************************************
  772. System unit initialization.
  773. ****************************************************************************}
  774. {****************************************************************************
  775. Error Message writing using messageboxes
  776. ****************************************************************************}
  777. type
  778. TWinMessageBox = function (Parent, Owner: cardinal;
  779. BoxText, BoxTitle: PChar; Identity, Style: cardinal): cardinal; cdecl;
  780. TWinInitialize = function (Options: cardinal): cardinal; cdecl;
  781. TWinCreateMsgQueue = function (Handle: cardinal; cmsg: longint): cardinal;
  782. cdecl;
  783. const
  784. ErrorBufferLength = 1024;
  785. mb_OK = $0000;
  786. mb_Error = $0040;
  787. mb_Moveable = $4000;
  788. MBStyle = mb_OK or mb_Error or mb_Moveable;
  789. WinInitialize: TWinInitialize = nil;
  790. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  791. WinMessageBox: TWinMessageBox = nil;
  792. EnvSize: cardinal = 0;
  793. var
  794. ErrorBuf: array [0..ErrorBufferLength] of char;
  795. ErrorLen: longint;
  796. PMWinHandle: cardinal;
  797. function ErrorWrite (var F: TextRec): integer;
  798. {
  799. An error message should always end with #13#10#13#10
  800. }
  801. var
  802. P: PChar;
  803. I: longint;
  804. begin
  805. if F.BufPos > 0 then
  806. begin
  807. if F.BufPos + ErrorLen > ErrorBufferLength then
  808. I := ErrorBufferLength - ErrorLen
  809. else
  810. I := F.BufPos;
  811. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  812. Inc (ErrorLen, I);
  813. ErrorBuf [ErrorLen] := #0;
  814. end;
  815. if ErrorLen > 3 then
  816. begin
  817. P := @ErrorBuf [ErrorLen];
  818. for I := 1 to 4 do
  819. begin
  820. Dec (P);
  821. if not (P^ in [#10, #13]) then
  822. break;
  823. end;
  824. end;
  825. if ErrorLen = ErrorBufferLength then
  826. I := 4;
  827. if (I = 4) then
  828. begin
  829. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  830. ErrorLen := 0;
  831. end;
  832. F.BufPos := 0;
  833. ErrorWrite := 0;
  834. end;
  835. function ErrorClose (var F: TextRec): integer;
  836. begin
  837. if ErrorLen > 0 then
  838. begin
  839. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  840. ErrorLen := 0;
  841. end;
  842. ErrorLen := 0;
  843. ErrorClose := 0;
  844. end;
  845. function ErrorOpen (var F: TextRec): integer;
  846. begin
  847. TextRec(F).InOutFunc := @ErrorWrite;
  848. TextRec(F).FlushFunc := @ErrorWrite;
  849. TextRec(F).CloseFunc := @ErrorClose;
  850. ErrorOpen := 0;
  851. end;
  852. procedure AssignError (var T: Text);
  853. begin
  854. Assign (T, '');
  855. TextRec (T).OpenFunc := @ErrorOpen;
  856. Rewrite (T);
  857. end;
  858. procedure DosEnvInit;
  859. var
  860. Q: PPChar;
  861. I: cardinal;
  862. begin
  863. (* It's a hack, in fact - DOS stores the environment the same way as OS/2 does,
  864. but I don't know how to find Program Segment Prefix and thus the environment
  865. address under EMX, so I'm recreating this structure using EnvP pointer. *)
  866. {$ASMMODE INTEL}
  867. asm
  868. cld
  869. mov ecx, EnvC
  870. mov esi, EnvP
  871. xor eax, eax
  872. xor edx, edx
  873. @L1:
  874. xchg eax, edx
  875. push ecx
  876. mov ecx, -1
  877. mov edi, [esi]
  878. repne
  879. scasb
  880. neg ecx
  881. dec ecx
  882. xchg eax, edx
  883. add eax, ecx
  884. pop ecx
  885. dec ecx
  886. jecxz @Stop
  887. inc esi
  888. inc esi
  889. inc esi
  890. inc esi
  891. jmp @L1
  892. @Stop:
  893. inc eax
  894. mov EnvSize, eax
  895. end;
  896. Environment := GetMem (EnvSize);
  897. asm
  898. cld
  899. mov ecx, EnvC
  900. mov edx, EnvP
  901. mov edi, Environment
  902. @L2:
  903. mov esi, [edx]
  904. @Copying:
  905. lodsb
  906. stosb
  907. or al, al
  908. jnz @Copying
  909. dec ecx
  910. jecxz @Stop2
  911. inc edx
  912. inc edx
  913. inc edx
  914. inc edx
  915. jmp @L2
  916. @Stop2:
  917. stosb
  918. end;
  919. end;
  920. procedure SysInitStdIO;
  921. begin
  922. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  923. displayed in a messagebox }
  924. (*
  925. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  926. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  927. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  928. if not IsConsole then
  929. begin
  930. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  931. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  932. and
  933. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  934. and
  935. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  936. = 0)
  937. then
  938. begin
  939. WinInitialize (0);
  940. WinCreateMsgQueue (0, 0);
  941. end
  942. else
  943. HandleError (2);
  944. AssignError (StdErr);
  945. AssignError (StdOut);
  946. Assign (Output, '');
  947. Assign (Input, '');
  948. end
  949. else
  950. begin
  951. *)
  952. OpenStdIO (Input, fmInput, StdInputHandle);
  953. OpenStdIO (Output, fmOutput, StdOutputHandle);
  954. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  955. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  956. (*
  957. end;
  958. *)
  959. end;
  960. function GetFileHandleCount: longint;
  961. var L1, L2: longint;
  962. begin
  963. L1 := 0; (* Don't change the amount, just check. *)
  964. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  965. else GetFileHandleCount := L2;
  966. end;
  967. var TIB: PThreadInfoBlock;
  968. PIB: PProcessInfoBlock;
  969. begin
  970. IsLibrary := FALSE;
  971. {Determine the operating system we are running on.}
  972. {$ASMMODE INTEL}
  973. asm
  974. mov os_mode, 0
  975. mov eax, 7F0Ah
  976. call syscall
  977. test bx, 512 {Bit 9 is OS/2 flag.}
  978. setne byte ptr os_mode
  979. test bx, 4096
  980. jz @noRSX
  981. mov os_mode, 2
  982. @noRSX:
  983. {Enable the brk area by initializing it with the initial heap size.}
  984. mov eax, 7F01h
  985. mov edx, heap_brk
  986. add edx, heap_base
  987. call syscall
  988. cmp eax, -1
  989. jnz @heapok
  990. push dword 204
  991. call HandleError
  992. @heapok:
  993. {$IFDEF CONTHEAP}
  994. { Find out brk limit }
  995. mov eax, 7F02h
  996. mov ecx, 3
  997. call syscall
  998. jcxz @heaplimitknown
  999. mov eax, 0
  1000. @heaplimitknown:
  1001. mov BrkLimit, eax
  1002. {$ELSE CONTHEAP}
  1003. { Change sbrk behaviour to allocate arbitrary (non-contiguous) memory blocks }
  1004. mov eax, 7F0Fh
  1005. mov ecx, 0Ch
  1006. mov edx, 8
  1007. call syscall
  1008. {$ENDIF CONTHEAP}
  1009. end;
  1010. { in OS/2 this will always be nil, but in DOS mode }
  1011. { this can be changed. }
  1012. first_meg := nil;
  1013. {Now request, if we are running under DOS,
  1014. read-access to the first meg. of memory.}
  1015. if os_mode in [osDOS,osDPMI] then
  1016. asm
  1017. mov eax, 7F13h
  1018. xor ebx, ebx
  1019. mov ecx, 0FFFh
  1020. xor edx, edx
  1021. call syscall
  1022. jc @endmem
  1023. mov first_meg, eax
  1024. @endmem:
  1025. end
  1026. else
  1027. begin
  1028. (* Initialize the amount of file handles *)
  1029. FileHandleCount := GetFileHandleCount;
  1030. end;
  1031. {At 0.9.2, case for enumeration does not work.}
  1032. case os_mode of
  1033. osDOS:
  1034. begin
  1035. stackbottom:=cardinal(heap_brk); {In DOS mode, heap_brk is
  1036. also the stack bottom.}
  1037. ApplicationType := 1; (* Running under DOS. *)
  1038. IsConsole := true;
  1039. DosEnvInit;
  1040. end;
  1041. osOS2:
  1042. begin
  1043. DosGetInfoBlocks (@TIB, @PIB);
  1044. StackBottom := cardinal (TIB^.Stack);
  1045. Environment := pointer (PIB^.Env);
  1046. ApplicationType := PIB^.ProcType;
  1047. IsConsole := ApplicationType <> 3;
  1048. end;
  1049. osDPMI:
  1050. begin
  1051. stackbottom:=0; {Not sure how to get it, but seems to be
  1052. always zero.}
  1053. ApplicationType := 1; (* Running under DOS. *)
  1054. IsConsole := true;
  1055. DosEnvInit;
  1056. end;
  1057. end;
  1058. exitproc:=nil;
  1059. {Initialize the heap.}
  1060. initheap;
  1061. { ... and exceptions }
  1062. SysInitExceptions;
  1063. { ... and I/O }
  1064. SysInitStdIO;
  1065. { no I/O-Error }
  1066. inoutres:=0;
  1067. {$ifdef HASVARIANT}
  1068. initvariantmanager;
  1069. {$endif HASVARIANT}
  1070. {$IFDEF DUMPGROW}
  1071. {$IFDEF CONTHEAP}
  1072. WriteLn ('Initial brk size is ', GetHeapSize);
  1073. WriteLn ('Brk limit is ', BrkLimit);
  1074. {$ENDIF CONTHEAP}
  1075. {$ENDIF DUMPGROW}
  1076. end.
  1077. {
  1078. $Log$
  1079. Revision 1.8 2003-09-29 18:39:59 hajny
  1080. * append fix applied to GO32v2, OS/2 and EMX
  1081. Revision 1.7 2003/09/27 11:52:35 peter
  1082. * sbrk returns pointer
  1083. Revision 1.6 2003/09/24 11:13:09 yuri
  1084. * Cosmetic changes
  1085. * Slightly improved emx.pas
  1086. Revision 1.5 2003/06/26 17:12:29 yuri
  1087. * pmbidi added
  1088. * some cosmetic changes
  1089. Revision 1.4 2003/03/23 23:11:17 hajny
  1090. + emx target added
  1091. Revision 1.3 2002/12/15 22:46:29 hajny
  1092. * First_Meg fixed + Environment initialization under Dos
  1093. Revision 1.2 2002/11/17 22:32:05 hajny
  1094. * type corrections (longing x cardinal)
  1095. Revision 1.1 2002/11/17 16:22:54 hajny
  1096. + RTL for emx target
  1097. }