/*===========================================================================
  Copyright (C) 1995-2010 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  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 along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++++++++++++++ Module MIDERR +++++++++++++++++++++++++++++++++++++++
.LANGUAGE   C
.IDENTIFICATION  Module MIDERR
.COMMENTS
holds MID_ERROR, MID_ERRFIL, MID_DSPERR, MID_INITER, MID_E1, MID_E2, MID_PUTERR
.AUTHOR   Klaus Banse		ESO - Garching
.KEYWORDS Midas errors
.ENVIRONMENT VMS and UNIX

.VERSION 

 100816		last modif
------------------------------------------------------------------------*/
 
#include <fileexts.h>
#include <errtable.h>

#include <stdio.h>
#include <string.h>

 
 
#define  READ         0
#define  WRITE        1
#define  READ_WRITE   2
#define  APPEND       3
 
static char	caller[16], work[104], mess[84], *messpntr, *pntr;
/*

*/
 
void MID_ERRFIL(ulevel,label)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE: display error messages
.ALGORITHM: straight forward
.RETURNS: nothing
--------------------------------------------------------------------*/

int   ulevel;		/* IN: user level      */
char   *label;		/* IN: label           */
 
{	
int mm, fp;

 
if ((ulevel == 2) ||
    (KIWORDS[OFF_ERROR+3] == 0)) return;	/* expert mode or NoDisplay */


/*  for novices + users we do more  */
 
fp = CGN_OPEN("MID_MONIT:errpar.dat",READ);
if (fp == -1)
   {
   (void) printf("problems opening system errorfile %s ...\n",mess);
   return;
   }
	
 
while (osaread(fp,mess,80) >= 1) 		/* read a file record */
   {
   if (strncmp(mess,label,6) == 0)		/* compare with given label */
      {
      mm = osaread(fp,mess,80);		/* match - read next record */
      if (KIWORDS[OFF_ERROR+3] != 0)
         {
         (void) printf("%s\n",mess);		/* and print it */
         (void) MID_LOG('G',mess,mm);
         }
 
      if (ulevel == 1)
         {				/* for novice users */
         loop:				/* get more records */
	 mm = osaread(fp,mess,80);
	 if ( mm != -1)
	    {
	    if ( strncmp(mess,"_END",4) != 0)
	       {
               (void) printf("%s\n",mess);		/* and print it */
               (void) MID_LOG('G',mess,mm);
	       goto loop;
	       }
	    }
	 }
      break;
      }
   }
	
(void)osaclose(fp);				/* close error message file */
}
/*

*/
 
void MID_DSPERR()
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  display error messages
.ALGORITHM
  straight forward
.RETURNS 
  nothing
--------------------------------------------------------*/
	
