/*

cls_2: Curl Like Syntax
Yauheni A. Akhotnikau (C) 2001-2003
eao197@yahoo.com
-------------------------------------------------

Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:

1. This software 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.

2. The origin of this software must not be misrepresented, either by
   explicit claim or by omission.

3. Altered versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

-------------------------------------------------

*/
#include <assert.h>
#include <string.h>
#include <errno.h>

#include <cls_2/h/is_file.hpp>

namespace cls_2 {

static char	g_chars_to_ignore[] = "\r";
static char g_eol_chars[] = "\n";

static bool
is_eol( char ch ) {
	return ( 0 != strchr( g_eol_chars, ch ) );
}

static bool
is_char_must_be_ignored( char ch ) {
	return ( 0 != strchr( g_chars_to_ignore, ch ) );
}

//
// input_stream_file_t
//
const size_t	c_file_buffer_capacity = 2048;
input_stream_file_t::input_stream_file_t(
	const char * file_name ) :
	m_file( 0 ),
	m_size( 0 ),
	m_pos( 0 ),
	m_line( 1 ),
	m_errno( 0 ) {
	assert( file_name );

	size_t len = strlen( file_name ) + 1;
	m_file_name.set( new char[ len ], len );

	strcpy( m_file_name.query(), file_name );

	m_file = fopen( m_file_name.query(), "r" );
	if( 0 != m_file ) {
		m_buf.set( new char[ c_file_buffer_capacity ],
			c_file_buffer_capacity );
		if( 0 == m_buf.query() ) {
			fclose( m_file );
			m_file = 0;
		}
	}
	else
		m_errno = errno;
}

input_stream_file_t::~input_stream_file_t( void ) {
	if( 0 != m_file )
		fclose( m_file );
}

bool
input_stream_file_t::is_open() const {
	return ( 0 != m_file );
}

int
input_stream_file_t::query_last_io_result() const {
	return m_errno;
}

const char *
input_stream_file_t::query_file_name() const {
	return m_file_name.query();
}

unsigned int
input_stream_file_t::query_line() const {
	return m_line;
}

int
input_stream_file_t::get( char & ch ) {
	register char cur = 0;
	register int err;
	while( 1 ) {
		if( e_ok == ( err = lo_get_ch( cur ) ) ) {
			if( cur && !is_char_must_be_ignored( cur ) ) {
				ch = cur;
				return e_ok;
			}
		}
		else
			return err;
	}
}

void
input_stream_file_t::back() {
	lo_back_ch();
}

int
input_stream_file_t::lo_get_ch( char & ch ) {
	if( m_pos == m_size ) {
		m_pos = 0;
		m_size = 0;

		if( 0 == m_file || ferror( m_file ) )
			return e_error;
		else if( feof( m_file ) )
			return e_eof;
		m_size = fread( m_buf.query(), 1, m_buf.size(), m_file );
		if( !m_size ) {
			m_errno = errno;
			return e_eof;
		}
	}
	ch = *(m_buf.query() + m_pos++);

	if( is_eol( ch ) )
		++m_line;

	return e_ok;
}

void
input_stream_file_t::lo_back_ch( void ) {
	if( is_eol( m_buf.query()[ m_pos ] ) )
		--m_line;
	m_pos--;
}

} /* namespace cls_2 */
