]> rtime.felk.cvut.cz Git - arc.git/blobdiff - common/printf.c
Merge branch 'mikulka' of git@rtime.felk.cvut.cz:arc into mikulka
[arc.git] / common / printf.c
index 6d2b13b2d12e0f0168dde1d69a363108771d7a48..be39635ab039acdcbebb8f9952fdf4f5c5818e5f 100644 (file)
-/* -------------------------------- Arctic Core ------------------------------
- * Arctic Core - the open source AUTOSAR platform http://arccore.com
- *
- * Copyright (C) 2009  ArcCore AB <contact@arccore.com>
- *
- * This source code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by the
- * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- * -------------------------------- Arctic Core ------------------------------*/
-
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include "simple_printf.h"
-
-#define BUF_SIZE       60
-#define STD_OUT 1
-
-#if 0
-//char *
-int dbg_printf(const char *fmt, ...) {
-   /* Guess we need no more than 100 bytes. */
-   int n;
-   va_list ap;
-   char p[BUF_SIZE];
-
-  /* Try to print in the allocated space. */
-  va_start(ap, fmt);
-  n = vsnprintf (p, BUF_SIZE, fmt, ap);
-  puts(p);
-  va_end(ap);
-  return 0;
-}
-
-#endif
-/*
-       Copyright 2001, 2002 Georges Menie (www.menie.org)
-       stdarg version contributed by Christian Ettinger
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU Lesser General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-/*
-       putchar is the only external dependency for this file,
-       if you have a working putchar, leave it commented out.
-       If not, uncomment the define below and
-       replace outbyte(c) by your own function call.
-
-#define putchar(c) outbyte(c)
-*/
-
-
-extern int arc_putchar(int fd, int c);
-
-static void printchar(int fd, char **str, int c)
-{
-       if (str) {
-               **str = c;
-               ++(*str);
-       }
-       else {
-               (void)arc_putchar(fd, c);
-       }
-}
-
-#define PAD_RIGHT 1
-#define PAD_ZERO 2
-
-static int prints(int fd, char **out, const char *string, int width, int pad)
-{
-       register int pc = 0, padchar = ' ';
-
-       if (width > 0) {
-               register int len = 0;
-               register const char *ptr;
-               for (ptr = string; *ptr; ++ptr) ++len;
-               if (len >= width) width = 0;
-               else width -= len;
-               if (pad & PAD_ZERO) padchar = '0';
-       }
-       if (!(pad & PAD_RIGHT)) {
-               for ( ; width > 0; --width) {
-                       printchar (fd, out, padchar);
-                       ++pc;
-               }
-       }
-       for ( ; *string ; ++string) {
-               printchar (fd, out, *string);
-               ++pc;
-       }
-       for ( ; width > 0; --width) {
-               printchar (fd, out, padchar);
-               ++pc;
-       }
-
-       return pc;
-}
-
-
-
-/* the following should be enough for 32 bit int */
-#define PRINT_BUF_LEN 12
-
-static int printi(int fd, char **out, int i, int b, int sg, int width, int pad, int letbase)
-{
-       char print_buf[PRINT_BUF_LEN];
-       register char *s;
-       register int t, neg = 0, pc = 0;
-       register unsigned int u = i;
-
-       if (i == 0) {
-               print_buf[0] = '0';
-               print_buf[1] = '\0';
-               return prints (fd, out, print_buf, width, pad);
-       }
-
-       if (sg && b == 10 && i < 0) {
-               neg = 1;
-               u = -i;
-       }
-
-       s = print_buf + PRINT_BUF_LEN-1;
-       *s = '\0';
-
-       while (u) {
-               t = u % b;
-               if( t >= 10 )
-                       t += letbase - '0' - 10;
-               *--s = t + '0';
-               u /= b;
-       }
-
-       if (neg) {
-               if( width && (pad & PAD_ZERO) ) {
-                       printchar (fd, out, '-');
-                       ++pc;
-                       --width;
-               }
-               else {
-                       *--s = '-';
-               }
-       }
-
-       return pc + prints (fd, out, s, width, pad);
-}
-
-static int print(int fd, char **out, const char *format, va_list args )
-{
-       int width, pad;
-       int pc = 0;
-       char scr[2];
-
-       for (; *format != 0; ++format) {
-               if (*format == '%') {
-                       ++format;
-                       width = pad = 0;
-                       if (*format == '\0') break;
-                       if (*format == '%') goto out;
-                       if (*format == '-') {
-                               ++format;
-                               pad = PAD_RIGHT;
-                       }
-                       while (*format == '0') {
-                               ++format;
-                               pad |= PAD_ZERO;
-                       }
-                       for ( ; *format >= '0' && *format <= '9'; ++format) {
-                               width *= 10;
-                               width += *format - '0';
-                       }
-                       if( *format == 's' ) {
-                               char *s = (char *)va_arg( args, int );
-                               pc += prints (fd, out, s?s:"(null)", width, pad);
-                               continue;
-                       }
-                       if( *format == 'd' ) {
-                               pc += printi (fd, out, va_arg( args, int ), 10, 1, width, pad, 'a');
-                               continue;
-                       }
-                       if( *format == 'x' ) {
-                               pc += printi (fd, out, va_arg( args, int ), 16, 0, width, pad, 'a');
-                               continue;
-                       }
-                       if( *format == 'X' ) {
-                               pc += printi (fd, out, va_arg( args, int ), 16, 0, width, pad, 'A');
-                               continue;
-                       }
-                       if( *format == 'u' ) {
-                               pc += printi (fd, out, va_arg( args, int ), 10, 0, width, pad, 'a');
-                               continue;
-                       }
-                       if( *format == 'c' ) {
-                               /* char are converted to int then pushed on the stack */
-                               scr[0] = (char)va_arg( args, int );
-                               scr[1] = '\0';
-                               pc += prints (fd, out, scr, width, pad);
-                               continue;
-                       }
-               }
-               else {
-               out:
-                       printchar (fd, out, *format);
-                       ++pc;
-               }
-       }
-       if (out) **out = '\0';
-       va_end( args );
-       return pc;
-}
-
-
-
-#if 0
-int arc_fprintf(FILE *fd, const char *format, ...);
-int arc_vfprintf(FILE *fp, const char *fmt, va_list list);
-#endif
-
-
-#if 0
-int simple_fprintf(FILE *fd, const char *format, ...)
-{
-    va_list args;
-
-    va_start( args, format );
-    return fprint( &fd, format, args );
-}
-#endif
-
-int simple_printf(const char *format, ...)
-{
-        va_list args;
-
-        va_start( args, format );
-        return print( STD_OUT, 0, format, args );
-}
-
-int simple_sprintf(char *out, const char *format, ...)
-{
-        va_list args;
-
-        va_start( args, format );
-        return print(STD_OUT, &out, format, args );
-}
-
-int standard_simple_sprintf(int fd, char *out, const char *format, ...)
-{
-        va_list args;
-
-        va_start( args, format );
-        return print(fd, &out, format, args );
-}
-
-#ifdef TEST_PRINTF
-int main(void)
-{
-       char *ptr = "Hello world!";
-       char *np = 0;
-       int i = 5;
-       unsigned int bs = sizeof(int)*8;
-       int mi;
-       char buf[80];
-
-       mi = (1 << (bs-1)) + 1;
-dbg_printf("%s\n", ptr);
-dbg_printf("printf test\n");
-dbg_printf("%s is null pointer\n", np);
-dbg_printf("%d = 5\n", i);
-dbg_printf("%d = - max int\n", mi);
-dbg_printf("char %c = 'a'\n", 'a');
-dbg_printf("hex %x = ff\n", 0xff);
-dbg_printf("hex %02x = 00\n", 0);
-dbg_printf("signed %d = unsigned %u = hex %x\n", -3, -3, -3);
-dbg_printf("%d %s(s)%", 0, "message");
-dbg_printf("\n");
-dbg_printf("%d %s(s) with %%\n", 0, "message");
-       sprintf(buf, "justif: \"%-10s\"\n", "left");dbg_printf("%s", buf);
-       sprintf(buf, "justif: \"%10s\"\n", "right");dbg_printf("%s", buf);
-       sprintf(buf, " 3: %04d zero padded\n", 3);dbg_printf("%s", buf);
-       sprintf(buf, " 3: %-4d left justif.\n", 3);dbg_printf("%s", buf);
-       sprintf(buf, " 3: %4d right justif.\n", 3);dbg_printf("%s", buf);
-       sprintf(buf, "-3: %04d zero padded\n", -3);dbg_printf("%s", buf);
-       sprintf(buf, "-3: %-4d left justif.\n", -3);dbg_printf("%s", buf);
-       sprintf(buf, "-3: %4d right justif.\n", -3);dbg_printf("%s", buf);
-
-       return 0;
-}
-
-/*
- * if you compile this file with
- *   gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -cdbg_printf.c
- * you will get a normal warning:
- *  dbg_printf.c:214: warning: spurious trailing `%' in format
- * this line is testing an invalid % at the end of the format string.
- *
- * this should display (on 32bit int machine) :
- *
- * Hello world!
- *dbg_printf test
- * (null) is null pointer
- * 5 = 5
- * -2147483647 = - max int
- * char a = 'a'
- * hex ff = ff
- * hex 00 = 00
- * signed -3 = unsigned 4294967293 = hex fffffffd
- * 0 message(s)
- * 0 message(s) with %
- * justif: "left      "
- * justif: "     right"
- *  3: 0003 zero padded
- *  3: 3    left justif.
- *  3:    3 right justif.
- * -3: -003 zero padded
- * -3: -3   left justif.
- * -3:   -3 right justif.
- */
-
-#endif
-
-
+/*\r
+ * Copyright ArcCore AB\r
+ *\r
+ * A simple implementation of all formatted xxprintf functionallity.\r
+ *\r
+ * DESIGN CRITERIA:\r
+ *  - Reentrant\r
+ *  - Use little stack\r
+ *\r
+ *  What you normally would do is to print to a buffer of some kind and then\r
+ *  call write(). However little stack indicates that we can't place buffers\r
+ *  on the stack and reentrant tells us that we can't have a static buffer.\r
+ *  That leaves us with printing characters as it is ready. From a speed\r
+ *  point of view that is less than optimal, but that the way it's got to be.\r
+ *  (Could make a 16 long char buffer??)\r
+ *\r
+ *  This is just intended to be used as a replacement for newlibs implementation.\r
+ *  Newlib porting interface have the following API:\r
+ *    int write(  int fd, char *buf, int nbytes)\r
+ *\r
+ *\r
+ *  Note that puts(), putc() are still the newlib variants....\r
+ *\r
+ *    printf()       -> vfprintf(stdout,) -> vsnprintf(buf,)\r
+ *                                           write()\r
+ *    vprintf()      -> vfprintf(stdout,) -> vsnprintf(buf,)\r
+ *                                           write()\r
+ *    sprintf(buf,)  ->                      vsnprintf(buf,)\r
+ *    snprintf(buf,) ->                      vsnprintf(buf,)\r
+ *\r
+ * IMPLEMENTATION NOTE:\r
+ *  - If printing more than the limit, e.g. using vsnprintf() then\r
+ *    the emit function will only stop printing, but not interrupted\r
+ *    (The code will get more complicated that way)\r
+ *  - ANSI-C and POSIX, streams and POSIX filenumbers.\r
+ *    POSIX file-numbers exist in unistd.h and are only to be used by the porting\r
+ *    newlib interface i.e. newlib_port.c.\r
+ *\r
+ *\r
+ * NEWLIB: File handles vs files\r
+ *   This printf() family of functions does not use newlib at all.\r
+ *   At this point the following can have happend:\r
+ *   1. A call to any of the file functions in newlib have been called.\r
+ *      This then calls a number of functions (sbrk, __sinit(_impure_ptr), etc ).\r
+ *      __sinit(_impure_ptr) initializes the standard files, stdin, stdout, stderr.\r
+ *      file->_file is the actual posix file number (stdin=0, stdout=1, stderr=2)\r
+ *   2. No calls is done to newlib file functions. The impure_data is then empty and\r
+ *      all fields are 0.\r
+ *\r
+ *  Code for checking if the newlib have initialized (or we have explicitly called __sinit(_impure_ptr)\r
+ *     if( _impure_ptr->__sdidinit == 1 ) {\r
+ *       // We use the real filenumber\r
+ *       arc_putchar((int)(file->_file), c);\r
+ *     )\r
+ *\r
+ */\r
+\r
+#include <unistd.h>\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include <assert.h>\r
+#include <string.h>\r
+#if defined(USE_NEWLIB) && defined(__GNUC__)\r
+#include "reent.h"\r
+#endif\r
+//#define HOST_TEST    1\r
+\r
+int arc_putchar(int fd, int c);\r
+int print(FILE *file, char **buffer, size_t n, const char *format, va_list ap);\r
+static inline int emitChar( FILE *file, char **buf, char c, int *left );\r
+\r
+int fputs( const char *s, FILE *file ) {\r
+       int left = ~(size_t)0;\r
+       while(*s) {\r
+               emitChar(file,NULL,*s++,&left);\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+int printf(const char *format, ...) {\r
+       va_list ap;\r
+       int rv;\r
+\r
+       va_start(ap, format);\r
+       rv = vfprintf((FILE *)STDOUT_FILENO, format, ap);\r
+       va_end(ap);\r
+       return rv;\r
+}\r
+\r
+int fprintf(FILE *file, const char *format, ...) {\r
+       va_list ap;\r
+       int rv;\r
+\r
+       va_start(ap, format);\r
+       rv = vfprintf(file, format, ap);\r
+       va_end(ap);\r
+       return rv;\r
+}\r
+\r
+int sprintf(char *buffer, const char *format, ...) {\r
+       va_list ap;\r
+       int rv;\r
+\r
+       va_start(ap, format);\r
+       rv = vsnprintf(buffer, ~(size_t)0, format, ap);\r
+       va_end(ap);\r
+\r
+       return rv;\r
+}\r
+\r
+int snprintf(char *buffer, size_t n, const char *format, ...) {\r
+       va_list ap;\r
+       int rv;\r
+\r
+       va_start(ap, format);\r
+       rv = vsnprintf(buffer, n, format, ap);\r
+       va_end(ap);\r
+       return rv;\r
+}\r
+\r
+int vprintf(const char *format, va_list ap) {\r
+       return vfprintf((FILE *)STDOUT_FILENO, format, ap);\r
+}\r
+\r
+int vsprintf(char *buffer, const char *format, va_list ap) {\r
+       return vsnprintf(buffer, ~(size_t)0, format, ap);\r
+}\r
+\r
+int vfprintf(FILE *file, const char *format, va_list ap) {\r
+       int rv;\r
+       /* Just print to stdout */\r
+       rv = print(file,NULL,~(size_t)0, format,ap);\r
+       return rv;\r
+}\r
+\r
+\r
+int vsnprintf(char *buffer, size_t n, const char *format, va_list ap) {\r
+       int rv;\r
+\r
+       rv = print(NULL, &buffer, n, format,ap);\r
+       return rv;\r
+}\r
+\r
+\r
+/*\r
+ * The integer only counterpart\r
+ */\r
+int iprintf(const char *format, ...) __attribute__ ((alias("printf")));\r
+int fiprintf(FILE *file, const char *format, ...) __attribute__ ((alias("fprintf")));\r
+int siprintf(char *buffer, const char *format, ...) __attribute__ ((alias("sprintf")));\r
+int sniprintf(char *buffer, size_t n, const char *format, ...) __attribute__ ((alias("snprintf")));\r
+int viprintf(const char *format, va_list ap) __attribute__ ((alias("vprintf")));\r
+int vsiprintf(char *buffer, const char *format, va_list ap) __attribute__ ((alias("vsprintf")));\r
+int vfiprintf(FILE *file, const char *format, va_list ap) __attribute__ ((alias("vfprintf")));\r
+\r
+/**\r
+ *\r
+ * @param file  The file to print to\r
+ * @param buf   The buffer to print to\r
+ * @param c            The char to print\r
+ * @return\r
+ */\r
+static inline int emitChar( FILE *file, char **buf, char c, int *left ) {\r
+       if( (*left) == 1 ) {\r
+               return 1;\r
+       }\r
+       --(*left);\r
+       if( buf == NULL ) {\r
+#if HOST_TEST\r
+               putc(c, stdout);\r
+               fflush(stdout);\r
+#else\r
+#if 0\r
+#if defined(USE_NEWLIB) && defined(__GNUC__)\r
+               /* We are trying to print with newlib file descriptor.\r
+                * That's wrong since we are using the POSIX file numbers here instead\r
+                * Check stdout */\r
+               assert( file != _impure_ptr->_stdout );\r
+#endif\r
+#endif\r
+               if( (unsigned )file > 10UL ) {\r
+                       arc_putchar((int)(file->_file), c);\r
+               } else {\r
+                       arc_putchar((int)(file), c);\r
+               }\r
+\r
+#endif /* HOST_TEST */\r
+       } else {\r
+               **buf = c;\r
+               (*buf)++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+#if defined(HOST_TEST)\r
+/**\r
+ * Convert a number to a string\r
+ *\r
+ * @param val          The value to convert\r
+ * @param str          Pointer to a space where to put the string\r
+ * @param base         The base\r
+ * @param negative     If negative or not.\r
+ */\r
+void xtoa( unsigned long val, char* str, int base, int negative) {\r
+       int i;\r
+       char *oStr = str;\r
+       char c;\r
+\r
+       if (negative) {\r
+               val = -val;\r
+       }\r
+\r
+       if( base < 10 && base > 16 ) {\r
+               *str = '0';\r
+               return;\r
+       }\r
+    i = 0;\r
+\r
+    do {\r
+      str[i++] = "0123456789abcdef"[ val % base ];\r
+       } while ((val /= base) > 0);\r
+\r
+\r
+    if (negative) {\r
+        str[i++] = '-';\r
+    }\r
+\r
+    str[i] = '\0';\r
+    str = &str[i]-1;\r
+    while(str > oStr) {\r
+       c = *str;\r
+       *str-- = *oStr;\r
+       *oStr++=c;\r
+    }\r
+}\r
+#else\r
+extern void xtoa( unsigned long val, char* str, int base, int negative);\r
+#endif\r
+\r
+\r
+#define FL_NONE                                        (0<<0)\r
+#define FL_ZERO                                        (1<<1)\r
+#define FL_HASH                                        (1<<2)\r
+#define FL_SPACE                               (1<<3)\r
+#define FL_ALIGN_LEFT                  (1<<4)\r
+#define FL_TYPE_SIGNED_INT             (1<<5)\r
+#define FL_TYPE_UNSIGNED_INT   (1<<6)\r
+#define FL_TYPE_POINTER                        (1<<7)\r
+\r
+static void emitString( FILE *file, char **buffer, char *string, int width, int flags, int *left) {\r
+       char pad;\r
+       char *str = string;\r
+       int i;\r
+       int strLen;\r
+       /* padding: FL_ZERO or normal ' '\r
+        * align: FL_ALIGN_LEFT (left) or normal (right)\r
+        */\r
+       pad = (flags & FL_ZERO) ? '0' : ' ';\r
+\r
+\r
+       if( flags & FL_ALIGN_LEFT ) {\r
+               for(i=0;str[i]; i++) {\r
+                       emitChar(file,buffer,str[i],left);\r
+               }\r
+\r
+               /* Pad the rest */\r
+               for(;i<width;i++) {\r
+                       emitChar(file,buffer,pad,left);\r
+               }\r
+       } else {\r
+\r
+               strLen = strlen(string);\r
+\r
+               /* Pad first  */\r
+               if( width > strLen ) {\r
+                       for(i=0;i<(width-strLen);i++) {\r
+                               emitChar(file,buffer,pad,left);\r
+                       }\r
+               }\r
+\r
+               for(i=0;i<strLen; i++) {\r
+                       emitChar(file,buffer,string[i],left);\r
+               }\r
+       }\r
+}\r
+\r
+void emitInt( FILE *file, char **buffer, int val, int base, int width, int flags, int *left )\r
+{\r
+       char lBuf[12];  // longest is base 10, 2^32\r
+       char *str = lBuf;\r
+\r
+       if( flags & FL_TYPE_SIGNED_INT ) {\r
+               xtoa(val,str,base ,(val < 0));\r
+       } else {\r
+               xtoa((unsigned)val,str,base ,0);\r
+       }\r
+\r
+       emitString(file,buffer,str,width,flags,left);\r
+}\r
+\r
+#define PRINT_CHAR(_c)  *buffer++= (_c);\r
+\r
+\r
+/**\r
+ * Write formatted output to an array with a maximum number of characters.\r
+ *\r
+ * This is the mother of the formatted print family. The main goal here\r
+ * is to be very small and memory efficient.\r
+ *\r
+ * Support:\r
+ *   Parameter: None\r
+ *   Flags    : '-' and '0'\r
+ *   Width    : Normal padding is supported, '*' is not.\r
+ *   Precision: None\r
+ *   Length   : None\r
+ *   C99      : None\r
+ *   Type     : d,u,x,s,and c\r
+ *\r
+ * @param file    The file descriptor\r
+ * @param buffer  A pointer to the place to store the output\r
+ *                If NULL the output is instead\r
+ * @param n       The maximum number of characters to write\r
+ * @param format  The format string\r
+ * @param ap      The va list\r
+ * @return\r
+ */\r
+int print(FILE *file, char **buffer, size_t n, const char *format, va_list ap)\r
+{\r
+       char ch;\r
+       int flags;\r
+       char *str;\r
+       int width;\r
+       int left = n;\r
+\r
+       while ( (ch = *format++) ) {\r
+\r
+               if (ch == '%') {\r
+                       ch = *format++;\r
+\r
+                       if( ch == '%') {\r
+                               emitChar(file,buffer,ch,&left);\r
+                               continue;\r
+                       }\r
+\r
+                       /* Find flags */\r
+                       if (ch == '0')\r
+                       {\r
+                               flags = FL_ZERO;\r
+                       }\r
+                       else if (ch == ' ')\r
+                       {\r
+                               flags = FL_SPACE;\r
+                       }\r
+                       else if (ch == '-')\r
+                       {\r
+                               flags = FL_ALIGN_LEFT;\r
+                       }\r
+                       else\r
+                       {\r
+                               /* Not supported or no flag */\r
+                               flags = FL_NONE;\r
+                               format--;\r
+                       }\r
+\r
+                       ch = *format++;\r
+\r
+                       /* Width */\r
+                       if( (ch >= '0')  && (ch <= '9') ) {\r
+                               width = ch -'0';\r
+                               ch = *format++;\r
+                       } else {\r
+                               width = 0;\r
+                       }\r
+\r
+                       /* Find type */\r
+                       if (ch =='c')\r
+                       {\r
+                               emitChar(file,buffer,(char )va_arg( ap, int ),&left);\r
+                       }\r
+                       else if (ch == 'd')\r
+                       {\r
+                               flags |= FL_TYPE_SIGNED_INT;\r
+                               emitInt(file,buffer,va_arg( ap, int ),10,width,flags,&left);\r
+                       }\r
+                       else if (ch == 'u')\r
+                       {\r
+                               flags |= FL_TYPE_UNSIGNED_INT;\r
+                               emitInt(file,buffer,va_arg( ap, int ),10,width,flags,&left);\r
+                       }\r
+                       else if (ch == 'x')\r
+                       {\r
+                               flags |= FL_TYPE_UNSIGNED_INT;\r
+                               emitInt(file,buffer,va_arg( ap, int ),16,width,flags,&left);\r
+                       }\r
+                       else if (ch == 'p')\r
+                       {\r
+                               flags |= FL_TYPE_POINTER;\r
+                               emitInt(file,buffer,va_arg( ap, int ),16,width,flags,&left);\r
+                       }\r
+                       else if (ch == 's')\r
+                       {\r
+                               str = (char *)va_arg( ap, int );\r
+\r
+                               if( str == NULL ) {\r
+                                       str = "(null)";\r
+                               }\r
+\r
+                               emitString(file,buffer,str,width,flags,&left);\r
+                       }\r
+                       else\r
+                       {\r
+                               assert(0); // oops\r
+                       }\r
+               } else {\r
+                       flags = FL_NONE;\r
+                       emitChar(file,buffer,ch,&left);\r
+               }\r
+       }\r
+//     va_end(ap);             // Removed, TODO: Check the va_start/va_end handling (used in calling functions also).\r
+       if(buffer!=0) {\r
+               left = 0;\r
+               emitChar(file,buffer,'\0',&left);\r
+       }\r
+       return 0; // Wrong.. but for now.\r
+}\r
+\r
+#if 0\r
+int main(void) {\r
+       char *ptr = NULL;\r
+       char buff[30];\r
+\r
+       printf("char: %c %c = a B\n", 'a', 66);\r
+\r
+       printf("string: %s = (null)\n", (char *)ptr);\r
+\r
+       printf("string: %s = foobar \n", "foobar");\r
+\r
+       printf("string: %2s = foobar \n", "foobar");\r
+       printf("string: \"%8s\" = \"  foobar\" \n", "foobar");\r
+       /* Left justify */\r
+       printf("string: \"%-8s\" = \"foobar  \" \n", "foobar");\r
+\r
+       printf("decimal:  23 = %d \n", 23);\r
+       printf("hex:     c23 = %x \n", 0xc23);\r
+       printf("hex:    0c23 = %04x \n", 0xc23);\r
+       printf("decimal with blanks:     23 = %6d  \n", 23);\r
+       printf("decimal with zero:   000023 = %06d \n", 23);\r
+\r
+       /* negative and large numbers */\r
+       printf("decimal:  -23 = %d \n", -23);\r
+       printf("decimal:  4294967273 = %u \n", -23);\r
+       printf("decimal:  c0000000   = %x \n", 0xc0000000);\r
+\r
+       printf("decimal:  00c000   = %06x \n", 0xc000);\r
+\r
+       fprintf(stdout, "string: %s = foobar \n", "foobar");\r
+       sprintf(buff, "string: %s = foobar \n", "foobar");\r
+       printf("%s",buff);\r
+\r
+       snprintf(buff,10, "%s\n", "12345678901234567");\r
+       printf("\"123456789\" = \"%s\"\n",buff);\r
+\r
+       snprintf(buff,12, "%s\n", "abcdefghijklmn");\r
+       printf("\"abcdefghijkl\" = \"%s\"\n",buff);\r
+\r
+       return 0;\r
+}\r
+#endif\r
+\r
+\r