system.pas 33 KB

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