Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

/* p2hex.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Konvertierung von AS-P-Dateien nach Hex                                   */
/*                                                                           */
/*****************************************************************************/

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

#include "version.h"
#include "be_le.h"
#include "bpemu.h"
#include "nls.h"
#include "nlmessages.h"
#include "p2hex.rsc"
#ifdef _USE_MSH
# include "p2hex.msh"
#endif
#include "ioerrs.h"
#include "strutil.h"
#include "chunks.h"
#include "stringlists.h"
#include "msg_level.h"
#include "cmdarg.h"

#include "toolutils.h"
#include "headids.h"

static const char *HexSuffix = ".hex";
#define MaxLineLen 254
#define AVRLEN_DEFAULT 3
#define DefaultCFormat "dSEl"

typedef void (*ProcessProc)(
#ifdef __PROTOS__
const char *FileName, LongWord Offset
#endif
);

static FILE *TargFile;
static String TargName, CFormat;
static Byte ForceSegment;

static LongWord StartAdr[SegCount], StopAdr[SegCount], LineLen, EntryAdr;
static LargeInt Relocate;
static Boolean StartAuto, StopAuto, AutoErase, EntryAdrPresent;
static Word Seg, Ofs;
static LongWord Dummy;
static Byte IntelMode;
static Byte MultiMode;   /* 0=8M, 1=16, 2=8L, 3=8H */
static Byte MinMoto;
static Boolean Rec5;
static Boolean SepMoto;
static LongWord AVRLen;

static Boolean RelAdr;

static unsigned FormatOccured;
enum
{
  eMotoOccured = (1 << 0),
  eIntelOccured = (1 << 1),
  eMOSOccured = (1 << 2),
  eDSKOccured = (1 << 3),
  eMico8Occured = (1 << 4)
};
static Byte MaxMoto, MaxIntel;

static tHexFormat DestFormat;

static ChunkList UsedList;

static String CTargName;
static unsigned NumCBlocks;

static void DefStartStopAdr(LongWord SegMask)
{
  Byte Seg;

  for (Seg = 0; Seg < SegCount; Seg++)
    if (SegMask & (1 << Seg))
    {
      StartAdr[Seg] = 0;
      StopAdr[Seg] = (Seg == SegData) ? 0x1fff : 0x7fff;
    }
}

static void Filename2CName(char *pDest, const char *pSrc)
{
  char Trans;
  const char *pPos;
  Boolean Written = False;

  pPos = strrchr(pSrc, PATHSEP);
#ifdef DRSEP
  if (!pPos)
    pPos = strchr(pSrc, DRSEP);
#endif
  if (pPos)
    pSrc = pPos + 1;

  for (; *pSrc; pSrc++)
  {
    Trans = (*pSrc == '-') ? '_' : *pSrc;
    if (isalnum(*pSrc) || (*pSrc == '_'))
    {
      *pDest++ = Trans;
      Written = True;
    }
    else if (Written)
      break;
  }
  *pDest = '\0';
}

static void GetCBlockName(char *pDest, size_t DestSize, unsigned Num)
{
  if (Num > 0)
    as_snprintf(pDest, DestSize, "_%u", Num + 1);
  else
    *pDest = '\0';
}

static void ParamError(Boolean InEnv, char *Arg)
{
   fprintf(stderr, "%s%s\n", getmessage(InEnv ? Num_ErrMsgInvEnvParam : Num_ErrMsgInvParam), Arg);
   fprintf(stderr, "%s\n", getmessage(Num_ErrMsgProgTerm));
}

static void OpenTarget(void)
{
  TargFile = fopen(TargName, "w");
  if (!TargFile)
    ChkIO(TargName);
}

static void CloseTarget(void)
{
  errno = 0;
  fclose(TargFile);
  ChkIO(TargName);
  if (Magic != 0)
    unlink(TargName);
}

static void PrCData(FILE *pTargFile, char Ident, const char *pName,
                    const char *pCTargName, const char *pCBlockName, LongWord Value)
{
  const char *pFormat;

  if (strchr(CFormat, toupper(Ident)))
    pFormat = "ul";
  else if (strchr(CFormat, tolower(Ident)))
    pFormat = "u";
  else
    return;

  errno = 0;
  fprintf(pTargFile, "#define %s%s_%s 0x%08lX%s\n",
          pCTargName, pCBlockName, pName,
          LoDWord(Value), pFormat);
  ChkIO(TargName);
}

