// HEX2BIN.C

// Convert INTEL-HEX-FORMAT to Binary

#define IDE

#include <dos.h>
#include <alloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "e:\l\mylib\source\fil.c"

#ifdef IDE
  #define BUFFLEN 65536L-0x3000
  UCHAR buffer[BUFFLEN];
#else
  #define BUFFLEN 65536L
  UCHAR far *buffer;
#endif

UINT eprombeg = 0xffff;
UINT epromend = 0;

INT error=0;

VOID exit_fn(VOID)
{
  if (error)
  {
    printf("\nConvert HEX -> BIN-Format, HEX-Explain\n"
           "usage: HEX2BIN name\n"
           "       name....source <name>.HEX\n"
           "creates <name>.BIN, starting with first record\n"
          );
  }
}

UCHAR hex2bin(UCHAR hi, UCHAR lo)
{
  CHAR HEXDIGITS[] = "0123456789ABCDEF";

  return (strchr(HEXDIGITS,toupper(hi)) - HEXDIGITS) * 16 +
         (strchr(HEXDIGITS,toupper(lo)) - HEXDIGITS);
}

/* process_HEX
 *************
 * l HEX-line
 * f outpu-file
 * pass  0..analyze and write to textfile, fill buffer
 *       1..write to binary-file
 */

INT process_HEX(CHAR *l, FILE *f, INT pass)
{
  // Interpretierte Zeile
  if (pass==0)
  {
    // HEX-Zeile
    fprintf(f,"%s\n",l);

    if (l[0]!=':')
    {
      fprintf(f,"falsches Zeilenbeginnzeichen\n");
      return 1;
    }
    if ((l[7]=='0') && (l[8]=='0'))
      fprintf(f,"Typ: DAT  ");
    else if ((l[7]=='0') && (l[8]=='1'))
      fprintf(f,"Typ: END  ");
    else
    {
      fprintf(f,"Unbekanntes Format\n");
      return 2;
    }
  }

  if (l[8]=='1') /* Ende-Record */
  {
    /* prfen der restlichen Bestandteile des ENDE-Records */
    if (strcmp(&l[1],"00000001FF")!=0)
    {
      if (pass==0) fprintf(f,"Falscher Ende-Record\n");
      return 3;
    }
    else
      return 0;
  }

  UINT len=hex2bin(l[1],l[2]);
  if (pass==0)
  {
    fprintf(f,"Len: %2d  ",len);
    fprintf(f,"Adr: %c%c%c%c  ",l[3],l[4],l[5],l[6]);
  }

  UINT adr=hex2bin(l[3],l[4])*256 + hex2bin(l[5],l[6]);
  if (adr<eprombeg)
    eprombeg=adr;
  if (adr+len>epromend)
    epromend=adr+len-1;

  switch (pass) // copy data to buffer
  {
  case 0:  // pass 0 area only
    for (UINT a=adr; a<adr+len; a++)
    {
      if (buffer[a])
        fprintf(f,"!");
      buffer[a]++;
    }
    break;
  case 1:  // pass 1 data itself
    for (a=adr; a<adr+len; a++)
      buffer[a]=(UCHAR)hex2bin(l[9+(a-adr)*2],l[10+(a-adr)*2]);
    break;
  }

  if (pass==0)
  {
    UINT  chk=0;

    for (int i=1; i<(strlen(l)-2); i++,i++)
      chk+=hex2bin(l[i],l[1+i]);
    fprintf(f,"Chk: %4x \n",(0-chk)%256);
  }
  return 0;
}

