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