/*SCCS header -          %W%   %G%                                     */
/************************************************************************ 
*                                                                       * 
*                      Filename:        x2x_main.c                      *      
*                       Version:        0.0                             * 
*                       Author :        Gary Duncan                     * 
*					24 Inkster St                   *
*					Kambah ACT 2902                 *
*					Australia                       *
*                                                                       * 
*-----------------------------------------------------------------------*/

#include "x2x_amiga.h"
#include "x2x_data.c"
extern uchar Ichar();
extern char *MakeDate[] ;
/*************************************************************************
* 
* Modification record 
* ------------------- 
* 
* Date         By whom             Change 
* ----         -------             ------ 
* 
* 12 Apr 89     GMD                AMIGA'd
* 
*------------------------------------------------------------------------ 
*  
*    This program will convert a given file in Down-Line Load (DLL) format 
*    to another (or the same)  DLL format .  
* 
*    The DLL formats are the usual ASCII_hex formats of  
*    INTEL / TEKTRONIX ( and extended) /  MOTOROLA (S1-3)  
* 
*    If no input params , the program solicits for :- 
* 
*        1) Input File name ( which it then scans to determine DLL format) 
*        2) Output file DLL format 
*        3) Output DLL record DATA length ( 0 < len < 256 ) 
* 
*   ( In MOTOROLA format , prompts are made for addr length , ie 2,3, 4 bytes)  
* 
*      else ( if there are params ) , it is invoked as follows :- 
* 
*      x2x -Ifilename -Otype [-Srecord_data_length] 
* 
*      type :  I=INTEL , T=TEKTRONIX ,t= TEKTRONIX (extended) 
*              M1=MOTOROLA (S1) , M2=MOTOROLA (S2) M3=MOTOROLA (S3) 
*     
* 
* Output file name generation 
*----------------------------- 
* 
* VAX 
* 
*    The input file name then has ".xi / .xt / .xm2,3,or4 / or .xq appended 
*    to form the output file name. Note that no overwrite check is done. 
*    e.g  fred.xi -> fred.xi.xi -> fred.xi.xi.x(whatever) etc  
* 
* PC 
* 
*    A filename in wonderful MS_DOS is limited to the form of :- 
*    <8 charas max>.< 3 charas max> thus appending ( appension ?) to 
*    avoid ambiguity is not possible thus we progressively "backspace" 
*    from the "." separator looking for a non-'&' chara which is then 
*    transformed to '&'. 
*    e.g   (INTEL to INTEL ) , abcdef.xi -> abcde&.xi -> abcd&&.xi etc  

*     
*    Note that there is no restriction on cross-conversion ; ie you can 
*    use this program to produce a file of the same format but of a different  
*    data length. ( This could be useful because utilities such as  AZTEC  
*    'hex86' program only create DLL records  with the boring length of 16)  
* 
*    Whilst running , the program displays dots before the eyes to soothe 
*    those who are nervous about silent programs. 
* 
* 
* On Completion 
* ------------- 
*                 ... some nice stats are presented. Note that the  
*                checksum is a one_byte_sum_with_carry_wrap of the data  
*                bytes ( a la MICE ) so if using the MICE you can verify  
*                the Down Line Load with its memory checksum command (T). 
*                ( valid only for contiguous load , of course )  
* 
************************************************************************* 
* 
*                                                                       * 
*         This program  will run on a uVAX or IBM PC                    * 
*                                                                       * 
*  VAX build    :   cc -o x2x x2x.c        ( produces x2x* )            * 
*                                                                       * 
*  IBM PC  "    :   cc -DAMIGA x2x.c                                    * 
*                   ln x2x.o \lib\c.lib \lib\s.lib                      * 
*                                              ( produces x2x.exe )     * 
*                                                                       * 
*                                                                       * 
************************************************************************* 
 
* 
############################################################################# 
# 
#  Examples of ACSII-hex formats for :- 
# 
#    INTEL 
#    MOTOROLA 
#    TEKTRONIX ( inc extended format ) 
# 
# 
#  Note: the INTEL example (data length 16dec bytes) is the reference. 
#      : in following "byte" =  binary value of 2 ASCII-hex charas 
#                               hi nibble = 1st byte  
# 
############################################################################# 
 
# 
# Format :  INTEL 
# 
 
:LLAAAATTdd..ddCC 
 
LL   = # of data bytes  
AAAA = 16 bit address 
TT   = type  
        0 = data 
        1 = end record 
        2 = Upper Segment Base Address (USBA) 
        3 = start address record ( data length = 4 bytes) 
 
CC   = checksum ( = -ve sum of record : ie sum of all byte-pairs = 0 ) 
dd = ASCII-hex charas 
 
USBA format = :02000002ssssCC 
( following data records will be have (16 * ssss) added to their load addr) 
 
 
---------------------------------------------------------------------------- 
 
:020000020500??                              # type 2 record , base = 500H 
:1012340090FAFCE96B002020202020202020202090  # type 0 record (data) 
                                             #      (load addr = 1234H) 
:00000001FF                                  # type 1 record (end) 
 
# above converted to :- 
 
:1062340090FAFCE96B002020202020202020202040    <<EXAMPLE 
:00000001FF 
 
#----------------------------------------------------------------------------- 
# 
#  MOTOROLA - all use S9 as end record 
# 
# 
# Format :  Motorola ( S1 , 16 bit address ) 
# 
    |<-------------- LL ---------------->| 
S1LLAAAAdd..ddCC                             << Format 
 
LL = 2 + (# of data bytes) + 1    
AAAA = address 
CC = ~( LL + (AA .. + AA) + ( data bytes ))  : Note 1's complement! 
 
 
S1LLAAAAdd..ddCC                              << Format 
S113623490FAFCE96B00202020202020202020203C    <<EXAMPLE 
S9030000FC 
 
#----------------------------------------------------------------------------- 
# 
# Format :  Motorola ( S2 , 24 bit address ) 
# 
S2LLAAAAAAdd..ddCC                              << Format 
S21400623490FAFCE96B00202020202020202020203B    <<EXAMPLE 
S904000000FB 
 
#----------------------------------------------------------------------------- 
# 
# Format :  Motorola ( S3 , 32 bit address ) 
# 
STLLAAAAAAAAdd..ddCC                              << Format 
S3150000623490FAFCE96B00202020202020202020203A    <<EXAMPLE 
S90500000000FA 
 
#----------------------------------------------------------------------------- 
# 
# Format :  Tektronix 
# 
#  Note checksum algorithm 
# 
/AAAALLRRdd..ddCC    << Format 
 
AAAA = load address 
LL   = record length ( # of data bytes : 0 = last record ) 
RR   = load checksum ( = sum of previous 6 de-ASCII'd CHARAS ) 
CC   = data    "     ( sum of de-ASCII'D CHARAS ) 
 
/AAAALLRRdd..ddCC                              << Format 
/6234101090FAFCE96B002020202020202020202079    <<EXAMPLE 
/00000000 
 
#----------------------------------------------------------------------------- 
# 
# Format :  Tektronix (extended) 
# 
#  Note checksum algorithm 
# 
%LLTCCky......ydd..dd    << Format 
 
LL = length ( all charas after % ) 
T  = type chara ( 6 = data , 8 = end ) 
CC = checksum   ( sum of all de-ASCII'd CHARAS = 0 ) 
k  = # of address charas, max 8 ( = 4 bytes ) 
y...y = 'k' address charas 
xx =  data as usual 
 
  
%LLTCCky......ydd..dd    << Format 
 
%2E6A680000623490FAFCE96B0020202020202020202020    <<EXAMPLE 
%0E81E800000000 
 
 
* 
*------------------------------------------------------------------------------ 
* Contents 
* ------- 
*+ 
*+              main            exec bit..           
*+              getc2           gets byte from 2 ASCII hex bytes 
*+              convc2          converts 2 ASCII hex bytes to a byte 
*+              get_hex         converts ASCII hex chara to binary 
*+              Ichar           gets chara from input file 
*+  
* 
******************************************************************************/ 


 
/*------------------------------------------------------------------------*/ 
 
