TRIO_PRIVATE int TrioFormatProcess TRIO_ARGS3((data, format, parameters), trio_class_t* data,
                                              TRIO_CONST char* format, trio_parameter_t* parameters)
{
	int i;
#if TRIO_FEATURE_ERRNO
	TRIO_CONST char* string;
#endif
	trio_pointer_t pointer;
	trio_flags_t flags;
	int width;
	int precision;
	int base;
	int offset;

	offset = 0;
	i = 0;

	for (;;)
	{
		/* Skip the parameter entries */
		while (parameters[i].type == FORMAT_PARAMETER)
			i++;

		/* Copy non conversion-specifier part of format string */
		while (offset < parameters[i].beginOffset)
		{
			if (CHAR_IDENTIFIER == format[offset] && CHAR_IDENTIFIER == format[offset + 1])
			{
				data->OutStream(data, CHAR_IDENTIFIER);
				offset += 2;
			}
			else
			{
				data->OutStream(data, format[offset++]);
			}
		}

		/* Abort if we reached end of format string */
		if (parameters[i].type == FORMAT_SENTINEL)
			break;

		/* Ouput parameter */
		flags = parameters[i].flags;

		/* Find width */
		width = parameters[i].width;
		if (flags & FLAGS_WIDTH_PARAMETER)
		{
			/* Get width from parameter list */
			width = (int)parameters[width].data.number.as_signed;
			if (width < 0)
			{
				/*
				 * A negative width is the same as the - flag and
				 * a positive width.
				 */
				flags |= FLAGS_LEFTADJUST;
				flags &= ~FLAGS_NILPADDING;
				width = -width;
			}
		}

		/* Find precision */
		if (flags & FLAGS_PRECISION)
		{
			precision = parameters[i].precision;
			if (flags & FLAGS_PRECISION_PARAMETER)
			{
				/* Get precision from parameter list */
				precision = (int)parameters[precision].data.number.as_signed;
				if (precision < 0)
				{
					/*
					 * A negative precision is the same as no
					 * precision
					 */
					precision = NO_PRECISION;
				}
			}
		}
		else
		{
			precision = NO_PRECISION;
		}

		/* Find base */
		if (NO_BASE != parameters[i].baseSpecifier)
		{
			/* Base from specifier has priority */
			base = parameters[i].baseSpecifier;
		}
		else if (flags & FLAGS_BASE_PARAMETER)
		{
			/* Get base from parameter list */
			base = parameters[i].base;
			base = (int)parameters[base].data.number.as_signed;
		}
		else
		{
			/* Use base from format string */
			base = parameters[i].base;
		}

		switch (parameters[i].type)
		{
			case FORMAT_CHAR:
#if TRIO_FEATURE_QUOTE
				if (flags & FLAGS_QUOTE)
					data->OutStream(data, CHAR_QUOTE);
#endif
				if (!(flags & FLAGS_LEFTADJUST))
				{
					while (--width > 0)
						data->OutStream(data, CHAR_ADJUST);
				}
#if TRIO_FEATURE_WIDECHAR
				if (flags & FLAGS_WIDECHAR)
				{
					TrioWriteWideStringCharacter(
					    data, (trio_wchar_t)parameters[i].data.number.as_signed, flags, NO_WIDTH);
				}
				else
#endif
				{
					TrioWriteStringCharacter(data, (int)parameters[i].data.number.as_signed, flags);
				}

				if (flags & FLAGS_LEFTADJUST)
				{
					while (--width > 0)
						data->OutStream(data, CHAR_ADJUST);
				}
#if TRIO_FEATURE_QUOTE
				if (flags & FLAGS_QUOTE)
					data->OutStream(data, CHAR_QUOTE);
#endif

				break; /* FORMAT_CHAR */

			case FORMAT_INT:
				TrioWriteNumber(data, parameters[i].data.number.as_unsigned, flags, width,
				                precision, base);

				break; /* FORMAT_INT */

#if TRIO_FEATURE_FLOAT
			case FORMAT_DOUBLE:
				TrioWriteDouble(data, parameters[i].data.longdoubleNumber, flags, width, precision,
				                base);
				break; /* FORMAT_DOUBLE */
#endif

			case FORMAT_STRING:
#if TRIO_FEATURE_WIDECHAR
				if (flags & FLAGS_WIDECHAR)
				{
					TrioWriteWideString(data, parameters[i].data.wstring, flags, width, precision);
				}
				else
#endif
				{
					TrioWriteString(data, parameters[i].data.string, flags, width, precision);
				}
				break; /* FORMAT_STRING */

			case FORMAT_POINTER:
			{
				trio_reference_t reference;

				reference.data = data;
				reference.parameter = &parameters[i];
				trio_print_pointer(&reference, parameters[i].data.pointer);
			}
			break; /* FORMAT_POINTER */

			case FORMAT_COUNT:
				pointer = parameters[i].data.pointer;
				if (NULL != pointer)
				{
					/*
					 * C99 paragraph 7.19.6.1.8 says "the number of
					 * characters written to the output stream so far by
					 * this call", which is data->actually.committed
					 */
#if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
					if (flags & FLAGS_SIZE_T)
						*(size_t*)pointer = (size_t)data->actually.committed;
					else
#endif
#if TRIO_FEATURE_PTRDIFF_T
					    if (flags & FLAGS_PTRDIFF_T)
						*(ptrdiff_t*)pointer = (ptrdiff_t)data->actually.committed;
					else
#endif
#if TRIO_FEATURE_INTMAX_T
					    if (flags & FLAGS_INTMAX_T)
						*(trio_intmax_t*)pointer = (trio_intmax_t)data->actually.committed;
					else
#endif
					    if (flags & FLAGS_QUAD)
					{
						*(trio_ulonglong_t*)pointer = (trio_ulonglong_t)data->actually.committed;
					}
					else if (flags & FLAGS_LONG)
					{
						*(long int*)pointer = (long int)data->actually.committed;
					}
					else if (flags & FLAGS_SHORT)
					{
						*(short int*)pointer = (short int)data->actually.committed;
					}
					else
					{
						*(int*)pointer = (int)data->actually.committed;
					}
				}
				break; /* FORMAT_COUNT */

			case FORMAT_PARAMETER:
				break; /* FORMAT_PARAMETER */

#if TRIO_FEATURE_ERRNO
			case FORMAT_ERRNO:
				string = trio_error(parameters[i].data.errorNumber);
				if (string)
				{
					TrioWriteString(data, string, flags, width, precision);
				}
				else
				{
					data->OutStream(data, '#');
					TrioWriteNumber(data, (trio_uintmax_t)parameters[i].data.errorNumber, flags,
					                width, precision, BASE_DECIMAL);
				}
				break; /* FORMAT_ERRNO */
#endif                 /* TRIO_FEATURE_ERRNO */

#if TRIO_FEATURE_USER_DEFINED
			case FORMAT_USER_DEFINED:
			{
				trio_reference_t reference;
				trio_userdef_t* def = NULL;

				if (parameters[i].flags & FLAGS_USER_DEFINED_PARAMETER)
				{
					/* Use handle */
					if ((i > 0) || (parameters[i - 1].type == FORMAT_PARAMETER))
						def = (trio_userdef_t*)parameters[i - 1].data.pointer;
				}
				else
				{
					/* Look up namespace */
					def = TrioFindNamespace(parameters[i].user_defined.namespace, NULL);
				}
				if (def)
				{
					reference.data = data;
					reference.parameter = &parameters[i];
					def->callback(&reference);
				}
			}
			break;
#endif /* TRIO_FEATURE_USER_DEFINED */

			default:
				break;
		} /* switch parameter type */

		/* Prepare for next */
		offset = parameters[i].endOffset;
		i++;
	}

	return data->processed;
}