/*  File: freeout.c
 *  Author: Danielle et jean Thierry-Mieg (mieg@mrc-lmba.cam.ac.uk)
 *  Copyright (C) J Thierry-Mieg and R Durbin, 1995
 * -------------------------------------------------------------------
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * -------------------------------------------------------------------
 * This file is part of the ACEDB genome database package, written by
 * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmba.cam.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@frmop11.bitnet
 *
 * Description:
 * Exported functions: see regular.h
 * HISTORY:
 * Last edited: Nov  3 13:14 1999 (fw)
 * * Sep 11 09:26 1998 (edgrif): Add messExit function registering.
 * * Dec 14 16:47 1995 (mieg)
 * Created: Thu Dec  7 22:22:33 1995 (mieg)
 *-------------------------------------------------------------------
 */

/* $Id: freeout.c,v 1.23 2004/08/22 02:18:17 mieg Exp $ */

#include "freeout.h"
#include <ctype.h>
#include <glib.h>

typedef struct outStruct { int magic ;
			   FILE *fil ;
			   Stack s ;
			   int line ;  /* line number */
			   int pos ;   /* char number in line */
			   int byte ;  /* total byte length */
			   int level ;
			   struct outStruct *next ;
			 } OUT ;

static int MAGIC = 245393 ;
static int outLevel = 0 ;
static Array outArray = 0 ;
static OUT *outCurr ;
static Stack outBuf = 0 ;  /* buffer for messages */
#define BUFSIZE 65536 

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

void freeOutInit (void)
{
  static BOOL isInitialised = FALSE ;
  
  if (!isInitialised)
    { isInitialised = TRUE ;
      outLevel = 0 ;
      outCurr = 0 ;
      outArray = arrayCreate (6, OUT) ;
      freeOutSetFile (stdout) ;
      outBuf = stackCreate (BUFSIZE) ;
    }
}

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

static int freeOutSetFileStack (FILE *fil, Stack s)
{ int i = 0 ;

  freeOutInit () ;
  while (array (outArray, i, OUT).magic) i++ ;
  
  outLevel++ ;
  outCurr = arrayp (outArray, i, OUT) ;
  if (fil) outCurr->fil = fil ;
  else if (s) outCurr->s = s ;
  outCurr->line = outCurr->pos = outCurr->byte = 0 ;    
  outCurr->next = 0 ;
  outCurr->level = outLevel ;
  outCurr->magic = MAGIC ;
  return outLevel ;
}

int freeOutSetFile (FILE *fil)
{ return freeOutSetFileStack (fil, 0) ;
}

int freeOutSetStack (Stack s)
{ return freeOutSetFileStack (0, s) ;
}

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

void freeOutClose (int level)
{ int  i = arrayMax (outArray) ;
  OUT *out ;
  
  while (i--)
    { out = arrayp (outArray, i, OUT) ;
      if (!out->magic)
	continue ;
      if (out->magic != MAGIC)
	messcrash("bad magic in freeOutClose") ;
      if (out->level >= outLevel)  /* close all tees */
	{ /* do NOT close fil, because freeOutSetFile did not open it */
	  out->s = 0 ; out->fil = 0 ;
	  outCurr->line = outCurr->pos = outCurr->byte = 0 ;    
	  out->next = 0 ;
	  out->magic = 0 ;
	  out->level = 0 ;
	}
      else
	break ;
    }
  outLevel-- ;
  outCurr = arrayp (outArray, i, OUT) ;
  if (outCurr->level != outLevel)
    messcrash ("anomaly in freeOutClose") ;
}

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

void freeOut (char *text)
{ OUT *out = outCurr ;
  char *cp ;
  int pos = 0, line = 0, ln  ;
  
  cp = text ;
  ln = strlen(text) ;
  while (*cp) 
    if (*cp++ == '\n') 
      { pos = 0 ; line++ ;}
    else
      pos++ ;
  while (out)
    { if (out->s)
	catText(out->s, text) ;
      if (out->fil)
	fputs(text, out->fil) ; /* fprintf over interprets % and \ */
      out->byte += ln ;
      if (line)
	{ out->line += line ; out->pos = pos ; }
      else
	out->pos += pos ;
      out = out->next ;
    }
}

/*************************************************************/
/* copy a binary structure onto a text stack */
void freeOutBinary (char *data, int size)
{ 
  OUT *out = outCurr ;
  if (out->fil)
    fwrite(data,size,1,out->fil);
  else if (out->s) {
    catBinary (out->s,data,size);
    /* acts like a newline was added */
    out->pos = 0;
    out->line++;
  }
}

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

void freeOutxy (char *text, int x, int y)
{ static Array buf = 0 ;
  OUT *out = outCurr ;
  int i, j, k = 0 ;

  i = x - out->pos , j = y - out->line ;
  if (i || j)
    { buf = arrayReCreate (buf, 100, char) ;
      k = 0 ;
      if (j > 0)
	{ while (j--)
	    array (buf, k++, char) = '\n' ;
	  i = x ;
	}
      if (i < 0)
	{ array (buf, k++, char) = '\n' ;
	  i = x ; out->line-- ; /* kludge, user should ignore this line feed */
	}
      if (i > 0)
	{ while (i--)
	    array (buf, k++, char) = ' ' ;
	}
      array (buf, k++, char) = 0 ;
      freeOut (arrp(buf, 0, char)) ;
    }
  freeOut (text) ;
}

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

void freeOutf (char *format,...)
{ 
  int len ;
  char *message ;
  va_list ap; 

  stackClear (outBuf) ;

  va_start(ap, format);
  len = g_printf_string_upper_bound (format, ap) ;
  va_end (ap) ;

  stackExtend (outBuf, len + 1) ;
  message = stackText (outBuf, 0) ;

  va_start (ap, format);
  len = vsprintf (message, format, ap) ;
  va_end (ap) ;

  freeOut (message) ;
}

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

int freeOutLine (void)
{ return outCurr->line ; }

int freeOutByte (void)
{ return outCurr->byte ; }

int freeOutPos (void)
{ return outCurr->pos ; }

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














 