static void ProcessFile(const char *FileName, LongWord Offset)
{
  FILE *SrcFile;
  Word TestID;
  Byte InpHeader, InpCPU, InpSegment, InpGran;
  LongWord InpStart, SumLen;
  Word InpLen, TransLen;
  Boolean doit, FirstBank = 0;
  Boolean CDataLower = !!strchr(CFormat, 'd'),
          CDataUpper = !!strchr(CFormat, 'D');
  Byte Buffer[MaxLineLen];
  Word *WBuffer = (Word *) Buffer;
  LongWord ErgStart,
           ErgStop = 0xfffffffful,
           IntOffset = 0, MaxAdr;
  LongInt NextPos;
  LongWord ValidSegs;
  Word ErgLen = 0, ChkSum = 0, RecCnt, Gran, HSeg;
  String CBlockName;

  LongInt z;

  Byte MotRecType = 0;

  tHexFormat ActFormat;
  const TFamilyDescr *FoundDscr;

  SrcFile = fopen(FileName, OPENRDMODE);
  if (!SrcFile) ChkIO(FileName);

  if (!Read2(SrcFile, &TestID))
    chk_wr_read_error(FileName);
  if (TestID !=FileMagic)
    FormatError(FileName, getmessage(Num_FormatInvHeaderMsg));

  if (msg_level >= e_msg_level_normal)
  {
    errno = 0; printf("%s==>>%s", FileName, TargName); ChkIO(OutName);
  }

  SumLen = 0;

  do
  {
    ReadRecordHeader(&InpHeader, &InpCPU, &InpSegment, &InpGran, FileName, SrcFile);

    if (InpHeader == FileHeaderStartAdr)
    {
      if (!Read4(SrcFile, &ErgStart))
        chk_wr_read_error(FileName);
      if (!EntryAdrPresent)
      {
        EntryAdr = ErgStart;
        EntryAdrPresent = True;
      }
    }

    else if (InpHeader == FileHeaderDataRec)
    {
      Gran = InpGran;

      if ((ActFormat = DestFormat) == eHexFormatDefault)
      {
        FoundDscr = FindFamilyById(InpCPU);
        if (!FoundDscr)
          FormatError(FileName, getmessage(Num_FormatInvRecordHeaderMsg));
        else
          ActFormat = FoundDscr->HexFormat;
      }

      if (ForceSegment != SegNone)
        ValidSegs = (1 << ForceSegment);
      else
      {
        ValidSegs = (1 << SegCode);
        if (eHexFormatTiDSK == ActFormat)
          ValidSegs |= (1 << SegData);
      }

      switch (ActFormat)
      {
        case eHexFormatMotoS:
        case eHexFormatIntel32:
        case eHexFormatC:
          MaxAdr = 0xfffffffful;
          break;
        case eHexFormatIntel16:
          MaxAdr = 0xffff0ul + 0xffffu;
          break;
        case eHexFormatAtmel:
          MaxAdr = (1 << (AVRLen << 3)) - 1;
          break;
        case eHexFormatMico8:
          MaxAdr = 0xfffffffful;
          break;
        default:
          MaxAdr = 0xffffu;
      }

      if (!Read4(SrcFile, &InpStart))
        chk_wr_read_error(FileName);
      if (!Read2(SrcFile, &InpLen))
        chk_wr_read_error(FileName);

      NextPos = ftell(SrcFile) + InpLen;
      if (NextPos >= FileSize(SrcFile) - 1)
        FormatError(FileName, getmessage(Num_FormatInvRecordLenMsg));

      doit = FilterOK(InpCPU) && (ValidSegs & (1 << InpSegment));

      if (doit)
      {
        InpStart += Offset;
        ErgStart = max(StartAdr[InpSegment], InpStart);
        ErgStop = min(StopAdr[InpSegment], InpStart + (InpLen/Gran) - 1);
        doit = (ErgStop >= ErgStart);
        if (doit)
        {
          ErgLen = (ErgStop + 1 - ErgStart) * Gran;
          if (AddChunk(&UsedList, ErgStart, ErgStop - ErgStart + 1, True))
          {
            errno = 0; fprintf(stderr, " %s\n", getmessage(Num_ErrMsgOverlap)); ChkIO(OutName);
          }
        }
      }

      if (doit && (ErgStop > MaxAdr))
      {
        errno = 0; fprintf(stderr, " %s\n", getmessage(Num_ErrMsgAdrOverflow)); ChkIO(OutName);
      }

      if (doit)
      {
        /* an Anfang interessierender Daten */

        if (fseek(SrcFile, (ErgStart - InpStart) * Gran, SEEK_CUR) == -1)
          ChkIO(FileName);

        /* Statistik, Anzahl Datenzeilen ausrechnen */

        RecCnt = ErgLen / LineLen;
        if ((ErgLen % LineLen) !=0)
          RecCnt++;

        /* relative Angaben ? */

        if (RelAdr)
          ErgStart -= StartAdr[InpSegment];

        /* Auf Zieladressbereich verschieben */

        ErgStart += Relocate;

        /* Kopf einer Datenzeilengruppe */

        switch (ActFormat)
        {
          case eHexFormatMotoS:
            if ((!(FormatOccured & eMotoOccured)) || (SepMoto))
            {
              errno = 0; fprintf(TargFile, "S0030000FC\n"); ChkIO(TargName);
            }
            if ((ErgStop >> 24) != 0)
              MotRecType = 2;
            else if ((ErgStop >> 16) !=0)
              MotRecType = 1;
            else
              MotRecType = 0;
            if (MotRecType < (MinMoto - 1))
              MotRecType = (MinMoto - 1);
            if (MaxMoto < MotRecType)
              MaxMoto = MotRecType;
            if (Rec5)
            {
              ChkSum = Lo(RecCnt) + Hi(RecCnt) + 3;
              errno = 0;
              fprintf(TargFile, "S503%04X%02X\n", LoWord(RecCnt), Lo(ChkSum ^ 0xff));
              ChkIO(TargName);
            }
            FormatOccured |= eMotoOccured;
            break;
          case eHexFormatMOS:
            FormatOccured |= eMOSOccured;
            break;
          case eHexFormatIntel:
            FormatOccured |= eIntelOccured;
            IntOffset = 0;
            break;
          case eHexFormatIntel16:
            FormatOccured |= eIntelOccured;
            IntOffset = (ErgStart * Gran);
            IntOffset -= IntOffset & 0x0f;
            HSeg = IntOffset >> 4;
            ChkSum = 4 + Lo(HSeg) + Hi(HSeg);
            IntOffset /= Gran;
            errno = 0; fprintf(TargFile, ":02000002%04X%02X\n", LoWord(HSeg), Lo(0x100 - ChkSum)); ChkIO(TargName);
            if (MaxIntel < 1)
              MaxIntel = 1;
            break;
          case eHexFormatIntel32:
            FormatOccured |= eIntelOccured;
            IntOffset = (ErgStart * Gran);
            IntOffset -= IntOffset & 0xffff;
            HSeg = IntOffset >> 16;
            ChkSum = 6 + Lo(HSeg) + Hi(HSeg);
            IntOffset /= Gran;
            errno = 0; fprintf(TargFile, ":02000004%04X%02X\n", LoWord(HSeg), Lo(0x100 - ChkSum)); ChkIO(TargName);
            if (MaxIntel < 2)
              MaxIntel = 2;
            FirstBank = False;
            break;
          case eHexFormatTek:
            break;
          case eHexFormatAtmel:
            break;
          case eHexFormatMico8:
            break;
          case eHexFormatTiDSK:
            if (!(FormatOccured & eDSKOccured))
            {
              FormatOccured |= eDSKOccured;
              errno = 0; fprintf(TargFile, "%s%s\n", getmessage(Num_DSKHeaderLine), TargName); ChkIO(TargName);
            }
            break;
          case eHexFormatC:
            GetCBlockName(CBlockName, sizeof(CBlockName), NumCBlocks);
            PrCData(TargFile, 's', "start", CTargName, CBlockName, ErgStart);
            PrCData(TargFile, 'l', "len", CTargName, CBlockName, ErgLen);
            PrCData(TargFile, 'e', "end", CTargName, CBlockName, ErgStart + ErgLen - 1);
            if (CDataLower || CDataUpper)
            {
              errno = 0;
              fprintf(TargFile, "static const unsigned char %s%s_data[] =\n{\n",
                      CTargName, CBlockName);
              ChkIO(TargName);
            }
            break;
          default:
            break;
        }

        /* Datenzeilen selber */

        while (ErgLen > 0)
        {
          /* evtl. Folgebank fuer Intel32 ausgeben */

          if ((ActFormat == eHexFormatIntel32) && (FirstBank))
          {
            IntOffset += (0x10000 / Gran);
            HSeg = IntOffset >> 16;
            ChkSum = 6 + Lo(HSeg) + Hi(HSeg);
            errno = 0;
            fprintf(TargFile, ":02000004%04X%02X\n", LoWord(HSeg), Lo(0x100 - ChkSum));
            ChkIO(TargName);
            FirstBank = False;
          }

          /* Recordlaenge ausrechnen, fuer Intel32 auf 64K-Grenze begrenzen
             Bei Atmel nur 2 Byte pro Zeile!
             Bei Mico8 nur 4 Byte (davon ein Wort=18 Bit) pro Zeile! */


          TransLen = min(LineLen, ErgLen);
          if ((ActFormat == eHexFormatIntel32) && ((ErgStart & 0xffff) + (TransLen/Gran) >= 0x10000))
          {
            TransLen = Gran * (0x10000 - (ErgStart & 0xffff));
            FirstBank = True;
          }
          else if (ActFormat == eHexFormatAtmel)
            TransLen = min(2, TransLen);
          else if (ActFormat == eHexFormatMico8)
            TransLen = min(4, TransLen);

          /* Start der Datenzeile */

          switch (ActFormat)
          {
            case eHexFormatMotoS:
              errno = 0;
              fprintf(TargFile, "S%c%02X", '1' + MotRecType, Lo(TransLen + 3 + MotRecType));
              ChkIO(TargName);
              ChkSum = TransLen + 3 + MotRecType;
              if (MotRecType >= 2)
              {
                errno = 0; fprintf(TargFile, "%02X", Lo(ErgStart >> 24)); ChkIO(TargName);
                ChkSum += ((ErgStart >> 24) & 0xff);
              }
              if (MotRecType >= 1)
              {
                errno = 0; fprintf(TargFile, "%02X", Lo(ErgStart >> 16)); ChkIO(TargName);
                ChkSum += ((ErgStart >> 16) & 0xff);
              }
              errno = 0; fprintf(TargFile, "%04X", LoWord(ErgStart)); ChkIO(TargName);
              ChkSum += Hi(ErgStart) + Lo(ErgStart);
              break;
            case eHexFormatMOS:
              errno = 0; fprintf(TargFile, ";%02X%04X", Lo(TransLen), LoWord(ErgStart)); ChkIO(TargName);
              ChkSum += TransLen + Lo(ErgStart) + Hi(ErgStart);
              break;
            case eHexFormatIntel:
            case eHexFormatIntel16:
            case eHexFormatIntel32:
            {
              Word WrTransLen;
              LongWord WrErgStart;

              WrTransLen = (MultiMode < 2) ? TransLen : (TransLen / Gran);
              WrErgStart = (ErgStart - IntOffset) * ((MultiMode < 2) ? Gran : 1);
              errno = 0;
              fprintf(TargFile, ":%02X%04X00", Lo(WrTransLen), LoWord(WrErgStart));
              ChkIO(TargName);
              ChkSum = Lo(WrTransLen) + Hi(WrErgStart) + Lo(WrErgStart);

              break;
            }
            case eHexFormatTek:
              errno = 0;
              fprintf(TargFile, "/%04X%02X%02X", LoWord(ErgStart), Lo(TransLen),
                                         Lo(Lo(ErgStart) + Hi(ErgStart) + TransLen));
              ChkIO(TargName);
              ChkSum = 0;
              break;
            case eHexFormatTiDSK:
              errno = 0; fprintf(TargFile, "9%04X", LoWord(/*Gran**/ErgStart));
              ChkIO(TargName);
              ChkSum = 0;
              break;
            case eHexFormatAtmel:
              for (z = (AVRLen - 1) << 3; z >= 0; z -= 8)
              {
                errno = 0;
                fprintf(TargFile, "%02X", Lo(ErgStart >> z));
                ChkIO(TargName);
              }
              errno = 0;
              fputc(':', TargFile);
              ChkIO(TargName);
              break;
            case eHexFormatMico8:
              break;
            case eHexFormatC:
              errno = 0;
              fprintf(TargFile, "  ");
              ChkIO(TargName);
              break;
            default:
              break;
          }

          /* Daten selber */

          if (fread(Buffer, 1, TransLen, SrcFile) !=TransLen)
            chk_wr_read_error(FileName);
          if (MultiMode == 1)
            switch (Gran)
            {
              case 4:
                DSwap(Buffer, TransLen);
                break;
              case 2:
                WSwap(Buffer, TransLen);
                break;
              case 1:
                break;
            }
          switch (ActFormat)
          {
            case eHexFormatTiDSK:
              if (HostBigEndian)
                WSwap(WBuffer, TransLen);
              for (z = 0; z < (TransLen / 2); z++)
              {
                errno = 0;
                if (((ErgStart + z >= StartAdr[SegData]) && (ErgStart + z <= StopAdr[SegData]))
                 || (InpSegment == SegData))
                  fprintf(TargFile, "M%04X", LoWord(WBuffer[z]));
                else
                  fprintf(TargFile, "B%04X", LoWord(WBuffer[z]));
                ChkIO(TargName);
                ChkSum += WBuffer[z];
                SumLen += Gran;
              }
              break;
            case eHexFormatAtmel:
              if (TransLen >= 2)
              {
                fprintf(TargFile, "%04X", LoWord(WBuffer[0]));
                SumLen += 2;
              }
              else if (TransLen >= 1)
              {
                fprintf(TargFile, "%04X", Lo(WBuffer[0]));
                SumLen++;
              }
              break;
            case eHexFormatMico8:
              if (TransLen >= 4)
              {
                fprintf(TargFile, "%01X%02X%02X", Buffer[1] & 0x0f, Buffer[2] % 0xff, Buffer[3] & 0xff);
                SumLen += 4;
              }
              break;
            case eHexFormatC:
              if (CDataLower || CDataUpper)
                for (z = 0; z < (LongInt)TransLen; z++)
                  if ((MultiMode < 2) || (z % Gran == MultiMode - 2))
                  {
                    errno = 0;
                    fprintf(TargFile, CDataLower ? "0x%02x%s" : "0x%02X%s", (unsigned)Buffer[z],
                            (ErgLen - z > 1) ? "," : "");
                    ChkIO(TargName);
                    ChkSum += Buffer[z];
                    SumLen++;
                  }
              break;
            default:
              for (z = 0; z < (LongInt)TransLen; z++)
                if ((MultiMode < 2) || (z % Gran == MultiMode - 2))
                {
                  errno = 0; fprintf(TargFile, "%02X", Lo(Buffer[z])); ChkIO(TargName);
                  ChkSum += Buffer[z];
                  SumLen++;
                }
          }

          /* Ende Datenzeile */

          switch (ActFormat)
          {
            case eHexFormatMotoS:
              errno = 0;
              fprintf(TargFile, "%02X\n", Lo(ChkSum ^ 0xff));
              ChkIO(TargName);
              break;
            case eHexFormatMOS:
              errno = 0;
              fprintf(TargFile, "%04X\n", LoWord(ChkSum));
              break;
            case eHexFormatIntel:
            case eHexFormatIntel16:
            case eHexFormatIntel32:
              errno = 0;
              fprintf(TargFile, "%02X\n", Lo(1 + (ChkSum ^ 0xff)));
              ChkIO(TargName);
              break;
            case eHexFormatTek:
              errno = 0;
              fprintf(TargFile, "%02X\n", Lo(ChkSum));
              ChkIO(TargName);
              break;
            case eHexFormatTiDSK:
              errno = 0;
              fprintf(TargFile, "7%04XF\n", LoWord(ChkSum));
              ChkIO(TargName);
              break;
            case eHexFormatAtmel:
            case eHexFormatMico8:
            case eHexFormatC:
              errno = 0;
              fprintf(TargFile, "\n");
              ChkIO(TargName);
              break;
            default:
              break;
          }

          /* Zaehler rauf */

          ErgLen -= TransLen;
          ErgStart += TransLen/Gran;
        }

        /* Ende der Datenzeilengruppe */

        switch (ActFormat)
        {
          case eHexFormatMotoS:
            if (SepMoto)
            {
              errno = 0;
              fprintf(TargFile, "S%c%02X", '9' - MotRecType, Lo(3 + MotRecType));
              ChkIO(TargName);
              for (z = 1; z <= 2 + MotRecType; z++)
              {
                errno = 0; fprintf(TargFile, "%02X", 0); ChkIO(TargName);
              }
              errno = 0;
              fprintf(TargFile, "%02X\n", Lo(0xff - 3 - MotRecType));
              ChkIO(TargName);
            }
            break;
          case eHexFormatMOS:
            break;
          case eHexFormatIntel:
          case eHexFormatIntel16:
          case eHexFormatIntel32:
            break;
          case eHexFormatTek:
            break;
          case eHexFormatTiDSK:
            break;
          case eHexFormatAtmel:
            break;
          case eHexFormatMico8:
            break;
          case eHexFormatC:
            if (CDataLower || CDataUpper)
            {
              errno = 0;
              fprintf(TargFile, "};\n\n");
              NumCBlocks++;
              ChkIO(TargName);
            }
            break;
          default:
            break;
        };
      }
      if (fseek(SrcFile, NextPos, SEEK_SET) == -1)
        ChkIO(FileName);
    }
    else
      SkipRecord(InpHeader, FileName, SrcFile);
  }
  while (InpHeader !=0);

  if (msg_level >= e_msg_level_normal)
  {
    errno = 0; printf(" ("); ChkIO(OutName);
    errno = 0; printf(Integ32Format, SumLen); ChkIO(OutName);
    errno = 0; printf(" %s)\n", getmessage((SumLen == 1) ? Num_Byte : Num_Bytes)); ChkIO(OutName);
  }
  if (!SumLen)
  {
    errno = 0; fputs(getmessage(Num_WarnEmptyFile), stderr); ChkIO(OutName);
  }

  errno = 0;
  fclose(SrcFile);
  ChkIO(FileName);
}

