����8-10 linux/kernel/vsprintf.c


  1 /*

  2  *  linux/kernel/vsprintf.c

  3  *

  4  *  (C) 1991  Linus Torvalds

  5  */

  6

  7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */

  8 /*

  9  * Wirzenius wrote this portably, Torvalds fucked it up :-)

 10  */

    // Lars Wirzenius��Linus�ĺ��ѣ���Helsinki��ѧʱ��ͬ��һ��칫�ҡ���1991���ļ�����Linux

    // ʱ��Linus��ʱ��C���Ի����Ǻ���Ϥ��������ʹ�ÿɱ�����б��������ܡ����Lars Wirzenius

    // ��Ϊ����д����������ں���ʾ��Ϣ�Ĵ��롣������(1998��)��������δ�������һ��bug��ֱ��

    // 1994������˷��֣������Ծ��������bug����ʹ��*��Ϊ��������ʱ�����ǵ���ָ�����������

    // ���ˡ��ڱ����������bug����Ȼ���ڣ�130�У��� ���ĸ�����ҳ��http://liw.iki.fi/liw/

 11

 12 #include <stdarg.h>       // ��׼����ͷ�ļ����Ժ����ʽ������������б�����Ҫ˵����-��

                              // ����(va_list)��������(va_start, va_arg��va_end)������

                              // vsprintf��vprintf��vfprintf������

 13 #include <string.h>       // �ַ���ͷ�ļ�����Ҫ������һЩ�й��ַ���������Ƕ�뺯����

 14

 15 /* we use this so that we can do without the ctype library */

    /* ����ʹ������Ķ��壬�������ǾͿ��Բ�ʹ��ctype���� */

 16 #define is_digit(c)     ((c) >= '0' && (c) <= '9')   // �ж��ַ�c�Ƿ�Ϊ�����ַ���

 17

    // �ú������ַ����ִ�ת�������������������ִ�ָ���ָ�룬�����ǽ����ֵ������ָ�뽫ǰ�ơ�

 18 static int skip_atoi(const char **s)

 19 {

 20         int i=0;

 21

 22         while (is_digit(**s))

 23                 i = i*10 + *((*s)++) - '0';

 24         return i;

 25 }

 26

    // ���ﶨ��ת�����͵ĸ��ַ��ų�����

 27 #define ZEROPAD 1               /* pad with zero */        /* ����� */

 28 #define SIGN    2               /* unsigned/signed long */ /* �޷���/���ų����� */

 29 #define PLUS    4               /* show plus */            /* ��ʾ�� */

 30 #define SPACE   8               /* space if plus */        /* ���Ǽӣ����ÿո� */

 31 #define LEFT    16              /* left justified */      /* ����� */

 32 #define SPECIAL 32              /* 0x */                  /* 0x */

 33 #define SMALL   64              /* use 'abcdef' instead of 'ABCDEF' */ /* ʹ��Сд��ĸ */

 34

    // �����������룺nΪ��������baseΪ�����������nΪ�̣���������ֵΪ������

    // �μ�4.5.3���й�Ƕ�������Ϣ��

 35 #define do_div(n,base) ({ \

 36 int __res; \

 37 __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \

 38 __res; })

 39

    // ������ת��Ϊָ�����Ƶ��ַ�����

    // ���룺num-������base-���ƣ�size-�ַ������ȣ�precision-���ֳ���(����)��type-����ѡ�

    // ���������ת�����ַ�����ָ����ַ���ĩ�˺����ָ�롣

 40 static char * number(char * str, int num, int base, int size, int precision

 41         ,int type)

 42 {

 43         char c,sign,tmp[36];

 44         const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

 45         int i;

 46

    // �������typeָ����Сд��ĸ������Сд��ĸ����

    // �������ָ��Ҫ�����������߽磩�������������е������־��

    // ������ƻ���С��2�����36�����˳�������Ҳ��������ֻ�ܴ���������2-32֮�������

 47         if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";

 48         if (type&LEFT) type &= ~ZEROPAD;

 49         if (base<2 || base>36)

 50                 return 0;

    // �������ָ��Ҫ���㣬�����ַ�����c='0'������c���ڿո��ַ���

    // �������ָ���Ǵ�������������ֵnumС��0�����÷��ű���sign=���ţ���ʹnumȡ����ֵ��

    // �����������ָ���ǼӺţ�����sign=�Ӻţ����������ʹ��ո��־��sign=�ո񣬷�����0��

 51         c = (type & ZEROPAD) ? '0' : ' ' ;

 52         if (type&SIGN && num<0) {

 53                 sign='-';

 54                 num = -num;

 55         } else

 56                 sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);

    // �������ţ������ֵ��1��������ָ��������ת���������ʮ�����ƿ����ټ���2λ(����0x)��

    // ���ڰ˽��ƿ��ȼ�1�����ڰ˽���ת�����ǰ��һ���㣩��

 57         if (sign) size--;

 58         if (type&SPECIAL)

 59                 if (base==16) size -= 2;

 60                 else if (base==8) size--;

    // �����ֵnumΪ0������ʱ�ַ���='0'��������ݸ����Ļ�������ֵnumת�����ַ���ʽ��

 61         i=0;

 62         if (num==0)

 63                 tmp[i++]='0';

 64         else while (num!=0)

 65                 tmp[i++]=digits[do_div(num,base)];

    // ����ֵ�ַ��������ھ���ֵ���򾫶�ֵ��չΪ���ָ���ֵ��

    // ����ֵsize��ȥ���ڴ����ֵ�ַ��ĸ�����

 66         if (i>precision) precision=i;

 67         size -= precision;

 

    // ������������ʼ�γ�����Ҫ��ת�����������ʱ�����ַ���str�С�

    // ��������û������(ZEROPAD)�����루���������־������str������

    // ���ʣ�����ֵָ���Ŀո��������������λ���������š�

 68         if (!(type&(ZEROPAD+LEFT)))

 69                 while(size-->0)

 70                         *str++ = ' ';

 71         if (sign)

 72                 *str++ = sign;

    // ������ָ��������ת��������ڰ˽���ת�����ͷһλ����һ��'0'��������ʮ����������'0x'��

 73         if (type&SPECIAL)

 74                 if (base==8)

 75                         *str++ = '0';

 76                 else if (base==16) {

 77                         *str++ = '0';

 78                         *str++ = digits[33];   // 'X'��'x'

 79                 }

    // ��������û������������룩��־������ʣ������д��c�ַ���'0'��ո񣩣���51�С�

 80         if (!(type&LEFT))

 81                 while(size-->0)

 82                         *str++ = c;

    // ��ʱi������ֵnum�����ָ����������ָ���С�ھ���ֵ����str�з��루����ֵ-i����'0'��

 83         while(i<precision--)

 84                 *str++ = '0';

    // ����ֵת���õ������ַ�����str�С���i����

 85         while(i-->0)

 86                 *str++ = tmp[i];

    // ������ֵ�Դ����㣬���ʾ���ͱ�־���������־������ʣ������з���ո�

 87         while(size-->0)

 88                 *str++ = ' ';

 89         return str;    // ����ת���õ�ָ���ַ���ĩ�˺��ָ�롣

 90 }

 91

    // ���溯�����͸�ʽ��������ַ����С�

    // Ϊ�������ں���ʹ�ø�ʽ���������Linus���ں�ʵ���˸�C��׼������

    // ���в���fmt�Ǹ�ʽ�ַ�����args�Ǹ����仯��ֵ��buf������ַ�����������

    // ��μ��������б�����йظ�ʽת���ַ��Ľ��ܡ�

 92 int vsprintf(char *buf, const char *fmt, va_list args)

 93 {

 94         int len;

 95         int i;

 96         char * str;            // ���ڴ��ת�������е��ַ�����

 97         char *s;

 98         int *ip;

 99

100         int flags;              /* flags to number() */

101                                 /* number()����ʹ�õı�־ */

102         int field_width;        /* width of output field */

                                    /* ����ֶο���*/

103         int precision;          /* min. # of digits for integers; max

104                                    number of chars for from string */

                                    /* min. �������ָ�����max. �ַ������ַ����� */

105         int qualifier;          /* 'h', 'l', or 'L' for integer fields */

106                                 /* 'h', 'l',��'L'���������ֶ� */

    // ���Ƚ��ַ�ָ��ָ��buf��Ȼ��ɨ���ʽ�ַ������Ը�����ʽת��ָʾ������Ӧ�Ĵ�����

107         for (str=buf ; *fmt ; ++fmt) {

    // ��ʽת��ָʾ�ַ�������'%'��ʼ�������fmt��ʽ�ַ�����ɨ��'%'��Ѱ�Ҹ�ʽת���ַ����Ŀ�ʼ��

    // ���Ǹ�ʽָʾ��һ���ַ��������δ���str��

108                 if (*fmt != '%') {

109                         *str++ = *fmt;

110                         continue;

111                 }

112                        

    // ����ȡ�ø�ʽָʾ�ַ����еı�־�򣬲�����־��������flags�����С�

113                 /* process flags */

114                 flags = 0;

115                 repeat:

116                         ++fmt;          /* this also skips first '%' */

117                         switch (*fmt) {

118                                 case '-': flags |= LEFT; goto repeat;    // ���������

119                                 case '+': flags |= PLUS; goto repeat;    // �żӺš�

120                                 case ' ': flags |= SPACE; goto repeat;   // �ſո�

121                                 case '#': flags |= SPECIAL; goto repeat; // ������ת����

122                                 case '': flags |= ZEROPAD; goto repeat;  // Ҫ����(��'0')��

123                                 }

124                

    // ȡ��ǰ�����ֶο�����ֵ������field_width�����С����������������ֵ��ֱ��ȡ��Ϊ����ֵ��

    // ��������������ַ�'*'����ʾ��һ������ָ�����ȡ���˵���va_argȡ����ֵ������ʱ����ֵ

    // С��0����ø�����ʾ����б�־��'-'��־�����룩����˻����ڱ�־����������ñ�־����

    // ���ֶο���ֵȡΪ�����ֵ��

125                 /* get field width */

126                 field_width = -1;

127                 if (is_digit(*fmt))

128                         field_width = skip_atoi(&fmt);

129                 else if (*fmt == '*') {

130                         /* it's the next argument */     // �����и�bug��Ӧ����++fmt;

131                         field_width = va_arg(args, int);

132                         if (field_width < 0) {

133                                 field_width = -field_width;

134                                 flags |= LEFT;

135                         }

136                 }

137

    // ������δ��룬ȡ��ʽת�����ľ����򣬲�����precision�����С�������ʼ�ı�־��'.'��

    // �䴦���������������������ơ����������������ֵ��ֱ��ȡ��Ϊ����ֵ���������������

    // �ַ�'*'����ʾ��һ������ָ�����ȡ���˵���va_argȡ����ֵ������ʱ����ֵС��0����

    // �ֶξ���ֵȡΪ0��

138                 /* get the precision */

139                 precision = -1;

140                 if (*fmt == '.') {

141                         ++fmt; 

142                         if (is_digit(*fmt))

143                                 precision = skip_atoi(&fmt);

144                         else if (*fmt == '*') {

145                                 /* it's the next argument */   // ͬ������ҲӦ����++fmt;

146                                 precision = va_arg(args, int);

147                         }

148                         if (precision < 0)

149                                 precision = 0;

150                 }

151

    // ������δ�������������η������������qualifer��������h,l,L�ĺ���μ��б����˵������

152                 /* get the conversion qualifier */

153                 qualifier = -1;

154                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {

155                         qualifier = *fmt;

156                         ++fmt;

157                 }

158

    // �������ת��ָʾ����

159                 switch (*fmt) {

    // ���ת��ָʾ����'c'�����ʾ��Ӧ����Ӧ���ַ�����ʱ�����־������������룬����ֶ�ǰ��

    // ����'������ֵ-1'���ո��ַ���Ȼ���ٷ�������ַ�����������򻹴���0�����ʾΪ���룬����

    // �����ַ���������'����ֵ-1'���ո��ַ���

160                 case 'c':

161                         if (!(flags & LEFT))

162                                 while (--field_width > 0)

163                                         *str++ = ' ';

164                         *str++ = (unsigned char) va_arg(args, int);

165                         while (--field_width > 0)

166                                 *str++ = ' ';

167                         break;

168

    // ���ת��ָʾ����'s'�����ʾ��Ӧ�������ַ���������ȡ�����ַ����ij��ȣ����䳬���˾�����ֵ��

    // ����չ������=�ַ������ȡ���ʱ�����־������������룬����ֶ�ǰ����'����ֵ-�ַ�������'

    // ���ո��ַ���Ȼ���ٷ�������ַ�������������򻹴���0�����ʾΪ���룬���ڲ����ַ�������

    // ����'����ֵ-�ַ�������'���ո��ַ���

169                 case 's':

170                         s = va_arg(args, char *);

171                         len = strlen(s);

172                         if (precision < 0)

173                                 precision = len;

174                         else if (len > precision)

175                                 len = precision;

176

177                         if (!(flags & LEFT))

178                                 while (len < field_width--)

179                                         *str++ = ' ';

180                         for (i = 0; i < len; ++i)

181                                 *str++ = *s++;

182                         while (len < field_width--)

183                                 *str++ = ' ';

184                         break;

185

    // �����ʽת������'o'����ʾ�轫��Ӧ�IJ���ת���ɰ˽��������ַ���������number()����������

186                 case 'o':

187                         str = number(str, va_arg(args, unsigned long), 8,

188                                 field_width, precision, flags);

189                         break;

190

    // �����ʽת������'p'����ʾ��Ӧ������һ��ָ�����͡���ʱ���ò���û�����ÿ�������Ĭ�Ͽ���

    // Ϊ8��������Ҫ���㡣Ȼ�����number()�������д�����

191                 case 'p':

192                         if (field_width == -1) {

193                                 field_width = 8;

194                                 flags |= ZEROPAD;

195                         }

196                         str = number(str,

197                                 (unsigned long) va_arg(args, void *), 16,

198                                 field_width, precision, flags);

199                         break;

200

    // ����ʽת��ָʾ��'x'��'X'�����ʾ��Ӧ������Ҫ��ӡ��ʮ�������������'x'��ʾ��Сд��ĸ��ʾ��

201                 case 'x':

202                         flags |= SMALL;

203                 case 'X':

204                         str = number(str, va_arg(args, unsigned long), 16,

205                                 field_width, precision, flags);

206                         break;

207

    // �����ʽת���ַ���'d','i'��'u'�����ʾ��Ӧ������������'d', 'i'�������������������Ҫ����

    // �����ű�־��'u'�����޷���������

208                 case 'd':

209                 case 'i':

210                         flags |= SIGN;

211                 case 'u':

212                         str = number(str, va_arg(args, unsigned long), 10,

213                                 field_width, precision, flags);

214                         break;

215

    // ����ʽת��ָʾ����'n'�����ʾҪ�ѵ�ĿǰΪֹת������ַ������浽��Ӧ����ָ��ָ����λ���С�

    // ��������va_arg()ȡ�øò���ָ�룬Ȼ���Ѿ�ת���õ��ַ��������ָ����ָ��λ�á�

216                 case 'n':

217                         ip = va_arg(args, int *);

218                         *ip = (str - buf);

219                         break;

220

    // ����ʽת��������'%'�����ʾ��ʽ�ַ����д���ֱ�ӽ�һ��'%'д��������С�

    // �����ʽת������λ�ô������ַ�����Ҳֱ�ӽ����ַ�д��������У������ص�107�м�������

    // ��ʽ�ַ����������ʾ�Ѿ���������ʽ�ַ����Ľ�β�������˳�ѭ����

221                 default:

222                         if (*fmt != '%')

223                                 *str++ = '%';

224                         if (*fmt)

225                                 *str++ = *fmt;

226                         else

227                                 --fmt;

228                         break;

229                 }

230         }

231         *str = '\0';         // �����ת���õ��ַ�����β������null��

232         return str-buf;      // ����ת���õ��ַ�������ֵ��

233 }

234