Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

rprintf.c

Go to the documentation of this file.
00001 /*! \file rprintf.c \brief printf routine and associated routines. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'rprintf.c'
00005 // Title        : printf routine and associated routines
00006 // Author       : Pascal Stang - Copyright (C) 2000-2002
00007 // Created      : 2000.12.26
00008 // Revised      : 2003.5.1
00009 // Version      : 1.0
00010 // Target MCU   : Atmel AVR series and other targets
00011 // Editor Tabs  : 4
00012 //
00013 // NOTE: This code is currently below version 1.0, and therefore is considered
00014 // to be lacking in some functionality or documentation, or may not be fully
00015 // tested.  Nonetheless, you can expect most functions to work.
00016 //
00017 // This code is distributed under the GNU Public License
00018 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00019 //
00020 //*****************************************************************************
00021 
00022 //#include <avr/pgmspace.h>
00023 //#include <string-avr.h>
00024 //#include <stdlib.h>
00025 #include <stdarg.h>
00026 //#include "global.h"
00027 #include "rprintf.h"
00028 
00029 #ifndef TRUE
00030     #define TRUE    -1
00031     #define FALSE   0
00032 #endif
00033 
00034 #define INF     32766   // maximum field size to print
00035 #define READMEMBYTE(a,char_ptr) ((a)?(*char_ptr):(*char_ptr))
00036 
00037 #ifdef RPRINTF_COMPLEX
00038     static unsigned char buf[128];
00039 #endif
00040 
00041 // hex conversion table
00042 static const char HexChars[] = "0123456789ABCDEF";
00043 #define hexchar(x)  HexChars[(x)&0x0F]
00044 //#define hexchar(x)    ((((x)&0x0F)>9)?((x)+'A'-10):((x)+'0'))
00045 
00046 // function pointer to single character output routine
00047 static void (*rputchar)(unsigned char c);
00048 
00049 // *** rprintf initialization ***
00050 // you must call this function once and supply the character output
00051 // routine before using other functions in this library
00052 void rprintfInit(void (*putchar_func)(unsigned char c))
00053 {
00054     rputchar = putchar_func;
00055 }
00056 
00057 // *** rprintfChar ***
00058 // send a character/byte to the current output device
00059 void rprintfChar(unsigned char c)
00060 {
00061     // do LF -> CR/LF translation
00062     if(c == '\n')
00063         rputchar('\r');
00064     // send character
00065     rputchar(c);
00066 }
00067 
00068 // *** rprintfStr ***
00069 // prints a null-terminated string stored in RAM
00070 void rprintfStr(char str[])
00071 {
00072     // send a string stored in RAM
00073     // check to make sure we have a good pointer
00074     if (!str) return;
00075 
00076     // print the string until a null-terminator
00077     while (*str)
00078         rprintfChar(*str++);
00079 }
00080 
00081 // *** rprintfStrLen ***
00082 // prints a section of a string stored in RAM
00083 // begins printing at position indicated by <start>
00084 // prints number of characters indicated by <len>
00085 void rprintfStrLen(char str[], unsigned char start, unsigned char len)
00086 {
00087     register char i=0;
00088 
00089     // check to make sure we have a good pointer
00090     if (!str) return;
00091     // spin through characters up to requested start
00092     // keep going as long as there's no null
00093     while((i++<start) && (*str++));
00094 
00095     // then print exactly len characters
00096     for(i=0; i<len; i++)
00097     {
00098         // print data out of the string as long as we haven't reached a null yet
00099         // at the null, start printing spaces
00100         if(*str)
00101             rprintfChar(*str++);
00102         else
00103             rprintfChar(' ');
00104     }
00105 
00106 }
00107 
00108 // *** rprintfCRLF ***
00109 // prints carriage return and line feed
00110 void rprintfCRLF(void)
00111 {
00112     // print CR/LF
00113     rprintfChar('\r');
00114     rprintfChar('\n');
00115 }
00116 
00117 // *** rprintfu04 ***
00118 // prints an unsigned 4-bit number in hex (1 digit)
00119 void rprintfu04(unsigned char data)
00120 {
00121     // print 4-bit hex value
00122     rprintfChar( hexchar(data) );
00123 }
00124 
00125 // *** rprintfu08 ***
00126 // prints an unsigned 8-bit number in hex (2 digits)
00127 void rprintfu08(unsigned char data)
00128 {
00129     // print 8-bit hex value
00130     rprintfu04(data>>4);
00131     rprintfu04(data);
00132 }
00133 
00134 // *** rprintfu16 ***
00135 // prints an unsigned 16-bit number in hex (4 digits)
00136 void rprintfu16(unsigned short data)
00137 {
00138     // print 16-bit hex value
00139     rprintfu08(data>>8);
00140     rprintfu08(data);
00141 }
00142 
00143 // *** rprintfu32 ***
00144 // prints an unsigned 32-bit number in hex (8 digits)
00145 void rprintfu32(unsigned long data)
00146 {
00147     // print 32-bit hex value
00148     rprintfu16(data>>16);
00149     rprintfu16(data);
00150 }
00151 
00152 // *** rprintfNum ***
00153 // special printf for numbers only
00154 // see formatting information below
00155 //  Print the number "n" in the given "base"
00156 //  using exactly "numDigits"
00157 //  print +/- if signed flag "isSigned" is TRUE
00158 //  use the character specified in "padchar" to pad extra characters
00159 //
00160 //  Examples:
00161 //  uartPrintfNum(10, 6,  TRUE, ' ',   1234);  -->  " +1234"
00162 //  uartPrintfNum(10, 6, FALSE, '0',   1234);  -->  "001234"
00163 //  uartPrintfNum(16, 6, FALSE, '.', 0x5AA5);  -->  "..5AA5"
00164 void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n)
00165 {
00166     // define a global HexChars or use line below
00167     //static char HexChars[16] = "0123456789ABCDEF";
00168     char *p, buf[32];
00169     unsigned long x;
00170     unsigned char count;
00171 
00172     // prepare negative number
00173     if( isSigned && (n < 0) )
00174     {
00175         x = -n;
00176     }
00177     else
00178     {
00179         x = n;
00180     }
00181 
00182     // setup little string buffer
00183     count = (numDigits-1)-(isSigned?1:0);
00184     p = buf + sizeof (buf);
00185     *--p = '\0';
00186     
00187     // force calculation of first digit
00188     // (to prevent zero from not printing at all!!!)
00189     *--p = hexchar(x%base); x /= base;
00190     // calculate remaining digits
00191     while(count--)
00192     {
00193         if(x != 0)
00194         {
00195             // calculate next digit
00196             *--p = hexchar(x%base); x /= base;
00197         }
00198         else
00199         {
00200             // no more digits left, pad out to desired length
00201             *--p = padchar;
00202         }
00203     }
00204 
00205     // apply signed notation if requested
00206     if( isSigned )
00207     {
00208         if(n < 0)
00209         {
00210             *--p = '-';
00211         }
00212         else if(n > 0)
00213         {
00214             *--p = '+';
00215         }
00216         else
00217         {
00218             *--p = ' ';
00219         }
00220     }
00221 
00222     // print the string right-justified
00223     count = numDigits;
00224     while(count--)
00225     {
00226         rprintfChar(*p++);
00227     }
00228 }
00229 
00230 #ifdef RPRINTF_FLOAT
00231 // *** rprintfFloat ***
00232 // floating-point print
00233 void rprintfFloat(char numDigits, double x)
00234 {
00235     unsigned char firstplace = FALSE;
00236     unsigned char negative;
00237     unsigned char i, digit;
00238     double place = 1.0;
00239     
00240     // save sign
00241     negative = (x<0);
00242     // convert to absolute value
00243     x = (x>0)?(x):(-x);
00244     
00245     // find starting digit place
00246     for(i=0; i<15; i++)
00247     {
00248         if((x/place) < 10.0)
00249             break;
00250         else
00251             place *= 10.0;
00252     }
00253     // print polarity character
00254     if(negative)
00255         rprintfChar('-');
00256     else
00257         rprintfChar('+');
00258 
00259     // print digits
00260     for(i=0; i<numDigits; i++)
00261     {
00262         digit = (x/place);
00263 
00264         if(digit | firstplace | (place == 1.0))
00265         {
00266             firstplace = TRUE;
00267             rprintfChar(digit+0x30);
00268         }
00269         else
00270             rprintfChar(' ');
00271         
00272         if(place == 1.0)
00273         {
00274             rprintfChar('.');
00275         }
00276         
00277         x -= (digit*place);
00278         place /= 10.0;
00279     }
00280 }
00281 #endif
00282 
00283 #ifdef RPRINTF_SIMPLE
00284 // *** rprintf1RamRom ***
00285 //! called by rprintf() - does a simple printf (supports %d, %x, %c)
00286 // Supports:
00287 // %d - decimal
00288 // %x - hex
00289 // %c - character
00290 int rprintf1RamRom(unsigned char stringInRom, const char *format, ...)
00291 {
00292     // simple printf routine
00293     // define a global HexChars or use line below
00294     //static char HexChars[16] = "0123456789ABCDEF";
00295     char format_flag;
00296     unsigned int u_val, div_val, base;
00297     va_list ap;
00298 
00299     va_start(ap, format);
00300     for (;;)
00301     {
00302         while ((format_flag = READMEMBYTE(stringInRom,format++) ) != '%')
00303         {   // Until '%' or '\0'
00304             if (!format_flag)
00305             {
00306                 va_end(ap);
00307                 return(0);
00308             }
00309             rprintfChar(format_flag);
00310         }
00311 
00312         switch (format_flag = READMEMBYTE(stringInRom,format++) )
00313         {
00314             case 'c': format_flag = va_arg(ap,int);
00315             default:  rprintfChar(format_flag); continue;
00316             case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP;
00317             case 'x': base = 16; div_val = 0x1000;
00318 
00319             CONVERSION_LOOP:
00320             u_val = va_arg(ap,int);
00321             if (format_flag == 'd')
00322             {
00323                 if (((int)u_val) < 0)
00324                 {
00325                     u_val = - u_val;
00326                     rprintfChar('-');
00327                 }
00328                 while (div_val > 1 && div_val > u_val) div_val /= 10;
00329             }
00330             do
00331             {
00332                 //rprintfChar( hexchar(u_val/div_val) );
00333                 rprintfu04(u_val/div_val);
00334                 u_val %= div_val;
00335                 div_val /= base;
00336             } while (div_val);
00337         }
00338     }
00339     va_end(ap);
00340 }
00341 #endif
00342 
00343 
00344 #ifdef RPRINTF_COMPLEX
00345 // *** rprintf2RamRom ***
00346 //! called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s)
00347 // Supports:
00348 // %d - decimal
00349 // %u - unsigned decimal
00350 // %o - octal
00351 // %x - hex
00352 // %c - character
00353 // %s - strings
00354 // and the width,precision,padding modifiers
00355 // **this printf does not support floating point numbers
00356 int rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...)
00357 {
00358     register unsigned char *f, *bp;
00359     register long l;
00360     register unsigned long u;
00361     register int i;
00362     register int fmt;
00363     register unsigned char pad = ' ';
00364     int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00365     int sign = 0;
00366 
00367     va_list ap;
00368     va_start(ap, sfmt);
00369 
00370     f = (unsigned char *) sfmt;
00371 
00372     for (; READMEMBYTE(stringInRom,f); f++)
00373     {
00374         if (READMEMBYTE(stringInRom,f) != '%')
00375         {   // not a format character
00376             // then just output the char
00377             rprintfChar(READMEMBYTE(stringInRom,f));
00378         }
00379         else 
00380         {
00381             f++;                        // if we have a "%" then skip it
00382             if (READMEMBYTE(stringInRom,f) == '-')
00383             {
00384                 flush_left = 1; // minus: flush left
00385                 f++;
00386             }
00387             if (READMEMBYTE(stringInRom,f) == '0'
00388                  || READMEMBYTE(stringInRom,f) == '.')
00389                 {
00390                     // padding with 0 rather than blank
00391                     pad = '0';
00392                     f++;
00393             }
00394             if (READMEMBYTE(stringInRom,f) == '*')
00395                 {   // field width
00396                     f_width = va_arg(ap, int);
00397                     f++;
00398             }
00399             else if (Isdigit(READMEMBYTE(stringInRom,f)))
00400                 {
00401                     f_width = atoiRamRom(stringInRom, (char *) f);
00402                     while (Isdigit(READMEMBYTE(stringInRom,f)))
00403                         f++;        // skip the digits
00404             }
00405             if (READMEMBYTE(stringInRom,f) == '.')
00406                 {   // precision
00407                     f++;
00408                     if (READMEMBYTE(stringInRom,f) == '*')
00409                     {
00410                         prec = va_arg(ap, int);
00411                         f++;
00412                     }
00413                     else if (Isdigit(READMEMBYTE(stringInRom,f)))
00414                     {
00415                         prec = atoiRamRom(stringInRom, (char *) f);
00416                         while (Isdigit(READMEMBYTE(stringInRom,f)))
00417                             f++;    // skip the digits
00418                     }
00419                 }
00420             if (READMEMBYTE(stringInRom,f) == '#')
00421                 {   // alternate form
00422                     hash = 1;
00423                     f++;
00424             }
00425             if (READMEMBYTE(stringInRom,f) == 'l')
00426                 {   // long format
00427                     do_long = 1;
00428                     f++;
00429             }
00430 
00431                 fmt = READMEMBYTE(stringInRom,f);
00432                 bp = buf;
00433                 switch (fmt) {      // do the formatting
00434                 case 'd':           // 'd' signed decimal
00435                     if (do_long)
00436                         l = va_arg(ap, long);
00437                     else
00438                         l = (long) (va_arg(ap, int));
00439                     if (l < 0)
00440                     {
00441                         sign = 1;
00442                         l = -l;
00443                     }
00444                     do  {
00445                         *bp++ = l % 10 + '0';
00446                     } while ((l /= 10) > 0);
00447                     if (sign)
00448                         *bp++ = '-';
00449                     f_width = f_width - (bp - buf);
00450                     if (!flush_left)
00451                         while (f_width-- > 0)
00452                             rprintfChar(pad);
00453                     for (bp--; bp >= buf; bp--)
00454                         rprintfChar(*bp);
00455                     if (flush_left)
00456                         while (f_width-- > 0)
00457                             rprintfChar(' ');
00458                     break;
00459             case 'o':           // 'o' octal number
00460             case 'x':           // 'x' hex number
00461             case 'u':           // 'u' unsigned decimal
00462                     if (do_long)
00463                         u = va_arg(ap, unsigned long);
00464                     else
00465                         u = (unsigned long) (va_arg(ap, unsigned));
00466                     if (fmt == 'u')
00467                     {   // unsigned decimal
00468                         do {
00469                             *bp++ = u % 10 + '0';
00470                         } while ((u /= 10) > 0);
00471                     }
00472                     else if (fmt == 'o')
00473                     {  // octal
00474                         do {
00475                             *bp++ = u % 8 + '0';
00476                         } while ((u /= 8) > 0);
00477                         if (hash)
00478                             *bp++ = '0';
00479                     }
00480                     else if (fmt == 'x')
00481                     {   // hex
00482                         do {
00483                             i = u % 16;
00484                             if (i < 10)
00485                                 *bp++ = i + '0';
00486                             else
00487                                 *bp++ = i - 10 + 'a';
00488                         } while ((u /= 16) > 0);
00489                         if (hash)
00490                         {
00491                             *bp++ = 'x';
00492                             *bp++ = '0';
00493                         }
00494                     }
00495                     i = f_width - (bp - buf);
00496                     if (!flush_left)
00497                         while (i-- > 0)
00498                             rprintfChar(pad);
00499                     for (bp--; bp >= buf; bp--)
00500                         rprintfChar((int) (*bp));
00501                     if (flush_left)
00502                         while (i-- > 0)
00503                             rprintfChar(' ');
00504                     break;
00505             case 'c':           // 'c' character
00506                     i = va_arg(ap, int);
00507                     rprintfChar((int) (i));
00508                     break;
00509             case 's':           // 's' string
00510                     bp = va_arg(ap, unsigned char *);
00511                     if (!bp)
00512                         bp = (unsigned char *) "(nil)";
00513                     f_width = f_width - strlen((char *) bp);
00514                     if (!flush_left)
00515                         while (f_width-- > 0)
00516                             rprintfChar(pad);
00517                     for (i = 0; *bp && i < prec; i++)
00518                     {
00519                         rprintfChar(*bp);
00520                         bp++;
00521                     }
00522                     if (flush_left)
00523                         while (f_width-- > 0)
00524                             rprintfChar(' ');
00525                     break;
00526             case '%':           // '%' character
00527                     rprintfChar('%');
00528                     break;
00529             }
00530             flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00531             sign = 0;
00532             pad = ' ';
00533         }
00534     }
00535 
00536     va_end(ap);
00537     return 0;
00538 }
00539 
00540 unsigned char Isdigit(char c)
00541 {
00542     if((c >= 0x30) && (c <= 0x39))
00543         return TRUE;
00544     else
00545         return FALSE;
00546 }
00547 
00548 int atoiRamRom(unsigned char stringInRom, char *str)
00549 {
00550     int num = 0;;
00551 
00552     while(Isdigit(READMEMBYTE(stringInRom,str)))
00553     {
00554         num *= 10;
00555         num += ((READMEMBYTE(stringInRom,str++)) - 0x30);
00556     }
00557     return num;
00558 }
00559 
00560 #endif
00561 
00562 //******************************************************************************
00563 // code below this line is commented out and can be ignored
00564 //******************************************************************************
00565 /*
00566 char* sprintf(const char *sfmt, ...)
00567 {
00568     register unsigned char *f, *bp, *str;
00569     register long l;
00570     register unsigned long u;
00571     register int i;
00572     register int fmt;
00573     register unsigned char pad = ' ';
00574     int     flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00575     int     sign = 0;
00576 
00577     va_list ap;
00578     va_start(ap, sfmt);
00579 
00580     str = bufstring;
00581     f = (unsigned char *) sfmt;
00582 
00583     for (; *f; f++)
00584     {
00585         if (*f != '%')
00586         {                               // not a format character
00587             *str++ = (*f);          // then just output the char
00588         }
00589         else 
00590         {
00591             f++;                        // if we have a "%" then skip it
00592             if (*f == '-')
00593             {
00594                 flush_left = 1; // minus: flush left
00595                 f++;
00596             }
00597             if (*f == '0' || *f == '.')
00598                 {
00599                     // padding with 0 rather than blank
00600                     pad = '0';
00601                     f++;
00602             }
00603             if (*f == '*')
00604                 {   // field width
00605                     f_width = va_arg(ap, int);
00606                     f++;
00607             }
00608             else if (Isdigit(*f))
00609                 {
00610                     f_width = atoi((char *) f);
00611                     while (Isdigit(*f))
00612                         f++;        // skip the digits
00613             }
00614             if (*f == '.')
00615                 {   // precision
00616                     f++;
00617                     if (*f == '*')
00618                     {
00619                         prec = va_arg(ap, int);
00620                         f++;
00621                     }
00622                     else if (Isdigit(*f))
00623                     {
00624                         prec = atoi((char *) f);
00625                         while (Isdigit(*f))
00626                             f++;    // skip the digits
00627                     }
00628                 }
00629             if (*f == '#')
00630                 {   // alternate form
00631                     hash = 1;
00632                     f++;
00633             }
00634             if (*f == 'l')
00635                 {   // long format
00636                     do_long = 1;
00637                     f++;
00638             }
00639 
00640                 fmt = *f;
00641                 bp = buf;
00642                 switch (fmt) {      // do the formatting
00643                 case 'd':           // 'd' signed decimal
00644                     if (do_long)
00645                         l = va_arg(ap, long);
00646                     else
00647                         l = (long) (va_arg(ap, int));
00648                     if (l < 0)
00649                     {
00650                         sign = 1;
00651                         l = -l;
00652                     }
00653                     do  {
00654                         *bp++ = l % 10 + '0';
00655                     } while ((l /= 10) > 0);
00656                     if (sign)
00657                         *bp++ = '-';
00658                     f_width = f_width - (bp - buf);
00659                     if (!flush_left)
00660                         while (f_width-- > 0)
00661                             *str++ = (pad);
00662                     for (bp--; bp >= buf; bp--)
00663                         *str++ = (*bp);
00664                     if (flush_left)
00665                         while (f_width-- > 0)
00666                             *str++ = (' ');
00667                     break;
00668             case 'o':           // 'o' octal number
00669             case 'x':           // 'x' hex number
00670             case 'u':           // 'u' unsigned decimal
00671                     if (do_long)
00672                         u = va_arg(ap, unsigned long);
00673                     else
00674                         u = (unsigned long) (va_arg(ap, unsigned));
00675                     if (fmt == 'u')
00676                     {   // unsigned decimal
00677                         do {
00678                             *bp++ = u % 10 + '0';
00679                         } while ((u /= 10) > 0);
00680                     }
00681                     else if (fmt == 'o')
00682                     {  // octal
00683                         do {
00684                             *bp++ = u % 8 + '0';
00685                         } while ((u /= 8) > 0);
00686                         if (hash)
00687                             *bp++ = '0';
00688                     }
00689                     else if (fmt == 'x')
00690                     {   // hex
00691                         do {
00692                             i = u % 16;
00693                             if (i < 10)
00694                                 *bp++ = i + '0';
00695                             else
00696                                 *bp++ = i - 10 + 'a';
00697                         } while ((u /= 16) > 0);
00698                         if (hash)
00699                         {
00700                             *bp++ = 'x';
00701                             *bp++ = '0';
00702                         }
00703                     }
00704                     i = f_width - (bp - buf);
00705                     if (!flush_left)
00706                         while (i-- > 0)
00707                             *str++ = (pad);
00708                     for (bp--; bp >= buf; bp--)
00709                         *str++ = ((int) (*bp));
00710                     if (flush_left)
00711                         while (i-- > 0)
00712                             *str++ = (' ');
00713                     break;
00714             case 'c':           // 'c' character
00715                     i = va_arg(ap, int);
00716                     *str++ = ((int) (i));
00717                     break;
00718             case 's':           // 's' string
00719                     bp = va_arg(ap, unsigned char *);
00720                     if (!bp)
00721                         bp = (unsigned char *) "(nil)";
00722                     f_width = f_width - strlen((char *) bp);
00723                     if (!flush_left)
00724                         while (f_width-- > 0)
00725                             *str++ = (pad);
00726                     for (i = 0; *bp && i < prec; i++)
00727                     {
00728                         *str++ = (*bp);
00729                         bp++;
00730                     }
00731                     if (flush_left)
00732                         while (f_width-- > 0)
00733                             *str++ = (' ');
00734                     break;
00735             case '%':           // '%' character
00736                     *str++ = ('%');
00737                     break;
00738             }
00739             flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
00740             sign = 0;
00741             pad = ' ';
00742         }
00743     }
00744 
00745     va_end(ap);
00746     // terminate string with null
00747     *str++ = '\0';
00748     return bufstring;
00749 }
00750 
00751 */

Generated on Mon Nov 6 23:36:59 2006 for Procyon ARMlib by  doxygen 1.4.2