#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
+#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>
/* FIXME: one too many flags to work on a 16-bit machine, join some (e.g. the
width flags) into a combined field.
*/
-#define E_minus 1<<0
-#define E_plus 1<<1
-#define E_alt 1<<2
-#define E_space 1<<3
-#define E_zero 1<<4
-#define E_done 1<<5
-#define E_char 1<<6
-#define E_short 1<<7
-#define E_long 1<<8
-#define E_llong 1<<9
-#define E_intmax 1<<10
-#define E_size 1<<11
-#define E_ptrdiff 1<<12
-#define E_intptr 1<<13
-#define E_ldouble 1<<14
-#define E_lower 1<<15
-#define E_unsigned 1<<16
+#define E_minus (1<<0)
+#define E_plus (1<<1)
+#define E_alt (1<<2)
+#define E_space (1<<3)
+#define E_zero (1<<4)
+#define E_done (1<<5)
+#define E_char (1<<6)
+#define E_short (1<<7)
+#define E_long (1<<8)
+#define E_llong (1<<9)
+#define E_intmax (1<<10)
+#define E_size (1<<11)
+#define E_ptrdiff (1<<12)
+#define E_intptr (1<<13)
+#define E_ldouble (1<<14)
+#define E_lower (1<<15)
+#define E_unsigned (1<<16)
/* This macro delivers a given character to either a memory buffer or a stream,
depending on the contents of 'status' (struct _PDCLIB_status_t).
int character = x; \
if ( status->i < status->n ) { \
if ( status->stream != NULL ) \
- putc( character, status->stream ); \
+ putc_unlocked( character, status->stream ); \
else \
status->s[status->i] = character; \
} \
const char * digits = (status->flags & E_lower) ?
_PDCLIB_digits : _PDCLIB_Xdigits;
uintmax_t remaining = value;
- do {
+ if(status->prec != 0 || remaining != 0) do {
uintmax_t digit = remaining % status->base;
remaining /= status->base;
PUT( outend[-written--] );
}
+static void printstr( const char * str, struct _PDCLIB_status_t * status )
+{
+ if ( status->width == 0 || status->flags & E_minus )
+ {
+ // Simple case or left justification
+ while ( str[status->current] &&
+ ( status->prec < 0 || (long)status->current < status->prec ) )
+ {
+ PUT( str[status->current++] );
+ }
+
+ while( status->current < status->width )
+ {
+ PUT( ' ' );
+ status->current++;
+ }
+ } else {
+ // Right justification
+ size_t len = status->prec >= 0 ? strnlen( str, status->prec )
+ : strlen( str );
+ int padding = status->width - len;
+ while((long)status->current < padding)
+ {
+ PUT( ' ' );
+ status->current++;
+ }
+
+ for( size_t i = 0; i != len; i++ )
+ {
+ PUT( str[i] );
+ status->current++;
+ }
+ }
+}
+
+static void printchar( char chr, struct _PDCLIB_status_t * status )
+{
+ if( ! ( status->flags & E_minus ) )
+ {
+ // Right justification
+ for( ; status->current + 1 < status->width; status->current++)
+ {
+ PUT( ' ' );
+ }
+ PUT( chr );
+ status->current++;
+ } else {
+ // Left justification
+ PUT( chr );
+ status->current++;
+
+ for( ; status->current < status->width; status->current++)
+ {
+ PUT( ' ' );
+ }
+ }
+}
+
const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
{
const char * orig_spec = spec;
EOF (negative), there is no need for testing for negative here.
*/
status->prec = va_arg( status->arg, int );
+ ++spec;
}
else
{
- char * endptr;
- status->prec = (int)strtol( spec, &endptr, 10 );
- if ( spec == endptr )
- {
- /* Decimal point but no number - bad conversion specifier. */
- return orig_spec;
- }
- spec = endptr;
+ status->prec = (int)strtol( spec, (char**) &spec, 10 );
}
/* Having a precision cancels out any zero flag. */
- status->flags ^= E_zero;
+ status->flags &= ~E_zero;
}
/* Optional length modifier
case 'A':
break;
case 'c':
- /* TODO: Flags, wide chars. */
- PUT( va_arg( status->arg, int ) );
+ /* TODO: wide chars. */
+ printchar( va_arg( status->arg, int ), status );
return ++spec;
case 's':
- /* TODO: Flags, wide chars. */
+ /* TODO: wide chars. */
{
char * s = va_arg( status->arg, char * );
- while ( *s != '\0' )
- {
- PUT( *(s++) );
- }
+ printstr( s, status );
return ++spec;
}
case 'p':