/****************************************************************************
**
**  Name:  mkerrors.c
**
**  Description:
**     This is the little program that will generate the error header
**     files needed in PowerViews.  This files that are automatically 
**     produced by this are:
**       actor\res\errcodea.h : error code defines in Actor format
**       inc\errcodec.h : error code defines in C format
**       errtext\errtext.rc : string resources (error text)
**       errtext\errhelp.map : help [MAP] codes for the pwrviews.hpj file
**       errtext\errhelp.h : include file of help codes 
**       errtext\errhlptr.h : include file of translation array of
**                            error code to help entry
**       errtext\mkerrors.new : the next version of the mkerrors.h file
**       errtext\errtrans.h : include file of translation array of error
**                            code to offset in errtext.rc
**
**  Status:  PRELIMINARY 
**
**  $Log:   S:/tbird/arcppc/errtext/mkerrors.c_v  $
** 
**    Rev 1.0   15 Jan 1997 15:51:50   kevin
** Initial revision.
** 
**    Rev 1.0   15 Jan 1997 15:19:42   kevin
** Initial revision.
** 
**    Rev 1.0   03 Jun 1996 11:23:04   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:22:52   gene
** Initial revision.
** 
**    Rev 1.14   30 Mar 1994 18:30:08   tom
** Use external data from extern.c.
** 
**    Rev 1.13   19 Jul 1993 13:29:56   ron
** need to keep the IDs of errors in errerr.h and offsets in errtrans.h the
** same as the order of the errors in errtext.rc.
** 
**    Rev 1.12   16 Jul 1993 15:26:26   ernie
** 1. Cleaned up compiler warnings.
** 2. Fixed bug in errorcode conflict check that printed lots of bogus errors.
** 3. Fixed bug in generation of errtrans.h--the wrong string numbers were
**    being stuck into the file.
** 
**    Rev 1.11   16 Jul 1993 08:58:12   tom
** ppr 8368: remove timestamp on critical errors
** 
**    Rev 1.10   14 Jul 1993 17:12:22   steve
** Conflict with locked numbers, so start at 500 as kludge.  
** 
**    Rev 1.9   14 Jul 1993 16:04:40   steve
** Added quotes and fixed error if first error is internal (extra comma).
** 
**    Rev 1.8   14 Jul 1993 15:40:36   steveh
** Error array over 64k
** 
**    Rev 1.7   29 Jun 1993 16:09:22   steveh
** Bug in LOCKED vs UNLOCKED code
** 
**    Rev 1.6   28 Jun 1993 10:42:26   ron
** changes to get help buttons for all server errors
** 
**    Rev 1.5   24 Jun 1993 11:09:10   ron
** fixed a bug in regeneration of error codes
** 
**    Rev 1.4   14 Jun 1993 10:08:16   ron
** forgot fclose of errhelp.map file.
** 
**    Rev 1.3   14 Jun 1993 09:38:16   ron
** changes due to addition of help buttons to errorBox dialogs in Actor
** 
**    Rev 1.2   09 Jun 1993 17:01:52   ron
** PIP: translate error codes to rc offsets and help entry points
** 
**    Rev 1.1   04 Jun 1993 16:21:30   ron
** done with Actor part -- checking in prior to tackling servers
** 
**    Rev 1.0   03 Jun 1993 16:34:56   ron
** Initial revision.
** 
**  $Header:   S:/tbird/arcppc/errtext/mkerrors.c_v   1.0   15 Jan 1997 15:51:50   kevin  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/


#define _ERRCODEC_      /* Prevent inclusion of file this program produces */

#include <stdio.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif

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

#ifndef _CLISRV_
#include "clisrv.h"
#endif

#ifndef _CLIULIB_
#include "cliulib.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
U32 externSize(VOID);

/*
 * LOCKED means that you can't change the error code, even if changeCodes
 * is true.
 */
#define LOCKED       1
#define UNLOCKED     2

#define ER_RC_BASE   500
#define ER_HELP_BASE 3000
#define BAD          (GOOD + 666)
#define MAX_ERRORS   1024

BOOLEAN changeCodes = TRUE;
BOOLEAN changeHelp  = TRUE;

RETCODE Regen_mkerrs_h(void);
RETCODE CopyHeader(FILE *fp, char *HeaderFile);
RETCODE Regen_errcodec_h(void);
RETCODE Regen_errcodea_h(void);
RETCODE Regen_errerr_h(void);
RETCODE Regen_errtext_rc(void);

