mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 14:59:37 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			271 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1997-98 by Michael Van Canneyt
 | 
						|
 | 
						|
    Unit to catch segmentation faults and Ctrl-C and exit gracefully
 | 
						|
    under linux and go32v2
 | 
						|
 | 
						|
    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 fpcatch;
 | 
						|
interface
 | 
						|
 | 
						|
{$i globdir.inc}
 | 
						|
 | 
						|
{$ifdef Unix}
 | 
						|
uses
 | 
						|
  baseunix,
 | 
						|
  unix;
 | 
						|
{$endif}
 | 
						|
{$ifdef go32v2}
 | 
						|
uses
 | 
						|
  dpmiexcp;
 | 
						|
{$endif}
 | 
						|
{$ifdef Windows}
 | 
						|
uses
 | 
						|
  windows
 | 
						|
  {$ifdef HasSignal}
 | 
						|
    ,signals
 | 
						|
  {$endif}
 | 
						|
  ;
 | 
						|
{$endif}
 | 
						|
 | 
						|
{$ifdef HasSignal}
 | 
						|
Var
 | 
						|
  NewSignal,OldSigSegm,OldSigILL,
 | 
						|
  OldSigInt,OldSigFPE : SignalHandler;
 | 
						|
{$endif}
 | 
						|
 | 
						|
Const
 | 
						|
  CtrlCPressed : Boolean = false;
 | 
						|
 | 
						|
Procedure EnableCatchSignals;
 | 
						|
Procedure DisableCatchSignals;
 | 
						|
 | 
						|
{$ifdef DEBUG}
 | 
						|
procedure Generate_SIGSEGV;
 | 
						|
procedure Generate_SIGFPE;
 | 
						|
{$endif DEBUG}
 | 
						|
 | 
						|
var
 | 
						|
  StopJmp : Jmp_Buf;
 | 
						|
const
 | 
						|
  StopJmpValid : boolean = false;
 | 
						|
 | 
						|
{$IFNDEF HASSIGNAL}
 | 
						|
const
 | 
						|
  SIGABRT   = 288;
 | 
						|
  SIGFPE    = 289;
 | 
						|
  SIGILL    = 290;
 | 
						|
  SIGSEGV   = 291;
 | 
						|
  SIGTERM   = 292;
 | 
						|
  SIGALRM   = 293;
 | 
						|
  SIGHUP    = 294;
 | 
						|
  SIGINT    = 295;
 | 
						|
  SIGKILL   = 296;
 | 
						|
  SIGPIPE   = 297;
 | 
						|
  SIGQUIT   = 298;
 | 
						|
  SIGUSR1   = 299;
 | 
						|
  SIGUSR2   = 300;
 | 
						|
  SIGNOFP   = 301;
 | 
						|
  SIGTRAP   = 302;
 | 
						|
  SIGTIMR   = 303;    { Internal for setitimer (SIGALRM, SIGPROF) }
 | 
						|
  SIGPROF   = 304;
 | 
						|
  SIGMAX    = 320;
 | 
						|
 | 
						|
  SIG_BLOCK   = 1;
 | 
						|
  SIG_SETMASK = 2;
 | 
						|
  SIG_UNBLOCK = 3;
 | 
						|
{$ENDIF HASSIGNAL}
 | 
						|
 | 
						|
 | 
						|
Implementation
 | 
						|
 | 
						|
uses
 | 
						|
  keyboard,
 | 
						|
  drivers,
 | 
						|
  FVConsts,
 | 
						|
  dos,app,msgbox,
 | 
						|
  FPCompil,FPIDE;
 | 
						|
 | 
						|
Const
 | 
						|
  LastCtrlC : longint = 0;
 | 
						|
 | 
						|
 | 
						|
{$ifdef useresstrings}
 | 
						|
resourcestring
 | 
						|
{$else}
 | 
						|
const
 | 
						|
{$endif}
 | 
						|
      msg_quitconfirm         = 'Do You really want to quit?';
 | 
						|
 | 
						|
{$ifdef DEBUG}
 | 
						|
 | 
						|
