system.pas 36 KB

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