/*
 * i o . c 					-- Low level I/O
 * 
 * Copyright (C) 1993,1994,1995 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
 * 
 *
 * Permission to use, copy, and/or distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that both the above copyright notice and this permission notice appear in
 * all copies and derived works.  Fees for distribution or use of this
 * software or derived works may only be charged with express written
 * permission of the copyright holder.  
 * This software is provided ``as is'' without express or implied warranty.
 *
 * This software is a derivative work of other copyrighted softwares; the
 * copyright notices of these softwares are placed in the file COPYRIGHTS
 *
 *           Author: Erick Gallesio [eg@kaolin.unice.fr]
 *    Creation date: ????
 * Last file update: 14-Apr-1995 19:38
 */

#include "stk.h"
#include "sport.h"

#define BUFFER_SIZE     1024
#define SYSTEM(instr)   {long flag = No_interrupt(1); instr; No_interrupt(flag);}
#define STRING_PORTP(f) (((struct str_iob *) f)->signature == SPORT_SIGNATURE)

static char buffer[BUFFER_SIZE+1];
static int  bufidx=0;
static int  count=-1;
static int previous_char;
static int  ungetted = 0;
static int  filled=0;


#ifdef USE_TK
extern int tk_NumMainWindows;
#endif

static void badport(int read)
{
  Err(read ? "String port is not open for reading"
           : "String port is not open for writing",
      NIL);
}

void STk_StdinProc()
{
  SYSTEM(count = read(fileno(stdin), buffer, BUFFER_SIZE););
  filled = 1;
}

int STk_getc(FILE *f)
{
  if (f == stdin) {
    if (ungetted) {
      ungetted = 0;
      return previous_char;
    }
    if (bufidx < count) return buffer[bufidx++];
    else {
#ifdef USE_TK
      if (Tk_initialized) {
	filled = 0;
	while (!filled) {
	  Tk_DoOneEvent(0);
	  if (tk_NumMainWindows <= 0) return EOF;
	}
      }
      else
#endif
      STk_StdinProc();

      if (count <= 0) return EOF;
      else {
	bufidx = 1;
	return *buffer;
      }
    }
  }
  else
    if (STRING_PORTP(f)) {
      register struct str_iob *g = (struct str_iob *)f;
      if (!(g->flag & READING)) badport(TRUE);
      return (--(g->cnt)>=0? ((int)*g->ptr++): EOF);
    }
    else {
      int result;
      SYSTEM(result=getc(f));
      return result;
    }
}

int STk_ungetc(int c, FILE *f)
{
  if (f == stdin) {
    ungetted = 1;
    previous_char = c;
  }
  else
    if (STRING_PORTP(f)) {
      register struct str_iob *g = (struct str_iob *)f;
      if (g->ptr == g->base) Err("INTERNAL ERROR: cannont unget char", NIL);
      if (!(g->flag & READING)) badport(TRUE);
      g->ptr--;
      g->cnt++;
    }
    else
      SYSTEM(ungetc(c, f));
  return c;
}

int STk_putc(int c, FILE *f)
{
  if (STRING_PORTP(f)) {
    register struct str_iob *g = (struct str_iob *)f;
    register int tmp;

    if (!(g->flag & WRITING)) badport(FALSE);
    if (++g->cnt == g->bufsiz) {
      tmp 	 = g->bufsiz;
      tmp 	+= tmp/2;
      g->base	 = must_realloc(g->base, tmp);
      g->ptr 	 = g->base + g->bufsiz - 1; /* since base can have been moved */
      g->bufsiz	 = tmp;
    }
    *g->ptr++ = (char) c;
  }
  else 
    SYSTEM(fputc(c, f));
  return c;
}

int STk_puts(char *s, FILE *f)
{
  if (STRING_PORTP(f)) {
    while (*s) STk_putc(*s++, f);
    return 0;
  }
  else {
    int result;
    SYSTEM(result = fputs(s, f));
    return result;
  }
}

int STk_eof(FILE *f)
{
  if (STRING_PORTP(f))
    return (((struct str_iob *)f)->cnt <= 0);
  else {
    int result;
    SYSTEM(result=feof(f));
    return result;
    }
}
