#ifndef INCLUDED_ircd_snprintf_h
#define INCLUDED_ircd_snprintf_h
/*
 * IRC - Internet Relay Chat, include/ircd_snprintf.h
 * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
 *
 * 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 3, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: ircd_snprintf.h 2156 2008-06-10 00:46:03Z sirvulcan $
 */
#ifndef INCLUDED_sys_types_h
#include <sys/types.h>
#define INCLUDED_sys_types_h
#endif
#ifndef INCLUDED_stdarg_h
#include <stdarg.h>
#define INCLUDED_stdarg_h
#endif

struct Client;

/* structure passed as argument for %v conversion */
struct VarData {
  size_t	vd_chars;	/* number of characters inserted */
  size_t	vd_overflow;	/* number of characters that couldn't be */
  const char   *vd_format;	/* format string */
  va_list	vd_args;	/* arguments for %v */
};

#ifndef HAVE_VA_COPY
#if HAVE___VA_COPY
#define va_copy(DEST, SRC) __va_copy(DEST, SRC)
#else
#define va_copy(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof(DEST))
#endif
#endif

extern int ircd_snprintf(struct Client *dest, char *buf, size_t buf_len,
			 const char *format, ...);
extern int ircd_vsnprintf(struct Client *dest, char *buf, size_t buf_len,
			  const char *format, va_list args);

