/* asmerr.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Error Message Writing                                                     */
/*                                                                           */
/*****************************************************************************/


#include "stdinc.h"
#include <string.h>
#include <ctype.h>
#include <stdarg.h>

#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "console.h"
#include "strutil.h"
#include "nlmessages.h"
#include "stdhandl.h"
#include "as.h"
#include "as.rsc"
#include "ioerrs.h"
#include "cmdarg.h"
#include "asmallg.h"
#include "asmerr.h"

typedef struct sExpectError
{
  struct sExpectError *pNext;
  tErrorNum Num;
} tExpectError;

Word ErrorCount, WarnCount;
static tExpectError *pExpectErrors = NULL;
static Boolean InExpect = False;
static Boolean treat_warnings_as_errors,
               warn_sign_extension,
               def_warn_relative,
               def_warn_relative_set,
               warn_relative;

static unsigned warn_registered;

static void ClearExpectErrors(void)
{
  tExpectError *pOld;

  while (pExpectErrors)
  {
    pOld = pExpectErrors;
    pExpectErrors = pExpectErrors->pNext;
    free(pOld);
  }
}

static void AddExpectError(tExpectError *pExpectError)
{
  pExpectError->pNext = pExpectErrors;
  pExpectErrors = pExpectError;
}

/*!------------------------------------------------------------------------
 * \fn     FindAndTakeExpectError(tErrorNum Num)
 * \brief  check whether a certain error was expected
 * \param  Num number of error message that was expected
 * \return True if ther was an expectation
 * ------------------------------------------------------------------------ */

Boolean FindAndTakeExpectError(tErrorNum Num)
{
  tExpectError *pRun, *pPrev;

  for (pRun = pExpectErrors, pPrev = NULL; pRun; pPrev = pRun, pRun = pRun->pNext)
    if (Num == pRun->Num)
    {
      if (pPrev)
        pPrev->pNext = pRun->pNext;
      else
        pExpectErrors = pRun->pNext;
      free(pRun);
      return True;
    }
  return False;
}

/*!------------------------------------------------------------------------
 * \fn     registered_test_and_set(unsigned mask)
 * \brief  check whether on/off insn is registered first time during pass
 * \param  mask insn to test
 * \return mask if first time, otherwise 0
 * ------------------------------------------------------------------------ */

enum
{
  e_onoff_reg_warn_relative = 1 << 0
};

static unsigned registered_test_and_set(unsigned mask)
{
  unsigned curr = warn_registered;
  warn_registered |= mask;
  return curr & mask;
}

/*!------------------------------------------------------------------------
 * \fn     asmerr_warn_relative_add(Boolean def_value)
 * \brief  register on/off command to warn about possible relative jump
 * \param  def_value to set as default
 * ------------------------------------------------------------------------ */

#define WarnRelativeCmdName "WARNRELATIVE"
#define WarnRelativeSymName "WARNRELATIVE"

void asmerr_warn_relative_add(void)
{
  if (!registered_test_and_set(e_onoff_reg_warn_relative))
    SetFlag(&warn_relative, WarnRelativeSymName, def_warn_relative_set ? def_warn_relative : False);
  AddONOFF(WarnRelativeCmdName, &warn_relative, WarnRelativeSymName, False);
}

/*!------------------------------------------------------------------------
 * \fn     GenLineMarker(char *pDest, unsigned DestSize, char Marker, const struct sLineComp *pLineComp, * const char *pPrefix)
 * \brief  print a line, optionally with a marking of a component below
 * \param  pDest where to write
 * \param  DestSize destination buffer size
 * \param  Marker character to use for marking
 * \param  pLineComp position and length of optional marker
 * \param  pPrefix what to print before (under)line
 * ------------------------------------------------------------------------ */

static void GenLineMarker(char *pDest, unsigned DestSize, char Marker, const struct sLineComp *pLineComp, const char *pPrefix)
{
  char *pRun;
  int z;

  strmaxcpy(pDest, pPrefix, DestSize);
  pRun = pDest + strlen(pDest);

  for (z = 0; (z < pLineComp->StartCol) && (pRun - pDest + 1 < (int)DestSize); z++)
    *pRun++ = ' ';
  for (z = 0; (z < (int)pLineComp->Len) && (pRun - pDest + 1 < (int)DestSize); z++)
    *pRun++ = Marker;
  *pRun = '\0';
}

/*!------------------------------------------------------------------------
 * \fn     GenLineForMarking(char *pDest, unsigned DestSize, const char *pSrc, const char *pPrefix)
 * \brief  generate a line, in compressed form for optional marking of a component below
 * \param  pDest where to write
 * \param  DestSize destination buffer size
 * \param  pSrc line to print/underline
 * \param  pPrefix what to print before (under)line
 * ------------------------------------------------------------------------ */

static void GenLineForMarking(char *pDest, unsigned DestSize, const char *pSrc, const char *pPrefix)
{
  char *pRun;

  strmaxcpy(pDest, pPrefix, DestSize);
  pRun = pDest + strlen(pDest);

  /* replace TABs in line with spaces - column counting counts TAB as one character */

  for (; *pSrc && (pRun - pDest + 1 < (int)DestSize); pSrc++)
    *pRun++ = TabCompressed(*pSrc);
  *pRun = '\0';
}

/*!------------------------------------------------------------------------
 * \fn     EmergencyStop(void)
 * \brief  instantly stop upon fatal error
 * ------------------------------------------------------------------------ */

static void EmergencyStop(void)
{
  CloseIfOpen(&ErrorFile);
  CloseIfOpen(&LstFile);
  if (ShareMode != 0)
  {
    CloseIfOpen(&ShareFile);
    unlink(ShareName);
  }
  if (MacProOutput)
  {
    CloseIfOpen(&MacProFile);
    unlink(MacProName);
  }
  if (MacroOutput)
  {
    CloseIfOpen(&MacroFile);
    unlink(MacroName);
  }
  if (MakeDebug)
    CloseIfOpen(&Debug);
  if (CodeOutput)
  {
    CloseIfOpen(&PrgFile);
    unlink(OutName);
  }
}

/*!------------------------------------------------------------------------
 * \fn     ErrorNum2String(tErrorNum Num, char Buf, int BufSize)
 * \brief  convert error # to string
 * \param  Num numeric error
 * \param  Buf buffer for complex messages
 * \param  BufSize capacity of Buf
 * \return * to message
 * ------------------------------------------------------------------------ */

