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

ViewCVS 0.9.2