TRIO_PRIVATE int TrioScanProcess TRIO_ARGS3((data, format, parameters), trio_class_t* data,
                                            TRIO_CONST char* format, trio_parameter_t* parameters)
{
	int status;
	int assignment;
	int ch;
	int offset; /* Offset of format string */
	int i;      /* Offset of current parameter */
	trio_flags_t flags;
	int width;
	int base;
	trio_pointer_t pointer;

	/* Return on empty format string */
	if (format[0] == NIL)
		return 0;

	status = 0;
	assignment = 0;
	i = 0;
	offset = 0;
	data->InStream(data, &ch);

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

		/* Compare non conversion-specifier part of format string */
		while (offset < parameters[i].beginOffset)
		{
			if ((CHAR_IDENTIFIER == format[offset]) && (CHAR_IDENTIFIER == format[offset + 1]))
			{
				/* Two % in format matches one % in input stream */
				if (CHAR_IDENTIFIER == ch)
				{
					data->InStream(data, &ch);
					offset += 2;
					continue; /* while format chars left */
				}
				else
				{
					status = TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
					goto end;
				}
			}
			else /* Not an % identifier */
			{
				if (isspace((int)format[offset]))
				{
					/* Whitespaces may match any amount of whitespaces */
					ch = TrioSkipWhitespaces(data);
				}
				else if (ch == format[offset])
				{
					data->InStream(data, &ch);
				}
				else
				{
					status = assignment;
					goto end;
				}

				offset++;
			}
		}

		if (parameters[i].type == FORMAT_SENTINEL)
			break;

		if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
		{
			status = (assignment > 0) ? assignment : EOF;
			goto end;
		}

		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;
		}

		/* 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_INT:
			{
				trio_uintmax_t number;

				if (0 == base)
					base = BASE_DECIMAL;

				if (!TrioReadNumber(data, &number, flags, width, base))
				{
					status = assignment;
					goto end;
				}

				if (!(flags & FLAGS_IGNORE))
				{
					assignment++;

					pointer = parameters[i].data.pointer;
#if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
					if (flags & FLAGS_SIZE_T)
						*(size_t*)pointer = (size_t)number;
					else
#endif
#if TRIO_FEATURE_PTRDIFF_T
					    if (flags & FLAGS_PTRDIFF_T)
						*(ptrdiff_t*)pointer = (ptrdiff_t)number;
					else
#endif
#if TRIO_FEATURE_INTMAX_T
					    if (flags & FLAGS_INTMAX_T)
						*(trio_intmax_t*)pointer = (trio_intmax_t)number;
					else
#endif
					    if (flags & FLAGS_QUAD)
						*(trio_ulonglong_t*)pointer = (trio_ulonglong_t)number;
					else if (flags & FLAGS_LONG)
						*(long int*)pointer = (long int)number;
					else if (flags & FLAGS_SHORT)
						*(short int*)pointer = (short int)number;
					else
						*(int*)pointer = (int)number;
				}
			}
			break; /* FORMAT_INT */

			case FORMAT_STRING:
#if TRIO_FEATURE_WIDECHAR
				if (flags & FLAGS_WIDECHAR)
				{
					if (!TrioReadWideString(
					        data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.wstring, flags,
					        width))
					{
						status = assignment;
						goto end;
					}
				}
				else
#endif
				{
					if (!TrioReadString(data,
					                    (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.string,
					                    flags, width))
					{
						status = assignment;
						goto end;
					}
				}
				if (!(flags & FLAGS_IGNORE))
					assignment++;
				break; /* FORMAT_STRING */

#if TRIO_FEATURE_FLOAT
			case FORMAT_DOUBLE:
			{
				if (flags & FLAGS_IGNORE)
				{
					pointer = NULL;
				}
				else
				{
					pointer = (flags & FLAGS_LONGDOUBLE)
					              ? (trio_pointer_t)parameters[i].data.longdoublePointer
					              : (trio_pointer_t)parameters[i].data.doublePointer;
				}
				if (!TrioReadDouble(data, pointer, flags, width))
				{
					status = assignment;
					goto end;
				}
				if (!(flags & FLAGS_IGNORE))
				{
					assignment++;
				}
				break; /* FORMAT_DOUBLE */
			}
#endif

			case FORMAT_GROUP:
			{
				int characterclass[MAX_CHARACTER_CLASS + 1];

				/* Skip over modifiers */
				while (format[offset] != SPECIFIER_GROUP)
				{
					offset++;
				}
				/* Skip over group specifier */
				offset++;

				memset(characterclass, 0, sizeof(characterclass));
				status = TrioGetCharacterClass(format, &offset, &flags, characterclass);
				if (status < 0)
					goto end;

				if (!TrioReadGroup(data, (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.string,
				                   characterclass, flags, parameters[i].width))
				{
					status = assignment;
					goto end;
				}
				if (!(flags & FLAGS_IGNORE))
					assignment++;
			}
			break; /* FORMAT_GROUP */

			case FORMAT_COUNT:
				pointer = parameters[i].data.pointer;
				if (NULL != pointer)
				{
					int count = data->processed;
					if (ch != EOF)
						count--; /* a character is read, but is not consumed yet */
#if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
					if (flags & FLAGS_SIZE_T)
						*(size_t*)pointer = (size_t)count;
					else
#endif
#if TRIO_FEATURE_PTRDIFF_T
					    if (flags & FLAGS_PTRDIFF_T)
						*(ptrdiff_t*)pointer = (ptrdiff_t)count;
					else
#endif
#if TRIO_FEATURE_INTMAX_T
					    if (flags & FLAGS_INTMAX_T)
						*(trio_intmax_t*)pointer = (trio_intmax_t)count;
					else
#endif
					    if (flags & FLAGS_QUAD)
					{
						*(trio_ulonglong_t*)pointer = (trio_ulonglong_t)count;
					}
					else if (flags & FLAGS_LONG)
					{
						*(long int*)pointer = (long int)count;
					}
					else if (flags & FLAGS_SHORT)
					{
						*(short int*)pointer = (short int)count;
					}
					else
					{
						*(int*)pointer = (int)count;
					}
				}
				break; /* FORMAT_COUNT */

			case FORMAT_CHAR:
#if TRIO_FEATURE_WIDECHAR
				if (flags & FLAGS_WIDECHAR)
				{
					if (TrioReadWideChar(data,
					                     (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.wstring,
					                     flags, (width == NO_WIDTH) ? 1 : width) == 0)
					{
						status = assignment;
						goto end;
					}
				}
				else
#endif
				{
					if (TrioReadChar(data,
					                 (flags & FLAGS_IGNORE) ? NULL : parameters[i].data.string,
					                 flags, (width == NO_WIDTH) ? 1 : width) == 0)
					{
						status = assignment;
						goto end;
					}
				}
				if (!(flags & FLAGS_IGNORE))
					assignment++;
				break; /* FORMAT_CHAR */

			case FORMAT_POINTER:
				if (!TrioReadPointer(
				        data,
				        (flags & FLAGS_IGNORE) ? NULL : (trio_pointer_t*)parameters[i].data.pointer,
				        flags))
				{
					status = assignment;
					goto end;
				}
				if (!(flags & FLAGS_IGNORE))
					assignment++;
				break; /* FORMAT_POINTER */

			case FORMAT_PARAMETER:
				break; /* FORMAT_PARAMETER */

			default:
				status = TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
				goto end;
		}

		ch = data->current;
		offset = parameters[i].endOffset;
		i++;
	}

	status = assignment;
end:
	if (data->UndoStream)
		data->UndoStream(data);
	return status;
}