| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 |  | 
|---|
| 5 | /*++ | 
|---|
| 6 |  | 
|---|
| 7 |  | 
|---|
| 8 |  | 
|---|
| 9 | Module Name: | 
|---|
| 10 |  | 
|---|
| 11 | printfcpp.cpp | 
|---|
| 12 |  | 
|---|
| 13 | Abstract: | 
|---|
| 14 |  | 
|---|
| 15 | Implementation of suspension safe printf functions. | 
|---|
| 16 |  | 
|---|
| 17 | Revision History: | 
|---|
| 18 |  | 
|---|
| 19 |  | 
|---|
| 20 |  | 
|---|
| 21 | --*/ | 
|---|
| 22 |  | 
|---|
| 23 | #include "pal/corunix.hpp" | 
|---|
| 24 | #include "pal/thread.hpp" | 
|---|
| 25 | #include "pal/malloc.hpp" | 
|---|
| 26 | #include "pal/file.hpp" | 
|---|
| 27 | #include "pal/printfcpp.hpp" | 
|---|
| 28 | #include "pal/palinternal.h" | 
|---|
| 29 | #include "pal/dbgmsg.h" | 
|---|
| 30 | #include "pal/cruntime.h" | 
|---|
| 31 |  | 
|---|
| 32 | #include <errno.h> | 
|---|
| 33 |  | 
|---|
| 34 | SET_DEFAULT_DEBUG_CHANNEL(CRT); | 
|---|
| 35 |  | 
|---|
| 36 | using namespace CorUnix; | 
|---|
| 37 |  | 
|---|
| 38 | static const char __nullstring[] = "(null)";  /* string to print on null ptr */ | 
|---|
| 39 | static const WCHAR __wnullstring[] = W( "(null)"); /* string to print on null ptr */ | 
|---|
| 40 |  | 
|---|
| 41 | int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap); | 
|---|
| 42 | int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap); | 
|---|
| 43 |  | 
|---|
| 44 | extern "C" | 
|---|
| 45 | { | 
|---|
| 46 |  | 
|---|
| 47 | /******************************************************************************* | 
|---|
| 48 | Function: | 
|---|
| 49 | Internal_Convertfwrite | 
|---|
| 50 | This function is a wrapper around fwrite for cases where the buffer has | 
|---|
| 51 | to be converted from WideChar to MultiByte | 
|---|
| 52 | *******************************************************************************/ | 
|---|
| 53 |  | 
|---|
| 54 | static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, size_t size, size_t count, FILE *stream, BOOL convert) | 
|---|
| 55 | { | 
|---|
| 56 | int ret; | 
|---|
| 57 | int iError = 0; | 
|---|
| 58 |  | 
|---|
| 59 | #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL | 
|---|
| 60 | clearerr (stream); | 
|---|
| 61 | #endif | 
|---|
| 62 |  | 
|---|
| 63 | if(convert) | 
|---|
| 64 | { | 
|---|
| 65 | int nsize; | 
|---|
| 66 | LPSTR newBuff = 0; | 
|---|
| 67 | nsize = WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)buffer, count, 0, 0, 0, 0); | 
|---|
| 68 | if (!nsize) | 
|---|
| 69 | { | 
|---|
| 70 | ASSERT( "WideCharToMultiByte failed.  Error is %d\n", GetLastError()); | 
|---|
| 71 | return -1; | 
|---|
| 72 | } | 
|---|
| 73 | newBuff = (LPSTR) InternalMalloc(nsize); | 
|---|
| 74 | if (!newBuff) | 
|---|
| 75 | { | 
|---|
| 76 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 77 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 78 | return -1; | 
|---|
| 79 | } | 
|---|
| 80 | nsize = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)buffer, count, newBuff, nsize, 0, 0); | 
|---|
| 81 | if (!nsize) | 
|---|
| 82 | { | 
|---|
| 83 | ASSERT( "WideCharToMultiByte failed.  Error is %d\n", GetLastError()); | 
|---|
| 84 | free(newBuff); | 
|---|
| 85 | return -1; | 
|---|
| 86 | } | 
|---|
| 87 | ret = InternalFwrite(newBuff, 1, count, stream, &iError); | 
|---|
| 88 | if (iError != 0) | 
|---|
| 89 | { | 
|---|
| 90 | ERROR( "InternalFwrite did not write the whole buffer. Error is %d\n", iError); | 
|---|
| 91 | free(newBuff); | 
|---|
| 92 | return -1; | 
|---|
| 93 | } | 
|---|
| 94 | free(newBuff); | 
|---|
| 95 | } | 
|---|
| 96 | else | 
|---|
| 97 | { | 
|---|
| 98 | ret = InternalFwrite(buffer, size, count, stream, &iError); | 
|---|
| 99 | if (iError != 0) | 
|---|
| 100 | { | 
|---|
| 101 | ERROR( "InternalFwrite did not write the whole buffer. Error is %d\n", iError); | 
|---|
| 102 | return -1; | 
|---|
| 103 | } | 
|---|
| 104 | } | 
|---|
| 105 | return ret; | 
|---|
| 106 |  | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | /******************************************************************************* | 
|---|
| 110 | Function: | 
|---|
| 111 | Internal_ExtractFormatA | 
|---|
| 112 |  | 
|---|
| 113 | Paramaters: | 
|---|
| 114 | Fmt | 
|---|
| 115 | - format string to parse | 
|---|
| 116 | - first character must be a '%' | 
|---|
| 117 | - paramater gets updated to point to the character after | 
|---|
| 118 | the %<foo> format string | 
|---|
| 119 | Out | 
|---|
| 120 | - buffer will contain the %<foo> format string | 
|---|
| 121 | Flags | 
|---|
| 122 | - paramater will be set with the PRINTF_FORMAT_FLAGS defined above | 
|---|
| 123 | Width | 
|---|
| 124 | - will contain the width specified by the format string | 
|---|
| 125 | - -1 if none given | 
|---|
| 126 | Precision | 
|---|
| 127 | - will contain the precision specified in the format string | 
|---|
| 128 | - -1 if none given | 
|---|
| 129 | Prefix | 
|---|
| 130 | - an enumeration of the type prefix | 
|---|
| 131 | Type | 
|---|
| 132 | - an enumeration of the type value | 
|---|
| 133 |  | 
|---|
| 134 | Notes: | 
|---|
| 135 | - I'm also handling the undocumented %ws, %wc, %w... | 
|---|
| 136 | - %#10x, when we have a width greater than the length (i.e padding) the | 
|---|
| 137 | length of the padding is not consistent with MS's wsprintf | 
|---|
| 138 | (MS adds an extra 2 padding chars, length of "0x") | 
|---|
| 139 | - MS's wsprintf seems to ingore a 'h' prefix for number types | 
|---|
| 140 | - MS's "%p" is different than gcc's | 
|---|
| 141 | e.g. printf("%p", NULL); | 
|---|
| 142 | MS  -->  00000000 | 
|---|
| 143 | gcc -->  0x0 | 
|---|
| 144 | - the length of the exponent (precision) for floating types is different | 
|---|
| 145 | between MS and gcc | 
|---|
| 146 | e.g. printf("%E", 256.0); | 
|---|
| 147 | MS  -->  2.560000E+002 | 
|---|
| 148 | gcc -->  2.560000E+02 | 
|---|
| 149 | *******************************************************************************/ | 
|---|
| 150 | BOOL (CPalThread *pthrCurrent, LPCSTR *Fmt, LPSTR Out, LPINT Flags, | 
|---|
| 151 | LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type) | 
|---|
| 152 | { | 
|---|
| 153 | BOOL Result = FALSE; | 
|---|
| 154 | LPSTR TempStr; | 
|---|
| 155 | LPSTR TempStrPtr; | 
|---|
| 156 |  | 
|---|
| 157 | *Width = WIDTH_DEFAULT; | 
|---|
| 158 | *Precision = PRECISION_DEFAULT; | 
|---|
| 159 | *Flags = PFF_NONE; | 
|---|
| 160 | *Prefix = PFF_PREFIX_DEFAULT; | 
|---|
| 161 | *Type = PFF_TYPE_DEFAULT; | 
|---|
| 162 |  | 
|---|
| 163 | if (*Fmt && **Fmt == '%') | 
|---|
| 164 | { | 
|---|
| 165 | *Out++ = *(*Fmt)++; | 
|---|
| 166 | } | 
|---|
| 167 | else | 
|---|
| 168 | { | 
|---|
| 169 | return Result; | 
|---|
| 170 | } | 
|---|
| 171 |  | 
|---|
| 172 | /* we'll never need a temp string longer than the original */ | 
|---|
| 173 | TempStrPtr = TempStr = (LPSTR) InternalMalloc(strlen(*Fmt)+1); | 
|---|
| 174 | if (!TempStr) | 
|---|
| 175 | { | 
|---|
| 176 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 177 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 178 | return Result; | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 | /* parse flags */ | 
|---|
| 182 | while (**Fmt && (**Fmt == '-' || **Fmt == '+' || | 
|---|
| 183 | **Fmt == '0' || **Fmt == ' ' || **Fmt == '#')) | 
|---|
| 184 | { | 
|---|
| 185 | switch (**Fmt) | 
|---|
| 186 | { | 
|---|
| 187 | case '-': | 
|---|
| 188 | *Flags |= PFF_MINUS; break; | 
|---|
| 189 | case '+': | 
|---|
| 190 | *Flags |= PFF_PLUS; break; | 
|---|
| 191 | case '0': | 
|---|
| 192 | *Flags |= PFF_ZERO; break; | 
|---|
| 193 | case ' ': | 
|---|
| 194 | *Flags |= PFF_SPACE; break; | 
|---|
| 195 | case '#': | 
|---|
| 196 | *Flags |= PFF_POUND; break; | 
|---|
| 197 | } | 
|---|
| 198 | *Out++ = *(*Fmt)++; | 
|---|
| 199 | } | 
|---|
| 200 | /* '-' flag negates '0' flag */ | 
|---|
| 201 | if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO)) | 
|---|
| 202 | { | 
|---|
| 203 | *Flags -= PFF_ZERO; | 
|---|
| 204 | } | 
|---|
| 205 |  | 
|---|
| 206 | /* grab width specifier */ | 
|---|
| 207 | if (isdigit((unsigned char) **Fmt)) | 
|---|
| 208 | { | 
|---|
| 209 | TempStrPtr = TempStr; | 
|---|
| 210 | while (isdigit((unsigned char) **Fmt)) | 
|---|
| 211 | { | 
|---|
| 212 | *TempStrPtr++ = **Fmt; | 
|---|
| 213 | *Out++ = *(*Fmt)++; | 
|---|
| 214 | } | 
|---|
| 215 | *TempStrPtr = 0; /* end string */ | 
|---|
| 216 | *Width = atoi(TempStr); | 
|---|
| 217 | if (*Width < 0) | 
|---|
| 218 | { | 
|---|
| 219 | ERROR( "atoi returned a negative value indicative of an overflow.\n"); | 
|---|
| 220 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); | 
|---|
| 221 | return Result; | 
|---|
| 222 | } | 
|---|
| 223 | } | 
|---|
| 224 | else if (**Fmt == '*') | 
|---|
| 225 | { | 
|---|
| 226 | *Width = WIDTH_STAR; | 
|---|
| 227 | *Out++ = *(*Fmt)++; | 
|---|
| 228 | if (isdigit((unsigned char) **Fmt)) | 
|---|
| 229 | { | 
|---|
| 230 | /* this is an invalid width because we have a * then a number */ | 
|---|
| 231 | /* printf handles this by just printing the whole string */ | 
|---|
| 232 | *Width = WIDTH_INVALID; | 
|---|
| 233 | while (isdigit((unsigned char) **Fmt)) | 
|---|
| 234 | { | 
|---|
| 235 | *Out++ = *(*Fmt)++; | 
|---|
| 236 | } | 
|---|
| 237 | } | 
|---|
| 238 | } | 
|---|
| 239 |  | 
|---|
| 240 |  | 
|---|
| 241 | /* grab precision specifier */ | 
|---|
| 242 | if (**Fmt == '.') | 
|---|
| 243 | { | 
|---|
| 244 | *Out++ = *(*Fmt)++; | 
|---|
| 245 | if (isdigit((unsigned char) **Fmt)) | 
|---|
| 246 | { | 
|---|
| 247 | TempStrPtr = TempStr; | 
|---|
| 248 | while (isdigit((unsigned char) **Fmt)) | 
|---|
| 249 | { | 
|---|
| 250 | *TempStrPtr++ = **Fmt; | 
|---|
| 251 | *Out++ = *(*Fmt)++; | 
|---|
| 252 | } | 
|---|
| 253 | *TempStrPtr = 0; /* end string */ | 
|---|
| 254 | *Precision = atoi(TempStr); | 
|---|
| 255 | if (*Precision < 0) | 
|---|
| 256 | { | 
|---|
| 257 | ERROR( "atoi returned a negative value indicative of an overflow.\n"); | 
|---|
| 258 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); | 
|---|
| 259 | return Result; | 
|---|
| 260 | } | 
|---|
| 261 | } | 
|---|
| 262 | else if (**Fmt == '*') | 
|---|
| 263 | { | 
|---|
| 264 | *Precision = PRECISION_STAR; | 
|---|
| 265 | *Out++ = *(*Fmt)++; | 
|---|
| 266 | if (isdigit((unsigned char) **Fmt)) | 
|---|
| 267 | { | 
|---|
| 268 | /* this is an invalid precision because we have a .* then a number */ | 
|---|
| 269 | /* printf handles this by just printing the whole string */ | 
|---|
| 270 | *Precision = PRECISION_INVALID; | 
|---|
| 271 | while (isdigit((unsigned char) **Fmt)) | 
|---|
| 272 | { | 
|---|
| 273 | *Out++ = *(*Fmt)++; | 
|---|
| 274 | } | 
|---|
| 275 | } | 
|---|
| 276 | } | 
|---|
| 277 | else | 
|---|
| 278 | { | 
|---|
| 279 | *Precision = PRECISION_DOT; | 
|---|
| 280 | } | 
|---|
| 281 | } | 
|---|
| 282 |  | 
|---|
| 283 | #ifdef BIT64 | 
|---|
| 284 | if (**Fmt == 'p') | 
|---|
| 285 | { | 
|---|
| 286 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 287 | } | 
|---|
| 288 | #endif | 
|---|
| 289 | if ((*Fmt)[0] == 'I') | 
|---|
| 290 | { | 
|---|
| 291 | /* grab prefix of 'I64' for __int64 */ | 
|---|
| 292 | if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4') | 
|---|
| 293 | { | 
|---|
| 294 | /* convert to 'll' so that Unix snprintf can handle it */ | 
|---|
| 295 | *Fmt += 3; | 
|---|
| 296 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 297 | } | 
|---|
| 298 | /* grab prefix of 'I32' for __int32 */ | 
|---|
| 299 | else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2') | 
|---|
| 300 | { | 
|---|
| 301 | *Fmt += 3; | 
|---|
| 302 | } | 
|---|
| 303 | else | 
|---|
| 304 | { | 
|---|
| 305 | ++(*Fmt); | 
|---|
| 306 | #ifdef BIT64 | 
|---|
| 307 | /* convert to 'll' so that Unix snprintf can handle it */ | 
|---|
| 308 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 309 | #endif | 
|---|
| 310 | } | 
|---|
| 311 | } | 
|---|
| 312 | /* grab a prefix of 'h' */ | 
|---|
| 313 | else if (**Fmt == 'h') | 
|---|
| 314 | { | 
|---|
| 315 | *Prefix = PFF_PREFIX_SHORT; | 
|---|
| 316 | ++(*Fmt); | 
|---|
| 317 | } | 
|---|
| 318 | /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */ | 
|---|
| 319 | else if (**Fmt == 'l' || **Fmt == 'w') | 
|---|
| 320 | { | 
|---|
| 321 | ++(*Fmt); | 
|---|
| 322 | #ifdef BIT64 | 
|---|
| 323 | // Only want to change the prefix on 64 bit when printing characters. | 
|---|
| 324 | if (**Fmt == 'c' || **Fmt == 's') | 
|---|
| 325 | #endif | 
|---|
| 326 | { | 
|---|
| 327 | *Prefix = PFF_PREFIX_LONG; | 
|---|
| 328 | } | 
|---|
| 329 | if (**Fmt == 'l') | 
|---|
| 330 | { | 
|---|
| 331 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 332 | ++(*Fmt); | 
|---|
| 333 | } | 
|---|
| 334 | } | 
|---|
| 335 | else if (**Fmt == 'L') | 
|---|
| 336 | { | 
|---|
| 337 | /* a prefix of 'L' seems to be ignored */ | 
|---|
| 338 | ++(*Fmt); | 
|---|
| 339 | } | 
|---|
| 340 |  | 
|---|
| 341 | /* grab type 'c' */ | 
|---|
| 342 | if (**Fmt == 'c' || **Fmt == 'C') | 
|---|
| 343 | { | 
|---|
| 344 | *Type = PFF_TYPE_CHAR; | 
|---|
| 345 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'C') | 
|---|
| 346 | { | 
|---|
| 347 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ | 
|---|
| 348 | } | 
|---|
| 349 | if (*Prefix == PFF_PREFIX_LONG) | 
|---|
| 350 | { | 
|---|
| 351 | *Out++ = 'l'; | 
|---|
| 352 | } | 
|---|
| 353 | *Out++ = 'c'; | 
|---|
| 354 | ++(*Fmt); | 
|---|
| 355 | Result = TRUE; | 
|---|
| 356 | } | 
|---|
| 357 | /* grab type 's' */ | 
|---|
| 358 | else if (**Fmt == 's' || **Fmt == 'S') | 
|---|
| 359 | { | 
|---|
| 360 | *Type = PFF_TYPE_STRING; | 
|---|
| 361 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'S') | 
|---|
| 362 | { | 
|---|
| 363 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ | 
|---|
| 364 | } | 
|---|
| 365 | if (*Prefix == PFF_PREFIX_LONG) | 
|---|
| 366 | { | 
|---|
| 367 | *Out++ = 'l'; | 
|---|
| 368 | } | 
|---|
| 369 | *Out++ = 's'; | 
|---|
| 370 | ++(*Fmt); | 
|---|
| 371 | Result = TRUE; | 
|---|
| 372 | } | 
|---|
| 373 | /* grab int types */ | 
|---|
| 374 | else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' || | 
|---|
| 375 | **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X') | 
|---|
| 376 | { | 
|---|
| 377 | *Type = PFF_TYPE_INT; | 
|---|
| 378 | if (*Prefix == PFF_PREFIX_SHORT) | 
|---|
| 379 | { | 
|---|
| 380 | *Out++ = 'h'; | 
|---|
| 381 | } | 
|---|
| 382 | else if (*Prefix == PFF_PREFIX_LONG) | 
|---|
| 383 | { | 
|---|
| 384 | *Out++ = 'l'; | 
|---|
| 385 | } | 
|---|
| 386 | else if (*Prefix == PFF_PREFIX_LONGLONG) | 
|---|
| 387 | { | 
|---|
| 388 | *Out++ = 'l'; | 
|---|
| 389 | *Out++ = 'l'; | 
|---|
| 390 | } | 
|---|
| 391 | *Out++ = *(*Fmt)++; | 
|---|
| 392 | Result = TRUE; | 
|---|
| 393 | } | 
|---|
| 394 | else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || | 
|---|
| 395 | **Fmt == 'g' || **Fmt == 'G') | 
|---|
| 396 | { | 
|---|
| 397 | /* we can safely ignore the prefixes and only add the type*/ | 
|---|
| 398 | *Type = PFF_TYPE_FLOAT; | 
|---|
| 399 | *Out++ = *(*Fmt)++; | 
|---|
| 400 | Result = TRUE; | 
|---|
| 401 | } | 
|---|
| 402 | else if (**Fmt == 'n') | 
|---|
| 403 | { | 
|---|
| 404 | if (*Prefix == PFF_PREFIX_SHORT) | 
|---|
| 405 | { | 
|---|
| 406 | *Out++ = 'h'; | 
|---|
| 407 | } | 
|---|
| 408 | *Out++ = *(*Fmt)++; | 
|---|
| 409 | *Type = PFF_TYPE_N; | 
|---|
| 410 | Result = TRUE; | 
|---|
| 411 | } | 
|---|
| 412 | else if (**Fmt == 'p') | 
|---|
| 413 | { | 
|---|
| 414 | *Type = PFF_TYPE_P; | 
|---|
| 415 | (*Fmt)++; | 
|---|
| 416 |  | 
|---|
| 417 | if (*Prefix == PFF_PREFIX_LONGLONG) | 
|---|
| 418 | { | 
|---|
| 419 | if (*Precision == PRECISION_DEFAULT) | 
|---|
| 420 | { | 
|---|
| 421 | *Precision = 16; | 
|---|
| 422 | *Out++ = '.'; | 
|---|
| 423 | *Out++ = '1'; | 
|---|
| 424 | *Out++ = '6'; | 
|---|
| 425 | } | 
|---|
| 426 | /* native *printf does not support %I64p | 
|---|
| 427 | (actually %llp), so we need to cheat a little bit */ | 
|---|
| 428 | *Out++ = 'l'; | 
|---|
| 429 | *Out++ = 'l'; | 
|---|
| 430 | } | 
|---|
| 431 | else | 
|---|
| 432 | { | 
|---|
| 433 | if (*Precision == PRECISION_DEFAULT) | 
|---|
| 434 | { | 
|---|
| 435 | *Precision = 8; | 
|---|
| 436 | *Out++ = '.'; | 
|---|
| 437 | *Out++ = '8'; | 
|---|
| 438 | } | 
|---|
| 439 | } | 
|---|
| 440 | *Out++ = 'X'; | 
|---|
| 441 | Result = TRUE; | 
|---|
| 442 | } | 
|---|
| 443 |  | 
|---|
| 444 | *Out = 0;  /* end the string */ | 
|---|
| 445 | free(TempStr); | 
|---|
| 446 | return Result; | 
|---|
| 447 | } | 
|---|
| 448 |  | 
|---|
| 449 | /******************************************************************************* | 
|---|
| 450 | Function: | 
|---|
| 451 | Internal_ExtractFormatW | 
|---|
| 452 |  | 
|---|
| 453 | -- see Internal_ExtractFormatA above | 
|---|
| 454 | *******************************************************************************/ | 
|---|
| 455 | BOOL (CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, LPINT Flags, | 
|---|
| 456 | LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type) | 
|---|
| 457 | { | 
|---|
| 458 | BOOL Result = FALSE; | 
|---|
| 459 | LPSTR TempStr; | 
|---|
| 460 | LPSTR TempStrPtr; | 
|---|
| 461 |  | 
|---|
| 462 | *Width = WIDTH_DEFAULT; | 
|---|
| 463 | *Precision = PRECISION_DEFAULT; | 
|---|
| 464 | *Flags = PFF_NONE; | 
|---|
| 465 | *Prefix = PFF_PREFIX_DEFAULT; | 
|---|
| 466 | *Type = PFF_TYPE_DEFAULT; | 
|---|
| 467 |  | 
|---|
| 468 | if (*Fmt && **Fmt == '%') | 
|---|
| 469 | { | 
|---|
| 470 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 471 | } | 
|---|
| 472 | else | 
|---|
| 473 | { | 
|---|
| 474 | return Result; | 
|---|
| 475 | } | 
|---|
| 476 |  | 
|---|
| 477 | /* we'll never need a temp string longer than the original */ | 
|---|
| 478 | TempStrPtr = TempStr = (LPSTR) InternalMalloc(PAL_wcslen(*Fmt)+1); | 
|---|
| 479 | if (!TempStr) | 
|---|
| 480 | { | 
|---|
| 481 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 482 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 483 | return Result; | 
|---|
| 484 | } | 
|---|
| 485 |  | 
|---|
| 486 | /* parse flags */ | 
|---|
| 487 | while (**Fmt && (**Fmt == '-' || **Fmt == '+' || | 
|---|
| 488 | **Fmt == '0' || **Fmt == ' ' || **Fmt == '#')) | 
|---|
| 489 | { | 
|---|
| 490 | switch (**Fmt) | 
|---|
| 491 | { | 
|---|
| 492 | case '-': | 
|---|
| 493 | *Flags |= PFF_MINUS; break; | 
|---|
| 494 | case '+': | 
|---|
| 495 | *Flags |= PFF_PLUS; break; | 
|---|
| 496 | case '0': | 
|---|
| 497 | *Flags |= PFF_ZERO; break; | 
|---|
| 498 | case ' ': | 
|---|
| 499 | *Flags |= PFF_SPACE; break; | 
|---|
| 500 | case '#': | 
|---|
| 501 | *Flags |= PFF_POUND; break; | 
|---|
| 502 | } | 
|---|
| 503 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 504 | } | 
|---|
| 505 | /* '-' flag negates '0' flag */ | 
|---|
| 506 | if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO)) | 
|---|
| 507 | { | 
|---|
| 508 | *Flags -= PFF_ZERO; | 
|---|
| 509 | } | 
|---|
| 510 |  | 
|---|
| 511 | /* grab width specifier */ | 
|---|
| 512 | if (isdigit(**Fmt)) | 
|---|
| 513 | { | 
|---|
| 514 | TempStrPtr = TempStr; | 
|---|
| 515 | while (isdigit(**Fmt)) | 
|---|
| 516 | { | 
|---|
| 517 | *TempStrPtr++ = (CHAR) **Fmt; | 
|---|
| 518 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 519 | } | 
|---|
| 520 | *TempStrPtr = 0; /* end string */ | 
|---|
| 521 | *Width = atoi(TempStr); | 
|---|
| 522 | if (*Width < 0) | 
|---|
| 523 | { | 
|---|
| 524 | ERROR( "atoi returned a negative value indicative of an overflow.\n"); | 
|---|
| 525 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); | 
|---|
| 526 | return Result; | 
|---|
| 527 | } | 
|---|
| 528 | } | 
|---|
| 529 | else if (**Fmt == '*') | 
|---|
| 530 | { | 
|---|
| 531 | *Width = WIDTH_STAR; | 
|---|
| 532 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 533 | if (isdigit(**Fmt)) | 
|---|
| 534 | { | 
|---|
| 535 | /* this is an invalid width because we have a * then a number */ | 
|---|
| 536 | /* printf handles this by just printing the whole string */ | 
|---|
| 537 | *Width = WIDTH_INVALID; | 
|---|
| 538 | while (isdigit(**Fmt)) | 
|---|
| 539 | { | 
|---|
| 540 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 541 | } | 
|---|
| 542 | } | 
|---|
| 543 | } | 
|---|
| 544 |  | 
|---|
| 545 | /* grab precision specifier */ | 
|---|
| 546 | if (**Fmt == '.') | 
|---|
| 547 | { | 
|---|
| 548 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 549 | if (isdigit(**Fmt)) | 
|---|
| 550 | { | 
|---|
| 551 | TempStrPtr = TempStr; | 
|---|
| 552 | while (isdigit(**Fmt)) | 
|---|
| 553 | { | 
|---|
| 554 | *TempStrPtr++ = (CHAR) **Fmt; | 
|---|
| 555 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 556 | } | 
|---|
| 557 | *TempStrPtr = 0; /* end string */ | 
|---|
| 558 | *Precision = atoi(TempStr); | 
|---|
| 559 | if (*Precision < 0) | 
|---|
| 560 | { | 
|---|
| 561 | ERROR( "atoi returned a negative value indicative of an overflow.\n"); | 
|---|
| 562 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); | 
|---|
| 563 | return Result; | 
|---|
| 564 | } | 
|---|
| 565 | } | 
|---|
| 566 | else if (**Fmt == '*') | 
|---|
| 567 | { | 
|---|
| 568 | *Precision = PRECISION_STAR; | 
|---|
| 569 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 570 | if (isdigit(**Fmt)) | 
|---|
| 571 | { | 
|---|
| 572 | /* this is an invalid precision because we have a .* then a number */ | 
|---|
| 573 | /* printf handles this by just printing the whole string */ | 
|---|
| 574 | *Precision = PRECISION_INVALID; | 
|---|
| 575 | while (isdigit(**Fmt)) | 
|---|
| 576 | { | 
|---|
| 577 | *Out++ = (CHAR) *(*Fmt)++; | 
|---|
| 578 | } | 
|---|
| 579 | } | 
|---|
| 580 | } | 
|---|
| 581 | else | 
|---|
| 582 | { | 
|---|
| 583 | *Precision = PRECISION_DOT; | 
|---|
| 584 | } | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | #ifdef BIT64 | 
|---|
| 588 | if (**Fmt == 'p') | 
|---|
| 589 | { | 
|---|
| 590 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 591 | } | 
|---|
| 592 | #endif | 
|---|
| 593 | if ((*Fmt)[0] == 'I') | 
|---|
| 594 | { | 
|---|
| 595 | /* grab prefix of 'I64' for __int64 */ | 
|---|
| 596 | if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4') | 
|---|
| 597 | { | 
|---|
| 598 | /* convert to 'll' so that Unix snprintf can handle it */ | 
|---|
| 599 | *Fmt += 3; | 
|---|
| 600 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 601 | } | 
|---|
| 602 | /* grab prefix of 'I32' for __int32 */ | 
|---|
| 603 | else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2') | 
|---|
| 604 | { | 
|---|
| 605 | *Fmt += 3; | 
|---|
| 606 | } | 
|---|
| 607 | else | 
|---|
| 608 | { | 
|---|
| 609 | ++(*Fmt); | 
|---|
| 610 | #ifdef BIT64 | 
|---|
| 611 | /* convert to 'll' so that Unix snprintf can handle it */ | 
|---|
| 612 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 613 | #endif | 
|---|
| 614 | } | 
|---|
| 615 | } | 
|---|
| 616 | /* grab a prefix of 'h' */ | 
|---|
| 617 | else if (**Fmt == 'h') | 
|---|
| 618 | { | 
|---|
| 619 | *Prefix = PFF_PREFIX_SHORT; | 
|---|
| 620 | ++(*Fmt); | 
|---|
| 621 | } | 
|---|
| 622 | else if (**Fmt == 'l' || **Fmt == 'w') | 
|---|
| 623 | { | 
|---|
| 624 | ++(*Fmt); | 
|---|
| 625 | #ifdef BIT64 | 
|---|
| 626 | // Only want to change the prefix on 64 bit when printing characters. | 
|---|
| 627 | if (**Fmt == 'C' || **Fmt == 'S') | 
|---|
| 628 | #endif | 
|---|
| 629 | { | 
|---|
| 630 | *Prefix = PFF_PREFIX_LONG_W; | 
|---|
| 631 | } | 
|---|
| 632 | if (**Fmt == 'l') | 
|---|
| 633 | { | 
|---|
| 634 | *Prefix = PFF_PREFIX_LONGLONG; | 
|---|
| 635 | ++(*Fmt); | 
|---|
| 636 | } | 
|---|
| 637 | } | 
|---|
| 638 | else if (**Fmt == 'L') | 
|---|
| 639 | { | 
|---|
| 640 | /* a prefix of 'L' seems to be ignored */ | 
|---|
| 641 | ++(*Fmt); | 
|---|
| 642 | } | 
|---|
| 643 |  | 
|---|
| 644 |  | 
|---|
| 645 | /* grab type 'c' */ | 
|---|
| 646 | if (**Fmt == 'c' || **Fmt == 'C') | 
|---|
| 647 | { | 
|---|
| 648 | *Type = PFF_TYPE_CHAR; | 
|---|
| 649 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'c') | 
|---|
| 650 | { | 
|---|
| 651 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ | 
|---|
| 652 | } | 
|---|
| 653 | if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W) | 
|---|
| 654 | { | 
|---|
| 655 | *Out++ = 'l'; | 
|---|
| 656 | *Prefix = PFF_PREFIX_LONG; | 
|---|
| 657 | } | 
|---|
| 658 | *Out++ = 'c'; | 
|---|
| 659 | ++(*Fmt); | 
|---|
| 660 | Result = TRUE; | 
|---|
| 661 | } | 
|---|
| 662 | /* grab type 's' */ | 
|---|
| 663 | else if (**Fmt == 's' || **Fmt == 'S' ) | 
|---|
| 664 | { | 
|---|
| 665 | if ( **Fmt == 'S' ) | 
|---|
| 666 | { | 
|---|
| 667 | *Type = PFF_TYPE_WSTRING; | 
|---|
| 668 | } | 
|---|
| 669 | else | 
|---|
| 670 | { | 
|---|
| 671 | *Type = PFF_TYPE_STRING; | 
|---|
| 672 | } | 
|---|
| 673 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 's') | 
|---|
| 674 | { | 
|---|
| 675 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ | 
|---|
| 676 | } | 
|---|
| 677 | if (*Prefix == PFF_PREFIX_LONG) | 
|---|
| 678 | { | 
|---|
| 679 | *Out++ = 'l'; | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | *Out++ = 's'; | 
|---|
| 683 | ++(*Fmt); | 
|---|
| 684 | Result = TRUE; | 
|---|
| 685 | } | 
|---|
| 686 | /* grab int types */ | 
|---|
| 687 | else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' || | 
|---|
| 688 | **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X') | 
|---|
| 689 | { | 
|---|
| 690 | *Type = PFF_TYPE_INT; | 
|---|
| 691 | if (*Prefix == PFF_PREFIX_SHORT) | 
|---|
| 692 | { | 
|---|
| 693 | *Out++ = 'h'; | 
|---|
| 694 | } | 
|---|
| 695 | else if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W) | 
|---|
| 696 | { | 
|---|
| 697 | *Out++ = 'l'; | 
|---|
| 698 | *Prefix = PFF_PREFIX_LONG; | 
|---|
| 699 | } | 
|---|
| 700 | else if (*Prefix == PFF_PREFIX_LONGLONG) | 
|---|
| 701 | { | 
|---|
| 702 | *Out++ = 'l'; | 
|---|
| 703 | *Out++ = 'l'; | 
|---|
| 704 | } | 
|---|
| 705 | *Out++ = *(*Fmt)++; | 
|---|
| 706 | Result = TRUE; | 
|---|
| 707 | } | 
|---|
| 708 | else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || | 
|---|
| 709 | **Fmt == 'g' || **Fmt == 'G') | 
|---|
| 710 | { | 
|---|
| 711 | /* we can safely ignore the prefixes and only add the type*/ | 
|---|
| 712 | if (*Prefix == PFF_PREFIX_LONG_W) | 
|---|
| 713 | { | 
|---|
| 714 | *Prefix = PFF_PREFIX_LONG; | 
|---|
| 715 | } | 
|---|
| 716 |  | 
|---|
| 717 | *Type = PFF_TYPE_FLOAT; | 
|---|
| 718 | *Out++ = *(*Fmt)++; | 
|---|
| 719 | Result = TRUE; | 
|---|
| 720 | } | 
|---|
| 721 | else if (**Fmt == 'n') | 
|---|
| 722 | { | 
|---|
| 723 | if (*Prefix == PFF_PREFIX_LONG_W) | 
|---|
| 724 | { | 
|---|
| 725 | *Prefix = PFF_PREFIX_LONG; | 
|---|
| 726 | } | 
|---|
| 727 |  | 
|---|
| 728 | if (*Prefix == PFF_PREFIX_SHORT) | 
|---|
| 729 | { | 
|---|
| 730 | *Out++ = 'h'; | 
|---|
| 731 | } | 
|---|
| 732 | *Out++ = *(*Fmt)++; | 
|---|
| 733 | *Type = PFF_TYPE_N; | 
|---|
| 734 | Result = TRUE; | 
|---|
| 735 | } | 
|---|
| 736 | else if (**Fmt == 'p') | 
|---|
| 737 | { | 
|---|
| 738 | *Type = PFF_TYPE_P; | 
|---|
| 739 | (*Fmt)++; | 
|---|
| 740 |  | 
|---|
| 741 | if (*Prefix == PFF_PREFIX_LONGLONG) | 
|---|
| 742 | { | 
|---|
| 743 | if (*Precision == PRECISION_DEFAULT) | 
|---|
| 744 | { | 
|---|
| 745 | *Precision = 16; | 
|---|
| 746 | *Out++ = '.'; | 
|---|
| 747 | *Out++ = '1'; | 
|---|
| 748 | *Out++ = '6'; | 
|---|
| 749 | } | 
|---|
| 750 | /* native *printf does not support %I64p | 
|---|
| 751 | (actually %llp), so we need to cheat a little bit */ | 
|---|
| 752 | *Out++ = 'l'; | 
|---|
| 753 | *Out++ = 'l'; | 
|---|
| 754 | } | 
|---|
| 755 | else | 
|---|
| 756 | { | 
|---|
| 757 | if (*Precision == PRECISION_DEFAULT) | 
|---|
| 758 | { | 
|---|
| 759 | *Precision = 8; | 
|---|
| 760 | *Out++ = '.'; | 
|---|
| 761 | *Out++ = '8'; | 
|---|
| 762 | } | 
|---|
| 763 | if (*Prefix == PFF_PREFIX_LONG_W) | 
|---|
| 764 | { | 
|---|
| 765 | *Prefix = PFF_PREFIX_LONG; | 
|---|
| 766 | } | 
|---|
| 767 | } | 
|---|
| 768 | *Out++ = 'X'; | 
|---|
| 769 | Result = TRUE; | 
|---|
| 770 | } | 
|---|
| 771 |  | 
|---|
| 772 | *Out = 0;  /* end the string */ | 
|---|
| 773 | free(TempStr); | 
|---|
| 774 | return Result; | 
|---|
| 775 | } | 
|---|
| 776 |  | 
|---|
| 777 | /******************************************************************************* | 
|---|
| 778 | Function: | 
|---|
| 779 | Internal_AddPaddingVfprintf | 
|---|
| 780 |  | 
|---|
| 781 | Parameters: | 
|---|
| 782 | stream | 
|---|
| 783 | - file stream to place padding and given string (In) | 
|---|
| 784 | In | 
|---|
| 785 | - string to place into (Out) accompanied with padding | 
|---|
| 786 | Padding | 
|---|
| 787 | - number of padding chars to add | 
|---|
| 788 | Flags | 
|---|
| 789 | - padding style flags (PRINTF_FORMAT_FLAGS) | 
|---|
| 790 | *******************************************************************************/ | 
|---|
| 791 |  | 
|---|
| 792 | INT Internal_AddPaddingVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPCSTR In, | 
|---|
| 793 | INT Padding, INT Flags) | 
|---|
| 794 | { | 
|---|
| 795 | LPSTR Out; | 
|---|
| 796 | INT LengthInStr; | 
|---|
| 797 | INT Length; | 
|---|
| 798 | LPSTR OutOriginal; | 
|---|
| 799 | INT Written; | 
|---|
| 800 |  | 
|---|
| 801 | LengthInStr = strlen(In); | 
|---|
| 802 | Length = LengthInStr; | 
|---|
| 803 |  | 
|---|
| 804 | if (Padding > 0) | 
|---|
| 805 | { | 
|---|
| 806 | Length += Padding; | 
|---|
| 807 | } | 
|---|
| 808 | Out = (LPSTR) InternalMalloc(Length+1); | 
|---|
| 809 | int iLength = Length+1; | 
|---|
| 810 | if (!Out) | 
|---|
| 811 | { | 
|---|
| 812 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 813 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 814 | return -1; | 
|---|
| 815 | } | 
|---|
| 816 | OutOriginal = Out; | 
|---|
| 817 |  | 
|---|
| 818 | if (Flags & PFF_MINUS) /* pad on right */ | 
|---|
| 819 | { | 
|---|
| 820 | if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS) | 
|---|
| 821 | { | 
|---|
| 822 | ERROR( "strcpy_s failed\n"); | 
|---|
| 823 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|---|
| 824 | Written = -1; | 
|---|
| 825 | goto Done; | 
|---|
| 826 | } | 
|---|
| 827 |  | 
|---|
| 828 | Out += LengthInStr; | 
|---|
| 829 | iLength -= LengthInStr; | 
|---|
| 830 | } | 
|---|
| 831 | if (Padding > 0) | 
|---|
| 832 | { | 
|---|
| 833 | iLength -= Padding; | 
|---|
| 834 | if (Flags & PFF_ZERO) /* '0', pad with zeros */ | 
|---|
| 835 | { | 
|---|
| 836 | while (Padding--) | 
|---|
| 837 | { | 
|---|
| 838 | *Out++ = '0'; | 
|---|
| 839 | } | 
|---|
| 840 | } | 
|---|
| 841 | else /* pad with spaces */ | 
|---|
| 842 | { | 
|---|
| 843 | while (Padding--) | 
|---|
| 844 | { | 
|---|
| 845 | *Out++ = ' '; | 
|---|
| 846 | } | 
|---|
| 847 | } | 
|---|
| 848 | } | 
|---|
| 849 | if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ | 
|---|
| 850 | { | 
|---|
| 851 | if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS) | 
|---|
| 852 | { | 
|---|
| 853 | ERROR( "strcpy_s failed\n"); | 
|---|
| 854 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|---|
| 855 | Written = -1; | 
|---|
| 856 | goto Done; | 
|---|
| 857 | } | 
|---|
| 858 |  | 
|---|
| 859 | Out += LengthInStr; | 
|---|
| 860 | iLength -= LengthInStr; | 
|---|
| 861 | } | 
|---|
| 862 |  | 
|---|
| 863 | #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL | 
|---|
| 864 | clearerr (stream->bsdFilePtr); | 
|---|
| 865 | #endif | 
|---|
| 866 |  | 
|---|
| 867 | Written = InternalFwrite(OutOriginal, 1, Length, stream->bsdFilePtr, &stream->PALferrorCode); | 
|---|
| 868 | if (stream->PALferrorCode == PAL_FILE_ERROR) | 
|---|
| 869 | { | 
|---|
| 870 | ERROR( "fwrite() failed with errno == %d\n", errno); | 
|---|
| 871 | } | 
|---|
| 872 |  | 
|---|
| 873 | Done: | 
|---|
| 874 | free(OutOriginal); | 
|---|
| 875 |  | 
|---|
| 876 | return Written; | 
|---|
| 877 | } | 
|---|
| 878 |  | 
|---|
| 879 | /******************************************************************************* | 
|---|
| 880 | Function: | 
|---|
| 881 | Internal_AddPaddingVfwprintf | 
|---|
| 882 |  | 
|---|
| 883 | Parameters: | 
|---|
| 884 | stream | 
|---|
| 885 | - file stream to place padding and given string (In) | 
|---|
| 886 | In | 
|---|
| 887 | - string to place into (Out) accompanied with padding | 
|---|
| 888 | Padding | 
|---|
| 889 | - number of padding chars to add | 
|---|
| 890 | Flags | 
|---|
| 891 | - padding style flags (PRINTF_FORMAT_FLAGS) | 
|---|
| 892 | *******************************************************************************/ | 
|---|
| 893 | static INT Internal_AddPaddingVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPWSTR In, | 
|---|
| 894 | INT Padding, INT Flags,BOOL convert) | 
|---|
| 895 | { | 
|---|
| 896 | LPWSTR Out; | 
|---|
| 897 | LPWSTR OutOriginal; | 
|---|
| 898 | INT LengthInStr; | 
|---|
| 899 | INT Length; | 
|---|
| 900 | INT Written = 0; | 
|---|
| 901 |  | 
|---|
| 902 | LengthInStr = PAL_wcslen(In); | 
|---|
| 903 | Length = LengthInStr; | 
|---|
| 904 |  | 
|---|
| 905 | if (Padding > 0) | 
|---|
| 906 | { | 
|---|
| 907 | Length += Padding; | 
|---|
| 908 | } | 
|---|
| 909 |  | 
|---|
| 910 | int iLen = (Length+1); | 
|---|
| 911 | Out = (LPWSTR) InternalMalloc(iLen * sizeof(WCHAR)); | 
|---|
| 912 | if (!Out) | 
|---|
| 913 | { | 
|---|
| 914 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 915 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 916 | return -1; | 
|---|
| 917 | } | 
|---|
| 918 | OutOriginal = Out; | 
|---|
| 919 |  | 
|---|
| 920 | if (Flags & PFF_MINUS) /* pad on right */ | 
|---|
| 921 | { | 
|---|
| 922 | if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS) | 
|---|
| 923 | { | 
|---|
| 924 | ERROR( "wcscpy_s failed!\n"); | 
|---|
| 925 | free(OutOriginal); | 
|---|
| 926 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|---|
| 927 | return -1; | 
|---|
| 928 | } | 
|---|
| 929 | Out += LengthInStr; | 
|---|
| 930 | iLen -= LengthInStr; | 
|---|
| 931 | } | 
|---|
| 932 | if (Padding > 0) | 
|---|
| 933 | { | 
|---|
| 934 | iLen -= Padding; | 
|---|
| 935 | if (Flags & PFF_ZERO) /* '0', pad with zeros */ | 
|---|
| 936 | { | 
|---|
| 937 | while (Padding--) | 
|---|
| 938 | { | 
|---|
| 939 | *Out++ = '0'; | 
|---|
| 940 | } | 
|---|
| 941 | } | 
|---|
| 942 | else /* pad with spaces */ | 
|---|
| 943 | { | 
|---|
| 944 | while (Padding--) | 
|---|
| 945 | { | 
|---|
| 946 | *Out++ = ' '; | 
|---|
| 947 | } | 
|---|
| 948 | } | 
|---|
| 949 | } | 
|---|
| 950 | if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ | 
|---|
| 951 | { | 
|---|
| 952 | if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS) | 
|---|
| 953 | { | 
|---|
| 954 | ERROR( "wcscpy_s failed!\n"); | 
|---|
| 955 | free(OutOriginal); | 
|---|
| 956 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|---|
| 957 | return -1; | 
|---|
| 958 | } | 
|---|
| 959 |  | 
|---|
| 960 | Out += LengthInStr; | 
|---|
| 961 | iLen -= LengthInStr; | 
|---|
| 962 | } | 
|---|
| 963 |  | 
|---|
| 964 | if (Length > 0) { | 
|---|
| 965 | Written = Internal_Convertfwrite(pthrCurrent, OutOriginal, sizeof(wchar_16), Length, | 
|---|
| 966 | (FILE*)(stream->bsdFilePtr), convert); | 
|---|
| 967 |  | 
|---|
| 968 | if (-1 == Written) | 
|---|
| 969 | { | 
|---|
| 970 | ERROR( "fwrite() failed with errno == %d\n", errno); | 
|---|
| 971 | } | 
|---|
| 972 | free(OutOriginal); | 
|---|
| 973 | } | 
|---|
| 974 |  | 
|---|
| 975 | return Written; | 
|---|
| 976 | } | 
|---|
| 977 |  | 
|---|
| 978 | /******************************************************************************* | 
|---|
| 979 | Function: | 
|---|
| 980 | PAL_vfprintf | 
|---|
| 981 |  | 
|---|
| 982 | Parameters: | 
|---|
| 983 | stream | 
|---|
| 984 | - out stream | 
|---|
| 985 | Format | 
|---|
| 986 | - format string | 
|---|
| 987 | ap | 
|---|
| 988 | - stdarg parameter list | 
|---|
| 989 | *******************************************************************************/ | 
|---|
| 990 |  | 
|---|
| 991 | int __cdecl PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap) | 
|---|
| 992 | { | 
|---|
| 993 | return CoreVfprintf(InternalGetCurrentThread(), stream, format, ap); | 
|---|
| 994 | } | 
|---|
| 995 |  | 
|---|
| 996 | /******************************************************************************* | 
|---|
| 997 | Function: | 
|---|
| 998 | PAL_vfwprintf | 
|---|
| 999 |  | 
|---|
| 1000 | Parameters: | 
|---|
| 1001 | stream | 
|---|
| 1002 | - out stream | 
|---|
| 1003 | Format | 
|---|
| 1004 | - format string | 
|---|
| 1005 | ap | 
|---|
| 1006 | - stdarg parameter list | 
|---|
| 1007 | *******************************************************************************/ | 
|---|
| 1008 |  | 
|---|
| 1009 | int __cdecl PAL_vfwprintf(PAL_FILE *stream, const wchar_16 *format, va_list ap) | 
|---|
| 1010 | { | 
|---|
| 1011 | return CoreVfwprintf(InternalGetCurrentThread(), stream, format, ap); | 
|---|
| 1012 | } | 
|---|
| 1013 |  | 
|---|
| 1014 | } // end extern "C" | 
|---|
| 1015 |  | 
|---|
| 1016 | int CorUnix::InternalVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap) | 
|---|
| 1017 | { | 
|---|
| 1018 | return CoreVfprintf(pthrCurrent, stream, format, ap); | 
|---|
| 1019 | } | 
|---|
| 1020 |  | 
|---|
| 1021 | int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list aparg) | 
|---|
| 1022 | { | 
|---|
| 1023 | CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ | 
|---|
| 1024 | LPCWSTR Fmt = format; | 
|---|
| 1025 | LPCWSTR TempWStr = NULL; | 
|---|
| 1026 | LPWSTR AllocedTempWStr = NULL; | 
|---|
| 1027 | LPWSTR WorkingWStr = NULL; | 
|---|
| 1028 | WCHAR TempWChar[2]; | 
|---|
| 1029 | INT Flags; | 
|---|
| 1030 | INT Width; | 
|---|
| 1031 | INT Precision; | 
|---|
| 1032 | INT Prefix; | 
|---|
| 1033 | INT Type; | 
|---|
| 1034 | INT TempInt; | 
|---|
| 1035 | int mbtowcResult; | 
|---|
| 1036 | int written=0; | 
|---|
| 1037 | int paddingReturnValue; | 
|---|
| 1038 | int ret; | 
|---|
| 1039 | va_list ap; | 
|---|
| 1040 |  | 
|---|
| 1041 | /* fwprintf for now in the PAL is always used on file opened | 
|---|
| 1042 | in text mode. In those case the output should be ANSI not Unicode */ | 
|---|
| 1043 | BOOL textMode = TRUE; | 
|---|
| 1044 |  | 
|---|
| 1045 | PERF_ENTRY(vfwprintf); | 
|---|
| 1046 | ENTRY( "vfwprintf (stream=%p, format=%p (%S))\n", | 
|---|
| 1047 | stream, format, format); | 
|---|
| 1048 |  | 
|---|
| 1049 | va_copy(ap, aparg); | 
|---|
| 1050 |  | 
|---|
| 1051 | while (*Fmt) | 
|---|
| 1052 | { | 
|---|
| 1053 | if(*Fmt == '%' && | 
|---|
| 1054 | TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags, | 
|---|
| 1055 | &Width, &Precision, | 
|---|
| 1056 | &Prefix, &Type)) | 
|---|
| 1057 | { | 
|---|
| 1058 | if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) && | 
|---|
| 1059 | (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) || | 
|---|
| 1060 | (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0)) | 
|---|
| 1061 | { | 
|---|
| 1062 | AllocedTempWStr = NULL; | 
|---|
| 1063 |  | 
|---|
| 1064 | if (WIDTH_STAR == Width) | 
|---|
| 1065 | { | 
|---|
| 1066 | Width = va_arg(ap, INT); | 
|---|
| 1067 | } | 
|---|
| 1068 | else if (WIDTH_INVALID == Width) | 
|---|
| 1069 | { | 
|---|
| 1070 | /* both a '*' and a number, ignore, but remove arg */ | 
|---|
| 1071 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1072 | } | 
|---|
| 1073 |  | 
|---|
| 1074 | if (PRECISION_STAR == Precision) | 
|---|
| 1075 | { | 
|---|
| 1076 | Precision = va_arg(ap, INT); | 
|---|
| 1077 | } | 
|---|
| 1078 | else if (PRECISION_INVALID == Precision) | 
|---|
| 1079 | { | 
|---|
| 1080 | /* both a '*' and a number, ignore, but remove arg */ | 
|---|
| 1081 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1082 | } | 
|---|
| 1083 |  | 
|---|
| 1084 | if (Type == PFF_TYPE_STRING || Prefix == PFF_PREFIX_LONG_W) | 
|---|
| 1085 | { | 
|---|
| 1086 | TempWStr = va_arg(ap, LPWSTR); | 
|---|
| 1087 | } | 
|---|
| 1088 | else | 
|---|
| 1089 | { | 
|---|
| 1090 | /* %lS assumes a LPSTR argument. */ | 
|---|
| 1091 | LPCSTR s = va_arg(ap, LPSTR ); | 
|---|
| 1092 | if (s == NULL) | 
|---|
| 1093 | { | 
|---|
| 1094 | TempWStr = NULL; | 
|---|
| 1095 | } | 
|---|
| 1096 | else | 
|---|
| 1097 | { | 
|---|
| 1098 | UINT Length = 0; | 
|---|
| 1099 | Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 ); | 
|---|
| 1100 | if ( Length != 0 ) | 
|---|
| 1101 | { | 
|---|
| 1102 | AllocedTempWStr = | 
|---|
| 1103 | (LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) ); | 
|---|
| 1104 |  | 
|---|
| 1105 | if ( AllocedTempWStr ) | 
|---|
| 1106 | { | 
|---|
| 1107 | MultiByteToWideChar( CP_ACP, 0, s, -1, | 
|---|
| 1108 | AllocedTempWStr, Length ); | 
|---|
| 1109 | TempWStr = AllocedTempWStr; | 
|---|
| 1110 | } | 
|---|
| 1111 | else | 
|---|
| 1112 | { | 
|---|
| 1113 | ERROR( "InternalMalloc failed.\n"); | 
|---|
| 1114 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1115 | PERF_EXIT(vfwprintf); | 
|---|
| 1116 | va_end(ap); | 
|---|
| 1117 | return -1; | 
|---|
| 1118 | } | 
|---|
| 1119 | } | 
|---|
| 1120 | else | 
|---|
| 1121 | { | 
|---|
| 1122 | ASSERT( "Unable to convert from multibyte " | 
|---|
| 1123 | " to wide char.\n"); | 
|---|
| 1124 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1125 | PERF_EXIT(vfwprintf); | 
|---|
| 1126 | va_end(ap); | 
|---|
| 1127 | return -1; | 
|---|
| 1128 | } | 
|---|
| 1129 | } | 
|---|
| 1130 | } | 
|---|
| 1131 |  | 
|---|
| 1132 | if (TempWStr == NULL) | 
|---|
| 1133 | { | 
|---|
| 1134 | TempWStr = __wnullstring; | 
|---|
| 1135 | } | 
|---|
| 1136 |  | 
|---|
| 1137 | INT Length = PAL_wcslen(TempWStr); | 
|---|
| 1138 | WorkingWStr = (LPWSTR) InternalMalloc((sizeof(WCHAR) * (Length + 1))); | 
|---|
| 1139 | if (!WorkingWStr) | 
|---|
| 1140 | { | 
|---|
| 1141 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 1142 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1143 | PERF_EXIT(vfwprintf); | 
|---|
| 1144 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 1145 | free(AllocedTempWStr); | 
|---|
| 1146 | va_end(ap); | 
|---|
| 1147 | return -1; | 
|---|
| 1148 | } | 
|---|
| 1149 | if (PRECISION_DOT == Precision) | 
|---|
| 1150 | { | 
|---|
| 1151 | /* copy nothing */ | 
|---|
| 1152 | *WorkingWStr = 0; | 
|---|
| 1153 | Length = 0; | 
|---|
| 1154 | } | 
|---|
| 1155 | else if (Precision > 0 && Precision < Length) | 
|---|
| 1156 | { | 
|---|
| 1157 | if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS) | 
|---|
| 1158 | { | 
|---|
| 1159 | ERROR( "Internal_AddPaddingVfwprintf failed\n"); | 
|---|
| 1160 | free(AllocedTempWStr); | 
|---|
| 1161 | free(WorkingWStr); | 
|---|
| 1162 | LOGEXIT( "wcsncpy_s failed!\n"); | 
|---|
| 1163 | PERF_EXIT(vfwprintf); | 
|---|
| 1164 | va_end(ap); | 
|---|
| 1165 | return (-1); | 
|---|
| 1166 | } | 
|---|
| 1167 |  | 
|---|
| 1168 | Length = Precision; | 
|---|
| 1169 | } | 
|---|
| 1170 | /* copy everything */ | 
|---|
| 1171 | else | 
|---|
| 1172 | { | 
|---|
| 1173 | PAL_wcscpy(WorkingWStr, TempWStr); | 
|---|
| 1174 | } | 
|---|
| 1175 |  | 
|---|
| 1176 |  | 
|---|
| 1177 | /* do the padding (if needed)*/ | 
|---|
| 1178 | paddingReturnValue = | 
|---|
| 1179 | Internal_AddPaddingVfwprintf( pthrCurrent, stream, WorkingWStr, | 
|---|
| 1180 | Width - Length, | 
|---|
| 1181 | Flags,textMode); | 
|---|
| 1182 |  | 
|---|
| 1183 | if (paddingReturnValue == -1) | 
|---|
| 1184 | { | 
|---|
| 1185 | ERROR( "Internal_AddPaddingVfwprintf failed\n"); | 
|---|
| 1186 | free(AllocedTempWStr); | 
|---|
| 1187 | free(WorkingWStr); | 
|---|
| 1188 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1189 | PERF_EXIT(vfwprintf); | 
|---|
| 1190 | va_end(ap); | 
|---|
| 1191 | return (-1); | 
|---|
| 1192 | } | 
|---|
| 1193 | written += paddingReturnValue; | 
|---|
| 1194 |  | 
|---|
| 1195 | free(WorkingWStr); | 
|---|
| 1196 | free(AllocedTempWStr); | 
|---|
| 1197 | } | 
|---|
| 1198 | else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) | 
|---|
| 1199 | { | 
|---|
| 1200 | if (WIDTH_STAR == Width || | 
|---|
| 1201 | WIDTH_INVALID == Width) | 
|---|
| 1202 | { | 
|---|
| 1203 | /* ignore (because it's a char), and remove arg */ | 
|---|
| 1204 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1205 | } | 
|---|
| 1206 |  | 
|---|
| 1207 | if (PRECISION_STAR == Precision || | 
|---|
| 1208 | PRECISION_INVALID == Precision) | 
|---|
| 1209 | { | 
|---|
| 1210 | /* ignore (because it's a char), and remove arg */ | 
|---|
| 1211 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1212 | } | 
|---|
| 1213 |  | 
|---|
| 1214 | TempWChar[0] = va_arg(ap, int); | 
|---|
| 1215 | TempWChar[1] = 0; | 
|---|
| 1216 |  | 
|---|
| 1217 | /* do the padding (if needed)*/ | 
|---|
| 1218 | paddingReturnValue = | 
|---|
| 1219 | Internal_AddPaddingVfwprintf(pthrCurrent, stream, TempWChar, | 
|---|
| 1220 | Width - 1, | 
|---|
| 1221 | Flags,textMode); | 
|---|
| 1222 | if (paddingReturnValue == -1) | 
|---|
| 1223 | { | 
|---|
| 1224 | ERROR( "Internal_AddPaddingVfwprintf failed\n"); | 
|---|
| 1225 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1226 | PERF_EXIT(vfwprintf); | 
|---|
| 1227 | va_end(ap); | 
|---|
| 1228 | return(-1); | 
|---|
| 1229 | } | 
|---|
| 1230 | written += paddingReturnValue; | 
|---|
| 1231 | } | 
|---|
| 1232 | /* this places the number of bytes written to the buffer in the | 
|---|
| 1233 | next arg */ | 
|---|
| 1234 | else if (Type == PFF_TYPE_N) | 
|---|
| 1235 | { | 
|---|
| 1236 | if (WIDTH_STAR == Width) | 
|---|
| 1237 | { | 
|---|
| 1238 | Width = va_arg(ap, INT); | 
|---|
| 1239 | } | 
|---|
| 1240 |  | 
|---|
| 1241 | if (PRECISION_STAR == Precision) | 
|---|
| 1242 | { | 
|---|
| 1243 | Precision = va_arg(ap, INT); | 
|---|
| 1244 | } | 
|---|
| 1245 |  | 
|---|
| 1246 | if (Prefix == PFF_PREFIX_SHORT) | 
|---|
| 1247 | { | 
|---|
| 1248 | *(va_arg(ap, short *)) = written; | 
|---|
| 1249 | } | 
|---|
| 1250 | else | 
|---|
| 1251 | { | 
|---|
| 1252 | *(va_arg(ap, LPLONG)) = written; | 
|---|
| 1253 | } | 
|---|
| 1254 | } | 
|---|
| 1255 | else | 
|---|
| 1256 | { | 
|---|
| 1257 | // Types that sprintf can handle. | 
|---|
| 1258 |  | 
|---|
| 1259 | /* note: I'm using the wide buffer as a (char *) buffer when I | 
|---|
| 1260 | pass it to sprintf().  After I get the buffer back I make a | 
|---|
| 1261 | backup of the chars copied and then convert them to wide | 
|---|
| 1262 | and place them in the buffer (BufferPtr) */ | 
|---|
| 1263 |  | 
|---|
| 1264 | // This argument will be limited to 1024 characters. | 
|---|
| 1265 | // It should be enough. | 
|---|
| 1266 | size_t TEMP_COUNT = 1024; | 
|---|
| 1267 | char TempSprintfStrBuffer[1024]; | 
|---|
| 1268 | char *TempSprintfStrPtr = NULL; | 
|---|
| 1269 | char *TempSprintfStr = TempSprintfStrBuffer; | 
|---|
| 1270 | LPWSTR TempWideBuffer; | 
|---|
| 1271 |  | 
|---|
| 1272 | TempInt = 0; | 
|---|
| 1273 | // %h (short) doesn't seem to be handled properly by local sprintf, | 
|---|
| 1274 | // so we do the truncation ourselves for some cases. | 
|---|
| 1275 | if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) | 
|---|
| 1276 | { | 
|---|
| 1277 | // Convert from pointer -> int -> short to avoid warnings. | 
|---|
| 1278 | long trunc1; | 
|---|
| 1279 | short trunc2; | 
|---|
| 1280 |  | 
|---|
| 1281 | trunc1 = va_arg(ap, LONG); | 
|---|
| 1282 | trunc2 = (short)trunc1; | 
|---|
| 1283 | trunc1 = trunc2; | 
|---|
| 1284 |  | 
|---|
| 1285 | TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, trunc1); | 
|---|
| 1286 |  | 
|---|
| 1287 | if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) | 
|---|
| 1288 | { | 
|---|
| 1289 | if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) | 
|---|
| 1290 | { | 
|---|
| 1291 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 1292 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1293 | PERF_EXIT(vfwprintf); | 
|---|
| 1294 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 1295 | va_end(ap); | 
|---|
| 1296 | return -1; | 
|---|
| 1297 | } | 
|---|
| 1298 |  | 
|---|
| 1299 | TempSprintfStr = TempSprintfStrPtr; | 
|---|
| 1300 | snprintf(TempSprintfStr, TempInt, TempBuff, trunc2); | 
|---|
| 1301 | } | 
|---|
| 1302 | } | 
|---|
| 1303 | else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) | 
|---|
| 1304 | { | 
|---|
| 1305 | // Convert explicitly from int to short to get | 
|---|
| 1306 | // correct sign extension for shorts on all systems. | 
|---|
| 1307 | int n; | 
|---|
| 1308 | short s; | 
|---|
| 1309 |  | 
|---|
| 1310 | n = va_arg(ap, int); | 
|---|
| 1311 | s = (short) n; | 
|---|
| 1312 |  | 
|---|
| 1313 | TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, s); | 
|---|
| 1314 |  | 
|---|
| 1315 | if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) | 
|---|
| 1316 | { | 
|---|
| 1317 | if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) | 
|---|
| 1318 | { | 
|---|
| 1319 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 1320 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1321 | PERF_EXIT(vfwprintf); | 
|---|
| 1322 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 1323 | va_end(ap); | 
|---|
| 1324 | return -1; | 
|---|
| 1325 | } | 
|---|
| 1326 |  | 
|---|
| 1327 | TempSprintfStr = TempSprintfStrPtr; | 
|---|
| 1328 | snprintf(TempSprintfStr, TempInt, TempBuff, s); | 
|---|
| 1329 | } | 
|---|
| 1330 | } | 
|---|
| 1331 | else | 
|---|
| 1332 | { | 
|---|
| 1333 | va_list apcopy; | 
|---|
| 1334 |  | 
|---|
| 1335 | va_copy(apcopy, ap); | 
|---|
| 1336 | TempInt = _vsnprintf_s(TempSprintfStr, TEMP_COUNT, _TRUNCATE, TempBuff, apcopy); | 
|---|
| 1337 | va_end(apcopy); | 
|---|
| 1338 | PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); | 
|---|
| 1339 |  | 
|---|
| 1340 | if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) | 
|---|
| 1341 | { | 
|---|
| 1342 | if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) | 
|---|
| 1343 | { | 
|---|
| 1344 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 1345 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1346 | PERF_EXIT(vfwprintf); | 
|---|
| 1347 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 1348 | va_end(ap); | 
|---|
| 1349 | return -1; | 
|---|
| 1350 | } | 
|---|
| 1351 |  | 
|---|
| 1352 | TempSprintfStr = TempSprintfStrPtr; | 
|---|
| 1353 | va_copy(apcopy, ap); | 
|---|
| 1354 | _vsnprintf_s(TempSprintfStr, TempInt, _TRUNCATE, TempBuff, apcopy); | 
|---|
| 1355 | va_end(apcopy); | 
|---|
| 1356 | PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); | 
|---|
| 1357 | } | 
|---|
| 1358 | } | 
|---|
| 1359 |  | 
|---|
| 1360 | mbtowcResult = MultiByteToWideChar(CP_ACP, 0, | 
|---|
| 1361 | TempSprintfStr, -1, | 
|---|
| 1362 | NULL, 0); | 
|---|
| 1363 |  | 
|---|
| 1364 | if (mbtowcResult == 0) | 
|---|
| 1365 | { | 
|---|
| 1366 | ERROR( "MultiByteToWideChar failed\n"); | 
|---|
| 1367 | if(TempSprintfStrPtr) | 
|---|
| 1368 | { | 
|---|
| 1369 | free(TempSprintfStrPtr); | 
|---|
| 1370 | } | 
|---|
| 1371 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1372 | PERF_EXIT(vfwprintf); | 
|---|
| 1373 | va_end(ap); | 
|---|
| 1374 | return -1; | 
|---|
| 1375 | } | 
|---|
| 1376 |  | 
|---|
| 1377 | TempWideBuffer = (LPWSTR) InternalMalloc(mbtowcResult*sizeof(WCHAR)); | 
|---|
| 1378 | if (!TempWideBuffer) | 
|---|
| 1379 | { | 
|---|
| 1380 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 1381 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1382 | PERF_EXIT(vfwprintf); | 
|---|
| 1383 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 1384 | if(TempSprintfStrPtr) | 
|---|
| 1385 | { | 
|---|
| 1386 | free(TempSprintfStrPtr); | 
|---|
| 1387 | } | 
|---|
| 1388 | va_end(ap); | 
|---|
| 1389 | return -1; | 
|---|
| 1390 | } | 
|---|
| 1391 |  | 
|---|
| 1392 | MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1, | 
|---|
| 1393 | TempWideBuffer, mbtowcResult); | 
|---|
| 1394 |  | 
|---|
| 1395 | ret = Internal_Convertfwrite( | 
|---|
| 1396 | pthrCurrent, | 
|---|
| 1397 | TempWideBuffer, | 
|---|
| 1398 | sizeof(wchar_16), | 
|---|
| 1399 | mbtowcResult-1, | 
|---|
| 1400 | (FILE*)stream->bsdFilePtr, | 
|---|
| 1401 | textMode); | 
|---|
| 1402 |  | 
|---|
| 1403 | if (-1 == ret) | 
|---|
| 1404 | { | 
|---|
| 1405 | ERROR( "fwrite() failed with errno == %d (%s)\n", errno, strerror(errno)); | 
|---|
| 1406 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1407 | PERF_EXIT(vfwprintf); | 
|---|
| 1408 | free(TempWideBuffer); | 
|---|
| 1409 | if(TempSprintfStrPtr) | 
|---|
| 1410 | { | 
|---|
| 1411 | free(TempSprintfStrPtr); | 
|---|
| 1412 | } | 
|---|
| 1413 | va_end(ap); | 
|---|
| 1414 | return -1; | 
|---|
| 1415 | } | 
|---|
| 1416 | if(TempSprintfStrPtr) | 
|---|
| 1417 | { | 
|---|
| 1418 | free(TempSprintfStrPtr); | 
|---|
| 1419 | } | 
|---|
| 1420 | free(TempWideBuffer); | 
|---|
| 1421 | } | 
|---|
| 1422 | } | 
|---|
| 1423 | else | 
|---|
| 1424 | { | 
|---|
| 1425 | ret = Internal_Convertfwrite( | 
|---|
| 1426 | pthrCurrent, | 
|---|
| 1427 | Fmt++, | 
|---|
| 1428 | sizeof(wchar_16), | 
|---|
| 1429 | 1, | 
|---|
| 1430 | (FILE*)stream->bsdFilePtr, | 
|---|
| 1431 | textMode); /* copy regular chars into buffer */ | 
|---|
| 1432 |  | 
|---|
| 1433 | if (-1 == ret) | 
|---|
| 1434 | { | 
|---|
| 1435 | ERROR( "fwrite() failed with errno == %d\n", errno); | 
|---|
| 1436 | LOGEXIT( "vfwprintf returns int -1\n"); | 
|---|
| 1437 | PERF_EXIT(vfwprintf); | 
|---|
| 1438 | va_end(ap); | 
|---|
| 1439 | return -1; | 
|---|
| 1440 | } | 
|---|
| 1441 | ++written; | 
|---|
| 1442 | } | 
|---|
| 1443 | } | 
|---|
| 1444 |  | 
|---|
| 1445 | LOGEXIT( "vfwprintf returns int %d\n", written); | 
|---|
| 1446 | PERF_EXIT(vfwprintf); | 
|---|
| 1447 | va_end(ap); | 
|---|
| 1448 | return (written); | 
|---|
| 1449 | } | 
|---|
| 1450 |  | 
|---|
| 1451 | int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list aparg) | 
|---|
| 1452 | { | 
|---|
| 1453 | CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ | 
|---|
| 1454 | LPCSTR Fmt = format; | 
|---|
| 1455 | LPCWSTR TempWStr; | 
|---|
| 1456 | LPSTR TempStr; | 
|---|
| 1457 | WCHAR TempWChar; | 
|---|
| 1458 | INT Flags; | 
|---|
| 1459 | INT Width; | 
|---|
| 1460 | INT Precision; | 
|---|
| 1461 | INT Prefix; | 
|---|
| 1462 | INT Type; | 
|---|
| 1463 | INT Length; | 
|---|
| 1464 | INT TempInt; | 
|---|
| 1465 | int wctombResult; | 
|---|
| 1466 | int written = 0; | 
|---|
| 1467 | int paddingReturnValue; | 
|---|
| 1468 | va_list ap; | 
|---|
| 1469 |  | 
|---|
| 1470 | PERF_ENTRY(vfprintf); | 
|---|
| 1471 |  | 
|---|
| 1472 | va_copy(ap, aparg); | 
|---|
| 1473 |  | 
|---|
| 1474 | while (*Fmt) | 
|---|
| 1475 | { | 
|---|
| 1476 | if (*Fmt == '%' && | 
|---|
| 1477 | TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags, | 
|---|
| 1478 | &Width, &Precision, | 
|---|
| 1479 | &Prefix, &Type)) | 
|---|
| 1480 | { | 
|---|
| 1481 | if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING) | 
|---|
| 1482 | { | 
|---|
| 1483 | if (WIDTH_STAR == Width) | 
|---|
| 1484 | { | 
|---|
| 1485 | Width = va_arg(ap, INT); | 
|---|
| 1486 | } | 
|---|
| 1487 | else if (WIDTH_INVALID == Width) | 
|---|
| 1488 | { | 
|---|
| 1489 | /* both a '*' and a number, ignore, but remove arg */ | 
|---|
| 1490 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1491 | } | 
|---|
| 1492 |  | 
|---|
| 1493 | if (PRECISION_STAR == Precision) | 
|---|
| 1494 | { | 
|---|
| 1495 | Precision = va_arg(ap, INT); | 
|---|
| 1496 | } | 
|---|
| 1497 | else if (PRECISION_INVALID == Precision) | 
|---|
| 1498 | { | 
|---|
| 1499 | /* both a '*' and a number, ignore, but remove arg */ | 
|---|
| 1500 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1501 | } | 
|---|
| 1502 |  | 
|---|
| 1503 | TempWStr = va_arg(ap, LPWSTR); | 
|---|
| 1504 | if (TempWStr == NULL)\ | 
|---|
| 1505 | { | 
|---|
| 1506 | TempWStr = __wnullstring; | 
|---|
| 1507 | } | 
|---|
| 1508 | Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0, | 
|---|
| 1509 | 0, 0, 0); | 
|---|
| 1510 | if (!Length) | 
|---|
| 1511 | { | 
|---|
| 1512 | ASSERT( "WideCharToMultiByte failed.  Error is %d\n", | 
|---|
| 1513 | GetLastError()); | 
|---|
| 1514 | PERF_EXIT(vfprintf); | 
|---|
| 1515 | va_end(ap); | 
|---|
| 1516 | return -1; | 
|---|
| 1517 | } | 
|---|
| 1518 | TempStr = (LPSTR) InternalMalloc(Length); | 
|---|
| 1519 | if (!TempStr) | 
|---|
| 1520 | { | 
|---|
| 1521 | ERROR( "InternalMalloc failed\n"); | 
|---|
| 1522 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); | 
|---|
| 1523 | PERF_EXIT(vfprintf); | 
|---|
| 1524 | va_end(ap); | 
|---|
| 1525 | return -1; | 
|---|
| 1526 | } | 
|---|
| 1527 | if (PRECISION_DOT == Precision) | 
|---|
| 1528 | { | 
|---|
| 1529 | /* copy nothing */ | 
|---|
| 1530 | *TempStr = 0; | 
|---|
| 1531 | Length = 0; | 
|---|
| 1532 | } | 
|---|
| 1533 | else if (Precision > 0 && Precision < Length - 1) | 
|---|
| 1534 | { | 
|---|
| 1535 | Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, | 
|---|
| 1536 | Precision, TempStr, Length, | 
|---|
| 1537 | 0, 0); | 
|---|
| 1538 | if (!Length) | 
|---|
| 1539 | { | 
|---|
| 1540 | ASSERT( "WideCharToMultiByte failed.  Error is %d\n", | 
|---|
| 1541 | GetLastError()); | 
|---|
| 1542 | free(TempStr); | 
|---|
| 1543 | PERF_EXIT(vfprintf); | 
|---|
| 1544 | va_end(ap); | 
|---|
| 1545 | return -1; | 
|---|
| 1546 | } | 
|---|
| 1547 | TempStr[Length] = 0; | 
|---|
| 1548 | Length = Precision; | 
|---|
| 1549 | } | 
|---|
| 1550 | /* copy everything */ | 
|---|
| 1551 | else | 
|---|
| 1552 | { | 
|---|
| 1553 | wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, | 
|---|
| 1554 | TempStr, Length, 0, 0); | 
|---|
| 1555 | if (!wctombResult) | 
|---|
| 1556 | { | 
|---|
| 1557 | ASSERT( "WideCharToMultiByte failed.  Error is %d\n", | 
|---|
| 1558 | GetLastError()); | 
|---|
| 1559 | free(TempStr); | 
|---|
| 1560 | PERF_EXIT(vfprintf); | 
|---|
| 1561 | va_end(ap); | 
|---|
| 1562 | return -1; | 
|---|
| 1563 | } | 
|---|
| 1564 | --Length; /* exclude null char */ | 
|---|
| 1565 | } | 
|---|
| 1566 |  | 
|---|
| 1567 | /* do the padding (if needed)*/ | 
|---|
| 1568 | paddingReturnValue = | 
|---|
| 1569 | Internal_AddPaddingVfprintf(pthrCurrent, stream, TempStr, | 
|---|
| 1570 | Width - Length, Flags); | 
|---|
| 1571 | if (-1 == paddingReturnValue) | 
|---|
| 1572 | { | 
|---|
| 1573 | ERROR( "Internal_AddPaddingVfprintf failed\n"); | 
|---|
| 1574 | free(TempStr); | 
|---|
| 1575 | PERF_EXIT(vfprintf); | 
|---|
| 1576 | va_end(ap); | 
|---|
| 1577 | return -1; | 
|---|
| 1578 | } | 
|---|
| 1579 | written += paddingReturnValue; | 
|---|
| 1580 |  | 
|---|
| 1581 | free(TempStr); | 
|---|
| 1582 | } | 
|---|
| 1583 | else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) | 
|---|
| 1584 | { | 
|---|
| 1585 | CHAR TempBuffer[5]; | 
|---|
| 1586 | if (WIDTH_STAR == Width || | 
|---|
| 1587 | WIDTH_INVALID == Width) | 
|---|
| 1588 | { | 
|---|
| 1589 | /* ignore (because it's a char), and remove arg */ | 
|---|
| 1590 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1591 | } | 
|---|
| 1592 | if (PRECISION_STAR == Precision || | 
|---|
| 1593 | PRECISION_INVALID == Precision) | 
|---|
| 1594 | { | 
|---|
| 1595 | /* ignore (because it's a char), and remove arg */ | 
|---|
| 1596 | TempInt = va_arg(ap, INT); /* value not used */ | 
|---|
| 1597 | } | 
|---|
| 1598 |  | 
|---|
| 1599 | TempWChar = va_arg(ap, int); | 
|---|
| 1600 | Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1, | 
|---|
| 1601 | TempBuffer, sizeof(TempBuffer), | 
|---|
| 1602 | 0, 0); | 
|---|
| 1603 | if (!Length) | 
|---|
| 1604 | { | 
|---|
| 1605 | ASSERT( "WideCharToMultiByte failed.  Error is %d\n", | 
|---|
| 1606 | GetLastError()); | 
|---|
| 1607 | PERF_EXIT(vfprintf); | 
|---|
| 1608 | va_end(ap); | 
|---|
| 1609 | return -1; | 
|---|
| 1610 | } | 
|---|
| 1611 | TempBuffer[Length] = 0; | 
|---|
| 1612 |  | 
|---|
| 1613 | /* do the padding (if needed)*/ | 
|---|
| 1614 | paddingReturnValue = | 
|---|
| 1615 | Internal_AddPaddingVfprintf(pthrCurrent, stream, TempBuffer, | 
|---|
| 1616 | Width - Length, Flags); | 
|---|
| 1617 | if (-1 == paddingReturnValue) | 
|---|
| 1618 | { | 
|---|
| 1619 | ERROR( "Internal_AddPaddingVfprintf failed\n"); | 
|---|
| 1620 | PERF_EXIT(vfprintf); | 
|---|
| 1621 | va_end(ap); | 
|---|
| 1622 | return -1; | 
|---|
| 1623 | } | 
|---|
| 1624 | written += paddingReturnValue; | 
|---|
| 1625 |  | 
|---|
| 1626 | } | 
|---|
| 1627 | /* this places the number of bytes written to the buffer in the | 
|---|
| 1628 | next arg */ | 
|---|
| 1629 | else if (Type == PFF_TYPE_N) | 
|---|
| 1630 | { | 
|---|
| 1631 | if (WIDTH_STAR == Width) | 
|---|
| 1632 | { | 
|---|
| 1633 | Width = va_arg(ap, INT); | 
|---|
| 1634 | } | 
|---|
| 1635 | if (PRECISION_STAR == Precision) | 
|---|
| 1636 | { | 
|---|
| 1637 | Precision = va_arg(ap, INT); | 
|---|
| 1638 | } | 
|---|
| 1639 |  | 
|---|
| 1640 | if (Prefix == PFF_PREFIX_SHORT) | 
|---|
| 1641 | { | 
|---|
| 1642 | *(va_arg(ap, short *)) = written; | 
|---|
| 1643 | } | 
|---|
| 1644 | else | 
|---|
| 1645 | { | 
|---|
| 1646 | *(va_arg(ap, LPLONG)) = written; | 
|---|
| 1647 | } | 
|---|
| 1648 | } | 
|---|
| 1649 | else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0) | 
|---|
| 1650 | { | 
|---|
| 1651 | // Some versions of fprintf don't support 0-padded chars, | 
|---|
| 1652 | // so we handle them here. | 
|---|
| 1653 | char ch[2]; | 
|---|
| 1654 |  | 
|---|
| 1655 | ch[0] = (char) va_arg(ap, int); | 
|---|
| 1656 | ch[1] = '\0'; | 
|---|
| 1657 | Length = 1; | 
|---|
| 1658 | paddingReturnValue = Internal_AddPaddingVfprintf( | 
|---|
| 1659 | pthrCurrent, | 
|---|
| 1660 | stream, | 
|---|
| 1661 | ch, | 
|---|
| 1662 | Width - Length, | 
|---|
| 1663 | Flags); | 
|---|
| 1664 | if (-1 == paddingReturnValue) | 
|---|
| 1665 | { | 
|---|
| 1666 | ERROR( "Internal_AddPaddingVfprintf failed\n"); | 
|---|
| 1667 | PERF_EXIT(vfprintf); | 
|---|
| 1668 | va_end(ap); | 
|---|
| 1669 | return -1; | 
|---|
| 1670 | } | 
|---|
| 1671 | written += paddingReturnValue; | 
|---|
| 1672 | } | 
|---|
| 1673 | else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0) | 
|---|
| 1674 | { | 
|---|
| 1675 | // Some versions of fprintf don't support 0-padded strings, | 
|---|
| 1676 | // so we handle them here. | 
|---|
| 1677 | const char *tempStr; | 
|---|
| 1678 |  | 
|---|
| 1679 | tempStr = va_arg(ap, char *); | 
|---|
| 1680 | if (tempStr == NULL) | 
|---|
| 1681 | { | 
|---|
| 1682 | tempStr = __nullstring; | 
|---|
| 1683 | } | 
|---|
| 1684 | Length = strlen(tempStr); | 
|---|
| 1685 | paddingReturnValue = Internal_AddPaddingVfprintf( | 
|---|
| 1686 | pthrCurrent, | 
|---|
| 1687 | stream, | 
|---|
| 1688 | tempStr, | 
|---|
| 1689 | Width - Length, | 
|---|
| 1690 | Flags); | 
|---|
| 1691 | if (-1 == paddingReturnValue) | 
|---|
| 1692 | { | 
|---|
| 1693 | ERROR( "Internal_AddPaddingVfprintf failed\n"); | 
|---|
| 1694 | PERF_EXIT(vfprintf); | 
|---|
| 1695 | va_end(ap); | 
|---|
| 1696 | return -1; | 
|---|
| 1697 | } | 
|---|
| 1698 | written += paddingReturnValue; | 
|---|
| 1699 | } | 
|---|
| 1700 | else | 
|---|
| 1701 | { | 
|---|
| 1702 | // Types that fprintf can handle. | 
|---|
| 1703 | TempInt = 0; | 
|---|
| 1704 |  | 
|---|
| 1705 | // %h (short) doesn't seem to be handled properly by local sprintf, | 
|---|
| 1706 | // so we do the truncation ourselves for some cases. | 
|---|
| 1707 | if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) | 
|---|
| 1708 | { | 
|---|
| 1709 | // Convert from pointer -> int -> short to avoid warnings. | 
|---|
| 1710 | long trunc1; | 
|---|
| 1711 | short trunc2; | 
|---|
| 1712 |  | 
|---|
| 1713 | trunc1 = va_arg(ap, LONG); | 
|---|
| 1714 | trunc2 = (short)trunc1; | 
|---|
| 1715 | trunc1 = trunc2; | 
|---|
| 1716 |  | 
|---|
| 1717 | TempInt = fprintf(stream->bsdFilePtr, TempBuff, trunc1); | 
|---|
| 1718 | } | 
|---|
| 1719 | else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) | 
|---|
| 1720 | { | 
|---|
| 1721 | // Convert explicitly from int to short to get | 
|---|
| 1722 | // correct sign extension for shorts on all systems. | 
|---|
| 1723 | int n; | 
|---|
| 1724 | short s; | 
|---|
| 1725 |  | 
|---|
| 1726 | n = va_arg(ap, int); | 
|---|
| 1727 | s = (short) n; | 
|---|
| 1728 |  | 
|---|
| 1729 | TempInt = fprintf( stream->bsdFilePtr, TempBuff, s); | 
|---|
| 1730 | } | 
|---|
| 1731 | else | 
|---|
| 1732 | { | 
|---|
| 1733 | va_list apcopy; | 
|---|
| 1734 | va_copy(apcopy, ap); | 
|---|
| 1735 | TempInt = vfprintf(stream->bsdFilePtr, TempBuff, apcopy); | 
|---|
| 1736 | va_end(apcopy); | 
|---|
| 1737 | PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); | 
|---|
| 1738 | } | 
|---|
| 1739 |  | 
|---|
| 1740 | if (-1 == TempInt) | 
|---|
| 1741 | { | 
|---|
| 1742 | ERROR( "vfprintf returned an error\n"); | 
|---|
| 1743 | } | 
|---|
| 1744 | else | 
|---|
| 1745 | { | 
|---|
| 1746 | written += TempInt; | 
|---|
| 1747 | } | 
|---|
| 1748 | } | 
|---|
| 1749 | } | 
|---|
| 1750 | else | 
|---|
| 1751 | { | 
|---|
| 1752 |  | 
|---|
| 1753 | #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL | 
|---|
| 1754 | clearerr (stream->bsdFilePtr); | 
|---|
| 1755 | #endif | 
|---|
| 1756 |  | 
|---|
| 1757 | InternalFwrite(Fmt++, 1, 1, stream->bsdFilePtr, &stream->PALferrorCode); /* copy regular chars into buffer */ | 
|---|
| 1758 | if (stream->PALferrorCode == PAL_FILE_ERROR) | 
|---|
| 1759 | { | 
|---|
| 1760 | ERROR( "fwrite() failed with errno == %d\n", errno); | 
|---|
| 1761 | PERF_EXIT(vfprintf); | 
|---|
| 1762 | va_end(ap); | 
|---|
| 1763 | return -1; | 
|---|
| 1764 | } | 
|---|
| 1765 | ++written; | 
|---|
| 1766 | } | 
|---|
| 1767 | } | 
|---|
| 1768 |  | 
|---|
| 1769 | va_end(ap); | 
|---|
| 1770 |  | 
|---|
| 1771 | PERF_EXIT(vfprintf); | 
|---|
| 1772 | return written; | 
|---|
| 1773 | } | 
|---|
| 1774 |  | 
|---|