1 krisbash 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
|
8 krisbash 1.2 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
|
13 krisbash 1.1 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15 krisbash 1.2 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
|
18 krisbash 1.1 **
|
19 krisbash 1.2 ** See the Apache 2 License for the specific language governing permissions
|
20 krisbash 1.1 ** and limitations under the License.
21 **
22 **==============================================================================
23 */
24
25 #include "format.h"
26 #include <pal/strings.h>
27
28 #include <string.h>
29 #include <pal/once.h>
|
30 krisbash 1.2 #include <pal/intsafe.h>
|
31 krisbash 1.1 #include <locale.h>
32
33 char* FixupFormat(
|
34 krisbash 1.2 _Out_writes_z_(size) _Null_terminated_ char* buf,
35 _In_ size_t size,
|
36 krisbash 1.1 _In_z_ const char* fmt)
37 {
38 size_t n = strlen(fmt) + 1;
39 char* start;
40 char* p;
41
42 if (n > size)
43 {
44 start = (char*)SystemMalloc(n * sizeof(char));
45
46 if (!start)
47 return NULL;
48 }
49 else
50 start = buf;
51
52 for (p = start; *fmt; )
53 {
54 if (fmt[0] == '%' && fmt[1] == 'T')
55 {
56 *p++ = '%';
57 krisbash 1.1 #if defined(CONFIG_ENABLE_WCHAR)
58 *p++ = 'S';
59 #else
60 *p++ = 's';
61 #endif
62 fmt += 2;
63 }
64 else
65 *p++ = *fmt++;
66 }
67
68 *p = '\0';
69
70 return start;
71 }
72
73 int Printf(
|
74 krisbash 1.2 const char* format,
|
75 krisbash 1.1 ...)
76 {
77 va_list ap;
78 int r;
79
80 memset(&ap, 0, sizeof(ap));
81 va_start(ap, format);
82 r = Vfprintf(stdout, format, ap);
83 va_end(ap);
84
85 return r;
86 }
87
88 int Fprintf(
|
89 krisbash 1.2 FILE* os,
90 const char* format,
|
91 krisbash 1.1 ...)
92 {
93 va_list ap;
94 int r;
95
96 memset(&ap, 0, sizeof(ap));
97 va_start(ap, format);
98 r = Vfprintf(os, format, ap);
99 va_end(ap);
100
101 return r;
102 }
103
104 _Use_decl_annotations_
105 int Snprintf(
|
106 krisbash 1.2 char* buffer,
107 size_t size,
108 const char* format,
|
109 krisbash 1.1 ...)
110 {
111 va_list ap;
112 int r;
113
114 va_start(ap, format);
115 r = Vsnprintf(buffer, size, format, ap);
116 va_end(ap);
117
118 return r;
119 }
120
121 _Use_decl_annotations_
122 int Snprintf_CultureInvariant(
|
123 krisbash 1.2 char* buffer,
124 size_t size,
125 const char* format,
|
126 krisbash 1.1 ...)
127 {
128 va_list ap;
129 int r;
130
131 va_start(ap, format);
132 r = Vsnprintf_CultureInvariant(buffer, size, format, ap);
133 va_end(ap);
134
135 return r;
136 }
137
138 int Vprintf(
|
139 krisbash 1.2 const char* format,
|
140 krisbash 1.1 va_list ap)
141 {
142 return Vfprintf(stdout, format, ap);
143 }
144
145 int Vfprintf(
146 FILE* os,
|
147 krisbash 1.2 const char* format,
|
148 krisbash 1.1 va_list ap)
149 {
150 int r;
151 char buf[128];
152 char* fmt;
153
154 memset(&buf, 0, sizeof(buf));
155
156 fmt = FixupFormat(buf, PAL_COUNT(buf), format);
157
158 if (!fmt)
159 return -1;
160
161 r = vfprintf(os, fmt, ap);
162
163 if (fmt != buf)
164 SystemFree(fmt);
165
166 return r;
167 }
168
169 krisbash 1.1 #if defined(CONFIG_VSNPRINTF_RETURN_MINUSONE_WITH_NULLBUFFER)
170 static int _GetFormattedSize(
|
171 krisbash 1.2 const char* fmt,
|
172 krisbash 1.1 va_list ap)
173 {
174 char buf[128];
175 char* p = buf;
176 size_t n = sizeof buf;
177 int r;
178
179 while ((r = vsnprintf(p, n, fmt, ap)) == -1)
180 {
|
181 krisbash 1.2 if (SizeTMult(n, 2, &n) != S_OK)
182 return -1;
|
183 krisbash 1.1
184 if (p == buf)
185 p = (char*)SystemMalloc(n);
186 else
187 {
188 char* q = (char*)SystemRealloc(p, n);
189
190 if (q != NULL)
191 p = q;
192 }
193 if (p == NULL)
194 return -1;
195
196 if (p != buf)
197 SystemFree(p);
198 }
199 return r;
200 }
201 #endif /* defined(CONFIG_VSNPRINTF_RETURN_MINUSONE_WITH_NULLBUFFER) */
202
203 _Use_decl_annotations_
204 krisbash 1.1 int Vsnprintf(
|
205 krisbash 1.2 char* buffer,
206 size_t size,
207 const char* format,
|
208 krisbash 1.1 va_list ap)
209 {
210 int r;
211 char* fmt;
212 char buf[128];
213
214 memset(&buf, 0, sizeof(buf));
215
216 fmt = FixupFormat(buf, PAL_COUNT(buf), format);
217
218 if (!fmt)
219 {
220 buffer[0] = '\0';
221 return -1;
222 }
223
224 #ifdef _MSC_VER
225 r = _vsnprintf_s(buffer, size, _TRUNCATE, fmt, ap);
226 #else
227 # ifdef __hpux // HP-UX 11.21 and earlier will core dump if buffer is NULL
228 if (buffer == NULL || size == 0)
229 krisbash 1.1 r = _GetFormattedSize(fmt, ap);
230 else
231 # endif
232 r = vsnprintf(buffer, size, fmt, ap);
233 #if defined(CONFIG_VSNPRINTF_RETURN_MINUSONE_WITH_NULLBUFFER) // SUN-SPARC and HP-UX without the UNIX 2003 standard option returns -1
234 if (r == -1) // instead of the needed byte count if size was too small
235 r = _GetFormattedSize(fmt, ap);
236 # endif
237 #endif
238
239 if (fmt != buf)
240 SystemFree(fmt);
241
242 return r;
243 }
244
245 _Use_decl_annotations_
246 int Vsnprintf_CultureInvariant(
|
247 krisbash 1.2 char* buffer,
248 size_t size,
249 const char* format,
|
250 krisbash 1.1 va_list ap)
251 {
252 /* Ideally we would avoid calling setlocale and use _vsprintf_s_l
253 instead. The problem is that _create_locale is not exported on Win7 */
254
255 int r;
256 char oldLocale[128];
257 Strlcpy(oldLocale, setlocale(LC_ALL, NULL), PAL_COUNT(oldLocale));
258 setlocale(LC_ALL, "C");
259 r = Vsnprintf(buffer, size, format, ap);
260 setlocale(LC_ALL, oldLocale);
261 return r;
262 }
263
264 wchar_t* WFixupFormat(
|
265 krisbash 1.2 _Out_writes_z_(size) _Null_terminated_ wchar_t* buf,
266 _In_ size_t size,
|
267 krisbash 1.1 _In_z_ const wchar_t* fmt)
268 {
269 size_t n = wcslen(fmt) + 1;
270 wchar_t* start;
271 wchar_t* p;
272
273 if (n > size)
274 {
|
275 krisbash 1.2 size_t allocSize;
276 if (SizeTMult(n, sizeof(wchar_t), &allocSize) != S_OK)
277 return NULL;
278
279 start = (wchar_t*)SystemMalloc(allocSize);
|
280 krisbash 1.1
281 if (!start)
282 return NULL;
283 }
284 else
285 start = buf;
286
287 for (p = start; *fmt; )
288 {
289 if (fmt[0] == '%' && fmt[1] == 'T')
290 {
291 *p++ = '%';
292 #if defined(CONFIG_ENABLE_WCHAR)
293 # if defined(_MSC_VER)
294 *p++ = 's';
295 # else
296 *p++ = 'S';
297 # endif
298 #else
299 # if defined(_MSC_VER)
300 *p++ = 'S';
301 krisbash 1.1 # else
302 *p++ = 's';
303 # endif
304 #endif
305 fmt += 2;
306 }
307 #if defined(_MSC_VER)
308 else if (fmt[0] == '%' && fmt[1] == 's')
309 {
310 *p++ = '%';
311 *p++ = 'S';
312 fmt += 2;
313 }
314 else if (fmt[0] == '%' && fmt[1] == 'S')
315 {
316 *p++ = '%';
317 *p++ = 's';
318 fmt += 2;
319 }
320 #endif
321 else
322 krisbash 1.1 *p++ = *fmt++;
323 }
324
325 *p = '\0';
326
327 return start;
328 }
329
330 int Wprintf(
|
331 krisbash 1.2 const wchar_t* format,
|
332 krisbash 1.1 ...)
333 {
334 va_list ap;
335 int r;
336
337 memset(&ap, 0, sizeof(ap));
338 va_start(ap, format);
339 r = Vfwprintf(stdout, format, ap);
340 va_end(ap);
341
342 return r;
343 }
344
345 int Fwprintf(
|
346 krisbash 1.2 FILE* os,
347 const wchar_t* format,
|
348 krisbash 1.1 ...)
349 {
350 va_list ap;
351 int r;
352
353 memset(&ap, 0, sizeof(ap));
354 va_start(ap, format);
355 r = Vfwprintf(os, format, ap);
356 va_end(ap);
357
358 return r;
359 }
360
361 _Use_decl_annotations_
362 int Swprintf(
|
363 krisbash 1.2 wchar_t* buffer,
364 size_t size,
365 const wchar_t* format,
|
366 krisbash 1.1 ...)
367 {
368 va_list ap;
369 int r;
370
371 va_start(ap, format);
372 r = Vswprintf(buffer, size, format, ap);
373 va_end(ap);
374
375 return r;
376 }
377
378 _Use_decl_annotations_
379 int Swprintf_CultureInvariant(
|
380 krisbash 1.2 wchar_t* buffer,
381 size_t size,
382 const wchar_t* format,
|
383 krisbash 1.1 ...)
384 {
385 va_list ap;
386 int r;
387
388 va_start(ap, format);
389 r = Vswprintf_CultureInvariant(buffer, size, format, ap);
390 va_end(ap);
391
392 return r;
393 }
394
395 int Vwprintf(
|
396 krisbash 1.2 const wchar_t* format,
|
397 krisbash 1.1 va_list ap)
398 {
399 return Vfwprintf(stdout, format, ap);
400 }
401
402 int Vfwprintf(
403 FILE* os,
|
404 krisbash 1.2 const wchar_t* format,
|
405 krisbash 1.1 va_list ap)
406 {
407 int r;
408 wchar_t buf[128];
409 wchar_t* fmt;
410
411 memset(&buf, 0, sizeof(buf));
412
413 fmt = WFixupFormat(buf, PAL_COUNT(buf), format);
414
415 if (!fmt)
416 return -1;
417
418 r = vfwprintf(os, fmt, ap);
419
420 if (fmt != buf)
421 SystemFree(fmt);
422
423 return r;
424 }
425
426 krisbash 1.1 _Use_decl_annotations_
427 int Vswprintf(
|
428 krisbash 1.2 wchar_t* buffer,
429 size_t size,
430 const wchar_t* format,
|
431 krisbash 1.1 va_list ap)
432 {
433 int r;
434 wchar_t* fmt;
435 wchar_t buf[128];
436
437 memset(&buf, 0, sizeof(buf));
438
439 fmt = WFixupFormat(buf, PAL_COUNT(buf), format);
440
441 if (!fmt)
442 {
443 buffer[0] = '\0';
444 return -1;
445 }
446
447 #ifdef _MSC_VER
448 r = vswprintf_s(buffer, size, fmt, ap);
449 #else
450 r = vswprintf(buffer, size, fmt, ap);
451 #endif
452 krisbash 1.1
453 if (fmt != buf)
454 SystemFree(fmt);
455
456 return r;
457 }
458
459 _Use_decl_annotations_
460 int Vswprintf_CultureInvariant(
|
461 krisbash 1.2 wchar_t* buffer,
462 size_t size,
463 const wchar_t* format,
|
464 krisbash 1.1 va_list ap)
465 {
466 /* Ideally we would avoid calling setlocale and use _vswprintf_s_l
467 instead. The problem is that _create_locale is not exported on Win7. */
468
469 int r;
|
470 krisbash 1.2 #ifdef _MSC_VER
|
471 krisbash 1.1 wchar_t oldLocale[128];
472 Wcslcpy(oldLocale, _wsetlocale(LC_ALL, NULL), PAL_COUNT(oldLocale));
473 _wsetlocale(LC_ALL, L"C");
474 #else
475 char oldLocale[128];
476 Strlcpy(oldLocale, setlocale(LC_ALL, NULL), PAL_COUNT(oldLocale));
477 setlocale(LC_ALL, "C");
478 #endif
479 r = Vswprintf(buffer, size, format, ap);
480 #ifdef _MSC_VER
481 _wsetlocale(LC_ALL, oldLocale);
482 #else
483 setlocale(LC_ALL, oldLocale);
484 #endif
485 return r;
486 }
487
488 _Use_decl_annotations_
489 int Sscanf_CultureInvariant(
|
490 krisbash 1.2 const char* buffer,
491 const char* format,
|
492 krisbash 1.1 ...)
493 {
494 va_list ap;
495 int r;
496
497 va_start(ap, format);
498 r = Vsscanf_CultureInvariant(buffer, format, ap);
499 va_end(ap);
500
501 return r;
502 }
503
504 _Use_decl_annotations_
505 int Vsscanf_CultureInvariant(
|
506 krisbash 1.2 const char* buffer,
507 const char* format,
|
508 krisbash 1.1 va_list ap)
509 {
510 int r;
511 char* fmt;
512 char buf[128];
513
514 memset(&buf, 0, sizeof(buf));
515
516 fmt = FixupFormat(buf, PAL_COUNT(buf), format);
517
518 if (!fmt)
519 {
520 return EOF;
521 }
522
523 {
524 /* Ideally we would avoid calling setlocale and use _sscanf_l
525 instead. The problem is that _create_locale is not exported on Win7 */
526 char oldLocale[128];
527 Strlcpy(oldLocale, setlocale(LC_ALL, NULL), PAL_COUNT(oldLocale));
528 setlocale(LC_ALL, "C");
529 krisbash 1.1 #ifdef _MSC_VER
530 {
531 /* no *v*scanf on Windows and some older UNIXes... using a workaround instead */
|
532 krisbash 1.2 void *args[10] = {0};
|
533 krisbash 1.1 int numberOfFormatSpecifiers = 0;
534 const char *c;
535
536 for (c = format; c[0] != '\0'; c++)
537 {
538 if (c[0] == '%')
539 {
540 if ((c[1] == '%') || (c[1] == '*'))
541 {
542 c++;
543 }
544 else
545 {
546 if (numberOfFormatSpecifiers >= 10)
547 {
548 r = EOF;
549 goto CleanUp;
550 }
551 args[numberOfFormatSpecifiers] = va_arg(ap, void*);
552 numberOfFormatSpecifiers++;
553 }
554 krisbash 1.1 }
555 }
556
557 r = sscanf_s(
|
558 krisbash 1.2 buffer, fmt,
|
559 krisbash 1.1 args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
560 }
561 CleanUp:
562 #else
563 r = vsscanf(buffer, fmt, ap);
564 #endif
565 setlocale(LC_ALL, oldLocale);
566 }
567
568 if (fmt != buf)
569 SystemFree(fmt);
570
571 return r;
572 }
573
574
575 _Use_decl_annotations_
576 int Swscanf_CultureInvariant(
|
577 krisbash 1.2 const wchar_t* buffer,
578 const wchar_t* format,
|
579 krisbash 1.1 ...)
580 {
581 va_list ap;
582 int r;
583
584 va_start(ap, format);
585 r = Vswscanf_CultureInvariant(buffer, format, ap);
586 va_end(ap);
587
588 return r;
589 }
590
591 _Use_decl_annotations_
592 int Vswscanf_CultureInvariant(
|
593 krisbash 1.2 const wchar_t* buffer,
594 const wchar_t* format,
|
595 krisbash 1.1 va_list ap)
596 {
597 int r;
598 wchar_t* fmt;
599 wchar_t buf[128];
600
601 memset(&buf, 0, sizeof(buf));
602
603 fmt = WFixupFormat(buf, PAL_COUNT(buf), format);
604
605 if (!fmt)
606 {
607 return EOF;
608 }
609
610 {
611 /* TODO/FIXME - ideally we would avoid calling setlocale and use _swscanf_l
612 instead. The problem is that _create_locale is not exported on Win7 */
613 #ifndef CONFIG_HAVE_VSWSCANF
614 # ifdef _MSC_VER
615 wchar_t oldLocale[128];
616 krisbash 1.1 Wcslcpy(oldLocale, _wsetlocale(LC_ALL, NULL), PAL_COUNT(oldLocale));
617 _wsetlocale(LC_ALL, L"C");
618 # else
619 char oldLocale[128];
620 Strlcpy(oldLocale, setlocale(LC_ALL, NULL), sizeof oldLocale);
621 setlocale(LC_ALL, "C");
622 # endif
623 {
624 /* no *v*scanf on Windows... using a workaround instead */
|
625 krisbash 1.2 void *args[10] = {0};
|
626 krisbash 1.1 int numberOfFormatSpecifiers = 0;
627 const wchar_t *c;
628
629 for (c = format; c[0] != L'\0'; c++)
630 {
631 if (c[0] == L'%')
632 {
633 if ((c[1] == L'%') || (c[1] == L'*'))
634 {
635 c++;
636 }
637 else
638 {
639 if (numberOfFormatSpecifiers >= 10)
640 {
641 r = EOF;
642 goto CleanUp;
643 }
644 args[numberOfFormatSpecifiers] = va_arg(ap, void*);
645 numberOfFormatSpecifiers++;
646 }
647 krisbash 1.1 }
648 }
649 # ifdef _MSC_VER
650 r = swscanf_s(
|
651 krisbash 1.2 buffer, fmt,
|
652 krisbash 1.1 args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
653 # else
654 r = swscanf(
|
655 krisbash 1.2 buffer, fmt,
|
656 krisbash 1.1 args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
657 # endif
658 }
|
659 krisbash 1.2
|
660 krisbash 1.1 CleanUp:
661 # ifdef _MSC_VER
|
662 krisbash 1.2 _wsetlocale(LC_ALL, oldLocale);
|
663 krisbash 1.1 # else
|
664 krisbash 1.2 setlocale(LC_ALL, oldLocale);
|
665 krisbash 1.1 # endif
666 #else
667 char oldLocale[128];
668 Strlcpy(oldLocale, setlocale(LC_ALL, NULL), PAL_COUNT(oldLocale));
669 setlocale(LC_ALL, "C");
670 r = vswscanf(buffer, fmt, ap);
|
671 krisbash 1.2 setlocale(LC_ALL, oldLocale);
|
672 krisbash 1.1 #endif
673 }
674
675 if (fmt != buf)
676 SystemFree(fmt);
677
678 return r;
679 }
680
681 PAL_Char* Vstprintf_StrDup(_In_z_ const PAL_Char* templateString, va_list ap)
682 {
683 PAL_Char* resultString = NULL;
684 int resultCharCount;
685 int err;
686 va_list tmpAp;
687
688 #if defined(CONFIG_ENABLE_WCHAR)
|
689 krisbash 1.2 /* on Linux, if stackBuffer is too small, then
|
690 krisbash 1.1 1. snprintf returns the number of required characters
691 2. swnprintf returns -1 (arrgh!)
692 for #2 we need to loop to find the required size...
693 */
694 resultCharCount = 16;
|
695 krisbash 1.2 do
|
696 krisbash 1.1 {
697 PAL_Char* tmp = (PAL_Char*)PAL_Realloc(
698 resultString, sizeof(PAL_Char) * resultCharCount);
699
700 if (!tmp)
701 {
702 PAL_Free(resultString);
703 resultString = NULL;
704 goto CleanUp;
705 }
706 resultString = tmp;
707
708 PAL_va_copy(tmpAp, ap);
709 err = Vstprintf(resultString, resultCharCount, templateString, tmpAp);
710 va_end(tmpAp);
711 if (err < 0)
712 {
713 if (resultCharCount < ( ((size_t)-1) / (2*sizeof(PAL_Char)) ))
714 {
715 resultCharCount *= 2;
716 continue;
717 krisbash 1.1 }
718 else
719 {
720 PAL_Free(resultString);
721 resultString = NULL;
722 goto CleanUp;
723 }
724 }
725 }
726 while (err < 0);
727 #else /* !defined(CONFIG_ENABLE_WCHAR) || defined(_MSC_VER) */
728 PAL_va_copy(tmpAp, ap);
729 resultCharCount = Vstprintf(NULL, 0, templateString, tmpAp);
730 va_end(tmpAp);
731 if (resultCharCount < 0)
732 {
733 goto CleanUp;
734 }
735 else
736 {
737 resultString = (PAL_Char*)PAL_Malloc(sizeof(PAL_Char) * (resultCharCount + 1));
738 krisbash 1.1
739 if (!resultString)
740 {
741 goto CleanUp;
742 }
743
744 err = Vstprintf(resultString, resultCharCount + 1, templateString, ap);
745 if ((0 <= err) && (err <= resultCharCount))
746 {
747 resultString[resultCharCount] = PAL_T('\0');
748 }
749 else
750 {
751 PAL_Free(resultString);
752 resultString = NULL;
753 goto CleanUp;
754 }
755 }
756 #endif /* ?defined(CONFIG_ENABLE_WCHAR) ?defined(_MSC_VER) */
757 CleanUp:
758 return resultString;
759 krisbash 1.1 }
760
761 PAL_Char* Stprintf_StrDup(_In_z_ const PAL_Char* templateString, ...)
762 {
763 PAL_Char* resultString = NULL;
|
764 krisbash 1.2 va_list ap;
|
765 krisbash 1.1
|
766 krisbash 1.2 va_start(ap, templateString);
|
767 krisbash 1.1 resultString = Vstprintf_StrDup(templateString, ap);
|
768 krisbash 1.2 va_end(ap);
|
769 krisbash 1.1 return resultString;
770 }
771
|