]> pd.if.org Git - pdclib/blob - functions/stdio/_vcbprintf.c
dbb217115553a93fa95d3fad5c9f3a7912043133
[pdclib] / functions / stdio / _vcbprintf.c
1 /* $Id$ */
2
3 /* vsnprintf( char *, size_t, const char *, va_list ap )
4
5    This file is part of the Public Domain C Library (PDCLib).
6    Permission is granted to use, modify, and / or redistribute at will.
7 */
8
9 #include <stdio.h>
10 #include <stdarg.h>
11 #include <stdbool.h>
12
13 #ifndef REGTEST
14 #include <_PDCLIB_io.h>
15
16 /* returns true if callback-based output succeeded; else false */
17 static inline bool cbout(
18     struct _PDCLIB_status_t * status,
19     const char *buf,
20     size_t size )
21 {
22     size_t rv = status->write( status->ctx, buf, size );
23     status->i += rv;
24     return rv == size;
25 }
26
27 int _vcbprintf(
28     void *p,
29     size_t ( *cb ) ( void *p, const char *buf, size_t size ),
30     const char *format,
31     va_list arg )
32 {
33     struct _PDCLIB_status_t status;
34     status.base     = 0;
35     status.flags    = 0;
36     status.n        = 0;
37     status.i        = 0;
38     status.current  = 0;
39     status.width    = 0;
40     status.prec     = 0;
41     status.ctx      = p;
42     status.write    = cb;
43     va_copy( status.arg, arg );
44
45     /* Alternate between outputing runs of verbatim text and conversions */
46     while ( *format != '\0' )
47     {
48         const char *mark = format;
49         while ( *format != '\0' && *format != '%')
50         {
51             format++;
52         }
53
54         if ( mark != format )
55         {
56             if ( !cbout(&status, mark, format - mark) )
57                 return -1;
58         }
59
60         if ( *format == '%' ) {
61             int consumed = _PDCLIB_print( format, &status );
62             if ( consumed > 0 )
63             {
64                 format += consumed;
65             }
66             else if ( consumed == 0 )
67             {
68                 /* not a conversion specifier, print verbatim */
69                 if ( !cbout(&status, format++, 1) )
70                     return -1;
71             }
72             else
73             {
74                 /* I/O callback error */
75                 return -1;
76             }
77         }
78     }
79
80     va_end( status.arg );
81     return status.i;
82 }
83
84 #endif
85
86 #ifdef TEST
87 #define _PDCLIB_FILEID "stdio/_vcbprintf.c"
88 #define _PDCLIB_STRINGIO
89 #include <stdint.h>
90 #include <stddef.h>
91 #include <_PDCLIB_test.h>
92
93 #ifndef REGTEST
94
95 static size_t testcb( void *p, const char *buf, size_t size )
96 {
97     char **destbuf = p;
98     memcpy(*destbuf, buf, size);
99     *destbuf += size;
100     return size;
101 }
102
103 static int testprintf( char * s, const char * format, ... )
104 {
105     int i;
106     va_list arg;
107     va_start( arg, format );
108     i = _vcbprintf( &s, testcb, format, arg );
109     *s = 0;
110     va_end( arg );
111     return i;
112 }
113
114 #endif
115
116 int main( void )
117 {
118     char target[100];
119 #ifndef REGTEST
120 #include "printf_testcases.h"
121 #endif
122     return TEST_RESULTS;
123 }
124
125 #endif
126