FILE * stream;/* for to-stream output */
};
-void parse_out( const char * spec, struct status_t * status, va_list ap );
-void parse_out_wrapper( const char * spec, struct status_t * status, ... );
+const char * parse_out( const char * spec, struct status_t * status, va_list ap );
+const char * parse_out_wrapper( const char * spec, struct status_t * status, ... );
+int _PDCLIB_printf( FILE * stream, const char * format, va_list ap );
#define TESTCASE( _n, _value, _expect ) \
status.n = _n; \
}
}
-void parse_out( const char * spec, struct status_t * status, va_list ap )
+const char * parse_out( const char * spec, struct status_t * status, va_list ap )
{
- /* TODO: "%%" handled correctly? */
-
+ const char * orig_spec = spec;
+#if 0
+ if ( *(++spec) == '%' )
+ {
+ DELIVER( *spec );
+ return spec;
+ }
+#endif
/* Initializing status structure */
status->flags = 0;
status->base = 0;
case 'p':
/* uint2base( 16, (intptr_t)value, true ) */
case 'n':
- case '%':
- // conversion specifier
- /* TODO: May this be accompaigned by flags, width, precision, length modifier at all? */
break;
default:
- /* TODO: No conversion specifier. Bad conversion. */
- return;
- }
- switch ( status->flags )
- {
- /* TODO */
+ /* No conversion specifier. Bad conversion. */
+ return orig_spec;
}
+
+ /* Do the actual output based on our findings */
if ( status->base != 0 )
{
/* Integer conversions */
- /* TODO: Eliminate the padwrap as far as possible. */
+ /* TODO: Check for invalid flag combinations. */
if ( status->flags & E_unsigned )
{
uintmax_t value;
- switch ( status->flags & ( E_char | E_short | E_long | E_llong ) )
+ switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size ) )
{
case E_char:
value = (uintmax_t)(unsigned char)va_arg( ap, int );
value = (uintmax_t)va_arg( ap, unsigned int );
break;
case E_long:
- value = (uintmax_t)(unsigned long)va_arg( ap, unsigned long );
+ value = (uintmax_t)va_arg( ap, unsigned long );
break;
case E_llong:
- value = (uintmax_t)(unsigned long long)va_arg( ap, unsigned long long );
+ value = (uintmax_t)va_arg( ap, unsigned long long );
+ break;
+ case E_size:
+ value = (uintmax_t)va_arg( ap, size_t );
break;
}
++(status->this);
}
else
{
- switch ( status->flags & ( E_char | E_short | E_long | E_llong ) )
+ switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) )
{
case E_char:
int2base( (intmax_t)(char)va_arg( ap, int ), status );
case E_llong:
int2base( (intmax_t)va_arg( ap, long long ), status );
break;
+ case E_ptrdiff:
+ int2base( (intmax_t)va_arg( ap, ptrdiff_t ), status );
+ break;
+ case E_intmax:
+ int2base( va_arg( ap, intmax_t ), status );
+ break;
}
}
if ( status->flags & E_minus )
status->s[status->n - 1] = '\0';
}
}
+ return ++spec;
}
-void parse_out_wrapper( const char * spec, struct status_t * status, ... )
+const char * parse_out_wrapper( const char * spec, struct status_t * status, ... )
{
+ const char * rc;
va_list ap;
va_start( ap, status );
- parse_out( spec, status, ap );
+ rc = parse_out( spec, status, ap );
va_end( ap );
+ return rc;
+}
+
+int _PDCLIB_printf( FILE * stream, const char * format, va_list ap )
+{
+ char * buffer = malloc( 50 );
+ struct status_t status = { 0, 0, SIZE_MAX, 0, 0, /* stream->buffer */ buffer, 0, 0, stream };
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = parse_out( format, &status, ap ) ) == format ) )
+ {
+ /* No conversion specifier, print verbatim */
+ putc( *(format++), stream );
+ }
+ else
+ {
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ return status.i;
}