#!/bin/sh
#------------------------------------------------------------------------------
# generate SysSignals from /usr/include/sys/signal.h
# afb 8/89
# rev afb 11/91: merge of Sig & Signals to Signals
# rev afb 3/92: Signals renamed to SysSignals
#------------------------------------------------------------------------------

	infile=/usr/include/sys/signal.h
	tmpfile=/tmp/gen_$$
	trap "rm -f $tmpfile; exit" 0 1 2 3 15

	date=`date +'AFB %m/%y' | sed 's/AFB 0\([0-9]\)/ AFB \1/'`

[ -r SysSignals.od ] && cp SysSignals.od old

# exported type declarations
typedecls='
   TYPE
      Signal = INTEGER; (* signal number: [1..nsigs-1] *)
      EventType = POINTER TO EventTypeRec;
      EventTypeRec =
	 RECORD
	    (Events.EventTypeRec)
	    signo: Signal;
	 END;
      Name = ARRAY 12 OF CHAR; (* traditional name, e.g. "SIGHUP" *)
      Event = POINTER TO EventRec;
      EventRec =
	 RECORD
	    (Events.EventRec)
	    signo: Signal;
	    (* see sigvec(2), NOTES for meaning of these fields *)
	    sigcode: INTEGER;
	    sigcontext: SysTypes.Address;
	    addr: SysTypes.Address;
	    (* "hard" errors need to be fixed -- else we loop endless;
	       if event.fixed is set to TRUE by one of the handlers,
	       continuation is allowed else the program aborts
	    *)
	    fixed: BOOLEAN;
	 END;
'

# private declarations and procedures
private='
   CONST
      Default = 0;
      Ignore = 1;

      (* do not return from these signals if they do not get fixed *)
      hardSignals = {sigILL, sigBUS, sigSEGV, sigSYS};

      (* signals which are related to memory managment *)
      memSignals = {sigSEGV};

      (* signals which cannot be caught or ignored *)
      voidSignals = {sigKILL, sigSTOP};

      (* signals which are not reset when caught *)
      againSignals = {1..nsigs-1};

      (* signals where default reaction means ignore *)
      defIsIgnSignals = {sigCHLD};
   VAR
      code2eventfields: SysConversions.Format;

   PROCEDURE SignalHandler(signo: Signal; sigcode: ARRAY OF BYTE);
      TYPE
	 Code =
	    RECORD
	       code: INTEGER;
	       sigcontext: SysTypes.Address;
	       addr: SysTypes.Address;
	    END;
      VAR
	 code: Code;
	 i: INTEGER;
	 sigevent: Event;
	 old, error: INTEGER;
   BEGIN
      (* close the window *)
      IF ~(signo IN againSignals) &
	 ~SYSTEM.UNIXSIGNAL(signo, SignalHandler, old, error) THEN
	 SysErrors.Raise(NIL, error, Sys.sigvec, text[signo]);
      END;

      NEW(sigevent);
      IF (signo >= 1) & (signo < nsigs) THEN
	 sigevent.type := eventType[signo];
	 sigevent.message := text[signo];
      ELSE
	 sigevent.type := unknownSignal;
	 sigevent.message := "unknown signal";
      END;
      sigevent.signo := signo;
      SysConversions.ByFmtFromC(sigcode, code, code2eventfields);
      sigevent.sigcode := code.code;
      sigevent.sigcontext := code.sigcontext;
      sigevent.addr := code.addr;
      sigevent.fixed := FALSE;
      Events.Raise(sigevent);
      IF (sigevent.signo IN hardSignals) & ~sigevent.fixed THEN
	 Process.Abort;
      END;
   END SignalHandler;
		       
   PROCEDURE SigManager(type: Events.EventType; reaction: Events.Reaction);
      VAR
	 oldproc: INTEGER;
	 error: INTEGER;
	 p: INTEGER;
   BEGIN
      WITH type: EventType DO
	 IF reaction = Events.funcs THEN
	    IF ~SYSTEM.UNIXSIGNAL(type.signo, SignalHandler, oldproc, error) THEN
	       SysErrors.Raise(NIL, error, Sys.sigvec, text[type.signo]);
	    END;
	 ELSE
	    IF reaction = Events.default THEN
	       p := Default;
	    ELSE
	       p := Ignore;
	    END;
	    IF ~SYSTEM.UNIXSIGNAL(type.signo, p, oldproc, error) THEN
	       SysErrors.Raise(NIL, error, Sys.sigvec, text[type.signo]);
	    END;
	 END;
      END;
   END SigManager;

   PROCEDURE GetSigHandler(sig: Signal; VAR handler: INTEGER);
      VAR
	 error: INTEGER;
	 old: INTEGER;
   BEGIN
      IF SYSTEM.UNIXSIGNAL(sig, Ignore, handler, error) &
	 SYSTEM.UNIXSIGNAL(sig, handler, old, error) THEN
      ELSE
	 handler := Default;
      END;
   END GetSigHandler;

   PROCEDURE Init;
      VAR
	 sig: Signal;
	 handler: INTEGER;
   BEGIN
      sig := 1;
      WHILE sig < nsigs DO
	 IF sig IN voidSignals THEN
	    eventType[sig] := NIL;
	 ELSE
	    NEW(eventType[sig]); Events.Init(eventType[sig]);
	    eventType[sig].signo := sig;
	    IF sig IN memSignals THEN
	       Events.SetPriority(eventType[sig], Priorities.storage);
	    ELSIF sig IN hardSignals THEN
	       Events.SetPriority(eventType[sig], Priorities.fatalsignals);
	    ELSE
	       Events.SetPriority(eventType[sig], Priorities.interrupts);
	    END;
	    IF sig IN defIsIgnSignals THEN
	       Events.Ignore(eventType[sig]);
	    ELSE
	       GetSigHandler(sig, handler);
	       IF handler = Ignore THEN
		  Events.Ignore(eventType[sig]);
	       ELSE
		  Events.RemoveHandlers(eventType[sig]);
	       END;
	    END;
	    Events.Manager(eventType[sig], SigManager);
	 END;
	 INC(sig);
      END;
      Events.Define(unknownSignal);
      Events.SetPriority(unknownSignal, Priorities.liberrors);
      SysConversions.Compile(code2eventfields, "ii/aa/aa");
   END Init;
