Patch title: Release 85 bulk changes
Abstract:
File: /pliant/language/debug/error.c
Key:
    Removed line
    Added line
// Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation.
// 
// 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.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// version 2 along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

/*
abstract
  text "Errors handling and reporting mechanism."
*/


FUNCTION Void ActionRecord_build(struct ActionRecord *ca) {
  Str_build(&ca->action);
  ca->next=(Address)(-1); }

FUNCTION Void ActionRecord_destroy(struct ActionRecord *ca) {
  if(ca->next!=(Address)(-1))
    G.action_pull_record_hook(ca);
  Str_destroy(&ca->action); }


FUNCTION Void default_action_push_record(struct ActionRecord *ca,struct Str *action) {
  struct Str temp;
  if(G.verbose_level>=2)
    consolen(Z,"\r",S,Str_map_area(&temp,action->chars,minimum(Str_len(action),78)),Z," ",END);
  Str_copy(action,&ca->action);
  ca->next=G.top_action;
  G.top_action=ca; }
  
INLINE Void action_push_record(struct ActionRecord *ca,struct Str *action) {
  G.action_push_record_hook(ca,action); }

FUNCTION Void action_push_recordn(struct ActionRecord *ca, ...) {
  struct Str action;
  va_list arguments; Int kind;
  struct Str *str; char *string;
  Str_build(&action);
  va_start(arguments,ca);
  for(;;) {
    kind=va_arg(arguments,Int);
    if(kind==S) {
      str=va_arg(arguments,struct Str *);
      Str_add(str,&action);
    orif(kind==Z)
      string=va_arg(arguments,char *);
      Str_addz(string,&action);
    orif(kind==(Int)END)
      break;
    other
      error_notify_fatalz(error_id_unexpected,"Invalid ActionRecord_insertn"); } }
  va_end(arguments); 
  action_push_record(ca,&action);
  Str_destroy(&action); }


FUNCTION Void default_action_pull_record(struct ActionRecord *ca) {
  #ifdef _CHECK_
    if(G.top_action!=ca)
      error_notify_fatalz(error_id_mismatch,"Wrong action record pulled");
  #endif
  G.top_action=ca->next;
  ca->next=(Address)(-1); }
  
INLINE Void action_pull_record(struct ActionRecord *ca) {
  G.action_pull_record_hook(ca); }


FUNCTION struct ActionRecord *default_action_top_record() {
  return G.top_action; }

INLINE struct ActionRecord *action_top_record() {
  return G.action_top_record_hook(); }


/*****************************************************************************/


FUNCTION Void default_error_fatal(Int id,struct Str *message) {
  consolen(Z,"\n",S,message,EOL);
  #ifdef _CRASH_
    *(int *)null=0;
  #endif
  process_exit(minimum(id,error_id_user)); }

FUNCTION Void error_notify_fatal(Int id,struct Str *message) {
  G.error_fatal_hook(id,message); }


FUNCTION Void error_notify_fatalz(Int id,Char *message) {
  struct Str temp;
  error_notify_fatal(id,Str_map_string(&temp,message)); }


/*****************************************************************************/


FUNCTION Void ErrorRecord_build(struct ErrorRecord *e) {
  Arrow_build(&e->context);
  Str_build(&e->message);
  e->next=(Address)(-1); }

FUNCTION Void ErrorRecord_destroy(struct ErrorRecord *e) {
  Str_destroy(&e->message);
  Arrow_destroy(&e->context); }


FUNCTION Void default_error_push_record(struct ErrorRecord *e,Int filter) {
  e->id=error_id_noerror;
  e->filter=filter;
  e->next=G.top_error;
  G.top_error=e; }

INLINE Void error_push_record(struct ErrorRecord *e,Int filter) {
  G.error_push_record_hook(e,filter); }


FUNCTION Void default_error_pull_record(struct ErrorRecord *e) {
  #ifdef _CHECK_
    if(G.top_error!=e)
      error_notify_fatalz(error_id_mismatch,"Wrong error record pulled");
  #endif
  error_propagate(e,e->next);
  G.top_error=e->next; 
  e->next=(Address)(-1);
  error_report(); }

INLINE Void error_pull_record(struct ErrorRecord *e) {
  G.error_pull_record_hook(e); }


FUNCTION struct ErrorRecord *default_error_top_record() {
  return G.top_error; }

INLINE struct ErrorRecord *error_top_record() {
  return G.error_top_record_hook(); }


FUNCTION Void error_report() {
  struct ErrorRecord *top,*e;
  top=error_top_record();
  if(top->id==error_id_noerror)
    return;
  for(e=top; e!=null; e=e->next)
    if(e->filter==top->id || e->filter==error_filter_all)
      return;
  error_notify_fatal(top->id,&top->message); }


FUNCTION Void error_notify(Int id,Arrow context,struct Str *message) {
  struct ErrorRecord *e; struct ActionRecord *a;
  e=error_top_record();
  if(e->id!=error_id_noerror)
    return;
  e->id=id; Str_copy(message,&e->message);
  for(a=action_top_record(); a!=null; a=a->next) {
    Str_addz("\n",&e->message);
    Str_add(&a->action,&e->message); }
  error_report();  }


FUNCTION Void error_renotify(Int id,Arrow context,struct Str *message) {
  struct ErrorRecord *e;
  e=error_top_record();
  if(e->id!=error_id_noerror)
    return;
  e->id=id;
  Str_copy(message,&e->message);
  error_report(); }


FUNCTION Void error_notifyn(Int id, ...) {
  struct Str msg;
  va_list arguments; Int kind; struct Str *str; Char *string;
  Str_build(&msg);
  va_start(arguments,id);
  for(;;) {
    kind=va_arg(arguments,Int);
    if(kind==S) {
      str=va_arg(arguments,struct Str *);
      Str_add(str,&msg);
    orif(kind==Z)
      string=va_arg(arguments,char *);
      Str_addz(string,&msg);
    orif(kind==(Int)END)
      break;
    other
      error_notify_fatalz(error_id_unexpected,"Invalid error_notifyn"); } }
  va_end(arguments);
  error_notify(id,null,&msg);
  Str_destroy(&msg); }


FUNCTION Bool error_notified() {
  struct ErrorRecord *e;
  e=error_top_record();
  return e->id!=error_id_noerror; }


FUNCTION Void error_propagate(struct ErrorRecord *src,struct ErrorRecord *dest) {
  if((src->id!=error_id_noerror) && (dest->id==error_id_noerror)) {
    dest->id=src->id;
    Arrow_copy(&src->context,&dest->context);
    Str_copy(&src->message,&dest->message); } }


FUNCTION Int error_allocate_id(struct Str *clear_text_message) {
  return G.error_first_available_id++; }


#ifdef _CHECK_

  FUNCTION Void check_assertion(Bool cond,Char *expression,Char *filename,Int linenum) {
    Char buffer[16]; struct Str temp;
    if(!cond) {
      error_notifyn(error_id_check,
        Z,"pliant internal bug: unsatisfied assertion\n",
        Z,"assertion is ",Z,expression,Z,"\n",
        Z,"in file ",Z,filename,
        Z," at line ",S,Str_map_area(&temp,buffer,Int_str2(linenum,10,buffer)),
        END);
      error_report(); } }

#endif