# vsprintf.c

Go to the documentation of this file.

    00001 /*****************************************************************************************
    00002  Copyright (c) 2002 The UbixOS Project
    00003  All rights reserved.
    00004
    00005 Redistribution and use in source and binary forms, with or without modification, are
    00006 permitted provided that the following conditions are met:
    00007
    00008 Redistributions of source code must retain the above copyright notice, this list of
    00009 conditions, the following disclaimer and the list of authors.  Redistributions in binary
    00010 form must reproduce the above copyright notice, this list of conditions, the following
    00011 disclaimer and the list of authors in the documentation and/or other materials provided
    00012 with the distribution. Neither the name of the UbixOS Project nor the names of its
    00013 contributors may be used to endorse or promote products derived from this software
    00014 without specific prior written permission.
    00015
    00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
    00017 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00018 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    00019 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    00020 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    00021 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    00022 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
    00023 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00024 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00025
    00026  $Log: vsprintf_8c-source.html,v $
    00026  Revision 1.7  2006/12/15 17:47:08  reddawg
    00026  Updates
    00026
    00027  Revision 1.1.1.1  2006/06/01 12:46:16  reddawg
    00028  ubix2
    00029
    00030  Revision 1.2  2005/10/12 00:13:37  reddawg
    00031  Removed
    00032
    00033  Revision 1.1.1.1  2005/09/26 17:24:14  reddawg
    00034  no message
    00035
    00036  Revision 1.2  2004/06/28 23:12:58  reddawg
    00037  file format now container:/path/to/file
    00038
    00039  Revision 1.1.1.1  2004/04/15 12:07:11  reddawg
    00040  UbixOS v1.0
    00041
    00042  Revision 1.3  2004/04/13 16:36:33  reddawg
    00043  Changed our copyright, it is all now under a BSD-Style license
    00044
    00045
    00046
    00047  $Id: vsprintf_8c-source.html 88 2016-01-12 00:11:29Z reddawg $
    00048
    00049 *****************************************************************************************/
    00050
    00051 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
    00052 /*
    00053  * Wirzenius wrote this portably, Torvalds fucked it up :-)
    00054  */
    00055
    00056 #include <stdarg.h>
    00057 #include <lib/string.h>
    00058
    00059 /* we use this so that we can do without the ctype library */
    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               /* pad with zero */
    00072 #define SIGN    2               /* unsigned/signed long */
    00073 #define PLUS    4               /* show plus */
    00074 #define SPACE   8               /* space if plus */
    00075 #define LEFT    16              /* left justified */
    00076 #define SPECIAL 32              /* 0x */
    00077 #define SMALL   64              /* use 'abcdef' instead of 'ABCDEF' */
    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;              /* flags to number() */
    00148
    00149         int field_width;        /* width of output field */
    00150         int precision;          /* min. # of digits for integers; max
    00151                                    number of chars for from string */
    00152         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
    00153
    00154         for (str=buf ; *fmt ; ++fmt) {
    00155                 if (*fmt != '%') {
    00156                         *str++ = *fmt;
    00157                         continue;
    00158                 }
    00159
    00160                 /* process flags */
    00161                 flags = 0;
    00162                 repeat:
    00163                         ++fmt;          /* this also skips first '%' */
    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                 /* get field width */
    00173                 field_width = -1;
    00174                 if (is_digit(*fmt))
    00175                         field_width = skip_atoi(&fmt);
    00176                 else if (*fmt == '*') {
    00177                         /* it's the next argument */
    00178                         field_width = vaArg(args, int);
    00179                         if (field_width < 0) {
    00180                                 field_width = -field_width;
    00181                                 flags |= LEFT;
    00182                         }
    00183                 }
    00184
    00185                 /* get the precision */
    00186                 precision = -1;
    00187                 if (*fmt == '.') {
    00188                         ++fmt;
    00189                         if (is_digit(*fmt))
    00190                                 precision = skip_atoi(&fmt);
    00191                         else if (*fmt == '*') {
    00192                                 /* it's the next argument */
    00193                                 precision = vaArg(args, int);
    00194                         }
    00195                         if (precision < 0)
    00196                                 precision = 0;
    00197                 }
    00198
    00199                 /* get the conversion qualifier */
    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  END
    00284  ***/
    00285