00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 #include <stdarg.h>
00057 #include <lib/string.h>
00058 
00059 
00060 #define is_digit(c)     ((c) >= '0' && (c) <= '9')
00061 
00062 static int skip_atoi(const char **s)
00063 {
00064         int i=0;
00065 
00066         while (is_digit(**s))
00067                 i = i*10 + *((*s)++) - '0';
00068         return i;
00069 }
00070 
00071 #define ZEROPAD 1               
00072 #define SIGN    2               
00073 #define PLUS    4               
00074 #define SPACE   8               
00075 #define LEFT    16              
00076 #define SPECIAL 32              
00077 #define SMALL   64              
00078 
00079 #define do_div(n,base) ({ \
00080 int __res; \
00081 __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
00082 __res; })
00083 
00084 static char * number(char * str, int num, int base, int size, int precision
00085         ,int type)
00086 {
00087         char c,sign,tmp[36];
00088         const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00089         int i;
00090 
00091         if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
00092         if (type&LEFT) type &= ~ZEROPAD;
00093         if (base<2 || base>36)
00094                 return 0;
00095         c = (type & ZEROPAD) ? '0' : ' ' ;
00096         if (type&SIGN && num<0) {
00097                 sign='-';
00098                 num = -num;
00099         } else
00100                 sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
00101         if (sign) size--;
00102         if (type&SPECIAL) {
00103           if (base==16) { size -= 2; }
00104                 else if (base==8) { size--; }
00105           }
00106         i=0;
00107         if (num==0)
00108                 tmp[i++]='0';
00109         else while (num!=0)
00110                 tmp[i++]=digits[do_div(num,base)];
00111         if (i>precision) precision=i;
00112         size -= precision;
00113         if (!(type&(ZEROPAD+LEFT)))
00114                 while(size-->0)
00115                         *str++ = ' ';
00116         if (sign)
00117                 *str++ = sign;
00118         if (type&SPECIAL) {
00119           if (base==8) {
00120             *str++ = '0';
00121             }
00122           else if (base==16) {
00123                 *str++ = '0';
00124                 *str++ = digits[33];
00125                 }
00126           }
00127         if (!(type&LEFT))
00128                 while(size-->0)
00129                         *str++ = c;
00130         while(i<precision--)
00131                 *str++ = '0';
00132         while(i-->0)
00133                 *str++ = tmp[i];
00134         while(size-->0)
00135                 *str++ = ' ';
00136         return str;
00137 }
00138 
00139 int vsprintf(char *buf, const char *fmt, vaList args)
00140 {
00141         int len;
00142         int i;
00143         char * str;
00144         char *s;
00145         int *ip;
00146 
00147         int flags;              
00148 
00149         int field_width;        
00150         int precision;          
00151 
00152         int qualifier;          
00153 
00154         for (str=buf ; *fmt ; ++fmt) {
00155                 if (*fmt != '%') {
00156                         *str++ = *fmt;
00157                         continue;
00158                 }
00159                         
00160                 
00161                 flags = 0;
00162                 repeat:
00163                         ++fmt;          
00164                         switch (*fmt) {
00165                                 case '-': flags |= LEFT; goto repeat;
00166                                 case '+': flags |= PLUS; goto repeat;
00167                                 case ' ': flags |= SPACE; goto repeat;
00168                                 case '#': flags |= SPECIAL; goto repeat;
00169                                 case '0': flags |= ZEROPAD; goto repeat;
00170                                 }
00171                 
00172                 
00173                 field_width = -1;
00174                 if (is_digit(*fmt))
00175                         field_width = skip_atoi(&fmt);
00176                 else if (*fmt == '*') {
00177                         
00178                         field_width = vaArg(args, int);
00179                         if (field_width < 0) {
00180                                 field_width = -field_width;
00181                                 flags |= LEFT;
00182                         }
00183                 }
00184 
00185                 
00186                 precision = -1;
00187                 if (*fmt == '.') {
00188                         ++fmt;  
00189                         if (is_digit(*fmt))
00190                                 precision = skip_atoi(&fmt);
00191                         else if (*fmt == '*') {
00192                                 
00193                                 precision = vaArg(args, int);
00194                         }
00195                         if (precision < 0)
00196                                 precision = 0;
00197                 }
00198 
00199                 
00200                 qualifier = -1;
00201                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
00202                         qualifier = *fmt;
00203                         ++fmt;
00204                 }
00205 
00206                 switch (*fmt) {
00207                 case 'c':
00208                         if (!(flags & LEFT))
00209                                 while (--field_width > 0)
00210                                         *str++ = ' ';
00211                         *str++ = (unsigned char) vaArg(args, int);
00212                         while (--field_width > 0)
00213                                 *str++ = ' ';
00214                         break;
00215 
00216                 case 's':
00217                         s = vaArg(args, char *);
00218                         len = strlen(s);
00219                         if (precision < 0)
00220                                 precision = len;
00221                         else if (len > precision)
00222                                 len = precision;
00223 
00224                         if (!(flags & LEFT))
00225                                 while (len < field_width--)
00226                                         *str++ = ' ';
00227                         for (i = 0; i < len; ++i)
00228                                 *str++ = *s++;
00229                         while (len < field_width--)
00230                                 *str++ = ' ';
00231                         break;
00232 
00233                 case 'o':
00234                         str = number(str, vaArg(args, unsigned long), 8,
00235                                 field_width, precision, flags);
00236                         break;
00237 
00238                 case 'p':
00239                         if (field_width == -1) {
00240                                 field_width = 8;
00241                                 flags |= ZEROPAD;
00242                         }
00243                         str = number(str,
00244                                 (unsigned long) vaArg(args, void *), 16,
00245                                 field_width, precision, flags);
00246                         break;
00247 
00248                 case 'x':
00249                         flags |= SMALL;
00250                 case 'X':
00251                         str = number(str, vaArg(args, unsigned long), 16,
00252                                 field_width, precision, flags);
00253                         break;
00254 
00255                 case 'd':
00256                 case 'i':
00257                         flags |= SIGN;
00258                 case 'u':
00259                         str = number(str, vaArg(args, unsigned long), 10,
00260                                 field_width, precision, flags);
00261                         break;
00262 
00263                 case 'n':
00264                         ip = vaArg(args, int *);
00265                         *ip = (str - buf);
00266                         break;
00267 
00268                 default:
00269                         if (*fmt != '%')
00270                                 *str++ = '%';
00271                         if (*fmt)
00272                                 *str++ = *fmt;
00273                         else
00274                                 --fmt;
00275                         break;
00276                 }
00277         }
00278         *str = '\0';
00279         return str-buf;
00280 }
00281 
00282 
00283 
00284 
00285