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