main (argc,argv) 
int argc; 
char *argv[]; 
 
{ 
int temp ; 
 
 
 /*----------------------- announce program / vers -------------------------*/ 
 

 printf ( "\nX2X - %s : written by Gary Duncan\n" , MakeDate[0]  ) ; 

 iffp = 0 ; 
 opftype = -1 ;                 /* invalidate things */ 
 
 if ( argc == 1 )                /* no params , solicit for them */ 
   sol_params () ;          
 else                            /* use command line params then */ 
   xmode = com_params ( argc , argv ) ; 
 
 
 /*------------------------   build o/p file here -------------------------*/ 
 
 f_reset () ; 
 
 xlen = 1 ;  
 while ( xlen )                      /* loop to process input file  */ 
   {  
 #if 0
     if ( func1 () )                /* PC only - exit on FUNC1   */ 
       exit (1) ; 
 #endif

     fill_ipbuf () ;                    /* fill input data buffer */ 
     xaddr = 0 ; 
     xlen = get_len ( &xaddr ) ;        /* find length of continuous chunk */ 
     
     switch ( opftype ) 
     { 
       case 0 :                      /* INTEL  */ 
 
         if ( ousba != ousban )  /* .. build a type 2 record maybe ? */ 
           { 
             ousba = ousban ; 
             xdllen = dll_Irec ( 2 , (long)ousba  , 2 ) ;   /* gen record */ 
 
             opbuf [xdllen++] = '\n' ;     /* append RETURN  to  record */ 
     
             rite_rec ( offp , opbuf , xdllen ) ;   /* write it */ 
             ++oprecs ; 
           }             
 
         if (xlen)     /* end record ? */ 
            { 
              xtype = 0 ;                     /* no */ 
            } 
         else                  /* yes , maybe insert checksum record */ 
            { 
              xtype = 1 ;  
              if ( xmode == 3 )    /* checksum mode ? */ 
		{ 
                   gen_csum () ;   /* build and write last data rec */ 
		} 
            }  
		 
         xdllen = dll_Irec ( xtype, xaddr, xlen ) ;  /* build INTEL record  */ 
          
         break ; 
  
       case 1 :                     /* MOTOROLA  */ 
       case 2 : 
       case 3 :   
 
         (xlen) ? (xtype = opftype + '0') : (xtype = '9') ; 
                                                     /* data or eof rec type */ 
          xdllen =  dll_Mrec ( xtype , xaddr , xlen )  ; 
        	 break ; 
 
       case 4 :                       /* TEKTRONIX  */ 
 
          xdllen  = dll_Trec ( 0 , xaddr ,xlen ) ; 
          break ; 
 
       case 5 :                       /* TEKTRONIX - extended   */ 
          
 
         (xlen) ? (xtype = '6') : (xtype = '8') ; /* data or eof rec type */ 
 
          xdllen  = dll_Txrec ( xtype , xaddr ,xlen ) ; 
          break ; 
 
       case 6 :                        /* QTAM  */ 
           
          xdllen = dll_Qrec ( 0 , xaddr , xlen ) ; 
          break ; 
 
       }  ; 
 
  /*--------------now write record to disc ----------------------------------*/ 
 
    ++datarecs ; 
    ++oprecs ; 
    totchars += xlen ;                  /* update total data chara count */ 
 
    opbuf [xdllen++] = '\n' ;            /* append RETURN  to each record */ 
     
    rite_rec ( offp , opbuf , xdllen ) ;   /* write it */ 
 
    if ( (!(totchars & 0x3FF) )  && (!pdots)  )                        
       fprintf ( stderr , "." ) ;   /* dots before the eyes.... , every 1K */ 
 
 
   } 
 
/*-------------------- FIN , print a message -------------------------------*/ 
 
  if ( odccon )                                  /* flush write buffer */ 
   {  
    if ( write( offp , dlldbuf , odccon) != odccon ) 
       {    
        perror("Disc write error: "); 
        exit(3); 
       } 
   } 
 
       printf (  "\nOutput file is :  %s\n" , ofile  ) ; 
       printf ( "*** Total recs = %d, Data recs = %d \n", oprecs , datarecs ) ; 
       printf ( "*** Reclen = %d, Data chars = %ldDec/%lXH \n", 
                       reclen , totchars, totchars ) ; 
 
    /*--------- if -P/-C  option , put printable charas in checksum buffer 
                into "temp.x2x" ( bit of a kluge for documentation) ----*/ 
 
      if ( temp = strlen ( mallocptr ) ) 
        if ( write( tffp , mallocptr , temp ) != temp ) 
              {    
                 fprintf (stderr,"(rite_rec) - write error" ); 
                 perror("Disc write error: "); 
                 exit(3); 
              } 
             
 
        
    exit (0) ; 
 
} 
 
 
/*************************************************************************** 
 
 
  Function :      getc2 
 
  Purpose  : 
 
  Entry    : 
 
  Returns  :     TRUE -  
 
                 FALSE- 
 
 
 
****************************************************************************/ 
 
