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 }