system.pas 36 KB

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