/*
*	Example implementation of scanf() type functions.
*
*	We assume that you have the following functions defined:
*
*	int	UartGetc( void );
*
*		Reads a character from the UART. It returns the character itself.
*		It waits for the character. If an error occurs it returns a
*		negative error code (other than EOF).
*
*	int	UartUngetc( int lastchar );
*
*		Returns the character 'lastchar' to the UART's input buffer.
*		The next call to UartGetc() should return that character.
*		This function is called at most once, just before scanf()
*		returns. It should return a non-negative number on success
*		and a negative error code (but not EOF) on failure.
*
*	int	getc( FILE *file );
*	int ungetc( int c, FILE *file );
*
*		These are the standard C library functions to get the next
*		character (or EOF) from a file or to push back the last
*		character to a file. In this example we assume that you defined
*		FILE to some type. The functions here do not care what that
*		type actually is.
*
*	We then create the following functions:
*
*		scanf() 		- with full float and wide character support
*		fscanf() 		- with float but not wide character support
*		vsscanf() 		- integer only
*
*	as an example. That should be enough for you to write pretty much
*	any function in the scanf() family.
*
*	Please realise that while the example functions seem long, that's
*	due to the comments. In fact, the longest of them contains only
*	four C statements, and simple ones of that.
*/

#include <stdio.h>			// It's your header, declaring the functions in
							// this file as well as FILE, getc() and ungetc()

#include <uart.h>			// Your header,  UartGetc() and UartUngetc()

#include <stdio_format.h>	// Library header, declaring scan_???()
#include <wchar.h>			// Library header, wide character support

#include <stdarg.h>			// GCC header, declaring the vararg macros

/*
*	Declaration of our local functions
*/

static int uart_get( void **unused );
static int uart_ung( int c, void **unused );
static int str_get( void **p );
static int str_ung( int c, void **p );

/*
*	Scan from the UART, support everything
*/

int scanf( const char *fmt, ... )
{
va_list	arg;		// Variable argument list object
int		ret;		// Return value

	// Get the variable argument list first

	va_start( arg, fmt );

	// Call the library's scanning function, passing it everything and
	// returning with whatever that returned to us.

	ret = scan_flt(		// We need to call _flt() for float support
			fmt,		// First argument is the format string
			arg,		// Next the variable argument list
			uart_get,	// Get a character
			uart_ung,	// Push-back a character
			NULL,		// No parameter for the wrapper
			mbtowci );	// Function to transform UTF-8 to a wide char

	// Finish the vararg list and return the result

	va_end( arg );
	return ret;
}

/*
*	Wrappers around the UART functions
*/

static int uart_get( void **unused )
{
	(void) unused;
	return UartGetc();
}

static int uart_ung( int c, void **unused )
{
	(void) unused;
	return UartUngetc( c );
}

/*
*	Scan from a file, support everything but wide char
*/

int fscanf( FILE *file, const char *format, ... )
{
va_list	args;

	// Get the argument list

	va_start( args, fmt );

	// This is an extremely simple case, as everything fits
	// the format function's requirements. The only thing is
	// that we have to cast getc() and ungetc() to the
	// relevant function type and the file pointer to void **.
	// The last parameter is NULL, disabling wide character
	// processing.

	ret = scan_flt( format,
				    args,
				    (BLC_FMT_GET) getc,
					(BLC_FMT_UNG) ungetc,
					(void **) file,
					NULL );

	// Finish the vararg list and return the result

	va_end( arg );
	return ret;
}

/*
*	Scan from a string, integers only. The vararg list is given to us
*/

int sscanf( char *str, const char *fmt, va_list arg )
{
	// Call the scan core. The get and unget functions are locally
	// defined little functions. Since we don't have to close the
	// vararg list, we can return straight from the scan function.

	return scan_int( fmt, arg, str_get, str_ung, (void **) &str, NULL );
}

/*
*	Read the next character from a string
*/

static int str_get( void **p )
{
char	*s;
int		c

	// We received a pointer to the string pointer. Fetch it.

	s = * (char **) p;

	// Get the next character. We cast the pointer to unsigned to
	// make sure that we never get a negative number.

	c = * (unsigned char *) s++;

	// If the character is 0, that is, the end of the string, we return
	// EOF and do *not* update the string pointer. Otherwise, we update
	// the string pointer (that is, we consume the character) and return
  	// whatever we fetched.

  	if ( c )

  		* (char **) p = s;
  	else
  		c = EOF;

  	return c;
}

static int str_ung( int c, void **p )
{
	// If the character to return is EOF, we do nothing.
	// Otherwise we simply decrement the current string
	// pointer. In either case we report success.

	if ( c != EOF ) (* (char **) p)--;
	return 0;
}

