#!/bin/sh
#------------------------------------------------------------------------------
# Ulm's Oberon Library
# Copyright (C) 1989-1994 by University of Ulm, SAI, D-89069 Ulm, Germany
# ----------------------------------------------------------------------------
# Ulm's Oberon Library is free software; you can redistribute it
# and/or modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either version
# 2 of the License, or (at your option) any later version.
# 
# Ulm's Oberon Library 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.  See the GNU
# Library General Public License for more details.
# 
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# ----------------------------------------------------------------------------
# E-mail contact: oberon@mathematik.uni-ulm.de
# ----------------------------------------------------------------------------
# $Id$
# ----------------------------------------------------------------------------
# $Log$
#------------------------------------------------------------------------------
# generate SysErrors from /usr/include/sys/errno.h
# afb 6/89
#------------------------------------------------------------------------------

	basename=`basename $0`
	infile=/usr/include/sys/errno.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 SysErrors.od ] && cp SysErrors.od old
[ -r SysErrors.om ] && cp SysErrors.om old

awk_filter='
# name:val:comment:shortname
BEGIN	{	tmpfile="'"$tmpfile"'"
		maxerrno = 0
	}
	{	if ($2 > maxerrno)
			maxerrno = $2
		printf "%s = %d; (* %s *)\n", $1, $2, $3
		printf "   message[%s] := \"%s\";\n", $1, $3 >> tmpfile
		printf "   name[%s] := \"%s\";\n", $1, $4 >> tmpfile
	}
END	{	printf "ncodes = %d; (* number of error codes *)\n", maxerrno+1
	}
'

{	echo '(* ======> DO NOT EDIT -- derived from '"$basename"' <===== *)'
	sed '/E-mail/q' header
	fgrep -e '---' header | line
	echo '   '"$date"
	fgrep -e '---' header | line
	echo '*)'
	echo; echo 'DEFINITION SysErrors;'; echo;
	echo '   IMPORT Events, RelatedEvents;'; echo;
	echo '   CONST'
	{	echo 'MODULE SysErrors; CONST'
		# assumptions about $infile:
		#    error names do not contain _'s
		{	echo '#include <errno.h>'
			grep 'define[ 	]*E' $infile |
			sed 's/  *\(\*\/\)/\1/
			     s/^#define[ 	]*\(E[A-Z0-9]*\)[ 	].*\/\* \([^	]*\)[ 	]*\*\/.*$/XXX _\1:\1:\2/
			     s/^#define[ 	]*\(E[A-Z0-9]*\)[ 	].*$/XXX _\1:\1/'
		} | /lib/cpp | grep XXX | sed 's/XXX _//' |
		while IFS=":" read name val comment
		do	val=`echo $val | bc`
			shortname="$name"
			name=`echo $name | sed 's/E//' | tr '[A-Z]' '[a-z]'`
			case $name
			in [0-9]*)	name=e$name
			esac
			case $comment
			in "")	comment="Error code $val ($name)"
			esac
			echo "$name:$val:$comment:$shortname"
		done | gawk -F: "$awk_filter"
		echo 'END SysErrors.'
	} | m2b -c30 | grep '='
	cat <<"eof"
      
      textlen = 512;

   TYPE
      Name = ARRAY 20 OF CHAR;
      Event = POINTER TO EventRec;
      EventRec =
	 RECORD
	    (Events.EventRec)
	    errno: INTEGER;
	    syscall: INTEGER; (* number of system call *)
	    text: ARRAY textlen OF CHAR;
	 END;

   VAR
      message: ARRAY ncodes OF Events.Message;
      name: ARRAY ncodes OF Name;
      syserrors: Events.EventType;
      syserror: ARRAY ncodes OF Events.EventType;

   PROCEDURE Raise(errors: RelatedEvents.Object;
		   errno, syscall: INTEGER; text: ARRAY OF CHAR);
      (* raises the events syserrors and syserrors[syscall];
	 `text' contains additional information (e.g. filenames);
	 further, the syserrors[syscall] event is passed to
	 RelatedEvents if object # NIL
      *)

END SysErrors.
eof
} >SysErrors.od && sed 's/DEFINITION/MODULE/' <SysErrors.od >SysErrors.om
ed - SysErrors.om <<!
/IMPORT/s/.*/   IMPORT Errors, Events, Priorities, RelatedEvents, Streams, Strings, Sys;/
/PROCEDURE Raise/;/\*)/a
      VAR
	 event: Event;

      PROCEDURE InitEvent(VAR event: Event; type: Events.EventType);
      BEGIN
	 NEW(event);
	 event.type := type;
	 event.message := message[errno];
	 event.errno := errno;
	 event.syscall := syscall;
	 COPY(text, event.text);
      END InitEvent;

   BEGIN
      IF (errno > 0) & (errno < ncodes) THEN
	 InitEvent(event, syserrors); Events.Raise(event);
	 InitEvent(event, syserror[errno]); Events.Raise(event);
	 IF errors # NIL THEN
	    InitEvent(event, syserrors);
	    RelatedEvents.Raise(errors, event);
	 END;
      END;
   END Raise;

   PROCEDURE Write(s: Streams.Stream; event: Events.Event);

      PROCEDURE WriteString(txt: ARRAY OF CHAR);
      BEGIN
	 IF ~Streams.WritePart(s, txt, 0, Strings.Len(txt)) THEN END;
      END WriteString;

      PROCEDURE Write(ch: CHAR);
      BEGIN
	 IF ~Streams.WriteByte(s, ch) THEN END;
      END Write;

      PROCEDURE WriteInt(intval: INTEGER);
	 VAR
	    rest: INTEGER;
      BEGIN
	 rest := intval DIV 10;
	 IF rest > 0 THEN
	    WriteInt(rest);
	 END;
	 Write(CHR(ORD("0") + intval MOD 10));
      END WriteInt;

   BEGIN
      IF event IS Event THEN
	 WITH event: Event DO
	    IF event.text[0] # 0X THEN
	       WriteString(event.text);
	       WriteString(": ");
	    END;
	    IF event.errno = 0 THEN
	       WriteString("no error (");
	       WriteString(Sys.name[event.syscall]); Write(")");
	    ELSIF (event.errno >= ncodes) OR (message[event.errno][0] = 0X) THEN
	       WriteString("unknown error (");
	       WriteString(Sys.name[event.syscall]);
	       WriteString(": "); WriteInt(event.errno); Write(")");
	    ELSE
	       WriteString(message[event.errno]);
	       WriteString(" (");
	       WriteString(Sys.name[event.syscall]); WriteString(": ");
	       WriteString(SysErrors.name[event.errno]); Write(")");
	    END;
	 END;
      ELSE
	 WriteString(event.message);
      END;
   END Write;

   PROCEDURE InitEvents;
      VAR
	 errno: INTEGER;
   BEGIN
      syserror[0] := NIL;
      errno := 1;
      WHILE errno < ncodes DO
	 Events.Define(syserror[errno]);
	 Events.Ignore(syserror[errno]);
	 Events.SetPriority(syserror[errno], Priorities.syserrors);
	 INC(errno);
      END;
      Events.Define(syserrors);
      Events.Ignore(syserrors);
      Events.SetPriority(syserrors, Priorities.syserrors);
      Errors.AssignWriteProcedure(syserrors, Write);
   END InitEvents;
.
\$i
BEGIN
   InitEvents;
.
.r $tmpfile
w
q
!
