Top secrets sources NedoPC pentevo

Rev

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

/* p2bin.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Umwandlung von AS-Codefiles in Binaerfiles                                */
/*                                                                           */
/*****************************************************************************/

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

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

#define BinSuffix ".bin"


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


static FILE *TargFile;
static String TargName;

static LongWord StartAdr, StopAdr, EntryAdr, RealFileLen;
static LongWord MaxGran, Dummy;
static Boolean StartAuto, StopAuto, AutoErase, EntryAdrPresent;

static Byte FillVal, ValidSegment;
static Boolean DoCheckSum;

static Byte SizeDiv;
static LongWord ANDMask, ANDEq;
static ShortInt StartHeader;

static ChunkList UsedList;


#ifdef DEBUG
#define ChkIO(s) ChkIO_L(s, __LINE__)

static void ChkIO_L(char *s, int line)
{
  if (errno != 0)
  {
    fprintf(stderr, "%s %d\n", s, line);
    exit(3);
  }
}
#endif

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

#define BufferSize 4096
static Byte Buffer[BufferSize];

static void OpenTarget(void)
{
  LongWord Rest, Trans, AHeader;

  TargFile = fopen(TargName, OPENWRMODE);
  if (!TargFile)
    ChkIO(TargName);
  RealFileLen = ((StopAdr - StartAdr + 1) * MaxGran) / SizeDiv;

  AHeader = abs(StartHeader);
  if (StartHeader != 0)
  {
    memset(Buffer, 0, AHeader);
    if (fwrite(Buffer, 1, abs(StartHeader), TargFile) != AHeader)
      ChkIO(TargName);
  }

  memset(Buffer, FillVal, BufferSize);

  Rest = RealFileLen;
  while (Rest != 0)
  {
    Trans = min(Rest, BufferSize);
    if (fwrite(Buffer, 1, Trans, TargFile) != Trans)
      ChkIO(TargName);
    Rest -= Trans;
  }
}

static void CloseTarget(void)
{
  LongWord z, AHeader;

  AHeader = abs(StartHeader);

  /* write entry address to file? */

  if ((EntryAdrPresent) && (StartHeader != 0))
  {
    LongWord bpos;

    rewind(TargFile);
    bpos = ((StartHeader > 0) ? 0 : -1 - StartHeader) << 3;
    for (z = 0; z < AHeader; z++)
    {
      Buffer[z] = (EntryAdr >> bpos) & 0xff;
      bpos += (StartHeader > 0) ? 8 : -8;
    }
    if (fwrite(Buffer, 1, AHeader, TargFile) != AHeader)
      ChkIO(TargName);
  }

  if (EOF == fclose(TargFile))
    ChkIO(TargName);

  /* compute checksum over file? */

  if (DoCheckSum)
  {
    LongWord Sum, Size, Rest, Trans, Read;

    TargFile = fopen(TargName, OPENUPMODE);
    if (!TargFile)
      ChkIO(TargName);
    if (fseek(TargFile, AHeader, SEEK_SET) == -1)
      ChkIO(TargName);
    Size = Rest = FileSize(TargFile) - AHeader - 1;

    Sum = 0;
    while (Rest > 0)
    {
      Trans = min(Rest, BufferSize);
      Rest -= Trans;
      Read = fread(Buffer, 1, Trans, TargFile);
      if (Read != Trans)
        chk_wr_read_error(TargName);
      for (z = 0; z < Trans; Sum += Buffer[z++]);
    }
    errno = 0;
    printf("%s%08lX\n", getmessage(Num_InfoMessChecksum), LoDWord(Sum));
    Buffer[0] = 0x100 - (Sum & 0xff);

    /* Some systems require fflush() between read & write operations.  And
       some other systems again garble the file pointer upon an fflush(): */


    fflush(TargFile);
    if (fseek(TargFile, AHeader + Size, SEEK_SET) == -1)
      ChkIO(TargName);
    if (fwrite(Buffer, 1, 1, TargFile) != 1)
      ChkIO(TargName);
    fflush(TargFile);

    if (fclose(TargFile) == EOF)
      ChkIO(TargName);
  }

  if (Magic != 0)
    unlink(TargName);
}