typedef struct {
   char * name;
   U32  code;
   char * text;
   char * helpentry;
   U16  flags; /* only LOCKED/UNLOCKED so far */
} ErrorDef;

ErrorDef *SortArray[MAX_ERRORS];
U16 MaxIDNameLen = 0;

/*
 * This include file is in a non-standard place, because this include
 * file is actually re-generated by this program, from the previous include
 * file (which may have been hand-modified).
 */
extern ErrorDef huge ErrorArray[];


main()
{
   int n;
   int maxerr;
   int cmpval;
   int dups;
   int switched;
   ErrorDef *tmp;

   maxerr = externSize() / sizeof(ErrorDef);
   for (n = 0; n < maxerr; n++) {
      SortArray[n] = &(ErrorArray[n]);
   }
   /* 
    *  Sort the entries by the ID names, and use the sorted order
    *  to regenerate the new mkerrors.h (mkerrors.new) file.
    *
    *  Efficiency is unnecessary here...simplest sort is ok.
    */
   switched = 1;
   dups = 0;
   while (switched) {
      switched = 0;
      for (n = 0; n < maxerr - 1; n++) {
         if ((cmpval = strcmp(SortArray[n]->name, SortArray[n+1]->name)) > 0) {
            tmp = SortArray[n];
            SortArray[n] = SortArray[n+1];
            SortArray[n+1] = tmp;
            switched = 1;
         }
         else if (cmpval == 0) {
            printf("%s is duplicated in mkerrors.h\n", SortArray[n]->name);
            dups++;
         }
         if (strlen(SortArray[n]->name) > MaxIDNameLen) {
            MaxIDNameLen = strlen(SortArray[n]->name);
         }
      }
   }
   if (dups > 0) {
      printf("Please fix the errors in mkerrors.h and try again.\n");
   }
   if (Regen_mkerrs_h() != GOOD) {
      printf("Error making mkerrs.new file!\n");
   }
   if (Regen_errcodec_h() != GOOD) {
      printf("Error making errcodec.h file!\n");
   }
   if (Regen_errcodea_h() != GOOD) {
      printf("Error making errcodea.h file!\n");
   }
   if (Regen_errerr_h() != GOOD) {
      printf("Error making errerr.h file!\n");
   }
   if (Regen_errtext_rc() != GOOD) {
      printf("Error making errtext.rc file!\n");
   }
   return (0);
}