static const char *ErrorNum2String(tErrorNum Num, char *Buf, int BufSize)
{
  int msgno = -1;

  *Buf = '\0';
  switch (Num)
  {
    case ErrNum_UselessDisp:
      msgno = Num_ErrMsgUselessDisp; break;
    case ErrNum_ShortAddrPossible:
      msgno = Num_ErrMsgShortAddrPossible; break;
    case ErrNum_ShortJumpPossible:
      msgno = Num_ErrMsgShortJumpPossible; break;
    case ErrNum_RelJumpPossible:
      msgno = Num_ErrMsgRelJumpPossible; break;
    case ErrNum_NoShareFile:
      msgno = Num_ErrMsgNoShareFile; break;
    case ErrNum_BigDecFloat:
      msgno = Num_ErrMsgBigDecFloat; break;
    case ErrNum_PrivOrder:
      msgno = Num_ErrMsgPrivOrder; break;
    case ErrNum_DistNull:
      msgno = Num_ErrMsgDistNull; break;
    case ErrNum_WrongSegment:
      msgno = Num_ErrMsgWrongSegment; break;
    case ErrNum_InAccSegment:
      msgno = Num_ErrMsgInAccSegment; break;
    case ErrNum_PhaseErr:
      msgno = Num_ErrMsgPhaseErr; break;
    case ErrNum_Overlap:
      msgno = Num_ErrMsgOverlap; break;
    case ErrNum_OverlapReg:
      msgno = Num_ErrMsgOverlapReg; break;
    case ErrNum_NoCaseHit:
      msgno = Num_ErrMsgNoCaseHit; break;
    case ErrNum_InAccPage:
      msgno = Num_ErrMsgInAccPage; break;
    case ErrNum_RMustBeEven:
      msgno = Num_ErrMsgRMustBeEven; break;
    case ErrNum_Obsolete:
      msgno = Num_ErrMsgObsolete; break;
    case ErrNum_Unpredictable:
      msgno = Num_ErrMsgUnpredictable; break;
    case ErrNum_AlphaNoSense:
      msgno = Num_ErrMsgAlphaNoSense; break;
    case ErrNum_Senseless:
      msgno = Num_ErrMsgSenseless; break;
    case ErrNum_RepassUnknown:
      msgno = Num_ErrMsgRepassUnknown; break;
    case  ErrNum_AddrNotAligned:
      msgno = Num_ErrMsgAddrNotAligned; break;
    case ErrNum_IOAddrNotAllowed:
      msgno = Num_ErrMsgIOAddrNotAllowed; break;
    case ErrNum_Pipeline:
      msgno = Num_ErrMsgPipeline; break;
    case ErrNum_DoubleAdrRegUse:
      msgno = Num_ErrMsgDoubleAdrRegUse; break;
    case ErrNum_NotBitAddressable:
      msgno = Num_ErrMsgNotBitAddressable; break;
    case ErrNum_StackNotEmpty:
      msgno = Num_ErrMsgStackNotEmpty; break;
    case ErrNum_NULCharacter:
      msgno = Num_ErrMsgNULCharacter; break;
    case ErrNum_PageCrossing:
      msgno = Num_ErrMsgPageCrossing; break;
    case ErrNum_WUnderRange:
      msgno = Num_ErrMsgWUnderRange; break;
    case ErrNum_WOverRange:
      msgno = Num_ErrMsgWOverRange; break;
    case ErrNum_NegDUP:
      msgno = Num_ErrMsgNegDUP; break;
    case ErrNum_ConvIndX:
      msgno = Num_ErrMsgConvIndX; break;
    case ErrNum_NullResMem:
      msgno = Num_ErrMsgNullResMem; break;
    case ErrNum_BitNumberTruncated:
      msgno = Num_ErrMsgBitNumberTruncated; break;
    case ErrNum_InvRegisterPointer:
      msgno = Num_ErrMsgInvRegisterPointer; break;
    case ErrNum_MacArgRedef:
      msgno = Num_ErrMsgMacArgRedef; break;
    case ErrNum_Deprecated:
      msgno = Num_ErrMsgDeprecated; break;
    case ErrNum_SrcLEThanDest:
      msgno = Num_ErrMsgSrcLEThanDest; break;
    case ErrNum_TrapValidInstruction:
      msgno = Num_ErrMsgTrapValidInstruction; break;
    case ErrNum_PaddingAdded:
      msgno = Num_ErrMsgPaddingAdded; break;
    case ErrNum_RegNumWraparound:
      msgno = Num_ErrMsgRegNumWraparound; break;
    case ErrNum_IndexedForIndirect:
      msgno = Num_ErrMsgIndexedForIndirect; break;
    case ErrNum_NotInNormalMode:
      msgno = Num_ErrMsgNotInNormalMode; break;
    case ErrNum_NotInPanelMode:
      msgno = Num_ErrMsgNotInPanelMode; break;
    case ErrNum_ArgOutOfRange:
      msgno = Num_ErrMsgArgOutOfRange; break;
    case ErrNum_TrySkipMultiwordInstruction:
      msgno = Num_ErrMsgTrySkipMultiwordInstruction; break;
    case ErrNum_SignExtension:
      msgno = Num_ErrMsgSignExtension; break;
    case ErrNum_MeansE:
      msgno = Num_ErrMsgMeansE; break;
    case ErrNum_NeedShortIO:
      msgno = Num_ErrMsgNeedShortIO; break;
    case ErrNum_CaseWrongArgCnt:
      msgno = Num_ErrMsgCaseWrongArgCnt; break;
    case ErrNum_ReplacedByNOP:
      msgno = Num_ErrMsgReplacedByNOP; break;
    case ErrNum_TreatedAsVector:
      msgno = Num_ErrMsgTreatedAsVector; break;
    case ErrNum_LargeIntAsFloat:
      msgno = Num_ErrMsgLargeIntAsFloat; break;
    case ErrNum_CodeNotInCodeSegment:
      msgno = Num_ErrMsgCodeNotInCodeSegment; break;
    case ErrNum_WillOverwriteSP:
      msgno = Num_ErrMsgWillOverwriteSP; break;
    case ErrNum_DoubleDef:
      msgno = Num_ErrMsgDoubleDef; break;
    case ErrNum_SymbolUndef:
      msgno = Num_ErrMsgSymbolUndef; break;
    case ErrNum_InvSymName:
      msgno = Num_ErrMsgInvSymName; break;
    case ErrNum_RsvdSymName:
      msgno = Num_ErrMsgRsvdSymName; break;
    case ErrNum_InvFormat:
      msgno = Num_ErrMsgInvFormat; break;
    case ErrNum_UseLessAttr:
      msgno = Num_ErrMsgUseLessAttr; break;
    case ErrNum_TooLongAttr:
      msgno = Num_ErrMsgTooLongAttr; break;
    case ErrNum_UndefAttr:
      msgno = Num_ErrMsgUndefAttr; break;
    case ErrNum_WrongArgCnt:
      msgno = Num_ErrMsgWrongArgCnt; break;
    case ErrNum_CannotSplitArg:
      msgno = Num_ErrMsgCannotSplitArg; break;
    case ErrNum_WrongOptCnt:
      msgno = Num_ErrMsgWrongOptCnt; break;
    case ErrNum_UnknownOption:
      msgno = Num_ErrMsgUnknownOption; break;
    case ErrNum_DuplicateOption:
      msgno = Num_ErrMsgDuplicateOption; break;
    case ErrNum_WrongOptionList:
      msgno = Num_ErrMsgWrongOptionList; break;
    case ErrNum_OnlyImmAddr:
      msgno = Num_ErrMsgOnlyImmAddr; break;
    case ErrNum_InvOpSize:
      msgno = Num_ErrMsgInvOpSize; break;
    case ErrNum_ConfOpSizes:
      msgno = Num_ErrMsgConfOpSizes; break;
    case ErrNum_UndefOpSizes:
      msgno = Num_ErrMsgUndefOpSizes; break;
    case ErrNum_StringOrIntButFloat:
      msgno = Num_ErrMsgStringOrIntButFloat; break;
    case ErrNum_IntButFloat:
      msgno = Num_ErrMsgIntButFloat; break;
    case ErrNum_FloatButString:
      msgno = Num_ErrMsgFloatButString; break;
    case ErrNum_OpTypeMismatch:
      msgno = Num_ErrMsgOpTypeMismatch; break;
    case ErrNum_StringButInt:
      msgno = Num_ErrMsgStringButInt; break;
    case ErrNum_StringButFloat:
      msgno = Num_ErrMsgStringButFloat; break;
    case ErrNum_TooManyArgs:
      msgno = Num_ErrMsgTooManyArgs; break;
    case ErrNum_IntButString:
      msgno = Num_ErrMsgIntButString; break;
    case ErrNum_IntOrFloatButString:
      msgno = Num_ErrMsgIntOrFloatButString; break;
    case ErrNum_ExpectString:
      msgno = Num_ErrMsgExpectString; break;
    case ErrNum_ExpectInt:
      msgno = Num_ErrMsgExpectInt; break;
    case ErrNum_StringOrIntOrFloatButReg:
      msgno = Num_ErrMsgStringOrIntOrFloatButReg; break;
    case ErrNum_ExpectIntOrString:
      msgno = Num_ErrMsgExpectIntOrString; break;
    case ErrNum_ExpectReg:
      msgno = Num_ErrMsgExpectReg; break;
    case ErrNum_RegWrongTarget:
      msgno = Num_ErrMsgRegWrongTarget; break;
    case ErrNum_FloatButInt:
      msgno = Num_ErrMsgFloatButInt; break;
    case ErrNum_NoRelocs:
      msgno = Num_ErrMsgNoRelocs; break;
    case ErrNum_IntOrFloatButReg:
      msgno = Num_ErrMsgIntOrFloatButReg; break;
    case ErrNum_IntOrStringButReg:
      msgno = Num_ErrMsgIntOrStringButReg; break;
    case ErrNum_StringTooLong:
      msgno = Num_ErrMsgStringTooLong; break;
    case ErrNum_IntButReg:
      msgno = Num_ErrMsgIntButReg; break;
    case ErrNum_UnresRelocs:
      msgno = Num_ErrMsgUnresRelocs; break;
    case ErrNum_Unexportable:
      msgno = Num_ErrMsgUnexportable; break;
    case ErrNum_UnknownInstruction:
      msgno = Num_ErrMsgUnknownInstruction; break;
    case ErrNum_BrackErr:
      msgno = Num_ErrMsgBrackErr; break;
    case ErrNum_DivByZero:
      msgno = Num_ErrMsgDivByZero; break;
    case ErrNum_UnderRange:
      msgno = Num_ErrMsgUnderRange; break;
    case ErrNum_OverRange:
      msgno = Num_ErrMsgOverRange; break;
    case ErrNum_NotPwr2:
      msgno = Num_ErrMsgNotPwr2; break;
    case ErrNum_InvalidDecDigit:
      msgno = Num_ErrMsgInvalidDecDigit; break;
    case ErrNum_DecStringTooLong:
      msgno = Num_ErrMsgDecStringTooLong; break;
    case ErrNum_NotAligned:
      msgno = Num_ErrMsgNotAligned; break;
    case ErrNum_DistTooBig:
      msgno = Num_ErrMsgDistTooBig; break;
    case ErrNum_TargOnDiffPage:
      msgno = Num_ErrMsgTargOnDiffPage; break;
    case ErrNum_InAccReg:
      msgno = Num_ErrMsgInAccReg; break;
    case ErrNum_NoShortAddr:
      msgno = Num_ErrMsgNoShortAddr; break;
    case ErrNum_InvAddrMode:
      msgno = Num_ErrMsgInvAddrMode; break;
    case ErrNum_AddrMustBeEven:
      msgno = Num_ErrMsgAddrMustBeEven; break;
    case ErrNum_AddrMustBeAligned:
      msgno = Num_ErrMsgAddrMustBeAligned; break;
    case ErrNum_InvParAddrMode:
      msgno = Num_ErrMsgInvParAddrMode; break;
    case ErrNum_UndefCond:
      msgno = Num_ErrMsgUndefCond; break;
    case ErrNum_IncompCond:
      msgno = Num_ErrMsgIncompCond; break;
    case ErrNum_UnknownFlag:
      msgno = Num_ErrMsgUnknownFlag; break;
    case ErrNum_DuplicateFlag:
      msgno = Num_ErrMsgDuplicateFlag; break;
    case ErrNum_UnknownInt:
      msgno = Num_ErrMsgUnknownInt; break;
    case ErrNum_DuplicateInt:
      msgno = Num_ErrMsgDuplicateInt; break;
    case ErrNum_JmpDistTooBig:
      msgno = Num_ErrMsgJmpDistTooBig; break;
    case ErrNum_JmpDistIsZero:
      msgno = Num_ErrMsgJmpDistIsZero; break;
    case ErrNum_DistIsOdd:
      msgno = Num_ErrMsgDistIsOdd; break;
    case ErrNum_SkipTargetMismatch:
      msgno = Num_ErrMsgSkipTargetMismatch; break;
    case ErrNum_InvShiftArg:
      msgno = Num_ErrMsgInvShiftArg; break;
    case ErrNum_Only1:
      msgno = Num_ErrMsgOnly1; break;
    case ErrNum_Range18:
      msgno = Num_ErrMsgRange18; break;
    case ErrNum_ShiftCntTooBig:
      msgno = Num_ErrMsgShiftCntTooBig; break;
    case ErrNum_InvRegList:
      msgno = Num_ErrMsgInvRegList; break;
    case ErrNum_InvCmpMode:
      msgno = Num_ErrMsgInvCmpMode; break;
    case ErrNum_InvCPUType:
      msgno = Num_ErrMsgInvCPUType; break;
    case ErrNum_InvFPUType:
      msgno = Num_ErrMsgInvFPUType; break;
    case ErrNum_InvPMMUType:
      msgno = Num_ErrMsgInvPMMUType; break;
    case ErrNum_InvProcReg:
      msgno = Num_ErrMsgInvProcReg; break;
    case ErrNum_InvBaseReg:
      msgno = Num_ErrMsgInvBaseReg; break;
    case ErrNum_InvIndexReg:
      msgno = Num_ErrMsgInvIndexReg; break;
    case ErrNum_InvCtrlReg:
      msgno = Num_ErrMsgInvCtrlReg; break;
    case ErrNum_UnknownVector:
      msgno = Num_ErrMsgUnknownVector; break;
    case ErrNum_RegAccessibleOnlyInExecMode:
      msgno = Num_ErrMsgRegAccessibleOnlyInExecMode; break;
    case ErrNum_RegReadOnlyInExecMode:
      msgno = Num_ErrMsgRegReadOnlyInExecMode; break;
    case ErrNum_InvReg:
      msgno = Num_ErrMsgInvReg; break;
    case ErrNum_DoubleReg:
      msgno = Num_ErrMsgDoubleReg; break;
    case ErrNum_RegBankMismatch:
      msgno = Num_ErrMsgRegBankMismatch; break;
    case ErrNum_UndefRegSize:
      msgno = Num_ErrMsgUndefRegSize; break;
    case ErrNum_InvOpOnReg:
      msgno = Num_ErrMsgInvOpOnReg; break;
    case ErrNum_NoSaveFrame:
      msgno = Num_ErrMsgNoSaveFrame; break;
    case ErrNum_NoRestoreFrame:
      msgno = Num_ErrMsgNoRestoreFrame; break;
    case ErrNum_UnknownMacArg:
      msgno = Num_ErrMsgUnknownMacArg; break;
    case ErrNum_MissEndif:
      msgno = Num_ErrMsgMissEndif; break;
    case ErrNum_InvIfConst:
      msgno = Num_ErrMsgInvIfConst; break;
    case ErrNum_ForwardNonCurrent:
      msgno = Num_ErrMsgForwardNonCurrent; break;
    case ErrNum_DoubleSection:
      msgno = Num_ErrMsgDoubleSection; break;
    case ErrNum_InvSection:
      msgno = Num_ErrMsgInvSection; break;
    case ErrNum_MissingEndSect:
      msgno = Num_ErrMsgMissingEndSect; break;
    case ErrNum_WrongEndSect:
      msgno = Num_ErrMsgWrongEndSect; break;
    case ErrNum_NotInSection:
      msgno = Num_ErrMsgNotInSection; break;
    case ErrNum_UndefdForward:
      msgno = Num_ErrMsgUndefdForward; break;
    case ErrNum_ContForward:
      msgno = Num_ErrMsgContForward; break;
    case ErrNum_InvFuncArgCnt:
      msgno = Num_ErrMsgInvFuncArgCnt; break;
    case ErrNum_DupFuncArgName:
      msgno = Num_ErrMsgDupFuncArgName; break;
    case ErrNum_MsgMissingLTORG:
      msgno = Num_ErrMsgMissingLTORG; break;
    case ErrNum_InstructionNotSupported:
      as_snprintf(Buf, BufSize, getmessage(Num_ErrMsgInstructionNotOnThisCPUSupported), MomCPUIdent);
      break;
    case ErrNum_FPUNotEnabled:
      msgno = Num_ErrMsgFPUNotEnabled; break;
    case ErrNum_PMMUNotEnabled:
      msgno = Num_ErrMsgPMMUNotEnabled; break;
    case ErrNum_FullPMMUNotEnabled:
      msgno = Num_ErrMsgFullPMMUNotEnabled; break;
    case ErrNum_Z80SyntaxNotEnabled:
      msgno = Num_ErrMsgZ80SyntaxNotEnabled; break;
    case ErrNum_Z80SyntaxExclusive:
      msgno = Num_ErrMsgZ80SyntaxExclusive; break;
    case ErrNum_FPUInstructionNotSupported:
      as_snprintf(Buf, BufSize, getmessage(Num_ErrMsgInstructionNotOnThisFPUSupported), MomFPUIdent);
      break;
    case ErrNum_AddrModeNotSupported:
      as_snprintf(Buf, BufSize, getmessage(Num_ErrMsgAddrModeNotOnThisCPUSupported), MomCPUIdent);
      break;
    case ErrNum_CustomNotEnabled:
      msgno = Num_ErrMsgCustomNotEnabled; break;
    case ErrNum_InvBitPos:
      msgno = Num_ErrMsgInvBitPos; break;
    case ErrNum_OnlyOnOff:
      msgno = Num_ErrMsgOnlyOnOff; break;
    case ErrNum_InvListingValue:
      msgno = Num_ErrMsgInvListingValue; break;
    case ErrNum_StackEmpty:
      msgno = Num_ErrMsgStackEmpty; break;
    case ErrNum_NotOneBit:
      msgno = Num_ErrMsgNotOneBit; break;
    case ErrNum_MissingStruct:
      msgno = Num_ErrMsgMissingStruct; break;
    case ErrNum_OpenStruct:
      msgno = Num_ErrMsgOpenStruct; break;
    case ErrNum_WrongStruct:
      msgno = Num_ErrMsgWrongStruct; break;
    case ErrNum_PhaseDisallowed:
      msgno = Num_ErrMsgPhaseDisallowed; break;
    case ErrNum_InvStructDir:
      msgno = Num_ErrMsgInvStructDir; break;
    case ErrNum_DoubleStruct:
      msgno = Num_ErrMsgDoubleStruct; break;
    case ErrNum_UnresolvedStructRef:
      msgno = Num_ErrMsgUnresolvedStructRef; break;
    case ErrNum_DuplicateStructElem:
      msgno = Num_ErrMsgDuplicateStructElem; break;
    case ErrNum_NotRepeatable:
      msgno = Num_ErrMsgNotRepeatable; break;
    case ErrNum_ShortRead:
      msgno = Num_ErrMsgShortRead; break;
    case ErrNum_UnknownCodepage:
      msgno = Num_ErrMsgUnknownCodepage; break;
    case ErrNum_RomOffs063:
      msgno = Num_ErrMsgRomOffs063; break;
    case ErrNum_InvFCode:
      msgno = Num_ErrMsgInvFCode; break;
    case ErrNum_InvFMask:
      msgno = Num_ErrMsgInvFMask; break;
    case ErrNum_InvMMUReg:
      msgno = Num_ErrMsgInvMMUReg; break;
    case ErrNum_Level07:
      msgno = Num_ErrMsgLevel07; break;
    case ErrNum_InvBitMask:
      msgno = Num_ErrMsgInvBitMask; break;
    case ErrNum_InvRegPair:
      msgno = Num_ErrMsgInvRegPair; break;
    case ErrNum_OpenMacro:
      msgno = Num_ErrMsgOpenMacro; break;
    case ErrNum_OpenIRP:
      msgno = Num_ErrMsgOpenIRP; break;
    case ErrNum_OpenIRPC:
      msgno = Num_ErrMsgOpenIRPC; break;
    case ErrNum_OpenREPT:
      msgno = Num_ErrMsgOpenREPT; break;
    case ErrNum_OpenWHILE:
      msgno = Num_ErrMsgOpenWHILE; break;
    case ErrNum_EXITMOutsideMacro:
      msgno = Num_ErrMsgEXITMOutsideMacro; break;
    case ErrNum_ENDMOutsideMacro:
      msgno = Num_ErrMsgENDMOutsideMacro; break;
    case ErrNum_TooManyMacParams:
      msgno = Num_ErrMsgTooManyMacParams; break;
    case ErrNum_UndefKeyArg:
      msgno = Num_ErrMsgUndefKeyArg; break;
    case ErrNum_NoPosArg:
      msgno = Num_ErrMsgNoPosArg; break;
    case ErrNum_DoubleMacro:
      msgno = Num_ErrMsgDoubleMacro; break;
    case ErrNum_FirstPassCalc:
      msgno = Num_ErrMsgFirstPassCalc; break;
    case ErrNum_TooManyNestedIfs:
      msgno = Num_ErrMsgTooManyNestedIfs; break;
    case ErrNum_MissingIf:
      msgno = Num_ErrMsgMissingIf; break;
    case ErrNum_RekMacro:
      msgno = Num_ErrMsgRekMacro; break;
    case ErrNum_UnknownFunc:
      msgno = Num_ErrMsgUnknownFunc; break;
    case ErrNum_InvFuncArg:
      msgno = Num_ErrMsgInvFuncArg; break;
    case ErrNum_FloatOverflow:
      msgno = Num_ErrMsgFloatOverflow; break;
    case ErrNum_InvArgPair:
      msgno = Num_ErrMsgInvArgPair; break;
    case ErrNum_NotOnThisAddress:
      msgno = Num_ErrMsgNotOnThisAddress; break;
    case ErrNum_NotFromThisAddress:
      msgno = Num_ErrMsgNotFromThisAddress; break;
    case ErrNum_JmpTargOnDiffPage:
      msgno = Num_ErrMsgJmpTargOnDiffPage; break;
    case ErrNum_TargOnDiffSection:
      msgno = Num_ErrMsgTargOnDiffSection; break;
    case ErrNum_CodeOverflow:
      msgno = Num_ErrMsgCodeOverflow; break;
    case ErrNum_AdrOverflow:
      msgno = Num_ErrMsgAdrOverflow; break;
    case ErrNum_MixDBDS:
      msgno = Num_ErrMsgMixDBDS; break;
    case ErrNum_NotInStruct:
      msgno = Num_ErrMsgNotInStruct; break;
    case ErrNum_ParNotPossible:
      msgno = Num_ErrMsgParNotPossible; break;
    case ErrNum_InvSegment:
      msgno = Num_ErrMsgInvSegment; break;
    case ErrNum_UnknownSegment:
      msgno = Num_ErrMsgUnknownSegment; break;
    case ErrNum_UnknownSegReg:
      msgno = Num_ErrMsgUnknownSegReg; break;
    case ErrNum_InvString:
      msgno = Num_ErrMsgInvString; break;
    case ErrNum_InvRegName:
      msgno = Num_ErrMsgInvRegName; break;
    case ErrNum_InvArg:
      msgno = Num_ErrMsgInvArg; break;
    case ErrNum_NoIndir:
      msgno = Num_ErrMsgNoIndir; break;
    case ErrNum_NotInThisSegment:
      msgno = Num_ErrMsgNotInThisSegment; break;
    case ErrNum_NotInMaxmode:
      msgno = Num_ErrMsgNotInMaxmode; break;
    case ErrNum_OnlyInMaxmode:
      msgno = Num_ErrMsgOnlyInMaxmode; break;
    case ErrNum_PackCrossBoundary:
      msgno = Num_ErrMsgPackCrossBoundary; break;
    case ErrNum_UnitMultipleUsed:
      msgno = Num_ErrMsgUnitMultipleUsed; break;
    case ErrNum_MultipleLongRead:
      msgno = Num_ErrMsgMultipleLongRead; break;
    case ErrNum_MultipleLongWrite:
      msgno = Num_ErrMsgMultipleLongWrite; break;
    case ErrNum_LongReadWithStore:
      msgno = Num_ErrMsgLongReadWithStore; break;
    case ErrNum_TooManyRegisterReads:
      msgno = Num_ErrMsgTooManyRegisterReads; break;
    case ErrNum_OverlapDests:
      msgno = Num_ErrMsgOverlapDests; break;
    case ErrNum_TooManyBranchesInExPacket:
      msgno = Num_ErrMsgTooManyBranchesInExPacket; break;
    case ErrNum_CannotUseUnit:
      msgno = Num_ErrMsgCannotUseUnit; break;
    case ErrNum_InvEscSequence:
      msgno = Num_ErrMsgInvEscSequence; break;
    case ErrNum_InvPrefixCombination:
      msgno = Num_ErrMsgInvPrefixCombination; break;
    case ErrNum_ConstantRedefinedAsVariable:
      msgno = Num_ErrMsgConstantRedefinedAsVariable; break;
    case ErrNum_VariableRedefinedAsConstant:
      msgno = Num_ErrMsgVariableRedefinedAsConstant; break;
    case ErrNum_StructNameMissing:
      msgno = Num_ErrMsgStructNameMissing; break;
    case ErrNum_EmptyArgument:
      msgno = Num_ErrMsgEmptyArgument; break;
    case ErrNum_Unimplemented:
      msgno = Num_ErrMsgUnimplemented; break;
    case ErrNum_FreestandingUnnamedStruct:
      msgno = Num_ErrMsgFreestandingUnnamedStruct; break;
    case ErrNum_STRUCTEndedByENDUNION:
      msgno = Num_ErrMsgSTRUCTEndedByENDUNION; break;
    case ErrNum_AddrOnDifferentPage:
      msgno = Num_ErrMsgAddrOnDifferentPage; break;
    case ErrNum_UnknownMacExpMod:
      msgno = Num_ErrMsgUnknownMacExpMod; break;
    case ErrNum_TooManyMacExpMod:
      msgno = Num_ErrMsgTooManyMacExpMod; break;
    case ErrNum_ConflictingMacExpMod:
      msgno = Num_ErrMsgConflictingMacExpMod; break;
    case ErrNum_InvalidPrepDir:
      msgno = Num_ErrMsgInvalidPrepDir; break;
    case ErrNum_ExpectedError:
      msgno = Num_ErrMsgExpectedError; break;
    case ErrNum_NoNestExpect:
      msgno = Num_ErrMsgNoNestExpect; break;
    case ErrNum_MissingENDEXPECT:
      msgno = Num_ErrMsgMissingENDEXPECT; break;
    case ErrNum_MissingEXPECT:
      msgno = Num_ErrMsgMissingEXPECT; break;
    case ErrNum_NoDefCkptReg:
      msgno = Num_ErrMsgNoDefCkptReg; break;
    case ErrNum_InvBitField:
      msgno = Num_ErrMsgInvBitField; break;
    case ErrNum_ArgValueMissing:
      msgno = Num_ErrMsgArgValueMissing; break;
    case ErrNum_UnknownArg:
      msgno = Num_ErrMsgUnknownArg; break;
    case ErrNum_IndexRegMustBe16Bit:
      msgno = Num_ErrMsgIndexRegMustBe16Bit; break;
    case ErrNum_IOAddrRegMustBe16Bit:
      msgno = Num_ErrMsgIOAddrRegMustBe16Bit; break;
    case ErrNum_SegAddrRegMustBe32Bit:
      msgno = Num_ErrMsgSegAddrRegMustBe32Bit; break;
    case ErrNum_NonSegAddrRegMustBe16Bit:
      msgno = Num_ErrMsgNonSegAddrRegMustBe16Bit; break;
    case ErrNum_InvStructArgument:
      msgno = Num_ErrMsgInvStructArgument; break;
    case ErrNum_TooManyArrayDimensions:
      msgno = Num_ErrMsgTooManyArrayDimensions; break;
    case ErrNum_InvIntFormat:
      msgno = Num_ErrMsgInvIntFormat; break;
    case ErrNum_InvIntFormatList:
      msgno = Num_ErrMsgInvIntFormatList; break;
    case ErrNum_InvScale:
      msgno = Num_ErrMsgInvScale; break;
    case ErrNum_ConfStringOpt:
      msgno = Num_ErrMsgConfStringOpt; break;
    case ErrNum_UnknownStringOpt:
      msgno = Num_ErrMsgUnknownStringOpt; break;
    case ErrNum_InvCacheInvMode:
      msgno = Num_ErrMsgInvCacheInvMode; break;
    case ErrNum_InvCfgList:
      msgno = Num_ErrMsgInvCfgList; break;
    case ErrNum_ConfBitBltOpt:
      msgno = Num_ErrMsgConfBitBltOpt; break;
    case ErrNum_UnknownBitBltOpt:
      msgno = Num_ErrMsgUnknownBitBltOpt; break;
    case ErrNum_InvCBAR:
      msgno = Num_ErrMsgInvCBAR; break;
    case ErrNum_InAccPageErr:
      msgno = Num_ErrMsgInAccPageErr; break;
    case ErrNum_CurrPCInInAccPageErr:
      msgno = Num_ErrMsgCurrPCInInAccPageErr; break;
    case ErrNum_InAccFieldErr:
      msgno = Num_ErrMsgInAccFieldErr; break;
    case ErrNum_TargInDiffField:
      msgno = Num_ErrMsgTargInDiffField; break;
    case ErrNum_InvCombination:
      msgno = Num_ErrMsgInvCombination; break;
    case ErrNum_UnmappedChar:
      msgno = Num_ErrMsgUnmappedChar; break;
    case ErrNum_NoTarget:
      msgno = Num_ErrMsgNoTarget; break;
    case ErrNum_MultiCharInvLength:
      msgno = Num_ErrMsgMultiCharInvLength; break;
    case ErrNum_InvDispLen:
      msgno = Num_ErrMsgInvDispLen; break;
    case ErrNum_InternalError:
      msgno = Num_ErrMsgInternalError; break;
    case ErrNum_OpeningFile:
      msgno = Num_ErrMsgOpeningFile; break;
    case ErrNum_ListWrError:
      msgno = Num_ErrMsgListWrError; break;
    case ErrNum_FileReadError:
      msgno = Num_ErrMsgFileReadError; break;
    case ErrNum_FileWriteError:
      msgno = Num_ErrMsgFileWriteError; break;
    case ErrNum_HeapOvfl:
      msgno = Num_ErrMsgHeapOvfl; break;
    case ErrNum_StackOvfl:
      msgno = Num_ErrMsgStackOvfl; break;
    case ErrNum_MaxIncLevelExceeded:
      msgno = Num_ErrMsgMaxIncLevelExceeded; break;
    case ErrNum_InvListHeadFormat:
      msgno = Num_ErrMsgInvListHeadFormat; break;
    case ErrNum_ListHeadFormatElemTooOften:
      msgno = Num_ErrMsgListHeadFormatElemTooOften; break;
    default:
      as_snprintf(Buf, BufSize, "%s %d", getmessage(Num_ErrMsgIntError), (int) Num);
  }
  return (msgno != -1) ? getmessage(msgno) : Buf;
}

