227 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
    Copyright (c) 2016-2018 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.
 | 
						|
 */
 | 
						|
 | 
						|
static int fmt_uintmax (
 | 
						|
	char_t* buf, int size,
 | 
						|
	hak_uintmax_t value, int base_and_flags, int prec,
 | 
						|
	char_t fillchar, char_t signchar, const char_t* prefix)
 | 
						|
{
 | 
						|
	char_t tmp[(HAK_SIZEOF(hak_uintmax_t) * 8)];
 | 
						|
	int reslen, base, fillsize, reqlen, pflen, preczero;
 | 
						|
	char_t* p, * bp, * be;
 | 
						|
	const hak_bch_t* xbasestr;
 | 
						|
 | 
						|
	base = base_and_flags & 0x3F;
 | 
						|
	if (base < 2 || base > 36) return -1;
 | 
						|
 | 
						|
	xbasestr = (base_and_flags & HAK_FMT_INTMAX_UPPERCASE)?
 | 
						|
		"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ":
 | 
						|
		"0123456789abcdefghijklmnopqrstuvwxyz";
 | 
						|
 | 
						|
	if ((base_and_flags & HAK_FMT_INTMAX_NOZERO) && value == 0)
 | 
						|
	{
 | 
						|
		p = tmp;
 | 
						|
		if (base_and_flags & HAK_FMT_INTMAX_ZEROLEAD)
 | 
						|
		{
 | 
						|
			/* NOZERO emits no digit, ZEROLEAD emits 1 digit.
 | 
						|
			 * so it emits '0' */
 | 
						|
			reslen = 1;
 | 
						|
			preczero = 1;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* since the value is zero, emit no digits */
 | 
						|
			reslen = 0;
 | 
						|
			preczero = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		hak_uintmax_t v = value;
 | 
						|
 | 
						|
		/* store the resulting numeric string into 'tmp' first */
 | 
						|
		p = tmp;
 | 
						|
		do
 | 
						|
		{
 | 
						|
			*p++ = xbasestr[v % base];
 | 
						|
			v /= base;
 | 
						|
		}
 | 
						|
		while (v > 0);
 | 
						|
 | 
						|
		/* reslen is the length of the resulting string without padding. */
 | 
						|
		reslen = (int)(p - tmp);
 | 
						|
 | 
						|
		/* precision specified the minum number of digits to produce.
 | 
						|
		 * so if the precision is larger that the digits produced,
 | 
						|
		 * reslen should be adjusted to precision */
 | 
						|
		if (prec > reslen)
 | 
						|
		{
 | 
						|
			/* if the precision is greater than the actual digits
 | 
						|
			 * made from the value, 0 is inserted in front.
 | 
						|
			 * ZEROLEAD doesn't have to be handled explicitly
 | 
						|
			 * since it's achieved effortlessly */
 | 
						|
			preczero = prec - reslen;
 | 
						|
			reslen = prec;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			preczero = 0;
 | 
						|
			if ((base_and_flags & HAK_FMT_INTMAX_ZEROLEAD) && value != 0)
 | 
						|
			{
 | 
						|
				/* if value is zero, 0 is emitted from it.
 | 
						|
				 * so ZEROLEAD don't need to add another 0. */
 | 
						|
				preczero++;
 | 
						|
				reslen++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (signchar) reslen++; /* increment reslen for the sign character */
 | 
						|
	if (prefix)
 | 
						|
	{
 | 
						|
		/* since the length can be truncated for different type sizes,
 | 
						|
		 * don't pass in a very long prefix. */
 | 
						|
		const char_t* pp;
 | 
						|
		for (pp = prefix; *pp != '\0'; pp++) ;
 | 
						|
		pflen = pp - prefix;
 | 
						|
		reslen += pflen;
 | 
						|
	}
 | 
						|
	else pflen = 0;
 | 
						|
 | 
						|
	/* get the required buffer size for lossless formatting */
 | 
						|
	reqlen = (base_and_flags & HAK_FMT_INTMAX_NONULL)? reslen: (reslen + 1);
 | 
						|
 | 
						|
	if (size <= 0 ||
 | 
						|
	    ((base_and_flags & HAK_FMT_INTMAX_NOTRUNC) && size < reqlen))
 | 
						|
	{
 | 
						|
		return -reqlen;
 | 
						|
	}
 | 
						|
 | 
						|
	/* get the size to fill with fill characters */
 | 
						|
	fillsize = (base_and_flags & HAK_FMT_INTMAX_NONULL)? size: (size - 1);
 | 
						|
	bp = buf;
 | 
						|
	be = buf + fillsize;
 | 
						|
 | 
						|
	/* fill space */
 | 
						|
	if (fillchar != '\0')
 | 
						|
	{
 | 
						|
		if (base_and_flags & HAK_FMT_INTMAX_FILLRIGHT)
 | 
						|
		{
 | 
						|
			/* emit sign */
 | 
						|
			if (signchar && bp < be) *bp++ = signchar;
 | 
						|
 | 
						|
			/* copy prefix if necessary */
 | 
						|
			if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
 | 
						|
 | 
						|
			/* add 0s for precision */
 | 
						|
			while (preczero > 0 && bp < be)
 | 
						|
			{
 | 
						|
				*bp++ = '0';
 | 
						|
				preczero--;
 | 
						|
			}
 | 
						|
 | 
						|
			/* copy the numeric string to the destination buffer */
 | 
						|
			while (p > tmp && bp < be) *bp++ = *--p;
 | 
						|
 | 
						|
			/* fill the right side */
 | 
						|
			while (fillsize > reslen)
 | 
						|
			{
 | 
						|
				*bp++ = fillchar;
 | 
						|
				fillsize--;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (base_and_flags & HAK_FMT_INTMAX_FILLCENTER)
 | 
						|
		{
 | 
						|
			/* emit sign */
 | 
						|
			if (signchar && bp < be) *bp++ = signchar;
 | 
						|
 | 
						|
			/* fill the left side */
 | 
						|
			while (fillsize > reslen)
 | 
						|
			{
 | 
						|
				*bp++ = fillchar;
 | 
						|
				fillsize--;
 | 
						|
			}
 | 
						|
 | 
						|
			/* copy prefix if necessary */
 | 
						|
			if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
 | 
						|
 | 
						|
			/* add 0s for precision */
 | 
						|
			while (preczero > 0 && bp < be)
 | 
						|
			{
 | 
						|
				*bp++ = '0';
 | 
						|
				preczero--;
 | 
						|
			}
 | 
						|
 | 
						|
			/* copy the numeric string to the destination buffer */
 | 
						|
			while (p > tmp && bp < be) *bp++ = *--p;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* fill the left side */
 | 
						|
			while (fillsize > reslen)
 | 
						|
			{
 | 
						|
				*bp++ = fillchar;
 | 
						|
				fillsize--;
 | 
						|
			}
 | 
						|
 | 
						|
			/* emit sign */
 | 
						|
			if (signchar && bp < be) *bp++ = signchar;
 | 
						|
 | 
						|
			/* copy prefix if necessary */
 | 
						|
			if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
 | 
						|
 | 
						|
			/* add 0s for precision */
 | 
						|
			while (preczero > 0 && bp < be)
 | 
						|
			{
 | 
						|
				*bp++ = '0';
 | 
						|
				preczero--;
 | 
						|
			}
 | 
						|
 | 
						|
			/* copy the numeric string to the destination buffer */
 | 
						|
			while (p > tmp && bp < be) *bp++ = *--p;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		/* emit sign */
 | 
						|
		if (signchar && bp < be) *bp++ = signchar;
 | 
						|
 | 
						|
		/* copy prefix if necessary */
 | 
						|
		if (prefix) while (*prefix && bp < be) *bp++ = *prefix++;
 | 
						|
 | 
						|
		/* add 0s for precision */
 | 
						|
		while (preczero > 0 && bp < be)
 | 
						|
		{
 | 
						|
			*bp++ = '0';
 | 
						|
			preczero--;
 | 
						|
		}
 | 
						|
 | 
						|
		/* copy the numeric string to the destination buffer */
 | 
						|
		while (p > tmp && bp < be) *bp++ = *--p;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!(base_and_flags & HAK_FMT_INTMAX_NONULL)) *bp = '\0';
 | 
						|
	return bp - buf;
 | 
						|
}
 |