/*
* Copyright (c) 2002, The Tendra Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Crown Copyright (c) 1997
*
* This TenDRA(r) Computer Program is subject to Copyright
* owned by the United Kingdom Secretary of State for Defence
* acting through the Defence Evaluation and Research Agency
* (DERA). It is made available to Recipients with a
* royalty-free licence for its use, reproduction, transfer
* to other parties and amendment for any purpose not excluding
* product development provided that any such use et cetera
* shall be deemed to be acceptance of the following conditions:-
*
* (1) Its Recipients shall ensure that this Notice is
* reproduced upon any copies or amended versions of it;
*
* (2) Any amended version of it shall be clearly marked to
* show both the nature of and the organisation responsible
* for the relevant amendment or amendments;
*
* (3) Its onward transfer from a recipient to another
* party shall be deemed to be that party's acceptance of
* these conditions;
*
* (4) DERA gives no warranty or assurance as to its
* quality or suitability for any purpose and DERA accepts
* no liability whatsoever in relation to any use to which
* it may be put.
*
* $TenDRA: tendra/src/tools/tld/istream.c,v 1.11 2005/10/18 15:31:06 stefanf Exp $
*/
/**** istream.c --- Input stream handling.
*
** Author: Steve Folkes
*
**** Commentary:
*
* This file implements the input stream facility specified in the file
* "istream.h". See that file for more details.
*
**** Change Log:*/
/****************************************************************************/
#include "istream.h"
#include "cstring.h"
#include "syntax.h"
/*--------------------------------------------------------------------------*/
#define ISTREAM_BUFSIZE 8193
/*--------------------------------------------------------------------------*/
ExceptionP XX_istream_read_error = EXCEPTION ("error reading from stream");
/*--------------------------------------------------------------------------*/
static char istream_input_buffer [ISTREAM_BUFSIZE];
static IStreamT istream_input_1 = {
NIL (FILE *),
&(istream_input_buffer [0]),
&(istream_input_buffer [ISTREAM_BUFSIZE - 1]),
&(istream_input_buffer [ISTREAM_BUFSIZE]),
&(istream_input_buffer [ISTREAM_BUFSIZE]),
1,
"",
FALSE
};
IStreamT *const istream_input = &istream_input_1;
/*--------------------------------------------------------------------------*/
static IStreamStatusT
istream_read_hex_char(IStreamP istream, char *c_ref)
{
int value;
int tmp;
char c;
redo1:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo1, eof);
return (ISTREAM_STAT_SYNTAX_ERROR);
case '\n':
istream_inc_line (istream);
return (ISTREAM_STAT_SYNTAX_ERROR);
default:
if (((value = syntax_value (c)) == SYNTAX_NO_VALUE) || (value >= 16)) {
return (ISTREAM_STAT_SYNTAX_ERROR);
}
tmp = value;
break;
}
redo2:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo2, eof);
return (ISTREAM_STAT_SYNTAX_ERROR);
case '\n':
istream_inc_line (istream);
return (ISTREAM_STAT_SYNTAX_ERROR);
default:
if (((value = syntax_value (c)) == SYNTAX_NO_VALUE) || (value >= 16)) {
return (ISTREAM_STAT_SYNTAX_ERROR);
}
break;
}
*c_ref = (char) ((tmp * 16) + value);
return (ISTREAM_STAT_READ_CHAR);
eof:
return (ISTREAM_STAT_SYNTAX_ERROR);
}
/*--------------------------------------------------------------------------*/
void
istream_setup(void)
{
istream_input_1.file = stdin;
}
#ifdef FS_FAST
#undef istream_init
#endif /* defined (FS_FAST) */
void
istream_init(IStreamP istream)
{
istream->name = NULL;
}
#ifdef FS_FAST
#define istream_init(is) ((is)->name = NULL)
#endif /* defined (FS_FAST) */
BoolT
istream_open(IStreamP istream, char *name)
{
if ((istream->file = fopen (name, "r")) == NIL (FILE *)) {
return (FALSE);
}
istream->buffer = ALLOCATE_VECTOR (char, ISTREAM_BUFSIZE);
istream->limit = &(istream->buffer [ISTREAM_BUFSIZE]);
istream->line = 1;
istream->name = name;
X__istream_fill_buffer (istream);
return (TRUE);
}
void
istream_assign(IStreamP to, IStreamP from)
{
to->file = from->file;
to->buffer = from->buffer;
to->current = from->current;
to->end = from->end;
to->limit = from->limit;
to->line = from->line;
to->name = from->name;
to->read_last = from->read_last;
}
#ifdef FS_FAST
#undef istream_is_open
#endif /* defined (FS_FAST) */
BoolT
istream_is_open(IStreamP istream)
{
return (istream->name != NULL);
}
#ifdef FS_FAST
#define istream_is_open(is) ((is)->name != NULL)
#endif /* defined (FS_FAST) */
BoolT
istream_read_char(IStreamP istream, char *c_ref)
{
char c;
redo:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\n':
istream_inc_line (istream);
break;
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
break;
default:
break;
}
*c_ref = c;
return (TRUE);
eof:
return (FALSE);
}
BoolT
istream_peek_char(IStreamP istream, char *c_ref)
{
char c;
redo:
switch (c = ISTREAM_PEEK_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
break;
default:
break;
}
*c_ref = c;
return (TRUE);
eof:
return (FALSE);
}
IStreamStatusT
istream_read_escaped_char(IStreamP istream, char *c_ref)
{
char c;
redo:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
*c_ref = c;
return (ISTREAM_STAT_READ_CHAR);
case '\n':
istream_inc_line (istream);
return (ISTREAM_STAT_NO_CHAR);
case '0':
*c_ref = '\0';
return (ISTREAM_STAT_READ_CHAR);
case 'f': case 'F':
*c_ref = '\f';
return (ISTREAM_STAT_READ_CHAR);
case 'n': case 'N':
*c_ref = '\n';
return (ISTREAM_STAT_READ_CHAR);
case 'r': case 'R':
*c_ref = '\r';
return (ISTREAM_STAT_READ_CHAR);
case 't': case 'T':
*c_ref = '\t';
return (ISTREAM_STAT_READ_CHAR);
case 'x': case 'X':
return (istream_read_hex_char (istream, c_ref));
default:
*c_ref = c;
return (ISTREAM_STAT_READ_CHAR);
}
eof:
return (ISTREAM_STAT_SYNTAX_ERROR);
}
#ifdef FS_FAST
#undef istream_inc_line
#endif /* defined (FS_FAST) */
void
istream_inc_line(IStreamP istream)
{
istream->line ++;
}
#ifdef FS_FAST
#define istream_inc_line(is) ((is)->line ++)
#endif /* defined (FS_FAST) */
#ifdef FS_FAST
#undef istream_line
#endif /* defined (FS_FAST) */
unsigned
istream_line(IStreamP istream)
{
return (istream->line);
}
#ifdef FS_FAST
#define istream_line(is) ((is)->line)
#endif /* defined (FS_FAST) */
#ifdef FS_FAST
#undef istream_name
#endif /* defined (FS_FAST) */
char *
istream_name(IStreamP istream)
{
return (istream->name);
}
#ifdef FS_FAST
#define istream_name(is) ((is)->name)
#endif /* defined (FS_FAST) */
void
istream_close(IStreamP istream)
{
(void) fclose (istream->file);
if (istream != istream_input) {
DEALLOCATE (istream->buffer);
}
istream_init (istream);
}
/*--------------------------------------------------------------------------*/
void
X__istream_fill_buffer(IStreamP istream)
{
size_t bytes = fread ((void *) (istream->buffer), sizeof (char),
(size_t) (ISTREAM_BUFSIZE - 1), istream->file);
if ((bytes == (size_t) 0) && (ferror (istream->file))) {
char *name = string_copy (istream->name);
THROW_VALUE (XX_istream_read_error, name);
UNREACHED;
}
istream->current = istream->buffer;
istream->end = (istream->current + bytes);
istream->read_last = FALSE;
*(istream->end) ++ = '\0';
}