/*
**
** Copyright (C) 1994 Swedish University Network (SUNET)
**
**
** This program is developed by UDAC, Uppsala University by commission
** of the Swedish University Network (SUNET). 
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**
**                                        Martin.Wendel@udac.uu.se
**                                        Torbjorn.Wictorin@udac.uu.se
**
**                                        UDAC	
**                                        P.O. Box 174
**                                        S-751 04 Uppsala
**                                        Sweden
**
*/


#include	<signal.h>
#include	<stdlib.h>
#include 	"emil.h"

#define	MAXSZ	256*1024	/* Maximum amount to allocate */
#define	MULTF	4		/* Increase factor */

#ifdef	SIGDANGER
extern	int	psdanger(int);
#endif

static	int	pz;

extern	int	in_fd;

static	void * Zalloc(void * old, off_t prevsize, off_t newsize)
{
	/* Allocate memory */


        void	* Z;

	if (newsize == 0)
	  newsize = 1;
	
	if (old == NULL)
	  {
		assert (prevsize == 0);
		Z 	= malloc((size_t)newsize);
	  }
	else {
		assert (prevsize != 0);
		assert (prevsize < newsize);
		Z	= realloc(old,(size_t)newsize);
	}

	if (Z == NULL) {
		logger(LOG_ERR,"load_data cannot allocate memory");
		closelog();
		exit(1);
	}
	memset(((char *) Z) + prevsize, 0, newsize - prevsize);
	return	Z;
}

struct data *
load_data()
{
	struct data *out;
	long chunk;
#ifdef	SIGDANGER
	long border;
#endif
	char	* tmp;
	int	l;

	/* Allocate an output struct */

	out	= (struct data *) Zalloc(NULL,0,sizeof(struct data));

	/* And an initial output buffer */

#ifdef	HAVE_GETPAGESIZE
	chunk		= pz = (int) getpagesize();
#elif	hpux
	chunk		= pz = 4096;
#else
	chunk		= pz = sysconf(_SC_PAGESIZE);
#endif

	out->contents	= (char *) Zalloc(NULL,0,chunk);
	out->size	= chunk;

	/* Read all on standard input and reallocate buffer if required */

	while ((l=read(in_fd, (out->contents + out->end), chunk)) > 0) {
		out->end	+= l;
		chunk		*= MULTF;
	    	if (chunk > MAXSZ) chunk = MAXSZ;
#ifdef	SIGDANGER
		border = (psdanger(SIGDANGER) * pz) / 2; 
		if (chunk > border)	chunk = border;
#endif
		/*
		 sprintf(ebuf,"load_data: realloc %ld to %ld\n",
			out->size,chunk);
		 logger(LOG_DEBUG,ebuf);
		*/
		out->contents	=  
			(char *)Zalloc(out->contents,out->size,out->size+chunk);
		out->size	+= chunk;
	}

	out->contents[out->end] = 0;

	/* Count number of lines */

	for (	tmp = out->contents, out->lend = 0;
		(tmp= index(tmp,'\n')) != NULL;
		tmp++)	out->lend++;

	return(out);
}

int
append_data(struct data *d, char *c, int len)
{
  if (d->size == 0)
    {
      if ((d->contents = Zalloc(NULL, 0, 10240)) == NULL)
	return(NOK);
      d->size = 10240;
    }
  while ((len + d->end + 1) >= d->size)	/* TW 941220 */
    {
      if ((d->contents = Zalloc(d->contents,d->size,d->size+10240)) == NULL)
	return(NOK);
      d->size += 10240;
    }
  /* bcopy(c, (d->contents + d->end), len); */
  memcpy((d->contents + d->end), c, (off_t) len);
  
  d->end += len;
  d->bodyend += len;
  
  return(OK);
}

int
append_char(struct data *d, char c)
{
  if (d->size == 0)
    {
      if ((d->contents = Zalloc(NULL, 0, 10240)) == NULL)
	return(NOK);
      d->size = 10240;
    }
  while ((1 + 1 + d->end) >= d->size)	/* 941220 / TW */
    {
      if ((d->contents = Zalloc(d->contents,d->size,d->size+10240)) == NULL)
	return(NOK);
      d->size += 10240;
    }
  *(d->contents + d->end) = c;
  d->end += 1;
  d->bodyend += 1;
  return(OK);
}
