
/* gemdos methods for streamoids */

#include "io-defs.h"
#include "com-meth.h"
#include "buf-meth.h"
#include "input-ed.h"
#include <osbind.h>
#include <file.h>
#include <linea.h>

/*
   get a fresh buffer for a buffered gemdos streamoid.  must 
   advance-input-buffer before doing this.
*/
local DEFMETHOD next_input_buffer(self)
struct streamoid * self;
{
  return((long )(Fread(self->gemdos_handle, self->buffer_size, self->buffer)));
}

/* 
   write the current buffer to the gemdos handle.  should 
   advance-output-buffer after this
*/
local DEFMETHOD send_output_buffer(self)
struct streamoid * self;
{
  return(long )(Fwrite(self->gemdos_handle, self->buffer_nbytes, self->buffer));
}

local DEFMETHOD seek_internal(self, where, how)
struct streamoid * self;
long where;
int how;
{
  return((long )(Fseek(where, self->gemdos_handle, how)));
}

local DEFMETHOD close_internal(self)
struct streamoid * self;
{
  Fclose(self->gemdos_handle);
}

/*
   Unbuffered methods for gem file handles.  These are *NOT* suitable
   for interactive streamoids.
*/

local DEFMETHOD tyi_binary_simple(self)
struct streamoid * self;
{
  int result;
  char ch[1];

  if (self->flags & STR_UNTYIED_P)
	{
	self->flags &= ~STR_UNTYIED_P;
	return(self->untyied_char);
	}
  result = Fread(self->gemdos_handle, 1, &ch);
  if (result == 1)
	{
	++self->file_position;
	return(ch[0]);
	}
  if (result < 0)
	errno = self->last_error = result;
  self->flags |= STR_AT_EOF_P;
  return(EOF_VALUE);
}

local DEFMETHOD tyi_text_simple(self)
struct streamoid * self;
{
  int ch = tyi_binary_simple(self);
  if (ch == EOF_VALUE)
	return(ch);
  if (ch == '\r')
	{
	ch = tyi_binary_simple(self);
	if (ch != '\n')
		{
		method_call_1(self, METHOD_UNTYI, ch);
		return('\r');
		}
	}
  return(ch);
}

local DEFMETHOD tyo_binary_simple(self, byte)
struct streamoid * self;
int byte;
{
  char ch[1];
  int result;

  ch[0] = byte;
  result = Fwrite(self->gemdos_handle, 1, &ch[0]);
  if (result < 0)
	errno = self->last_error = result;
    else
	++self->file_position;
  return(result);
}

local DEFMETHOD tyo_text_simple(self, ch)
struct streamoid * self;
int ch;
{
  if (ch == '\n')
	tyo_binary_simple(self, '\r');
  tyo_binary_simple(self, ch);
}

local DEFMETHOD seek_simple(self, pos, how)
struct streamoid * self;
long pos;
int how;
{
  int res = Fseek(pos, self->gemdos_handle, how);
  
  self->flags &= ~STR_AT_EOF_P;
  if (res < 0)
	{
	errno = self->last_error = res;
	return(self->file_position = Fseek(0, self->gemdos_handle, L_INCR));
	}
    else
	return(self->file_position = res);
}

/*
   info method for console streamoids
*/
local short * linea_ptr = (short * )0;

local int console_info(self, b)
struct streamoid * self;
struct console_info_block * b;
{
  if (b)
	{
	if (!linea_ptr)
		{
		asm volatile (".word 0xA000");	/* line-a init */
		asm volatile ("movel a0,_linea_ptr");
		}
	b->linea = linea_ptr;
	b->maxx = 80;				/* kludge! */
	b->maxy = 24;
	b->curx = linea_ptr[-13];
	b->curx = linea_ptr[-13];
	}
  return(INF_CONSOLE);				/* say we give console info */
}

