TRIO_PRIVATE int TrioParseSpecifier TRIO_ARGS4((type, format, offset, parameter), int type,
                                               TRIO_CONST char* format, int offset,
                                               trio_parameter_t* parameter)
{
	parameter->baseSpecifier = NO_BASE;

	switch (format[offset++])
	{
#if defined(SPECIFIER_CHAR_UPPER)
		case SPECIFIER_CHAR_UPPER:
			parameter->flags |= FLAGS_WIDECHAR;
			/* FALLTHROUGH */
#endif
		case SPECIFIER_CHAR:
			if (parameter->flags & FLAGS_LONG)
				parameter->flags |= FLAGS_WIDECHAR;
			else if (parameter->flags & FLAGS_SHORT)
				parameter->flags &= ~FLAGS_WIDECHAR;
			parameter->type = FORMAT_CHAR;
			break;

#if defined(SPECIFIER_STRING_UPPER)
		case SPECIFIER_STRING_UPPER:
			parameter->flags |= FLAGS_WIDECHAR;
			/* FALLTHROUGH */
#endif
		case SPECIFIER_STRING:
			if (parameter->flags & FLAGS_LONG)
				parameter->flags |= FLAGS_WIDECHAR;
			else if (parameter->flags & FLAGS_SHORT)
				parameter->flags &= ~FLAGS_WIDECHAR;
			parameter->type = FORMAT_STRING;
			break;

#if defined(SPECIFIER_GROUP)
		case SPECIFIER_GROUP:
			if (TYPE_SCAN == type)
			{
				int depth = 1;
				parameter->type = FORMAT_GROUP;
				if (format[offset] == QUALIFIER_CIRCUMFLEX)
					offset++;
				if (format[offset] == SPECIFIER_UNGROUP)
					offset++;
				if (format[offset] == QUALIFIER_MINUS)
					offset++;
				/* Skip nested brackets */
				while (format[offset] != NIL)
				{
					if (format[offset] == SPECIFIER_GROUP)
					{
						depth++;
					}
					else if (format[offset] == SPECIFIER_UNGROUP)
					{
						if (--depth <= 0)
						{
							offset++;
							break;
						}
					}
					offset++;
				}
			}
			break;
#endif /* defined(SPECIFIER_GROUP) */

		case SPECIFIER_INTEGER:
			parameter->type = FORMAT_INT;
			break;

		case SPECIFIER_UNSIGNED:
			parameter->flags |= FLAGS_UNSIGNED;
			parameter->type = FORMAT_INT;
			break;

		case SPECIFIER_DECIMAL:
			parameter->baseSpecifier = BASE_DECIMAL;
			parameter->type = FORMAT_INT;
			break;

		case SPECIFIER_OCTAL:
			parameter->flags |= FLAGS_UNSIGNED;
			parameter->baseSpecifier = BASE_OCTAL;
			parameter->type = FORMAT_INT;
			break;

#if TRIO_FEATURE_BINARY
		case SPECIFIER_BINARY_UPPER:
			parameter->flags |= FLAGS_UPPER;
			/* FALLTHROUGH */
		case SPECIFIER_BINARY:
			parameter->flags |= FLAGS_NILPADDING;
			parameter->baseSpecifier = BASE_BINARY;
			parameter->type = FORMAT_INT;
			break;
#endif

		case SPECIFIER_HEX_UPPER:
			parameter->flags |= FLAGS_UPPER;
			/* FALLTHROUGH */
		case SPECIFIER_HEX:
			parameter->flags |= FLAGS_UNSIGNED;
			parameter->baseSpecifier = BASE_HEX;
			parameter->type = FORMAT_INT;
			break;

#if defined(SPECIFIER_FLOAT_E)
#if defined(SPECIFIER_FLOAT_E_UPPER)
		case SPECIFIER_FLOAT_E_UPPER:
			parameter->flags |= FLAGS_UPPER;
			/* FALLTHROUGH */
#endif
		case SPECIFIER_FLOAT_E:
			parameter->flags |= FLAGS_FLOAT_E;
			parameter->type = FORMAT_DOUBLE;
			break;
#endif

#if defined(SPECIFIER_FLOAT_G)
#if defined(SPECIFIER_FLOAT_G_UPPER)
		case SPECIFIER_FLOAT_G_UPPER:
			parameter->flags |= FLAGS_UPPER;
			/* FALLTHROUGH */
#endif
		case SPECIFIER_FLOAT_G:
			parameter->flags |= FLAGS_FLOAT_G;
			parameter->type = FORMAT_DOUBLE;
			break;
#endif

#if defined(SPECIFIER_FLOAT_F)
#if defined(SPECIFIER_FLOAT_F_UPPER)
		case SPECIFIER_FLOAT_F_UPPER:
			parameter->flags |= FLAGS_UPPER;
			/* FALLTHROUGH */
#endif
		case SPECIFIER_FLOAT_F:
			parameter->type = FORMAT_DOUBLE;
			break;
#endif

#if defined(TRIO_COMPILER_VISUALC)
#pragma warning(push)
#pragma warning(disable : 4127) /* Conditional expression is constant */
#endif
		case SPECIFIER_POINTER:
			if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
				parameter->flags |= FLAGS_QUAD;
			else if (sizeof(trio_pointer_t) == sizeof(long))
				parameter->flags |= FLAGS_LONG;
			parameter->type = FORMAT_POINTER;
			break;
#if defined(TRIO_COMPILER_VISUALC)
#pragma warning(pop)
#endif

		case SPECIFIER_COUNT:
			parameter->type = FORMAT_COUNT;
			break;

#if TRIO_FEATURE_HEXFLOAT
		case SPECIFIER_HEXFLOAT_UPPER:
			parameter->flags |= FLAGS_UPPER;
			/* FALLTHROUGH */
		case SPECIFIER_HEXFLOAT:
			parameter->baseSpecifier = BASE_HEX;
			parameter->type = FORMAT_DOUBLE;
			break;
#endif

#if TRIO_FEATURE_ERRNO
		case SPECIFIER_ERRNO:
			parameter->type = FORMAT_ERRNO;
			break;
#endif

#if TRIO_FEATURE_USER_DEFINED
		case SPECIFIER_USER_DEFINED_BEGIN:
		{
			unsigned int max;
			int without_namespace = TRUE;
			char* tmpformat = (char*)&format[offset];
			int ch;

			parameter->type = FORMAT_USER_DEFINED;
			parameter->user_defined.namespace[0] = NIL;

			while ((ch = format[offset]) != NIL)
			{
				offset++;
				if ((ch == SPECIFIER_USER_DEFINED_END) || (ch == SPECIFIER_USER_DEFINED_EXTRA))
				{
					if (without_namespace)
						/* No namespace, handler will be passed as an argument */
						parameter->flags |= FLAGS_USER_DEFINED_PARAMETER;

					/* Copy the user data */
					max = (unsigned int)(&format[offset] - tmpformat);
					if (max > MAX_USER_DATA)
						max = MAX_USER_DATA;
					trio_copy_max(parameter->user_data, max, tmpformat);

					/* Skip extra data (which is only there to keep the compiler happy) */
					while ((ch != NIL) && (ch != SPECIFIER_USER_DEFINED_END))
						ch = format[offset++];

					break; /* while */
				}

				if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
				{
					without_namespace = FALSE;
					/* Copy the namespace for later looking-up */
					max = (int)(&format[offset] - tmpformat);
					if (max > MAX_USER_NAME)
						max = MAX_USER_NAME;
					trio_copy_max(parameter->user_defined.namespace, max, tmpformat);
					tmpformat = (char*)&format[offset];
				}
			}

			if (ch != SPECIFIER_USER_DEFINED_END)
				return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
		}
		break;
#endif /* TRIO_FEATURE_USER_DEFINED */

		default:
			/* Bail out completely to make the error more obvious */
			return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
	}

	parameter->endOffset = offset;

	return 0;
}