/*!------------------------------------------------------------------------
 * \fn     WrErrorString(const char *pMessage, const char *pAdd, Boolean Warning, Boolean Fatal,
                         const char *pExtendError, const struct sLineComp *pLineComp)
 * \brief  write error message, combined with string component of current src line
 * \param  pMessage textual error message
 * \param  Warning error is warning?
 * \param  Fatal error is fatal?
 * \param  pExtendError extended error explanation
 * \param  pLineComp associated string component
 * ------------------------------------------------------------------------ */

void WrErrorString(const char *pMessage, const char *pAdd, Boolean Warning, Boolean Fatal,
                   const char *pExtendError, const struct sLineComp *pLineComp)
{
  String ErrStr[4];
  unsigned ErrStrCount = 0, z;
  char *p;
  int l;
  const char *pLeadIn = GNUErrors ? "" : "> > > ";
  FILE *pErrFile;
  Boolean ErrorsWrittenToListing = False;

  if (treat_warnings_as_errors && Warning && !Fatal)
    Warning = False;

  strcpy(ErrStr[ErrStrCount], pLeadIn);
  p = GetErrorPos();
  if (p)
  {
    l = strlen(p) - 1;
    if ((l >= 0) && (p[l] == ' '))
      p[l] = '\0';
    strmaxcat(ErrStr[ErrStrCount], p, STRINGSIZE);
    free(p);
  }
  if (pLineComp)
  {
    char Num[20];

    as_snprintf(Num, sizeof(Num), ":%d", pLineComp->StartCol + 1);
    strmaxcat(ErrStr[ErrStrCount], Num, STRINGSIZE);
  }
  if (Warning || !GNUErrors)
  {
    strmaxcat(ErrStr[ErrStrCount], ": ", STRINGSIZE);
    strmaxcat(ErrStr[ErrStrCount], getmessage(Warning ? Num_WarnName : Num_ErrName), STRINGSIZE);
  }
  strmaxcat(ErrStr[ErrStrCount], pAdd, STRINGSIZE);
  strmaxcat(ErrStr[ErrStrCount], ": ", STRINGSIZE);
  if (Warning)
    WarnCount++;
  else
    ErrorCount++;

  strmaxcat(ErrStr[ErrStrCount], pMessage, STRINGSIZE);
  if ((ExtendErrors > 0) && pExtendError)
  {
    if (GNUErrors)
      strmaxcat(ErrStr[ErrStrCount], " '", STRINGSIZE);
    else
      strcpy(ErrStr[++ErrStrCount], pLeadIn);
    strmaxcat(ErrStr[ErrStrCount], pExtendError, STRINGSIZE);
    if (GNUErrors)
      strmaxcat(ErrStr[ErrStrCount], "'", STRINGSIZE);
  }
  if ((ExtendErrors > 1) || ((ExtendErrors > 0) && pLineComp))
  {
    strcpy(ErrStr[++ErrStrCount], "");
    GenLineForMarking(ErrStr[ErrStrCount], STRINGSIZE, SrcLine.str.p_str, pLeadIn);
    if (pLineComp)
    {
      strcpy(ErrStr[++ErrStrCount], "");
      GenLineMarker(ErrStr[ErrStrCount], STRINGSIZE, '~', pLineComp, pLeadIn);
    }
  }

  if (strcmp(LstName, "/dev/null") && !Fatal)
  {
    for (z = 0; z <= ErrStrCount; z++)
      WrLstLine(ErrStr[z]);
    ErrorsWrittenToListing = True;
  }

  if (!ErrorFile)
    OpenWithStandard(&ErrorFile, ErrorName);
  pErrFile = ErrorFile ? ErrorFile : stdout;
  if (strcmp(LstName, "!1") || !ListOn || !ErrorsWrittenToListing)
  {
    for (z = 0; z <= ErrStrCount; z++)
      if (ErrorFile)
        fprintf(pErrFile, "%s\n", ErrStr[z]);
      else
        WrConsoleLine(ErrStr[z], True);
  }

  if (Fatal)
    fprintf(pErrFile, "%s\n", getmessage(Num_ErrMsgIsFatal));
  else if (MaxErrors && (ErrorCount >= MaxErrors))
  {
    fprintf(pErrFile, "%s\n", getmessage(Num_ErrMsgTooManyErrors));
    Fatal = True;
  }

  if (Fatal)
  {
    EmergencyStop();
    exit(3);
  }
}

