221 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * $Id$
 | |
|  *
 | |
|     Copyright 2006-2014 Chung, Hyung-Hwan.
 | |
|     This file is part of QSE.
 | |
| 
 | |
|     QSE is free software: you can redistribute it and/or modify
 | |
|     it under the terms of the GNU Lesser General Public License as 
 | |
|     published by the Free Software Foundation, either version 3 of 
 | |
|     the License, or (at your option) any later version.
 | |
| 
 | |
|     QSE 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 Lesser General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU Lesser General Public 
 | |
|     License along with QSE. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| static int fmt_uintmax (
 | |
| 	char_t* buf, int size, 
 | |
| 	qse_uintmax_t value, int base_and_flags, int prec,
 | |
| 	char_t fillchar, char_t signchar, const char_t* prefix)
 | |
| {
 | |
| 	char_t tmp[(QSE_SIZEOF(qse_uintmax_t) * 8)];
 | |
| 	int reslen, base, fillsize, reqlen, pflen, preczero;
 | |
| 	char_t* p, * bp, * be;
 | |
| 	const char_t* xbasestr;
 | |
| 
 | |
| 	base = base_and_flags & 0x3F;
 | |
| 	if (base < 2 || base > 36) return -1;
 | |
| 
 | |
| 	xbasestr = (base_and_flags & QSE_FMTINTMAX_UPPERCASE)?
 | |
| 		T("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
 | |
| 		T("0123456789abcdefghijklmnopqrstuvwxyz");
 | |
| 
 | |
| 	if ((base_and_flags & QSE_FMTINTMAX_NOZERO) && value == 0) 
 | |
| 	{
 | |
| 		p = tmp; 
 | |
| 		if (base_and_flags & QSE_FMTINTMAX_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
 | |
| 	{
 | |
| 		qse_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 & QSE_FMTINTMAX_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. */
 | |
| 		pflen = (int) strlen(prefix);
 | |
| 		reslen += pflen;
 | |
| 	}
 | |
| 	else pflen = 0;
 | |
| 
 | |
| 	/* get the required buffer size for lossless formatting */
 | |
| 	reqlen = (base_and_flags & QSE_FMTINTMAX_NONULL)? reslen: (reslen + 1);
 | |
| 
 | |
| 	if (size <= 0 ||
 | |
| 	    ((base_and_flags & QSE_FMTINTMAX_NOTRUNC) && size < reqlen))
 | |
| 	{
 | |
| 		return -reqlen;
 | |
| 	}
 | |
| 
 | |
| 	/* get the size to fill with fill characters */
 | |
| 	fillsize = (base_and_flags & QSE_FMTINTMAX_NONULL)? size: (size - 1);
 | |
| 	bp = buf;
 | |
| 	be = buf + fillsize;
 | |
| 
 | |
| 	/* fill space */
 | |
| 	if (fillchar != T('\0'))
 | |
| 	{
 | |
| 		if (base_and_flags & QSE_FMTINTMAX_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++ = T('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 & QSE_FMTINTMAX_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++ = T('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++ = T('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++ = T('0');
 | |
| 			preczero--; 
 | |
| 		}
 | |
| 
 | |
| 		/* copy the numeric string to the destination buffer */
 | |
| 		while (p > tmp && bp < be) *bp++ = *--p;
 | |
| 	}
 | |
| 
 | |
| 	if (!(base_and_flags & QSE_FMTINTMAX_NONULL)) *bp = T('\0');
 | |
| 	return bp - buf;
 | |
| }
 |