/*
 * Fonctions d'acces aux fichiers
 * (c)1991 par Denis GOUNELLE
 */

#include "aroff.h"
#include "pile.h"

extern struct TeteListe TMac ;
extern struct Macro *CurrentMacro ;
extern struct String *CurrentString ;
extern unsigned char OutputBuf[], Arg[] ;
extern struct InputFile *CurrentInputFile ;
extern long InputMode, OutputLen, TmpLineLen, ArgLen, Flg, EmptyToWrite ;

/***********************************************************************/

static long GetFromMac()
{
  register unsigned long c ;
  register struct Macro *m ;

  m = CurrentMacro ;

  if ( (m->m_NextL) && (m->m_NextC >= m->m_NextL->ml_Len) )
  {
    m->m_NextC = 0 ;
    m->m_NextL = (struct MLine *)m->m_NextL->ml_Node.el_Suivant ;
    return( '\n' ) ;
  }

  if ( m->m_NextL )
  {
    c = m->m_NextL->ml_Text[m->m_NextC] ;
    m->m_NextC++ ;
    return( c ) ;
  }

  return( EOF ) ;
}

/***********************************************************************/

long GetChar()
{
  char *p ;
  struct InputFile *f ;
  register unsigned long c ;
  register struct Macro *m ;
  register struct String *s ;

_restart:

  if ( InputMode & IM_EXMACRO )
  {
    for (;;)
    {
      c = GetFromMac() ;
      if ( c != EOF ) return( c ) ;

      BCLR( Flg , F_TRAP ) ;
      InputMode = Pop( TE_INMODE , 1 ) ;

      if ( InputMode & IM_STRING )
      {
	s = (struct String *)Pop( TE_STRING , 1 ) ;
	CurrentString = s ;
      }
      if (! (InputMode & IM_EXMACRO)) break ;

      m = (struct Macro *)Pop( TE_MACRO , 1 ) ;

      CurrentMacro = m ;
      if ( m->m_Flag & MF_TRAP ) BSET( Flg , F_TRAP ) ;
      if ( m->m_Flag & MF_WAIT )
      {
	BCLR( m->m_Flag , MF_WAIT ) ;
	p = (char *)Pop( TE_OUTLINE , 1 ) ;
	c = Pop( TE_TOWRITE , 0 ) ;
	if ( c != -1 ) EmptyToWrite = c ;
	LigneSuiv( p ) ;
	free( p ) ;
      }
    }

    while (! (Flg & F_TRAP))
    {
      p = (char *)Pop( TE_OUTLINE , 0 ) ;
      if ( (! p) || (p == (char *)-1) ) break ;
      c = Pop( TE_TOWRITE , 0 ) ;
      if ( c != -1 ) EmptyToWrite = c ;
      LigneSuiv( p ) ;
      free( p ) ;
    }

    if ( Flg & F_TRAP ) goto _restart ;
    BCLR( InputMode , IM_EXMACRO ) ;
    CurrentMacro = NULL ;
  }

  if ( InputMode & IM_STRING )
  {
    s = CurrentString ;
    if ( s->s_pos >= s->s_len )
    {
      free( s ) ;
      InputMode = Pop( TE_INMODE , 1 ) ;
      if ( InputMode & IM_STRING )
      {
	s = (struct String *)Pop( TE_STRING , 1 ) ;
	CurrentString = s ;
      }
      else if ( InputMode & IM_EXMACRO )
      {
	m = (struct Macro *)Pop( TE_MACRO , 1 ) ;
	CurrentMacro = m ;
      }
      goto _restart ;
    }
    c = s->s_val[s->s_pos] ;
    s->s_pos++ ;
    return( c ) ;
  }

  f = CurrentInputFile ;

  /* si fin du tampon, lit LGMAXBUF octets dans le fichier */

  if ( f->if_NextC >= f->if_BufLen )
  {
    if ( f->if_Flag & IFF_LOADED ) return( EOF ) ;

    f->if_NextC = 0 ;
    f->if_BufLen = read( f->if_Desc , f->if_Buf , LGMAXBUF ) ;
    if (f->if_BufLen == -1 ) Fatal( ERR_READ ) ;
    if (! f->if_BufLen) return( EOF ) ;
  }

  /* lecture normale */

  c = f->if_Buf[f->if_NextC] ;
  f->if_NextC++ ;
  return( c ) ;
}