/*!------------------------------------------------------------------------
 * \fn     WrXErrorPos(tErrorNum Num, const char *pExtendError, const struct sLineComp *pLineComp)
 * \brief  write number-coded error message, combined with extended explamation and string component of current src line
 * \param  Num error number
 * \param  pExtendError extended error explanation
 * \param  pLineComp associated string component
 * ------------------------------------------------------------------------ */

void WrXErrorPos(tErrorNum Num, const char *pExtendError, const struct sLineComp *pLineComp)
{
  String h;
  char Add[11];
  const char *pErrorMsg;

  /* If issuing of a certain error or warning is disabled, a program
     that expects it should trigger an error. */

  switch (Num)
  {
    case ErrNum_RelJumpPossible:
      if (!warn_relative)
        return;
      break;
    case ErrNum_SignExtension:
      if (!warn_sign_extension)
        return;
      break;
    default:
      break;
  }

  if (FindAndTakeExpectError(Num))
    return;

  if (!CodeOutput && (Num == ErrNum_UnknownInstruction))
    return;

  if (SuppWarns && (Num < 1000))
    return;

  pErrorMsg = ErrorNum2String(Num, h, sizeof(h));

  if (((Num == ErrNum_JmpTargOnDiffPage) || (Num == ErrNum_JmpDistTooBig))
   && !Repass)
    JmpErrors++;

  if (NumericErrors)
    as_snprintf(Add, sizeof(Add), " #%d", (int)Num);
  else
    *Add = '\0';
  WrErrorString(pErrorMsg, Add, Num < 1000, Num >= 10000, pExtendError, pLineComp);
}

