/* $VER: vlink errors.c V0.6a (19.12.98)
 *
 * This file is part of vlink, a portable linker for multiple
 * object formats.
 * Copyright (c) 1997-99  Frank Wille
 *
 * vlink is freeware and part of the portable and retargetable ANSI C
 * compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
 * vlink may be freely redistributed as long as no modifications are
 * made and nothing is charged for it. Non-commercial usage is allowed
 * without any restrictions.
 * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
 * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
 *
 *
 * v0.6a (19.12.98) phx
 *       Error 61, when objects have different endianess.
 * v0.6  (23.10.98) phx
 *       Shared objects (60).
 * v0.5e (05.10.98) phx
 *       Error 59.
 * v0.5a (28.06.98) phx
 *       Multiple symbol definition (error 19) was turned into a warning.
 * v0.4  (05.06.98) phx
 *       Warnings for section-merging.
 * v0.3  (15.04.98) phx
 *       Changed all "%s(%s+0x%x):" strings into "%s (%s+0x%x):"
 *       New error messages for ELF and AR support.
 * v0.1  (27.02.98) phx
 *       First version that seems to link AmigaOS ADOS and EHF
 *       objects and libraries. Many common features, like linking
 *       sections together which have relative references, are
 *       still missing. Also, PowerPC-ELF32 support is about to come.
 * v0.0  (04.08.97) phx
 *       File created. Project started on a beautiful summer-day
 *       at the North Sea beach of Cuxhaven. :)
 *       Based on errors.c v0.4 of the portable PowerPC assembler "pasm".
 */


#define ERRORS_C
#include "vlink.h"


/* error flags */
#define EF_NONE 0
#define EF_WARNING 1
#define EF_ERROR 2
#define EF_FATAL 3


void error(int,...);
void ierror(char *,...);



static struct {
  char *txt;
  int flags;
} errors[] = {
  /* startup, command line */
  "",EF_NONE,
  "Out of memory",EF_FATAL,                                         /* 01 */
  "Unrecognized option '%s'",EF_WARNING,
  "Unknown link mode: %s",EF_WARNING,
  "Unknown argument for option -d: %c",EF_WARNING,
  "Option '-%c' requires an argument",EF_FATAL,                     /* 05 */
  "No input files",EF_FATAL,
  "File \"%s\" has a read error",EF_FATAL,
  "Cannot open \"%s\": No such file or directory",EF_FATAL,
  "Invalid target format \"%s\"",EF_FATAL,
  "Directory \"%s\" could not be examined",EF_ERROR,                /* 10 */
  "%s: File format not recognized",EF_FATAL,
  "\"%s\" is already an executable file",EF_WARNING,
  "%s: File format corrupted",EF_FATAL,
  "Can't open \"%s\" for output",EF_WARNING,
  "%s: Unexpected end of section %s in %s",EF_FATAL,                /* 15 */
  "%s: %s appeared twice in %s",EF_FATAL,
  "%s: Misplaced %s in %s",EF_FATAL,
  "%s: Symbol definition %s in %s uses unsupported type %d",EF_FATAL,
  "%s: Global symbol %s (%s) is already defined in %s (%s)",EF_WARNING,
  "%s: Unresolved reference to symbol %s in %s uses "               /* 20 */
    "unsupported type %d",EF_FATAL,
  "%s (%s+0x%x): Undefined reference to %s",EF_ERROR,
  "Protection of section %s was changed from %s to %s",EF_WARNING,
  "Alignment of section %s was changed from %d to %d",EF_WARNING,
  "%s (%s+0x%x): Illegal relative reference to %s+0x%x",EF_ERROR,    /* 24 */
  "%s (%s+0x%x): %dbit relative reference to %s+0x%x out of range",EF_ERROR,
  "%s (%s+0x%x): Referenced absolute symbol %s=0x%x + 0x%x "
    "doesn't fit into %d bits",EF_ERROR,
  "%s (%s+0x%x): Illegal relative reference to symbol %s",EF_ERROR,
  "%s (%s+0x%x): Relative reference to relocatable symbol %s=0x%x + 0x%x "
    "doesn't fit into %d bits",EF_ERROR,
  "Can't create output file %s",EF_ERROR,
  "Target file format doesn't support shared objects",EF_ERROR,     /* 30 */
  "Error while writing to %s",EF_FATAL,
  "Target %s: Unsupported relocation type %s at %s+0x%x",EF_ERROR,
  "Target %s: Can't reproduce symbol %s, which is a %s%s%s",EF_ERROR,
  "Option '%s' requires an argument",EF_FATAL,
  "-baseoff offsets are valid from 0 to 0x8000",EF_WARNING,         /* 35 */
  "%s (%s+0x%x): Base relative reference to relocatable symbol "
    "%s=0x%x + 0x%x doesn't fit into %d bits",EF_ERROR,
  "%s: Malformatted archive member %s",EF_FATAL,
  "%s: Empty archive ignored. Unable to determine file format",EF_WARNING,
  "%s: %s doesn't support shared objects in library archives",EF_FATAL,
  "%s: %s doesn't support executables in library archives",EF_FATAL,/* 40 */
  "%s (%s): Illegal format / file corrupted",EF_FATAL,
  "%s: Consistency check for archive member %s failed",EF_FATAL,
  "%s: Invalid ELF section header index (%d) in %s",EF_FATAL,
  "%s: ELF section header #%d has illegal offset in %s",EF_FATAL,
  "%s: ELF section header string table has illegal type in %s",     /* 45 */
    EF_ERROR,
  "%s: ELF section header string table has illegal offset in %s",EF_ERROR,
  "%s: ELF program header table in %s was ignored",EF_WARNING,
  "%s: ELF section header type %d in %s is not needed in "
    "relocatable objects",EF_WARNING,
  "%s: Illegal section offset for %s in %s",EF_FATAL,
  "%s: ELF %s table has illegal type in %s",EF_FATAL,               /* 50 */
  "%s: ELF %s table has illegal offset in %s",EF_FATAL,
  "%s: %s in %s defines relocations relative to a non-existing ELF "
    "section with index=%d",EF_FATAL,
  "%s: Symbol %s, defined in %s, has an invalid reference to "
    "a non-existing ELF section with index=%d",EF_FATAL,
  "%s: Illegal ELF symbol type %d for %s in %s",EF_ERROR,
  "%s: ELF symbol %s has illegal binding type %d in %s",EF_ERROR,   /* 55 */
  "%s: Symbol %s in %s is multiply defined (first occurence in %s)",EF_ERROR,
  "%s: Merging a code section with name \"__MERGED\"",EF_WARNING,
  "Relative references between %s section \"%s\" and %s section "
    "\"%s\" (%s) force a combination of the two",EF_WARNING,
  "Can't define %s as section label. Symbol already exists.",EF_ERROR,
  "%s: ELF section header type %d in %s is not needed in "          /* 60 */
    "shared objects",EF_WARNING,
  "%s: Endianess differs from previous objects",EF_FATAL,
};


