//-----------------------------------------------------------------------------
// Copyright © 2003 - Philip Howard - All rights reserved
//
// 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 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//-----------------------------------------------------------------------------
// package	libh/string
// homepage	http://libh.slashusr.org/
//-----------------------------------------------------------------------------
// author	Philip Howard
// email	libh at ipal dot org
// homepage	http://phil.ipal.org/
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier
// and in a display at least 120 columns wide.
//-----------------------------------------------------------------------------

#include "string_lib.h"

__FMACRO_BEGIN__
//-----------------------------------------------------------------------------
// macros	str_app_da str_app_dA
//		str_app_de str_app_dE
//		str_app_df str_app_dF
//		str_app_dg str_app_dG
//
// purpose	Append to the first string (given with maximum available space)
//		a string of digits representing the double value.  Use a format
//		type the same as the ending character of the macro.
//
//		Do append only if all the digits can be appended.
//
// arguments	1 (char *) pointer to target string
//		2 (size_t) maximum space in target string
//		3 (double) the number to convert
//		4 (int) total conversion field size
//		5 (int) fractional precision size
//
// returns	(size_t) new length of string, or ~0 for error
//
// note		Contents of available space after the termination character
//		are destroyed if the append fails due to insufficient space.
//		Nothing should be kept there, anyway.
//-----------------------------------------------------------------------------
#if LIBC1999 == 1
#define str_app_da(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'a')
#define str_app_dA(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'A')
#endif

#define str_app_de(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'e')
#define str_app_dE(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'E')

#define str_app_df(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'f')
#define str_app_dF(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'F')

#define str_app_dg(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'g')
#define str_app_dG(t,s,v,f,p)	str_app_d((t),(s),(v),(f),(p),'G')

__FMACRO_END__

__PROTO_BEGIN__
//-----------------------------------------------------------------------------
// function	str_app_d
//
// purpose	Append to the first string (given with maximum available space)
//		a string of digits representing the double value.
//
//		Do append only if all the digits can be appended.
//
// arguments	1 (char *) pointer to target string
//		2 (size_t) maximum space in target string
//		3 (double) the number to convert
//		4 (int) total conversion field size
//		5 (int) fractional precision size
//		6 (int) (char) format type, one of (a,A,e,E,f,F,g,G)
//
// returns	(size_t) new length of string, or ~0 for error
//
// note		Contents of available space after the termination character
//		are destroyed if the append fails due to insufficient space.
//		Nothing should be kept there, anyway.
//-----------------------------------------------------------------------------
size_t
str_app_d (
    char *		arg_target
    ,
    size_t		arg_length
    ,
    double		arg_value
    ,
    int			arg_field
    ,
    int			arg_prec
    ,
    int			arg_format
    )
__PROTO_END__
{
    char		convert_space	[(CHAR_BIT * sizeof (double) + 8)];
    char		format_string	[8];


    //------------------------
    // Check format type code.
    //------------------------
    if ( arg_format != 'f' && arg_format != 'F'
      && arg_format != 'e' && arg_format != 'E'
      && arg_format != 'g' && arg_format != 'G'
#if LIBC1999 == 1
      && arg_format != 'a' && arg_format != 'A'
#endif
	) return ~0;

    //-------------------
    // Set up the format.
    //-------------------
    format_string[0] = '%';
    format_string[1] = '#';
    format_string[2] = '*';
    format_string[3] = '.';
    format_string[4] = '*';
    format_string[5] = arg_format;
    format_string[6] = 0;

    //---------------------------------
    // Make sure we don't go oversized.
    //---------------------------------
    if ( arg_field <= 0 ) arg_field = 1;
    if ( arg_field >= sizeof convert_space ) arg_field = sizeof convert_space - 1;
    if ( arg_prec >= arg_field ) arg_prec = arg_field - 1;
    if ( arg_prec <= 0 ) arg_prec = 0;

    //--------------------------------
    // Let snprintf do the conversion.
    //--------------------------------
    snprintf( convert_space,
	      sizeof convert_space,
	      format_string,
	      arg_field,
	      arg_prec,
	      arg_value
    );

    //---------------------------------------
    // Return appending to the target string.
    //---------------------------------------
    return str_app_str( arg_target, arg_length, convert_space );
}

