//  crm_errorhandlers.c  - Controllable Regex Mutilator,  version v1.0
// Copyright 2001-2006  William S. Yerazunis, all rights reserved.
//  
//  This software is licensed to the public under the Free Software
//  Foundation's GNU GPL, version 2.  You may obtain a copy of the
//  GPL by visiting the Free Software Foundations web site at
//  www.fsf.org, and a copy is included in this distribution.  
//
//  Other licenses may be negotiated; contact the 
//  author for details.  
//
//  include some standard files
#include "crm114_sysincludes.h"

//  include any local crm114 configuration file
#include "crm114_config.h"

//  include the crm114 data structures file
#include "crm114_structs.h"

//  and include the routine declarations file
#include "crm114.h"

//    the command line argc, argv
extern int prog_argc;
extern char **prog_argv;

//    the auxilliary input buffer (for WINDOW input)
extern char *newinputbuf;

//    the globals used when we need a big buffer  - allocated once, used 
//    wherever needed.  These are sized to the same size as the data window.
extern char *inbuf;
extern char *outbuf;
extern char *tempbuf;
//     Helper routines 
//    

//     apocalyptic eerror - an error that can't be serviced on a TRAP - forces
//     exit, not a prayer of survival.
void untrappableerror (char *text1, char *text2)
{
  int iline, ichar;
  int maxchar;
  char reason[MAX_PATTERN];
  //
  //   Create our reason string.
  snprintf (reason, MAX_PATTERN, 
	    "\n%s: *UNTRAPPABLE ERROR* \n %s %s\nSorry, but I can't recover from that.\nThis happened at line %ld of file %s\n", 
	   prog_argv[0], text1, text2, csl->cstmt, csl->filename);
  fprintf (stderr, "%s", reason);

  //     Check to see - is there a trap available or is this a non-trap 
  //     program?
  //
  if (csl && csl->mct)
    {
      fprintf (stderr, "The line was: \n--> ");
      iline = csl->cstmt;
      maxchar = csl->mct[iline+1]->fchar;
      if (maxchar > csl->mct[iline]->fchar + 255) 
	maxchar = csl->mct[iline]->fchar + 255;
      if (iline > 0)
	for (ichar = csl->mct[iline]->fchar;
	     ichar < maxchar;
	     ichar++)
	  fprintf (stderr, "%c", csl->filetext[ichar]);
      fprintf (stderr, "\n");
      fprintf (stderr, "<--");
    }
  if (engine_exit_base != 0)
    {
      exit (engine_exit_base + 2);
    }
  else
    exit (CRM_EXIT_APOCALYPSE);

}


//     fatalerror - print a fatal error on stdout, trap if we can, else exit  
long fatalerror ( char *text1, char *text2 )
{
  int iline, ichar;
  int maxchar;
  char *rbuf;
  char reason[MAX_PATTERN];
  //
  //   Create our reason string.  Note that some reason text2's can be VERY 
  //   long, so we put out only the first 1024 characters
  //
  if (strlen (text2) < 1023)
    sprintf (reason, "\n%s: *ERROR* \n %.1024s %.1024s\n Sorry, but this program is very sick and probably should be killed off.\nThis happened at line %ld of file %s\n", 
	   prog_argv[0], text1, text2, csl->cstmt, csl->filename);
  else
    sprintf (reason, "\n%s: *ERROR* \n %.1024s %.1024s(...truncated)\n Sorry, but this program is very sick and probably should be killed off.\nThis happened at line %ld of file %s\n", 
	   prog_argv[0], text1, text2, csl->cstmt, csl->filename);

  //     Check to see - is there a trap available or is this a non-trap 
  //     program?
  //
  //   if (csl->mct[csl->cstmt]->trap_index <  csl->nstmts)
  if ((csl->nstmts > 0) && (csl->mct[csl->cstmt]->trap_index < csl->nstmts))
    {
      long fresult;
      rbuf = malloc (MAX_PATTERN);
      if (!rbuf)
	{
          fprintf(stderr,
	    "Couldn't malloc rbuf in 'fatalerror()'!  \nIt's really bad when the error fixup routine gets an error!.\n");
          if (engine_exit_base != 0)
            {
              exit (engine_exit_base + 3);
            }
          else
	    exit( CRM_EXIT_FATAL);
	};

      strcpy (rbuf, reason);
      fresult = crm_trigger_fault (rbuf);
      if (fresult == 0)
	return (0);
    };
  fprintf (stderr, "%s", reason);
  if (csl->nstmts > 0)
    {
      fprintf (stderr, "The line was: \n--> ");
      iline = csl->cstmt;
      maxchar = csl->mct[iline+1]->fchar;
      if (maxchar > csl->mct[iline]->fchar + 255) 
	maxchar = csl->mct[iline]->fchar + 255;
      for (ichar = csl->mct[iline]->fchar;
	   ichar < maxchar;
	   ichar++)
	fprintf (stderr, "%c", csl->filetext[ichar]);
      fprintf (stderr, "<--");
    }
  else
    fprintf (stderr, "\n <<< no compiled statements yet >>>");

  fprintf (stderr, "\n");
  if (engine_exit_base != 0)
    {
      exit (engine_exit_base + 4);
    }
  else
  exit ( CRM_EXIT_FATAL );
}

