system.pas 33 KB

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