[PATCH] packhex: Import from RTEMS

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Jun 7 05:49:15 UTC 2018


Corresponding RTEMS commit is 75933d5d25cd50f80162b7a0d2f66a5534e1763f.

Update #3379.
---
 misc/packhex/packhex.c | 541 +++++++++++++++++++++++++++++++++++++++++++++++++
 misc/wscript           |   9 +
 2 files changed, 550 insertions(+)
 create mode 100644 misc/packhex/packhex.c

diff --git a/misc/packhex/packhex.c b/misc/packhex/packhex.c
new file mode 100644
index 0000000..9619fa2
--- /dev/null
+++ b/misc/packhex/packhex.c
@@ -0,0 +1,541 @@
+/*****  P A C K H E X . C  ************************************************
+ *
+ *   Packhex is a hex-file compaction utility.  It attempts to concatenate
+ *   hex records to produce more size-efficient packaging.
+ *
+ *   Limitations: Input files must be correctly formatted.  This utility
+ *                is not robust enough to detect hex-record formatting
+ *                errors.
+ *
+ *   Published:   May 1993 Embedded Systems Programming magazine
+ *                "Creating Faster Hex Files"
+ *
+ *   URL:         ESP magazine: http://www.embedded.com
+ *                Source Code:  ftp://ftp.mfi.com/pub/espmag/1993/pakhex.zip
+ *
+ *   Author:      Mark Gringrich
+ *
+ *   Compiler:    Microsoft C 6.0
+ *                cl /F 1000 packhex.c
+ *
+ **************************************************************************/
+
+
+/* #define SMALLER_RECORDS */
+#ifdef SMALLER_RECORDS
+#define MAX_LEN_S1_RECS 128
+#define MAX_LEN_S2_RECS 128
+#define MAX_LEN_S3_RECS 128
+#else
+#define MAX_LEN_S1_RECS 252
+#define MAX_LEN_S2_RECS 251
+#define MAX_LEN_S3_RECS 250
+#endif
+
+
+/*--------------------------------- includes ---------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__unix__) && !defined(EXIT_FAILURE)
+#define EXIT_FAILURE -1
+#define EXIT_SUCCESS  0
+#endif
+
+/*--------------------------------- defines ----------------------------------*/
+
+#define YES                   1
+#define MAX_LINE_SIZE       600
+#define EOS                 '\0'
+
+
+/*---------------------------------- macros ----------------------------------*/
+
+/* Convert ASCII hexadecimal digit to value. */
+
+#define HEX_DIGIT( C )   ( ( ( ( C ) > '9' ) ? ( C ) + 25 : ( C ) ) & 0xF )
+
+
+/*--------------------------------- typedefs ---------------------------------*/
+
+typedef unsigned char   Boolean;
+typedef unsigned char   Uchar;
+typedef unsigned int    Uint;
+typedef unsigned long   Ulong;
+
+typedef struct   /* Functions and constant returning Hex-record vital stats. */
+{
+    Boolean    ( *is_data_record  )( char *              );
+    Ulong      ( *get_address     )( char *              );
+    Uint       ( *get_data_count  )( char *              );
+    const Uint    max_data_count;
+    char      *( *get_data_start  )( char *              );
+    void       ( *put_data_record )( Uint, Ulong, char * );
+} Rec_vitals;
+
+
+/*--------------------------- function prototypes ----------------------------*/
+
+Rec_vitals  * identify_first_data_record( char *, int );
+Ulong         get_ndigit_hex( char *, int );
+
+
+/*----------------------------- Intel Hex format -----------------------------*/
+
+/*
+ *    Intel Hex data-record layout
+ *
+ *    :aabbbbccd...dee
+ *
+ *    :      - header character
+ *    aa     - record data byte count, a 2-digit hex value
+ *    bbbb   - record address, a 4-digit hex value
+ *    cc     - record type, a 2-digit hex value:
+ *              "00" is a data record
+ *              "01" is an end-of-data record
+ *              "02" is an extended-address record
+ *              "03" is a start record
+ *    d...d  - data (always an even number of chars)
+ *    ee     - record checksum, a 2-digit hex value
+ *             checksum = 2's complement
+ *                 [ (sum of bytes: aabbbbccd...d) modulo 256 ]
+ */
+
+
+Boolean is_intel_data_rec( char * rec_str )
+{
+    return( ( rec_str[ 0 ] == ':' )  &&  ( rec_str[ 8 ] == '0' ) );
+}
+
+Uint get_intel_rec_data_count( char * rec_str )
+{
+    return( ( Uint ) get_ndigit_hex( rec_str + 1, 2 ) );
+}
+
+Ulong get_intel_rec_address( char * rec_str )
+{
+    return( get_ndigit_hex( rec_str + 3, 4 ) );
+}
+
+char * get_intel_rec_data_start( char * rec_str )
+{
+    return( rec_str + 9 );
+}
+
+void put_intel_data_rec( Uint count, Ulong address, char * data_str )
+{
+    char    *ptr;
+    Uint    sum = count + ( address >> 8 & 0xff ) + ( address & 0xff );
+
+    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+    printf(
+      ":%02X%04lX00%s%02X\n", count, address, data_str, (~sum + 1) & 0xff
+    );
+}
+
+
+Rec_vitals  intel_hex =
+{
+    is_intel_data_rec,
+    get_intel_rec_address,
+    get_intel_rec_data_count,
+    255,                        /* Maximum data bytes in a record. */
+    get_intel_rec_data_start,
+    put_intel_data_rec
+};
+
+
+/*------------------------- Motorola S1-record format ------------------------*/
+
+/*
+ *    Motorola S-record data-record layout
+ *
+ *    Sabbc...cd...dee
+ *
+ *    S      - header character
+ *    a      - record type, a 1-digit value:
+ *               "0" is a header record
+ *               "1" is a 2-byte-address data record
+ *               "2" is a 3-byte-address data record
+ *               "3" is a 4-byte-address data record
+ *               "7" is a 4-byte-address end-of-data record
+ *               "8" is a 3-byte-address end-of-data record
+ *               "9" is a 2-byte-address end-of-data record
+ *    bb     - record length in bytes, a 2-digit hex value
+ *             (record length doesn't count the header/type
+ *              chars and checksum byte)
+ *    c...c  - record address, a 4-, 6-, or 8-digit value,
+ *               depending on record type
+ *    d...d  - data (always an even number of chars)
+ *    ee     - record checksum, a 2-digit hex value
+ *             checksum = 1's complement
+ *             [ (sum of all bytes: bbc..cd...d) modulo 256 ]
+ */
+
+#define S1_COUNT_OFFSET         3
+
+
+Boolean is_moto_s1_data_rec( char * rec_str )
+{
+    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '1' ) );
+}
+
+Uint get_moto_s1_rec_data_count( char * rec_str )
+{
+    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S1_COUNT_OFFSET );
+}
+
+Ulong get_moto_s1_rec_address( char * rec_str )
+{
+    return( get_ndigit_hex( rec_str + 4, 4 ) );
+}
+
+char * get_moto_s1_rec_data_start( char * rec_str )
+{
+    return( rec_str + 8 );
+}
+
+void put_moto_s1_data_rec( Uint count, Ulong address, char * data_str )
+{
+    char   *ptr;
+    Uint    sum = S1_COUNT_OFFSET + count +
+                    ( address >> 8 & 0xff ) + ( address & 0xff );
+
+    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+    printf(
+      "S1%02X%04lX%s%02X\n",
+      count + S1_COUNT_OFFSET, address, data_str, ~sum & 0xff
+    );
+}
+
+
+Rec_vitals  motorola_s1_rec =
+{
+    is_moto_s1_data_rec,
+    get_moto_s1_rec_address,
+    get_moto_s1_rec_data_count,
+    MAX_LEN_S1_RECS,            /* Maximum data bytes in a record. */
+    get_moto_s1_rec_data_start,
+    put_moto_s1_data_rec
+};
+
+
+/*------------------------- Motorola S2-record format ------------------------*/
+
+#define S2_COUNT_OFFSET         4
+
+Boolean is_moto_s2_data_rec( char * rec_str )
+{
+    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '2' ) );
+}
+
+Uint get_moto_s2_rec_data_count( char * rec_str )
+{
+    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S2_COUNT_OFFSET );
+}
+
+Ulong get_moto_s2_rec_address( char * rec_str )
+{
+    return( get_ndigit_hex( rec_str + 4, 6 ) );
+}
+
+char * get_moto_s2_rec_data_start( char * rec_str )
+{
+    return( rec_str + 10 );
+}
+
+void put_moto_s2_data_rec( Uint count, Ulong address, char * data_str )
+{
+    char    *ptr;
+    Uint    sum = S2_COUNT_OFFSET + count + ( address >> 16 & 0xff ) +
+                                            ( address >>  8 & 0xff ) +
+                                            ( address       & 0xff );
+
+    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+    printf(
+      "S2%02X%06lX%s%02X\n",
+      count + S2_COUNT_OFFSET, address, data_str, ~sum & 0xff
+    );
+}
+
+
+Rec_vitals  motorola_s2_rec =
+{
+    is_moto_s2_data_rec,
+    get_moto_s2_rec_address,
+    get_moto_s2_rec_data_count,
+    MAX_LEN_S2_RECS,            /* Maximum data bytes in a record. */
+    get_moto_s2_rec_data_start,
+    put_moto_s2_data_rec
+};
+
+
+/*------------------------- Motorola S3-record format ------------------------*/
+
+#define S3_COUNT_OFFSET         5
+
+Boolean is_moto_s3_data_rec( char * rec_str )
+{
+    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '3' ) );
+}
+
+Uint get_moto_s3_rec_data_count( char * rec_str )
+{
+    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S3_COUNT_OFFSET );
+}
+
+Ulong get_moto_s3_rec_address( char * rec_str )
+{
+    return( get_ndigit_hex( rec_str + 4, 8 ) );
+}
+
+char * get_moto_s3_rec_data_start( char * rec_str )
+{
+    return( rec_str + 12 );
+}
+
+void put_moto_s3_data_rec( Uint count, Ulong address, char * data_str )
+{
+    char    *ptr;
+    Uint     sum = S3_COUNT_OFFSET + count + ( address >> 24 & 0xff ) +
+                                             ( address >> 16 & 0xff ) +
+                                             ( address >>  8 & 0xff ) +
+                                             ( address       & 0xff );
+
+    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
+        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
+
+    printf(
+      "S3%02X%08lX%s%02X\n",
+      count + S3_COUNT_OFFSET, address, data_str, ~sum & 0xff
+   );
+}
+
+
+Rec_vitals  motorola_s3_rec =
+{
+    is_moto_s3_data_rec,
+    get_moto_s3_rec_address,
+    get_moto_s3_rec_data_count,
+    MAX_LEN_S3_RECS,            /* Maximum data bytes in a record. */
+    get_moto_s3_rec_data_start,
+    put_moto_s3_data_rec
+};
+
+
+/*-------------------- Put your favorite hex format here ---------------------*/
+
+/*
+ *    * * *  The following is a template for an additional hex format:  * * *
+ *
+ *
+ *    Boolean is_X_data_rec( char * rec_str ) {}
+ *
+ *    Uint get_X_rec_data_count( char * rec_str ) {}
+ *
+ *    Ulong get_X_rec_address( char * rec_str ) {}
+ *
+ *    char * get_X_rec_data_start( char * rec_str ) {}
+ *
+ *    void put_X_data_rec( Uint count, Ulong address, char * data_str ) {}
+ *
+ *    Rec_vitals  X_rec =
+ *    {
+ *        is_X_data_rec,
+ *        get_X_rec_address,
+ *        get_X_rec_data_count,
+ *        MAXIMUM DATA BYTES IN A RECORD,
+ *        get_X_rec_data_start,
+ *        put_X_data_rec
+ *    };
+ *
+ */
+
+/*----------------------------------------------------------------------------*/
+
+
+/*
+ *   Put address of additional Rec_vitals structures
+ *   in this array, before the NULL entry.
+ */
+
+Rec_vitals  *formats[] =
+{
+    &intel_hex,
+    &motorola_s1_rec,
+    &motorola_s2_rec,
+    &motorola_s3_rec,
+    ( Rec_vitals * ) NULL
+};
+
+
+/****   main   *****************************************************************
+*
+*
+*       Expects: Nothing (no command-line parameters).
+*
+*       Returns: Exit status (EXIT_SUCCESS or EXIT_FAILURE).
+*
+*       Reads hex records on the standard input and attempts to
+*       splice adjacent data fields together.  Results appear on
+*       the standard output.
+*
+*******************************************************************************/
+
+int main(void)
+{
+
+    char       inbuff[ MAX_LINE_SIZE ], outbuff[ MAX_LINE_SIZE ];
+    char       *in_dptr, *out_dptr;
+    int        d_total, d_count, d_excess, n;
+    int        length;
+    Ulong      in_rec_addr, out_rec_addr = 0;
+    Rec_vitals *rptr;
+
+
+    /* Sift through file until first hex record is identified.    */
+
+    rptr = identify_first_data_record( inbuff, MAX_LINE_SIZE );
+    if ( rptr == NULL )
+    {
+        fputs( "No hex records found.\n", stderr );
+        exit( EXIT_FAILURE );
+    }
+
+
+    /* Attempt data-record splicing until end-of-file is reached. */
+    d_total = 0;
+    for (;;) {
+        if ( rptr->is_data_record( inbuff ) == YES )
+        { /* Input record is a data record. */
+            d_count     = rptr->get_data_count( inbuff );
+            in_rec_addr = rptr->get_address( inbuff );
+            in_dptr     = rptr->get_data_start( inbuff );
+
+            if ( d_total == 0  ||  in_rec_addr != out_rec_addr + d_total )
+            { /* Begin a new output record. */
+                if ( d_total != 0 )
+                    rptr->put_data_record( d_total, out_rec_addr, outbuff );
+                out_dptr     = outbuff;
+                n = d_total  = d_count;
+                out_rec_addr = in_rec_addr;
+            }
+            else if
+              ( ( d_excess = d_total + d_count - rptr->max_data_count ) > 0 )
+            { /* Output a maximum-length record, then start a new record. */
+                strncat( outbuff, in_dptr, 2 * ( d_count - d_excess ) );
+                rptr->put_data_record(
+                  rptr->max_data_count, out_rec_addr, outbuff
+                );
+                in_dptr      += 2 * ( d_count - d_excess );
+                out_dptr      = outbuff;
+                n = d_total   = d_excess;
+                out_rec_addr += rptr->max_data_count;
+            }
+            else
+            { /* Append input record's data field with accumulated data. */
+                out_dptr = outbuff + ( 2 * d_total );
+                d_total += n = d_count;
+            }
+            strncpy( out_dptr, in_dptr, 2 * n );
+            out_dptr[ 2 * n ] = EOS;
+        }
+        else
+        { /* Not a data record;
+           * flush accumulated data then echo non-data record.
+           */
+            if ( d_total != 0 )
+            {
+                rptr->put_data_record( d_total, out_rec_addr, outbuff );
+                d_total = 0;
+            }
+            puts( inbuff );
+        }
+
+        inbuff[ MAX_LINE_SIZE - 1 ] = '\0';
+        if ( !fgets( inbuff, MAX_LINE_SIZE, stdin ) )
+           break;
+        if ( inbuff[ MAX_LINE_SIZE - 1 ] ) {
+           fprintf( stderr, "Input line too long" );
+           exit( 1 );
+        }
+        length = strlen(inbuff);
+        inbuff[length - 1] = '\0';
+
+    }
+
+
+    return ( EXIT_SUCCESS );
+
+}
+
+
+/****   identify_first_data_record   *******************************************
+*
+*       Expects: Pointer to hex-record line buffer.
+*
+*       Returns: Pointer to hex-record structure (NULL if no match found).
+*
+*       Reads the standard input, line by line, searching for a valid
+*       record header character.  If a valid header is found, a pointer
+*       to the hex-record's type structure is returned, otherwise NULL.
+*
+*       The input-stream pointer is left pointing to the first valid hex record.
+*
+*******************************************************************************/
+
+Rec_vitals * identify_first_data_record( char * buff_ptr, int max_length )
+{
+    Rec_vitals  ** ptr;
+    int            length;
+
+
+
+    for ( ;; ) {
+
+        buff_ptr[ max_length - 1 ] = '\0';
+        if ( !fgets( buff_ptr, max_length, stdin ) )
+           break;
+        if ( buff_ptr[ max_length - 1 ] ) {
+           fprintf( stderr, "Input line too long" );
+           exit( 1 );
+        }
+        length = strlen(buff_ptr);
+        buff_ptr[length - 1] = '\0';
+
+        for ( ptr = formats ; *ptr != ( Rec_vitals * ) NULL ; ptr++ )
+            if ( ( *ptr )->is_data_record( buff_ptr ) == YES )
+                return( *ptr );        /* Successful return.        */
+
+        puts( buff_ptr );              /* Echo non-hex-record line. */
+    }
+
+    return( ( Rec_vitals * ) NULL );   /* Unsuccessful return.      */
+}
+
+
+/****   get_ndigit_hex   *******************************************************
+*
+*       Expects: Pointer to first ASCII hexadecimal digit, number of digits.
+*
+*       Returns: Value of hexadecimal string as an unsigned long.
+*
+*******************************************************************************/
+
+Ulong get_ndigit_hex( char * cptr, int digits )
+{
+    Ulong    value;
+
+    for ( value = 0 ; --digits >= 0 ; cptr++ )
+        value = ( value * 16L ) + HEX_DIGIT( *cptr );
+
+    return( value );
+}
diff --git a/misc/wscript b/misc/wscript
index 137cf07..3aa5010 100644
--- a/misc/wscript
+++ b/misc/wscript
@@ -79,6 +79,15 @@ def build(bld):
                 linkflags = conf['linkflags'])
 
     #
+    # Build the packhex.
+    #
+    bld.program(target = 'rtems-packhex',
+                source = ['packhex/packhex.c'],
+                defines = defines,
+                cflags = conf['cflags'] + conf['warningflags'],
+                linkflags = conf['linkflags'])
+
+    #
     # Build the shgen.
     #
     bld.program(target = 'rtems-shgen',
-- 
2.13.7



More information about the devel mailing list