system.pas 33 KB

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