715 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: utprint - Formatted printing routines5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12 13#define _COMPONENT ACPI_UTILITIES14ACPI_MODULE_NAME("utprint")15 16#define ACPI_FORMAT_SIGN 0x0117#define ACPI_FORMAT_SIGN_PLUS 0x0218#define ACPI_FORMAT_SIGN_PLUS_SPACE 0x0419#define ACPI_FORMAT_ZERO 0x0820#define ACPI_FORMAT_LEFT 0x1021#define ACPI_FORMAT_UPPER 0x2022#define ACPI_FORMAT_PREFIX 0x4023/* Local prototypes */24static acpi_size25acpi_ut_bound_string_length(const char *string, acpi_size count);26 27static char *acpi_ut_bound_string_output(char *string, const char *end, char c);28 29static char *acpi_ut_format_number(char *string,30 char *end,31 u64 number,32 u8 base, s32 width, s32 precision, u8 type);33 34static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper);35 36/*******************************************************************************37 *38 * FUNCTION: acpi_ut_bound_string_length39 *40 * PARAMETERS: string - String with boundary41 * count - Boundary of the string42 *43 * RETURN: Length of the string. Less than or equal to Count.44 *45 * DESCRIPTION: Calculate the length of a string with boundary.46 *47 ******************************************************************************/48 49static acpi_size50acpi_ut_bound_string_length(const char *string, acpi_size count)51{52 u32 length = 0;53 54 while (*string && count) {55 length++;56 string++;57 count--;58 }59 60 return (length);61}62 63/*******************************************************************************64 *65 * FUNCTION: acpi_ut_bound_string_output66 *67 * PARAMETERS: string - String with boundary68 * end - Boundary of the string69 * c - Character to be output to the string70 *71 * RETURN: Updated position for next valid character72 *73 * DESCRIPTION: Output a character into a string with boundary check.74 *75 ******************************************************************************/76 77static char *acpi_ut_bound_string_output(char *string, const char *end, char c)78{79 80 if (string < end) {81 *string = c;82 }83 84 ++string;85 return (string);86}87 88/*******************************************************************************89 *90 * FUNCTION: acpi_ut_put_number91 *92 * PARAMETERS: string - Buffer to hold reverse-ordered string93 * number - Integer to be converted94 * base - Base of the integer95 * upper - Whether or not using upper cased digits96 *97 * RETURN: Updated position for next valid character98 *99 * DESCRIPTION: Convert an integer into a string, note that, the string holds a100 * reversed ordered number without the trailing zero.101 *102 ******************************************************************************/103 104static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper)105{106 const char *digits;107 u64 digit_index;108 char *pos;109 110 pos = string;111 digits = upper ? acpi_gbl_upper_hex_digits : acpi_gbl_lower_hex_digits;112 113 if (number == 0) {114 *(pos++) = '0';115 } else {116 while (number) {117 (void)acpi_ut_divide(number, base, &number,118 &digit_index);119 *(pos++) = digits[digit_index];120 }121 }122 123 /* *(Pos++) = '0'; */124 return (pos);125}126 127/*******************************************************************************128 *129 * FUNCTION: acpi_ut_scan_number130 *131 * PARAMETERS: string - String buffer132 * number_ptr - Where the number is returned133 *134 * RETURN: Updated position for next valid character135 *136 * DESCRIPTION: Scan a string for a decimal integer.137 *138 ******************************************************************************/139 140const char *acpi_ut_scan_number(const char *string, u64 *number_ptr)141{142 u64 number = 0;143 144 while (isdigit((int)*string)) {145 acpi_ut_short_multiply(number, 10, &number);146 number += *(string++) - '0';147 }148 149 *number_ptr = number;150 return (string);151}152 153/*******************************************************************************154 *155 * FUNCTION: acpi_ut_print_number156 *157 * PARAMETERS: string - String buffer158 * number - The number to be converted159 *160 * RETURN: Updated position for next valid character161 *162 * DESCRIPTION: Print a decimal integer into a string.163 *164 ******************************************************************************/165 166const char *acpi_ut_print_number(char *string, u64 number)167{168 char ascii_string[20];169 const char *pos1;170 char *pos2;171 172 pos1 = acpi_ut_put_number(ascii_string, number, 10, FALSE);173 pos2 = string;174 175 while (pos1 != ascii_string) {176 *(pos2++) = *(--pos1);177 }178 179 *pos2 = 0;180 return (string);181}182 183/*******************************************************************************184 *185 * FUNCTION: acpi_ut_format_number186 *187 * PARAMETERS: string - String buffer with boundary188 * end - Boundary of the string189 * number - The number to be converted190 * base - Base of the integer191 * width - Field width192 * precision - Precision of the integer193 * type - Special printing flags194 *195 * RETURN: Updated position for next valid character196 *197 * DESCRIPTION: Print an integer into a string with any base and any precision.198 *199 ******************************************************************************/200 201static char *acpi_ut_format_number(char *string,202 char *end,203 u64 number,204 u8 base, s32 width, s32 precision, u8 type)205{206 char *pos;207 char sign;208 char zero;209 u8 need_prefix;210 u8 upper;211 s32 i;212 char reversed_string[66];213 214 /* Parameter validation */215 216 if (base < 2 || base > 16) {217 return (NULL);218 }219 220 if (type & ACPI_FORMAT_LEFT) {221 type &= ~ACPI_FORMAT_ZERO;222 }223 224 need_prefix = ((type & ACPI_FORMAT_PREFIX)225 && base != 10) ? TRUE : FALSE;226 upper = (type & ACPI_FORMAT_UPPER) ? TRUE : FALSE;227 zero = (type & ACPI_FORMAT_ZERO) ? '0' : ' ';228 229 /* Calculate size according to sign and prefix */230 231 sign = '\0';232 if (type & ACPI_FORMAT_SIGN) {233 if ((s64)number < 0) {234 sign = '-';235 number = -(s64)number;236 width--;237 } else if (type & ACPI_FORMAT_SIGN_PLUS) {238 sign = '+';239 width--;240 } else if (type & ACPI_FORMAT_SIGN_PLUS_SPACE) {241 sign = ' ';242 width--;243 }244 }245 if (need_prefix) {246 width--;247 if (base == 16) {248 width--;249 }250 }251 252 /* Generate full string in reverse order */253 254 pos = acpi_ut_put_number(reversed_string, number, base, upper);255 i = (s32)ACPI_PTR_DIFF(pos, reversed_string);256 257 /* Printing 100 using %2d gives "100", not "00" */258 259 if (i > precision) {260 precision = i;261 }262 263 width -= precision;264 265 /* Output the string */266 267 if (!(type & (ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT))) {268 while (--width >= 0) {269 string = acpi_ut_bound_string_output(string, end, ' ');270 }271 }272 if (sign) {273 string = acpi_ut_bound_string_output(string, end, sign);274 }275 if (need_prefix) {276 string = acpi_ut_bound_string_output(string, end, '0');277 if (base == 16) {278 string =279 acpi_ut_bound_string_output(string, end,280 upper ? 'X' : 'x');281 }282 }283 if (!(type & ACPI_FORMAT_LEFT)) {284 while (--width >= 0) {285 string = acpi_ut_bound_string_output(string, end, zero);286 }287 }288 289 while (i <= --precision) {290 string = acpi_ut_bound_string_output(string, end, '0');291 }292 while (--i >= 0) {293 string = acpi_ut_bound_string_output(string, end,294 reversed_string[i]);295 }296 while (--width >= 0) {297 string = acpi_ut_bound_string_output(string, end, ' ');298 }299 300 return (string);301}302 303/*******************************************************************************304 *305 * FUNCTION: vsnprintf306 *307 * PARAMETERS: string - String with boundary308 * size - Boundary of the string309 * format - Standard printf format310 * args - Argument list311 *312 * RETURN: Number of bytes actually written.313 *314 * DESCRIPTION: Formatted output to a string using argument list pointer.315 *316 ******************************************************************************/317 318int vsnprintf(char *string, acpi_size size, const char *format, va_list args)319{320 u8 base;321 u8 type;322 s32 width;323 s32 precision;324 char qualifier;325 u64 number;326 char *pos;327 char *end;328 char c;329 const char *s;330 const void *p;331 s32 length;332 int i;333 334 pos = string;335 336 if (size != ACPI_UINT32_MAX) {337 end = string + size;338 } else {339 end = ACPI_CAST_PTR(char, ACPI_UINT32_MAX);340 }341 342 for (; *format; ++format) {343 if (*format != '%') {344 pos = acpi_ut_bound_string_output(pos, end, *format);345 continue;346 }347 348 type = 0;349 base = 10;350 351 /* Process sign */352 353 do {354 ++format;355 if (*format == '#') {356 type |= ACPI_FORMAT_PREFIX;357 } else if (*format == '0') {358 type |= ACPI_FORMAT_ZERO;359 } else if (*format == '+') {360 type |= ACPI_FORMAT_SIGN_PLUS;361 } else if (*format == ' ') {362 type |= ACPI_FORMAT_SIGN_PLUS_SPACE;363 } else if (*format == '-') {364 type |= ACPI_FORMAT_LEFT;365 } else {366 break;367 }368 369 } while (1);370 371 /* Process width */372 373 width = -1;374 if (isdigit((int)*format)) {375 format = acpi_ut_scan_number(format, &number);376 width = (s32)number;377 } else if (*format == '*') {378 ++format;379 width = va_arg(args, int);380 if (width < 0) {381 width = -width;382 type |= ACPI_FORMAT_LEFT;383 }384 }385 386 /* Process precision */387 388 precision = -1;389 if (*format == '.') {390 ++format;391 if (isdigit((int)*format)) {392 format = acpi_ut_scan_number(format, &number);393 precision = (s32)number;394 } else if (*format == '*') {395 ++format;396 precision = va_arg(args, int);397 }398 399 if (precision < 0) {400 precision = 0;401 }402 }403 404 /* Process qualifier */405 406 qualifier = -1;407 if (*format == 'h' || *format == 'l' || *format == 'L') {408 qualifier = *format;409 ++format;410 411 if (qualifier == 'l' && *format == 'l') {412 qualifier = 'L';413 ++format;414 }415 }416 417 switch (*format) {418 case '%':419 420 pos = acpi_ut_bound_string_output(pos, end, '%');421 continue;422 423 case 'c':424 425 if (!(type & ACPI_FORMAT_LEFT)) {426 while (--width > 0) {427 pos =428 acpi_ut_bound_string_output(pos,429 end,430 ' ');431 }432 }433 434 c = (char)va_arg(args, int);435 pos = acpi_ut_bound_string_output(pos, end, c);436 437 while (--width > 0) {438 pos =439 acpi_ut_bound_string_output(pos, end, ' ');440 }441 continue;442 443 case 's':444 445 s = va_arg(args, char *);446 if (!s) {447 s = "<NULL>";448 }449 length = (s32)acpi_ut_bound_string_length(s, precision);450 if (!(type & ACPI_FORMAT_LEFT)) {451 while (length < width--) {452 pos =453 acpi_ut_bound_string_output(pos,454 end,455 ' ');456 }457 }458 459 for (i = 0; i < length; ++i) {460 pos = acpi_ut_bound_string_output(pos, end, *s);461 ++s;462 }463 464 while (length < width--) {465 pos =466 acpi_ut_bound_string_output(pos, end, ' ');467 }468 continue;469 470 case 'o':471 472 base = 8;473 break;474 475 case 'X':476 477 type |= ACPI_FORMAT_UPPER;478 ACPI_FALLTHROUGH;479 480 case 'x':481 482 base = 16;483 break;484 485 case 'd':486 case 'i':487 488 type |= ACPI_FORMAT_SIGN;489 490 case 'u':491 492 break;493 494 case 'p':495 496 if (width == -1) {497 width = 2 * sizeof(void *);498 type |= ACPI_FORMAT_ZERO;499 }500 501 p = va_arg(args, void *);502 pos =503 acpi_ut_format_number(pos, end, ACPI_TO_INTEGER(p),504 16, width, precision, type);505 continue;506 507 default:508 509 pos = acpi_ut_bound_string_output(pos, end, '%');510 if (*format) {511 pos =512 acpi_ut_bound_string_output(pos, end,513 *format);514 } else {515 --format;516 }517 continue;518 }519 520 if (qualifier == 'L') {521 number = va_arg(args, u64);522 if (type & ACPI_FORMAT_SIGN) {523 number = (s64)number;524 }525 } else if (qualifier == 'l') {526 number = va_arg(args, unsigned long);527 if (type & ACPI_FORMAT_SIGN) {528 number = (s32)number;529 }530 } else if (qualifier == 'h') {531 number = (u16)va_arg(args, int);532 if (type & ACPI_FORMAT_SIGN) {533 number = (s16)number;534 }535 } else {536 number = va_arg(args, unsigned int);537 if (type & ACPI_FORMAT_SIGN) {538 number = (signed int)number;539 }540 }541 542 pos = acpi_ut_format_number(pos, end, number, base,543 width, precision, type);544 }545 546 if (size > 0) {547 if (pos < end) {548 *pos = '\0';549 } else {550 end[-1] = '\0';551 }552 }553 554 return ((int)ACPI_PTR_DIFF(pos, string));555}556 557/*******************************************************************************558 *559 * FUNCTION: snprintf560 *561 * PARAMETERS: string - String with boundary562 * size - Boundary of the string563 * Format, ... - Standard printf format564 *565 * RETURN: Number of bytes actually written.566 *567 * DESCRIPTION: Formatted output to a string.568 *569 ******************************************************************************/570 571int snprintf(char *string, acpi_size size, const char *format, ...)572{573 va_list args;574 int length;575 576 va_start(args, format);577 length = vsnprintf(string, size, format, args);578 va_end(args);579 580 return (length);581}582 583/*******************************************************************************584 *585 * FUNCTION: sprintf586 *587 * PARAMETERS: string - String with boundary588 * Format, ... - Standard printf format589 *590 * RETURN: Number of bytes actually written.591 *592 * DESCRIPTION: Formatted output to a string.593 *594 ******************************************************************************/595 596int sprintf(char *string, const char *format, ...)597{598 va_list args;599 int length;600 601 va_start(args, format);602 length = vsnprintf(string, ACPI_UINT32_MAX, format, args);603 va_end(args);604 605 return (length);606}607 608#ifdef ACPI_APPLICATION609/*******************************************************************************610 *611 * FUNCTION: vprintf612 *613 * PARAMETERS: format - Standard printf format614 * args - Argument list615 *616 * RETURN: Number of bytes actually written.617 *618 * DESCRIPTION: Formatted output to stdout using argument list pointer.619 *620 ******************************************************************************/621 622int vprintf(const char *format, va_list args)623{624 acpi_cpu_flags flags;625 int length;626 627 flags = acpi_os_acquire_lock(acpi_gbl_print_lock);628 length = vsnprintf(acpi_gbl_print_buffer,629 sizeof(acpi_gbl_print_buffer), format, args);630 631 (void)fwrite(acpi_gbl_print_buffer, length, 1, ACPI_FILE_OUT);632 acpi_os_release_lock(acpi_gbl_print_lock, flags);633 634 return (length);635}636 637/*******************************************************************************638 *639 * FUNCTION: printf640 *641 * PARAMETERS: Format, ... - Standard printf format642 *643 * RETURN: Number of bytes actually written.644 *645 * DESCRIPTION: Formatted output to stdout.646 *647 ******************************************************************************/648 649int printf(const char *format, ...)650{651 va_list args;652 int length;653 654 va_start(args, format);655 length = vprintf(format, args);656 va_end(args);657 658 return (length);659}660 661/*******************************************************************************662 *663 * FUNCTION: vfprintf664 *665 * PARAMETERS: file - File descriptor666 * format - Standard printf format667 * args - Argument list668 *669 * RETURN: Number of bytes actually written.670 *671 * DESCRIPTION: Formatted output to a file using argument list pointer.672 *673 ******************************************************************************/674 675int vfprintf(FILE * file, const char *format, va_list args)676{677 acpi_cpu_flags flags;678 int length;679 680 flags = acpi_os_acquire_lock(acpi_gbl_print_lock);681 length = vsnprintf(acpi_gbl_print_buffer,682 sizeof(acpi_gbl_print_buffer), format, args);683 684 (void)fwrite(acpi_gbl_print_buffer, length, 1, file);685 acpi_os_release_lock(acpi_gbl_print_lock, flags);686 687 return (length);688}689 690/*******************************************************************************691 *692 * FUNCTION: fprintf693 *694 * PARAMETERS: file - File descriptor695 * Format, ... - Standard printf format696 *697 * RETURN: Number of bytes actually written.698 *699 * DESCRIPTION: Formatted output to a file.700 *701 ******************************************************************************/702 703int fprintf(FILE * file, const char *format, ...)704{705 va_list args;706 int length;707 708 va_start(args, format);709 length = vfprintf(file, format, args);710 va_end(args);711 712 return (length);713}714#endif715