/***********************************************************************/

long PutChar( c )
unsigned char c ;

{
  register struct MLine *l ;

  if ( InputMode & IM_RDMACRO )
  {
    if ( c == '\n' ) CurrentMacro->m_NextL = NULL ;

    l = CurrentMacro->m_NextL ;
    if ( ! l )
    {
      l = (struct MLine *)myalloc( sizeof(struct MLine) , 1 ) ;
      InsereQueue( &(CurrentMacro->m_Def) , l ) ;
      CurrentMacro->m_NextL = l ;
      CurrentMacro->m_NextC = 0 ;
    }

    if ( c == '\n' ) return( 0 ) ;

    if ( l->ml_Len >= LGMAXSTR ) Fatal( ERR_OVERFLOW ) ;
    l->ml_Text[l->ml_Len] = c ;
    l->ml_Len++ ;
    return( 0 ) ;
  }

  if ( InputMode & IM_RDARGS )
  {
    if ( ArgLen >= LGMAXSTR ) Fatal( ERR_OVERFLOW ) ;
    Arg[ArgLen] = c ;
    ArgLen++ ;
    return( 0 ) ;
  }

  if ( OutputLen >= LGMAXBUF ) Fatal( ERR_OVERFLOW ) ;
  OutputBuf[OutputLen] = c ;
  OutputLen++ ;
  return( OutputLen > TmpLineLen ) ;
}

/***********************************************************************/

struct InputFile *NewFile( name )
char *name ;

{
  long lg ;
  struct InputFile *f ;

  f = (struct InputFile *)myalloc( sizeof(struct InputFile) , 1 ) ;

  if (! strcmp( name , "-" ))
  {
    f->if_Desc = 0 ;
    f->if_Name = "stdin" ;
    BSET( f->if_Flag , IFF_STDIN ) ;
  }
  else
  {
    f->if_Name = (char *)myalloc( strlen(name)+1 ) ;
    strcpy( f->if_Name , name ) ;
    f->if_Desc = open( name , O_RDONLY ) ;
  }

  if ( f->if_Desc == -1 ) Fatal( ERR_OPEN ) ;

  /* charge le fichier en memoire */

  if ( Flg & F_LOADED )
  {
    lg = lseek( f->if_Desc , 0 , 2 ) ;
    if ( lg < 1 ) Fatal( ERR_EMPTY ) ;
    if ( lg == -1 ) Fatal( ERR_SEEK ) ;
    if ( lseek( f->if_Desc , 0 , 0 ) == -1 ) Fatal( ERR_SEEK ) ;
    f->if_Buf = (unsigned char *)myalloc( lg , 0 ) ;
    f->if_BufLen = lg ;
    if ( read( f->if_Desc , f->if_Buf , lg ) != lg ) Fatal( ERR_READ ) ;
    close( f->if_Desc ) ;
    BSET( f->if_Flag , IFF_LOADED ) ;
  }
  else f->if_Buf = (unsigned char *)myalloc( LGMAXBUF , 0 ) ;

  f->if_Line = 1 ;
  return( f ) ;
}

/**************************************************************************/

void CloseFile( f )
struct InputFile *f ;

{
  if ( (f != NULL) &&
       (f != (struct InputFile *)-1) &&
       (f->if_Desc > 0) )
  {
    if ( f->if_Buf ) free( f->if_Buf ) ;
    if ( f->if_Flag & (IFF_STDIN|IFF_LOADED) ) return ;

    close( f->if_Desc ) ;
    free( f->if_Name ) ;
    f->if_Desc = -1 ;
  }
}

