/* sts.c -- Implementation File (module.c template V1.0)
   Copyright (C) 1995 Free Software Foundation, Inc.
   Contributed by James Craig Burley (burley@gnu.ai.mit.edu).

This file is part of GNU Fortran.

GNU Fortran 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, or (at your option)
any later version.

GNU Fortran 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Fortran; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

   Related Modules:
      None (despite the name, it doesn't really depend on ffest*)

   Description:
      Provides an arbitrary-length string facility for the limited needs of
      GNU Fortran FORMAT statement generation.

   Modifications:
*/

/* Include files. */

#include "proj.h"
#include "sts.h"
#include "com.h"
#include "malloc.h"

/* Externals defined here. */


/* Simple definitions and enumerations. */


/* Internal typedefs. */


/* Private include files. */


/* Internal structure definitions. */


/* Static objects accessed by functions in this module. */


/* Static functions (internal). */


/* Internal macros. */


/* ffests_kill -- Kill a varying-length string

   ffests s;
   ffests_kill(s);

   The storage associated with the string <s> is freed.	 */

void
ffests_kill (ffests s)
{
  if (s->text_ != NULL)
    malloc_kill_ksr (s->pool_, s->text_, s->max_);
}

/* ffests_new -- Make a varying-length string

   ffests s;
   ffests_new(s,malloc_pool_image(),0);

   The string is initialized to hold, in this case, 0 characters, and
   current and future heap manipulations to hold the string will use
   the image pool.  */

void
ffests_new (ffests s, mallocPool pool, ffestsLength size)
{
  s->pool_ = pool;
  s->len_ = 0;
  s->max_ = size;

  if (size == 0)
    s->text_ = NULL;
  else
    s->text_ = malloc_new_ksr (pool, "ffests", size);
}

/* ffests_printf_1D -- printf("...%ld...",(long)) to a string

   ffests s;
   ffests_printf_1D(s,"...%ld...",1);

   Like printf, but into a string.  */

void
ffests_printf_1D (ffests s, char *ctl, long arg1)
{
  char quickbuf[40];
  char *buff;
  ffestsLength len;

  if ((len = strlen (ctl) + 21) < ARRAY_SIZE (quickbuf))
    /* No # bigger than 20 digits. */
    {
      sprintf (&quickbuf[0], ctl, arg1);
      ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
    }
  else
    {
      buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_1D", len);
      sprintf (buff, ctl, arg1);
      ffests_puttext (s, buff, strlen (buff));
      malloc_kill_ks (malloc_pool_image (), buff, len);
    }
}

/* ffests_printf_1U -- printf("...%lu...",(unsigned long)) to a string

   ffests s;
   ffests_printf_1U(s,"...%lu...",1);

   Like printf, but into a string.  */

void
ffests_printf_1U (ffests s, char *ctl, unsigned long arg1)
{
  char quickbuf[40];
  char *buff;
  ffestsLength len;

  if ((len = strlen (ctl) + 21) < ARRAY_SIZE (quickbuf))
    /* No # bigger than 20 digits. */
    {
      sprintf (&quickbuf[0], ctl, arg1);
      ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
    }
  else
    {
      buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_1U", len);
      sprintf (buff, ctl, arg1);
      ffests_puttext (s, buff, strlen (buff));
      malloc_kill_ks (malloc_pool_image (), buff, len);
    }
}

/* ffests_printf_1s -- printf("...%s...",(char *)) to a string

   ffests s;
   ffests_printf_1s(s,"...%s...","hi there!");

   Like printf, but into a string.  */

void
ffests_printf_1s (ffests s, char *ctl, char *arg1)
{
  char quickbuf[40];
  char *buff;
  ffestsLength len;

  if ((len = strlen (ctl) + strlen (arg1) - 1) < ARRAY_SIZE (quickbuf))
    {
      sprintf (&quickbuf[0], ctl, arg1);
      ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
    }
  else
    {
      buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_1s", len);
      sprintf (buff, ctl, arg1);
      ffests_puttext (s, buff, strlen (buff));
      malloc_kill_ks (malloc_pool_image (), buff, len);
    }
}

/* ffests_printf_2Us -- printf("...%lu...%s...",...) to a string

   ffests s;
   ffests_printf_2Us(s,"...%lu...%s...",1,"hi there!");

   Like printf, but into a string.  */

void
ffests_printf_2Us (ffests s, char *ctl, unsigned long arg1, char *arg2)
{
  char quickbuf[60];
  char *buff;
  ffestsLength len;

  if ((len = strlen (ctl) + 21 + strlen (arg2) - 1) < ARRAY_SIZE (quickbuf))
    /* No # bigger than 20 digits. */
    {
      sprintf (&quickbuf[0], ctl, arg1, arg2);
      ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
    }
  else
    {
      buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_2Us", len);
      sprintf (buff, ctl, arg1, arg2);
      ffests_puttext (s, buff, strlen (buff));
      malloc_kill_ks (malloc_pool_image (), buff, len);
    }
}

/* ffests_putc -- Put a single character into string

   ffests s;
   ffests_putc(s,'*');	*/

void
ffests_putc (ffests s, char c)
{
  ffests_puttext (s, &c, 1);
}

/* ffests_puts -- Put a zero-terminated (C-style) string into string

   ffests s;
   ffests_puts(s,"append me");	*/

void
ffests_puts (ffests s, char *string)
{
  ffests_puttext (s, string, strlen (string));
}

/* ffests_puttext -- Put a number of characters into string

   ffests s;
   ffests_puttext(s,"hi there",8);

   The string need not be 0-terminated, because the passed length is used,
   and may be 0.  */

void
ffests_puttext (ffests s, char *text, ffestsLength length)
{
  ffestsLength newlen;
  ffestsLength newmax;

  if (length <= 0)
    return;

  newlen = s->len_ + length;
  if (newlen > s->max_)
    if (s->text_ == NULL)
      {
	s->max_ = 40;
	s->text_ = malloc_new_ksr (s->pool_, "ffests", s->max_);
      }
    else
      {
	newmax = s->max_ << 1;
	while (newmax < newlen)
	  newmax <<= 1;
	s->text_ = malloc_resize_ksr (s->pool_, s->text_, newmax, s->max_);
	s->max_ = newmax;
      }

  memcpy (s->text_ + s->len_, text, length);
  s->len_ = newlen;
}