static ProcessProc CurrProcessor;
static LongWord CurrOffset;

static void Callback(char *Name)
{
  CurrProcessor(Name, CurrOffset);
}

static void ProcessGroup(const char *GroupName_O, ProcessProc Processor)
{
  String Ext, GroupName;

  CurrProcessor = Processor;
  strmaxcpy(GroupName, GroupName_O, STRINGSIZE);
  strmaxcpy(Ext, GroupName, STRINGSIZE);
  if (!RemoveOffset(GroupName, &CurrOffset))
  {
    ParamError(False, Ext);
    exit(1);
  }
  AddSuffix(GroupName, STRINGSIZE, getmessage(Num_Suffix));

  if (!DirScan(GroupName, Callback))
    fprintf(stderr, "%s%s%s\n", getmessage(Num_ErrMsgNullMaskA), GroupName, getmessage(Num_ErrMsgNullMaskB));
}

static void MeasureFile(const char *FileName, LongWord Offset)
{
  FILE *f;
  Byte Header, InpCPU, InpSegment, Gran;
  Word Length, TestID;
  LongWord Adr, EndAdr;
  LongInt NextPos;
  LongWord ValidSegs;
  Boolean doit;

  f = fopen(FileName, OPENRDMODE);
  if (!f)
    ChkIO(FileName);

  if (!Read2(f, &TestID))
    chk_wr_read_error(FileName);
  if (TestID !=FileMagic)
    FormatError(FileName, getmessage(Num_FormatInvHeaderMsg));

  do
  {
    ReadRecordHeader(&Header, &InpCPU, &InpSegment, &Gran, FileName, f);

    if (Header == FileHeaderDataRec)
    {
      if (!Read4(f, &Adr))
        chk_wr_read_error(FileName);
      if (!Read2(f, &Length))
        chk_wr_read_error(FileName);
      NextPos = ftell(f) + Length;
      if (NextPos > FileSize(f))
        FormatError(FileName, getmessage(Num_FormatInvRecordLenMsg));

      if (ForceSegment != SegNone)
        ValidSegs = (1 << ForceSegment);
      else
        ValidSegs = (1 << SegCode) | (1 << SegData);

      doit = FilterOK(InpCPU) && (ValidSegs & (1 << InpSegment));

      if (doit)
      {
        Adr += Offset;
        EndAdr = Adr + (Length/Gran) - 1;
        if (StartAuto)
          if (StartAdr[InpSegment] > Adr)
            StartAdr[InpSegment] = Adr;
        if (StopAuto)
          if (EndAdr > StopAdr[InpSegment])
            StopAdr[InpSegment] = EndAdr;
      }

      fseek(f, NextPos, SEEK_SET);
    }
    else
     SkipRecord(Header, FileName, f);
  }
  while(Header !=0);

  fclose(f);
}

