4 * A simple implementation of all formatted xxprintf functionallity.
10 * What you normally would do is to print to a buffer of some kind and then
11 * call write(). However little stack indicates that we can't place buffers
12 * on the stack and reentrant tells us that we can't have a static buffer.
13 * That leaves us with printing characters as it is ready. From a speed
14 * point of view that is less than optimal, but that the way it's got to be.
15 * (Could make a 16 long char buffer??)
17 * This is just intended to be used as a replacement for newlibs implementation.
18 * Newlib porting interface have the following API:
19 * int write( int fd, char *buf, int nbytes)
22 * Note that puts(), putc() are still the newlib variants....
24 * printf() -> vfprintf(stdout,) -> vsnprintf(buf,)
26 * vprintf() -> vfprintf(stdout,) -> vsnprintf(buf,)
28 * sprintf(buf,) -> vsnprintf(buf,)
29 * snprintf(buf,) -> vsnprintf(buf,)
31 * IMPLEMENTATION NOTE:
32 * If printing more than the limit, e.g. using vsnprintf() then
33 * the emit function will only stop printing, but not interrupted
34 * (The code will get more complicated that way)
45 #define _STDOUT stdout
47 #define _STDERR stderr
49 #define _STDOUT (FILE *)STDOUT_FILENO
50 #define _STDINT STDIN_FILENO
51 #define _STDERR (FILE *)STDERR_FILENO
56 int print(FILE *file, char **buffer, size_t n, const char *format, va_list ap);
58 int printf(const char *format, ...) {
63 rv = vfprintf(_STDOUT, format, ap);
68 int fprintf(FILE *file, const char *format, ...) {
73 rv = vfprintf(file, format, ap);
78 int sprintf(char *buffer, const char *format, ...) {
83 rv = vsnprintf(buffer, ~(size_t)0, format, ap);
89 int snprintf(char *buffer, size_t n, const char *format, ...) {
94 rv = vsnprintf(buffer, n, format, ap);
99 int vprintf(const char *format, va_list ap) {
100 return vfprintf(_STDOUT, format, ap);
103 int vsprintf(char *buffer, const char *format, va_list ap) {
104 return vsnprintf(buffer, ~(size_t)0, format, ap);
107 int vfprintf(FILE *file, const char *format, va_list ap) {
109 /* Just print to _STDOUT */
110 rv = print(file,NULL,~(size_t)0, format,ap);
114 int vsnprintf(char *buffer, size_t n, const char *format, va_list ap) {
117 rv = print(NULL, &buffer, n, format,ap);
124 * @param file The file to print to
125 * @param buf The buffer to print to
126 * @param c The char to print
129 static inline int emitChar( FILE *file, char **buf, char c, int *left ) {
149 #if defined(HOST_TEST)
151 * Convert a number to a string
153 * @param val The value to convert
154 * @param str Pointer to a space where to put the string
155 * @param base The base
156 * @param negative If negative or not.
158 void xtoa( unsigned long val, char* str, int base, int negative) {
167 if( base < 10 && base > 16 ) {
174 str[i++] = "0123456789abcdef"[ val % base ];
175 } while ((val /= base) > 0);
191 extern void xtoa( unsigned long val, char* str, int base, int negative);
195 #define FL_NONE (0<<0)
196 #define FL_ZERO (1<<1)
197 #define FL_HASH (1<<2)
198 #define FL_SPACE (1<<3)
199 #define FL_ALIGN_LEFT (1<<4)
200 #define FL_TYPE_SIGNED_INT (1<<5)
201 #define FL_TYPE_UNSIGNED_INT (1<<6)
204 static void emitString( FILE *file, char **buffer, char *string, int width, int flags, int *left) {
209 /* padding: FL_ZERO or normal ' '
210 * align: FL_ALIGN_LEFT (left) or normal (right)
212 pad = (flags & FL_ZERO) ? '0' : ' ';
215 if( flags & FL_ALIGN_LEFT ) {
216 for(i=0;str[i]; i++) {
217 emitChar(file,buffer,str[i],left);
222 emitChar(file,buffer,pad,left);
226 strLen = strlen(string);
229 if( width > strLen ) {
230 for(i=0;i<(width-strLen);i++) {
231 emitChar(file,buffer,pad,left);
235 for(i=0;i<strLen; i++) {
236 emitChar(file,buffer,string[i],left);
241 void emitInt( FILE *file, char **buffer, int base, int width, int flags, va_list ap, int *left )
243 char lBuf[12]; // longest is base 10, 2^32
247 if( flags & FL_TYPE_SIGNED_INT ) {
248 val = (int )va_arg( ap, int );
249 xtoa(val,str,base ,(val < 0));
251 xtoa((unsigned)va_arg( ap, int ),str,base ,0);
254 emitString(file,buffer,str,width,flags,left);
259 #define PRINT_CHAR(_c) *buffer++= (_c);
263 * Write formatted output to an array with a maximum number of characters.
265 * This is the mother of the formatted print family. The main goal here
266 * is to be very small and memory efficient.
270 * Flags : '-' and '0'
271 * Width : Normal padding is supported, '*' is not.
275 * Type : d,u,x,s,and c
277 * @param file The file descriptor
278 * @param buffer A pointer to the place to store the output
279 * If NULL the output is instead
280 * @param n The maximum number of characters to write
281 * @param format The format string
282 * @param ap The va list
285 int print(FILE *file, char **buffer, size_t n, const char *format, va_list ap)
293 while ( (ch = *format++) ) {
299 emitChar(file,buffer,ch,&left);
312 flags = FL_ALIGN_LEFT;
315 /* Not supported or no flag */
324 if( (ch >= '0') && (ch <= '9') ) {
334 emitChar(file,buffer,(char )va_arg( ap, int ),&left);
337 flags |= FL_TYPE_SIGNED_INT;
338 emitInt(file,buffer,10,width,flags,ap,&left);
341 flags |= FL_TYPE_UNSIGNED_INT;
342 emitInt(file,buffer,10,width,flags,ap,&left);
345 flags |= FL_TYPE_UNSIGNED_INT;
346 emitInt(file,buffer,16,width,flags,ap,&left);
349 str = (char *)va_arg( ap, int );
355 emitString(file,buffer,str,width,flags,&left);
364 emitChar(file,buffer,ch,&left);
370 emitChar(file,buffer,'\0',&left);
372 return 0; // Wrong.. but for now.
375 #if defined(HOST_TEST)
380 printf("char: %c %c = a B\n", 'a', 66);
382 printf("string: %s = (null)\n", (char *)ptr);
384 printf("string: %s = foobar \n", "foobar");
386 printf("string: %2s = foobar \n", "foobar");
387 printf("string: \"%8s\" = \" foobar\" \n", "foobar");
389 printf("string: \"%-8s\" = \"foobar \" \n", "foobar");
391 printf("decimal: 23 = %d \n", 23);
392 printf("hex: c23 = %x \n", 0xc23);
393 printf("hex: 0c23 = %04x \n", 0xc23);
394 printf("decimal with blanks: 23 = %6d \n", 23);
395 printf("decimal with zero: 000023 = %06d \n", 23);
397 /* negative and large numbers */
398 printf("decimal: -23 = %d \n", -23);
399 printf("decimal: 4294967273 = %u \n", -23);
400 printf("decimal: c0000000 = %x \n", 0xc0000000);
402 printf("decimal: 00c000 = %06x \n", 0xc000);
404 fprintf(_STDOUT, "string: %s = foobar \n", "foobar");
405 sprintf(buff, "string: %s = foobar \n", "foobar");
408 snprintf(buff,10, "%s\n", "12345678901234567");
409 printf("\"123456789\" = \"%s\"\n",buff);
411 snprintf(buff,12, "%s\n", "abcdefghijklmn");
412 printf("\"abcdefghijkl\" = \"%s\"\n",buff);