/*!------------------------------------------------------------------------
 * \fn     WrStrErrorPos(tErrorNum Num, const const struct sLineComp *pLineComp)
 * \brief  write number-coded error message, combined with string component of current src line
 * \param  Num error number
 * \param  pStrComp associated string component
 * ------------------------------------------------------------------------ */

void WrStrErrorPos(tErrorNum Num, const struct sStrComp *pStrComp)
{
  WrXErrorPos(Num, pStrComp->str.p_str, &pStrComp->Pos);
}

/*!------------------------------------------------------------------------
 * \fn     WrError(tErrorNum Num)
 * \brief  write number-coded error message, without any explanation
 * \param  Num error number
 * ------------------------------------------------------------------------ */

void WrError(tErrorNum Num)
{
  WrXErrorPos(Num, NULL, NULL);
}

/*!------------------------------------------------------------------------
 * \fn     WrXError(tErrorNum Num, const char *pExtError)
 * \brief  write number-coded error message with extended explanation
 * \param  Num error number
 * \param  pExtendError extended error explanation
 * ------------------------------------------------------------------------ */

void WrXError(tErrorNum Num, const char *pExtError)
{
  WrXErrorPos(Num, pExtError, NULL);
}

/*!------------------------------------------------------------------------
 * \fn     void ChkIO(tErrorNum ErrNo)
 * \brief  check for I/O error and report given error if yes
 * \param  ErrNo error number to report if error occured
 * ------------------------------------------------------------------------ */