procedure Generate_SIGSEGV;
 | 
						|
var
 | 
						|
  l : plongint;
 | 
						|
begin
 | 
						|
  { Force a SIGSEGV }
 | 
						|
  l:=pointer (ptrint ($ffffffff));
 | 
						|
  l^:=1;
 | 
						|
end;
 | 
						|
 | 
						|
procedure Generate_SIGFPE;
 | 
						|
var
 | 
						|
  x,y : real;
 | 
						|
begin
 | 
						|
  { Force a SIGFPE }
 | 
						|
  y:=-5;
 | 
						|
  x:=sqrt(y);
 | 
						|
end;
 | 
						|
 | 
						|
{$endif DEBUG}
 | 
						|
 | 
						|
{$ifdef HasSignal}
 | 
						|
{$ifndef SignalIsFunction}
 | 
						|
Procedure Catchsignal(Sig : Longint);cdecl;
 | 
						|
{$else SignalIsFunction}
 | 
						|
  {$ifdef SignalIsCdecl}
 | 
						|
  Function Catchsignal(Sig : longint):longint; cdecl;
 | 
						|
  {$else not SignalIsCdecl}
 | 
						|
  Function Catchsignal(Sig : longint):longint;
 | 
						|
  {$endif not SignalIsCdecl}
 | 
						|
{$endif SignalIsFunction}
 | 
						|
var MustQuit: boolean;
 | 
						|
