source: rtems/tools/build/packhex.c @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

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