static void ProcessFile(const char *FileName, LongWord Offset)
{
  FILE *SrcFile;
  Word TestID;
  Byte InpHeader, InpCPU, InpSegment;
  LongWord InpStart, SumLen;
  Word InpLen, TransLen, ResLen;
  Boolean doit;
  LongWord ErgStart, ErgStop;
  LongInt NextPos;
  Word ErgLen = 0;
  Byte Gran;

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

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

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

  SumLen = 0;

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

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

    else if (InpHeader == FileHeaderDataRec)
    {
      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(InpHeader) && (InpSegment == ValidSegment));

      if (doit)
      {
        InpStart += Offset;
        ErgStart = max(StartAdr, InpStart);
        ErgStop = min(StopAdr, 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)
      {
        /* an Anfang interessierender Daten */

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

        /* in Zieldatei an passende Stelle */

        if (fseek(TargFile, (((ErgStart - StartAdr) * Gran)/SizeDiv) + abs(StartHeader), SEEK_SET) == -1)
          ChkIO(TargName);

        /* umkopieren */

        while (ErgLen > 0)
        {
          TransLen = min(BufferSize, ErgLen);
          if (fread(Buffer, 1, TransLen, SrcFile) != TransLen)
            chk_wr_read_error(FileName);
          if (SizeDiv == 1) ResLen = TransLen;
          else
          {
            LongWord Addr;

            ResLen = 0;
            for (Addr = 0; Addr < (LongWord)TransLen; Addr++)
              if (((ErgStart * Gran + Addr) & ANDMask) == ANDEq)
                Buffer[ResLen++] = Buffer[Addr];
          }
          if (fwrite(Buffer, 1, ResLen, TargFile) != ResLen)
            ChkIO(TargName);
          ErgLen -= TransLen;
          ErgStart += TransLen;
          SumLen += ResLen;
        }
      }
      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), stdout);
    ChkIO(OutName);
  }

  if (fclose(SrcFile) == EOF)
    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, CPU, Gran, Segment;
  Word Length, TestID;
  LongWord Adr, EndAdr;
  LongInt NextPos;

  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, &CPU, &Segment, &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 (FilterOK(Header) && (Segment == ValidSegment))
      {
        Adr += Offset;
        EndAdr = Adr + (Length/Gran)-1;
        if (Gran > MaxGran)
          MaxGran = Gran;
        if (StartAuto)
          if (StartAdr > Adr)
            StartAdr = Adr;
        if (StopAuto)
          if (EndAdr > StopAdr)
            StopAdr = EndAdr;
      }

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

  if (fclose(f) == EOF)
    ChkIO(FileName);
}

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

static as_cmd_result_t CMD_AdrRange(Boolean Negate, const char *Arg)
{
  if (Negate)
  {
    StartAdr = 0; StopAdr = 0x7fff;
    return e_cmd_ok;
  }
  else
    return CMD_Range(&StartAdr, &StopAdr,
                     &StartAuto, &StopAuto, Arg);
}

