/****************************************************************************
**
**  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/mt2_186/errtext/mkerrors.c_v  $
** 
**    Rev 1.0   16 Dec 1996 14:29:36   Judy
** Initial revision.
** 
**    Rev 1.17   18 Aug 1994 11:16:28   nghia
** Fixed bug in generate error code not the same for ERRCODEC.H and ERRCODEA.H
** 
**    Rev 1.16   21 Jul 1994 17:06:02   nghia
** Put back the mkerrors.new fiel generation.
** 
**    Rev 1.15   21 Jul 1994 16:12:44   nghia
** Revised to support multiple MKERROR#.H files.
** Fixed bug in the bubble sort section.
** Removed mkerrors.new generation - Unused file.
** 
**    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/mt2_186/errtext/mkerrors.c_v   1.0   16 Dec 1996 14:29:36   Judy  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

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

#include <stdio.h>
#include <malloc.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

#ifndef _MKERRS_
#include "mkerrs.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

BOOLEAN changeCodes = TRUE;
BOOLEAN changeHelp  = TRUE;
ErrorDefPtr SortArray[MAX_ERRORS];
U16 MaxIDNameLen = 0;
U16 maxErr = 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).
 * NOTES: Nghia - 07/21/94
 * Each ErrorArray#[] should be in a module (see extern.c and extern1.c)
 * Each ErrorArray# use the correspond mkerror#.h file.
 */
extern ErrorDef huge ErrorArray[];   // defined in extern.c
extern ErrorDef huge ErrorArray1[];  // defined in extern1.c

int main() {
   U32 n, m;
   U32 numerr;
   S16 cmpval;
   U16 dups;
   U16 switched;
   ErrorDefPtr tmp;
   
   /* Combine the ErrorArray#[] into the SortArray[] */
   maxErr = SizeErrArray() + SizeErrArray1();
   /* check to make use the SortArray has room */
   if (maxErr > MAX_ERRORS) {
      printf("Not enough memory - Increase MAX_ERRORS (mkerrs.h) to %d\n",
              maxErr+1);
      return 0;
   }
   
   numerr = SizeErrArray();
   for (n = 0; n < numerr; n++) {
      SortArray[n] = (ErrorDefPtr)&(ErrorArray[n]);
   }
   
   numerr = SizeErrArray1();
   // continue where n left off in SortArray
   for (m = 0; m < numerr; m++) {
      SortArray[n++] = (ErrorDefPtr)&(ErrorArray1[m]);
   }
   
   /* 
    *  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.
    *  
    */

   dups = 0;
   for (m = 0; m < maxErr; m++) {
      for (n = maxErr-1; m < n; n--) {
         if ((cmpval = strcmp(SortArray[n]->name, SortArray[n-1]->name)) < 0) {
            tmp = SortArray[n];
            SortArray[n] = SortArray[n-1];
            SortArray[n-1] = tmp;
         }
         else if (cmpval == 0) {
            printf("%s is duplicated in mkerrors.h\n",
                   (CHAR*)SortArray[n]->name);
            dups++;
         }
      }
      if (strlen(SortArray[m]->name) > MaxIDNameLen) {
         MaxIDNameLen = strlen(SortArray[m]->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() {
   U16 n, m;
   U16 code;
   FILE *cfp;
   FILE *hfp;
   FILE *mfp;
   U32 severity;
   U32 errcode = ER_RC_BASE + 1;
   CHAR buf[256];
   BOOL collision;

   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;
   S16 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()
{
   U16 n;
   FILE *cfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;

   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);
      /*
      ** 08/16/94 - Nghia
      ** Cannot do this format any more, actually we don't need to do this.
      ** It's better to generate the same error code as the ERRCODEA.H
      ** BUG:
      ** If an error is (E_FATAL | E_WARNING | x) or a combination that
      ** generate an SEVERITY_ID == E_SEVERITY_MASK then this error code
      ** will screw up.
      ** ----------------------- REMOVE --------------------------------
      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 |");
      }
      ** --------------------------- REMOVE ----------------------------
      **
      */

      fprintf(cfp,"0x%lXL\n", SortArray[n]->code);
   }
   fclose(cfp);
   return (GOOD);
}

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

   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() {
   U16 n;
   FILE *cfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;

   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() {
   U16 n;
   U16 maxhelp;
   FILE *cfp;
   FILE *tfp;
   FILE *hfp;
   U32 severity;
   U16 namesize = MaxIDNameLen + 1;
   CHAR buf[256];
   U16 printedSomething = FALSE;

   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);
}