int  getc2 (  )       /* returns with de-hexed byte  
			     from 2 ASCII hex bytes       */ 
 
 
 
{ 
  int c , c0 , c1  ; 
 
  if ( (c = Ichar ()) == -1 )                  /* MS nibble   */ 
    { 
       fprintf ( stderr , "\Ichar fail" ) ; 
       exit (3) ; 
    } 
  if ( (c0 = get_hex (c) ) == -1 ) 
    { 
       fprintf ( stderr , "\Non ASCII-hex chara in file = %c " , c ) ; 
       exit (3) ; 
    } 
 
  if ( (c = Ichar ()) == -1 )                  /* MS nibble   */ 
    { 
       fprintf ( stderr , "\Ichar fail" ) ; 
       exit (3) ; 
    } 
  if ( (c1 = get_hex (c) ) == -1 ) 
    { 
       fprintf ( stderr , "\Non ASCII-hex chara in file" ) ; 
       exit (3) ; 
    } 
 
  c = (( c0 << 4 )  | c1 )  ;     
 
  return ( c & 0xFF ) ;         /* ensure return byte here only  */ 
 
} 
 
 
/*************************************************************************** 
 
 
  Function :      convc2 
 
  Purpose  :      converts byte to 2 ASCII hex charas  
 
  Entry    : 
 
  Returns  :      (hi byte/lo byte)  as int  
 
 
 
 
****************************************************************************/ 
 