static as_cmd_result_t CMD_ByteMode(Boolean Negate, const char *pArg)
{
#define ByteModeCnt 9
  static const char *ByteModeStrings[ByteModeCnt] =
  {
    "ALL", "EVEN", "ODD", "BYTE0", "BYTE1", "BYTE2", "BYTE3", "WORD0", "WORD1"
  };
  static Byte ByteModeDivs[ByteModeCnt] =
  {
    1, 2, 2, 4, 4, 4, 4, 2, 2
  };
  static Byte ByteModeMasks[ByteModeCnt] =
  {
    0, 1, 1, 3, 3, 3, 3, 2, 2
  };
  static Byte ByteModeEqs[ByteModeCnt] =
  {
    0, 0, 1, 0, 1, 2, 3, 0, 2
  };

  int z;
  UNUSED(Negate);

  if (*pArg == '\0')
  {
    SizeDiv = 1;
    ANDEq = 0;
    ANDMask = 0;
    return e_cmd_ok;
  }
  else
  {
    String Arg;

    strmaxcpy(Arg, pArg, STRINGSIZE);
    NLS_UpString(Arg);
    ANDEq = 0xff;
    for (z = 0; z < ByteModeCnt; z++)
      if (strcmp(Arg, ByteModeStrings[z]) == 0)
      {
        SizeDiv = ByteModeDivs[z];
        ANDMask = ByteModeMasks[z];
        ANDEq   = ByteModeEqs[z];
      }
    if (ANDEq == 0xff)
      return e_cmd_err;
    else
      return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_StartHeader(Boolean Negate, const char *Arg)
{
  Boolean err;
  ShortInt Sgn;

  if (Negate)
  {
    StartHeader = 0;
    return e_cmd_ok;
  }
  else
  {
    Sgn = 1;
    if (*Arg == '\0')
      return e_cmd_err;
    switch (as_toupper(*Arg))
    {
      case 'B':
        Sgn = -1;
        /* fall-through */
      case 'L':
        Arg++;
    }
    StartHeader = ConstLongInt(Arg, &err, 10);
    if ((!err) || (StartHeader > 4))
      return e_cmd_err;
    StartHeader *= Sgn;
    return e_cmd_arg;
  }
}      

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

  if (Negate)
  {
    EntryAdrPresent = False;
    return e_cmd_ok;
  }
  else
  {
    EntryAdr = ConstLongInt(Arg, &err, 10);
    if (err)
      EntryAdrPresent = True;
    return (err) ? e_cmd_arg : e_cmd_err;
  }
}

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

  FillVal = ConstLongInt(Arg, &err, 10);
  return err ? e_cmd_arg : e_cmd_err;
}

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

  DoCheckSum = !Negate;
  return e_cmd_ok;
}

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_ForceSegment(Boolean Negate,  const char *Arg)
{
  int z = addrspace_lookup(Arg);

  if (z >= SegCount)
    return e_cmd_err;

  if (!Negate)
    ValidSegment = z;
  else if (ValidSegment == z)
    ValidSegment = SegCode;

  return e_cmd_arg;
}

static as_cmd_rec_t P2BINParams[] =
{
  { "f"        , CMD_FilterList },
  { "r"        , CMD_AdrRange },
  { "s"        , CMD_CheckSum },
  { "m"        , CMD_ByteMode },
  { "l"        , CMD_FillVal },
  { "e"        , CMD_EntryAdr },
  { "S"        , CMD_StartHeader },
  { "k"        , CMD_AutoErase },
  { "SEGMENT"  , CMD_ForceSegment }
};

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

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

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

  InitChunk(&UsedList);

  StartAdr = 0;
  StopAdr = 0x7fff;
  StartAuto = True;
  StopAuto = True;
  FillVal = 0xff;
  DoCheckSum = False;
  SizeDiv = 1;
  ANDEq = 0;
  EntryAdr = -1;
  EntryAdrPresent = False;
  AutoErase = False;
  StartHeader = 0;
  ValidSegment = SegCode;

  as_cmd_register(P2BINParams, as_array_size(P2BINParams));
  if (e_cmd_err == as_cmd_process(argc, argv, "P2BINCMD", &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), "P2BIN 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)
  {
    if (p_target_name) free(p_target_name);
    p_target_name = NULL;
    errno = 0;
    fprintf(stderr, "%s\n", getmessage(Num_ErrMsgTargMissing));
    ChkIO(OutName);
    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).bin */

  if (StringListEmpty(cmd_results.file_arg_list))
  {
    AddStringListLast(&cmd_results.file_arg_list, p_target_name);
    DelSuffix(TargName);
  }
  AddSuffix(TargName, STRINGSIZE, BinSuffix);
  free(p_target_name); p_target_name = NULL;

  MaxGran = 1;
  if ((StartAuto) || (StopAuto))
  {
    if (StartAuto)
      StartAdr = 0xfffffffful;
    if (StopAuto)
      StopAdr = 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 > StopAdr)
    {
      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));
      printf("0x%08lX\n", LoDWord(StopAdr));
    }
  }

  OpenTarget();

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

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