(* 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: Conclusions.om,v 1.2 1994/07/05 12:50:01 borchert Exp $
   ----------------------------------------------------------------------------
   $Log: Conclusions.om,v $
   Revision 1.2  1994/07/05 12:50:01  borchert
   formatting of error messages depends now on the indentation width
   of StreamDisciplines

   Revision 1.1  1994/02/23  07:46:17  borchert
   Initial revision

   ----------------------------------------------------------------------------
   AFB 11/91
   ----------------------------------------------------------------------------
*)

MODULE ulmConclusions;

   (* convert errors and events into conclusions,
      i.e. a final message and reaction
   *)

   IMPORT Errors := ulmErrors, Events := ulmEvents, Process := ulmProcess, RelatedEvents := ulmRelatedEvents, StreamDisciplines := ulmStreamDisciplines,
      Streams := ulmStreams, Strings := ulmStrings, Write := ulmWrite;

   VAR
      handlerSet*: Errors.HandlerSet;
      errors*: INTEGER; (* number of errors *)
      fatalcode*: INTEGER; (* exit code on fatal events *)

      (* private variables *)
      cmdName: Process.Name; (* should be sufficient for a base name *)
      cmdNameLen: INTEGER; (* Strings.Len(cmdName) *)

   (* private procedures *)

   PROCEDURE GeneralHandler(event: Events.Event; kind: Errors.Kind);
      VAR
	 width: INTEGER;
   BEGIN
      IF event # NIL THEN
	 Write.IndentS(Streams.stderr);
	 Write.StringS(Streams.stderr, cmdName);
	 Write.StringS(Streams.stderr, ": ");
	 width := SHORT(Strings.Len(cmdName) + 2);
	 StreamDisciplines.IncrIndentationWidth(Streams.stderr, width);
	 IF kind # Errors.message THEN
	    Write.StringS(Streams.stderr, Errors.kindText[kind]);
	    Write.StringS(Streams.stderr, ": ");
	 END;
	 Errors.Write(Streams.stderr, event); Write.LnS(Streams.stderr);
	 StreamDisciplines.IncrIndentationWidth(Streams.stderr, -width);
      END;
      CASE kind OF
      | Errors.error:   INC(errors);
      | Errors.fatal:   Process.Exit(fatalcode);
      | Errors.bug:     Process.Abort;
      ELSE
	 (* no further actions *)
      END;
   END GeneralHandler;

   PROCEDURE AbortHandler(event: Events.Event);
   BEGIN
      GeneralHandler(event, Errors.bug);
   END AbortHandler;

   PROCEDURE Init;
      VAR
	 messageKind: Errors.Kind;
   BEGIN
      fatalcode := 1;
      errors := 0;

      cmdName := Process.name;
      cmdNameLen := SHORT(Strings.Len(cmdName));

      messageKind := 0;
      Errors.CreateHandlerSet(handlerSet);
      WHILE messageKind < Errors.nkinds DO
	 Errors.InstallHandler(handlerSet, messageKind, GeneralHandler);
	 INC(messageKind);
      END;
      Events.AbortHandler(AbortHandler);
   END Init;

   (* public procedures *)

   PROCEDURE CatchEvent*(type: Events.EventType; kind: Errors.Kind);
   BEGIN
      Errors.CatchEvent(handlerSet, kind, type);
   END CatchEvent;

   PROCEDURE ConcludeS*(s: Streams.Stream;
		       object: RelatedEvents.Object; kind: Errors.Kind;
		       text: ARRAY OF CHAR);
      VAR
	 queue: RelatedEvents.Queue;
	 width: INTEGER;

      PROCEDURE ReverseQueue(VAR queue: RelatedEvents.Queue);
	 VAR
	    ptr, prev, next: RelatedEvents.Queue;
      BEGIN
	 ptr := queue; prev := NIL;
	 WHILE ptr # NIL DO
	    next := ptr.next;
	    ptr.next := prev;
	    prev := ptr;
	    ptr := next;
	 END;
	 queue := prev;
      END ReverseQueue;

   BEGIN
      RelatedEvents.GetQueue(object, queue);
      Write.IndentS(s);
      Write.StringS(s, cmdName); Write.StringS(s, ": ");
      IF kind # Errors.message THEN
	 Write.StringS(s, Errors.kindText[kind]); Write.StringS(s, ": ");
      END;
      IF text # "" THEN
	 Write.StringS(s, text); Write.StringS(s, ": ");
      END;
      IF queue = NIL THEN
	 Write.StringS(s, "*no error messages found*"); Write.LnS(s);
      ELSE
	 width := cmdNameLen + (* ": " *) 2;
	 StreamDisciplines.IncrIndentationWidth(s, width);
	 (* convert FIFO into LIFO *)
	 ReverseQueue(queue);
	 LOOP
	    Errors.Write(s, queue.event); Write.LnS(s);
	    queue := queue.next;
	    (**)IF queue = NIL THEN EXIT END;
	    Write.IndentS(s);
	 END;
	 StreamDisciplines.IncrIndentationWidth(s, -width);
      END;
      GeneralHandler(NIL, kind);
   END ConcludeS;

   PROCEDURE Conclude*(object: RelatedEvents.Object; kind: Errors.Kind;
		      text: ARRAY OF CHAR);
   BEGIN
      ConcludeS(Streams.stderr, object, kind, text);
   END Conclude;

BEGIN
   Init;
END ulmConclusions.
