system.pas 34 KB

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