ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

streamout.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       GNU GPL, see COPYING in the top level directory
00003  * PROJECT:         ReactOS crt library
00004  * FILE:            lib/sdk/crt/printf/streamout.c
00005  * PURPOSE:         Implementation of streamout
00006  * PROGRAMMER:      Timo Kreuzer
00007  */
00008 
00009 #include <stdio.h>
00010 #include <stdarg.h>
00011 #include <tchar.h>
00012 #include <strings.h>
00013 #include <math.h>
00014 #include <float.h>
00015 
00016 #ifdef _UNICODE
00017 # define streamout wstreamout
00018 # define format_float format_floatw
00019 #endif
00020 
00021 #define MB_CUR_MAX 10
00022 #define BUFFER_SIZE (32 + 17)
00023 
00024 int mbtowc(wchar_t *wchar, const char *mbchar, size_t count);
00025 int wctomb(char *mbchar, wchar_t wchar);
00026 
00027 typedef struct _STRING
00028 {
00029   unsigned short Length;
00030   unsigned short MaximumLength;
00031   void *Buffer;
00032 } STRING;
00033 
00034 enum
00035 {
00036     /* Formatting flags */
00037     FLAG_ALIGN_LEFT =    0x01,
00038     FLAG_FORCE_SIGN =    0x02,
00039     FLAG_FORCE_SIGNSP =  0x04,
00040     FLAG_PAD_ZERO =      0x08,
00041     FLAG_SPECIAL =       0x10,
00042 
00043     /* Data format flags */
00044     FLAG_SHORT =         0x100,
00045     FLAG_LONG =          0x200,
00046     FLAG_WIDECHAR =      FLAG_LONG,
00047     FLAG_INT64 =         0x400,
00048 #ifdef _WIN64
00049     FLAG_INTPTR =        FLAG_INT64,
00050 #else
00051     FLAG_INTPTR =        0,
00052 #endif
00053     FLAG_LONGDOUBLE =    0x800,
00054 };
00055 
00056 #define va_arg_f(argptr, flags) \
00057     (flags & FLAG_INT64) ? va_arg(argptr, __int64) : \
00058     (flags & FLAG_SHORT) ? (short)va_arg(argptr, int) : \
00059     va_arg(argptr, int)
00060 
00061 #define va_arg_fu(argptr, flags) \
00062     (flags & FLAG_INT64) ? va_arg(argptr, unsigned __int64) : \
00063     (flags & FLAG_SHORT) ? (unsigned short)va_arg(argptr, int) : \
00064     va_arg(argptr, unsigned int)
00065 
00066 #define va_arg_ffp(argptr, flags) \
00067     (flags & FLAG_LONGDOUBLE) ? va_arg(argptr, long double) : \
00068     va_arg(argptr, double)
00069 
00070 #define get_exp(f) (int)floor(f == 0 ? 0 : (f >= 0 ? log10(f) : log10(-f)))
00071 #define round(x) floor((x) + 0.5)
00072 
00073 #ifndef _USER32_WSPRINTF
00074 
00075 void
00076 #ifdef _LIBCNT_
00077 /* Due to restrictions in kernel mode regarding the use of floating point,
00078    we prevent it from being inlined */
00079 __declspec(noinline)
00080 #endif
00081 format_float(
00082     TCHAR chr,
00083     unsigned int flags,
00084     int precision,
00085     TCHAR **string,
00086     const TCHAR **prefix,
00087     va_list *argptr)
00088 {
00089     static const TCHAR digits_l[] = _T("0123456789abcdef0x");
00090     static const TCHAR digits_u[] = _T("0123456789ABCDEF0X");
00091     static const TCHAR _nan[] = _T("#QNAN");
00092     static const TCHAR _infinity[] = _T("#INF");
00093     const TCHAR *digits = digits_l;
00094     int exponent = 0, sign;
00095     long double fpval, fpval2;
00096     int padding = 0, num_digits, val32, base = 10;
00097 
00098     /* Normalize the precision */
00099     if (precision < 0) precision = 6;
00100     else if (precision > 17)
00101     {
00102         padding = precision - 17;
00103         precision = 17;
00104     }
00105 
00106     /* Get the float value and calculate the exponent */
00107     fpval = va_arg_ffp(*argptr, flags);
00108     exponent = get_exp(fpval);
00109     sign = fpval < 0 ? -1 : 1;
00110 
00111     switch (chr)
00112     {
00113         case _T('G'):
00114             digits = digits_u;
00115         case _T('g'):
00116             if (precision > 0) precision--;
00117             if (exponent < -4 || exponent >= precision) goto case_e;
00118 
00119             /* Shift the decimal point and round */
00120             fpval2 = round(sign * fpval * pow(10., precision));
00121 
00122             /* Skip trailing zeroes */
00123             while (precision && (unsigned __int64)fpval2 % 10 == 0)
00124             {
00125                 precision--;
00126                 fpval2 /= 10;
00127             }
00128             break;
00129 
00130         case _T('E'):
00131             digits = digits_u;
00132         case _T('e'):
00133         case_e:
00134             /* Shift the decimal point and round */
00135             fpval2 = round(sign * fpval * pow(10., precision - exponent));
00136 
00137             /* Compensate for changed exponent through rounding */
00138             if (fpval2 >= (unsigned __int64)pow(10., precision + 1))
00139             {
00140                 exponent++;
00141                 fpval2 = round(sign * fpval * pow(10., precision - exponent));
00142             }
00143 
00144             val32 = exponent >= 0 ? exponent : -exponent;
00145 
00146             // FIXME: handle length of exponent field:
00147             // http://msdn.microsoft.com/de-de/library/0fatw238%28VS.80%29.aspx
00148             num_digits = 3;
00149             while (num_digits--)
00150             {
00151                 *--(*string) = digits[val32 % 10];
00152                 val32 /= 10;
00153             }
00154 
00155             /* Sign for the exponent */
00156             *--(*string) = exponent >= 0 ? _T('+') : _T('-');
00157 
00158             /* Add 'e' or 'E' separator */
00159             *--(*string) = digits[0xe];
00160             break;
00161 
00162         case _T('A'):
00163             digits = digits_u;
00164         case _T('a'):
00165 //            base = 16;
00166             // FIXME: TODO
00167 
00168         case _T('f'):
00169         default:
00170             /* Shift the decimal point and round */
00171             fpval2 = round(sign * fpval * pow(10., precision));
00172             break;
00173     }
00174 
00175     /* Handle sign */
00176     if (fpval < 0)
00177     {
00178         *prefix = _T("-");
00179     }
00180     else if (flags & FLAG_FORCE_SIGN)
00181         *prefix = _T("+");
00182     else if (flags & FLAG_FORCE_SIGNSP)
00183         *prefix = _T(" ");
00184 
00185     /* Handle special cases first */
00186     if (_isnan(fpval))
00187     {
00188         (*string) -= sizeof(_nan) / sizeof(TCHAR) - 1;
00189         _tcscpy((*string), _nan);
00190         fpval2 = 1;
00191     }
00192     else if (!_finite(fpval))
00193     {
00194         (*string) -= sizeof(_infinity) / sizeof(TCHAR) - 1;
00195         _tcscpy((*string), _infinity);
00196         fpval2 = 1;
00197     }
00198     else
00199     {
00200         /* Zero padding */
00201         while (padding-- > 0) *--(*string) = _T('0');
00202 
00203         /* Digits after the decimal point */
00204         num_digits = precision;
00205         while (num_digits-- > 0)
00206         {
00207             *--(*string) = digits[(unsigned __int64)fpval2 % 10];
00208             fpval2 /= base;
00209         }
00210     }
00211 
00212     if (precision > 0 || flags & FLAG_SPECIAL)
00213         *--(*string) = _T('.');
00214 
00215     /* Digits before the decimal point */
00216     do
00217     {
00218         *--(*string) = digits[(unsigned __int64)fpval2 % base];
00219         fpval2 /= base;
00220     }
00221     while ((unsigned __int64)fpval2);
00222 
00223 }
00224 #endif
00225 
00226 static
00227 int
00228 streamout_char(FILE *stream, int chr)
00229 {
00230 #if defined(_USER32_WSPRINTF) || defined(_LIBCNT_)
00231     /* Check if the buffer is full */
00232     if (stream->_cnt < sizeof(TCHAR))
00233         return 0;
00234 
00235     *(TCHAR*)stream->_ptr = chr;
00236     stream->_ptr += sizeof(TCHAR);
00237     stream->_cnt -= sizeof(TCHAR);
00238 
00239     return 1;
00240 #else
00241     return _fputtc((TCHAR)chr, stream) != _TEOF;
00242 #endif
00243 }
00244 
00245 static
00246 int
00247 streamout_astring(FILE *stream, const char *string, size_t count)
00248 {
00249     TCHAR chr;
00250     int written = 0;
00251 
00252     while (count--)
00253     {
00254 #ifdef _UNICODE
00255         int len;
00256         if ((len = mbtowc(&chr, string, MB_CUR_MAX)) < 1) break;
00257         string += len;
00258 #else
00259         chr = *string++;
00260 #endif
00261         if (streamout_char(stream, chr) == 0) return -1;
00262         written++;
00263     }
00264 
00265     return written;
00266 }
00267 
00268 static
00269 int
00270 streamout_wstring(FILE *stream, const wchar_t *string, size_t count)
00271 {
00272     wchar_t chr;
00273     int written = 0;
00274 
00275     while (count--)
00276     {
00277 #ifndef _UNICODE
00278         char mbchar[MB_CUR_MAX], *ptr = mbchar;
00279         int mblen;
00280 
00281         mblen = wctomb(mbchar, *string++);
00282         if (mblen <= 0) return written;
00283 
00284         while (chr = *ptr++, mblen--)
00285 #else
00286         chr = *string++;
00287 #endif
00288         {
00289             if (streamout_char(stream, chr) == 0) return -1;
00290             written++;
00291         }
00292     }
00293 
00294     return written;
00295 }
00296 
00297 #ifdef _UNICODE
00298 #define streamout_string streamout_wstring
00299 #else
00300 #define streamout_string streamout_astring
00301 #endif
00302 
00303 #ifdef _USER32_WSPRINTF
00304 # define USE_MULTISIZE 0
00305 #else
00306 # define USE_MULTISIZE 1
00307 #endif
00308 
00309 int
00310 _cdecl
00311 streamout(FILE *stream, const TCHAR *format, va_list argptr)
00312 {
00313     static const TCHAR digits_l[] = _T("0123456789abcdef0x");
00314     static const TCHAR digits_u[] = _T("0123456789ABCDEF0X");
00315     static const char *_nullstring = "(null)";
00316     TCHAR buffer[BUFFER_SIZE + 1];
00317     TCHAR chr, *string;
00318     STRING *nt_string;
00319     const TCHAR *digits, *prefix;
00320     int base, fieldwidth, precision, padding;
00321     size_t prefixlen, len;
00322     int written = 1, written_all = 0;
00323     unsigned int flags;
00324     unsigned __int64 val64;
00325 
00326     buffer[BUFFER_SIZE] = '\0';
00327 
00328     while (written >= 0)
00329     {
00330         chr = *format++;
00331 
00332         /* Check for end of format string */
00333         if (chr == _T('\0')) break;
00334 
00335         /* Check for 'normal' character or double % */
00336         if ((chr != _T('%')) ||
00337             (chr = *format++) == _T('%'))
00338         {
00339             /* Write the character to the stream */
00340             if ((written = streamout_char(stream, chr)) == 0) return -1;
00341             written_all += written;
00342             continue;
00343         }
00344 
00345         /* Handle flags */
00346         flags = 0;
00347         while (1)
00348         {
00349                  if (chr == _T('-')) flags |= FLAG_ALIGN_LEFT;
00350             else if (chr == _T('+')) flags |= FLAG_FORCE_SIGN;
00351             else if (chr == _T(' ')) flags |= FLAG_FORCE_SIGNSP;
00352             else if (chr == _T('0')) flags |= FLAG_PAD_ZERO;
00353             else if (chr == _T('#')) flags |= FLAG_SPECIAL;
00354             else break;
00355             chr = *format++;
00356         }
00357 
00358         /* Handle field width modifier */
00359         if (chr == _T('*'))
00360         {
00361             fieldwidth = va_arg(argptr, int);
00362             if (fieldwidth < 0)
00363             {
00364                 flags |= FLAG_ALIGN_LEFT;
00365                 fieldwidth = -fieldwidth;
00366             }
00367             chr = *format++;
00368         }
00369         else
00370         {
00371             fieldwidth = 0;
00372             while (chr >= _T('0') && chr <= _T('9'))
00373             {
00374                 fieldwidth = fieldwidth * 10 + (chr - _T('0'));
00375                 chr = *format++;
00376             }
00377         }
00378 
00379         /* Handle precision modifier */
00380         if (chr == '.')
00381         {
00382             chr = *format++;
00383 
00384             if (chr == _T('*'))
00385             {
00386                 precision = va_arg(argptr, int);
00387                 chr = *format++;
00388             }
00389             else
00390             {
00391                 precision = 0;
00392                 while (chr >= _T('0') && chr <= _T('9'))
00393                 {
00394                     precision = precision * 10 + (chr - _T('0'));
00395                     chr = *format++;
00396                 }
00397             }
00398         }
00399         else precision = -1;
00400 
00401         /* Handle argument size prefix */
00402         do
00403         {
00404                  if (chr == _T('h')) flags |= FLAG_SHORT;
00405             else if (chr == _T('w')) flags |= FLAG_WIDECHAR;
00406             else if (chr == _T('L')) flags |= 0; // FIXME: long double
00407             else if (chr == _T('F')) flags |= 0; // FIXME: what is that?
00408             else if (chr == _T('l'))
00409             {
00410                 /* Check if this is the 2nd 'l' in a row */
00411                 if (format[-2] == 'l') flags |= FLAG_INT64;
00412                 else flags |= FLAG_LONG;
00413             }
00414             else if (chr == _T('I'))
00415             {
00416                 if (format[0] == _T('3') && format[1] == _T('2'))
00417                 {
00418                     format += 2;
00419                 }
00420                 else if (format[0] == _T('6') && format[1] == _T('4'))
00421                 {
00422                     format += 2;
00423                     flags |= FLAG_INT64;
00424                 }
00425                 else if (format[0] == _T('x') || format[0] == _T('X') ||
00426                          format[0] == _T('d') || format[0] == _T('i') ||
00427                          format[0] == _T('u') || format[0] == _T('o'))
00428                 {
00429                     flags |= FLAG_INTPTR;
00430                 }
00431                 else break;
00432             }
00433             else break;
00434             chr = *format++;
00435         }
00436         while (USE_MULTISIZE);
00437 
00438         /* Handle the format specifier */
00439         digits = digits_l;
00440         string = &buffer[BUFFER_SIZE];
00441         base = 10;
00442         prefix = 0;
00443         switch (chr)
00444         {
00445             case _T('n'):
00446                 if (flags & FLAG_INT64)
00447                     *va_arg(argptr, __int64*) = written_all;
00448                 else if (flags & FLAG_SHORT)
00449                     *va_arg(argptr, short*) = written_all;
00450                 else
00451                     *va_arg(argptr, int*) = written_all;
00452                 continue;
00453 
00454             case _T('C'):
00455 #ifndef _UNICODE
00456                 if (!(flags & FLAG_SHORT)) flags |= FLAG_WIDECHAR;
00457 #endif
00458                 goto case_char;
00459 
00460             case _T('c'):
00461 #ifdef _UNICODE
00462                 if (!(flags & FLAG_SHORT)) flags |= FLAG_WIDECHAR;
00463 #endif
00464             case_char:
00465                 string = buffer;
00466                 len = 1;
00467                 if (flags & FLAG_WIDECHAR)
00468                 {
00469                     ((wchar_t*)string)[0] = va_arg(argptr, int);
00470                     ((wchar_t*)string)[1] = _T('\0');
00471                 }
00472                 else
00473                 {
00474                     ((char*)string)[0] = va_arg(argptr, int);
00475                     ((char*)string)[1] = _T('\0');
00476                 }
00477                 break;
00478 
00479             case _T('Z'):
00480                 nt_string = va_arg(argptr, void*);
00481                 if (nt_string && (string = nt_string->Buffer))
00482                 {
00483                     len = nt_string->Length;
00484                     if (flags & FLAG_WIDECHAR) len /= sizeof(wchar_t);
00485                     break;
00486                 }
00487                 string = 0;
00488                 goto case_string;
00489 
00490             case _T('S'):
00491                 string = va_arg(argptr, void*);
00492 #ifndef _UNICODE
00493                 if (!(flags & FLAG_SHORT)) flags |= FLAG_WIDECHAR;
00494 #endif
00495                 goto case_string;
00496 
00497             case _T('s'):
00498                 string = va_arg(argptr, void*);
00499 #ifdef _UNICODE
00500                 if (!(flags & FLAG_SHORT)) flags |= FLAG_WIDECHAR;
00501 #endif
00502 
00503             case_string:
00504                 if (!string)
00505                 {
00506                     string = (TCHAR*)_nullstring;
00507                     flags &= ~FLAG_WIDECHAR;
00508                 }
00509 
00510                 if (flags & FLAG_WIDECHAR)
00511                     len = wcslen((wchar_t*)string);
00512                 else
00513                     len = strlen((char*)string);
00514                 if (precision >= 0 && len > (unsigned)precision) len = precision;
00515                 precision = 0;
00516                 break;
00517 
00518 #ifndef _USER32_WSPRINTF
00519             case _T('G'):
00520             case _T('E'):
00521             case _T('A'):
00522             case _T('g'):
00523             case _T('e'):
00524             case _T('a'):
00525             case _T('f'):
00526 #ifdef _UNICODE
00527                 flags |= FLAG_WIDECHAR;
00528 #else
00529                 flags &= ~FLAG_WIDECHAR;
00530 #endif
00531                 /* Use external function, one for kernel one for user mode */
00532                 format_float(chr, flags, precision, &string, &prefix, &argptr);
00533                 len = _tcslen(string);
00534                 precision = 0;
00535                 break;
00536 #endif
00537 
00538             case _T('d'):
00539             case _T('i'):
00540                 val64 = (__int64)va_arg_f(argptr, flags);
00541 
00542                 if ((__int64)val64 < 0)
00543                 {
00544                     val64 = -(__int64)val64;
00545                     prefix = _T("-");
00546                 }
00547                 else if (flags & FLAG_FORCE_SIGN)
00548                     prefix = _T("+");
00549                 else if (flags & FLAG_FORCE_SIGNSP)
00550                     prefix = _T(" ");
00551 
00552                 goto case_number;
00553 
00554             case _T('o'):
00555                 base = 8;
00556                 if (flags & FLAG_SPECIAL)
00557                 {
00558                     prefix = _T("0");
00559                     if (precision > 0) precision--;
00560                 }
00561                 goto case_unsigned;
00562 
00563             case _T('p'):
00564                 precision = 2 * sizeof(void*);
00565                 flags &= ~FLAG_PAD_ZERO;
00566                 flags |= FLAG_INTPTR;
00567                 /* Fall through */
00568 
00569             case _T('X'):
00570                 digits = digits_u;
00571                 /* Fall through */
00572 
00573             case _T('x'):
00574                 base = 16;
00575                 if (flags & FLAG_SPECIAL)
00576                 {
00577                     prefix = &digits[16];
00578 #ifdef _USER32_WSPRINTF
00579                     fieldwidth += 2;
00580 #endif
00581                 }
00582 
00583             case _T('u'):
00584             case_unsigned:
00585                 val64 = va_arg_fu(argptr, flags);
00586 
00587             case_number:
00588 #ifdef _UNICODE
00589                 flags |= FLAG_WIDECHAR;
00590 #else
00591                 flags &= ~FLAG_WIDECHAR;
00592 #endif
00593                 if (precision < 0) precision = 1;
00594 
00595                 /* Gather digits in reverse order */
00596                 while (val64)
00597                 {
00598                     *--string = digits[val64 % base];
00599                     val64 /= base;
00600                     precision--;
00601                 }
00602 
00603                 len = _tcslen(string);
00604                 break;
00605 
00606             default:
00607                 /* Treat anything else as a new character */
00608                 format--;
00609                 continue;
00610         }
00611 
00612         /* Calculate padding */
00613         prefixlen = prefix ? _tcslen(prefix) : 0;
00614         if (precision < 0) precision = 0;
00615         padding = (int)(fieldwidth - len - prefixlen - precision);
00616         if (padding < 0) padding = 0;
00617 
00618         /* Optional left space padding */
00619         if ((flags & (FLAG_ALIGN_LEFT | FLAG_PAD_ZERO)) == 0)
00620         {
00621             for (; padding > 0; padding--)
00622             {
00623                 if ((written = streamout_char(stream, _T(' '))) == 0) return -1;
00624                 written_all += written;
00625             }
00626         }
00627 
00628         /* Optional prefix */
00629         if (prefix)
00630         {
00631             written = streamout_string(stream, prefix, prefixlen);
00632             if (written == -1) return -1;
00633             written_all += written;
00634         }
00635 
00636         /* Optional left '0' padding */
00637         if ((flags & FLAG_ALIGN_LEFT) == 0) precision += padding;
00638         while (precision-- > 0)
00639         {
00640             if ((written = streamout_char(stream, _T('0'))) == 0) return -1;
00641             written_all += written;
00642         }
00643 
00644         /* Output the string */
00645         if (flags & FLAG_WIDECHAR)
00646             written = streamout_wstring(stream, (wchar_t*)string, len);
00647         else
00648             written = streamout_astring(stream, (char*)string, len);
00649         if (written == -1) return -1;
00650         written_all += written;
00651 
00652 #if 0 && SUPPORT_FLOAT
00653         /* Optional right '0' padding */
00654         while (precision-- > 0)
00655         {
00656             if ((written = streamout_char(stream, _T('0'))) == 0) return -1;
00657             written_all += written;
00658             len++;
00659         }
00660 #endif
00661 
00662         /* Optional right padding */
00663         if (flags & FLAG_ALIGN_LEFT)
00664         {
00665             while (padding-- > 0)
00666             {
00667                 if ((written = streamout_char(stream, _T(' '))) == 0) return -1;
00668                 written_all += written;
00669             }
00670         }
00671 
00672     }
00673 
00674     if (written == -1) return -1;
00675 
00676     return written_all;
00677 }
00678 

Generated on Sat May 26 2012 04:35:28 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.