system.pas 34 KB

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