system.pas 36 KB

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