long nonfatalerror ( char *text1, char *text2 )
{
  int iline, ichar;
  int maxchar;
  static int nonfatalerrorcount = 0;
  char *rbuf;
  char reason[MAX_PATTERN];

  //
  //   Create our reason string.  Note that some reason text2's can be VERY 
  //   long, so we put out only the first 1024 characters
  //
  if (strlen (text2) < 1023)
    sprintf (reason, "\n%s: *WARNING* \n %.1024s %.1024s\nI'll try to keep working.\nThis happened at line %ld of file %s\n", 
	   prog_argv[0], text1, text2, csl->cstmt, csl->filename);
  else
    sprintf (reason, "\n%s: *WARNING* \n %.1024s %.1024s(...truncated)\nI'll try to keep working.\nThis happened at line %ld of file %s\n", 
	   prog_argv[0], text1, text2, csl->cstmt, csl->filename);

  //     Check to see - is there a trap available or is this a non-trap 
  //     program?
  //

  //  if (csl->mct[csl->cstmt]->trap_index < csl->nstmts)
  if ((csl->nstmts > 0) && (csl->mct[csl->cstmt]->trap_index<csl->nstmts))
    {
      long fresult;
      rbuf = malloc (MAX_PATTERN);
      if (!rbuf)
	{
          fprintf(stderr,
	    "Couldn't malloc rbuf in 'nonfatalerror()'! \nIt's really bad when the error fixup routine gets an error ! \n");
          
	  if (engine_exit_base != 0)
            {
              exit (engine_exit_base + 5);
            }
          else
	    exit(CRM_EXIT_FATAL);
	};

      strcpy (rbuf, reason);
      fresult = crm_trigger_fault (rbuf);
      if (fresult == 0) return (0);
    };

  fprintf (stderr, "%s", reason);
  if (csl->nstmts > 0) 
    {
      fprintf (stderr, "The line was: \n--> "); 
      iline = csl->cstmt;
      maxchar = csl->mct[iline+1]->fchar;
      if (maxchar > csl->mct[iline]->fchar + 255) 
	maxchar = csl->mct[iline]->fchar + 255;
      for (ichar = csl->mct[iline]->fchar;
	   ichar < maxchar;
	   ichar++)
	fprintf (stderr, "%c", csl->filetext[ichar]);
      fprintf (stderr, "<--");
    }
  else 
    fprintf (stderr, "<<< no compiled statements yet >>>");
  fprintf (stderr, "\n");
  nonfatalerrorcount++;
  if (nonfatalerrorcount > MAX_NONFATAL_ERRORS) 
    fatalerror 
      ("Too many untrapped warnings; your program is very likely unrecoverably broken.\n",
       "\n\n  'Better shut her down, Scotty.  She's sucking mud again.'\n");
    return (0);
}

