source: rtems/c/build-tools/packhex.c @ 8cbbe312

4.104.114.84.95
Last change on this file since 8cbbe312 was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on 05/11/95 at 17:39:37

Initial revision

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