RETCODE Regen_mkerrs_h()
{
   int n, m;
   U16 code;
   int maxerr;
   FILE *cfp;
   FILE *hfp;
   FILE *mfp;
   U32 severity;
   U32 errcode = ER_RC_BASE + 1;
   char buf[256];
   BOOL collision;

   maxerr = externSize() / sizeof(ErrorDef);
   cfp = fopen("mkerrors.new", "w");
   if (changeHelp) {
      hfp = fopen("errhelp.h", "w");
   }
   mfp = fopen("errhelp.map", "w");
   if (cfp == NULL) {
      printf("Couldn't open mkerrors.new\n");
      return (BAD);
   }
   if (changeHelp && hfp == NULL) {
      printf("Couldn't open errhelp.h\n");
      return (BAD);
   }
   if (mfp == NULL) {
      printf("Couldn't open errhelp.map\n");
      return (BAD);
   }
   if (CopyHeader(cfp, "mkerrors.hdr") != GOOD) {
      printf("Couldn't copy mkerrors.hdr to mkerrors.new\n");
      return (BAD);
   }
   /* Change the error codes, avoiding locked values and warn about dups */
   if (changeCodes) {
      for (n = 0; n < maxerr; n++) {
         if (SortArray[n]->flags & LOCKED) {
            code = E_ERRORID(SortArray[n]->code);
            for (m = n + 1; m < maxerr; m++) {
               if ((code == E_ERRORID(SortArray[m]->code))
                    && (SortArray[m]->flags & LOCKED)) {
                  printf("WARNING!!\n %s and %s have same error code! (%ldL)\n",
                     SortArray[n]->name, SortArray[m]->name, E_ERRORID(code));
                  break;
               }
            }
         }
         else {
            collision = TRUE;
            while (collision) {
               code = errcode++;
               collision = FALSE;
               for (m = n + 1; m < maxerr; m++) {
                  if ((SortArray[m]->flags & LOCKED) && 
                        (code == E_ERRORID(SortArray[m]->code))) {
                     collision = TRUE;
                     break;
                  }
               }
            }
            SortArray[n]->code &= ~(E_ERRORID(SortArray[n]->code));
            SortArray[n]->code |= code;
         }
      }
   }
   else {
      for (n = 0; n < maxerr; n++) {
         code = E_ERRORID(SortArray[n]->code);
         for (m = n + 1; m < maxerr; m++) {
            if (code == E_ERRORID(SortArray[m]->code)) {
               printf("WARNING!!\n %s and %s have same error code! (%ldL)\n",
                  SortArray[n]->name, SortArray[m]->name, E_ERRORID(code));
               break;
            }
         }
      }
   }
   for (n = 0; n < maxerr; n++) {
      fprintf(cfp,"{\n   \"%s\",\n   (", SortArray[n]->name);
      if (INTERNAL_ERROR(SortArray[n]->code)) {
         fprintf(cfp," INTERNAL_ERROR_ON |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_INFORMATIVE) {
         fprintf(cfp," E_INFORMATIVE |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_WARNING) {
         fprintf(cfp," E_WARNING |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_SEVERE) {
         fprintf(cfp," E_SEVERE |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_FATAL) {
         fprintf(cfp," E_FATAL |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_CATASTROPHIC) {
         fprintf(cfp," E_CATASTROPHIC |");
      }
      fprintf(cfp," %lXL |", (E_COMPONENT_MASK & SortArray[n]->code));
      fprintf(cfp," %ldL ),\n", E_ERRORID(SortArray[n]->code));
      fprintf(cfp,"   \"%s\",\n", SortArray[n]->text);
      strcpy(buf, SortArray[n]->name);
      buf[0] = 'H';
      buf[1] = 'E';
      if (!INTERNAL_ERROR(SortArray[n]->code)) {
         if (changeHelp) {
            fprintf(hfp,"#define %s %ldL\n", buf, 
               E_ERRORID(SortArray[n]->code) + ER_HELP_BASE);
         }
         fprintf(mfp,"%s %ld  ; %s\n", buf, 
            E_ERRORID(SortArray[n]->code) + ER_HELP_BASE, SortArray[n]->text,
            " ", " ", " "); /* empty strings are to handle printf funnies */
      }
      if (SortArray[n]->flags & LOCKED)
         fprintf(cfp,"   \"%s\",\n   LOCKED\n}", buf);
      else
         fprintf(cfp,"   \"%s\",\n   UNLOCKED\n}", buf);
      if (n < maxerr - 1) {
         fprintf(cfp,",");
      }
      fprintf(cfp,"\n");
   }
   fclose(cfp);
   fclose(hfp);
   fclose(mfp);
   return (GOOD);
}

RETCODE CopyHeader(FILE *fp, char *HeaderFile)
{
   FILE *hfp;
   int c;

   if ((hfp = fopen(HeaderFile,"r")) == NULL) {
      return (BAD);
   }
   while ((c = fgetc(hfp)) != EOF) {
      fputc(c, fp);
   }
   fclose(hfp);
   return (GOOD);
}

RETCODE Regen_errcodec_h()
{
   int n;
   int maxerr;
   FILE *cfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;

   maxerr = externSize() / sizeof(ErrorDef);
   cfp = fopen("errcodec.h", "w");
   if (CopyHeader(cfp, "errcodec.hdr") != GOOD) {
      printf("Couldn't copy errcodec.hdr to errcodec.h\n");
      return (BAD);
   }
   for (n = 0; n < maxerr; n++) {
      fprintf(cfp,"#define %-*s (", namesize, SortArray[n]->name);
      if (INTERNAL_ERROR(SortArray[n]->code)) {
         fprintf(cfp," INTERNAL_ERROR_ON |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_INFORMATIVE) {
         fprintf(cfp," E_INFORMATIVE |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_WARNING) {
         fprintf(cfp," E_WARNING |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_SEVERE) {
         fprintf(cfp," E_SEVERE |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_FATAL) {
         fprintf(cfp," E_FATAL |");
      }
      if ((E_SEVERITY_MASK & SortArray[n]->code) == E_CATASTROPHIC) {
         fprintf(cfp," E_CATASTROPHIC |");
      }
      fprintf(cfp," %ldL )\n", E_ERRORID(SortArray[n]->code));
   }
   fclose(cfp);
   return (GOOD);
}

RETCODE Regen_errcodea_h()
{
   int n;
   int maxerr;
   FILE *cfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;

   maxerr = externSize() / sizeof(ErrorDef);
   cfp = fopen("errcodea.h", "w");
   if (CopyHeader(cfp, "errcodea.hdr") != GOOD) {
      printf("Couldn't copy errcodea.hdr to errcodea.h\n");
      return (BAD);
   }
   for (n = 0; n < maxerr; n++) {
      if (n % 4 == 0) {
         fprintf(cfp,"!!\n");
      }
      fprintf(cfp,"#define %-*s ", namesize, SortArray[n]->name);
      fprintf(cfp,"0x%lXL\n", SortArray[n]->code);
   }
   fclose(cfp);
   return (GOOD);
}

RETCODE Regen_errerr_h()
{
   int n;
   int maxerr;
   FILE *cfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;

   maxerr = externSize() / sizeof(ErrorDef);
   cfp = fopen("errerr.h", "w");
   if (CopyHeader(cfp, "errerr.hdr") != GOOD) {
      printf("Couldn't copy errerr.hdr to errerr.h\n");
      return (BAD);
   }
   for (n = 0; n < maxerr; n++) {
      fprintf(cfp,"#define %-*s ", namesize, SortArray[n]->name);
      fprintf(cfp,"%ld\n", (long) (n + 1 + ER_RC_BASE));
   }
   fclose(cfp);
   return (GOOD);
}

RETCODE Regen_errtext_rc()
{
   int n;
   int maxerr;
   int maxhelp;
   FILE *cfp;
   FILE *tfp;
   FILE *hfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;
   char buf[256];
   int printedSomething = FALSE;

   maxerr = externSize() / sizeof(ErrorDef);
   cfp = fopen("errtext.rc", "w");
   tfp = fopen("errtrans.h", "w");
   hfp = fopen("errhlptr.h", "w");
   if (cfp == NULL) {
      printf("Couldn't write new errtext.rc\n");
      return (BAD);
   }
   if (tfp == NULL) {
      printf("Couldn't write new errtrans.h\n");
      return (BAD);
   }
   if (hfp == NULL) {
      printf("Couldn't write new errhlptr.h\n");
      return (BAD);
   }
   fprintf(tfp,"typedef struct {\n   U32 errcode;\n   U16 offset;\n");
   fprintf(tfp,"} ErrTrans;\nErrTrans ErrTranslation[] = {\n");
   fprintf(hfp,"typedef struct {\n   U32 errcode;\n   U16 helpEntry;\n");
   fprintf(hfp,"} ErrHelpTrans;\nErrHelpTrans ErrHelpTranslation[] = {\n");
   if (CopyHeader(cfp, "errtext.hdr") != GOOD) {
      printf("Couldn't copy errtext.hdr to errtext.rc\n");
      return (BAD);
   }
   for (n = 0, maxhelp = 0; n < maxerr; n++) {
      sprintf(buf,"%s,", SortArray[n]->name);
      fprintf(cfp,"%-*s ", namesize, buf);
      fprintf(cfp,"\"%s\"\n", SortArray[n]->text);
      /* fprintf(tfp,"   { 0x%lXL, %d}", SortArray[n]->code,
         E_ERRORID(SortArray[n]->code)); -- From Ernie */
      fprintf(tfp,"   { 0x%lXL, %d}", SortArray[n]->code, n + 1 +
         ER_RC_BASE);
      if (!INTERNAL_ERROR(SortArray[n]->code)) {
         maxhelp++;
         if (printedSomething) {
            fprintf(hfp,",\n");
         }
         fprintf(hfp,"   { 0x%lXL, %s}", SortArray[n]->code,  
            SortArray[n]->helpentry);
      printedSomething = TRUE;
      }
      if (n < maxerr - 1) {
         fprintf(tfp,",\n");
      }
      else {
         fprintf(tfp,"\n};\n#define MAX_ERR_TRANS %d", maxerr);
         fprintf(hfp,"\n};\n#define MAX_HELP_TRANS %d", maxhelp);
      }
   }
   fprintf(cfp,"}\n");
   fclose(cfp);
   fclose(tfp);
   fclose(hfp);
   return (GOOD);
}