/////////////////////////////////////////////////////////////////////////
//
//        Five-arg error handlers - put the execution engine location
//        in as well as as the error text.
//
/////////////////////////////////////////////////////////////////////////
//     apocalyptic eerror - an error that can't be serviced on a TRAP - forces
//     exit, not a prayer of survival.
void untrappableerror5 (char *text1, char *text2, 
			char *filename, 
			char *function,
			unsigned lineno )
{
  int iline, ichar;
  int maxchar;
  char reason[MAX_PATTERN];
  //
  //   Create our reason string.
  snprintf (reason, MAX_PATTERN, 
	    "\n%s: *UNTRAPPABLE ERROR* \n %s %s\nSorry, but I can't recover from that.\nThis happened at line %ld of file %s\n(runtime system location: %s(%u), function %s)\n", 
	    prog_argv[0], text1, text2, csl->cstmt, csl->filename, filename, lineno, function);
  fprintf (stderr, "%s", reason);

  //     Check to see - is there a trap available or is this a non-trap 
  //     program?
  //
  if (csl && csl->mct)
    {
      fprintf (stderr, "The line was: \n--> ");
      iline = csl->cstmt;
      maxchar = csl->mct[iline+1]->fchar;
      if (maxchar > csl->mct[iline]->fchar + 255) 
	maxchar = csl->mct[iline]->fchar + 255;
      if (iline > 0)
	for (ichar = csl->mct[iline]->fchar;
	     ichar < maxchar;
	     ichar++)
	  fprintf (stderr, "%c", csl->filetext[ichar]);
      fprintf (stderr, "\n");
      fprintf (stderr, "<--");
    }
  if (engine_exit_base != 0)
    {
      exit (engine_exit_base + 2);
    }
  else
    exit (CRM_EXIT_APOCALYPSE);

}


//     fatalerror - print a fatal error on stdout, trap if we can, else exit  
long fatalerror5 ( char *text1, char *text2, 
		   char *filename, 
		   char *function,
		   unsigned lineno )
{
  int iline, ichar;
  int maxchar;
  char *rbuf;
  char reason[MAX_PATTERN];
  //
  //   Create our reason string.  Note that some reason text2's can be VERY 
  //   long, so we put out only the first 1024 characters
  //
  if (strlen (text2) < 1023)
    sprintf (reason, "\n%s: *ERROR* \n %.1024s %.1024s\n Sorry, but this program is very sick and probably should be killed off.\nThis happened at line %ld of file %s\n(runtime system location: %s(%u) function %s)\n", 
	     prog_argv[0], text1, text2, csl->cstmt, csl->filename, filename, lineno, function);
  else
    sprintf (reason, "\n%s: *ERROR* \n %.1024s %.1024s(...truncated)\n Sorry, but this program is very sick and probably should be killed off.\nThis happened at line %ld of file %s\n(runtime system location: %s(%u) function %s)\n", 
	     prog_argv[0], text1, text2, csl->cstmt, csl->filename, filename, lineno, function);

  //     Check to see - is there a trap available or is this a non-trap 
  //     program?
  //
  //   if (csl->mct[csl->cstmt]->trap_index <  csl->nstmts)
  if ((csl->nstmts > 0) && (csl->mct[csl->cstmt]->trap_index < csl->nstmts))
    {
      long fresult;
      rbuf = malloc (MAX_PATTERN);
      if (!rbuf)
	{
          fprintf(stderr,
	    "Couldn't malloc rbuf in 'fatalerror()'!  \nIt's really bad when the error fixup routine gets an error!.\n");
          if (engine_exit_base != 0)
            {
              exit (engine_exit_base + 3);
            }
          else
	    exit( CRM_EXIT_FATAL);
	};

      strcpy (rbuf, reason);
      fresult = crm_trigger_fault (rbuf);
      if (fresult == 0)
	return (0);
    };
  //       Nope, no trap, print out the reason
  fprintf (stderr, "%s", reason);
  if (csl->nstmts > 0)
    {
      fprintf (stderr, "The line was: \n--> ");
      iline = csl->cstmt;
      maxchar = csl->mct[iline+1]->fchar;
      if (maxchar > csl->mct[iline]->fchar + 255) 
	maxchar = csl->mct[iline]->fchar + 255;
      for (ichar = csl->mct[iline]->fchar;
	   ichar < maxchar;
	   ichar++)
	fprintf (stderr, "%c", csl->filetext[ichar]);
      fprintf (stderr, "<--");
    }
  else
    fprintf (stderr, "\n <<< no compiled statements yet >>>");

  fprintf (stderr, "\n");
  if (engine_exit_base != 0)
    {
      exit (engine_exit_base + 4);
    }
  else
  exit ( CRM_EXIT_FATAL );
}

