1 //
2 // srecord - manipulate eprom load files
3 // Copyright (C) 1998-2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see
17 // <http://www.gnu.org/licenses/>.
18 //
19 
20 #include <cerrno>
21 #include <cstdio>
22 #include <cstring>
23 #include <iostream>
24 
25 #include <srecord/input/file.h>
26 
27 bool srecord::input_file::ignore_checksums_default = false;
28 
29 
input_file()30 srecord::input_file::input_file() :
31     file_name("standard input"),
32     line_number(1),
33     prev_was_newline(false),
34     vfp(stdin),
35     checksum(0),
36     ignore_checksums(ignore_checksums_default)
37 {
38 }
39 
40 
41 bool
is_binary(void) const42 srecord::input_file::is_binary(void)
43     const
44 {
45     return false;
46 }
47 
48 
input_file(const std::string & a_file_name)49 srecord::input_file::input_file(const std::string &a_file_name) :
50     file_name(a_file_name),
51     line_number(1),
52     prev_was_newline(false),
53     vfp(0),
54     checksum(0),
55     ignore_checksums(ignore_checksums_default)
56 {
57     if (file_name == "-")
58     {
59         file_name = "standard input";
60         vfp = stdin;
61     }
62     else
63     {
64         //
65         // The call to fopen is deferred until the constructor has
66         // completed.  This is so that the virtual is_binary() method
67         // is available (it isn't in the base class constructor).
68         //
69     }
70 }
71 
72 
73 void *
get_fp(void)74 srecord::input_file::get_fp(void)
75 {
76     if (!vfp)
77     {
78         //
79         // The call to fopen is deferred until the constructor has
80         // completed.  This is so that the virtual is_binary() method
81         // is available (it isn't in the base class constructor).
82         //
83         const char *the_mode = "r";
84         if (is_binary())
85         {
86             the_mode = "rb";
87             line_number = 0;
88         }
89         vfp = fopen(file_name.c_str(), the_mode);
90         if (!vfp)
91             fatal_error_errno("open");
92     }
93     return vfp;
94 }
95 
96 
~input_file()97 srecord::input_file::~input_file()
98 {
99     FILE *fp = (FILE *)get_fp();
100     if (fp != stdin && fclose(fp))
101         fatal_error_errno("close");
102 }
103 
104 
105 std::string
filename(void) const106 srecord::input_file::filename(void)
107     const
108 {
109     return file_name;
110 }
111 
112 
113 std::string
filename_and_line(void) const114 srecord::input_file::filename_and_line(void)
115     const
116 {
117     if (!vfp)
118         return file_name;
119     char buffer[20];
120     if (!is_binary())
121         sprintf(buffer, ": %d", line_number);
122     else
123         sprintf(buffer, ": 0x%04X", line_number);
124     return (file_name + buffer);
125 }
126 
127 
128 int
get_char(void)129 srecord::input_file::get_char(void)
130 {
131     FILE *fp = (FILE *)get_fp();
132     if (prev_was_newline)
133         ++line_number;
134     int c = getc(fp);
135     if (c == EOF)
136     {
137         if (ferror(fp))
138             fatal_error_errno("read");
139 
140         //
141         // If this is a text file, but the last character wasn't
142         // a newline, insert one.
143         //
144         c = ((!is_binary() && !prev_was_newline) ? '\n' : -1);
145     }
146     else if (c == '\r' && !is_binary())
147     {
148         //
149         // If this is a text file, turn CRLF into LF.
150         // Leave all other sequences containing CR alone.
151         //
152         c = getc(fp);
153         if (c == EOF)
154         {
155             if (ferror(fp))
156                 fatal_error_errno("read");
157             c = '\r';
158         }
159         else if (c != '\n')
160         {
161             ungetc(c, fp);
162             c = '\r';
163         }
164     }
165     if (is_binary() && c >= 0)
166         ++line_number;
167     prev_was_newline = (!is_binary() && c == '\n');
168     return c;
169 }
170 
171 
172 void
get_char_undo(int c)173 srecord::input_file::get_char_undo(int c)
174 {
175     if (c >= 0)
176     {
177         FILE *fp = (FILE *)get_fp();
178         prev_was_newline = false;
179         if (is_binary())
180             --line_number;
181         ungetc(c, fp);
182     }
183 }
184 
185 
186 int
peek_char(void)187 srecord::input_file::peek_char(void)
188 {
189     FILE *fp = (FILE *)get_fp();
190     int c = getc(fp);
191     if (c == EOF)
192     {
193         if (ferror(fp))
194             fatal_error_errno("read");
195         c = -1;
196     }
197     else
198         ungetc(c, fp);
199     return c;
200 }
201 
202 
203 int
get_nibble_value(int c)204 srecord::input_file::get_nibble_value(int c)
205 {
206     switch (c)
207     {
208     case '0': case '1': case '2': case '3': case '4':
209     case '5': case '6': case '7': case '8': case '9':
210         return (c - '0');
211 
212     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
213         return (c - 'a' + 10);
214 
215     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
216         return (c - 'A' + 10);
217     }
218     return -1;
219 }
220 
221 
222 int
get_nibble(void)223 srecord::input_file::get_nibble(void)
224 {
225     int c = get_char();
226     int n = get_nibble_value(c);
227     if (n < 0)
228         fatal_error("hexadecimal digit expected");
229     return n;
230 }
231 
232 
233 int
get_byte(void)234 srecord::input_file::get_byte(void)
235 {
236     int c1 = get_nibble();
237     int c2 = get_nibble();
238     int n = ((c1 << 4) | c2);
239     checksum_add(n);
240     return n;
241 }
242 
243 
244 unsigned
get_word_be(void)245 srecord::input_file::get_word_be(void)
246 {
247     int b1 = get_byte();
248     int b2 = get_byte();
249     return ((b1 << 8) | b2);
250 }
251 
252 
253 unsigned
get_word_le(void)254 srecord::input_file::get_word_le(void)
255 {
256     int b1 = get_byte();
257     int b2 = get_byte();
258     return (b1 | (b2 << 8));
259 }
260 
261 
262 unsigned long
get_3bytes_be(void)263 srecord::input_file::get_3bytes_be(void)
264 {
265     unsigned long b1 = get_byte();
266     unsigned long b2 = get_byte();
267     unsigned long b3 = get_byte();
268     return ((((b1 << 8) | b2) << 8) | b3);
269 }
270 
271 
272 unsigned long
get_3bytes_le(void)273 srecord::input_file::get_3bytes_le(void)
274 {
275     unsigned long b1 = get_byte();
276     unsigned long b2 = get_byte();
277     unsigned long b3 = get_byte();
278     return ((((b3 << 8) | b2) << 8) | b1);
279 }
280 
281 
282 unsigned long
get_4bytes_be(void)283 srecord::input_file::get_4bytes_be(void)
284 {
285     unsigned long b1 = get_byte();
286     unsigned long b2 = get_byte();
287     unsigned long b3 = get_byte();
288     unsigned long b4 = get_byte();
289     return ((((((b1 << 8) | b2) << 8) | b3) << 8) | b4);
290 }
291 
292 
293 unsigned long
get_4bytes_le(void)294 srecord::input_file::get_4bytes_le(void)
295 {
296     unsigned long b1 = get_byte();
297     unsigned long b2 = get_byte();
298     unsigned long b3 = get_byte();
299     unsigned long b4 = get_byte();
300     return ((((((b4 << 8) | b3) << 8) | b2) << 8) | b1);
301 }
302 
303 
304 int
checksum_get(void) const305 srecord::input_file::checksum_get(void)
306     const
307 {
308     return (checksum & 0xFF);
309 }
310 
311 
312 int
checksum_get16(void) const313 srecord::input_file::checksum_get16(void)
314     const
315 {
316     return (checksum & 0xFFFF);
317 }
318 
319 
320 void
checksum_reset(void)321 srecord::input_file::checksum_reset(void)
322 {
323     checksum = 0;
324 }
325 
326 
327 void
checksum_add(unsigned char n)328 srecord::input_file::checksum_add(unsigned char n)
329 {
330     checksum += n;
331 }
332 
333 
334 void
seek_to_end(void)335 srecord::input_file::seek_to_end(void)
336 {
337     FILE *fp = (FILE *)get_fp();
338     fseek(fp, 0L, SEEK_END);
339 }
340 
341 
342 void
disable_checksum_validation(void)343 srecord::input_file::disable_checksum_validation(void)
344 {
345     ignore_checksums = true;
346 }
347 
348 
349 // vim: set ts=8 sw=4 et :
350