Replace Perl version of packihx with C version
[fw/sdcc] / src / packihx
1 #!/bin/sh
2 exec perl -x "$0" "$@"
3 #!perl -w
4 # Real script begins here; the above ugliness should locate
5 # perl on your path.
6
7 # Quick & dirty perl hack to pack an Intel Hex format output file.
8 # Will consolidate lines up to $outChunk bytes per line.
9
10 use integer;
11
12 # 16 bytes per line is default.
13 $outChunk = 16;
14
15 $nextOffset = 0;
16 $pendingData = "";
17 $pendingDataStart = 0;
18 $pendingDataCount = 0;
19 $lastExtendedOffset = 0;
20
21 while (<>)
22 {
23     if (/:([\dABCDEFabcdef]{2})([\dABCDEFabcdef]{4})(\d\d)(.*)([\dABCDEFabcdef]{2})/)
24     {
25         # $1 = record len; $2 = offset; $3 = record type; $4 = data; $5 = checksum.
26         $recordLen = hex $1;
27         $recordOffset = hex $2;
28
29         # Sanity checks...
30         if ((length $4) % 2 == 1)
31         {
32             print STDERR "packihx: odd data length $4 in line $.\n";
33             exit -1;
34         }
35         if ((length $4) / 2 != $recordLen)
36         {
37             print STDERR "packihx: data len mismatch in line $.: $1 != len $4\n";
38             exit -1;
39         }
40         if (checksum("$1$2$3$4") != hex $5)
41         {
42             print STDERR "packihx: bad checksum in line $.: ";
43             printf STDERR "wanted %02X, got %s\n", checksum("$1$2$3$4"), $5;
44             exit -1;
45         }
46
47         if ($3 != 0)
48         {
49             # If this is an extended data offset record, and it
50             # matches the expected extended data offset, then
51             # we can simply discard it.
52             if (($3 == 4) && ($recordLen == 2))
53             {
54                 my $extendedOffset = hex $4;
55                 if ($extendedOffset == $lastExtendedOffset)
56                 {
57                     next;
58                 }
59                 $lastExtendedOffset = $extendedOffset;
60             }
61             # Not a data record. Flush anything pending, then write this
62             # line as is.
63             &flush_pending_data;
64             $pendingDataStart = 0;
65             $nextOffset = 0;
66             print;
67         }
68         else
69         {
70             # If this isn't contigous with the last record, 
71             # flush anything pending and start collecting anew.
72             if ($recordOffset != $nextOffset)
73             {
74                 &flush_pending_data;
75                 $pendingDataStart = $recordOffset;
76                 $nextOffset = $pendingDataStart;
77             }
78
79             # Append this data onto the pending data.
80             $pendingData .= $4;
81             $pendingDataCount += $recordLen;
82             $nextOffset += $recordLen;
83
84             # If we'va accumulated at least an outChunk
85             # worth of data, write it out.
86             while ($pendingDataCount >= $outChunk)
87             {
88                 &write_pending_line($outChunk);
89             }
90         }           
91     }
92     else
93     {
94         print STDERR "packihx: don't recognize line $.: $_";
95         exit -1;
96     }
97 }
98 &flush_pending_data;
99
100 exit 0;
101
102 # Write all buffered data.
103 sub flush_pending_data
104 {
105     while ($pendingDataCount > $outChunk)
106     {
107         &write_pending_line($outChunk);
108     }
109     if ($pendingDataCount)
110     {
111         &write_pending_line($pendingDataCount);
112     }
113 }
114
115 # Write a given number of bytes of buffered output.
116 sub write_pending_line
117 {   
118     my $lineLen = shift(@_);
119
120     if ($lineLen > $pendingDataCount)
121     {
122         print STDERR "packihx: internal error: asked to write $lineLen bytes ";
123         print STDERR "with only $pendingDataCount bytes buffered.\n";
124         exit -1;
125     }
126
127     my $data = substr $pendingData, 0, $lineLen * 2;
128     my $toWrite = sprintf "%02X%04X00%s", $lineLen, $pendingDataStart, $data;
129
130     my $cks = checksum($toWrite);
131
132     printf ":%s%02X\n", $toWrite, $cks;
133
134     $pendingDataStart += $lineLen;
135     $pendingDataCount -= $lineLen;  
136     $pendingData = substr $pendingData, $lineLen * 2;
137 }
138
139 # Generate a IHX checksum.
140 sub checksum
141 {
142    my $line = shift(@_);
143    my $offset = 0;
144    my $cks = 0;
145    
146    while ($offset < length $line)
147    {
148        my $byte = substr $line, $offset, 2;
149        $cks += hex $byte;
150        $offset += 2;
151    }
152
153    if ($offset != length $line)
154    {
155         print STDERR "packihx: checksum: got odd number of bytes... I hate that";
156         exit -1;
157    }
158
159    $cks &= 0xff;
160    if ($cks)
161    {
162         $cks = 0x100 - $cks;
163    }
164    return $cks;
165 }