void ChkIO(tErrorNum ErrNo)
{
  int io;

  io = errno;
  if ((io == 0) || (io == 19) || (io == 25))
    return;

  WrXError(ErrNo, GetErrorMsg(io));
}

/*!------------------------------------------------------------------------
 * \fn     ChkXIO(tErrorNum ErrNo, char *pExtError)
 * \brief  check for I/O error and report given error if yes
 * \param  ErrNo error number to report if error occured
 * \param  pExtError, file name, as plain string
 * ------------------------------------------------------------------------ */

void ChkXIO(tErrorNum ErrNo, char *pExtError)
{
  tStrComp TmpComp;

  StrCompMkTemp(&TmpComp, pExtError, 0);
  ChkStrIO(ErrNo, &TmpComp);
}

/*!------------------------------------------------------------------------
 * \fn     void ChkIO(tErrorNum ErrNo)
 * \brief  check for I/O error and report given error if yes
 * \param  ErrNo error number to report if error occured
 * \param  pComp, file name, as string component with position
 * ------------------------------------------------------------------------ */

void ChkStrIO(tErrorNum ErrNo, const struct sStrComp *pComp)
{
  int io;
  String s;

  io = errno;
  if ((io == 0) || (io == 19) || (io == 25))
    return;

  as_snprintf(s, STRINGSIZE, "%s: %s", pComp->str.p_str, GetErrorMsg(io));
  if ((pComp->Pos.StartCol >= 0) || pComp->Pos.Len)
    WrXErrorPos(ErrNo, s, &pComp->Pos);
  else
    WrXError(ErrNo, s);
}

