/***************************************************************************
**
**    $Header$
**
**    $Log$
** 
****************************************************************************/

/****************************************************************************
**
**  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 
**
** 
**  Date:   3/22/96 		by: Jamoon Zhou
**
**  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>

#include "basewind.h"

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

#include "hosterr.h"

#include "mkerrs.h"

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

BOOLEAN changeCodes = TRUE;
BOOLEAN changeHelp  = TRUE;
//ErrorDefPtr SortArray[MAX_ERRORS];
ErrorDefPtr *SortArray;
U16 MaxIDNameLen = 0;
U16 maxErr = 0;
char Path[_MAX_PATH]="";


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
/*
 * 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
extern ErrorDef huge ErrorArray2[];  // defined in extern2.c
extern ErrorDef huge ErrorArray3[];  // defined in extinfo.c

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
// mode : 0 for name sorting,  1 for Id value sorting
int SortError( int mode = 0 );
RETCODE Regen_errcodec_h(int mode = 0 );
RETCODE Regen_errtext_rc(int mode = 0 ); 
RETCODE CopyHeader(FILE *fp, CHAR *HeaderFile); 

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/


int main(int argc, char** argv) 
{
   	U32 n, m;
   	U32 numerr;
   	//S16 cmpval;
   	//int dups;
   	//U16 switched;
   	//ErrorDefPtr tmp;

	if( argc > 1 ) {  
		strcpy( Path, argv[1] );
		if( Path[strlen(Path)-1] != '\\' ) strcat(Path,"\\");
	}
	
   	/* Combine the ErrorArray#[] into the SortArray[] */
   	maxErr =(U16) ( SizeErrArray() + SizeErrArray1() + SizeErrArray2() 
   			+ SizeErrArray3() );
   	SortArray = new ErrorDefPtr[maxErr];
   	if ( SortArray == NULL ) {
      	printf("Not enough memory - Total error items: %d\n",
              maxErr);
      	return 0;
    }
    else printf("Total error items: %d\n", maxErr);
/*   		
   	// 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]);
   	}

   	numerr = SizeErrArray2();
   	// continue where n left off in SortArray
   	for (m = 0; m < numerr; m++) {
      	SortArray[n++] = (ErrorDefPtr)&(ErrorArray2[m]);
   	}

   	numerr = SizeErrArray3();
   	// continue where n left off in SortArray
   	for (m = 0; m < numerr; m++) {
      	SortArray[n++] = (ErrorDefPtr)&(ErrorArray3[m]);
   	}

	SortError(1);
/*	  
   	if (Regen_mkerrs_h() != GOOD) {
      	printf("Error making mkerrs.new file!\n");
   	}
*/
   	if (Regen_errcodec_h(1) != GOOD) {
      	printf("Error making errcodea.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(1) != GOOD) {
      	printf("Error making errtext.rc file!\n");
   	}
   	
	SortError();
   	if (Regen_errcodec_h(0) != GOOD) {
      	printf("Error making errcodec.h file!\n");
   	}
//   	if (Regen_errtext_rc(0) != GOOD) {
//      	printf("Error making errtexta.rc file!\n");
//   	}
	delete []SortArray;
   	return (0);
}

int SortError( int mode  )
{
   	/* 
      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.
      
    */
    unsigned n, m;
   	int  cmpval, dups = 0;
	ErrorDefPtr tmp;
   	
   	for (m = 0; m < maxErr; m++) {
    	for (n = maxErr-1; m < n; n--) {
    		if ( mode == 0 ) 
    			cmpval = strcmp(SortArray[n]->name, SortArray[n-1]->name);
    		else
    			cmpval = ((UINT) SortArray[n]->code > 
    						(UINT)SortArray[n-1]->code ) ?  1 :
    					 ( (UINT)SortArray[n]->code < 
    					 	(UINT)SortArray[n-1]->code ) ? -1 : 0;
       		if ( cmpval < 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");
   	}
   	return dups;
}


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 =(U16) 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 =(U16) 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_ERROR) {
         fprintf(cfp," E_ERROR |");
      }
      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);
*/
	  fprintf(cfp,"}");
      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(int mode)
{
   	U16 n;
   	FILE *cfp;
   	//U32 severity;
   	U16 namesize = MaxIDNameLen + 1;
   	char PathName[_MAX_PATH], HeadName[20];

   	strcpy( PathName, Path );
//   	if ( mode == 0 )
//  		strcat(PathName,"errcodec.h");
//   	else strcat( PathName,"errcodea.h" );
   	if ( mode != 0 ) {
   		strcat(PathName,"errcodec.h");
   		strcpy(HeadName,"errcodec.hdr");
   	}
   	else {
   		strcat( PathName,"errcodea.h" );
   		strcpy(HeadName,"errcodea.hdr");
   	}
   	cfp = fopen(PathName, "w");
   	if (CopyHeader(cfp, HeadName) != GOOD) {
      	printf("Couldn't copy errcodec(a).hdr to errcodec(a).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, *tfp;
   //U32 severity;
   U16 namesize = MaxIDNameLen + 1;

   char PathName[_MAX_PATH];

//   strcpy( PathName, Path );
//   strcat(PathName,"errerr.h");
	strcpy(PathName,"errerr.h");
   cfp = fopen(PathName, "w");
   tfp = fopen("errtrans.h", "w");
//   cfp = fopen("errerr.h", "w");
   if (cfp == NULL || tfp == NULL) {
      printf("Couldn't write new errtext.rc/errtrans.h");
      return (BAD);
   }
   if (CopyHeader(cfp, "errerr.hdr") != GOOD) {
      printf("Couldn't copy errerr.hdr to errerr.h\n");
      return (BAD);
   }
   fprintf(tfp,"typedef struct {\n   U16 offset;\n   U32 errcode;\n");
   fprintf(tfp,"} ErrTrans;\n\nErrTrans ErrTranslation[] = {\n");
   
   for (n = 0; n < maxErr; n++) {
      fprintf(cfp,"#define %-*s ", namesize, SortArray[n]->name);
      fprintf(cfp,"%u\n", (U16)SortArray[n]->code);
      //fprintf(cfp,"%ld\n", (long) (n + 1 + ER_RC_BASE));

      fprintf(tfp,"   { 0x%04X,   0x%08lXL },\n", 
      			(U16)SortArray[n]->code, SortArray[n]->code );
   }
   fprintf(tfp,"};\n\n"); 
   fprintf(tfp,"#define MAX_ERR_TRANS %d\n", maxErr);

   fclose(tfp);
   fclose(cfp);
   return (GOOD);
}

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

//   	strcpy( PathName, Path );
	strcpy( PathName, "");
/*   	if ( mode == 0 )
   		strcat(PathName,"errtext.rc");
   	else
   		strcat(PathName,"errtexta.rc");
*/
   	if ( mode != 0 )
   		strcat(PathName,"errtext.rc");
   	else
   		strcat(PathName,"errtexta.rc");
   	cfp = fopen(PathName, "w");

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