TRIO_PRIVATE void TrioWriteNumber TRIO_ARGS6((self, number, flags, width, precision, base),
                                             trio_class_t* self, trio_uintmax_t number,
                                             trio_flags_t flags, int width, int precision, int base)
{
	BOOLEAN_T isNegative;
	BOOLEAN_T isNumberZero;
	BOOLEAN_T isPrecisionZero;
	BOOLEAN_T ignoreNumber;
	char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
	char* bufferend;
	char* pointer;
	TRIO_CONST char* digits;
	int i;
#if TRIO_FEATURE_QUOTE
	int length;
	char* p;
#endif
	int count;
	int digitOffset;

	assert(VALID(self));
	assert(VALID(self->OutStream));
	assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));

	digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
	if (base == NO_BASE)
		base = BASE_DECIMAL;

	isNumberZero = (number == 0);
	isPrecisionZero = (precision == 0);
	ignoreNumber =
	    (isNumberZero && isPrecisionZero && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));

	if (flags & FLAGS_UNSIGNED)
	{
		isNegative = FALSE;
		flags &= ~FLAGS_SHOWSIGN;
	}
	else
	{
		isNegative = ((trio_intmax_t)number < 0);
		if (isNegative)
			number = -((trio_intmax_t)number);
	}

	if (flags & FLAGS_QUAD)
		number &= (trio_ulonglong_t)-1;
	else if (flags & FLAGS_LONG)
		number &= (unsigned long)-1;
	else
		number &= (unsigned int)-1;

	/* Build number */
	pointer = bufferend = &buffer[sizeof(buffer) - 1];
	*pointer-- = NIL;
	for (i = 1; i < (int)sizeof(buffer); i++)
	{
		digitOffset = number % base;
		*pointer-- = digits[digitOffset];
		number /= base;
		if (number == 0)
			break;

#if TRIO_FEATURE_QUOTE
		if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
		{
			/*
			 * We are building the number from the least significant
			 * to the most significant digit, so we have to copy the
			 * thousand separator backwards
			 */
			length = internalThousandSeparatorLength;
			if (((int)(pointer - buffer) - length) > 0)
			{
				p = &internalThousandSeparator[length - 1];
				while (length-- > 0)
					*pointer-- = *p--;
			}
		}
#endif
	}

	if (!ignoreNumber)
	{
		/* Adjust width */
		width -= (bufferend - pointer) - 1;
	}

	/* Adjust precision */
	if (NO_PRECISION != precision)
	{
		precision -= (bufferend - pointer) - 1;
		if (precision < 0)
			precision = 0;
		flags |= FLAGS_NILPADDING;
	}

	/* Calculate padding */
	count = (!((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION))) ? precision : 0;

	/* Adjust width further */
	if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
		width--;
	if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
	{
		switch (base)
		{
			case BASE_BINARY:
			case BASE_HEX:
				width -= 2;
				break;
			case BASE_OCTAL:
				if (!(flags & FLAGS_NILPADDING) || (count == 0))
					width--;
				break;
			default:
				break;
		}
	}

	/* Output prefixes spaces if needed */
	if (!((flags & FLAGS_LEFTADJUST) ||
	      ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
	{
		while (width-- > count)
			self->OutStream(self, CHAR_ADJUST);
	}

	/* width has been adjusted for signs and alternatives */
	if (isNegative)
		self->OutStream(self, '-');
	else if (flags & FLAGS_SHOWSIGN)
		self->OutStream(self, '+');
	else if (flags & FLAGS_SPACE)
		self->OutStream(self, ' ');

	/* Prefix is not written when the value is zero */
	if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
	{
		switch (base)
		{
			case BASE_BINARY:
				self->OutStream(self, '0');
				self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
				break;

			case BASE_OCTAL:
				if (!(flags & FLAGS_NILPADDING) || (count == 0))
					self->OutStream(self, '0');
				break;

			case BASE_HEX:
				self->OutStream(self, '0');
				self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
				break;

			default:
				break;
		} /* switch base */
	}

	/* Output prefixed zero padding if needed */
	if (flags & FLAGS_NILPADDING)
	{
		if (precision == NO_PRECISION)
			precision = width;
		while (precision-- > 0)
		{
			self->OutStream(self, '0');
			width--;
		}
	}

	if (!ignoreNumber)
	{
		/* Output the number itself */
		while (*(++pointer))
		{
			self->OutStream(self, *pointer);
		}
	}

	/* Output trailing spaces if needed */
	if (flags & FLAGS_LEFTADJUST)
	{
		while (width-- > 0)
			self->OutStream(self, CHAR_ADJUST);
	}
}