summaryrefslogtreecommitdiff
path: root/rtl/emx/system.pas
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/emx/system.pas')
-rw-r--r--rtl/emx/system.pas603
1 files changed, 603 insertions, 0 deletions
diff --git a/rtl/emx/system.pas b/rtl/emx/system.pas
new file mode 100644
index 0000000000..2ed1c52899
--- /dev/null
+++ b/rtl/emx/system.pas
@@ -0,0 +1,603 @@
+{
+ $Id: system.pas,v 1.35 2005/04/03 21:10:59 hajny Exp $
+ ****************************************************************************
+
+ This file is part of the Free Pascal run time library.
+ Copyright (c) 1999-2002 by Free Pascal development team
+
+ Free Pascal - EMX 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 {$ifdef VER1_0}sysemx{$else}System{$endif};
+
+interface
+
+{Link the startup code.}
+{$ifdef VER1_0}
+ {$l prt1.oo2}
+{$else}
+ {$l prt1.o}
+{$endif}
+
+{$I systemh.inc}
+
+const
+ LineEnding = #13#10;
+{ LFNSupport is defined separately below!!! }
+ DirectorySeparator = '\';
+ DriveSeparator = ':';
+ PathSeparator = ';';
+{ FileNameCaseSensitive is defined separately below!!! }
+ maxExitCode = 255;
+
+type Tos=(osDOS,osOS2,osDPMI);
+
+var os_mode:Tos;
+ first_meg:pointer;
+
+type TByteArray = array [0..$ffff] of byte;
+ PByteArray = ^TByteArray;
+
+ TSysThreadIB = record
+ TID,
+ Priority,
+ Version: cardinal;
+ MCCount,
+ MCForceFlag: word;
+ end;
+ PSysThreadIB = ^TSysThreadIB;
+
+ TThreadInfoBlock = record
+ PExChain,
+ Stack,
+ StackLimit: pointer;
+ TIB2: PSysThreadIB;
+ Version,
+ Ordinal: cardinal;
+ end;
+ PThreadInfoBlock = ^TThreadInfoBlock;
+ PPThreadInfoBlock = ^PThreadInfoBlock;
+
+ TProcessInfoBlock = record
+ PID,
+ ParentPid,
+ Handle: cardinal;
+ Cmd,
+ Env: PByteArray;
+ Status,
+ ProcType: cardinal;
+ end;
+ PProcessInfoBlock = ^TProcessInfoBlock;
+ PPProcessInfoBlock = ^PProcessInfoBlock;
+
+const UnusedHandle=-1;
+ StdInputHandle=0;
+ StdOutputHandle=1;
+ StdErrorHandle=2;
+
+ LFNSupport: boolean = true;
+ FileNameCaseSensitive: boolean = false;
+ CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
+
+ sLineBreak = LineEnding;
+ DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
+
+var
+{ C-compatible arguments and environment }
+ argc : longint;external name '_argc';
+ argv : ppchar;external name '_argv';
+ envp : ppchar;external name '_environ';
+ EnvC: cardinal; external name '_envc';
+
+(* Pointer to the block of environment variables - used e.g. in unit Dos. *)
+ Environment: PChar;
+
+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;
+
+
+procedure SetDefaultOS2FileType (FType: ShortString);
+
+procedure SetDefaultOS2Creator (Creator: ShortString);
+
+
+
+implementation
+
+{$I system.inc}
+
+var
+ heap_base: pointer; external name '__heap_base';
+ heap_brk: pointer; external name '__heap_brk';
+ heap_end: pointer; external name '__heap_end';
+
+(* Maximum heap size - only used if heap is allocated as continuous block. *)
+{$IFDEF CONTHEAP}
+ BrkLimit: cardinal;
+{$ENDIF CONTHEAP}
+
+
+{****************************************************************************
+
+ Miscellaneous related routines.
+
+****************************************************************************}
+
+{$asmmode intel}
+procedure system_exit; assembler;
+asm
+ mov ah, 04ch
+ mov al, byte ptr exitcode
+ call syscall
+end {['EAX']};
+
+{$ASMMODE ATT}
+
+function paramcount:longint;assembler;
+
+asm
+ movl argc,%eax
+ decl %eax
+end {['EAX']};
+
+ function args:pointer;assembler;
+
+ asm
+ movl argv,%eax
+end {['EAX']};
+
+
+function paramstr(l:longint):string;
+
+var p:^Pchar;
+
+begin
+ { There seems to be a problem with EMX for DOS when trying to }
+ { access paramstr(0), and to avoid problems between DOS and }
+ { OS/2 they have been separated. }
+ if os_Mode = OsOs2 then
+ begin
+ if L = 0 then
+ begin
+ GetMem (P, 260);
+ p[0] := #0; { in case of error, initialize to empty string }
+{$ASMMODE INTEL}
+ asm
+ mov edx, P
+ mov ecx, 260
+ mov eax, 7F33h
+ call syscall { error handle already with empty string }
+ end ['eax', 'ecx', 'edx'];
+ ParamStr := StrPas (PChar (P));
+ FreeMem (P, 260);
+ end
+ else
+ if (l>0) and (l<=paramcount) then
+ begin
+ p:=args;
+ paramstr:=strpas(p[l]);
+ end
+ else paramstr:='';
+ end
+ else
+ begin
+ p:=args;
+ paramstr:=strpas(p[l]);
+ end;
+end;
+
+
+procedure randomize; assembler;
+asm
+ mov ah, 2Ch
+ call syscall
+ mov word ptr [randseed], cx
+ mov word ptr [randseed + 2], dx
+end {['eax', 'ecx', 'edx']};
+
+{$ASMMODE ATT}
+
+
+{*****************************************************************************
+
+ System unit initialization.
+
+****************************************************************************}
+
+{****************************************************************************
+ Error Message writing using messageboxes
+****************************************************************************}
+
+type
+ TWinMessageBox = function (Parent, Owner: cardinal;
+ BoxText, BoxTitle: PChar; Identity, Style: cardinal): cardinal; cdecl;
+ TWinInitialize = function (Options: cardinal): cardinal; cdecl;
+ TWinCreateMsgQueue = function (Handle: cardinal; cmsg: longint): cardinal;
+ cdecl;
+
+const
+ ErrorBufferLength = 1024;
+ mb_OK = $0000;
+ mb_Error = $0040;
+ mb_Moveable = $4000;
+ MBStyle = mb_OK or mb_Error or mb_Moveable;
+ WinInitialize: TWinInitialize = nil;
+ WinCreateMsgQueue: TWinCreateMsgQueue = nil;
+ WinMessageBox: TWinMessageBox = nil;
+ EnvSize: cardinal = 0;
+
+var
+ ErrorBuf: array [0..ErrorBufferLength] of char;
+ ErrorLen: longint;
+ PMWinHandle: cardinal;
+
+function ErrorWrite (var F: TextRec): integer;
+{
+ An error message should always end with #13#10#13#10
+}
+var
+ P: PChar;
+ 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, PChar ('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, PChar ('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 DosEnvInit;
+var
+ Q: PPChar;
+ I: cardinal;
+begin
+(* It's a hack, in fact - DOS stores the environment the same way as OS/2 does,
+ but I don't know how to find Program Segment Prefix and thus the environment
+ address under EMX, so I'm recreating this structure using EnvP pointer. *)
+{$ASMMODE INTEL}
+ asm
+ cld
+ mov ecx, EnvC
+ mov esi, EnvP
+ xor eax, eax
+ xor edx, edx
+@L1:
+ xchg eax, edx
+ push ecx
+ mov ecx, -1
+ mov edi, [esi]
+ repne
+ scasb
+ neg ecx
+ dec ecx
+ xchg eax, edx
+ add eax, ecx
+ pop ecx
+ dec ecx
+ jecxz @Stop
+ inc esi
+ inc esi
+ inc esi
+ inc esi
+ jmp @L1
+@Stop:
+ inc eax
+ mov EnvSize, eax
+ end ['eax','ecx','edx','esi','edi'];
+ Environment := GetMem (EnvSize);
+ asm
+ cld
+ mov ecx, EnvC
+ mov edx, EnvP
+ mov edi, Environment
+@L2:
+ mov esi, [edx]
+@Copying:
+ lodsb
+ stosb
+ or al, al
+ jnz @Copying
+ dec ecx
+ jecxz @Stop2
+ inc edx
+ inc edx
+ inc edx
+ inc edx
+ jmp @L2
+@Stop2:
+ stosb
+ end ['eax','ecx','edx','esi','edi'];
+end;
+
+
+procedure SysInitStdIO;
+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
+ if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
+ (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
+ and
+ (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
+ and
+ (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
+ = 0)
+ then
+ begin
+ WinInitialize (0);
+ WinCreateMsgQueue (0, 0);
+ end
+ else
+ 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;
+
+
+{$ifdef HASTHREADVAR}
+threadvar
+{$else HASTHREADVAR}
+var
+{$endif HASTHREADVAR}
+ 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;
+
+
+function GetFileHandleCount: longint;
+var L1: longint;
+ L2: cardinal;
+begin
+ L1 := 0; (* Don't change the amount, just check. *)
+ if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
+ else GetFileHandleCount := L2;
+end;
+
+var TIB: PThreadInfoBlock;
+ PIB: PProcessInfoBlock;
+
+const
+ FatalHeap: array [0..33] of char = 'FATAL: Cannot initialize heap!!'#13#10'$';
+
+begin
+ IsLibrary := FALSE;
+ {Determine the operating system we are running on.}
+{$ASMMODE INTEL}
+ asm
+ push ebx
+ mov os_mode, 0
+ mov eax, 7F0Ah
+ call syscall
+ test bx, 512 {Bit 9 is OS/2 flag.}
+ setne byte ptr os_mode
+ test bx, 4096
+ jz @noRSX
+ mov os_mode, 2
+ @noRSX:
+ {Enable the brk area by initializing it with the initial heap size.}
+ mov eax, 7F01h
+ mov edx, heap_brk
+ add edx, heap_base
+ call syscall
+ cmp eax, -1
+ jnz @heapok
+ lea edx, FatalHeap
+ mov eax, 900h
+ call syscall
+ pop ebx
+ push dword 204
+ call HandleError
+ @heapok:
+{$IFDEF CONTHEAP}
+{ Find out brk limit }
+ mov eax, 7F02h
+ mov ecx, 3
+ call syscall
+ jcxz @heaplimitknown
+ mov eax, 0
+ @heaplimitknown:
+ mov BrkLimit, eax
+{$ELSE CONTHEAP}
+{ Change sbrk behaviour to allocate arbitrary (non-contiguous) memory blocks }
+ mov eax, 7F0Fh
+ mov ecx, 0Ch
+ mov edx, 8
+ call syscall
+{$ENDIF CONTHEAP}
+ pop ebx
+ end ['eax', 'ecx', 'edx'];
+ { in OS/2 this will always be nil, but in DOS mode }
+ { this can be changed. }
+ first_meg := nil;
+ {Now request, if we are running under DOS,
+ read-access to the first meg. of memory.}
+ if os_mode in [osDOS,osDPMI] then
+ asm
+ push ebx
+ mov eax, 7F13h
+ xor ebx, ebx
+ mov ecx, 0FFFh
+ xor edx, edx
+ call syscall
+ jc @endmem
+ mov first_meg, eax
+ @endmem:
+ pop ebx
+ end ['eax', 'ecx', 'edx']
+ else
+ begin
+ (* Initialize the amount of file handles *)
+ FileHandleCount := GetFileHandleCount;
+ end;
+ {At 0.9.2, case for enumeration does not work.}
+ case os_mode of
+ osDOS:
+ begin
+ stackbottom:=pointer(heap_brk); {In DOS mode, heap_brk is
+ also the stack bottom.}
+ ApplicationType := 1; (* Running under DOS. *)
+ IsConsole := true;
+ ProcessID := 1;
+ ThreadID := 1;
+ end;
+ osOS2:
+ begin
+ DosGetInfoBlocks (@TIB, @PIB);
+ StackBottom := pointer (TIB^.Stack);
+ Environment := pointer (PIB^.Env);
+ ApplicationType := PIB^.ProcType;
+ ProcessID := PIB^.PID;
+ ThreadID := TIB^.TIB2^.TID;
+ IsConsole := ApplicationType <> 3;
+ end;
+ osDPMI:
+ begin
+ stackbottom:=nil; {Not sure how to get it, but seems to be
+ always zero.}
+ ApplicationType := 1; (* Running under DOS. *)
+ IsConsole := true;
+ ProcessID := 1;
+ ThreadID := 1;
+ end;
+ end;
+ exitproc:=nil;
+
+ {Initialize the heap.}
+ initheap;
+
+ { ... and exceptions }
+ SysInitExceptions;
+
+ { ... and I/O }
+ SysInitStdIO;
+
+ { no I/O-Error }
+ inoutres:=0;
+
+ InitSystemThreads;
+
+{$ifdef HASVARIANT}
+ initvariantmanager;
+{$endif HASVARIANT}
+
+ if os_Mode in [osDOS,osDPMI] then
+ DosEnvInit;
+
+{$IFDEF DUMPGROW}
+ {$IFDEF CONTHEAP}
+ WriteLn ('Initial brk size is ', GetHeapSize);
+ WriteLn ('Brk limit is ', BrkLimit);
+ {$ENDIF CONTHEAP}
+{$ENDIF DUMPGROW}
+end.
+{
+ $Log: system.pas,v $
+ Revision 1.35 2005/04/03 21:10:59 hajny
+ * EOF_CTRLZ conditional define replaced with CtrlZMarksEOF, #26 handling made more consistent (fix for bug 2453)
+
+ Revision 1.34 2005/02/14 17:13:22 peter
+ * truncate log
+
+ Revision 1.33 2005/02/06 16:57:18 peter
+ * threads for go32v2,os,emx,netware
+
+}