{
int   mm, kk, prflag, usr_level, mesoff, kk1;
int  source = 0;
static int  fflag = 0;

char  saverr[8], full_mess[80];


if (ERRO_DISP != 0)
   { 
   prflag = KIWORDS[OFF_ERROR];		/* print flag = ERROR(1) */
   if (fflag == 0)
      {
      fflag = 1;
      if (prflag > 0)
         {
         kk = OFF_APPLIC + 2;		/* point to name of application */
         pntr = &KCWORDS[kk];
         memset((void *)work,32,(size_t)58);
         (void) strncpy(work,pntr,58);	 	/* applic length - 2 */
         work[58] = '\0';
         kk = CGN_INDEXC(work,' ');
         if (kk > 0) work[kk] = '\0';		/* truncate if possible */
         (void) strcpy(full_mess,"--- in module  ");
         (void) strcat(full_mess,work);
         if (KIWORDS[OFF_ERROR+3] != 0)	
            {				/* ERROR(4) = 0  -> no display */
            (void) printf("%s\n",full_mess); 
            (void) MID_LOG('G',full_mess,(int)strlen(full_mess));
            }
         }
      }

   usr_level = KIWORDS[OFF_ERROR+1];	/* user level = ERROR(2) */
   kk1 = ERRO_INDX;

	
   /*  empty error message stack  */
 
   for (kk=kk1; kk > -1; kk--)		/* loop from kk1 down to 0 */
      {	
      mesoff = ERROS[kk][1];
      pntr = &ERRO_MESAGS[mesoff];
      if ((kk == kk1) || (kk == 0) || (prflag != 0)) 
         {
         if (KIWORDS[OFF_ERROR+3] != 0)
            {
            (void) printf("%s\n",pntr); 	/* display error message */
            (void) MID_LOG('G',pntr,(int)strlen(pntr));
            }
    
         if (kk == kk1)			/* save error of top of stack */
            {
            (void) SCKWRC("MID$ERRMESS",1,pntr,1,80,&mm);  /* => MID$ERRMESS */

            source = ERROS[kk][0];
            mm = CGN_INDEXS(pntr,"- ");		/* get to error itself... */
            pntr += (mm + 2);
            (void) strncpy(saverr,pntr,6);
            }
 
         if (kk == 0)
            {
            if (source == 1) 				/* MIDAS error: */
               MID_ERRFIL(usr_level,saverr);	/* write canned help text */
#if vms
            else if (source == 2)
               {  		/* - Operating or File system interfaces: */
               int  istat;

               mm = sscanf(saverr,"%d",&istat);
               if ((mm != 0) && (istat != 0))
                  {
                  char  tmp[260];

                  OSY_MESSAGE(istat,tmp);	/* obtain full message */
                  (void)printf("%s\n",tmp);
                  }
               }
#endif
            }	
         }	
      }
 
   ERRO_INDX = -1;
   ERRO_OFF = 0;
   }
}
/*

*/
 
void MID_ERROR(subsystem,text,status,print)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  display error/warning/info messages
.ALGORITHM
store message into error stack + display complete stack if relevant
store warning/error status and error source into key PROGSTAT
.RETURNS 
nothing.
--------------------------------------------------------*/
 
char   *subsystem	/* subsystem from which error resulted OSY or FSY or \
                           MIDAS */;
char   *text	  	/* text to be stored in the error stack */;
int   status		/* error status */;
int   print		/* print flag, if set dump contents of error stack + \
                           reset pointer */;
 