int  convc2 ( bite  ) 
 
unsigned char bite ; 
 
 
{ 
  unsigned char cc , k  ; 
  unsigned int chch = 0  ; 
 
   cc = bite  ; 
 
   k = cc ; 
 
    cc = (k >> 4) & 0xF ;     /* MS nibble  */ 
 
  (cc < 0xA) ? ( cc = cc + '0') : ( cc = cc + 'A' - 10 ) ;  
 
  chch = (int) cc << 8  ;            /*Hi  nibble  */ 
 
  cc = k & 0xF ; 
 
  (cc < 0xA) ? ( cc = cc + '0') : ( cc = cc + 'A' - 10 ) ;  
  
  return ( chch | cc ) ; 
 
} 
 
/*************************************************************************** 
 
 
  Function :    get_hex 
 
  Purpose  :    Returns with given ASCII hex chara de-ASCIIed 
 
  Entry    :    chara 
 
  Returns  :     - 1 , error , else chara ( 0 > 15 )  
 
 
 
 
**************************************************************************/ 
 
int get_hex ( bite )  
 
 
uchar bite ; 
 
{ 
   if ( isdigit (bite) ) 
      return ( bite & 0xF ) ;                  /* number */ 
 
  bite |= 0x20 ; 
 
  if ( islower (bite) && ( bite < 'g')  ) 
     return ( (bite & 0xF) + 9 )   ;           /* A _ F */ 
 
  return ( -1 )  ;                             /* error */ 
 
} 
 
/*************************************************************************** 
 
 
  Function :    Ichar 
 
  Purpose  :    Returns with chara from input file 
 
  Entry    :    chara 
 
  Returns  :     - 1 , error , else chara  
 
 
 
 
**************************************************************************/ 
 
 
uchar Ichar () 
 
{ 
 int  ch ; 
 
   if ( boffs == -1 ) 
       return ( -1 ) ;            /* File empty */ 
 
   if ( !disclen ) 
     { 
       disclen =   read (iffp , dbuf , 1024 ) ; /* read a block of file */ 
       boffs = 0 ; 
     } 
 
   if ( !disclen ) 
      return ( -1 ) ; 
    
   ch =  dbuf[ boffs ] &0xFF  ; 
 
   xchek += ch ;                  /* accum a checksum for ext use */ 
 
   if (  ++boffs != disclen ) 
       return ( ch ) ; 
   else if ( boffs == 1024 ) 
       disclen  = 0 ;                 /* flag buffer empty */ 
   else  
       boffs = -1 ;                   /* flag file empty   */ 
 
   return ( ch ) ; 
   
} 
