rprintf.c

00001 //#########################################################################
00002 // printf.c
00003 //
00004 // *** printf() based on sprintf() from gcctest9.c Volker Oth
00005 //
00006 // *** Changes made by Holger Klabunde
00007 // Now takes format strings from FLASH (was into RAM ! before)
00008 // Fixed bug for %i, %I. u_val was used before it had the right value
00009 // Added %d, %D (is same as %i, %I)
00010 // Support for long variables %li, %ld, %Lu, %LX ....
00011 // %x, %X now gives upper case hex characters A,B,C,D,E,F
00012 // Output can be redirected in a single function: myputchar()
00013 // Make printf() smaller by commenting out a few #defines
00014 // Added some SPACE and ZERO padding %02x or % 3u up to 9 characters
00015 // 
00016 // Todo:
00017 // %f, %F for floating point numbers
00018 //
00019 // *** Changes made by Martin Thomas for the efsl debug output:
00020 // - removed AVR "progmem"
00021 // - added function pointer for "putchar"
00022 // - devopen function
00023 //
00024 //#########################################################################
00025 
00026 #include <stdarg.h>
00027 #include <string.h>
00028 #include "rprintf.h"
00029 
00030 #define SCRATCH 12        //32Bits go up to 4GB + 1 Byte for \0
00031 
00032 //Spare some program space by making a comment of all not used format flag lines
00033 #define USE_LONG         // %lx, %Lu and so on, else only 16 bit integer is allowed
00034 //#define USE_OCTAL        // %o, %O Octal output. Who needs this ?
00035 #define USE_STRING      // %s, %S Strings as parameters
00036 #define USE_CHAR        // %c, %C Chars as parameters
00037 #define USE_INTEGER        // %i, %I Remove this format flag. %d, %D does the same
00038 #define USE_HEX                // %x, %X Hexadezimal output
00039 #define USE_UPPERHEX        // %x, %X outputs A,B,C... else a,b,c...
00040 #ifndef USE_HEX
00041  #undef USE_UPPERHEX    // ;)
00042 #endif
00043 #define USE_UPPER        // uncommenting this removes %C,%D,%I,%O,%S,%U,%X and %L..
00044                         // only lowercase format flags are used
00045 #define PADDING         //SPACE and ZERO padding
00046 
00047 
00048 static int (*putcharfunc)(int c);
00049 
00050 void rprintf_devopen( int(*put)(int) )
00051 {
00052    putcharfunc = put;
00053 }
00054 
00055 static void myputchar(unsigned char c)
00056 {
00057         if(c == '\n') putcharfunc('\r');
00058         putcharfunc(c);
00059 }
00060 
00061 void rprintf(char const *format, ...)
00062 {
00063   unsigned char scratch[SCRATCH];
00064   unsigned char format_flag;
00065   unsigned short base;
00066   unsigned char *ptr;
00067   unsigned char issigned=0;
00068   va_list ap;
00069 
00070 #ifdef USE_LONG
00071 // #warning "use long"
00072   unsigned char islong=0;
00073   unsigned long u_val=0;
00074   long s_val=0;
00075 #else
00076   unsigned int u_val=0;
00077   int s_val=0;
00078 #endif
00079 
00080   unsigned char fill;
00081   unsigned char width;
00082 
00083   va_start (ap, format);
00084   for (;;){
00085     while ((format_flag = *(format++)) != '%'){      // Until '%' or '\0' 
00086       if (!format_flag){va_end (ap); return;}
00087       myputchar(format_flag);
00088     }
00089 
00090     issigned=0; //default unsigned
00091     base = 10;
00092 
00093     format_flag = *format++; //get char after '%'
00094 
00095 #ifdef PADDING
00096     width=0; //no formatting
00097     fill=0;  //no formatting
00098     if(format_flag=='0' || format_flag==' ') //SPACE or ZERO padding  ?
00099      {
00100       fill=format_flag;
00101       format_flag = *format++; //get char after padding char
00102       if(format_flag>='0' && format_flag<='9')
00103        {
00104         width=format_flag-'0';
00105         format_flag = *format++; //get char after width char
00106        }
00107      }
00108 #endif
00109 
00110 #ifdef USE_LONG
00111     islong=0; //default int value
00112 #ifdef USE_UPPER
00113     if(format_flag=='l' || format_flag=='L') //Long value 
00114 #else
00115     if(format_flag=='l') //Long value 
00116 #endif
00117      {
00118       islong=1;
00119       format_flag = *format++; //get char after 'l' or 'L'
00120      }
00121 #endif
00122 
00123     switch (format_flag)
00124     {
00125 #ifdef USE_CHAR
00126     case 'c':
00127 #ifdef USE_UPPER
00128     case 'C':
00129 #endif
00130       format_flag = va_arg(ap,int);
00131       // no break -> run into default
00132 #endif
00133 
00134     default:
00135       myputchar(format_flag);
00136       continue;
00137 
00138 #ifdef USE_STRING
00139 #ifdef USE_UPPER
00140     case 'S':
00141 #endif
00142     case 's':
00143       ptr = (unsigned char*)va_arg(ap,char *);
00144       while(*ptr) { myputchar(*ptr); ptr++; }
00145       continue;
00146 #endif
00147 
00148 #ifdef USE_OCTAL
00149     case 'o':
00150 #ifdef USE_UPPER
00151     case 'O':
00152 #endif
00153       base = 8;
00154       myputchar('0');
00155       goto CONVERSION_LOOP;
00156 #endif
00157 
00158 #ifdef USE_INTEGER //don't use %i, is same as %d
00159     case 'i':
00160 #ifdef USE_UPPER
00161     case 'I':
00162 #endif
00163 #endif
00164     case 'd':
00165 #ifdef USE_UPPER
00166     case 'D':
00167 #endif
00168       issigned=1;
00169       // no break -> run into next case
00170     case 'u':
00171 #ifdef USE_UPPER
00172     case 'U':
00173 #endif
00174 
00175 //don't insert some case below this if USE_HEX is undefined !
00176 //or put       goto CONVERSION_LOOP;  before next case.
00177 #ifdef USE_HEX
00178       goto CONVERSION_LOOP;
00179     case 'x':
00180 #ifdef USE_UPPER
00181     case 'X':
00182 #endif
00183       base = 16;
00184 #endif
00185 
00186     CONVERSION_LOOP:
00187 
00188       if(issigned) //Signed types
00189        {
00190 #ifdef USE_LONG
00191         if(islong) { s_val = va_arg(ap,long); }
00192         else { s_val = va_arg(ap,int); }
00193 #else
00194         s_val = va_arg(ap,int);
00195 #endif
00196 
00197         if(s_val < 0) //Value negativ ?
00198          {
00199           s_val = - s_val; //Make it positiv
00200           myputchar('-');    //Output sign
00201          }
00202 
00203         u_val = (unsigned long)s_val;
00204        }
00205       else //Unsigned types
00206        {
00207 #ifdef USE_LONG
00208         if(islong) { u_val = va_arg(ap,unsigned long); }
00209         else { u_val = va_arg(ap,unsigned int); }
00210 #else
00211         u_val = va_arg(ap,unsigned int);
00212 #endif
00213        }
00214     
00215       ptr = scratch + SCRATCH;
00216       *--ptr = 0;
00217       do
00218        {
00219         char ch = u_val % base + '0';
00220 #ifdef USE_HEX
00221         if (ch > '9')
00222          {
00223           ch += 'a' - '9' - 1;
00224 #ifdef USE_UPPERHEX
00225           ch-=0x20;
00226 #endif
00227          }
00228 #endif          
00229         *--ptr = ch;
00230         u_val /= base;
00231 
00232 #ifdef PADDING
00233         if(width) width--; //calculate number of padding chars
00234 #endif
00235       } while (u_val);
00236 
00237 #ifdef PADDING
00238      while(width--) *--ptr = fill; //insert padding chars                      
00239 #endif
00240 
00241       while(*ptr) { myputchar(*ptr); ptr++; }
00242     }
00243   }
00244 }
Generated on Sun May 8 08:41:17 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3