//
// srecord - manipulate eprom load files
// Copyright (C) 1998-2007 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
#include
using namespace std;
#include
#include
bool srec_input_file::ignore_checksums_default = false;
srec_input_file::srec_input_file() :
file_name("standard input"),
line_number(1),
prev_was_newline(false),
vfp(stdin),
checksum(0),
is_text(0),
ignore_checksums(ignore_checksums_default)
{
}
const char *
srec_input_file::mode()
const
{
return "r";
}
srec_input_file::srec_input_file(const string &a_file_name) :
file_name(a_file_name),
line_number(1),
prev_was_newline(false),
vfp(0),
checksum(0),
is_text(0),
ignore_checksums(ignore_checksums_default)
{
if (file_name == string("-"))
{
file_name = "standard input";
vfp = stdin;
}
else
{
//
// The call to fopen is deferred until the constructor has
// completed. This is so that the virtual mode() method
// is available (it isn't in the base class constructor).
//
}
}
void *
srec_input_file::get_fp()
{
if (!vfp)
{
//
// The call to fopen is deferred until the constructor has
// completed. This is so that the virtual mode() method
// is available (it isn't in the base class constructor).
//
const char *the_mode = mode();
vfp = fopen(file_name.c_str(), the_mode);
if (!vfp)
fatal_error_errno("open");
is_text = !strchr(the_mode, 'b');
if (!is_text)
line_number = 0;
}
return vfp;
}
srec_input_file::~srec_input_file()
{
FILE *fp = (FILE *)get_fp();
if (fp != stdin && fclose(fp))
fatal_error_errno("close");
}
string
srec_input_file::filename()
const
{
return file_name;
}
string
srec_input_file::filename_and_line()
const
{
if (!vfp)
return file_name;
char buffer[20];
if (is_text)
sprintf(buffer, ": %d", line_number);
else
sprintf(buffer, ": 0x%04X", line_number);
return (file_name + buffer);
}
int
srec_input_file::get_char()
{
FILE *fp = (FILE *)get_fp();
if (prev_was_newline)
++line_number;
int c = getc(fp);
if (c == EOF)
{
if (ferror(fp))
fatal_error_errno("read");
//
// If this is a text file, but the last character wasn't
// a newline, insert one.
//
c = ((is_text && !prev_was_newline) ? '\n' : -1);
}
else if (c == '\r' && is_text)
{
//
// If this is a text file, turn CRLF into LF.
// Leave all other sequences containing CR alone.
//
c = getc(fp);
if (c == EOF)
{
if (ferror(fp))
fatal_error_errno("read");
c = '\r';
}
else if (c != '\n')
{
ungetc(c, fp);
c = '\r';
}
}
if (!is_text && c >= 0)
++line_number;
prev_was_newline = (is_text && c == '\n');
return c;
}
void
srec_input_file::get_char_undo(int c)
{
if (c >= 0)
{
FILE *fp = (FILE *)get_fp();
prev_was_newline = false;
if (!is_text)
--line_number;
ungetc(c, fp);
}
}
int
srec_input_file::peek_char()
{
FILE *fp = (FILE *)get_fp();
int c = getc(fp);
if (c == EOF)
{
if (ferror(fp))
fatal_error_errno("read");
c = -1;
}
else
ungetc(c, fp);
return c;
}
int
srec_input_file::get_nibble_value(int c)
{
switch (c)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return (c - '0');
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
return (c - 'a' + 10);
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
return (c - 'A' + 10);
}
return -1;
}
int
srec_input_file::get_nibble()
{
int c = get_char();
int n = get_nibble_value(c);
if (n < 0)
fatal_error("hexadecimal digit expected");
return n;
}
int
srec_input_file::get_byte()
{
int c1 = get_nibble();
int c2 = get_nibble();
int n = ((c1 << 4) | c2);
checksum_add(n);
return n;
}
int
srec_input_file::get_word()
{
int b1 = get_byte();
int b2 = get_byte();
return ((b1 << 8) | b2);
}
unsigned long
srec_input_file::get_3bytes()
{
unsigned long b1 = get_byte();
unsigned long b2 = get_byte();
unsigned long b3 = get_byte();
return ((((b1 << 8) | b2) << 8) | b3);
}
unsigned long
srec_input_file::get_4bytes()
{
unsigned long b1 = get_byte();
unsigned long b2 = get_byte();
unsigned long b3 = get_byte();
unsigned long b4 = get_byte();
return ((((((b1 << 8) | b2) << 8) | b3) << 8) | b4);
}
int
srec_input_file::checksum_get()
const
{
return (checksum & 0xFF);
}
int
srec_input_file::checksum_get16()
const
{
return (checksum & 0xFFFF);
}
void
srec_input_file::checksum_reset()
{
checksum = 0;
}
void
srec_input_file::checksum_add(unsigned char n)
{
checksum += n;
}
void
srec_input_file::seek_to_end()
{
FILE *fp = (FILE *)get_fp();
fseek(fp, 0L, SEEK_END);
}
void
srec_input_file::disable_checksum_validation()
{
ignore_checksums = true;
}