/*
** ircd_(v)snprintf
**
**   These functions are intended to be a complete replacement for
** sprintf and sprintf_irc.  They are a (nearly) complete
** reimplementation, and of course they're snprintf clones, making it
** more difficult for accidental buffer overflows to crop up.
**
**   First off, what's missing?  These functions support all ANSI C
** conversion specifiers and selected ones from ISO 9x, with the
** exception of all floating-point conversions.  The floating-point
** conversions are tricky, and will likely be dependent on the
** representation of a floating-point number on a particular
** architecture.  While that representation is likely to conform to
** some standard, it is not currently used in ircu, so seemed like a
** good thing to omit, given the difficulty of implementing it.
**
**   There are two more things missing from this implementation that
** would be required by ANSI; the first is support for multibyte
** character strings, and the second is support for locales, neither
** of which have any relevance for ircu, so again omission seemed to
** be a good policy.  Additionally, %#x always causes '0x' (or '0X')
** to be printed, even if the number is zero.
**
**   These functions also have some extensions not seen in a
** standards-compliant implementation; technically, the ISO 9x
** extensions fall into this category, for instance.  The ISO 9x
** extensions supported are type extensions--%ju, %tu, and %zu, for
** instance; %qu and %hhu are also supported.  The extensions added
** for use in ircu are %Tu, which takes a time_t, and the new %C
** conversion, which inserts either a numeric or a nick, dependant on
** the <dest> parameter.  The GNU %m extension, which inserts the
** strerror() string corresponding to the current value of errno, is
** also supported, as is a special %v extension, which essentially
** does a recursive call to ircd_snprintf.
**
**   The following description is descended from the Linux manpage for
** the printf family of functions.
**
**   The format string is composed of zero or more directives:
** ordinary characters (not %), which are copied unchanged to the
** output stream; and conversion specifications, each of which results
** in fetching zero or more subsequent arguments.  Each conversion
** specification is introduced by the character %.  The arguments must
** correspond properly (after type promotion) with the conversion
** specifier.  After the %, the following appear in sequence:
**
** * Zero or more of the following flags:
**
**   #	specifying that the value should be converted to an
**	"alternate form."  For c, d, i, n, p, s, and u conversions,
**	this option has no effect.  For o conversions, the precision
**	of the number is increased to force the first character of the
**	output string to a zero (except if a zero value is printed
**	with an explicit precision of zero).  For x and X conversions,
**	the string '0x' (or '0X' for X conversions) is prepended to
**	it.  For e, E, f, g, and G conversions, the result will always
**	contain a decimal point, even if no digits follow it
**	(normally, a decimal point appears in the results of those
**	conversions only if a digit follows).  For g and G
**	conversions, trailing zeros are not removed from the result as
**	they would otherwise be.  For C conversions, if the
**	destination is local and the origin is a user, the
**	nick!user@host form is used.
**
**   0	specifying zero padding.  For all conversions except n, the
**	converted value is padded on the left with zeros rather than
**	blanks.  If a precision is given with a numeric conversion (d,
**	i, o, u, i, x, and X), the 0 flag is ignored.
**
**   -	(a negative field width flag) indicates the converted value is
**	to be left adjusted on the field boundary.  Except for n
**	conversions, the converted value is padded on the right with
**	blanks, rather than on the left with blanks or zeros.  A -
**	overrides a 0 if both are given.
**
**  ' '	(a space) specifying that a blank should be left before a
**	positive number produced by a signed conversion (d, e, E, f,
**	g, G, or i).
**
**   +	specifying that a sign always be placed before a number
**	produced by a signed conversion.  A + overrides a space if
**	both are used.
**
**   :	specifying that a struct Client name should be preceded by a
**	':' character if the destination is a user
**
** * An optional decimal digit string specifying a minimum field
**   width.  If the converted value has fewer characters than the
**   field width, it will be padded with spaces on the left (or right,
**   if the left-adjustment flag has been given) to fill out the field
**   width.
**
** * An optional precision, in the form of a period (`.') followed by
**   an optional digit string.  If  the digit string is omitted, the
**   precision is taken as zero.  This gives the minimum number of
**   digits to appear for d, i, o, u, x, and X conversions, the number
**   of digits to appear after the decimal-point for e, E, and f
**   conversions, the maximum number of significant digits for g and G
**   conversions, or the maximum number of characters to be printed
**   from a string for s conversions.
**
** * The optional character h, specifying that a following d, i, o, u,
**   x, or X conversion corresponds to a short int or unsigned short
**   int argument, or that a following n conversion corresponds to a
**   pointer to a short int argument.  If the h character is given
**   again, char is used instead of short int.
**
** * The optional character l (ell) specifying that a following d, i,
**   o, u, x, or X conversion applies to a pointer to a long int or
**   unsigned long int argument, or that a following n conversion
**   corresponds to a pointer to a long int argument.
**
** * The character L specifying that a following e, E, f, g, or G
**   conversion corresponds to a long double argument, or a following
**   d, i, o, u, x, or X conversion corresponds to a long long
**   argument.  Note that long long is not specified in ANSI C and
**   therefore not portable to all architectures.
**
** * The optional character q.  This is equivalent to L.
**
** * A j character specifying that the following integer (d, i, o, u,
**   x, or X) conversion corresponds to an intmax_t argument.
**
** * A t character specifying that the following integer (d, i, o, u,
**   x, or X) conversion corresponds to a ptrdiff_t argument.
**
** * A z character specifying that the following integer (d, i, o, u,
**   x, or X) conversion corresponds to a size_t argument.
**
** * A T character specifying that the following integer (d, i, o, u,
**   x, or X) conversion corresponds to a time_t argument.
**
** * A character that specifies the type of conversion to be applied.
**
**   A field width or precision, or both, may be indicated by an
** asterisk `*' instead of a digit string.  In this case, an int
** argument supplies the field width or precision.  A negative field
** width is treated as a left adjustment flag followed by a positive
** field width; a negative precision is treated as though it were
** missing.
**
** The conversion specifiers and their meanings are:
**
** diouxX	The int (or appropriate variant) argument is converted
**		to signed decimal (d and i), unsigned octal (o),
**		unsigned decimal (u), or unsigned hexadecimal (x and
**		X) notation.  The letters abcdef are used for x
**		conversions; the letters ABCDEF are used for X
**		conversions.  The precision, if any, gives the minimum
**		number of digits that must appear; if the converted
**		value requires fewer digits, it is padded on the left
**		with zeros.
**
** eE		[NOT IMPLEMENTED] The double argument is rounded and
**		converted in the style [-]d.dddedd where there is one
**		digit before the decimal-point character and the
**		number of digits after it is equal to the precision;
**		if the precision is missing, it is taken as 6; if the
**		precision is zero, no decimal-point character appears.
**		An E conversion uses the letter E (rather than e) to
**		introduce the exponent.  The exponent always contains
**		at least two digits; if the value is zero, the
**		exponent is 00.
**
** f		[NOT IMPLEMENTED] The double argument is rounded and
**		converted to  decimal notation in the style
**		[-]ddd.ddd, where the number of digits after the
**		decimal-point character is equal to the precision
**		specification.  If the precision is missing, it is
**		taken as 6; if the precision is explicitly zero, no
**		decimal-point character appears.  If a decimal point
**		appears, at least one digit appears before it.
**
** g		[NOT IMPLEMENTED] The double argument is converted in
**		style f or e (or E for G conversions).  The precision
**		specifies the number of significant digits.  If the
**		precision is missing, 6 digits are given; if the
**		precision is zero, it is treated as 1.  Style e is
**		used if the exponent from its conversion is less than
**		-4 or greater than or equal to the precision.
**		Trailing zeros are removed from the fractional part of
**		the result; a decimal point appears only if it is
**		followed by at least one digit.
**
** c		The int argument is converted to an unsigned char, and
**		the resulting character is written.
**
** s		The "char *" argument is expected to be a pointer to
**		an array of character type (pointer to a string).
**		Characters from the array are written up to (but not
**		including) a terminating NUL character; if a precision
**		is specified, no more than the number specified are
**		written.  If a precision is given, no null character
**		need be present; if the precision is not specified, or
**		is greater than the size of the array, the array must
**		contain a terminating NUL character.
**
** p		The "void *" pointer argument is printed in
**		hexadecimal (as if by %#x or %#lx).
**
** n		The number of characters written so far is stored into
**		the integer indicated by the ``int *'' (or variant)
**		pointer argument.  No argument is converted.
**
** m		The error message associated with the current value of
**		errno is printed as if by %s.
**
** C		The client argument identifier is printed under the
**		control of the <dest> argument; if <dest> is NULL or
**		is a user, the client's name (nickname or server name)
**		is printed; otherwise, the client's network numeric is
**		printed.
**
** H		The channel argument identifier (channel name) is
**		printed.
**
** v		The argument given must be a pointer to a struct
**		VarData with vd_format and vd_args must be initialized
**		appropriately.  On return, vd_chars will contain the
**		number of characters added to the buffer, and
**		vd_overflow will contain the number of characters that
**		could not be added due to buffer overflow or due to a
**		precision.
**
** %		A `%' is written.  No argument is converted.  The
**		complete conversion specification is `%%'.
**
**   In no case does a non-existent or small field width cause
** truncation of a field; if the result of a conversion is wider than
** the field width, the field is expanded to contain the conversion
** result.
*/

#endif /* INCLUDED_ircd_snprintf_h */
