hio/lib/hio-fmt.h

390 lines
17 KiB
C

/*
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _HIO_FMT_H_
#define _HIO_FMT_H_
#include <hio-cmn.h>
#include <stdarg.h>
/** \file
* This file defines various formatting functions.
*/
/* =========================================================================
* FORMATTED OUTPUT
* ========================================================================= */
typedef struct hio_fmtout_t hio_fmtout_t;
typedef int (*hio_fmtout_putbchars_t) (
hio_fmtout_t* fmtout,
const hio_bch_t* ptr,
hio_oow_t len
);
typedef int (*hio_fmtout_putuchars_t) (
hio_fmtout_t* fmtout,
const hio_uch_t* ptr,
hio_oow_t len
);
enum hio_fmtout_fmt_type_t
{
HIO_FMTOUT_FMT_TYPE_BCH = 0,
HIO_FMTOUT_FMT_TYPE_UCH
};
typedef enum hio_fmtout_fmt_type_t hio_fmtout_fmt_type_t;
struct hio_fmtout_t
{
hio_oow_t count; /* out */
hio_mmgr_t* mmgr; /* in */
hio_fmtout_putbchars_t putbchars; /* in */
hio_fmtout_putuchars_t putuchars; /* in */
hio_bitmask_t mask; /* in */
void* ctx; /* in */
/* internally set a input */
hio_fmtout_fmt_type_t fmt_type;
const void* fmt_str;
};
/* =========================================================================
* INTMAX FORMATTING
* ========================================================================= */
/**
* The hio_fmt_intmax_flag_t type defines enumerators to change the
* behavior of hio_fmt_intmax() and hio_fmt_uintmax().
*/
enum hio_fmt_intmax_flag_t
{
/* Use lower 6 bits to represent base between 2 and 36 inclusive.
* Upper bits are used for these flag options */
/** Don't truncate if the buffer is not large enough */
HIO_FMT_INTMAX_NOTRUNC = (0x40 << 0),
#define HIO_FMT_INTMAX_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_UINTMAX_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_INTMAX_TO_BCSTR_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_UINTMAX_TO_BCSTR_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_INTMAX_TO_UCSTR_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_UINTMAX_TO_UCSTR_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_INTMAX_TO_OOCSTR_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
#define HIO_FMT_UINTMAX_TO_OOCSTR_NOTRUNC HIO_FMT_INTMAX_NOTRUNC
/** Don't append a terminating null */
HIO_FMT_INTMAX_NONULL = (0x40 << 1),
#define HIO_FMT_INTMAX_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_UINTMAX_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_INTMAX_TO_BCSTR_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_UINTMAX_TO_BCSTR_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_INTMAX_TO_UCSTR_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_UINTMAX_TO_UCSTR_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_INTMAX_TO_OOCSTR_NONULL HIO_FMT_INTMAX_NONULL
#define HIO_FMT_UINTMAX_TO_OOCSTR_NONULL HIO_FMT_INTMAX_NONULL
/** Produce no digit for a value of zero */
HIO_FMT_INTMAX_NOZERO = (0x40 << 2),
#define HIO_FMT_INTMAX_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_UINTMAX_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_INTMAX_TO_BCSTR_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_UINTMAX_TO_BCSTR_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_INTMAX_TO_UCSTR_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_UINTMAX_TO_UCSTR_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_INTMAX_TO_OOCSTR_NOZERO HIO_FMT_INTMAX_NOZERO
#define HIO_FMT_UINTMAX_TO_OOCSTR_NOZERO HIO_FMT_INTMAX_NOZERO
/** Produce a leading zero for a non-zero value */
HIO_FMT_INTMAX_ZEROLEAD = (0x40 << 3),
#define HIO_FMT_INTMAX_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_UINTMAX_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_INTMAX_TO_BCSTR_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_UINTMAX_TO_BCSTR_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_INTMAX_TO_UCSTR_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_UINTMAX_TO_UCSTR_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_INTMAX_TO_OOCSTR_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
#define HIO_FMT_UINTMAX_TO_OOCSTR_ZEROLEAD HIO_FMT_INTMAX_ZEROLEAD
/** Use uppercase letters for alphabetic digits */
HIO_FMT_INTMAX_UPPERCASE = (0x40 << 4),
#define HIO_FMT_INTMAX_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_UINTMAX_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_INTMAX_TO_BCSTR_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_UINTMAX_TO_BCSTR_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_INTMAX_TO_UCSTR_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_UINTMAX_TO_UCSTR_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_INTMAX_TO_OOCSTR_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
#define HIO_FMT_UINTMAX_TO_OOCSTR_UPPERCASE HIO_FMT_INTMAX_UPPERCASE
/** Insert a plus sign for a positive integer including 0 */
HIO_FMT_INTMAX_PLUSSIGN = (0x40 << 5),
#define HIO_FMT_INTMAX_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_UINTMAX_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_INTMAX_TO_BCSTR_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_UINTMAX_TO_BCSTR_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_INTMAX_TO_UCSTR_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_UINTMAX_TO_UCSTR_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_INTMAX_TO_OOCSTR_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
#define HIO_FMT_UINTMAX_TO_OOCSTR_PLUSSIGN HIO_FMT_INTMAX_PLUSSIGN
/** Insert a space for a positive integer including 0 */
HIO_FMT_INTMAX_EMPTYSIGN = (0x40 << 6),
#define HIO_FMT_INTMAX_EMPTYSIGN HIO_FMT_INTMAX_EMPTYSIGN
#define HIO_FMT_UINTMAX_EMPTYSIGN HIO_FMT_INTMAX_EMPTYSIGN
#define HIO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN HIO_FMT_INTMAX_EMPTYSIGN
#define HIO_FMT_UINTMAX_TO_BCSTR_EMPTYSIGN HIO_FMT_INTMAX_EMPTYSIGN
#define HIO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN HIO_FMT_INTMAX_EMPTYSIGN
#define HIO_FMT_UINTMAX_TO_UCSTR_EMPTYSIGN HIO_FMT_INTMAX_EMPTYSIGN
/** Fill the right part of the string */
HIO_FMT_INTMAX_FILLRIGHT = (0x40 << 7),
#define HIO_FMT_INTMAX_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_UINTMAX_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_INTMAX_TO_BCSTR_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_UINTMAX_TO_BCSTR_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_INTMAX_TO_UCSTR_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_UINTMAX_TO_UCSTR_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_INTMAX_TO_OOCSTR_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
#define HIO_FMT_UINTMAX_TO_OOCSTR_FILLRIGHT HIO_FMT_INTMAX_FILLRIGHT
/** Fill between the sign chacter and the digit part */
HIO_FMT_INTMAX_FILLCENTER = (0x40 << 8)
#define HIO_FMT_INTMAX_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_UINTMAX_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_INTMAX_TO_BCSTR_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_UINTMAX_TO_BCSTR_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_INTMAX_TO_UCSTR_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_UINTMAX_TO_UCSTR_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_INTMAX_TO_OOCSTR_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
#define HIO_FMT_UINTMAX_TO_OOCSTR_FILLCENTER HIO_FMT_INTMAX_FILLCENTER
};
#if defined(__cplusplus)
extern "C" {
#endif
/* =========================================================================
* FORMATTED OUTPUT
* ========================================================================= */
HIO_EXPORT int hio_bfmt_outv (
hio_fmtout_t* fmtout,
const hio_bch_t* fmt,
va_list ap
);
HIO_EXPORT int hio_ufmt_outv (
hio_fmtout_t* fmtout,
const hio_uch_t* fmt,
va_list ap
);
HIO_EXPORT int hio_bfmt_out (
hio_fmtout_t* fmtout,
const hio_bch_t* fmt,
...
);
HIO_EXPORT int hio_ufmt_out (
hio_fmtout_t* fmtout,
const hio_uch_t* fmt,
...
);
/* =========================================================================
* INTMAX FORMATTING
* ========================================================================= */
/**
* The hio_fmt_intmax_to_bcstr() function formats an integer \a value to a
* multibyte string according to the given base and writes it to a buffer
* pointed to by \a buf. It writes to the buffer at most \a size characters
* including the terminating null. The base must be between 2 and 36 inclusive
* and can be ORed with zero or more #hio_fmt_intmax_to_bcstr_flag_t enumerators.
* This ORed value is passed to the function via the \a base_and_flags
* parameter. If the formatted string is shorter than \a bufsize, the redundant
* slots are filled with the fill character \a fillchar if it is not a null
* character. The filling behavior is determined by the flags shown below:
*
* - If #HIO_FMT_INTMAX_TO_BCSTR_FILLRIGHT is set in \a base_and_flags, slots
* after the formatting string are filled.
* - If #HIO_FMT_INTMAX_TO_BCSTR_FILLCENTER is set in \a base_and_flags, slots
* before the formatting string are filled. However, if it contains the
* sign character, the slots between the sign character and the digit part
* are filled.
* - If neither #HIO_FMT_INTMAX_TO_BCSTR_FILLRIGHT nor #HIO_FMT_INTMAX_TO_BCSTR_FILLCENTER
* , slots before the formatting string are filled.
*
* The \a precision parameter specified the minimum number of digits to
* produce from the \a value. If \a value produces fewer digits than
* \a precision, the actual digits are padded with '0' to meet the precision
* requirement. You can pass a negative number if you don't wish to specify
* precision.
*
* The terminating null is not added if #HIO_FMT_INTMAX_TO_BCSTR_NONULL is set;
* The #HIO_FMT_INTMAX_TO_BCSTR_UPPERCASE flag indicates that the function should
* use the uppercase letter for a alphabetic digit;
* You can set #HIO_FMT_INTMAX_TO_BCSTR_NOTRUNC if you require lossless formatting.
* The #HIO_FMT_INTMAX_TO_BCSTR_PLUSSIGN flag and #HIO_FMT_INTMAX_TO_BCSTR_EMPTYSIGN
* ensures that the plus sign and a space is added for a positive integer
* including 0 respectively.
* The #HIO_FMT_INTMAX_TO_BCSTR_ZEROLEAD flag ensures that the numeric string
* begins with '0' before applying the prefix.
* You can set the #HIO_FMT_INTMAX_TO_BCSTR_NOZERO flag if you want the value of
* 0 to produce nothing. If both #HIO_FMT_INTMAX_TO_BCSTR_NOZERO and
* #HIO_FMT_INTMAX_TO_BCSTR_ZEROLEAD are specified, '0' is still produced.
*
* If \a prefix is not #HIO_NULL, it is inserted before the digits.
*
* \return
* - -1 if the base is not between 2 and 36 inclusive.
* - negated number of characters required for lossless formatting
* - if \a bufsize is 0.
* - if #HIO_FMT_INTMAX_TO_BCSTR_NOTRUNC is set and \a bufsize is less than
* the minimum required for lossless formatting.
* - number of characters written to the buffer excluding a terminating
* null in all other cases.
*/
HIO_EXPORT int hio_fmt_intmax_to_bcstr (
hio_bch_t* buf, /**< buffer pointer */
int bufsize, /**< buffer size */
hio_intmax_t value, /**< integer to format */
int base_and_flags, /**< base ORed with flags */
int precision, /**< precision */
hio_bch_t fillchar, /**< fill character */
const hio_bch_t* prefix /**< prefix */
);
/**
* The hio_fmt_intmax_to_ucstr() function formats an integer \a value to a
* wide-character string according to the given base and writes it to a buffer
* pointed to by \a buf. It writes to the buffer at most \a size characters
* including the terminating null. The base must be between 2 and 36 inclusive
* and can be ORed with zero or more #hio_fmt_intmax_to_ucstr_flag_t enumerators.
* This ORed value is passed to the function via the \a base_and_flags
* parameter. If the formatted string is shorter than \a bufsize, the redundant
* slots are filled with the fill character \a fillchar if it is not a null
* character. The filling behavior is determined by the flags shown below:
*
* - If #HIO_FMT_INTMAX_TO_UCSTR_FILLRIGHT is set in \a base_and_flags, slots
* after the formatting string are filled.
* - If #HIO_FMT_INTMAX_TO_UCSTR_FILLCENTER is set in \a base_and_flags, slots
* before the formatting string are filled. However, if it contains the
* sign character, the slots between the sign character and the digit part
* are filled.
* - If neither #HIO_FMT_INTMAX_TO_UCSTR_FILLRIGHT nor #HIO_FMT_INTMAX_TO_UCSTR_FILLCENTER
* , slots before the formatting string are filled.
*
* The \a precision parameter specified the minimum number of digits to
* produce from the \ value. If \a value produces fewer digits than
* \a precision, the actual digits are padded with '0' to meet the precision
* requirement. You can pass a negative number if don't wish to specify
* precision.
*
* The terminating null is not added if #HIO_FMT_INTMAX_TO_UCSTR_NONULL is set;
* The #HIO_FMT_INTMAX_TO_UCSTR_UPPERCASE flag indicates that the function should
* use the uppercase letter for a alphabetic digit;
* You can set #HIO_FMT_INTMAX_TO_UCSTR_NOTRUNC if you require lossless formatting.
* The #HIO_FMT_INTMAX_TO_UCSTR_PLUSSIGN flag and #HIO_FMT_INTMAX_TO_UCSTR_EMPTYSIGN
* ensures that the plus sign and a space is added for a positive integer
* including 0 respectively.
* The #HIO_FMT_INTMAX_TO_UCSTR_ZEROLEAD flag ensures that the numeric string
* begins with 0 before applying the prefix.
* You can set the #HIO_FMT_INTMAX_TO_UCSTR_NOZERO flag if you want the value of
* 0 to produce nothing. If both #HIO_FMT_INTMAX_TO_UCSTR_NOZERO and
* #HIO_FMT_INTMAX_TO_UCSTR_ZEROLEAD are specified, '0' is still produced.
*
* If \a prefix is not #HIO_NULL, it is inserted before the digits.
*
* \return
* - -1 if the base is not between 2 and 36 inclusive.
* - negated number of characters required for lossless formatting
* - if \a bufsize is 0.
* - if #HIO_FMT_INTMAX_TO_UCSTR_NOTRUNC is set and \a bufsize is less than
* the minimum required for lossless formatting.
* - number of characters written to the buffer excluding a terminating
* null in all other cases.
*/
HIO_EXPORT int hio_fmt_intmax_to_ucstr (
hio_uch_t* buf, /**< buffer pointer */
int bufsize, /**< buffer size */
hio_intmax_t value, /**< integer to format */
int base_and_flags, /**< base ORed with flags */
int precision, /**< precision */
hio_uch_t fillchar, /**< fill character */
const hio_uch_t* prefix /**< prefix */
);
/**
* The hio_fmt_uintmax_to_bcstr() function formats an unsigned integer \a value
* to a multibyte string buffer. It behaves the same as hio_fmt_intmax_to_bcstr()
* except that it handles an unsigned integer.
*/
HIO_EXPORT int hio_fmt_uintmax_to_bcstr (
hio_bch_t* buf, /**< buffer pointer */
int bufsize, /**< buffer size */
hio_uintmax_t value, /**< integer to format */
int base_and_flags, /**< base ORed with flags */
int precision, /**< precision */
hio_bch_t fillchar, /**< fill character */
const hio_bch_t* prefix /**< prefix */
);
/**
* The hio_fmt_uintmax_to_ucstr() function formats an unsigned integer \a value
* to a unicode string buffer. It behaves the same as hio_fmt_intmax_to_ucstr()
* except that it handles an unsigned integer.
*/
HIO_EXPORT int hio_fmt_uintmax_to_ucstr (
hio_uch_t* buf, /**< buffer pointer */
int bufsize, /**< buffer size */
hio_uintmax_t value, /**< integer to format */
int base_and_flags, /**< base ORed with flags */
int precision, /**< precision */
hio_uch_t fillchar, /**< fill character */
const hio_uch_t* prefix /**< prefix */
);
#if defined(HIO_OOCH_IS_BCH)
# define hio_fmt_intmax_to_oocstr hio_fmt_intmax_to_bcstr
# define hio_fmt_uintmax_to_oocstr hio_fmt_uintmax_to_bcstr
#else
# define hio_fmt_intmax_to_oocstr hio_fmt_intmax_to_ucstr
# define hio_fmt_uintmax_to_oocstr hio_fmt_uintmax_to_ucstr
#endif
/* TODO: hio_fmt_fltmax_to_bcstr()... hio_fmt_fltmax_to_ucstr() */
#if defined(__cplusplus)
}
#endif
#endif