long nonfatalerror5 ( char *text1, char *text2, char *filename, char *function, unsigned lineno )
{
  int iline, ichar;
  int maxchar;
  static int nonfatalerrorcount = 0;
  char *rbuf;
  char reason[MAX_PATTERN];

  //
  //   Create our reason string.  Note that some reason text2's can be VERY 
  //   long, so we put out only the first 1024 characters
  //
  if (strlen (text2) < 1023)
    sprintf (reason, "\n%s: *WARNING* \n %.1024s %.1024s\nI'll try to keep working.\nThis happened at line %ld of file %s\n(runtime system location %s(%u) function %s)\n", 
	     prog_argv[0], text1, text2, csl->cstmt, csl->filename, filename, lineno, function);
  else
    sprintf (reason, "\n%s: *WARNING* \n %.1024s %.1024s(...truncated)\nI'll try to keep working.\nThis happened at line %ld of file %s\n(runtime system location: %s(%u) function %s)\n", 
	     prog_argv[0], text1, text2, csl->cstmt, csl->filename, filename, lineno, function);

  //     Check to see - is there a trap available or is this a non-trap 
  //     program?
  //

  //  if (csl->mct[csl->cstmt]->trap_index < csl->nstmts)
  if ((csl->nstmts > 0) && (csl->mct[csl->cstmt]->trap_index<csl->nstmts))
    {
      long fresult;
      rbuf = malloc (MAX_PATTERN);
      if (!rbuf)
	{
          fprintf(stderr,
	    "Couldn't malloc rbuf in 'nonfatalerror()'! \nIt's really bad when the error fixup routine gets an error ! \n");
          
	  if (engine_exit_base != 0)
            {
              exit (engine_exit_base + 5);
            }
          else
	    exit(CRM_EXIT_FATAL);
	};

      strcpy (rbuf, reason);
      fresult = crm_trigger_fault (rbuf);
      if (fresult == 0) return (0);
    };

  fprintf (stderr, "%s", reason);
  if (csl->nstmts > 0) 
    {
      fprintf (stderr, "The line was: \n--> "); 
      iline = csl->cstmt;
      maxchar = csl->mct[iline+1]->fchar;
      if (maxchar > csl->mct[iline]->fchar + 255) 
	maxchar = csl->mct[iline]->fchar + 255;
      for (ichar = csl->mct[iline]->fchar;
	   ichar < maxchar;
	   ichar++)
	fprintf (stderr, "%c", csl->filetext[ichar]);
      fprintf (stderr, "<--");
    }
  else 
    fprintf (stderr, "<<< no compiled statements yet >>>");
  fprintf (stderr, "\n");
  nonfatalerrorcount++;
  if (nonfatalerrorcount > MAX_NONFATAL_ERRORS) 
    fatalerror 
      ("Too many untrapped warnings; your program is very likely unrecoverably broken.\n",
       "\n\n  'Better shut her down, Scotty.  She's sucking mud again.'\n");
    return (0);
}

//     print out timings of each statement
void crm_output_profile ( CSL_CELL *csl)
{
  long i;
  fprintf (stderr,
	   "\n         Execution Profile Results \n");
  fprintf (stderr, 
	   "\n  Memory usage at completion: %10ld window, %10ld isolated\n",
	   cdw->nchars, tdw->nchars);
  fprintf (stderr, 
	   "\n  Statement Execution Time Profiling (0 times suppressed)");
  fprintf (stderr, 
	   "\n  line:      usertime   systemtime    totaltime\n");
  for (i = 0; i < csl->nstmts; i++)
    {
      if (csl->mct[i]->stmt_utime +csl->mct[i]->stmt_stime > 0)
	fprintf (stderr, " %5ld:   %10ld   %10ld   %10ld\n",
		 i,
		 csl->mct[i]->stmt_utime,
		 csl->mct[i]->stmt_stime,
		 csl->mct[i]->stmt_utime + csl->mct[i]->stmt_stime);
    };
}



// crm_trigger_fault - whenever there's a fault, this routine Does The
//  Right Thing, in terms of looking up the next TRAP statement and
//  turning control over to it.
//  
//  Watch out, this routine must return cleanly with the CSL top set up
//  appropriately so execution can continue at the chosen statement.
//  That next statement executed will be a TRAP statement whose regex
//  matches the fault string.  All other intervening statements will
//  be ignored.
//
//  This routine returns 0 if execution should continue, or 1 if there
//  was no applicable trap to catch the fault and we should take the
//  default fault action (which might be to exit).
//
//  Routines that get here must be careful to NOT trash the constructed
//  csl frame that causes the next statement to be the TRAP statement.
//  In particular, we act like the MATCH and CLASSIFY and FAIL statments
//  and branch to the chosen location -1 (due to the increment in the 
//  main invocation loop)

