229 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			229 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * $Id$ | ||
|  |  * | ||
|  |     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,  | ||
|  | 	hcl_uintmax_t value, int base_and_flags, int prec, | ||
|  | 	char_t fillchar, char_t signchar, const char_t* prefix) | ||
|  | { | ||
|  | 	char_t tmp[(HCL_SIZEOF(hcl_uintmax_t) * 8)]; | ||
|  | 	int reslen, base, fillsize, reqlen, pflen, preczero; | ||
|  | 	char_t* p, * bp, * be; | ||
|  | 	const hcl_bch_t* xbasestr; | ||
|  | 
 | ||
|  | 	base = base_and_flags & 0x3F; | ||
|  | 	if (base < 2 || base > 36) return -1; | ||
|  | 
 | ||
|  | 	xbasestr = (base_and_flags & HCL_FMT_INTMAX_UPPERCASE)? | ||
|  | 		"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ": | ||
|  | 		"0123456789abcdefghijklmnopqrstuvwxyz"; | ||
|  | 
 | ||
|  | 	if ((base_and_flags & HCL_FMT_INTMAX_NOZERO) && value == 0)  | ||
|  | 	{ | ||
|  | 		p = tmp;  | ||
|  | 		if (base_and_flags & HCL_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 | ||
|  | 	{ | ||
|  | 		hcl_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 & HCL_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 & HCL_FMT_INTMAX_NONULL)? reslen: (reslen + 1); | ||
|  | 
 | ||
|  | 	if (size <= 0 || | ||
|  | 	    ((base_and_flags & HCL_FMT_INTMAX_NOTRUNC) && size < reqlen)) | ||
|  | 	{ | ||
|  | 		return -reqlen; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* get the size to fill with fill characters */ | ||
|  | 	fillsize = (base_and_flags & HCL_FMT_INTMAX_NONULL)? size: (size - 1); | ||
|  | 	bp = buf; | ||
|  | 	be = buf + fillsize; | ||
|  | 
 | ||
|  | 	/* fill space */ | ||
|  | 	if (fillchar != '\0') | ||
|  | 	{ | ||
|  | 		if (base_and_flags & HCL_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 & HCL_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 & HCL_FMT_INTMAX_NONULL)) *bp = '\0'; | ||
|  | 	return bp - buf; | ||
|  | } |