source: rtems/c/build-tools/src/packhex.c @ 2936b425

4.104.114.84.95
Last change on this file since 2936b425 was 2936b425, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 23, 1998 at 5:45:05 PM

Solaris port updates from Chris Johns

  • Property mode set to 100644
File size: 14.5 KB
Line 
1
2/*****  P A C K H E X . C  ************************************************
3 *
4 *   Packhex is a hex-file compaction utility.  It attempts to concatenate
5 *   hex records to produce more size-efficient packaging.
6 *
7 *   Limitations: Input files must be correctly formatted.  This utility
8 *                is not robust enough to detect hex-record formatting
9 *                errors.
10 *
11 *   Published:   5/93 Embedded Systems magazine
12 *
13 *   Compiler:    Microsoft C 6.0
14 *                cl /F 1000 packhex.c
15 *
16 *
17 *   $Id$
18 *
19 **************************************************************************/
20
21
22/* #define SMALLER_RECORDS */
23#ifdef SMALLER_RECORDS
24#define MAX_LEN_S1_RECS 128
25#define MAX_LEN_S2_RECS 128
26#define MAX_LEN_S3_RECS 128
27#else
28#define MAX_LEN_S1_RECS 252
29#define MAX_LEN_S2_RECS 251
30#define MAX_LEN_S3_RECS 250
31#endif
32
33
34/*--------------------------------- includes ---------------------------------*/
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39
40#include "config.h"
41
42#ifndef VMS
43#ifndef HAVE_STRERROR
44extern int sys_nerr;
45extern char *sys_errlist[];
46
47#define strerror( _err ) \
48  ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
49
50#else   /* HAVE_STRERROR */
51char *strerror ();
52#endif
53#else   /* VMS */
54char *strerror (int,...);
55#endif
56
57#if defined(__unix__) && !defined(EXIT_FAILURE)
58#define EXIT_FAILURE -1
59#define EXIT_SUCCESS  0
60#endif
61
62/*--------------------------------- defines ----------------------------------*/
63
64#define YES                   1
65#define MAX_LINE_SIZE       600
66#define EOS                 '\0'
67
68
69/*---------------------------------- macros ----------------------------------*/
70
71/* Convert ASCII hexadecimal digit to value. */
72
73#define HEX_DIGIT( C )   ( ( ( ( C ) > '9' ) ? ( C ) + 25 : ( C ) ) & 0xF )
74
75
76/*--------------------------------- typedefs ---------------------------------*/
77
78typedef unsigned char   Boolean;
79typedef unsigned char   Uchar;
80typedef unsigned int    Uint;
81typedef unsigned long   Ulong;
82
83typedef struct   /* Functions and constant returning Hex-record vital stats. */
84{
85    Boolean    ( *is_data_record  )( char *              );
86    Ulong      ( *get_address     )( char *              );
87    Uint       ( *get_data_count  )( char *              );
88    const Uint    max_data_count;
89    char      *( *get_data_start  )( char *              );
90    void       ( *put_data_record )( Uint, Ulong, char * );
91} Rec_vitals;
92
93
94/*--------------------------- function prototypes ----------------------------*/
95
96Rec_vitals  * identify_first_data_record( char * );
97Ulong         get_ndigit_hex( char *, int );
98
99
100/*----------------------------- Intel Hex format -----------------------------*/
101
102/*
103 *    Intel Hex data-record layout
104 *
105 *    :aabbbbccd...dee
106 *
107 *    :      - header character
108 *    aa     - record data byte count, a 2-digit hex value
109 *    bbbb   - record address, a 4-digit hex value
110 *    cc     - record type, a 2-digit hex value:
111 *              "00" is a data record
112 *              "01" is an end-of-data record
113 *              "02" is an extended-address record
114 *              "03" is a start record
115 *    d...d  - data (always an even number of chars)
116 *    ee     - record checksum, a 2-digit hex value
117 *             checksum = 2's complement
118 *                 [ (sum of bytes: aabbbbccd...d) modulo 256 ]
119 */
120
121
122Boolean is_intel_data_rec( char * rec_str )
123{
124    return( ( rec_str[ 0 ] == ':' )  &&  ( rec_str[ 8 ] == '0' ) );
125}
126
127Uint get_intel_rec_data_count( char * rec_str )
128{
129    return( ( Uint ) get_ndigit_hex( rec_str + 1, 2 ) );
130}
131
132Ulong get_intel_rec_address( char * rec_str )
133{
134    return( get_ndigit_hex( rec_str + 3, 4 ) );
135}
136
137char * get_intel_rec_data_start( char * rec_str )
138{
139    return( rec_str + 9 );
140}
141
142void put_intel_data_rec( Uint count, Ulong address, char * data_str )
143{
144    char    *ptr;
145    Uint    sum = count + ( address >> 8 & 0xff ) + ( address & 0xff );
146
147    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
148        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
149
150    printf(
151      ":%02X%04lX00%s%02X\n", count, address, data_str, (~sum + 1) & 0xff
152    );
153}
154
155
156Rec_vitals  intel_hex =
157{
158    is_intel_data_rec,
159    get_intel_rec_address,
160    get_intel_rec_data_count,
161    255,                        /* Maximum data bytes in a record. */
162    get_intel_rec_data_start,
163    put_intel_data_rec
164};
165
166
167/*------------------------- Motorola S1-record format ------------------------*/
168
169/*
170 *    Motorola S-record data-record layout
171 *
172 *    Sabbc...cd...dee
173 *
174 *    S      - header character
175 *    a      - record type, a 1-digit value:
176 *               "0" is a header record
177 *               "1" is a 2-byte-address data record
178 *               "2" is a 3-byte-address data record
179 *               "3" is a 4-byte-address data record
180 *               "7" is a 4-byte-address end-of-data record
181 *               "8" is a 3-byte-address end-of-data record
182 *               "9" is a 2-byte-address end-of-data record
183 *    bb     - record length in bytes, a 2-digit hex value
184 *             (record length doesn't count the header/type
185 *              chars and checksum byte)
186 *    c...c  - record address, a 4-, 6-, or 8-digit value,
187 *               depending on record type
188 *    d...d  - data (always an even number of chars)
189 *    ee     - record checksum, a 2-digit hex value
190 *             checksum = 1's complement
191 *             [ (sum of all bytes: bbc..cd...d) modulo 256 ]
192 */
193
194#define S1_COUNT_OFFSET         3
195
196
197Boolean is_moto_s1_data_rec( char * rec_str )
198{
199    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '1' ) );
200}
201
202Uint get_moto_s1_rec_data_count( char * rec_str )
203{
204    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S1_COUNT_OFFSET );
205}
206
207Ulong get_moto_s1_rec_address( char * rec_str )
208{
209    return( get_ndigit_hex( rec_str + 4, 4 ) );
210}
211
212char * get_moto_s1_rec_data_start( char * rec_str )
213{
214    return( rec_str + 8 );
215}
216
217void put_moto_s1_data_rec( Uint count, Ulong address, char * data_str )
218{
219    char   *ptr;
220    Uint    sum = S1_COUNT_OFFSET + count +
221                    ( address >> 8 & 0xff ) + ( address & 0xff );
222
223    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
224        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
225
226    printf(
227      "S1%02X%04lX%s%02X\n",
228      count + S1_COUNT_OFFSET, address, data_str, ~sum & 0xff
229    );
230}
231
232
233Rec_vitals  motorola_s1_rec =
234{
235    is_moto_s1_data_rec,
236    get_moto_s1_rec_address,
237    get_moto_s1_rec_data_count,
238    MAX_LEN_S1_RECS,            /* Maximum data bytes in a record. */
239    get_moto_s1_rec_data_start,
240    put_moto_s1_data_rec
241};
242
243
244/*------------------------- Motorola S2-record format ------------------------*/
245
246#define S2_COUNT_OFFSET         4
247
248Boolean is_moto_s2_data_rec( char * rec_str )
249{
250    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '2' ) );
251}
252
253Uint get_moto_s2_rec_data_count( char * rec_str )
254{
255    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S2_COUNT_OFFSET );
256}
257
258Ulong get_moto_s2_rec_address( char * rec_str )
259{
260    return( get_ndigit_hex( rec_str + 4, 6 ) );
261}
262
263char * get_moto_s2_rec_data_start( char * rec_str )
264{
265    return( rec_str + 10 );
266}
267
268void put_moto_s2_data_rec( Uint count, Ulong address, char * data_str )
269{
270    char    *ptr;
271    Uint    sum = S2_COUNT_OFFSET + count + ( address >> 16 & 0xff ) +
272                                            ( address >>  8 & 0xff ) +
273                                            ( address       & 0xff );
274
275    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
276        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
277
278    printf(
279      "S2%02X%06lX%s%02X\n",
280      count + S2_COUNT_OFFSET, address, data_str, ~sum & 0xff
281    );
282}
283
284
285Rec_vitals  motorola_s2_rec =
286{
287    is_moto_s2_data_rec,
288    get_moto_s2_rec_address,
289    get_moto_s2_rec_data_count,
290    MAX_LEN_S2_RECS,            /* Maximum data bytes in a record. */
291    get_moto_s2_rec_data_start,
292    put_moto_s2_data_rec
293};
294
295
296/*------------------------- Motorola S3-record format ------------------------*/
297
298#define S3_COUNT_OFFSET         5
299
300Boolean is_moto_s3_data_rec( char * rec_str )
301{
302    return ( ( rec_str[ 0 ] == 'S' )  &&  ( rec_str[ 1 ] == '3' ) );
303}
304
305Uint get_moto_s3_rec_data_count( char * rec_str )
306{
307    return( ( Uint ) get_ndigit_hex( rec_str + 2, 2 ) - S3_COUNT_OFFSET );
308}
309
310Ulong get_moto_s3_rec_address( char * rec_str )
311{
312    return( get_ndigit_hex( rec_str + 4, 8 ) );
313}
314
315char * get_moto_s3_rec_data_start( char * rec_str )
316{
317    return( rec_str + 12 );
318}
319
320void put_moto_s3_data_rec( Uint count, Ulong address, char * data_str )
321{
322    char    *ptr;
323    Uint     sum = S3_COUNT_OFFSET + count + ( address >> 24 & 0xff ) +
324                                             ( address >> 16 & 0xff ) +
325                                             ( address >>  8 & 0xff ) +
326                                             ( address       & 0xff );
327
328    for ( ptr = data_str ; *ptr != EOS ; ptr += 2 )
329        sum += ( Uint ) get_ndigit_hex( ptr, 2 );
330
331    printf(
332      "S3%02X%08lX%s%02X\n",
333      count + S3_COUNT_OFFSET, address, data_str, ~sum & 0xff
334   );
335}
336
337
338Rec_vitals  motorola_s3_rec =
339{
340    is_moto_s3_data_rec,
341    get_moto_s3_rec_address,
342    get_moto_s3_rec_data_count,
343    MAX_LEN_S3_RECS,            /* Maximum data bytes in a record. */
344    get_moto_s3_rec_data_start,
345    put_moto_s3_data_rec
346};
347
348
349/*-------------------- Put your favorite hex format here ---------------------*/
350
351/*
352 *    * * *  The following is a template for an additional hex format:  * * *
353 *
354 *
355 *    Boolean is_X_data_rec( char * rec_str ) {}
356 *
357 *    Uint get_X_rec_data_count( char * rec_str ) {}
358 *
359 *    Ulong get_X_rec_address( char * rec_str ) {}
360 *
361 *    char * get_X_rec_data_start( char * rec_str ) {}
362 *
363 *    void put_X_data_rec( Uint count, Ulong address, char * data_str ) {}
364 *
365 *    Rec_vitals  X_rec =
366 *    {
367 *        is_X_data_rec,
368 *        get_X_rec_address,
369 *        get_X_rec_data_count,
370 *        MAXIMUM DATA BYTES IN A RECORD,
371 *        get_X_rec_data_start,
372 *        put_X_data_rec
373 *    };
374 *
375 */
376
377/*----------------------------------------------------------------------------*/
378
379
380/*
381 *   Put address of additional Rec_vitals structures
382 *   in this array, before the NULL entry.
383 */
384
385Rec_vitals  *formats[] =
386{
387    &intel_hex,
388    &motorola_s1_rec,
389    &motorola_s2_rec,
390    &motorola_s3_rec,
391    ( Rec_vitals * ) NULL
392};
393
394
395/****   main   *****************************************************************
396*
397*
398*       Expects: Nothing (no command-line parameters).
399*
400*       Returns: Exit status (EXIT_SUCCESS or EXIT_FAILURE).
401*
402*       Reads hex records on the standard input and attempts to
403*       splice adjacent data fields together.  Results appear on
404*       the standard output.
405*
406*******************************************************************************/
407
408int main(
409  int argc,
410  char **argv
411)
412{
413
414    char       inbuff[ MAX_LINE_SIZE ], outbuff[ MAX_LINE_SIZE ];
415    char       *in_dptr, *out_dptr;
416    int        d_total, d_count, d_excess, n;
417    Ulong      in_rec_addr, out_rec_addr = 0;
418    Rec_vitals *rptr;
419
420
421    /* Sift through file until first hex record is identified.    */
422    if ( ( rptr = identify_first_data_record( inbuff ) ) == NULL )
423    {
424        fputs( "No hex records found.\n", stderr );
425        exit( EXIT_FAILURE );
426    }
427
428
429    /* Attempt data-record splicing until end-of-file is reached. */
430    d_total = 0;
431    do
432    {
433        if ( rptr->is_data_record( inbuff ) == YES )
434        { /* Input record is a data record. */
435            d_count     = rptr->get_data_count( inbuff );
436            in_rec_addr = rptr->get_address( inbuff );
437            in_dptr     = rptr->get_data_start( inbuff );
438
439            if ( d_total == 0  ||  in_rec_addr != out_rec_addr + d_total )
440            { /* Begin a new output record. */
441                if ( d_total != 0 )
442                    rptr->put_data_record( d_total, out_rec_addr, outbuff );
443                out_dptr     = outbuff;
444                n = d_total  = d_count;
445                out_rec_addr = in_rec_addr;
446            }
447            else if
448              ( ( d_excess = d_total + d_count - rptr->max_data_count ) > 0 )
449            { /* Output a maximum-length record, then start a new record. */
450                strncat( outbuff, in_dptr, 2 * ( d_count - d_excess ) );
451                rptr->put_data_record(
452                  rptr->max_data_count, out_rec_addr, outbuff
453                );
454                in_dptr      += 2 * ( d_count - d_excess );
455                out_dptr      = outbuff;
456                n = d_total   = d_excess;
457                out_rec_addr += rptr->max_data_count;
458            }
459            else
460            { /* Append input record's data field with accumulated data. */
461                out_dptr = outbuff + ( 2 * d_total );
462                d_total += n = d_count;
463            }
464            strncpy( out_dptr, in_dptr, 2 * n );
465            out_dptr[ 2 * n ] = EOS;
466        }
467        else
468        { /* Not a data record;
469           * flush accumulated data then echo non-data record.
470           */
471            if ( d_total != 0 )
472            {
473                rptr->put_data_record( d_total, out_rec_addr, outbuff );
474                d_total = 0;
475            }
476            puts( inbuff );
477        }
478    } while ( gets( inbuff ) != NULL );
479
480
481    return ( EXIT_SUCCESS );
482
483}
484
485
486/****   identify_first_data_record   *******************************************
487*
488*       Expects: Pointer to hex-record line buffer.
489*
490*       Returns: Pointer to hex-record structure (NULL if no match found).
491*
492*       Reads the standard input, line by line, searching for a valid
493*       record header character.  If a valid header is found, a pointer
494*       to the hex-record's type structure is returned, otherwise NULL.
495*
496*       The input-stream pointer is left pointing to the first valid hex record.
497*
498*******************************************************************************/
499
500Rec_vitals * identify_first_data_record( char * buff_ptr )
501{
502    Rec_vitals  ** ptr;
503
504    while ( gets( buff_ptr ) != NULL )
505    {
506        for ( ptr = formats ; *ptr != ( Rec_vitals * ) NULL ; ptr++ )
507            if ( ( *ptr )->is_data_record( buff_ptr ) == YES )
508                return( *ptr );        /* Successful return.        */
509
510        puts( buff_ptr );              /* Echo non-hex-record line. */
511    }
512
513    return( ( Rec_vitals * ) NULL );   /* Unsuccessful return.      */
514}
515
516
517/****   get_ndigit_hex   *******************************************************
518*
519*       Expects: Pointer to first ASCII hexadecimal digit, number of digits.
520*
521*       Returns: Value of hexadecimal string as an unsigned long.
522*
523*******************************************************************************/
524
525Ulong get_ndigit_hex( char * cptr, int digits )
526{
527    Ulong    value;
528
529    for ( value = 0 ; --digits >= 0 ; cptr++ )
530        value = ( value * 16L ) + HEX_DIGIT( *cptr );
531
532    return( value );
533}
Note: See TracBrowser for help on using the repository browser.