system.pas 33 KB

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