{
int    mm, kk, source, ind;
static int   errtab_off = 9;		/* must be = lowest warning code! */

char  *osmsg();
static char	fixtype[20] = {'(','O','S','Y',')','(','F','S','Y',')',
                       '(','E','R','R',')','(','I','/','W',')'};
static char    aux1 [3] = {' ','-',' '};
static char    aux2 [9] = {' ','-',' ','I','N','V','E','R','R'};
	
 


/* init message string */
 
mm = (int) strlen(text);			/* get length of text */
if (mm > 65) mm = 65;			/* minimize... */
memset((void *)mess,32,(size_t)6);
	

/*  subsystem may either be OSY, FSY, APP or MIDAS */
 
if ((*subsystem == 'O') || (*subsystem == 'F'))
   {
   source = 2;				/* OSY or FSY error... */
   pntr = fixtype;			/* use both "(OSY)" prefix */
   (void) strncpy(mess,pntr,5);		/* copy type of error */
   messpntr = mess + 6;
#if vms
   (void) snprintf(messpntr,(size_t) 78,
	           "%s - %d (or %x hex)",text,status,status);	
#else
   (void) snprintf(messpntr,(size_t) 78,"%s  %s",text,osmsg());
#endif
   KIWORDS[OFF_PRSTAT+3] = status;	/* save host system error */
   }

else if (*subsystem == 'A') 
   {
   source = 100;			/* application provided error */
   ERRO_INDX = -1;		/* reset error stack */
   ERRO_OFF = 0;
   (void) strcpy(mess,"(APP) application error");
   (void) snprintf(work,(size_t) 20," - %d ",status);	/* append error */
   (void) strcat(mess,work);

   }

else
   {
   if ( (ERRO_LOG == 0) ||
        ((ERRO_LOG == 1) && (status < 0)) ) return;
	
   source = 1;				/* error from MIDASLIB...  */
   if (status > 0)
      pntr = fixtype + 10;
   else
      pntr = fixtype + 15;
 
   (void) strncpy(mess,pntr,5);			/* copy type of error */
   messpntr = mess + 6;
   (void) strncpy(messpntr,text,(size_t) mm);	/* copy user message */
   messpntr += mm;				/* adapt to count in MESS */
   ind = (status + errtab_off) * 6;	    /* get offset into error table */

   if (ind >= (ETABLIM*6))
      {
      (void) strncpy(messpntr,aux2,9);
      messpntr += 9;				/* determine final length */
      }
   else
      {
      (void) strncpy(messpntr,aux1,3);
      pntr = ERRTAB + ind;
      (void) strncpy(messpntr+3,pntr,6);
      messpntr += 9;				/* determine final length */
      }
   *messpntr = '\0';				/* fix the end */
   }
 

/*  put all relevant stuff on error stack  */
 
kk = MID_PUTERR(source);
if (kk != 0) 			/* something went wrong... */
   {
   if (print > 0)
      {
      if (kk == 1) 		
         (void) printf(" error stack overflow... \n");
      else
         (void) printf(" error message buffer overflow... \n");

      MID_DSPERR();			/* display contents of error stack */
      }
   ERRO_INDX = -1;
   ERRO_OFF = 0;
   (void) MID_PUTERR(source);
   }
	

KCWORDS[OFF_APPLIC] = 'x';	/* indicate that module was "aborted" */

if (print < 1) return;		/* low level MIDAS routines exit here... */
 
ind = ERRO_INDX;				/* we may need it later...  */
MID_DSPERR();

if (source == 100) return;	/* do the rest in SCETER ... */


/*  finally check continuation flag for high level interfaces  */

if ( (ERRO_CONT == -1) ||			/* stop on everything */
     ((status > 0) && (ERRO_CONT == 0)) ) 	/* stop on errors only */
   {
   if (caller[0] != '*')
      {					/* print high level calling routine */
      kk = ERROS[ind][1];
      pntr = &ERRO_MESAGS[kk];
      mm = CGN_INDEXS(pntr,"- ");		/* get to error itself... */
      pntr += mm;
      (void) printf("(ERR) %s: %s\n",caller,pntr);
      caller[0] = '*';
      }

   MID_ABORT(status,source);		/* now exit (but set ERROR(6) first) */
   }
}
/*

*/
 
void MID_INITER()
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  initialize error structures
.ALGORITHM
  straight forward
.RETURNS 
  nothing
--------------------------------------------------------*/
 
{
 
/*  reset pointers  */
	
ERRO_INDX = -1;		/* last used entry in stack */
ERRO_OFF = 0;		/* offset to first free char. in message buffer */

ERRO_CONT = 0;				/* stop on errors only */
ERRO_LOG = 2;				/* log warnings + errors */
ERRO_DISP = 1;				/* display only errors */

caller[0] = '*';		 /*  clear high level calling routine  */

}
 
void MID_POPERR()
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  remove last (top) stack entry
.ALGORITHM
  straight forward
.RETURNS 
  nothing
--------------------------------------------------------*/
 
{
 
int   mm;

 
mm = ERRO_INDX;
if (mm > 0) 			/* if not 1st entry */
   {
   ERRO_INDX--;
   ERRO_OFF = ERROS[mm][1];		/* get previous offset */
   if (ERRO_OFF < 0) ERRO_OFF = 0;
   }
else	
   {
   ERRO_INDX = -1;	
   ERRO_OFF = 0;		/* offset to 1st free char. in messbuffer */
   }

caller[0] = '*';		/*  clear high level calling routine  */
}
/*

*/
 
int MID_PUTERR(source)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
put error message into error stack
.ALGORITHM
straight forward
.RETURNS
istat: 	0, if o.k; 1, overflow in error stack;
 	2, overflow in message buffer
-------------------------------------------------------*/

