Allow vcprintf() to be called by external code such as the curses library.
authorMichael Brown <mcb30@etherboot.org>
Mon, 22 May 2006 15:41:01 +0000 (15:41 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 22 May 2006 15:41:01 +0000 (15:41 +0000)
Also trim another eight bytes from vsprintf.o.  :)

src/core/vsprintf.c
src/include/vsprintf.h

index a8f7af6..a80c62e 100644 (file)
@@ -40,32 +40,6 @@ static uint8_t type_sizes[] = {
        [SIZE_T_LEN]    = sizeof ( size_t ),
 };
 
-/**
- * A printf context
- *
- * Contexts are used in order to be able to share code between
- * vprintf() and vsnprintf(), without requiring the allocation of a
- * buffer for vprintf().
- */
-struct printf_context {
-       /**
-        * Character handler
-        *
-        * @v ctx       Context
-        * @v c         Character
-        *
-        * This method is called for each character written to the
-        * formatted string.  It must increment @len.
-        */
-       void ( * handler ) ( struct printf_context *ctx, unsigned int c );
-       /** Length of formatted string */
-       size_t len;
-       /** Buffer for formatted string (used by printf_sputc()) */
-       char *buf;
-       /** Buffer length (used by printf_sputc()) */
-       size_t max_len;
-};
-
 /**
  * Use lower-case for hexadecimal digits
  *
@@ -163,6 +137,20 @@ static char * format_decimal ( char *end, signed long num, int width ) {
        return ptr;
 }
 
+/**
+ * Print character via a printf context
+ *
+ * @v ctx              Context
+ * @v c                        Character
+ *
+ * Call's the printf_context::handler() method and increments
+ * printf_context::len.
+ */
+static inline void cputchar ( struct printf_context *ctx, unsigned int c ) {
+       ctx->handler ( ctx, c );
+       ++ctx->len;
+}
+
 /**
  * Write a formatted string to a printf context
  *
@@ -185,7 +173,7 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
        for ( ; *fmt ; fmt++ ) {
                /* Pass through ordinary characters */
                if ( *fmt != '%' ) {
-                       ctx->handler ( ctx, *fmt );
+                       cputchar ( ctx, *fmt );
                        continue;
                }
                fmt++;
@@ -228,7 +216,7 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
                ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
                *ptr = '\0';
                if ( *fmt == 'c' ) {
-                       ctx->handler ( ctx, va_arg ( args, unsigned int ) );
+                       cputchar ( ctx, va_arg ( args, unsigned int ) );
                } else if ( *fmt == 's' ) {
                        ptr = va_arg ( args, char * );
                } else if ( *fmt == 'p' ) {
@@ -263,13 +251,22 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
                }
                /* Write out conversion result */
                for ( ; *ptr ; ptr++ ) {
-                       ctx->handler ( ctx, *ptr );
+                       cputchar ( ctx, *ptr );
                }
        }
 
        return ctx->len;
 }
 
+/** Context used by vsnprintf() and friends */
+struct sputc_context {
+       struct printf_context ctx;
+       /** Buffer for formatted string (used by printf_sputc()) */
+       char *buf;
+       /** Buffer length (used by printf_sputc()) */
+       size_t max_len; 
+};
+
 /**
  * Write character to buffer
  *
@@ -277,8 +274,11 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
  * @v c                        Character
  */
 static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
-       if ( ++ctx->len < ctx->max_len )
-               ctx->buf[ctx->len-1] = c;
+       struct sputc_context * sctx =
+               container_of ( ctx, struct sputc_context, ctx );
+
+       if ( ctx->len <= sctx->max_len )
+               sctx->buf[ctx->len] = c;
 }
 
 /**
@@ -295,15 +295,15 @@ static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
  * been available.
  */
 int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
-       struct printf_context ctx;
+       struct sputc_context sctx;
        size_t len;
        size_t end;
 
        /* Hand off to vcprintf */
-       ctx.handler = printf_sputc;
-       ctx.buf = buf;
-       ctx.max_len = size;
-       len = vcprintf ( &ctx, fmt, args );
+       sctx.ctx.handler = printf_sputc;
+       sctx.buf = buf;
+       sctx.max_len = size;
+       len = vcprintf ( &sctx.ctx, fmt, args );
 
        /* Add trailing NUL */
        if ( size ) {
@@ -341,8 +341,8 @@ int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
  * @v ctx              Context
  * @v c                        Character
  */
-static void printf_putchar ( struct printf_context *ctx, unsigned int c ) {
-       ++ctx->len;
+static void printf_putchar ( struct printf_context *ctx __unused,
+                            unsigned int c ) {
        putchar ( c );
 }
 
index 99d6683..d5018d7 100644 (file)
 
 #define PRINTF_NO_LENGTH ( ( size_t ) -1 )
 
+/**
+ * A printf context
+ *
+ * Contexts are used in order to be able to share code between
+ * vprintf() and vsnprintf(), without requiring the allocation of a
+ * buffer for vprintf().
+ */
+struct printf_context {
+       /**
+        * Character handler
+        *
+        * @v ctx       Context
+        * @v c         Character
+        *
+        * This method is called for each character written to the
+        * formatted string.
+        */
+       void ( * handler ) ( struct printf_context *ctx, unsigned int c );
+       /** Length of formatted string
+        *
+        * When handler() is called, @len will be set to the number of
+        * characters written so far (i.e. zero for the first call to
+        * handler()).
+        */
+       size_t len;
+};
+
+extern size_t vcprintf ( struct printf_context *ctx, const char *fmt,
+                        va_list args );
 extern int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args );
 extern int vprintf ( const char *fmt, va_list args );