/*
 * Srecord Downloader
 * Holger Lehmann
 * Kabat Projekt
 */

#include <stdio.h>
#include <string.h>
#ifndef TEST
#include <hwdefs.h>
#else
#include <ctype.h>
#endif


static char digits[16] =
{
  '0', '1', '2', '3', '4', '5', '6', '7',
  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

int ch_atoi (char c){
  int value;

  value = 0;

  while ( ( value < 16 ) && ( c != digits[value] ) )
    value++;

  if ( c != digits[value] )
    return ( -1 );
  else
    return ( value );
}

int hextoi (char *s){
  int sum, val;

  sum = 0;
  while (*s != '\0')
    {
      if ( (val = ch_atoi ( (char) toupper (*s++) ) ) == -1 )
	return ( -1 );
      else
	sum = sum * 16 + val;
    }

  return ( sum );
}

#ifndef TEST
char * strncpy (char *s1, char *s2, int n){
  /* copies n chars from s2 into s1 and terminates it with a nul char */
  int i;
  char *sp;

  sp = s1;
  i = 0;
  for (i = 0; (i < n) && *s2; i++)
    *s1++ = *s2++;

  *s1 = '\0';

  return (sp);
}
#endif

#if 0
char * strcpy (char *s1, char *s2){
  /* copies the chars from s2 into s1 and terminates it with a nul char */
  int i;
  char *sp;

  sp = s1;
  i = 0;
  for (i = 0; *s2; i++)
    *s1++ = *s2++;

  *s1 = '\0';

  return (sp);
}
#endif

u_long InterpretS1( char * Line ){
  int Length,i;
  u_long Adress, Val ,Retval;
  char * pMem , temp[5];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  /*   if ( Length != 3 ) */
  /*     return 0; */
  Checksum = (char) Length;

  strncpy( temp , &Line[2] , 4 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[4] = '\0';
#endif
  Adress = hextoi ( temp );
  pMem = (void *)Adress;
#ifdef TEST
  printf ("My Hexaddr would be: %p\n", pMem);
#endif

  for ( i = 6 ; i < ( Length * 2 ) ; i += 2 ){
    strncpy( temp , &Line[i] , 2 );
#ifdef TEST
    /* Linux macht beim strncpy kein \0 */
    temp[2] = '\0';
#endif
#ifndef TEST
    *pMem = (char)hextoi ( temp );
#else
    printf("Adresse %p: %x\n",pMem,hextoi ( temp ));
#endif
    pMem++;
  }

  for ( i = 2 ; i < ( Length * 2 ) ; i += 2 ){
    strncpy( temp , &Line[i] , 2 );
#ifdef TEST
    /* Linux macht beim strncpy kein \0 */
    temp[2] = '\0';
#endif
    Val = hextoi ( temp );
    Checksum += (char) Val;
  }

  strncpy( temp , &Line[i] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if( ( (unsigned char) hextoi ( temp ) + (unsigned char) Checksum ) != (unsigned char) 0xff )
    Retval = 0;

  Retval = Adress ;

  return Retval;
}

u_long InterpretS2( char * Line ){
  int Length,i;
  u_long Adress ,Val ,Retval;
  char * pMem , temp[7];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  /*   if ( Length != 3 ) */
  /*     return 0; */
  Checksum = (char) Length;

  strncpy( temp , &Line[2] , 6 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[6] = '\0';
#endif
  Adress = hextoi ( temp );
  pMem = (void *)Adress;
#ifdef TEST
  printf ("My Hexaddr would be: %p\n", pMem);
#endif

  for ( i = 8 ; i < ( Length * 2 ) ; i += 2 ){
    strncpy( temp , &Line[i] , 2 );
#ifdef TEST
    /* Linux macht beim strncpy kein \0 */
    temp[2] = '\0';
#endif
#ifndef TEST
    *pMem = (char)hextoi ( temp );
#else
    printf("Adresse %p: %x\n",pMem,hextoi ( temp ));
#endif
    pMem++;
  }

  for ( i = 2 ; i < ( Length * 2 ) ; i += 2 ){
    strncpy( temp , &Line[i] , 2 );
#ifdef TEST
    /* Linux macht beim strncpy kein \0 */
    temp[2] = '\0';
#endif
    Val = hextoi ( temp );
    Checksum += (char) Val;
  }

  strncpy( temp , &Line[i] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if( ( (unsigned char) hextoi ( temp ) + (unsigned char) Checksum ) != (unsigned char) 0xff )
    Retval = 0;

  Retval = Adress ;

  return Retval;
}

u_long InterpretS3( char * Line ){
  int Length,i;
  u_long Adress = 0 ,Val ,Retval;
  char * pMem , temp[9];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  /*   if ( Length != 3 ) */
  /*     return 0; */
  Checksum = (char) Length;
  pMem = (void *)Adress;
#ifdef TEST
  printf ("My Hexaddr would be: %p\n", pMem);
#endif

  for ( i = 10 ; i < ( Length * 2 ) ; i += 2 ){
    strncpy( temp , &Line[i] , 2 );
#ifdef TEST
    /* Linux macht beim strncpy kein \0 */
    temp[2] = '\0';
#endif
#ifndef TEST
    *pMem = (char)hextoi ( temp );
#else
    printf("Adresse %p: %x\n",pMem,hextoi ( temp ));
#endif
    pMem++;
  }

  strncpy( temp , &Line[2] , 8 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[8] = '\0';
#endif
  Adress = hextoi ( temp );

  for ( i = 2 ; i < ( Length * 2 ) ; i += 2 ){
    strncpy( temp , &Line[i] , 2 );
#ifdef TEST
    /* Linux macht beim strncpy kein \0 */
    temp[2] = '\0';
#endif
    Val = hextoi ( temp );
    Checksum += (char) Val;
  }

  strncpy( temp , &Line[i] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if( ( (unsigned char) hextoi ( temp ) + (unsigned char) Checksum ) != (unsigned char) 0xff )
    Retval = 0;

  Retval = Adress ;

  return Retval;
}

u_long InterpretS5( char * Line ){
  int Length;
  u_long Val ,Retval;
  char temp[5];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  if ( Length != 3 )
    return 0;
  Checksum = (char) Length;

  strncpy( temp , &Line[2] , 4 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[4] = '\0';
#endif
  Retval = hextoi ( temp );
  
  strncpy( temp , &Line[2] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[4] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;

  strncpy( temp , &Line[6] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if ( ( 0xff - Checksum ) != (char) hextoi ( temp ) )
    return 0;

  return Retval;
}

u_long InterpretS7( char * Line , u_long * Retval ){
  int Length;
  u_long Adress ,Val;
  char temp[9];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  if ( Length != 5 )
    return 0;
  Checksum = (char) Length;
  strncpy( temp , &Line[2] , 8 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[8] = '\0';
#endif
  Adress = hextoi ( temp );
  
  strncpy( temp , &Line[2] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[4] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[6] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[8] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;

  strncpy( temp , &Line[10] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if( ( (unsigned char) hextoi ( temp ) + (unsigned char) Checksum ) != (unsigned char) 0xff )
    *Retval = 0;
  else
    *Retval = Adress ;

  return *Retval;
}

u_long InterpretS8( char * Line , u_long * Retval ){
  int Length;
  u_long Adress ,Val;
  char temp[7];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  if ( Length != 4 )
    return 0;
  Checksum = (char) Length;

  strncpy( temp , &Line[2] , 6 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[6] = '\0';
#endif
  Adress = hextoi ( temp );
  
  strncpy( temp , &Line[2] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[4] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[6] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;

  strncpy( temp , &Line[8] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if( ( (unsigned char) hextoi ( temp ) + (unsigned char) Checksum ) != (unsigned char) 0xff )
    *Retval = 0;
  else
    *Retval = Adress ;

  return *Retval;
}

u_long InterpretS9( char * Line , u_long * Retval ){
  int Length;
  u_long Adress ,Val;
  char temp[5];
  char Checksum;

  strncpy( temp , Line , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Length = hextoi ( temp );
  if ( Length != 3 )
    return 0;
  Checksum = (char) Length;

  strncpy( temp , &Line[2] , 4 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[4] = '\0';
#endif
  Adress = hextoi ( temp );
  
  strncpy( temp , &Line[2] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;
  strncpy( temp , &Line[4] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  Val = hextoi ( temp );
  Checksum += (char) Val;

  strncpy( temp , &Line[6] , 2 );
#ifdef TEST
  /* Linux macht beim strncpy kein \0 */
  temp[2] = '\0';
#endif
  if( ( (unsigned char) hextoi ( temp ) + (unsigned char) Checksum ) != (unsigned char) 0xff )
    *Retval = 0;
  else
    *Retval = Adress ;

  return *Retval;
}


u_long Srecord(){
  /* POST: die Startadresse des Programms oder 0 bei Fehler */
#ifdef TEST
  char Line[550];
#else
  char * Line;
#endif
  u_long NumDataRecords = 0, CountedDataRecords = 0 , Success = 0;
  int EndOfSRecordSeen = 0;

  u_long Startadress = 0;


  printf("Beginne mit dem SRecord download ...\n");


  do{
#ifdef TEST
    gets(Line);
#else
    Line = kgets();
#endif
    printf("\nHabe\n"
	   "-------------------------\n%s\n"
	   "-------------------------\n"
	   "zum Interpretieren erhalten\n",Line);

    printf("Type: %c\n",Line[1]);
    switch (Line[1]){
    case '0':
      printf("InterpretS0\n");
      printf("Header weggeworfen\n");
      /* discarded */
      break;
    case '1':
      printf("InterpretS1\n");
      Success = InterpretS1(&(Line[2]));
      if( ! Success ){
	Startadress = 0;
	EndOfSRecordSeen = 1;
      }
      CountedDataRecords++;
      break;
    case '2':
      printf("InterpretS2\n");
      Success = InterpretS2(&(Line[2]));
      if( ! Success ){
	Startadress = 0;
	EndOfSRecordSeen = 1;
      }
      CountedDataRecords++;
      break;
    case '3':
      printf("InterpretS3\n");
      Success = InterpretS3(&(Line[2]));
      if( ! Success ){
	Startadress = 0;
	EndOfSRecordSeen = 1;
      }
      CountedDataRecords++;
      break;
    case '5':
      printf("InterpretS5\n");
      NumDataRecords = InterpretS5(&(Line[2]));
      if ( NumDataRecords != CountedDataRecords ){
	Startadress = 0;
	EndOfSRecordSeen = 1;
      }
      break;
    case '7':
      printf("InterpretS7\n");
      InterpretS7(&(Line[2]),&Startadress);
      if( ! Success ){
	Startadress = 0;
      }
      EndOfSRecordSeen = 1 ;
      break;
    case '8':
      printf("InterpretS8\n");
      InterpretS8(&(Line[2]),&Startadress);
      if( ! Success ){
	Startadress = 0;
      }
      EndOfSRecordSeen = 1 ;
      break;
    case '9':
      printf("InterpretS9\n");
      InterpretS9(&(Line[2]),&Startadress);
      if( ! Success ){
	Startadress = 0;
      }
      EndOfSRecordSeen = 1 ;
      break;
    case '4':
    case '6':
    default:
      Startadress = 0;
      EndOfSRecordSeen = 1;
    }
    putchar('.');
#ifdef TEST
    fflush(stdout);
#endif
  }while( ! EndOfSRecordSeen );


  if((Startadress)==0)
    printf("%s: Startadress: (nil)\n" , __PRETTY_FUNCTION__  );
  else
    printf("%s: Startadress: 0x%lx\n" , __PRETTY_FUNCTION__ , Startadress );
  return Startadress;
}

#ifdef TEST
int main(){
  u_long Start;
  return Srecord(&Start);
}
#endif
