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