void error(int errn,...)
/* prints errors and warnings */
{
  struct GlobalVars *gv = &gvars;
  va_list vl;
  char *errtype;
  int flags = errors[errn].flags;

  if ((flags == EF_WARNING) && gv->dontwarn)
    return;
  switch(flags) {
    case EF_WARNING:
      errtype = "Warning";
      break;
    case EF_ERROR:
      gv->returncode = EXIT_FAILURE;
      errtype = "Error";
      break;
    case EF_FATAL:
      gv->returncode = EXIT_FAILURE;
      errtype = "Fatal error";
      break;
    default:
      ierror("Illegal error type %d",flags);
      gv->returncode = EXIT_FAILURE;
      errtype = "";
      break;
  }

  /* print error message */
  fprintf(stderr,"%s %d: ",errtype,errn);
  va_start(vl,errn);
  vfprintf(stderr,errors[errn].txt,vl);
  va_end(vl);
  fprintf(stderr,".\n");

  switch(flags) {
    case EF_ERROR:
      /* check if maximum number of errors reached */
      if (++gv->errcnt >= gv->maxerrors) {
        gv->errcnt = 0;
        fprintf(stdout,"Do you want to continue (y/n) ? ");
        fflush(stdin);
        if (toupper((unsigned char)getchar()) == 'N')
          cleanup(gv);
      }
      /* avoid writing of output file in error case */
      gv->errflag = TRUE;
      break;
    case EF_FATAL:
      fprintf(stderr,"Aborting.\n");  /* fatal error aborts the linker */
      cleanup(gv);
      break;
  }
}


void ierror(char *errtxt,...)
/* display internal error and quit */
{
  struct GlobalVars *gv = &gvars;
  va_list vl;

  fprintf(stderr,"\nINTERNAL ERROR: ");
  va_start(vl,errtxt);
  vfprintf(stderr,errtxt,vl);
  va_end(vl);
  fprintf(stderr,".\nAborting.\n");
  cleanup(gv);
}