/*!------------------------------------------------------------------------
 * \fn     CodeEXPECT(Word Code)
 * \brief  process EXPECT command
 * ------------------------------------------------------------------------ */

void CodeEXPECT(Word Code)
{
  UNUSED(Code);

  if (!ChkArgCnt(1, ArgCntMax));
  else if (InExpect) WrStrErrorPos(ErrNum_NoNestExpect, &OpPart);
  else
  {
    int z;
    Boolean OK;
    tErrorNum Num;

    for (z = 1; z <= ArgCnt; z++)
    {
      tSymbolFlags flags;

      Num = (tErrorNum)EvalStrIntExpressionWithFlags(&ArgStr[z], UInt16, &OK, &flags);
      if (!OK)
        continue;
      if (mFirstPassUnknownOrQuestionable(flags))
        WrStrErrorPos(ErrNum_FirstPassCalc, &ArgStr[z]);
      else if (Num)
      {
        tExpectError *pNew = (tExpectError*)calloc(1, sizeof(*pNew));
        pNew->Num = Num;
        AddExpectError(pNew);
      }
    }
    InExpect = True;
  }
}

/*!------------------------------------------------------------------------
 * \fn     CodeENDEXPECT(Word Code)
 * \brief  process ENDEXPECT command
 * ------------------------------------------------------------------------ */