'

# scan <sys/signals.h> and generate appropiate CONSTs and VARs
awkprog='
BEGIN	{	tmpfile="'"$tmpfile"'"
		maxcode=0
		maxsig=0
		nsigs=0
		mode=0  # 1: CONST, 2: VAR
	}
/^#define[ 	]+SIG[A-Z0-9]*[ 	]+[1-9][0-9]*/	{
	split($0, args)
	comment = $5;
	for (i = 6; i < NF; ++i)
		comment = comment " " args[i]
	signame = substr($2, 4);
	if (mode != 1) { printf "CONST "; mode = 1; }
	printf "sig%s = %d; (* %s *)\n", signame, $3, comment
	signames[$3] = signame;
	printf "   %s := eventType[%d];", signame, $3 >> tmpfile
	printf " name[%d] := \"SIG%s\";\n", $3, signame >> tmpfile
	printf "   text[%d] := \"%s\";\n", $3, comment >> tmpfile
	if ($3 > maxsig)
		maxsig = $3;
	}
/^#define[ 	][ 	]*NSIG	[0-9]+/ {
	if ($3 > maxsig+1)
		maxsig = $3 - 1;
	if (mode != 1) { printf "CONST "; mode = 1; }
	printf "nsigs = %d; (* number of valid signals *)\n", $3
	nsigs = $3;
	}
/^#define[ 	][ 	]*K[A-Z0-9]* *	[0-9]+/ {
	split($0, args)
	comment = $5;
	for (i = 6; i < NF; ++i)
		comment = comment " " args[i]
	if (mode != 1) { printf "CONST "; mode = 1; }
	printf "%s = %d; (* %s *)\n", $2, $3, comment
	if ($3 > maxcode)
		maxcode = $3;
	printf "   codetext[%s] := \"%s\";\n", $2, comment >> tmpfile
	}
END	{	if (mode != 1) { printf "CONST "; mode = 1; }
		printf "allsigs = %d; (* number of all signals *)\n", maxsig+1
		printf "ncodes = %d; (* number of sigcodes *)\n", maxcode+1
		if (mode != 2) { printf "VAR "; mode = 2; }
		for (sig = 1; sig < nsigs; ++ sig)
			if (signames[sig])
				printf "%s: EventType;\n", signames[sig]
	}
'

{	echo '(* ======> DO NOT EDIT -- derived from make_signal <==== *)'
	echo '(* Oberon Library     - Sun 3 Workstation -    '"$date"' *)'
	echo '(* (c) University of Ulm, Sektion Informatik, D-7900 Ulm *)'
	echo; echo 'DEFINITION SysSignals;'; echo
	echo '   IMPORT Events, SysTypes;'
	echo "$typedecls"
	echo;
	{	echo 'MODULE SysSignals;'
		sed 's/([^)]*)//g' $infile |
		sed '/IOT instruction/d; /SIGCLD/d' |
		gawk "$awkprog"
		echo 'END SysSignals.'
	} | m2b -c30 | egrep 'VAR|:|CONST|='
	echo; echo '   VAR'
	echo '      unknownSignal: Events.EventType;'
	echo '      text: ARRAY allsigs OF Events.Message;'
	echo '      name: ARRAY allsigs OF Name;'
	echo '      codetext: ARRAY ncodes OF Events.Message;'
	echo '      eventType: ARRAY nsigs OF EventType;'
	echo; echo 'END SysSignals.'
} >SysSignals.od && sed 's/DEFINITION/MODULE/' <SysSignals.od >SysSignals.om
ed - SysSignals.om <<!
\$i
$private

BEGIN
   Init;
.
.r $tmpfile
/IMPORT Events/s/Events/&, Priorities, Process, RelatedEvents, Sys,\\
      SysConversions, SysErrors, SYSTEM/
w
q
!
