(file) Return to format.c CVS log (file) (dir) Up to [OMI] / omi / pal

  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              

ViewCVS 0.9.2