int  source	/* IN : source of error */;

	
{
int   mm, meslen;


/*  check index of error stack  */
 
mm = ERRO_INDX + 1;			/* point to next free slot in stack */
if (mm >= ERRO_MAXENT) return (1);
	
meslen = (int) strlen(mess);


/* test, if full message + '\0' fits... */

if ( (ERRO_OFF + meslen) >= ERRO_MAXLEN) return (2);
	

/*  we still got space for this one... */
 
ERRO_INDX = mm;				/* update stack index */
ERROS[mm][0] = source;
ERROS[mm][1] = ERRO_OFF;		/* set offset */
	

/*  finally put the actual message into message buffer */
 
(void) strcpy(&ERRO_MESAGS[ERRO_OFF],mess);
ERRO_OFF += (meslen + 1);		/* update message offset  */
	
return (0);
}
/*

*/
 
void MID_E1(funcno,text,status,print)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  display error/warning/info messages
.ALGORITHM
  call MID_ERROR
.RETURNS 
  nothing.
--------------------------------------------------------*/
 
int    funcno;	/* IN: no. of function from which error resulted */
char   *text	  	/* text to be stored in the error stack */;
int   status		/* error status */;
int   print		/* print flag, if set dump contents of error stack + \
                           reset pointer */;
 
{
int  mm;

static char	modu_1[] = 
                "SPROSEPIFOPNFCREKRDxKPROKWRxKINFIPUTIGETKFNDFINFFXMP";
	

mm = (funcno - 1) * 4;

(void) strcpy(work,"SC ");
(void) strncpy(&work[2],&modu_1[mm],4);
(void) strcpy(&work[6],": ");
(void) strcpy(&work[8],text);

MID_ERROR("MIDAS",work,status,print);
}
/*

*/
 
void MID_E2(funcno,imno,text,status,print)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  display error/warning/info workages
.ALGORITHM
  call MID_ERROR
.RETURNS 
  nothing.
--------------------------------------------------------*/
 
int    funcno;	/* IN: no. of function from which error resulted */
int    imno;	/* IN: FCT entry no. of frame involved  */
char   *text	  	/* text to be stored in the error stack */;
int   status		/* error status */;
int   print		/* print flag, if set dump contents of error stack + \
                           reset pointer */;
 
{
int  mm;

static char	modu_2[] = 
                "FCLOFMAPFUNMDDELDWRxDRDxDINFDCOPDFNDFGETFPUTPGETPPUT";
	

mm = (funcno - 1) * 4;

(void) strcpy(work,"SC ");
(void) strncpy(&work[2],&modu_2[mm],4);
(void) strcpy(&work[6],": ");

mm = MID_RETNAM(imno,&work[8],80);		/* get name of file */
if (mm < 0) (void) strcpy(&work[8],"wrong file number");
(void) strcat(work," + ");
(void) strcat(work,text);

MID_ERROR("MIDAS",work,status,print);
}
/*

*/
 
void MID_E3(callfunc)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  put name of high level calling rotuine into internal buffer
.ALGORITHM
use strcpy ...
.RETURNS 
  nothing.
--------------------------------------------------------*/
 
char   *callfunc;

{
(void) strcpy(caller,callfunc);
} 



void MID_ABORT(erro,source)
 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE
  abort application program, but close keyfile correctly
.ALGORITHM
  as it should be...
.RETURNS 
  nothing.
--------------------------------------------------------*/
 
int  erro, source;

{
KIWORDS[OFF_PRSTAT] = erro;	/* store status and error source */
KIWORDS[OFF_PRSTAT+1] = source;	/* into key PROGSTAT */

MID_LOG('O',work,5);	 	                  /* leave like in SCSEPI ... */
work[0] = ' ';
MID_MOVKEY("O",work);			  /* update keyfile  */

ospexit(0);					  /* and get out of here!  */
} 
/*

*/
 
void error_ret(fnam,addon,myerrno,status)

char  *fnam, *addon;
int myerrno, status;

{
int mm;

char  txt[80];

mm = CGN_INDEXC(fnam,' ');
if (mm <= 0) mm = (int) strlen(fnam);
(void) strncpy(txt,fnam,(size_t) mm);
txt[mm++] = ' ';
(void) strcpy(&txt[mm],addon);
MID_E1(myerrno,txt,status,1);
}