/* ------------------------------------------- */

static as_cmd_result_t CMD_AdrRange(Boolean Negate, const char *Arg)
{
  if (Negate)
  {
    DefStartStopAdr(1 << SegCode);
    return e_cmd_ok;
  }
  else
    return CMD_Range(&StartAdr[SegCode], &StopAdr[SegCode],
                     &StartAuto, &StopAuto, Arg);
}

static as_cmd_result_t CMD_RelAdr(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  RelAdr = (!Negate);
  return e_cmd_ok;
}

static as_cmd_result_t CMD_AdrRelocate(Boolean Negate, const char *Arg)
{
  Boolean ok;
  UNUSED(Arg);

  if (Negate)
  {
    Relocate = 0;
    return e_cmd_ok;
  }
  else
  {
    Relocate = ConstLongInt(Arg, &ok, 10);
    if (!ok) return e_cmd_err;

    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_Rec5(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  Rec5 = (!Negate);
  return e_cmd_ok;
}

static as_cmd_result_t CMD_SepMoto(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  SepMoto = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_IntelMode(Boolean Negate, const char *Arg)
{
  int Mode;
  Boolean ok;

  if (*Arg == '\0')
    return e_cmd_err;
  else
  {
    Mode = ConstLongInt(Arg, &ok, 10);
    if ((!ok) || (Mode < 0) || (Mode > 2))
      return e_cmd_err;
    else
    {
      if (!Negate)
        IntelMode = Mode;
      else if (IntelMode == Mode)
        IntelMode = 0;
      return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_MultiMode(Boolean Negate, const char *Arg)
{
  int Mode;
  Boolean ok;

  if (*Arg == '\0')
    return e_cmd_err;
  else
  {
    Mode = ConstLongInt(Arg, &ok, 10);
    if ((!ok) || (Mode < 0) || (Mode > 3))
      return e_cmd_err;
    else
    {
      if (!Negate)
        MultiMode = Mode;
      else if (MultiMode == Mode)
        MultiMode = 0;
      return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_DestFormat(Boolean Negate, const char *pArg)
{
#define NameCnt (sizeof(Names) / sizeof(*Names))

  static const char *Names[] =
  {
    "DEFAULT", "MOTO", "INTEL", "INTEL16", "INTEL32", "MOS", "TEK", "DSK", "ATMEL", "MICO8", "C"
  };
  static tHexFormat Format[] =
  {
    eHexFormatDefault, eHexFormatMotoS, eHexFormatIntel, eHexFormatIntel16,
    eHexFormatIntel32, eHexFormatMOS, eHexFormatTek, eHexFormatTiDSK,
    eHexFormatAtmel, eHexFormatMico8, eHexFormatC
  };
  unsigned z;
  String Arg;

  strmaxcpy(Arg, pArg, STRINGSIZE);
  NLS_UpString(Arg);

  z = 0;
  while ((z < NameCnt) && (strcmp(Arg, Names[z])))
    z++;
  if (z >= NameCnt)
    return e_cmd_err;

  if (!Negate)
    DestFormat = Format[z];
  else if (DestFormat == Format[z])
    DestFormat = eHexFormatDefault;

  return e_cmd_arg;
}

static as_cmd_result_t CMD_ForceSegment(Boolean Negate,  const char *Arg)
{
  int z = addrspace_lookup(Arg);

  if (z >= SegCount)
    return e_cmd_err;

  if (!Negate)
    ForceSegment = z;
  else if (ForceSegment == z)
    ForceSegment = SegNone;

  return e_cmd_arg;
}

static as_cmd_result_t CMD_DataAdrRange(Boolean Negate,  const char *Arg)
{
  fputs(getmessage(Num_WarnDOption), stderr);
  fflush(stdout);

  if (Negate)
  {
    DefStartStopAdr(1 << SegData);
    return e_cmd_ok;
  }
  else
  {
    Boolean StartDataAuto, StopDataAuto;
    as_cmd_result_t Ret = CMD_Range(&StartAdr[SegData], &StopAdr[SegData],
                              &StartDataAuto, &StopDataAuto, Arg);

    if (StartDataAuto || StopDataAuto)
      Ret = e_cmd_err;
    return Ret;
  }
}

static as_cmd_result_t CMD_EntryAdr(Boolean Negate, const char *Arg)
{
  Boolean ok;

  if (Negate)
  {
    EntryAdrPresent = False;
    return e_cmd_ok;
  }
  else
  {
    EntryAdr = ConstLongInt(Arg, &ok, 10);
    if ((!ok) || (EntryAdr > 0xffff))
      return e_cmd_err;
    EntryAdrPresent = True;
    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_LineLen(Boolean Negate, const char *Arg)
{
  Boolean ok;

  if (Negate)
  {
    if (*Arg !='\0')
      return e_cmd_err;
    else
    {
      LineLen = 16;
      return e_cmd_ok;
    }
  }
  else if (*Arg == '\0')
    return e_cmd_err;
  else
  {
    LineLen = ConstLongInt(Arg, &ok, 10);
    if ((!ok) || (LineLen < 1) || (LineLen > MaxLineLen))
      return e_cmd_err;
    else
    {
      LineLen += LineLen & 1;
      return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_MinMoto(Boolean Negate, const char *Arg)
{
  Boolean ok;

  if (Negate)
  {
    if (*Arg != '\0')
      return e_cmd_err;
    else
    {
      MinMoto = 0;
      return e_cmd_ok;
    }
  }
  else if (*Arg == '\0')
    return e_cmd_err;
  else
  {
    MinMoto = ConstLongInt(Arg, &ok, 10);
    if ((!ok) || (MinMoto < 1) || (MinMoto > 3))
      return e_cmd_err;
    else
      return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_AutoErase(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  AutoErase = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_AVRLen(Boolean Negate, const char *Arg)
{
  Word Temp;
  Boolean ok;

  if (Negate)
  {
    AVRLen = AVRLEN_DEFAULT;
    return e_cmd_ok;
  }
  else
  {
    Temp = ConstLongInt(Arg, &ok, 10);
    if ((!ok) || (Temp < 2) || (Temp > 3))
      return e_cmd_err;
    else
    {
      AVRLen = Temp;
      return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_CFormat(Boolean Negate, const char *pArg)
{
  if (Negate)
  {
    strcpy(CFormat, DefaultCFormat);
    return e_cmd_ok;
  }
  else
  {
    int NumData = 0, NumStart = 0, NumLen = 0, NumEnd = 0;
    const char *pFormat;

    for (pFormat = pArg; *pFormat; pFormat++)
      switch (toupper(*pFormat))
      {
        case 'S': NumStart++; break;
        case 'D': NumData++; break;
        case 'L': NumLen++; break;
        case 'E': NumEnd++; break;
        default: return e_cmd_err;
      }
    if ((NumData > 1) || (NumStart > 1) || (NumLen > 1) || (NumEnd > 1))
      return e_cmd_err;
    strcpy(CFormat, pArg);
    return e_cmd_arg;
  }
}

static const as_cmd_rec_t P2HEXParams[] =
{
  { "f"        , CMD_FilterList },
  { "r"        , CMD_AdrRange },
  { "R"        , CMD_AdrRelocate },
  { "a"        , CMD_RelAdr },
  { "i"        , CMD_IntelMode },
  { "m"        , CMD_MultiMode },
  { "F"        , CMD_DestFormat },
  { "5"        , CMD_Rec5 },
  { "s"        , CMD_SepMoto },
  { "d"        , CMD_DataAdrRange },
  { "e"        , CMD_EntryAdr },
  { "l"        , CMD_LineLen },
  { "k"        , CMD_AutoErase },
  { "M"        , CMD_MinMoto },
  { "SEGMENT"  , CMD_ForceSegment },
  { "AVRLEN"   , CMD_AVRLen },
  { "CFORMAT"  , CMD_CFormat }
};

static Word ChkSum;

int main(int argc, char **argv)
{
  char *p_target_name;
  const char *p_src_name;
  as_cmd_results_t cmd_results;
  StringRecPtr p_src_run;

  nls_init();
  if (!NLS_Initialize(&argc, argv))
    exit(4);

  be_le_init();
  bpemu_init();
  chunks_init();
  as_cmdarg_init(*argv);
  msg_level_init();
  toolutils_init(*argv);
#ifdef _USE_MSH
  nlmessages_init_buffer(p2hex_msh_data, sizeof(p2hex_msh_data), MsgId1, MsgId2);
#else
  nlmessages_init_file("p2hex.msg", *argv, MsgId1, MsgId2);
#endif
  ioerrs_init(*argv);

  InitChunk(&UsedList);

  DefStartStopAdr(0xffff);
  StartAuto = True;
  StopAuto = True;
  EntryAdr = -1;
  EntryAdrPresent = False;
  AutoErase = False;
  RelAdr = False;
  Rec5 = True;
  LineLen = 16;
  AVRLen = AVRLEN_DEFAULT;
  IntelMode = 0;
  MultiMode = 0;
  DestFormat = eHexFormatDefault;
  MinMoto = 1;
  *TargName = '\0';
  Relocate = 0;
  ForceSegment = SegNone;
  strcpy(CFormat, DefaultCFormat);

  as_cmd_register(P2HEXParams, as_array_size(P2HEXParams));
  if (e_cmd_err == as_cmd_process(argc, argv, "P2HEXCMD", &cmd_results))
  {
    ParamError(cmd_results.error_arg_in_env, cmd_results.error_arg);
    exit(1);
  }

  if ((msg_level >= e_msg_level_verbose) || cmd_results.write_version_exit)
  {
    String Ver;

    as_snprintf(Ver, sizeof(Ver), "P2HEX V%s", Version);
    WrCopyRight(Ver);
  }

  if (cmd_results.write_help_exit)
  {
    char *ph1, *ph2;

    errno = 0; printf("%s%s%s\n", getmessage(Num_InfoMessHead1), as_cmdarg_get_executable_name(), getmessage(Num_InfoMessHead2)); ChkIO(OutName);
    for (ph1 = getmessage(Num_InfoMessHelp), ph2 = strchr(ph1, '\n'); ph2; ph1 = ph2 + 1, ph2 = strchr(ph1, '\n'))
    {
      *ph2 = '\0';
      printf("%s\n", ph1);
      *ph2 = '\n';
    }
  }

  if (cmd_results.write_version_exit || cmd_results.write_help_exit)
    exit(0);

  if (StringListEmpty(cmd_results.file_arg_list))
  {
    fprintf(stderr, "%s: %s\n", as_cmdarg_get_executable_name(), getmessage(Num_ErrMessNoInputFiles));
    exit(1);
  }

  p_target_name = MoveAndCutStringListLast(&cmd_results.file_arg_list);
  if (!p_target_name || !*p_target_name)
  {
    errno = 0; fprintf(stderr, "%s\n", getmessage(Num_ErrMsgTargMissing)); ChkIO(OutName);
    if (p_target_name) free(p_target_name);
    p_target_name = NULL;
    exit(1);
  }

  strmaxcpy(TargName, p_target_name, STRINGSIZE);
  if (!RemoveOffset(TargName, &Dummy))
  {
    strmaxcpy(TargName, p_target_name, STRINGSIZE);
    free(p_target_name); p_target_name = NULL;
    ParamError(False, TargName);
  }

  /* special case: only one argument <name> treated like <name>.p -> <name).hex */

  if (StringListEmpty(cmd_results.file_arg_list))
  {
    AddStringListLast(&cmd_results.file_arg_list, p_target_name);
    DelSuffix(TargName);
  }
  free(p_target_name); p_target_name = NULL;
  AddSuffix(TargName, STRINGSIZE, HexSuffix);
  Filename2CName(CTargName, TargName);
  NumCBlocks = 0;

  if (StartAuto || StopAuto)
  {
    int z;
    Byte ChkSegment = ForceSegment ? ForceSegment : (Byte)SegCode;

    if (StartAuto)
      for (z = 0; z < SegCount; z++)
        StartAdr[z] = 0xfffffffful;
    if (StopAuto)
      for (z = 0; z < SegCount; z++)
        StopAdr[z] = 0;

    for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run);
         p_src_name; p_src_name = GetStringListNext(&p_src_run))
      if (*p_src_name)
        ProcessGroup(p_src_name, MeasureFile);

    if (StartAdr[ChkSegment] > StopAdr[ChkSegment])
    {
      errno = 0;
      fprintf(stderr, "%s\n", getmessage(Num_ErrMsgAutoFailed));
      ChkIO(OutName);
      exit(1);
    }
    if (msg_level >= e_msg_level_normal)
    {
      printf("%s: 0x%08lX-", getmessage(Num_InfoMessDeducedRange), LoDWord(StartAdr[ChkSegment]));
      printf("0x%08lX\n", LoDWord(StopAdr[ChkSegment]));
    }
  }

  OpenTarget();
  FormatOccured = 0;
  MaxMoto = 0;
  MaxIntel = 0;

  if (DestFormat == eHexFormatC)
  {
    errno = 0;
    fprintf(TargFile, "#ifndef _%s_H\n#define _%s_H\n\n", CTargName, CTargName);
    ChkIO(TargName);
    NumCBlocks = 0;
  }

  for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run);
       p_src_name; p_src_name = GetStringListNext(&p_src_run))
    if (*p_src_name)
      ProcessGroup(p_src_name, ProcessFile);

  if ((FormatOccured & eMotoOccured) && (!SepMoto))
  {
    errno = 0; fprintf(TargFile, "S%c%02X", '9' - MaxMoto, Lo(3 + MaxMoto)); ChkIO(TargName);
    ChkSum = 3 + MaxMoto;
    if (!EntryAdrPresent)
      EntryAdr = 0;
    if (MaxMoto >= 2)
    {
      errno = 0; fprintf(TargFile, "%02X", Lo(EntryAdr >> 24)); ChkIO(TargName);
      ChkSum += (EntryAdr >> 24) & 0xff;
    }
    if (MaxMoto >= 1)
    {
      errno = 0; fprintf(TargFile, "%02X", Lo(EntryAdr >> 16)); ChkIO(TargName);
      ChkSum += (EntryAdr >> 16) & 0xff;
    }
    errno = 0; fprintf(TargFile, "%04X", LoWord(EntryAdr & 0xffff)); ChkIO(TargName);
    ChkSum += (EntryAdr >> 8) & 0xff;
    ChkSum += EntryAdr & 0xff;
    errno = 0; fprintf(TargFile, "%02X\n", Lo(0xff - (ChkSum & 0xff))); ChkIO(TargName);
  }

  if (FormatOccured & eIntelOccured)
  {
    Word EndRecAddr = 0;

    if (EntryAdrPresent)
    {
      switch (MaxIntel)
      {
        case 2:
          errno = 0; fprintf(TargFile, ":04000005"); ChkIO(TargName);
          ChkSum = 4 + 5;
          errno = 0; fprintf(TargFile, "%08lX", LoDWord(EntryAdr)); ChkIO(TargName);
          ChkSum += ((EntryAdr >> 24) & 0xff) +
                    ((EntryAdr >> 16) & 0xff) +
                    ((EntryAdr >>  8) & 0xff) +
                    ( EntryAdr        & 0xff);
          goto WrChkSum;

        case 1:
          Seg = (EntryAdr >> 4) & 0xffff;
          Ofs = EntryAdr & 0x000f;
          errno = 0; fprintf(TargFile, ":04000003%04X%04X", LoWord(Seg), LoWord(Ofs)); ChkIO(TargName);
          ChkSum = 4 + 3 + Lo(Seg) + Hi(Seg) + Ofs;
          goto WrChkSum;

        default: /* == 0 */
          EndRecAddr = EntryAdr & 0xffff;
          break;

        WrChkSum:
          errno = 0; fprintf(TargFile, "%02X\n", Lo(0x100 - ChkSum)); ChkIO(TargName);
      }
    }
    errno = 0;
    switch (IntelMode)
    {
      case 0:
      {
        ChkSum = 1 + Hi(EndRecAddr) + Lo(EndRecAddr);
        fprintf(TargFile, ":00%04X01%02X\n", LoWord(EndRecAddr), Lo(0x100 - ChkSum));
        break;
      }
      case 1:
        fprintf(TargFile, ":00000001\n");
        break;
      case 2:
        fprintf(TargFile, ":0000000000\n");
        break;
    }
    ChkIO(TargName);
  }

  if (FormatOccured & eMOSOccured)
  {
    errno = 0; fprintf(TargFile, ";0000040004\n"); ChkIO(TargName);
  }

  if (FormatOccured & eDSKOccured)
  {
    if (EntryAdrPresent)
    {
      errno = 0;
      fprintf(TargFile, "1%04X7%04XF\n", LoWord(EntryAdr), LoWord(EntryAdr));
      ChkIO(TargName);
    }
    errno = 0; fprintf(TargFile, ":\n"); ChkIO(TargName);
  }

  if (DestFormat == eHexFormatC)
  {
    unsigned ThisCBlock;
    String CBlockName;
    const char *pFormat;

    errno = 0;
    fprintf(TargFile,
            "typedef struct\n"
            "{\n");
    for (pFormat = CFormat; *pFormat; pFormat++)
      switch (*pFormat)
      {
        case 'd':
        case 'D':
          fprintf(TargFile, "  const char *data;\n"); break;
        case 's':
          fprintf(TargFile, "  unsigned start;\n"); break;
        case 'S':
          fprintf(TargFile, "  unsigned long start;\n"); break;
        case 'l':
          fprintf(TargFile, "  unsigned len;\n"); break;
        case 'L':
          fprintf(TargFile, "  unsigned long len;\n"); break;
        case 'e':
          fprintf(TargFile, "  unsigned end;\n"); break;
        case 'E':
          fprintf(TargFile, "  unsigned long end;\n"); break;
        default:
          break;
      }
    fprintf(TargFile,
            "} %s_blk;\n"
            "static const %s_blk %s_blks[] =\n"
            "{\n",
            CTargName, CTargName, CTargName);
    for (ThisCBlock = 0; ThisCBlock < NumCBlocks; ThisCBlock++)
    {
      GetCBlockName(CBlockName, sizeof(CBlockName), ThisCBlock);
      fprintf(TargFile, "  {");
      for (pFormat = CFormat; *pFormat; pFormat++)
      {
        fprintf(TargFile, (pFormat != CFormat) ? ", " : " ");
        switch (toupper(*pFormat))
        {
          case 'D': fprintf(TargFile, "%s%s_data", CTargName, CBlockName); break;
          case 'S': fprintf(TargFile, "%s%s_start", CTargName, CBlockName); break;
          case 'L': fprintf(TargFile, "%s%s_len", CTargName, CBlockName); break;
          case 'E': fprintf(TargFile, "%s%s_end", CTargName, CBlockName); break;
          default: break;
        }
      }
      fprintf(TargFile, " },\n");
    }
    fprintf(TargFile, "  {");
    for (pFormat = CFormat; *pFormat; pFormat++)
      fprintf(TargFile, (pFormat != CFormat) ? ", 0" : " 0");
    fprintf(TargFile, " }\n"
                      "};\n\n");

    if (EntryAdrPresent)
      fprintf(TargFile, "#define %s_entry 0x%08lXul\n\n",
              CTargName, LoDWord(EntryAdr));
    fprintf(TargFile,
            "#endif /* _%s_H */\n",
            CTargName);
    ChkIO(TargName);
  }
  CloseTarget();

  if (AutoErase)
  {
    for (p_src_name = GetStringListFirst(cmd_results.file_arg_list, &p_src_run);
         p_src_name; p_src_name = GetStringListNext(&p_src_run))
      if (*p_src_name)
        ProcessGroup(p_src_name, EraseFile);
  }

  ClearStringList(&cmd_results.file_arg_list);

  return 0;
}