github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/libc/sprintf.c (about)

     1  /*
     2   * Copyright (c) 2013 Intel Corporation
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *     http://www.apache.org/licenses/LICENSE-2.0
     8   * Unless required by applicable law or agreed to in writing, software
     9   * distributed under the License is distributed on an "AS IS" BASIS,
    10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11   * See the License for the specific language governing permissions and
    12   * limitations under the License.
    13   */
    14  
    15  
    16  #include "common_libc.h"
    17  
    18  // fix for builtin_stdarg
    19  #define __builtin_va_end(p)
    20  #define __builtin_stdarg_start(a,b)
    21  #define __builtin_va_arg(a,p) 0
    22  
    23  #define LEFT_JUSTIFY    0x01
    24  #define PREFIX_SIGN     0x02
    25  #define PREFIX_BLANK    0x04
    26  #define COMMA_TYPE      0x08
    27  #define LONG_TYPE       0x10
    28  #define PREFIX_ZERO     0x20
    29  #define UPHEX           0x40
    30  #define UNSIGNED        0x80
    31  #define ZERO_HEX_PREFIX 0x100
    32  
    33  #if 8 == ARCH_ADDRESS_WIDTH
    34      #define SIZE_T_SIZE_TYPE        LONG_TYPE
    35      // make it 4 also
    36      #define DEFAULT_POINTER_WIDTH   (sizeof(UINT32) * 2)
    37  #else
    38      #define SIZE_T_SIZE_TYPE 0
    39      #define DEFAULT_POINTER_WIDTH   (sizeof(UINT32) * 2)
    40  #endif
    41  
    42  //#define DEFAULT_POINTER_WIDTH   (sizeof(ADDRESS) * 2)
    43  
    44  
    45  #define STRING_CHARS(a) (ARRAY_SIZE(a) - 1)
    46  #define TIME_PLACEHOLDER "99/99/9999  99:99"
    47  #define GUID_PLACEHOLDER "99999999-9999-9999-9999-999999999999"
    48  #define MAX_NUMBER_CHARS 30
    49  
    50  static const char up_hex[]  = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    51  static const char low_hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
    52  static const char decimal[] = {'0','1','2','3','4','5','6','7','8','9'};
    53  
    54  
    55  /*++
    56  Routine Description:
    57    prints an VMM_GUID.
    58  Arguments:
    59    Guid       - Pointer to GUID to print.
    60    Buffer     - Buffe to print Guid into.
    61    BufferSize - Size of Buffer.
    62  Returns:
    63    Number of characters printed.
    64  --*/
    65  static UINT32 safe_guid_to_string ( VMM_GUID* guid, char* buffer, size_t buffer_size )
    66  {
    67      UINT32 size;
    68  
    69      (void)size;
    70      if (buffer_size <= STRING_CHARS(GUID_PLACEHOLDER)) {
    71          // Not enough room for terminating null
    72          return 0;
    73      }
    74  
    75      size = vmm_sprintf_s( buffer, buffer_size, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    76              guid->data1, guid->data2, guid->data3, guid->data4[0], guid->data4[1],
    77              guid->data4[2], guid->data4[3], guid->data4[4], guid->data4[5], guid->data4[6],
    78              guid->data4[7]); 
    79      
    80      // sprintf_s will null terminate the string. The -1 skips the null
    81      return STRING_CHARS(GUID_PLACEHOLDER);
    82  }
    83  
    84  /*++
    85  Routine Description:
    86    worker function that prints a Value as a based number in Buffer
    87  Arguments:
    88    Buffer - Location to place ascii based number string of Value.
    89    Value  - value to convert to a string in Buffer.
    90    Flags  - Flags to use in printing decimal string, see file header for details.
    91    Width  - Width of value.
    92  Returns:
    93    Number of characters printed.
    94  --*/
    95  static UINT32 safe_value_to_string ( char* buffer, UINT32  buffer_limits, INT64  value, 
    96                                UINT32 flags, UINT32 width, UINT32 base, const char* chars)
    97  {
    98      char    temp_buffer[MAX_NUMBER_CHARS];
    99      char*   temp_str;
   100      char*   buffer_ptr;
   101      UINT32  count,comma_count,pre_count;
   102      UINT32  remainder;
   103      char    prefix;
   104      UINT32  index;
   105      UINT32  actual_chars = buffer_limits - 1;
   106      UINT64  uvalue, temp_value;
   107  
   108      //  Sanity
   109      if (buffer_limits > 0) {
   110          //  All is fine
   111      }
   112      else {
   113          return 0;
   114      }
   115  
   116      temp_str = temp_buffer;
   117      buffer_ptr = buffer;
   118      count = 0;
   119      comma_count = 0;
   120      pre_count = 0;
   121      if (actual_chars) {
   122          if (!(flags & UNSIGNED)) {
   123              if (value < 0) {
   124                  *(buffer_ptr++) = '-';
   125                  value = -value;
   126                  pre_count++;
   127              }
   128              else if (flags & PREFIX_SIGN) {
   129                  *(buffer_ptr++) = '+';
   130                  pre_count++;
   131              }
   132              else if (flags & PREFIX_BLANK) {
   133                  *(buffer_ptr++) = ' ';
   134                  pre_count++;
   135              }
   136          }
   137      }
   138  
   139      uvalue = (UINT64)value;
   140      do {
   141          temp_value = uvalue / base;
   142          remainder = (UINT32)(uvalue % base);
   143          uvalue = temp_value;
   144          *(temp_str++) = chars[remainder];
   145          count++;
   146          if ((flags & COMMA_TYPE) == COMMA_TYPE) {
   147              if ((count % 3 == 0) && (MAX_NUMBER_CHARS>(count+comma_count+pre_count))) {
   148                  if ((uvalue != 0) && ((temp_str - temp_buffer + 1) < MAX_NUMBER_CHARS)) {
   149                      *(temp_str++) = ',';
   150                      comma_count++;
   151                  }
   152              }
   153          }
   154      } while ((uvalue != 0) && ((temp_str - temp_buffer) < MAX_NUMBER_CHARS));
   155  
   156      if (flags & PREFIX_ZERO) {
   157          prefix = '0';
   158      }
   159      else if (!(flags & LEFT_JUSTIFY)) {
   160          prefix = ' ';
   161      }
   162      else {
   163          prefix = 0;
   164      }
   165  
   166      if (prefix != 0) {
   167          for (index = count+comma_count+pre_count; index < MIN(width,MAX_NUMBER_CHARS); index++)
   168          {
   169              *(temp_str++) = prefix;
   170          }
   171      }
   172  
   173      // Reverse temp string into Buffer.
   174      while ((temp_str != temp_buffer) && (buffer_limits-- > 0)) {
   175          *(buffer_ptr++) = *(--temp_str);
   176      }
   177  
   178      *buffer_ptr = 0;
   179      return (UINT32)(buffer_ptr - buffer);
   180  }
   181  
   182  static UINT32 safe_value_to_decimal_str ( char*   buffer, UINT32  buffer_limits, INT64 value, 
   183                              UINT32  flags, UINT32  width)
   184  {
   185      return safe_value_to_string( buffer, buffer_limits, value, flags, width, 10, decimal );
   186  }
   187  
   188  static
   189  UINT32 safe_value_to_hex_str ( char* buffer, UINT32  buffer_limits, UINT64  value,
   190                                 UINT32  flags, UINT32  width)
   191  {
   192      UINT32 prefix_size = 0;
   193  
   194      if ((flags & ZERO_HEX_PREFIX) && buffer && (buffer_limits > 2)) {
   195          *(buffer++) = '0';
   196          --buffer_limits;
   197  
   198          if (width != 0) {
   199              --width;
   200          }
   201  
   202          *(buffer++) = 'x';
   203          --buffer_limits;
   204  
   205          if (width != 0) {
   206              --width;
   207          }
   208          prefix_size = 2;
   209      }
   210  
   211      return prefix_size + safe_value_to_string( buffer, buffer_limits, value, flags | UNSIGNED,
   212                                           width, 16, (flags & UPHEX) ? up_hex : low_hex );
   213  }
   214  
   215  /*++
   216  Routine Description:
   217    worker function that prints VMM_TIME.
   218  Arguments:
   219    Time       - Pointer to VMM_TIME sturcture to print.
   220    Buffer     - Buffer to print Time into.
   221    BufferSize - Size of Buffer.
   222  Returns:
   223    Number of characters printed.
   224  --*/
   225  static UINT32 safe_time_to_string ( VMM_TIME* time, char* buffer, UINT32 buffer_size)
   226  {
   227      UINT32 size;
   228  
   229      (void)size;
   230      if (buffer_size <= STRING_CHARS(TIME_PLACEHOLDER)) {
   231          // Not enough room for terminating null
   232          return 0;
   233      }
   234      size = vmm_sprintf_s ( buffer, buffer_size, "%02d/%02d/%04d  %02d:%02d", time->day,
   235              time->month, time->year, time->hour, time->minute);
   236    // Sprint will null terminate the string. The -1 skips the null
   237    return STRING_CHARS(TIME_PLACEHOLDER);
   238  }
   239  
   240  
   241  /*++
   242  Routine Description:
   243    worker function that parses flag and width information from the
   244    Format string and returns the next index into the Format string that needs
   245    to be parsed. See file headed for details of Flag and Width.
   246  Arguments:
   247    Format    - Current location in the VSPrint format string.
   248    Flags     - Returns flags
   249    Width     - Returns width of element
   250    Precision - Returns precision of element
   251    Marker    - Vararg list that may be paritally consumed and returned.
   252  Returns:
   253    Pointer indexed into the Format string for all the information parsed
   254    by this routine.
   255  --*/
   256  static const char* get_flags_and_width_and_precision ( const char* format, UINT32* flags,
   257                  UINT32* width, UINT32* precision,
   258  #ifdef __GNUC__
   259    va_list   marker
   260  #else
   261    va_list*  marker
   262  #endif
   263  )
   264  {
   265      UINT32  count;
   266      BOOLEAN done;
   267      BOOLEAN at_precision;
   268      BOOLEAN done_precision;
   269  
   270      (void)marker;
   271      *flags = 0;
   272      *width = 0;
   273      *precision = 0xFFFF;
   274      at_precision = FALSE;
   275      done_precision = FALSE;
   276  
   277      for (done = FALSE; !done; ) {
   278          format++;
   279  
   280          switch (*format) {
   281              case '-': *flags |= LEFT_JUSTIFY;   break;
   282              case '+': *flags |= PREFIX_SIGN;    break;
   283              case ' ': *flags |= PREFIX_BLANK;   break;
   284              case ',': *flags |= COMMA_TYPE;     break;
   285              case '#': *flags |= ZERO_HEX_PREFIX|PREFIX_ZERO;break;
   286              case 'L':
   287              case 'l': *flags |= LONG_TYPE;      break;
   288              case 'I': *flags |= SIZE_T_SIZE_TYPE;break;
   289  
   290              case '*':
   291                  if (at_precision) {
   292  #ifdef __GNUC__
   293                      *precision = va_arg (marker, UINT32);
   294  #else
   295                      *precision = va_arg (*marker, UINT32);
   296  #endif
   297                  }
   298                  else {
   299  #ifdef __GNUC__
   300                      *width = va_arg (marker, UINT32);
   301  #else
   302                      *width = va_arg (*marker, UINT32);
   303  #endif
   304                  }
   305                  break;
   306  
   307              case '.':
   308                  if (done_precision)
   309                      done = TRUE;
   310                  else {
   311                      at_precision = TRUE;
   312                      done_precision = TRUE;
   313                      *precision = 0;
   314                  }
   315                  break;
   316  
   317              case '0': /* zero is at the number beginning */
   318                  if (! at_precision)
   319                      *flags |= PREFIX_ZERO;
   320                  break;
   321  
   322              case '1':
   323              case '2':
   324              case '3':
   325              case '4':
   326              case '5':
   327              case '6':
   328              case '7':
   329              case '8':
   330              case '9':
   331                  count = 0;
   332                  do {
   333                      count = (count * 10) + *format - '0';
   334                      format++;
   335                  } while ((*format >= '0')  &&  (*format <= '9'));
   336                  format--;
   337                  if (at_precision)
   338                      *precision = count;
   339                  else
   340                      *width = count;
   341                  at_precision = FALSE;
   342                  break;
   343  
   344              default:
   345                done = TRUE;
   346          }
   347      }
   348      return format;
   349  }
   350  
   351  
   352  /*++
   353  Routine Description:
   354    vsprintf_s function to process format and place the results in Buffer. Since a
   355    va_list is used this rountine allows the nesting of Vararg routines. Thus
   356    this is the main print working routine
   357  Arguments:
   358    start_of_buffer   - buffer to print the results of the parsing of Format into.
   359    size_of_buffer    - Maximum number of characters to put into buffer (including
   360                        the terminating null).
   361    format            - Format string see file header for more details.
   362    argptr            - Vararg list consumed by processing format.
   363  Returns:
   364    Number of characters printed.
   365  --*/
   366  int vmm_vsprintf_s( char*  start_of_buffer, size_t size_of_buffer,
   367                              const char* format_string, va_list  argptr )
   368  {
   369      char*       buffer;
   370      const char* format;
   371      char*       ascii_str;
   372      UINT32      chars_written;
   373      UINT32      index;
   374      UINT32      flags;
   375      UINT32      width;
   376      UINT32      precision;   // BUGBUG: Precision is currently used only for strings
   377      UINT32      count;
   378      UINT64      value;
   379      VMM_GUID*   tmp_GUID;
   380  
   381      // Reserve one place for the terminating null
   382      INT32 available_chars = (INT32)(size_of_buffer - 1);
   383      if (! (start_of_buffer && size_of_buffer && format_string && argptr)) {
   384          return -1;
   385      }
   386      if (available_chars == 0) {
   387          // there is only the place for null char
   388          *start_of_buffer = '\0';
   389          return 0;
   390      }
   391  
   392      // Process the format string. Stop if buffer is over run.
   393      buffer = start_of_buffer;
   394      format = format_string;
   395      for (index = 0; (*format != '\0') && (available_chars > 0); ++format) {
   396          if (*format != '%') {
   397              if (*format == '\n' && available_chars > 2) {
   398              //
   399              // If carriage return add line feed
   400              //
   401              buffer[index++] = '\r';
   402              --available_chars;
   403              }
   404              buffer[index++] = *format;
   405              --available_chars;
   406          }
   407          else {
   408              // Now it's time to parse what follows after %
   409              format = get_flags_and_width_and_precision(format, &flags, &width, &precision,
   410  #ifdef __GNUC__
   411                                                         argptr
   412  #else
   413                                                         &argptr
   414  #endif
   415                                                         );
   416              switch (*format) {
   417                  case 'X':   /* HEX UPPER_CASE */
   418                      flags |= UPHEX;
   419                      // break skipped on purpose
   420                  case 'x':   /* HEX LOWER CASE */
   421                      if ((flags & LONG_TYPE) == LONG_TYPE) {
   422                        value = va_arg (argptr, UINT64);
   423                      } else {
   424                        value = (UINT64)va_arg (argptr, UINT32);
   425                      }
   426                      chars_written = safe_value_to_hex_str (&buffer[index], available_chars, value, flags, width);
   427                      if (chars_written == 0) {
   428                        break;
   429                      }
   430                      index += chars_written;
   431                      available_chars -= chars_written;
   432                      break;
   433  
   434                  case 'P':   /* POINTER LOWER CASE */
   435                      flags |= UPHEX;
   436                      // break skipped on purpose
   437                  case 'p':   /* POINTER LOWER CASE */
   438                      flags |= ZERO_HEX_PREFIX|PREFIX_ZERO|SIZE_T_SIZE_TYPE;
   439  
   440                      if (width == 0) {
   441                          // set default width
   442                          width = DEFAULT_POINTER_WIDTH + 2; // 2 - sizeof "0x"
   443                      }
   444  
   445                      if ((flags & LONG_TYPE) == LONG_TYPE) {
   446                        value = va_arg (argptr, UINT64);
   447                      } else {
   448                        value = (UINT64)va_arg (argptr, UINT32);
   449                      }
   450  
   451                      chars_written = safe_value_to_hex_str (&buffer[index], available_chars, value, flags, width);
   452                      if (chars_written == 0) {
   453                        break;
   454                      }
   455  
   456                      index += chars_written;
   457                      available_chars -= chars_written;
   458                      break;
   459  
   460                  case 'u':   /* UNSIGNED DECIMAL */
   461                      flags |= UNSIGNED;
   462                      //
   463                      // break skiped on purpose
   464                      //
   465                  case 'd':   /* SIGNED DECIMAL */
   466                  case 'i':   /* SIGNED DECIMAL */
   467                      if ((flags & LONG_TYPE) == LONG_TYPE) {
   468                        value = va_arg (argptr, INT64);
   469                      } else {
   470                        value = (UINT64)(INT64)va_arg (argptr, INT32);
   471                      }
   472                      chars_written = safe_value_to_decimal_str (&buffer[index], available_chars, value, flags, width);
   473                      if (chars_written == 0) {
   474                        break;
   475                      }
   476                      index += chars_written;
   477                      available_chars -= chars_written;
   478                      break;
   479  
   480                  case 's':   /* ASCII STRING */
   481                      ascii_str = (char*)va_arg (argptr, char*);
   482                      if (ascii_str == NULL) {
   483                        ascii_str = "<null string>";
   484                      }
   485                      for (count = 0 ; (*ascii_str != '\0') &&
   486                             ((0 == width) || (count < width)) && (available_chars > 0) ;
   487                           ascii_str++, count++) {
   488                        available_chars--;
   489                        buffer[index++] = *ascii_str;
   490                      }
   491                      // Add padding if needed
   492                      for (;(count < width) && (available_chars-- > 0); count++) {
   493                        buffer[index++] = ' ';
   494                      }
   495                      break;
   496  
   497                  case 'c':   /* ASCII CHAR */
   498  #ifdef __GNUC__
   499                      buffer[index++] = (char)va_arg (argptr, int);
   500  #else
   501                      buffer[index++] = (char)va_arg (argptr, char);
   502   #endif
   503                      --available_chars;
   504                      break;
   505  
   506                  case 'g':   /* VMM_GUID* */
   507                      tmp_GUID = va_arg (argptr, VMM_GUID *);
   508  
   509                      if (tmp_GUID != NULL) {
   510                          chars_written= safe_guid_to_string (
   511                                  tmp_GUID,
   512                                  &buffer[index],
   513                                  available_chars
   514                                  );
   515                          if (chars_written == 0) {
   516                              break;
   517                          }
   518                          index += chars_written;
   519                          available_chars -= chars_written;
   520                      }
   521                      break;
   522  
   523                  case 't':   /* VMM_TIME* */
   524                      chars_written  = safe_time_to_string ( va_arg (argptr, VMM_TIME *),
   525                                &buffer[index], available_chars);
   526                      if (chars_written == 0) {
   527                          break;
   528                      }
   529                      index += chars_written;
   530                      available_chars -= chars_written;
   531                      break;
   532  
   533                  case '%':   /* % */
   534                      buffer[index++] = *format;
   535                      --available_chars;
   536                      break;
   537  
   538                  default:    /* unknown */
   539                      // if the type is unknown print it to the screen
   540                      buffer[index++] = *format;
   541                      --available_chars;
   542                      break;
   543              }
   544          }
   545      } // for (Index = 0; (*Format != L'\0') && (AvailableChars > 0); ++Format)
   546  
   547      buffer[index] = '\0';
   548      return index;
   549  }
   550  
   551  int vmm_sprintf_s( char *buffer, size_t size_of_buffer, const char *format, ...)
   552  {
   553      va_list marker;
   554  
   555      va_start( marker, format );
   556  
   557      return vmm_vsprintf_s( buffer, size_of_buffer, format, marker );
   558  }
   559  
   560