long crm_trigger_fault ( char *reason) 
{
  //
  //    and if the fault is correctly trapped, this is the fixup.
  //
  char trap_pat[MAX_PATTERN];
  long pat_len;
  regex_t preg;
  long i, j;
  ARGPARSE_BLOCK apb;
  long slen;
  long done;
  long trapline;

  //  Non null fault_text rstring -we'll take the trap 
  if (user_trace)
    {
      fprintf (stderr, "Catching FAULT generated on line %ld\n", 
	       csl->cstmt);
      fprintf (stderr, "FAULT reason: \n %s \n",
	       reason );
    };

  trapline = csl->cstmt;

  done = 0;
  while ( ! done)
    {
      if (csl->mct[trapline]->trap_index >= csl->nstmts
	  || (trapline = csl->mct[trapline]->trap_index) == -1)

	{
	  if (user_trace)
	    {
	      fprintf (stderr, "     ... no applicable TRAP. \n");
	    }
	  return (1);
	};
	      
      //      trapline = csl->mct[trapline]->trap_index;
      //      
      //        make sure we're really on a trap statement.
      //
      if (csl->mct[trapline]->stmt_type != CRM_TRAP)
	return (1);

      //       OK, we're here, with a live trap.  
      slen = (csl->mct[trapline+1]->fchar) 
	- (csl->mct[trapline ]->fchar);
      
      i = crm_statement_parse(
		      &(csl->filetext[csl->mct[trapline]->fchar]),
		      slen,
		      &apb);
      if (user_trace)
	{
	  fprintf (stderr, "Trying trap at line %ld: \n", trapline);
	  for (j =  (csl->mct[trapline ]->fchar);
	       j < (csl->mct[trapline+1]->fchar);
	       j++)
	    fprintf (stderr, "%c", csl->filetext[j]);
	  fprintf (stderr, "\n");
	};
      
      //  Get the trap pattern and  see if we match.
      crm_get_pgm_arg (trap_pat, MAX_PATTERN,
		       apb.s1start, apb.s1len);
      //
      //      Do variable substitution on the pattern
      pat_len = crm_nexpandvar (trap_pat, apb.s1len, MAX_PATTERN);
      
      //
      if (user_trace)
	{
	  fprintf (stderr, "This TRAP will trap anything matching =%s= . \n", 
		   trap_pat);
	};
      //       compile the regex
      i = crm_regcomp (&preg, trap_pat, pat_len, REG_EXTENDED);
      if ( i == 0)
	{
	  i = crm_regexec (&preg, 
			   reason,
			   strlen (reason),
			   0, NULL, 0, NULL);
	  crm_regfree (&preg);
	}
      else
	{
	  crm_regerror ( i, &preg, tempbuf, data_window_size);
	  csl->cstmt = trapline;
	  fatalerror ("Regular Expression Compilation Problem in TRAP pattern:", 
		      tempbuf);
	};
      
            
      //    trap_regcomp_error:


      //    if i != 0, we didn't match - kick the error further
      if (i == 0)
	{
	  if (user_trace)
	    {
	      fprintf (stderr, "TRAP matched.\n");
	      fprintf (stderr, "Next statement will be %ld\n",
		       trapline);
	    }
	  //
	  //   set the next statement to execute to be
	  //   the TRAP statement itself.

	  
	  csl->cstmt = trapline;
	  csl->aliusstk [ csl->mct[csl->cstmt]->nest_level ] = 1;
	  //
	  //     If there's a trap variable, modify it.
	  {
	    char reasonname [MAX_VARNAME];
	    long rnlen;
	    crm_get_pgm_arg(reasonname, MAX_VARNAME, apb.p1start, apb.p1len);
	    if (apb.p1len > 2)
	      {
		rnlen = crm_nexpandvar (reasonname, apb.p1len, MAX_VARNAME);
		//   crm_nexpandvar null-terminates for us so we can be
		//   8-bit-unclean here
		crm_set_temp_nvar (reasonname, 
				   reason,
				   strlen (reason));
	      };
	    done = 1;
	  }
	}
      else
	{
	  //   The trap pattern didn't match - move outward to 
	  //   the surrounding trap (if it exists)
	  if (user_trace)
	    {
	      fprintf (stderr, 
		       "TRAP didn't match- trying next trap in line.\n");
	    };
	};
      //      and note that we haven't set "done" == 1 yet, so
      //      we will go through the loop again.
    };
  return (0);
}




syntax highlighted by Code2HTML, v. 0.9.1