#define E_TYPES (E_char | E_short | E_long | E_llong | E_intmax \
| E_size | E_ptrdiff | E_intptr)
-/* This macro delivers a given character to either a memory buffer or a stream,
- depending on the contents of 'status' (struct _PDCLIB_status_t).
- x - the character to be delivered
- i - pointer to number of characters already delivered in this call
- n - pointer to maximum number of characters to be delivered in this call
- s - the buffer into which the character shall be delivered
-*/
-#define PUT( x ) \
-do { \
- int character = x; \
- if ( status->i < status->n ) { \
- if ( status->stream != NULL ) \
- _PDCLIB_putc_unlocked( character, status->stream ); \
- else \
- status->s[status->i] = character; \
- } \
- ++(status->i); \
-} while ( 0 )
-
-/* Maximum number of output characters =
- * number of bits in (u)intmax_t / number of bits per character in smallest
+/* returns true if callback-based output succeeded; else false */
+static inline bool cbout(
+ struct _PDCLIB_status_t * status,
+ const void * buf,
+ size_t size )
+{
+ size_t rv = status->write( status->ctx, buf, size );
+ status->i += rv;
+ status->current += rv;
+ return rv == size;
+}
+
+/* repeated output of a single character */
+static inline bool cbrept(
+ struct _PDCLIB_status_t * status,
+ char c,
+ size_t times )
+{
+ if ( sizeof(size_t) == 8 && CHAR_BIT == 8)
+ {
+ uint64_t spread = UINT64_C(0x0101010101010101) * c;
+ while ( times )
+ {
+ size_t n = times > 8 ? 8 : times;
+ if ( !cbout( status, &spread, n ) )
+ return false;
+ times -= n;
+ }
+ return true;
+ }
+ else if ( sizeof(size_t) == 4 && CHAR_BIT == 8)
+ {
+ uint32_t spread = UINT32_C(0x01010101) * c;
+ while ( times )
+ {
+ size_t n = times > 4 ? 4 : times;
+ if ( !cbout( status, &spread, n ) )
+ return false;
+ times -= n;
+ }
+ return true;
+ }
+ else
+ {
+ while ( times )
+ {
+ if ( !cbout( status, &c, 1) )
+ return false;
+ times--;
+ }
+ return true;
+ }
+}
+
+
+/* Maximum number of output characters =
+ * number of bits in (u)intmax_t / number of bits per character in smallest
* base. Smallest base is octal, 3 bits/char.
*
* Additionally require 2 extra characters for prefixes
+ *
+ * Returns false if an I/O error occured.
*/
static const size_t maxIntLen = sizeof(intmax_t) * CHAR_BIT / 3 + 1;
-static void int2base( uintmax_t value, struct _PDCLIB_status_t * status )
+static bool int2base( uintmax_t value, struct _PDCLIB_status_t * status )
{
char sign = 0;
- if ( ! ( status->flags & E_unsigned ) )
+ if ( ! ( status->flags & E_unsigned ) )
{
intmax_t signval = (intmax_t) value;
bool negative = signval < 0;
value = signval < 0 ? -signval : signval;
- if ( negative )
+ if ( negative )
{
sign = '-';
- }
- else if ( status->flags & E_plus )
+ }
+ else if ( status->flags & E_plus )
{
sign = '+';
}
}
}
- // The user could theoretically ask for a silly buffer length here.
+ // The user could theoretically ask for a silly buffer length here.
// Perhaps after a certain size we should malloc? Or do we refuse to protect
// them from their own stupidity?
size_t bufLen = (status->width > maxIntLen ? status->width : maxIntLen) + 2;
// Build up our output string - backwards
{
- const char * digits = (status->flags & E_lower) ?
+ const char * digits = (status->flags & E_lower) ?
_PDCLIB_digits : _PDCLIB_Xdigits;
uintmax_t remaining = value;
if(status->prec != 0 || remaining != 0) do {
// If a field width specified, and zero padding was requested, then pad to
// the field width
unsigned padding = 0;
- if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
+ if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
{
- while( written < (int) status->width )
+ while( written < (int) status->width )
{
outend[-++written] = '0';
padding++;
}
// Write output
- status->current = written;
- while ( written )
- PUT( outend[-written--] );
+ return cbout( status, outend - written, written );
}
-static void printstr( const char * str, struct _PDCLIB_status_t * status )
+/* print a string. returns false if an I/O error occured */
+static bool printstr( const char * str, struct _PDCLIB_status_t * status )
{
+ size_t len = status->prec >= 0 ? strnlen( str, status-> prec)
+ : strlen(str);
+
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 ) )
+ if ( status->prec > 0 )
{
- PUT( str[status->current++] );
+ len = (unsigned) status->prec < len ? (unsigned) status->prec : len;
}
- while( status->current < status->width )
- {
- PUT( ' ' );
- status->current++;
+ if ( !cbout( status, str, len ) )
+ return false;
+
+ /* right padding */
+ if ( status->width > status->current ) {
+ len = status->width - status->current;
+
+ if ( !cbrept( status, ' ', len ) )
+ return false;
}
} 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++;
+ if ( status->width > len ) {
+ size_t padding = status->width - len;
+
+ if ( !cbrept( status, ' ', padding ))
+ return false;
}
+
+ if ( !cbout( status, str, len ) )
+ return false;
}
+
+ return true;
}
-static void printchar( char chr, struct _PDCLIB_status_t * status )
+static bool printchar( char chr, struct _PDCLIB_status_t * status )
{
if( ! ( status->flags & E_minus ) )
{
// Right justification
- for( ; status->current + 1 < status->width; status->current++)
- {
- PUT( ' ' );
+ if ( status-> width ) {
+ size_t justification = status->width - status->current - 1;
+ if ( !cbrept( status, ' ', justification ))
+ return false;
}
- PUT( chr );
- status->current++;
+
+ if ( !cbout( status, &chr, 1 ))
+ return false;
} else {
// Left justification
- PUT( chr );
- status->current++;
- for( ; status->current < status->width; status->current++)
- {
- PUT( ' ' );
+ if ( !cbout( status, &chr, 1 ))
+ return false;
+
+ if ( status->width > status->current ) {
+ if ( !cbrept( status, ' ', status->width - status->current ) )
+ return false;
}
}
+
+ return true;
}
-const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
+int _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
{
const char * orig_spec = spec;
if ( *(++spec) == '%' )
{
/* %% -> print single '%' */
- PUT( *spec );
- return ++spec;
+ if ( !cbout(status, spec, 1) )
+ return -1;
+ ++spec;
+ return (spec - orig_spec);
}
/* Initializing status structure */
status->flags = 0;
break;
case 'c':
/* TODO: wide chars. */
- printchar( va_arg( status->arg, int ), status );
- return ++spec;
+ if ( !printchar( va_arg( status->arg, int ), status ) )
+ return -1;
+ ++spec;
+ return (spec - orig_spec);
case 's':
/* TODO: wide chars. */
{
char * s = va_arg( status->arg, char * );
- printstr( s, status );
- return ++spec;
+ if ( !printstr( s, status ) )
+ return -1;
+ ++spec;
+ return (spec - orig_spec);
}
case 'p':
status->base = 16;
{
int * val = va_arg( status->arg, int * );
*val = status->i;
- return ++spec;
+ ++spec;
+ return (spec - orig_spec);
}
default:
/* No conversion specifier. Bad conversion. */
- return orig_spec;
+ return 0;
}
/* Do the actual output based on our findings */
if ( status->base != 0 )
case E_intmax:
value = va_arg( status->arg, uintmax_t );
}
- int2base( value, status );
+ if ( !int2base( value, status ) )
+ return -1;
}
else
{
+ intmax_t value;
switch ( status->flags & E_TYPES )
{
case E_char:
- int2base( (intmax_t)(char)va_arg( status->arg, int ), status );
+ value = (intmax_t)(char)va_arg( status->arg, int );
break;
case E_short:
- int2base( (intmax_t)(short)va_arg( status->arg, int ), status );
+ value = (intmax_t)(short)va_arg( status->arg, int );
break;
case 0:
- int2base( (intmax_t)va_arg( status->arg, int ), status );
+ value = (intmax_t)va_arg( status->arg, int );
break;
case E_long:
- int2base( (intmax_t)va_arg( status->arg, long ), status );
+ value = (intmax_t)va_arg( status->arg, long );
break;
case E_llong:
- int2base( (intmax_t)va_arg( status->arg, long long ), status );
+ value = (intmax_t)va_arg( status->arg, long long );
break;
case E_size:
- int2base( (intmax_t)va_arg( status->arg, size_t ), status );
+ value = (intmax_t)va_arg( status->arg, size_t );
break;
case E_intptr:
- int2base( (intmax_t)va_arg( status->arg, intptr_t ), status );
+ value = (intmax_t)va_arg( status->arg, intptr_t );
break;
case E_ptrdiff:
- int2base( (intmax_t)va_arg( status->arg, ptrdiff_t ), status );
+ value = (intmax_t)va_arg( status->arg, ptrdiff_t );
break;
case E_intmax:
- int2base( va_arg( status->arg, intmax_t ), status );
+ value = va_arg( status->arg, intmax_t );
break;
}
+
+ if (!int2base( value, status ) )
+ return -1;
}
- if ( status->flags & E_minus )
- {
- while ( status->current < status->width )
- {
- PUT( ' ' );
- ++(status->current);
- }
- }
- if ( status->i >= status->n && status->n > 0 )
+
+ if ( status->flags & E_minus && status->current < status->width )
{
- status->s[status->n - 1] = '\0';
+ if (!cbrept( status, ' ', status->width - status->current ))
+ return -1;
}
}
- return ++spec;
+ ++spec;
+ return spec - orig_spec;
}
#endif
#include <_PDCLIB_test.h>
#ifndef REGTEST
+static size_t testcb( void *p, const char *buf, size_t size )
+{
+ char **destbuf = p;
+ memcpy(*destbuf, buf, size);
+ *destbuf += size;
+ return size;
+}
+
static int testprintf( char * buffer, const char * format, ... )
{
- /* Members: base, flags, n, i, current, s, width, prec, stream, arg */
+ /* Members: base, flags, n, i, current, width, prec, ctx, cb, arg */
struct _PDCLIB_status_t status;
status.base = 0;
status.flags = 0;
status.n = 100;
status.i = 0;
status.current = 0;
- status.s = buffer;
status.width = 0;
status.prec = 0;
- status.stream = NULL;
+ status.ctx = &buffer;
+ status.write = testcb;
va_start( status.arg, format );
memset( buffer, '\0', 100 );
- if ( *(_PDCLIB_print( format, &status )) != '\0' )
+ if ( _PDCLIB_print( format, &status ) != strlen( format ) )
{
printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format );
++TEST_RESULTS;
case 's':
{
char * c = va_arg( status->arg, char * );
- while ( ( status->current < status->width ) &&
+ while ( ( status->current < status->width ) &&
( ( rc = GET( status ) ) != EOF ) )
{
if ( isspace( rc ) )
} while ( *endspec != ']' );
// read according to scanlist, equiv. to %s above
char * c = va_arg( status->arg, char * );
- while ( ( status->current < status->width ) &&
+ while ( ( status->current < status->width ) &&
( ( rc = GET( status ) ) != EOF ) )
{
if ( negative_scanlist )
--- /dev/null
+/* _cbprintf( void *, size_t (*)( void*, const char *, size_t ), const char *, ... )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int _cbprintf(
+ void * p,
+ size_t (*cb)( void*, const char*, size_t ),
+ const char * _PDCLIB_restrict format,
+ ...)
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = _vcbprintf( p, cb, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/sprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stddef.h>
+
+#include <_PDCLIB_test.h>
+
+static char * bufptr;
+static size_t testcb( void *p, const char *buf, size_t size )
+{
+ memcpy(bufptr, buf, size);
+ bufptr += size;
+ *bufptr = '\0';
+ return size;
+}
+
+#define testprintf( s, ... ) _cbprintf( bufptr = s, testcb, __VA_ARGS__ )
+
+int main( void )
+{
+ char target[100];
+#ifndef REGTEST
+#include "printf_testcases.h"
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
--- /dev/null
+/* $Id$ */
+
+/* vsnprintf( char *, size_t, const char *, va_list ap )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#ifndef REGTEST
+#include <_PDCLIB_io.h>
+
+/* returns true if callback-based output succeeded; else false */
+static inline bool cbout(
+ struct _PDCLIB_status_t * status,
+ const char *buf,
+ size_t size )
+{
+ size_t rv = status->write( status->ctx, buf, size );
+ status->i += rv;
+ return rv == size;
+}
+
+int _vcbprintf(
+ void *p,
+ size_t ( *cb ) ( void *p, const char *buf, size_t size ),
+ const char *format,
+ va_list arg )
+{
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = 0;
+ status.i = 0;
+ status.current = 0;
+ status.width = 0;
+ status.prec = 0;
+ status.ctx = p;
+ status.write = cb;
+ va_copy( status.arg, arg );
+
+ /* Alternate between outputing runs of verbatim text and conversions */
+ while ( *format != '\0' )
+ {
+ const char *mark = format;
+ while ( *format != '\0' && *format != '%')
+ {
+ format++;
+ }
+
+ if ( mark != format )
+ {
+ if ( !cbout(&status, mark, format - mark) )
+ return -1;
+ }
+
+ if ( *format == '%' ) {
+ int consumed = _PDCLIB_print( format, &status );
+ if ( consumed > 0 )
+ {
+ format += consumed;
+ }
+ else if ( consumed == 0 )
+ {
+ /* not a conversion specifier, print verbatim */
+ if ( !cbout(&status, format++, 1) )
+ return -1;
+ }
+ else
+ {
+ /* I/O callback error */
+ return -1;
+ }
+ }
+ }
+
+ va_end( status.arg );
+ return status.i;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/_vcbprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+#include <_PDCLIB_test.h>
+
+#ifndef REGTEST
+
+static size_t testcb( void *p, const char *buf, size_t size )
+{
+ char **destbuf = p;
+ memcpy(*destbuf, buf, size);
+ *destbuf += size;
+ return size;
+}
+
+static int testprintf( char * s, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = _vcbprintf( &s, testcb, format, arg );
+ *s = 0;
+ va_end( arg );
+ return i;
+}
+
+#endif
+
+int main( void )
+{
+ char target[100];
+#ifndef REGTEST
+#include "printf_testcases.h"
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
+
#ifndef REGTEST
#include <_PDCLIB_io.h>
-int _PDCLIB_vfprintf_unlocked( FILE * _PDCLIB_restrict stream,
- const char * _PDCLIB_restrict format,
- va_list arg )
+static size_t filecb(void *p, const char *buf, size_t size)
{
- /* TODO: This function should interpret format as multibyte characters. */
- struct _PDCLIB_status_t status;
- status.base = 0;
- status.flags = 0;
- status.n = UINT_MAX;
- status.i = 0;
- status.current = 0;
- status.s = NULL;
- status.width = 0;
- status.prec = 0;
- status.stream = stream;
- va_copy( status.arg, arg );
+ return _PDCLIB_fwrite_unlocked( buf, 1, size, (FILE*) p );
+}
- while ( *format != '\0' )
- {
- const char * rc;
- if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
- {
- /* No conversion specifier, print verbatim */
- _PDCLIB_putc_unlocked( *(format++), stream );
- status.i++;
- }
- else
- {
- /* Continue parsing after conversion specifier */
- format = rc;
- }
- }
- va_end( status.arg );
- return status.i;
+int _PDCLIB_vfprintf_unlocked( FILE * _PDCLIB_restrict stream,
+ const char * _PDCLIB_restrict format,
+ va_list arg )
+{
+ return _vcbprintf(stream, filecb, format, arg);
}
-int vfprintf( FILE * _PDCLIB_restrict stream,
- const char * _PDCLIB_restrict format,
+int vfprintf( FILE * _PDCLIB_restrict stream,
+ const char * _PDCLIB_restrict format,
va_list arg )
{
_PDCLIB_flockfile( stream );
#ifndef REGTEST
#include <_PDCLIB_io.h>
-int _PDCLIB_vscanf_unlocked( const char * _PDCLIB_restrict format,
+int _PDCLIB_vscanf_unlocked( const char * _PDCLIB_restrict format,
_PDCLIB_va_list arg )
{
return _PDCLIB_vfscanf_unlocked( stdin, format, arg );
#ifndef REGTEST
#include <_PDCLIB_io.h>
+#include <string.h>
-int vsnprintf( char * _PDCLIB_restrict s,
- size_t n,
- const char * _PDCLIB_restrict format,
- _PDCLIB_va_list arg )
+struct state {
+ size_t bufrem;
+ char *bufp;
+};
+
+static size_t strout( void *p, const char *buf, size_t sz )
{
- /* TODO: This function should interpret format as multibyte characters. */
- struct _PDCLIB_status_t status;
- status.base = 0;
- status.flags = 0;
- status.n = n;
- status.i = 0;
- status.current = 0;
- status.s = s;
- status.width = 0;
- status.prec = 0;
- status.stream = NULL;
- va_copy( status.arg, arg );
+ struct state *s = p;
+ size_t copy = s->bufrem >= sz ? sz : s->bufrem;
+ memcpy( s->bufp, buf, copy );
+ s->bufrem -= copy;
+ s->bufp += copy;
+ return sz;
+}
- while ( *format != '\0' )
- {
- const char * rc;
- if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
- {
- /* No conversion specifier, print verbatim */
- if ( status.i < n )
- {
- s[ status.i ] = *format;
- }
- status.i++;
- format++;
- }
- else
- {
- /* Continue parsing after conversion specifier */
- format = rc;
- }
- }
- if ( status.i < n )
+int vsnprintf( char * _PDCLIB_restrict s,
+ size_t n,
+ const char * _PDCLIB_restrict format,
+ _PDCLIB_va_list arg )
+{
+ struct state st;
+ st.bufrem = n;
+ st.bufp = s;
+ int r = _vcbprintf( &st, strout, format, arg );
+ if ( st.bufrem )
{
- s[ status.i ] = '\0';
+ *st.bufp = 0;
}
- va_end( status.arg );
- return status.i;
+
+ return r;
}
#endif
#define L_tmpnam _PDCLIB_L_tmpnam
#define TMP_MAX _PDCLIB_TMP_MAX
-/* See fseek(), third argument
+/* See fseek(), third argument
*
* Some system headers (e.g. windows) also define the SEEK_* values. Check for
* this and validate that they're the same value
int remove( const char * filename ) _PDCLIB_nothrow;
/* Rename the given old file to the given new name.
- Returns zero if successful, non-zero otherwise.
+ Returns zero if successful, non-zero otherwise.
This implementation does detect if the old filename corresponds to an open
file, and fails the rename in this case.
If there already is a file with the new filename, behaviour is defined by
Returns a pointer to the stream handle if successfull, NULL otherwise.
*/
-FILE * fopen( const char * _PDCLIB_restrict filename,
+FILE * fopen( const char * _PDCLIB_restrict filename,
const char * _PDCLIB_restrict mode ) _PDCLIB_nothrow;
/* Creates a stream connected to the file descriptor \p fd with mode \p mode.
Mode must match the mode with which the file descriptor was opened.
*/
-FILE * _PDCLIB_fvopen( _PDCLIB_fd_t fd, const _PDCLIB_fileops_t * ops,
+FILE * _PDCLIB_fvopen( _PDCLIB_fd_t fd, const _PDCLIB_fileops_t * ops,
int mode, const char * filename ) _PDCLIB_nothrow;
/* Close any file currently associated with the given stream. Open the file
and NULL is returned. If a read error occurs, the contents of s are indeter-
minate, and NULL is returned.
- This function is dangerous and has been a great source of security
+ This function is dangerous and has been a great source of security
vulnerabilities. Do not use it. It was removed by C11.
*/
char * gets( char * s ) _PDCLIB_DEPRECATED _PDCLIB_nothrow;
*/
void perror( const char * s ) _PDCLIB_nothrow;
-/* Unlocked I/O
+/* Unlocked I/O
*
* Since threading was introduced in C11, FILE objects have had implicit locks
* to prevent data races and inconsistent output.
* the behaviour of the _unlocked variant is the same except that it will not
* take the lock associated with the stream.
*
- * flockfile, ftrylockfile and funlockfile can be used to manually manipulate
+ * flockfile, ftrylockfile and funlockfile can be used to manually manipulate
* the stream locks. The behaviour of the _unlocked functions if called when the
* stream isn't locked by the calling thread is implementation defined.
*/
#endif
#if _PDCLIB_BSD_SOURCE || _PDCLIB_SVID_SOURCE
-void clearerr_unlocked(FILE *stream) _PDCLIB_nothrow;
+void clearerr_unlocked(FILE *stream) _PDCLIB_nothrow;
int feof_unlocked(FILE *stream) _PDCLIB_nothrow;
int ferror_unlocked(FILE *stream) _PDCLIB_nothrow;
int fflush_unlocked(FILE *stream) _PDCLIB_nothrow;
int fputs_unlocked(const char *s, FILE *stream) _PDCLIB_nothrow;
#endif
-#if defined(_PDCLIB_EXTENSIONS)
+#if _PDCLIB_EXTENSIONS
+int _vcbprintf(
+ void *p,
+ _PDCLIB_size_t ( *cb ) ( void *p, const char *buf, _PDCLIB_size_t size ),
+ const char *format,
+ _PDCLIB_va_list arg );
+
+int _cbprintf(
+ void *p,
+ size_t ( *cb ) ( void *p, const char *buf, size_t size ),
+ const char *format,
+ ... );
+
int fgetpos_unlocked( FILE * _PDCLIB_restrict stream, fpos_t * _PDCLIB_restrict pos ) _PDCLIB_nothrow;
int fsetpos_unlocked( FILE * stream, const fpos_t * pos ) _PDCLIB_nothrow;
long int ftell_unlocked( FILE * stream ) _PDCLIB_nothrow;
*/
_PDCLIB_uint16_t _Surrogate;
- /* In cases where the underlying codec is capable of regurgitating a
+ /* In cases where the underlying codec is capable of regurgitating a
* character without consuming any extra input (e.g. a surrogate pair in a
- * UCS-4 to UTF-16 conversion) then these fields are used to track that
+ * UCS-4 to UTF-16 conversion) then these fields are used to track that
* state. In particular, they are used to buffer/fake the input for mbrtowc
* and similar functions.
*
- * See _PDCLIB_encoding.h for values of _PendState and the resultant value
+ * See _PDCLIB_encoding.h for values of _PendState and the resultant value
* in _PendChar.
*/
unsigned char _PendState;
/* Status structure required by _PDCLIB_print(). */
struct _PDCLIB_status_t
{
+ /* XXX This structure is horrible now. scanf needs its own */
+
int base; /* base to which the value shall be converted */
_PDCLIB_int_fast32_t flags; /* flags and length modifiers */
- unsigned n; /* print: maximum characters to be written */
+ unsigned n; /* print: maximum characters to be written (snprintf) */
/* scan: number matched conversion specifiers */
unsigned i; /* number of characters read/written */
unsigned current;/* chars read/written in the CURRENT conversion */
- char * s; /* *sprintf(): target buffer */
- /* *sscanf(): source string */
unsigned width; /* specified field width */
int prec; /* specified field precision */
- _PDCLIB_file_t * stream; /* *fprintf() / *fscanf() stream */
+
+ union {
+ void * ctx; /* context for callback */
+ const char * s; /* input string for scanf */
+ };
+
+ union {
+ _PDCLIB_size_t ( *write ) ( void *p, const char *buf, _PDCLIB_size_t size );
+ _PDCLIB_file_t *stream; /* for scanf */
+ };
_PDCLIB_va_list arg; /* argument stack */
};
be that of the current printf() function, of which the members n, s, stream\r
and arg will be preserved; i will be updated; and all others will be trashed\r
by the function.\r
- Returns a pointer to the first character not parsed as conversion specifier.\r
+ Returns the number of characters parsed as a conversion specifier (0 if none\r
+ parsed); returns -1 if the underlying I/O callback returns failure.\r
*/\r
-const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status );\r
+int _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status );\r
\r
/* The worker for all scanf() type of functions. The pointer spec should point\r
to the introducing '%' of a conversion specifier. The status structure is to\r
/* Parsing any fopen() style filemode string into a number of flags. */\r
unsigned int _PDCLIB_filemode( const char * mode );\r
\r
-/* Sanity checking and preparing of read buffer, should be called first thing \r
+/* Sanity checking and preparing of read buffer, should be called first thing\r
by any stdio read-data function.\r
Returns 0 on success, EOF on error.\r
On error, EOF / error flags and errno are set appropriately.\r
/* Repositions within a file. Returns new offset on success,\r
-1 / errno on error.\r
*/\r
-_PDCLIB_int_fast64_t _PDCLIB_seek( _PDCLIB_file_t * stream, \r
+_PDCLIB_int_fast64_t _PDCLIB_seek( _PDCLIB_file_t * stream,\r
_PDCLIB_int_fast64_t offset, int whence );\r
\r
/* File backend I/O operations\r
* On error, returns false and sets errno appropriately. *numBytesRead is\r
* ignored in this situation.\r
*/\r
- _PDCLIB_bool (*read)( _PDCLIB_fd_t self, \r
- void * buf, \r
- _PDCLIB_size_t length, \r
+ _PDCLIB_bool (*read)( _PDCLIB_fd_t self,\r
+ void * buf,\r
+ _PDCLIB_size_t length,\r
_PDCLIB_size_t * numBytesRead );\r
\r
/*! Write length bytes to the file from buf; returning the number of bytes\r
* actually written in *numBytesWritten\r
*\r
* Returns true if bytes were written successfully. On error, returns false\r
- * and setss errno appropriately (as with read, *numBytesWritten is \r
+ * and setss errno appropriately (as with read, *numBytesWritten is\r
* ignored)\r
*/\r
- _PDCLIB_bool (*write)( _PDCLIB_fd_t self, const void * buf, \r
+ _PDCLIB_bool (*write)( _PDCLIB_fd_t self, const void * buf,\r
_PDCLIB_size_t length, _PDCLIB_size_t * numBytesWritten );\r
\r
/* Seek to the file offset specified by offset, from location whence, which\r
* may be one of the standard constants SEEK_SET/SEEK_CUR/SEEK_END\r
*/\r
- _PDCLIB_bool (*seek)( _PDCLIB_fd_t self, _PDCLIB_int_fast64_t offset, \r
+ _PDCLIB_bool (*seek)( _PDCLIB_fd_t self, _PDCLIB_int_fast64_t offset,\r
int whence, _PDCLIB_int_fast64_t *newPos );\r
\r
void (*close)( _PDCLIB_fd_t self );\r
\r
- /*! Behaves as read does, except for wide characters. Both length and \r
+ /*! Behaves as read does, except for wide characters. Both length and\r
* *numCharsRead represent counts of characters, not bytes.\r
*\r
* This function is optional; if missing, PDCLib will buffer the character\r
* data as bytes and perform translation directly into the user's buffers.\r
- * It is useful if your backend can directly take wide characters (for \r
+ * It is useful if your backend can directly take wide characters (for\r
* example, the Windows console)\r
*/\r
- _PDCLIB_bool (*wread)( _PDCLIB_fd_t self, _PDCLIB_wchar_t * buf, \r
+ _PDCLIB_bool (*wread)( _PDCLIB_fd_t self, _PDCLIB_wchar_t * buf,\r
_PDCLIB_size_t length, _PDCLIB_size_t * numCharsRead );\r
\r
/* Behaves as write does, except for wide characters. As with wread, both\r
* length and *numCharsWritten are character counts.\r
*\r
- * This function is also optional; if missing, PDCLib will buffer the \r
- * character data as bytes and do translation directly from the user's \r
- * buffers. You only need to implement this if your backend can directly \r
+ * This function is also optional; if missing, PDCLib will buffer the\r
+ * character data as bytes and do translation directly from the user's\r
+ * buffers. You only need to implement this if your backend can directly\r
* take wide characters (for example, the Windows console)\r
*/\r
- _PDCLIB_bool (*wwrite)( _PDCLIB_fd_t self, const _PDCLIB_wchar_t * buf, \r
+ _PDCLIB_bool (*wwrite)( _PDCLIB_fd_t self, const _PDCLIB_wchar_t * buf,\r
_PDCLIB_size_t length, _PDCLIB_size_t * numCharsWritten );\r
};\r
\r
int c;\r
while ( stream->ungetidx > 0 && i != n )\r
{\r
- c = (unsigned char) \r
+ c = (unsigned char)\r
( out[ i++ ] = stream->ungetbuf[ --(stream->ungetidx) ] );\r
if( c == stopchar )\r
return i;\r
\r
while ( i != n )\r
{\r
- while ( stream->bufidx != stream->bufend && i != n) \r
+ while ( stream->bufidx != stream->bufend && i != n)\r
{\r
- c = (unsigned char) \r
+ c = (unsigned char)\r
( out[ i++ ] = stream->buffer[ stream->bufidx++ ] );\r
if( c == stopchar )\r
return i;\r
return i;\r
}\r
\r
-/* Unlocked functions - internal names \r
+/* Unlocked functions - internal names\r
*\r
* We can't use the functions using their "normal" names internally because that\r
- * would cause namespace leakage. Therefore, we use them by prefixed internal \r
+ * would cause namespace leakage. Therefore, we use them by prefixed internal\r
* names\r
*/\r
void _PDCLIB_flockfile(struct _PDCLIB_file *file) _PDCLIB_nothrow;\r
int _PDCLIB_getchar_unlocked(void) _PDCLIB_nothrow;\r
int _PDCLIB_putc_unlocked(int c, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
int _PDCLIB_putchar_unlocked(int c) _PDCLIB_nothrow;\r
-void _PDCLIB_clearerr_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow; \r
+void _PDCLIB_clearerr_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
int _PDCLIB_feof_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
int _PDCLIB_ferror_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
int _PDCLIB_fflush_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r