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