VOID main(INT argc, CHAR *argv[])
{
  atexit(exit_fn);

  if (argc!=2)
  {
    error=1;
    exit(EXIT_FAILURE);
  }

#ifndef IDE
  // Create Buffer for Binary
  // ***********************************************
  printf("%li\n",farcoreleft());
  buffer = (unsigned char far*)farmalloc(BUFFLEN);
  if (buffer == NULL)
  {
    printf("No Memory\n");
    exit(EXIT_FAILURE);
  }
  _fmemset(buffer,0,BUFFLEN);
#else
  // use smaller buffer for testing
  memset(buffer,0,BUFFLEN);
#endif

  // clear buffer

  // Open file to be converted
  // ***********************************************
  FILE *fsrc=NULL; // source-file
  CHAR dateiHEX[128];
  strcpy(dateiHEX, argv[1]);
  strcat(dateiHEX, ".HEX");
  fsrc = fopen(dateiHEX,"rt");
  if (fsrc==NULL)
  {
    printf("File %s does not exist\n",dateiHEX);
    fclose (fsrc);
    exit(EXIT_FAILURE);
  }

  // Create DOC-File
  // ***********************************************
  FILE *fdoc=NULL; // documentation-file
  CHAR dateiHDO[128];
  strcpy(dateiHDO, argv[1]);
  strcat(dateiHDO, ".HDO");
  printf("PASS 1: Creating document file %s\n",dateiHDO);
  fdoc = fopen(dateiHDO,"wt");
  if (fdoc==NULL)
  {
    printf("File %s cannot be created\n",dateiHDO);
    fclose (fdoc);
    exit(EXIT_FAILURE);
  }

  for (;;)
  {
    CHAR line[80];
    if (fscanf(fsrc,"%s",line)==EOF)
      break;
    else
    {
      INT error=process_HEX(line,fdoc,0);
      if (error)
      {
        printf("error:%i\n",error);
        exit(EXIT_FAILURE);
      }
    }
  }

  // find programmed area
  // ********************
  // find begin
  UINT a=0;
  UINT anf=0;
  UINT end=BUFFLEN-1;
  UINT anf0=anf;
  UINT end0=end;
  INT found = 0;
  do
  {
    for (UINT aa=0; aa<64; aa++)
    {
      if (anf0==0)
        if (buffer[anf+aa])
          anf0=anf+aa;
      found += buffer[anf+aa];
    }
    if (!found)
      anf+=64;
  }
  while (!found);

  // find end
  found=0;
  do
  {
    for (UINT aa=0; aa<64; aa++)
    {
      if (end0==BUFFLEN-1)
        if (buffer[end-aa])
          end0=end-aa;
      found += buffer[end-aa];
    }
    if (!found)
      end-=64;
  }
  while (!found);

  // display programmed area
  a=anf;
  fprintf(fdoc,"\nprogrammed bytes\n");
  while (a<end)
  {
    fprintf(fdoc,"%x:",a);
    for (UINT aa=0; aa<64; aa++)
      fprintf(fdoc,"%c",buffer[a+aa]+'0');
    a+=64;
    fprintf(fdoc,"\n");
  }

  // bounds
  fprintf(fdoc,"programmed area: %4x..%4x\n",anf0,end0);
  fprintf(fdoc,"displayed area: %4x..%4x\n",anf,end);
  fprintf(fdoc,"eprom from: %4x to %4x\n",0, epromend-eprombeg);

  printf("EPROM from %4x to %4x\n",eprombeg, epromend);

  fclose(fdoc);

  eprombeg=0xffff;
  epromend=0x0000;

  // Create BIN-File
  // ***********************************************
  FILE *fbin=NULL; // binary-file
  CHAR dateiBIN[128];
  strcpy(dateiBIN, argv[1]);
  strcat(dateiBIN, ".BIN");
  printf("PASS 2: Creating binary file %s\n",dateiBIN);
  fbin = fopen(dateiBIN,"wb");
  if (fbin==NULL)
  {
    printf("File %s cannot be created\n",dateiBIN);
    fclose (fbin);
    exit(EXIT_FAILURE);
  }

  rewind(fsrc);

  for (;;)
  {
    CHAR line[80];
    if (fscanf(fsrc,"%s",line)==EOF)
      break;
    else
    {
      INT error=process_HEX(line,fbin,1);
      if (error)
      {
        printf("error:%i\n",error);
        exit(EXIT_FAILURE);
      }
    }
  }

  printf("EPROM from %4x to %4x\n",eprombeg, epromend);

  fwrite(&buffer[eprombeg],1,epromend-eprombeg+1,fbin);
  fclose(fbin);

  fclose(fsrc);
  exit(EXIT_SUCCESS);
}