/*
   special purpose tyi method for interactive streamoids
*/
local DEFMETHOD tyi_interactive(self)
struct streamoid * self;
{
  int ch = tyi_binary_simple(self);
  if (ch == EOF_VALUE)
	return(ch);
  if (ch == 0x1A)				/* ^Z */
/*
   set eof, it can be cleared later
*/
	{
	self->flags |= STR_AT_EOF_P;
	return(EOF_VALUE);
	}
  if (ch == '\r')
	{
	method_call_1(self, METHOD_TYO, '\r');
	method_call_1(self, METHOD_TYO, '\n');
	return('\n');
	}
  return(ch);
}

/*
   fancy line-in method for console streamoids, using input-editor
*/
local int ie_tyi(self)
struct streamoid * self;
{
  return(method_call_0(self, METHOD_TYI));
}

local int ie_tyo(self, ch)
struct streamoid * self;
int ch;
{
  return(method_call_1(self, METHOD_TYO, ch));
}

local DEFMETHOD ie_line_in(self, buf, nbytes_buf)
struct streamoid * self;
char * buf;
int nbytes_buf;
{
  int term_char;

  *buf = '\0';
  term_char = __input_editor(self, buf, nbytes_buf - 1, ie_tyi, ie_tyo);
  if (term_char == '\n')
	strcat(buf, "\n");
  return(strlen(buf));
}

/*
   The method vectors for gem-file streamoids
*/
local method_fun gem_buffered_text_methods[] =
	{
	m_close,			/* default close method */
	m_tyi_text,			/* buffered-stream tyi text */
	m_untyi_byte,
	m_tyo_text,
	m_line_in,
	m_line_out,
	m_string_in,
	m_string_out,
	m_seek,
	m_no_info,			/* no info method */
	next_input_buffer,
	send_output_buffer,
	seek_internal,
	close_internal
	};

local method_fun gem_buffered_binary_methods[] =
	{
	m_close,			/* default close method */
	m_tyi_binary,			/* buffered-stream tyi bin */
	m_untyi_byte,
	m_tyo_binary,
	m_line_in,
	m_line_out,
	m_string_in,
	m_string_out,
	m_seek,
	m_no_info,			/* no info method */
	next_input_buffer,
	send_output_buffer,
	seek_internal,
	close_internal
	};

local method_fun gem_unbuffered_text_methods[] =
	{
	m_close,			/* default close method */
	tyi_text_simple,
	m_untyi_byte,
	tyo_text_simple,
	m_line_in,
	m_line_out,
	m_string_in,
	m_string_out,
	seek_simple,
	m_no_info			/* no info method.  see below */
	};

local method_fun gem_unbuffered_binary_methods[] =
	{
	m_close,			/* default close method */
	tyi_binary_simple,
	m_untyi_byte,
	tyo_binary_simple,
	m_line_in,
	m_line_out,
	m_string_in,
	m_string_out,
	seek_simple,
	m_no_info			/* no info method.  see below */
	};

/*
   the thing that constructs combined methods for gem-file frobs.
*/
gem_method_selector(self, flags)
struct streamoid * self;
int flags;
{
  method_fun * m;
  int n;

  if (flags & STR_BUFFERED_P)
	{
	if (flags & STR_TEXT_P)
		m = gem_buffered_text_methods;
	    else
		m = gem_buffered_binary_methods;
	n = METHODS_BUFFERED;
	}
    else
    	{
	if (flags & STR_TEXT_P)
		m = gem_unbuffered_text_methods;
	    else
		m = gem_unbuffered_binary_methods;
	n = METHODS_UNBUFFERED;
	}
  self->method = __clone_method_vector(m, n);
  if (flags & STR_INTERACTIVE_P)
	{
/* this is wrong!  need a better way of telling what
   a handle is connected to! */
	self->method[METHOD_INFO] = console_info;

	self->method[METHOD_TYI] = tyi_interactive;
	self->method[METHOD_READL] = ie_line_in;
	}
  self->n_methods = n;  
}