void CodeENDEXPECT(Word Code)
{
  UNUSED(Code);

  if (!ChkArgCnt(0, 0));
  else if (!InExpect) WrStrErrorPos(ErrNum_MissingEXPECT, &OpPart);
  else
  {
    tExpectError *pCurr;
    String h;

    while (pExpectErrors)
    {
      pCurr = pExpectErrors;
      pExpectErrors = pCurr->pNext;
      WrXError(ErrNum_ExpectedError, ErrorNum2String(pCurr->Num, h, sizeof(h)));
      free(pCurr);
    }
    InExpect = False;
  }
}

/*!------------------------------------------------------------------------
 * \fn     asmerr_check_fp_dispose_result(int ret, const struct sStrComp *p_arg)
 * \brief  check the result of as_float_2...and throw associated error messages
 * \param  ret return code
 * \param  p_arg associated source argument
 * ------------------------------------------------------------------------ */

Boolean asmerr_check_fp_dispose_result(int ret, const struct sStrComp *p_arg)
{
  if (ret >= 0)
    return True;
  switch (ret)
  {
    case -EIO:
      WrStrErrorPos(ErrNum_UnderRange, p_arg);
      return False;
    case -EBADF:
      WrXErrorPos(ErrNum_InvArg, "raster", &p_arg->Pos);
      return False;
    case -E2BIG:
      WrStrErrorPos(ErrNum_OverRange, p_arg);
      return False;
    case -EINVAL:
      WrXErrorPos(ErrNum_InvArg, "INF/NaN", &p_arg->Pos);
      return False;
    default:
      WrStrErrorPos(ErrNum_InvArg, p_arg);
      return False;
  }
}

/*!------------------------------------------------------------------------
 * \fn     exit_pass(void)
 * \brief  module checks & cleanups after a pass through sources
 * ------------------------------------------------------------------------ */

static void exit_pass(void)
{
  if (InExpect)
    WrError(ErrNum_MissingENDEXPECT);
  ClearExpectErrors();
  InExpect = False;
}

static as_cmd_result_t cmd_treat_warnings_as_errors(Boolean negate, const char *p_arg)
{
  UNUSED(p_arg);

  treat_warnings_as_errors = !negate;
  return e_cmd_ok;
}

static as_cmd_result_t cmd_warn_sign_extension(Boolean negate, const char *p_arg)
{
  UNUSED(p_arg);

  if (negate)
    return e_cmd_err;
  warn_sign_extension = True;
  return e_cmd_ok;
}

static as_cmd_result_t cmd_no_warn_sign_extension(Boolean negate, const char *p_arg)
{
  UNUSED(p_arg);

  if (negate)
    return e_cmd_err;
  warn_sign_extension = False;
  return e_cmd_ok;
}

static as_cmd_result_t cmd_warn_relative(Boolean negate, const char *p_arg)
{
  UNUSED(p_arg);

  if (negate)
    return e_cmd_err;
  def_warn_relative = True;
  def_warn_relative_set = True;
  return e_cmd_ok;
}

static as_cmd_result_t cmd_no_warn_relative(Boolean negate, const char *p_arg)
{
  UNUSED(p_arg);

  if (negate)
    return e_cmd_err;
  def_warn_relative = False;
  def_warn_relative_set = True;
  return e_cmd_ok;
}

static const as_cmd_rec_t cmd_params[] =
{
  { "werror"                     , cmd_treat_warnings_as_errors },
  { "wimplicit-sign-extension"   , cmd_warn_sign_extension      },
  { "wno-implicit-sign-extension", cmd_no_warn_sign_extension   },
  { "wrelative"                  , cmd_warn_relative            },
  { "wno-relative"               , cmd_no_warn_relative         }
};

/*!------------------------------------------------------------------------
 * \fn     init_pass(void)
 * \brief  called before start of each pass
 * ------------------------------------------------------------------------ */

static void init_pass(void)
{
  ErrorCount = 0;
  WarnCount = 0;
  ClearExpectErrors();
  InExpect = False;
  warn_registered = 0;
}

/*!------------------------------------------------------------------------
 * \fn     asmerr_init(void)
 * \brief  module setup
 * ------------------------------------------------------------------------ */

void asmerr_init(void)
{
  treat_warnings_as_errors = False;
  warn_sign_extension = True;
  def_warn_relative = def_warn_relative_set = False;
  as_cmd_register(cmd_params, as_array_size(cmd_params));
  AddInitPassProc(init_pass);
  add_exit_pass_proc(exit_pass);
}
