mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-06 06:28:04 +02:00
1529 lines
43 KiB
ObjectPascal
1529 lines
43 KiB
ObjectPascal
{
|
|
****************************************************************************
|
|
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 1999-2015 by Free Pascal development team
|
|
|
|
Free Pascal - OS/2 runtime library
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
****************************************************************************}
|
|
|
|
unit System;
|
|
|
|
interface
|
|
|
|
{$ifdef SYSTEMDEBUG}
|
|
{$define SYSTEMEXCEPTIONDEBUG}
|
|
{.$define IODEBUG}
|
|
{.$define DEBUGENVIRONMENT}
|
|
{.$define DEBUGARGUMENTS}
|
|
{.$define DEBUGOSERRORS}
|
|
{$endif SYSTEMDEBUG}
|
|
|
|
{$DEFINE OS2EXCEPTIONS}
|
|
{$DEFINE OS2UNICODE}
|
|
{$define DISABLE_NO_THREAD_MANAGER}
|
|
{$define DISABLE_NO_DYNLIBS_MANAGER}
|
|
{$DEFINE HAS_GETCPUCOUNT}
|
|
{$define FPC_SYSTEM_HAS_SYSDLH}
|
|
|
|
{$I systemh.inc}
|
|
|
|
|
|
const
|
|
LineEnding = #13#10;
|
|
{ LFNSupport is defined separately below!!! }
|
|
DirectorySeparator = '\';
|
|
DriveSeparator = ':';
|
|
ExtensionSeparator = '.';
|
|
PathSeparator = ';';
|
|
AllowDirectorySeparators : set of AnsiChar = ['\','/'];
|
|
AllowDriveSeparators : set of AnsiChar = [':'];
|
|
{ FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
|
|
MaxExitCode = 65535;
|
|
MaxPathLen = 260;
|
|
(* MaxPathLen is referenced as constant from unit SysUtils *)
|
|
(* - changing to variable or typed constant is not possible. *)
|
|
AllFilesMask = '*';
|
|
RealMaxPathLen: word = MaxPathLen;
|
|
(* Default value only - real value queried from the system on startup. *)
|
|
|
|
type
|
|
TOS = (osDOS, osOS2, osDPMI); (* For compatibility with target EMX *)
|
|
TUConvObject = pointer;
|
|
TLocaleObject = pointer;
|
|
|
|
const
|
|
OS_Mode: TOS = osOS2; (* For compatibility with target EMX *)
|
|
First_Meg: pointer = nil; (* For compatibility with target EMX *)
|
|
|
|
UnusedHandle=-1;
|
|
StdInputHandle=0;
|
|
StdOutputHandle=1;
|
|
StdErrorHandle=2;
|
|
|
|
LFNSupport: boolean = true;
|
|
FileNameCaseSensitive: boolean = false;
|
|
FileNameCasePreserving: boolean = true;
|
|
CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
|
|
RTLUsesWinCP: boolean = true; (* UnicodeString manager shall treat *)
|
|
(* codepage numbers passed to RTL functions as those used under MS Windows *)
|
|
(* and translates them to their OS/2 equivalents if necessary. *)
|
|
|
|
sLineBreak = LineEnding;
|
|
DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
|
|
|
|
var
|
|
{ C-compatible arguments and environment }
|
|
argc : longint;
|
|
argv : PPAnsiChar;
|
|
envp : PPAnsiChar;
|
|
EnvC: cardinal;
|
|
|
|
(* Pointer to the block of environment variables - used e.g. in unit Dos. *)
|
|
Environment: PAnsiChar;
|
|
|
|
|
|
var
|
|
(* Type / run mode of the current process: *)
|
|
(* 0 .. full screen OS/2 session *)
|
|
(* 1 .. DOS session *)
|
|
(* 2 .. VIO windowable OS/2 session *)
|
|
(* 3 .. Presentation Manager OS/2 session *)
|
|
(* 4 .. detached (background) OS/2 process *)
|
|
ApplicationType: cardinal;
|
|
|
|
const
|
|
HeapAllocFlags: cardinal = $53; (* Compatible to VP/2 *)
|
|
(* mfPag_Commit or mfObj_Tile or mfPag_Write or mfPag_Read *)
|
|
|
|
function ReadUseHighMem: boolean;
|
|
|
|
procedure WriteUseHighMem (B: boolean);
|
|
|
|
(* Is allocation of memory above 512 MB address limit allowed? Even if use *)
|
|
(* of high memory is supported by the underlying OS/2 version, just a subset *)
|
|
(* of OS/2 API functions can work with memory buffers located in high *)
|
|
(* memory. Since FPC RTL allocates heap using memory pools received from *)
|
|
(* the operating system and thus memory allocation from the operating system *)
|
|
(* may happen at a different time than allocation of memory from FPC heap, *)
|
|
(* use of high memory shall be enabled only if the given program is ensured *)
|
|
(* not to use any OS/2 API function beyond the limited set supporting it any *)
|
|
(* time between enabling this feature and program termination. *)
|
|
property
|
|
UseHighMem: boolean read ReadUseHighMem write WriteUseHighMem;
|
|
(* UseHighMem is provided for compatibility with 2.0.x. *)
|
|
|
|
|
|
{$IFDEF OS2UNICODE}
|
|
function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte;
|
|
var UConvObj: TUConvObject): TSystemCodepage;
|
|
|
|
function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte;
|
|
var UConvObj: TUConvObject): cardinal;
|
|
|
|
function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte): TSystemCodepage;
|
|
|
|
function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte): cardinal;
|
|
|
|
(* function RtlChangeCP (CP: TSystemCodePage; const stdcp: TStandardCodePageEnum): longint; *)
|
|
{$ENDIF OS2UNICODE}
|
|
|
|
|
|
const
|
|
(* Are file sizes > 2 GB (64-bit) supported on the current system? *)
|
|
FSApi64: boolean = false;
|
|
(* Is full Unicode support provided by the underlying OS/2 version available *)
|
|
(* and successfully initialized (otherwise dummy routines need to be used). *)
|
|
UniAPI: boolean = false;
|
|
|
|
(* Support for tracking I/O errors returned by OS/2 API calls - emulation *)
|
|
(* of GetLastError / fpGetError functionality used e.g. in Sysutils. *)
|
|
type
|
|
TOSErrorWatch = procedure (Error: cardinal);
|
|
|
|
procedure NoErrorTracking (Error: cardinal);
|
|
|
|
(* This shall be invoked whenever a non-zero error is returned by OS/2 APIs *)
|
|
(* used in the RTL. Direct OS/2 API calls in user programs are not covered! *)
|
|
const
|
|
OSErrorWatch: TOSErrorWatch = @NoErrorTracking;
|
|
|
|
|
|
function SetOSErrorTracking (P: pointer): pointer;
|
|
|
|
procedure SetDefaultOS2FileType (FType: ShortString);
|
|
|
|
procedure SetDefaultOS2Creator (Creator: ShortString);
|
|
|
|
type
|
|
TDosOpenL = function (FileName: PAnsiChar; var Handle: THandle;
|
|
var Action: cardinal; InitSize: int64;
|
|
Attrib, OpenFlags, FileMode: cardinal;
|
|
EA: pointer): cardinal; cdecl;
|
|
|
|
TDosSetFilePtrL = function (Handle: THandle; Pos: int64; Method: cardinal;
|
|
var PosActual: int64): cardinal; cdecl;
|
|
|
|
TDosSetFileSizeL = function (Handle: THandle; Size: int64): cardinal; cdecl;
|
|
|
|
|
|
TUniCreateUConvObject = function (const CpName: PWideChar;
|
|
var UConv_Object: TUConvObject): longint; cdecl;
|
|
|
|
TUniFreeUConvObject = function (UConv_Object: TUConvObject): longint; cdecl;
|
|
|
|
TUniMapCpToUcsCp = function (const Codepage: cardinal;
|
|
CodepageName: PWideChar; const N: cardinal): longint; cdecl;
|
|
|
|
TUniUConvFromUcs = function (UConv_Object: TUConvObject;
|
|
var UcsBuf: PWideChar; var UniCharsLeft: longint; var OutBuf: PAnsiChar;
|
|
var OutBytesLeft: longint; var NonIdentical: longint): longint; cdecl;
|
|
|
|
TUniUConvToUcs = function (UConv_Object: TUConvObject; var InBuf: PAnsiChar;
|
|
var InBytesLeft: longint; var UcsBuf: PWideChar; var UniCharsLeft: longint;
|
|
var NonIdentical: longint): longint; cdecl;
|
|
|
|
TUniToLower = function (UniCharIn: WideChar): WideChar; cdecl;
|
|
|
|
TUniToUpper = function (UniCharIn: WideChar): WideChar; cdecl;
|
|
|
|
TUniStrColl = function (Locale_Object: TLocaleObject;
|
|
const UCS1, UCS2: PWideChar): longint; cdecl;
|
|
|
|
TUniCreateLocaleObject = function (LocaleSpecType: longint;
|
|
const LocaleSpec: pointer;
|
|
var Locale_Object: TLocaleObject): longint; cdecl;
|
|
|
|
TUniFreeLocaleObject = function (Locale_Object: TLocaleObject): longint;
|
|
cdecl;
|
|
|
|
TUniMapCtryToLocale = function (CountryCode: cardinal; LocaleName: PWideChar;
|
|
BufSize: longint): longint; cdecl;
|
|
|
|
|
|
const
|
|
DosCallsHandle: THandle = THandle (-1);
|
|
{$IFDEF OS2UNICODE}
|
|
UConvHandle: THandle = THandle (-1);
|
|
LibUniHandle: THandle = THandle (-1);
|
|
{$ENDIF OS2UNICODE}
|
|
|
|
|
|
var
|
|
Sys_DosOpenL: TDosOpenL;
|
|
Sys_DosSetFilePtrL: TDosSetFilePtrL;
|
|
Sys_DosSetFileSizeL: TDosSetFileSizeL;
|
|
{$IFDEF OS2UNICODE}
|
|
Sys_UniCreateUConvObject: TUniCreateUConvObject;
|
|
Sys_UniFreeUConvObject: TUniFreeUConvObject;
|
|
Sys_UniMapCpToUcsCp: TUniMapCpToUcsCp;
|
|
Sys_UniUConvFromUcs: TUniUConvFromUcs;
|
|
Sys_UniUConvToUcs: TUniUConvToUcs;
|
|
Sys_UniToLower: TUniToLower;
|
|
Sys_UniToUpper: TUniToUpper;
|
|
Sys_UniStrColl: TUniStrColl;
|
|
Sys_UniCreateLocaleObject: TUniCreateLocaleObject;
|
|
Sys_UniFreeLocaleObject: TUniFreeLocaleObject;
|
|
Sys_UniMapCtryToLocale: TUniMapCtryToLocale;
|
|
|
|
{$ENDIF OS2UNICODE}
|
|
|
|
{$IFDEF SYSTEMDEBUG}
|
|
var
|
|
SysLastOSError: cardinal;
|
|
{$ENDIF SYSTEMDEBUG}
|
|
|
|
function GetDynLibsError: longint;
|
|
|
|
function GetDynLibsErrPath: PAnsiChar;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
{*****************************************************************************
|
|
|
|
System unit initialization.
|
|
|
|
****************************************************************************}
|
|
|
|
{$I system.inc}
|
|
|
|
{*****************************************************************************
|
|
|
|
Exception handling.
|
|
|
|
****************************************************************************}
|
|
|
|
{$IFDEF OS2EXCEPTIONS}
|
|
var
|
|
{ value of the stack segment
|
|
to check if the call stack can be written on exceptions }
|
|
_SS : Cardinal;
|
|
|
|
function Is_Prefetch (P: pointer): boolean;
|
|
var
|
|
A: array [0..15] of byte;
|
|
DoAgain: boolean;
|
|
InstrLo, InstrHi, OpCode: byte;
|
|
I: longint;
|
|
MemSize, MemAttrs: cardinal;
|
|
RC: cardinal;
|
|
begin
|
|
Is_Prefetch := false;
|
|
|
|
MemSize := SizeOf (A);
|
|
RC := DosQueryMem (P, MemSize, MemAttrs);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC)
|
|
else if (MemAttrs and (mfPag_Free or mfPag_Commit) <> 0)
|
|
and (MemSize >= SizeOf (A)) then
|
|
Move (P^, A [0], SizeOf (A))
|
|
else
|
|
Exit;
|
|
I := 0;
|
|
DoAgain := true;
|
|
while DoAgain and (I < 15) do
|
|
begin
|
|
OpCode := A [I];
|
|
InstrLo := OpCode and $f;
|
|
InstrHi := OpCode and $f0;
|
|
case InstrHi of
|
|
{ prefix? }
|
|
$20, $30:
|
|
DoAgain := (InstrLo and 7) = 6;
|
|
$60:
|
|
DoAgain := (InstrLo and $c) = 4;
|
|
$f0:
|
|
DoAgain := InstrLo in [0, 2, 3];
|
|
$0:
|
|
begin
|
|
Is_Prefetch := (InstrLo = $f) and (A [I + 1] in [$D, $18]);
|
|
Exit;
|
|
end;
|
|
else
|
|
DoAgain := false;
|
|
end;
|
|
Inc (I);
|
|
end;
|
|
end;
|
|
|
|
const
|
|
MaxExceptionLevel = 16;
|
|
ExceptLevel: byte = 0;
|
|
|
|
var
|
|
ExceptEIP: array [0..MaxExceptionLevel - 1] of longint;
|
|
ExceptError: array [0..MaxExceptionLevel - 1] of byte;
|
|
ResetFPU: array [0..MaxExceptionLevel - 1] of boolean;
|
|
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
procedure DebugHandleErrorAddrFrame (Error: longint; Addr, Frame: pointer);
|
|
begin
|
|
if IsConsole then
|
|
begin
|
|
Write (StdErr, ' HandleErrorAddrFrame (error = ', Error);
|
|
Write (StdErr, ', addr = ', hexstr (PtrUInt (Addr), 8));
|
|
WriteLn (StdErr, ', frame = ', hexstr (PtrUInt (Frame), 8), ')');
|
|
end;
|
|
HandleErrorAddrFrame (Error, Addr, Frame);
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
|
|
procedure JumpToHandleErrorFrame;
|
|
var
|
|
EIP, EBP, Error: longint;
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
ESP, EBP1: longint;
|
|
{$ENDIF SYSTEMEXCEPTIONDEBUG}
|
|
begin
|
|
(* save ebp *)
|
|
asm
|
|
movl (%ebp),%eax
|
|
movl %eax,ebp
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
movl %ebp,%eax
|
|
movl %eax,EBP1
|
|
movl %esp,%eax
|
|
movl %eax,ESP
|
|
{$ENDIF SYSTEMEXCEPTIONDEBUG}
|
|
end;
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole then
|
|
WriteLn (StdErr, 'Exception level at start of JumpToHandleErrorFrame = ', ExceptLevel);
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
if (ExceptLevel > 0) then
|
|
Dec (ExceptLevel);
|
|
EIP := ExceptEIP [ExceptLevel];
|
|
Error := ExceptError [ExceptLevel];
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole then
|
|
begin
|
|
WriteLn (StdErr, 'In JumpToHandleErrorFrame error = ', Error);
|
|
WriteLn (StdErr, 'EBP on entry: ', HexStr (EBP1, 8));
|
|
WriteLn (StdErr, 'Previous EBP: ', HexStr (EBP, 8));
|
|
WriteLn (StdErr, 'ESP on entry: ', HexStr (ESP, 8));
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
if ResetFPU [ExceptLevel] then
|
|
SysResetFPU;
|
|
{ build a fake stack }
|
|
asm
|
|
{$ifdef REGCALL}
|
|
movl ebp,%ecx
|
|
movl eip,%edx
|
|
movl error,%eax
|
|
pushl eip
|
|
movl ebp,%ebp // Change frame pointer
|
|
{$else}
|
|
movl ebp,%eax
|
|
pushl %eax
|
|
movl eip,%eax
|
|
pushl %eax
|
|
movl error,%eax
|
|
pushl %eax
|
|
movl eip,%eax
|
|
pushl %eax
|
|
movl ebp,%ebp // Change frame pointer
|
|
{$endif}
|
|
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
jmpl DebugHandleErrorAddrFrame
|
|
{$else not SYSTEMEXCEPTIONDEBUG}
|
|
jmpl HandleErrorAddrFrame
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
end;
|
|
end;
|
|
|
|
|
|
function System_Exception_Handler (Report: PExceptionReportRecord;
|
|
RegRec: PExceptionRegistrationRecord;
|
|
Context: PContextRecord;
|
|
DispContext: pointer): cardinal; cdecl;
|
|
var
|
|
Res: cardinal;
|
|
Err: byte;
|
|
Must_Reset_FPU: boolean;
|
|
RC: cardinal;
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
CurSS, CurESP, CurEBP: cardinal;
|
|
B: byte;
|
|
{$ENDIF SYSTEMEXCEPTIONDEBUG}
|
|
begin
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole then
|
|
begin
|
|
asm
|
|
pushl %eax
|
|
xorl %eax,%eax
|
|
movw %ss,%ax
|
|
movl %eax,CurSS
|
|
movl %esp,%eax
|
|
movl %eax,CurESP
|
|
movl %ebp,%eax
|
|
movl %eax,CurEBP
|
|
popl %eax
|
|
end;
|
|
WriteLn (StdErr, '------------------------------------------------------');
|
|
WriteLn (StdErr, 'In System_Exception_Handler, error = ',
|
|
HexStr (Report^.Exception_Num, 8));
|
|
WriteLn (StdErr, 'Handler flags = ', HexStr (Report^.HandlerFlags, 8));
|
|
WriteLn (StdErr, 'Nested_RepRec = ', HexStr (PtrUInt (Report^.Nested_RepRec), 8));
|
|
WriteLn (StdErr, 'Amount of passed parameters = ', Report^.ParamCount);
|
|
WriteLn (StdErr, 'Context SS = ', HexStr (Context^.Reg_SS, 8),
|
|
', current SS = ', HexStr (CurSS, 8));
|
|
WriteLn (StdErr, 'Current ESP = ', HexStr (CurESP, 8),
|
|
', current EBP = ', HexStr (CurEBP, 8));
|
|
WriteLn (StdErr, 'Context flags = ', HexStr (Context^.ContextFlags, 8));
|
|
WriteLn (StdErr, 'Thread ID = ', ThreadID);
|
|
if Context^.ContextFlags and Context_Control <> 0 then
|
|
begin
|
|
WriteLn (StdErr, 'EBP = ', HexStr (Context^.Reg_EBP, 8),
|
|
', SS = ', HexStr (Context^.Reg_SS, 8),
|
|
', ESP = ', HexStr (Context^.Reg_ESP, 8));
|
|
WriteLn (StdErr, 'CS = ', HexStr (Context^.Reg_CS, 8),
|
|
', EIP = ', HexStr (Context^.Reg_EIP, 8),
|
|
', EFlags = ', HexStr (Context^.Flags, 8));
|
|
end;
|
|
if Context^.ContextFlags and Context_Floating_Point <> 0 then
|
|
begin
|
|
for B := 1 to 6 do
|
|
Write (StdErr, 'Ctx Env [', B, '] = ', HexStr (Context^.Env [B], 8),
|
|
', ');
|
|
WriteLn (StdErr, 'Ctx Env [7] = ', HexStr (Context^.Env [7], 8));
|
|
for B := 0 to 6 do
|
|
Write (StdErr, 'FPU stack [', B, '] = ', Context^.FPUStack [B], ', ');
|
|
WriteLn (StdErr, 'FPU stack [7] = ', Context^.FPUStack [7]);
|
|
end;
|
|
if Context^.ContextFlags and Context_Segments <> 0 then
|
|
WriteLn (StdErr, 'GS = ', HexStr (Context^.Reg_GS, 8),
|
|
', FS = ', HexStr (Context^.Reg_FS, 8),
|
|
', ES = ', HexStr (Context^.Reg_ES, 8),
|
|
', DS = ', HexStr (Context^.Reg_DS, 8));
|
|
if Context^.ContextFlags and Context_Integer <> 0 then
|
|
begin
|
|
WriteLn (StdErr, 'EDI = ', HexStr (Context^.Reg_EDI, 8),
|
|
', ESI = ', HexStr (Context^.Reg_ESI, 8));
|
|
WriteLn (StdErr, 'EAX = ', HexStr (Context^.Reg_EAX, 8),
|
|
', EBX = ', HexStr (Context^.Reg_EBX, 8),
|
|
', ECX = ', HexStr (Context^.Reg_ECX, 8),
|
|
', EDX = ', HexStr (Context^.Reg_EDX, 8));
|
|
end;
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
Res := Xcpt_Continue_Search;
|
|
if Context^.Reg_SS = _SS then
|
|
begin
|
|
Err := 0;
|
|
Must_Reset_FPU := true;
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole then
|
|
Writeln (StdErr, 'Exception ', HexStr (Report^.Exception_Num, 8));
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
case Report^.Exception_Num of
|
|
Xcpt_Integer_Divide_By_Zero,
|
|
Xcpt_Float_Divide_By_Zero:
|
|
Err := 208;
|
|
Xcpt_Array_Bounds_Exceeded:
|
|
begin
|
|
Err := 201;
|
|
Must_Reset_FPU := false;
|
|
end;
|
|
Xcpt_Unable_To_Grow_Stack:
|
|
begin
|
|
Err := 202;
|
|
Must_Reset_FPU := false;
|
|
end;
|
|
Xcpt_Float_Overflow:
|
|
Err := 205;
|
|
Xcpt_Float_Denormal_Operand,
|
|
Xcpt_Float_Underflow:
|
|
Err := 206;
|
|
{Context^.FloatSave.StatusWord := Context^.FloatSave.StatusWord and $ffffff00;}
|
|
Xcpt_Float_Inexact_Result,
|
|
Xcpt_Float_Invalid_Operation,
|
|
Xcpt_Float_Stack_Check:
|
|
Err := 207;
|
|
Xcpt_Integer_Overflow:
|
|
begin
|
|
Err := 215;
|
|
Must_Reset_FPU := false;
|
|
end;
|
|
Xcpt_Illegal_Instruction:
|
|
{ if we're testing sse support, simply set the flag and continue }
|
|
if SSE_Check then
|
|
begin
|
|
OS_Supports_SSE := false;
|
|
{ skip the offending movaps %xmm7, %xmm6 instruction }
|
|
Inc (Context^.Reg_EIP, 3);
|
|
Report^.Exception_Num := 0;
|
|
Res := Xcpt_Continue_Execution;
|
|
end
|
|
else
|
|
Err := 216;
|
|
Xcpt_Access_Violation:
|
|
{ Athlon prefetch bug? }
|
|
if Is_Prefetch (pointer (Context^.Reg_EIP)) then
|
|
begin
|
|
{ if yes, then retry }
|
|
Report^.Exception_Num := 0;
|
|
Res := Xcpt_Continue_Execution;
|
|
end
|
|
else
|
|
begin
|
|
Err := 216;
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole and (Report^.ParamCount >= 2) then
|
|
begin
|
|
Writeln (StdErr, 'Access violation flags: ', Report^.Parameters [0]);
|
|
WriteLn (StdErr, 'Fault address: ', HexStr (Report^.Parameters [1], 8));
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
end;
|
|
Xcpt_Signal:
|
|
case Report^.Parameters [0] of
|
|
Xcpt_Signal_KillProc:
|
|
Err := 217;
|
|
Xcpt_Signal_Break,
|
|
Xcpt_Signal_Intr:
|
|
if Assigned (CtrlBreakHandler) then
|
|
if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
|
|
begin
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
WriteLn (StdErr, 'CtrlBreakHandler returned true');
|
|
{$ENDIF SYSTEMEXCEPTIONDEBUG}
|
|
Report^.Exception_Num := 0;
|
|
Res := Xcpt_Continue_Execution;
|
|
RC := DosAcknowledgeSignalException (Report^.Parameters [0]);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
end
|
|
else
|
|
Err := 217;
|
|
end;
|
|
Xcpt_Privileged_Instruction:
|
|
begin
|
|
Err := 218;
|
|
Must_Reset_FPU := false;
|
|
end;
|
|
else
|
|
begin
|
|
if ((Report^.Exception_Num and Xcpt_Severity_Code)
|
|
= Xcpt_Fatal_Exception) then
|
|
Err := 217
|
|
else
|
|
Err := 255;
|
|
end;
|
|
end;
|
|
|
|
if (Err <> 0) and (ExceptLevel < MaxExceptionLevel)
|
|
(* TH: The following line is necessary to avoid an endless loop *)
|
|
and (Report^.Exception_Num < Xcpt_Process_Terminate)
|
|
then
|
|
begin
|
|
ExceptEIP [ExceptLevel] := Context^.Reg_EIP;
|
|
ExceptError [ExceptLevel] := Err;
|
|
ResetFPU [ExceptLevel] := Must_Reset_FPU;
|
|
Inc (ExceptLevel);
|
|
|
|
Context^.Reg_EIP := cardinal (@JumpToHandleErrorFrame);
|
|
Report^.Exception_Num := 0;
|
|
|
|
if Must_Reset_FPU and
|
|
(Context^.ContextFlags and Context_Floating_Point <> 0) then
|
|
begin
|
|
{ Control word is index 1 }
|
|
Context^.Env [1] := Default8087CW;
|
|
{ Status word is index 2 }
|
|
Context^.Env [2] := Context^.Env [2] and not FPU_ExceptionMask;
|
|
{ Tag word is index 3 }
|
|
Context^.Env [3] := $FFFF;
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
WriteLn (StdErr, 'After FPU status reset in context record:');
|
|
for B := 1 to 2 do
|
|
Write (StdErr, 'Ctx Env [', B, '] = ', HexStr (Context^.Env [B], 8),
|
|
', ');
|
|
WriteLn (StdErr, 'Ctx Env [3] = ', HexStr (Context^.Env [3], 8));
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
end;
|
|
Res := Xcpt_Continue_Execution;
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole then
|
|
begin
|
|
WriteLn (StdErr, 'Exception Continue Exception set at ',
|
|
HexStr (ExceptEIP [Pred (ExceptLevel)], 8));
|
|
WriteLn (StdErr, 'EIP changed to ',
|
|
HexStr (Context^.Reg_EIP, 8), ', error = ', Err);
|
|
WriteLn (StdErr, 'Exception level = ', ExceptLevel);
|
|
WriteLn (StdErr, 'ResetFPU = ', ResetFPU [Pred (ExceptLevel)]);
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
end;
|
|
end
|
|
else
|
|
if (Report^.Exception_Num = Xcpt_Signal) and
|
|
(Report^.Parameters [0] and (Xcpt_Signal_Intr or Xcpt_Signal_Break) <> 0)
|
|
and Assigned (CtrlBreakHandler) then
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
begin
|
|
WriteLn (StdErr, 'XCPT_SIGNAL caught, CtrlBreakHandler assigned, Param = ',
|
|
Report^.Parameters [0]);
|
|
{$ENDIF SYSTEMEXCEPTIONDEBUG}
|
|
if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
|
|
begin
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
WriteLn (StdErr, 'CtrlBreakHandler returned true');
|
|
{$ENDIF SYSTEMEXCEPTIONDEBUG}
|
|
Report^.Exception_Num := 0;
|
|
Res := Xcpt_Continue_Execution;
|
|
RC := DosAcknowledgeSignalException (Report^.Parameters [0]);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
end
|
|
else
|
|
Err := 217;
|
|
{$IFDEF SYSTEMEXCEPTIONDEBUG}
|
|
end
|
|
else
|
|
if IsConsole then
|
|
begin
|
|
WriteLn (StdErr, 'Ctx flags = ', HexStr (Context^.ContextFlags, 8));
|
|
if Context^.ContextFlags and Context_Floating_Point <> 0 then
|
|
begin
|
|
for B := 1 to 6 do
|
|
Write (StdErr, 'Ctx Env [', B, '] = ', HexStr (Context^.Env [B], 8),
|
|
', ');
|
|
WriteLn (StdErr, 'Ctx Env [7] = ', HexStr (Context^.Env [7], 8));
|
|
for B := 0 to 6 do
|
|
Write (StdErr, 'FPU stack [', B, '] = ', Context^.FPUStack [B], ', ');
|
|
WriteLn (StdErr, 'FPU stack [7] = ', Context^.FPUStack [7]);
|
|
end;
|
|
if Context^.ContextFlags and Context_Segments <> 0 then
|
|
WriteLn (StdErr, 'GS = ', HexStr (Context^.Reg_GS, 8),
|
|
', FS = ', HexStr (Context^.Reg_FS, 8),
|
|
', ES = ', HexStr (Context^.Reg_ES, 8),
|
|
', DS = ', HexStr (Context^.Reg_DS, 8));
|
|
if Context^.ContextFlags and Context_Integer <> 0 then
|
|
begin
|
|
WriteLn (StdErr, 'EDI = ', HexStr (Context^.Reg_EDI, 8),
|
|
', ESI = ', HexStr (Context^.Reg_ESI, 8));
|
|
WriteLn (StdErr, 'EAX = ', HexStr (Context^.Reg_EAX, 8),
|
|
', EBX = ', HexStr (Context^.Reg_EBX, 8),
|
|
', ECX = ', HexStr (Context^.Reg_ECX, 8),
|
|
', EDX = ', HexStr (Context^.Reg_EDX, 8));
|
|
end;
|
|
if Context^.ContextFlags and Context_Control <> 0 then
|
|
begin
|
|
WriteLn (StdErr, 'EBP = ', HexStr (Context^.Reg_EBP, 8),
|
|
', SS = ', HexStr (Context^.Reg_SS, 8),
|
|
', ESP = ', HexStr (Context^.Reg_ESP, 8));
|
|
WriteLn (StdErr, 'CS = ', HexStr (Context^.Reg_CS, 8),
|
|
', EIP = ', HexStr (Context^.Reg_EIP, 8),
|
|
', EFlags = ', HexStr (Context^.Flags, 8));
|
|
end;
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
System_Exception_Handler := Res;
|
|
end;
|
|
|
|
|
|
var
|
|
ExcptReg: PExceptionRegistrationRecord; public name '_excptregptr';
|
|
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
var
|
|
OldExceptAddr,
|
|
NewExceptAddr: PtrUInt;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
|
|
procedure Install_Exception_Handler;
|
|
var
|
|
T: cardinal;
|
|
RC: cardinal;
|
|
begin
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
(* ThreadInfoBlock is located at FS:[0], the first *)
|
|
(* entry is pointer to head of exception handler chain. *)
|
|
asm
|
|
movl $0,%eax
|
|
movl %fs:(%eax),%eax
|
|
movl %eax, OldExceptAddr
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
with ExcptReg^ do
|
|
begin
|
|
Prev_Structure := nil;
|
|
ExceptionHandler := TExceptionHandler (@System_Exception_Handler);
|
|
end;
|
|
(* Disable pop-up windows for errors and exceptions *)
|
|
DosError (deDisableExceptions);
|
|
DosSetExceptionHandler (ExcptReg^);
|
|
if IsConsole then
|
|
begin
|
|
RC := DosSetSignalExceptionFocus (1, T);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
RC := DosAcknowledgeSignalException (Xcpt_Signal_Intr);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
RC := DosAcknowledgeSignalException (Xcpt_Signal_Break);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
end;
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
asm
|
|
movl $0,%eax
|
|
movl %fs:(%eax),%eax
|
|
movl %eax, NewExceptAddr
|
|
end;
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
end;
|
|
|
|
{$IFDEF SYSTEMDEBUG}
|
|
const
|
|
OrigOSErrorWatch: TOSErrorWatch = nil;
|
|
|
|
procedure TrackLastOSError (Error: cardinal);
|
|
begin
|
|
SysLastOSError := Error;
|
|
{$IFDEF DEBUGOSERRORS}
|
|
if IsConsole then
|
|
WriteLn (StdErr, 'Some OS/2 API returned error ', Error);
|
|
{$ENDIF DEBUGOSERRORS}
|
|
OrigOSErrorWatch (Error);
|
|
end;
|
|
{$ENDIF SYSTEMDEBUG}
|
|
|
|
procedure Remove_Exception_Handlers;
|
|
var
|
|
RC: cardinal;
|
|
begin
|
|
RC := DosUnsetExceptionHandler (ExcptReg^);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
end;
|
|
{$ENDIF OS2EXCEPTIONS}
|
|
|
|
procedure system_exit;
|
|
begin
|
|
(* if IsLibrary then
|
|
ExitDLL(ExitCode);
|
|
*)
|
|
(*
|
|
if not IsConsole then
|
|
begin
|
|
Close(stderr);
|
|
Close(stdout);
|
|
Close(erroutput);
|
|
Close(Input);
|
|
Close(Output);
|
|
end;
|
|
*)
|
|
{$IFDEF OS2EXCEPTIONS}
|
|
Remove_Exception_Handlers;
|
|
{$ENDIF OS2EXCEPTIONS}
|
|
DosExit (1{process}, exitcode);
|
|
end;
|
|
|
|
{$ASMMODE ATT}
|
|
|
|
|
|
|
|
{****************************************************************************
|
|
|
|
Miscellaneous related routines.
|
|
|
|
****************************************************************************}
|
|
|
|
function paramcount:longint;assembler;
|
|
asm
|
|
movl argc,%eax
|
|
decl %eax
|
|
end {['EAX']};
|
|
|
|
function paramstr(l:longint):shortstring;
|
|
|
|
var p:^PAnsiChar;
|
|
|
|
begin
|
|
if (l>=0) and (l<=paramcount) then
|
|
begin
|
|
p:=argv;
|
|
paramstr:=strpas(p[l]);
|
|
end
|
|
else paramstr:='';
|
|
end;
|
|
|
|
procedure randomize;
|
|
var
|
|
dt: TSysDateTime;
|
|
begin
|
|
// Hmm... Lets use timer
|
|
DosGetDateTime(dt);
|
|
randseed:=dt.hour+(dt.minute shl 8)+(dt.second shl 16)+(dt.sec100 shl 32);
|
|
end;
|
|
|
|
|
|
|
|
{****************************************************************************
|
|
Error Message writing using messageboxes
|
|
****************************************************************************}
|
|
|
|
const
|
|
WinInitialize: TWinInitialize = nil;
|
|
WinCreateMsgQueue: TWinCreateMsgQueue = nil;
|
|
WinMessageBox: TWinMessageBox = nil;
|
|
EnvSize: cardinal = 0;
|
|
|
|
var
|
|
ErrorBuf: array [0..ErrorBufferLength] of AnsiChar;
|
|
ErrorLen: longint;
|
|
PMWinHandle: cardinal;
|
|
|
|
function ErrorWrite (var F: TextRec): integer;
|
|
{
|
|
An error message should always end with #13#10#13#10
|
|
}
|
|
var
|
|
P: PAnsiChar;
|
|
I: longint;
|
|
begin
|
|
if F.BufPos > 0 then
|
|
begin
|
|
if F.BufPos + ErrorLen > ErrorBufferLength then
|
|
I := ErrorBufferLength - ErrorLen
|
|
else
|
|
I := F.BufPos;
|
|
Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
|
|
Inc (ErrorLen, I);
|
|
ErrorBuf [ErrorLen] := #0;
|
|
end;
|
|
if ErrorLen > 3 then
|
|
begin
|
|
P := @ErrorBuf [ErrorLen];
|
|
for I := 1 to 4 do
|
|
begin
|
|
Dec (P);
|
|
if not (P^ in [#10, #13]) then
|
|
break;
|
|
end;
|
|
end;
|
|
if ErrorLen = ErrorBufferLength then
|
|
I := 4;
|
|
if (I = 4) then
|
|
begin
|
|
WinMessageBox (0, 0, @ErrorBuf, PAnsiChar ('Error'), 0, MBStyle);
|
|
ErrorLen := 0;
|
|
end;
|
|
F.BufPos := 0;
|
|
ErrorWrite := 0;
|
|
end;
|
|
|
|
function ErrorClose (var F: TextRec): integer;
|
|
begin
|
|
if ErrorLen > 0 then
|
|
begin
|
|
WinMessageBox (0, 0, @ErrorBuf, PAnsiChar ('Error'), 0, MBStyle);
|
|
ErrorLen := 0;
|
|
end;
|
|
ErrorLen := 0;
|
|
ErrorClose := 0;
|
|
end;
|
|
|
|
function ErrorOpen (var F: TextRec): integer;
|
|
begin
|
|
TextRec(F).InOutFunc := @ErrorWrite;
|
|
TextRec(F).FlushFunc := @ErrorWrite;
|
|
TextRec(F).CloseFunc := @ErrorClose;
|
|
ErrorOpen := 0;
|
|
end;
|
|
|
|
|
|
procedure AssignError (var T: Text);
|
|
begin
|
|
Assign (T, '');
|
|
TextRec (T).OpenFunc := @ErrorOpen;
|
|
Rewrite (T);
|
|
end;
|
|
|
|
procedure SysInitStdIO;
|
|
(*
|
|
var
|
|
RC: cardinal;
|
|
*)
|
|
begin
|
|
{ Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
|
|
displayed in a messagebox }
|
|
(*
|
|
StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
|
|
StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
|
|
StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
|
|
|
|
if not IsConsole then
|
|
begin
|
|
RC := DosLoadModule (nil, 0, 'PMWIN', PMWinHandle);
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC)
|
|
else
|
|
begin
|
|
RC := DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox));
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC)
|
|
else
|
|
begin
|
|
RC := DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize));
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC)
|
|
else
|
|
begin
|
|
RC := DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue));
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC)
|
|
else
|
|
begin
|
|
WinInitialize (0);
|
|
WinCreateMsgQueue (0, 0);
|
|
end
|
|
end
|
|
end
|
|
end;
|
|
if RC <> 0 then
|
|
HandleError (2);
|
|
|
|
AssignError (StdErr);
|
|
AssignError (StdOut);
|
|
Assign (Output, '');
|
|
Assign (Input, '');
|
|
end
|
|
else
|
|
begin
|
|
*)
|
|
OpenStdIO (Input, fmInput, StdInputHandle);
|
|
OpenStdIO (Output, fmOutput, StdOutputHandle);
|
|
OpenStdIO (ErrOutput, fmOutput, StdErrorHandle);
|
|
OpenStdIO (StdOut, fmOutput, StdOutputHandle);
|
|
OpenStdIO (StdErr, fmOutput, StdErrorHandle);
|
|
(*
|
|
end;
|
|
*)
|
|
end;
|
|
|
|
|
|
function strcopy(dest,source : PAnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveeax,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
{$ifdef REGCALL}
|
|
movl %eax,saveeax
|
|
movl %edx,%edi
|
|
{$else}
|
|
movl source,%edi
|
|
{$endif}
|
|
testl %edi,%edi
|
|
jz .LStrCopyDone
|
|
leal 3(%edi),%ecx
|
|
andl $-4,%ecx
|
|
movl %edi,%esi
|
|
subl %edi,%ecx
|
|
{$ifdef REGCALL}
|
|
movl %eax,%edi
|
|
{$else}
|
|
movl dest,%edi
|
|
{$endif}
|
|
jz .LStrCopyAligned
|
|
.LStrCopyAlignLoop:
|
|
movb (%esi),%al
|
|
incl %edi
|
|
incl %esi
|
|
testb %al,%al
|
|
movb %al,-1(%edi)
|
|
jz .LStrCopyDone
|
|
decl %ecx
|
|
jnz .LStrCopyAlignLoop
|
|
.balign 16
|
|
.LStrCopyAligned:
|
|
movl (%esi),%eax
|
|
movl %eax,%edx
|
|
leal 0x0fefefeff(%eax),%ecx
|
|
notl %edx
|
|
addl $4,%esi
|
|
andl %edx,%ecx
|
|
andl $0x080808080,%ecx
|
|
jnz .LStrCopyEndFound
|
|
movl %eax,(%edi)
|
|
addl $4,%edi
|
|
jmp .LStrCopyAligned
|
|
.LStrCopyEndFound:
|
|
testl $0x0ff,%eax
|
|
jz .LStrCopyByte
|
|
testl $0x0ff00,%eax
|
|
jz .LStrCopyWord
|
|
testl $0x0ff0000,%eax
|
|
jz .LStrCopy3Bytes
|
|
movl %eax,(%edi)
|
|
jmp .LStrCopyDone
|
|
.LStrCopy3Bytes:
|
|
xorb %dl,%dl
|
|
movw %ax,(%edi)
|
|
movb %dl,2(%edi)
|
|
jmp .LStrCopyDone
|
|
.LStrCopyWord:
|
|
movw %ax,(%edi)
|
|
jmp .LStrCopyDone
|
|
.LStrCopyByte:
|
|
movb %al,(%edi)
|
|
.LStrCopyDone:
|
|
{$ifdef REGCALL}
|
|
movl saveeax,%eax
|
|
{$else}
|
|
movl dest,%eax
|
|
{$endif}
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
|
|
|
|
threadvar
|
|
DefaultCreator: ShortString;
|
|
DefaultFileType: ShortString;
|
|
|
|
|
|
procedure SetDefaultOS2FileType (FType: ShortString);
|
|
begin
|
|
{$WARNING Not implemented yet!}
|
|
DefaultFileType := FType;
|
|
end;
|
|
|
|
|
|
procedure SetDefaultOS2Creator (Creator: ShortString);
|
|
begin
|
|
{$WARNING Not implemented yet!}
|
|
DefaultCreator := Creator;
|
|
end;
|
|
|
|
|
|
(* The default handler does not store the OS/2 API error codes. *)
|
|
procedure NoErrorTracking (Error: cardinal);
|
|
begin
|
|
end;
|
|
|
|
|
|
function SetOSErrorTracking (P: pointer): pointer;
|
|
begin
|
|
SetOSErrorTracking := OSErrorWatch;
|
|
if P = nil then
|
|
OSErrorWatch := @NoErrorTracking
|
|
else
|
|
OSErrorWatch := TOSErrorWatch (P);
|
|
end;
|
|
|
|
|
|
procedure InitEnvironment;
|
|
var env_count : longint;
|
|
cp : PAnsiChar;
|
|
begin
|
|
env_count:=0;
|
|
cp:=environment;
|
|
while cp ^ <> #0 do
|
|
begin
|
|
inc(env_count);
|
|
while (cp^ <> #0) do inc(longint(cp)); { skip to NUL }
|
|
inc(longint(cp)); { skip to next character }
|
|
end;
|
|
envp := sysgetmem((env_count+1) * sizeof(PAnsiChar));
|
|
envc := env_count;
|
|
if (envp = nil) then exit;
|
|
cp:=environment;
|
|
env_count:=0;
|
|
while cp^ <> #0 do
|
|
begin
|
|
envp[env_count] := sysgetmem(strlen(cp)+1);
|
|
strcopy(envp[env_count], cp);
|
|
{$IfDef DEBUGENVIRONMENT}
|
|
Writeln(stderr,'env ',env_count,' = "',envp[env_count],'"');
|
|
{$EndIf}
|
|
inc(env_count);
|
|
while (cp^ <> #0) do
|
|
inc(longint(cp)); { skip to NUL }
|
|
inc(longint(cp)); { skip to next character }
|
|
end;
|
|
envp[env_count]:=nil;
|
|
end;
|
|
|
|
|
|
var
|
|
(* Initialized by system unit initialization *)
|
|
PIB: PProcessInfoBlock;
|
|
|
|
|
|
procedure InitArguments;
|
|
var
|
|
arglen,
|
|
count : PtrInt;
|
|
argstart,
|
|
pc,arg : PAnsiChar;
|
|
quote : AnsiChar;
|
|
argvlen : PtrInt;
|
|
RC: cardinal;
|
|
|
|
procedure allocarg(idx,len: PtrInt);
|
|
{ var
|
|
oldargvlen : PtrInt;}
|
|
begin
|
|
if idx>=argvlen then
|
|
begin
|
|
{ oldargvlen:=argvlen;}
|
|
argvlen:=(idx+8) and (not 7);
|
|
sysreallocmem(argv,argvlen*sizeof(pointer));
|
|
{ fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);}
|
|
end;
|
|
{ use realloc to reuse already existing memory }
|
|
{ always allocate, even if length is zero, since }
|
|
{ the arg. is still present! }
|
|
ArgV [Idx] := SysAllocMem (Succ (Len));
|
|
end;
|
|
|
|
begin
|
|
CmdLine := SysAllocMem (MaxPathLen);
|
|
|
|
ArgV := SysAllocMem (8 * SizeOf (pointer));
|
|
|
|
ArgLen := StrLen (PAnsiChar (PIB^.Cmd));
|
|
Inc (ArgLen);
|
|
|
|
RC := DosQueryModuleName (PIB^.Handle, MaxPathLen, CmdLine);
|
|
if RC = 0 then
|
|
ArgVLen := Succ (StrLen (CmdLine))
|
|
else
|
|
(* Error occurred - use program name from command line as fallback. *)
|
|
begin
|
|
Move (PIB^.Cmd^, CmdLine, ArgLen);
|
|
ArgVLen := ArgLen;
|
|
end;
|
|
|
|
{ Get ArgV [0] }
|
|
ArgV [0] := SysAllocMem (ArgVLen);
|
|
Move (CmdLine^, ArgV [0]^, ArgVLen);
|
|
Count := 1;
|
|
|
|
(* PC points to leading space after program name on command line *)
|
|
PC := PAnsiChar (PIB^.Cmd) + ArgLen;
|
|
|
|
(* ArgLen contains size of command line arguments including leading space. *)
|
|
ArgLen := Succ (StrLen (PC));
|
|
|
|
SysReallocMem (CmdLine, ArgVLen + Succ (ArgLen));
|
|
|
|
Move (PC^, CmdLine [ArgVLen], Succ (ArgLen));
|
|
|
|
(* ArgV has space for 8 parameters from the first allocation. *)
|
|
ArgVLen := 8;
|
|
|
|
{ process arguments }
|
|
while pc^<>#0 do
|
|
begin
|
|
{ skip leading spaces }
|
|
while pc^ in [#1..#32] do
|
|
inc(pc);
|
|
if pc^=#0 then
|
|
break;
|
|
{ calc argument length }
|
|
quote:=' ';
|
|
argstart:=pc;
|
|
arglen:=0;
|
|
while (pc^<>#0) do
|
|
begin
|
|
case pc^ of
|
|
#1..#32 :
|
|
begin
|
|
if quote<>' ' then
|
|
inc(arglen)
|
|
else
|
|
break;
|
|
end;
|
|
'"' :
|
|
begin
|
|
if quote<>'''' then
|
|
begin
|
|
if PAnsiChar(pc+1)^<>'"' then
|
|
begin
|
|
if quote='"' then
|
|
quote:=' '
|
|
else
|
|
quote:='"';
|
|
end
|
|
else
|
|
inc(pc);
|
|
end
|
|
else
|
|
inc(arglen);
|
|
end;
|
|
'''' :
|
|
begin
|
|
if quote<>'"' then
|
|
begin
|
|
if PAnsiChar(pc+1)^<>'''' then
|
|
begin
|
|
if quote='''' then
|
|
quote:=' '
|
|
else
|
|
quote:='''';
|
|
end
|
|
else
|
|
inc(pc);
|
|
end
|
|
else
|
|
inc(arglen);
|
|
end;
|
|
else
|
|
inc(arglen);
|
|
end;
|
|
inc(pc);
|
|
end;
|
|
{ copy argument }
|
|
{ Don't copy the first one, it is already there.}
|
|
If Count<>0 then
|
|
begin
|
|
allocarg(count,arglen);
|
|
quote:=' ';
|
|
pc:=argstart;
|
|
arg:=argv[count];
|
|
while (pc^<>#0) do
|
|
begin
|
|
case pc^ of
|
|
#1..#32 :
|
|
begin
|
|
if quote<>' ' then
|
|
begin
|
|
arg^:=pc^;
|
|
inc(arg);
|
|
end
|
|
else
|
|
break;
|
|
end;
|
|
'"' :
|
|
begin
|
|
if quote<>'''' then
|
|
begin
|
|
if PAnsiChar(pc+1)^<>'"' then
|
|
begin
|
|
if quote='"' then
|
|
quote:=' '
|
|
else
|
|
quote:='"';
|
|
end
|
|
else
|
|
inc(pc);
|
|
end
|
|
else
|
|
begin
|
|
arg^:=pc^;
|
|
inc(arg);
|
|
end;
|
|
end;
|
|
'''' :
|
|
begin
|
|
if quote<>'"' then
|
|
begin
|
|
if PAnsiChar(pc+1)^<>'''' then
|
|
begin
|
|
if quote='''' then
|
|
quote:=' '
|
|
else
|
|
quote:='''';
|
|
end
|
|
else
|
|
inc(pc);
|
|
end
|
|
else
|
|
begin
|
|
arg^:=pc^;
|
|
inc(arg);
|
|
end;
|
|
end;
|
|
else
|
|
begin
|
|
arg^:=pc^;
|
|
inc(arg);
|
|
end;
|
|
end;
|
|
inc(pc);
|
|
end;
|
|
arg^:=#0;
|
|
end;
|
|
{$IfDef DEBUGARGUMENTS}
|
|
Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
|
|
{$EndIf}
|
|
inc(count);
|
|
end;
|
|
{ get argc and create an nil entry }
|
|
argc:=count;
|
|
allocarg(argc,0);
|
|
{ free unused memory }
|
|
sysreallocmem(argv,(argc+1)*sizeof(pointer));
|
|
end;
|
|
|
|
function GetFileHandleCount: longint;
|
|
var L1: longint;
|
|
L2: cardinal;
|
|
RC: cardinal;
|
|
begin
|
|
L1 := 0; (* Don't change the amount, just check. *)
|
|
RC := DosSetRelMaxFH (L1, L2);
|
|
if RC <> 0 then
|
|
begin
|
|
GetFileHandleCount := 50;
|
|
OSErrorWatch (RC);
|
|
end
|
|
else
|
|
GetFileHandleCount := L2;
|
|
end;
|
|
|
|
function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
|
|
begin
|
|
CheckInitialStkLen := StkLen;
|
|
end;
|
|
|
|
var
|
|
TIB: PThreadInfoBlock;
|
|
RC: cardinal;
|
|
P: pointer;
|
|
DW: cardinal;
|
|
|
|
const
|
|
DosCallsName: array [0..8] of AnsiChar = 'DOSCALLS'#0;
|
|
|
|
{$IFDEF OS2UNICODE}
|
|
{$I sysucode.inc}
|
|
{$ENDIF OS2UNICODE}
|
|
|
|
begin
|
|
{$IFDEF OS2EXCEPTIONS}
|
|
asm
|
|
xorl %eax,%eax
|
|
movw %ss,%ax
|
|
movl %eax,_SS
|
|
end;
|
|
{$ENDIF OS2EXCEPTIONS}
|
|
DosGetInfoBlocks (@TIB, @PIB);
|
|
StackLength := CheckInitialStkLen (InitialStkLen);
|
|
{ OS/2 has top of stack in TIB^.StackLimit - unlike Windows where it is in TIB^.Stack }
|
|
StackBottom := TIB^.StackLimit - StackLength;
|
|
|
|
{Set type of application}
|
|
ApplicationType := PIB^.ProcType;
|
|
ProcessID := PIB^.PID;
|
|
ThreadID := TIB^.TIB2^.TID;
|
|
IsConsole := ApplicationType <> 3;
|
|
|
|
{$IFDEF SYSTEMDEBUG}
|
|
SysLastOSError := 0;
|
|
OrigOSErrorWatch := TOSErrorWatch (SetOSErrorTracking (@TrackLastOSError));
|
|
{$ENDIF SYSTEMDEBUG}
|
|
|
|
{Query maximum path length (QSV_MAX_PATH_LEN = 1)}
|
|
RC := DosQuerySysInfo (1, 1, DW, SizeOf (DW));
|
|
if RC = 0 then
|
|
RealMaxPathLen := DW
|
|
else
|
|
OSErrorWatch (RC);
|
|
|
|
ExitProc := nil;
|
|
|
|
{$IFDEF OS2EXCEPTIONS}
|
|
Install_Exception_Handler;
|
|
{$ENDIF OS2EXCEPTIONS}
|
|
|
|
(* Initialize the amount of file handles *)
|
|
FileHandleCount := GetFileHandleCount;
|
|
|
|
{Initialize the heap.}
|
|
(* Logic is following:
|
|
The heap is initially restricted to low address space (< 512 MB).
|
|
If underlying OS/2 version allows using more than 512 MB per process
|
|
(OS/2 WarpServer for e-Business, eComStation, possibly OS/2 Warp 4.0
|
|
with FP13 and above as well), use of this high memory is allowed for
|
|
future memory allocations at the end of System unit initialization.
|
|
The consequences are that the compiled application can allocate more
|
|
memory, but it must make sure to use direct DosAllocMem calls if it
|
|
needs a memory block for some system API not supporting high memory.
|
|
This is probably no problem for direct calls to these APIs, but
|
|
there might be situations when a memory block needs to be passed
|
|
to a 3rd party DLL which in turn calls such an API call. In case
|
|
of problems usage of high memory can be turned off by setting
|
|
UseHighMem to false - the program should change the setting at its
|
|
very beginning (e.g. in initialization section of the first unit
|
|
listed in the "uses" section) to avoid having preallocated memory
|
|
from the high memory region before changing value of this variable. *)
|
|
InitHeap;
|
|
|
|
Sys_DosOpenL := @DummyDosOpenL;
|
|
Sys_DosSetFilePtrL := @DummyDosSetFilePtrL;
|
|
Sys_DosSetFileSizeL := @DummyDosSetFileSizeL;
|
|
RC := DosQueryModuleHandle (@DosCallsName [0], DosCallsHandle);
|
|
if RC = 0 then
|
|
begin
|
|
RC := DosQueryProcAddr (DosCallsHandle, OrdDosOpenL, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_DosOpenL := TDosOpenL (P);
|
|
RC := DosQueryProcAddr (DosCallsHandle, OrdDosSetFilePtrL, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_DosSetFilePtrL := TDosSetFilePtrL (P);
|
|
RC := DosQueryProcAddr (DosCallsHandle, OrdDosSetFileSizeL, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_DosSetFileSizeL := TDosSetFileSizeL (P);
|
|
FSApi64 := true;
|
|
end;
|
|
end;
|
|
end;
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
RC := DosQueryProcAddr (DosCallsHandle, OrdDosAllocThreadLocalMemory,
|
|
nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
DosAllocThreadLocalMemory := TDosAllocThreadLocalMemory (P);
|
|
RC := DosQueryProcAddr (DosCallsHandle, OrdDosAllocThreadLocalMemory,
|
|
nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
DosFreeThreadLocalMemory := TDosFreeThreadLocalMemory (P);
|
|
TLSAPISupported := true;
|
|
end
|
|
else
|
|
OSErrorWatch (RC);
|
|
end
|
|
else
|
|
OSErrorWatch (RC);
|
|
end
|
|
else
|
|
OSErrorWatch (RC);
|
|
|
|
{ ... and exceptions }
|
|
SysInitExceptions;
|
|
fpc_cpucodeinit;
|
|
|
|
InitUnicodeStringManager;
|
|
|
|
{$IFDEF OS2UNICODE}
|
|
InitOS2WideStringManager;
|
|
|
|
InitDefaultCP;
|
|
{$ELSE OS2UNICODE}
|
|
(* Otherwise called within InitDefaultCP... *)
|
|
RC := DosQueryCP (SizeOf (CPArr), @CPArr, ReturnedSize);
|
|
if (RC <> 0) and (RC <> 473) then
|
|
begin
|
|
OSErrorWatch (RC);
|
|
CPArr [0] := 850;
|
|
end
|
|
else if (ReturnedSize < 4) then
|
|
CPArr [0] := 850;
|
|
DefaultFileSystemCodePage := CPArr [0];
|
|
{$ENDIF OS2UNICODE}
|
|
DefaultSystemCodePage := DefaultFileSystemCodePage;
|
|
DefaultRTLFileSystemCodePage := DefaultFileSystemCodePage;
|
|
DefaultUnicodeCodePage := CP_UTF16;
|
|
|
|
{ ... and I/O }
|
|
SysInitStdIO;
|
|
|
|
{ no I/O-Error }
|
|
InOutRes:=0;
|
|
|
|
{Initialize environment (must be after InitHeap because allocates memory)}
|
|
Environment := pointer (PIB^.Env);
|
|
InitEnvironment;
|
|
|
|
InitArguments;
|
|
|
|
DefaultCreator := '';
|
|
DefaultFileType := '';
|
|
|
|
InitSystemThreads;
|
|
InitSystemDynLibs;
|
|
|
|
{$IFDEF EXTDUMPGROW}
|
|
{ Int_HeapSize := high (cardinal);}
|
|
{$ENDIF EXTDUMPGROW}
|
|
{$ifdef SYSTEMEXCEPTIONDEBUG}
|
|
if IsConsole then
|
|
WriteLn (StdErr, 'Old exception ', HexStr (OldExceptAddr, 8),
|
|
', new exception ', HexStr (NewExceptAddr, 8), ', _SS = ', HexStr (_SS, 8));
|
|
{$endif SYSTEMEXCEPTIONDEBUG}
|
|
end.
|