begin
 | 
						|
  case Sig of
 | 
						|
   SIGSEGV : begin
 | 
						|
               if StopJmpValid then
 | 
						|
                 LongJmp(StopJmp,SIGSEGV);
 | 
						|
               if Assigned(Application) then IDEApp.Done;
 | 
						|
               Writeln('Internal SIGSEGV Error caught');
 | 
						|
{$ifndef DEBUG}
 | 
						|
               Halt;
 | 
						|
{$else DEBUG}
 | 
						|
               RunError(216);
 | 
						|
{$endif DEBUG}
 | 
						|
             end;
 | 
						|
    SIGFPE : begin
 | 
						|
                if StopJmpValid then
 | 
						|
                  LongJmp(StopJmp,SIGFPE);
 | 
						|
               if Assigned(Application) then IDEApp.Done;
 | 
						|
               Writeln('Internal SIGFPE Error caught');
 | 
						|
{$ifndef DEBUG}
 | 
						|
               Halt;
 | 
						|
{$else DEBUG}
 | 
						|
               RunError(207);
 | 
						|
{$endif DEBUG}
 | 
						|
             end;
 | 
						|
    SIGILL : begin
 | 
						|
                if StopJmpValid then
 | 
						|
                  LongJmp(StopJmp,SIGILL);
 | 
						|
               if Assigned(Application) then IDEApp.Done;
 | 
						|
               Writeln('Internal SIGILL Error caught');
 | 
						|
{$ifndef DEBUG}
 | 
						|
               Halt;
 | 
						|
{$else DEBUG}
 | 
						|
               RunError(216);
 | 
						|
{$endif DEBUG}
 | 
						|
             end;
 | 
						|
    SIGINT : begin
 | 
						|
               if StopJmpValid then
 | 
						|
                 LongJmp(StopJmp,SIGINT);
 | 
						|
               IF NOT CtrlCPressed and Assigned(Application) then
 | 
						|
                 begin
 | 
						|
                   MustQuit:=false;
 | 
						|
                   if GetDosTicks>LastCtrlC+10 then
 | 
						|
                     begin
 | 
						|
                       CtrlCPressed:=true;
 | 
						|
                       Keyboard.PutKeyEvent((kbCtrl shl 16) or kbCtrlC);
 | 
						|
                       LastCtrlC:=GetDosTicks;
 | 
						|
                     end;
 | 
						|
                 end
 | 
						|
               else
 | 
						|
                 begin
 | 
						|
                   if Assigned(Application) then
 | 
						|
                     MustQuit:=MessageBox(#3+msg_QuitConfirm,nil,mferror+mfyesbutton+mfnobutton)=cmYes
 | 
						|
                   else
 | 
						|
                     MustQuit:=true;
 | 
						|
                 end;
 | 
						|
               if MustQuit then
 | 
						|
                begin
 | 
						|
                  if Assigned(Application) then IDEApp.Done;
 | 
						|
{$ifndef DEBUG}
 | 
						|
                  Halt;
 | 
						|
{$else DEBUG}
 | 
						|
                  RunError(216);
 | 
						|
{$endif DEBUG}
 | 
						|
                end;
 | 
						|
             end;
 | 
						|
  end;
 | 
						|
{$ifdef SignalIsFunction}
 | 
						|
  CatchSignal:=0;
 | 
						|
{$endif SignalIsFunction}
 | 
						|
end;
 | 
						|
{$endif def HasSignal}
 | 
						|
 | 
						|
 | 
						|
Const
 | 
						|
  CatchSignalsEnabled : boolean = false;
 | 
						|
 | 
						|
Procedure EnableCatchSignals;
 | 
						|
{$ifdef Windows}
 | 
						|
  var Mode: DWORD;
 | 
						|
{$endif Windows}
 | 
						|
begin
 | 
						|
  if CatchSignalsEnabled then
 | 
						|
    exit;
 | 
						|
{$ifdef Windows}
 | 
						|
  if GetConsoleMode(GetStdHandle(cardinal(Std_Input_Handle)), @Mode) then
 | 
						|
    begin
 | 
						|
{$ifdef DEBUG}
 | 
						|
      Writeln(stderr,'Starting value of ConsoleMode is $',hexstr(Mode,8));
 | 
						|
{$endif DEBUG}
 | 
						|
      SetConsoleMode(GetStdHandle(cardinal(Std_Input_Handle)),
 | 
						|
        (Mode or ENABLE_MOUSE_INPUT) and not ENABLE_PROCESSED_INPUT);
 | 
						|
{$ifdef DEBUG}
 | 
						|
    end
 | 
						|
  else
 | 
						|
    begin
 | 
						|
      Writeln(stderr,'Call to GetConsoleMode failed, GetLastError=',
 | 
						|
        GetLastError);
 | 
						|
{$endif DEBUG}
 | 
						|
    end;
 | 
						|
{$endif Windows}
 | 
						|
{$ifdef go32v2}
 | 
						|
  {
 | 
						|
    I think that it was an error to put that here PM
 | 
						|
    djgpp_set_ctrl_c(false);
 | 
						|
    at least since that this is now handled in fpusrscr.pas unit
 | 
						|
  }
 | 
						|
{$endif go32v2}
 | 
						|
{$ifdef HasSignal}
 | 
						|
  NewSignal:=@CatchSignal;
 | 
						|
  OldSigSegm:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGSEGV,NewSignal);
 | 
						|
  OldSigInt:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGINT,NewSignal);
 | 
						|
  OldSigFPE:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGFPE,NewSignal);
 | 
						|
  OldSigILL:={$ifdef unix}fpSignal{$else}Signal{$endif}(SIGILL,NewSignal);
 | 
						|
  CatchSignalsEnabled:=true;
 | 
						|
{$endif}
 | 
						|
end;
 | 
						|
 | 
						|
Procedure DisableCatchSignals;
 | 
						|
begin
 | 
						|
{$ifdef HasSignal}
 | 
						|
  if not CatchSignalsEnabled then
 | 
						|
    exit;
 | 
						|
  {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGSEGV,OldSigSegm);
 | 
						|
  {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGINT,OldSigInt);
 | 
						|
  {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGFPE,OldSigFPE);
 | 
						|
  {$ifdef unix}fpSignal{$else}Signal{$endif}(SIGILL,OldSigILL);
 | 
						|
  CatchSignalsEnabled:=false;
 | 
						|
{$endif}
 | 
						|
end;
 | 
						|
 | 
						|
end.
 |