Contributors: 4
Author Tokens Token Proportion Commits Commit Proportion
Lv Zheng 2186 98.56% 7 53.85%
Robert Moore 30 1.35% 4 30.77%
Toomas Soome 1 0.05% 1 7.69%
Erik Schmauss 1 0.05% 1 7.69%
Total 2218 13

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
 *
 * Module Name: utprint - Formatted printing routines
 *
 * Copyright (C) 2000 - 2019, Intel Corp.
 *
 *****************************************************************************/

#include <acpi/acpi.h>
#include "accommon.h"

#define _COMPONENT          ACPI_UTILITIES
ACPI_MODULE_NAME("utprint")

#define ACPI_FORMAT_SIGN            0x01
#define ACPI_FORMAT_SIGN_PLUS       0x02
#define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04
#define ACPI_FORMAT_ZERO            0x08
#define ACPI_FORMAT_LEFT            0x10
#define ACPI_FORMAT_UPPER           0x20
#define ACPI_FORMAT_PREFIX          0x40
/* Local prototypes */
static acpi_size
acpi_ut_bound_string_length(const char *string, acpi_size count);

static char *acpi_ut_bound_string_output(char *string, const char *end, char c);

static char *acpi_ut_format_number(char *string,
				   char *end,
				   u64 number,
				   u8 base, s32 width, s32 precision, u8 type);

static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper);

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_bound_string_length
 *
 * PARAMETERS:  string              - String with boundary
 *              count               - Boundary of the string
 *
 * RETURN:      Length of the string. Less than or equal to Count.
 *
 * DESCRIPTION: Calculate the length of a string with boundary.
 *
 ******************************************************************************/

static acpi_size
acpi_ut_bound_string_length(const char *string, acpi_size count)
{
	u32 length = 0;

	while (*string && count) {
		length++;
		string++;
		count--;
	}

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_bound_string_output
 *
 * PARAMETERS:  string              - String with boundary
 *              end                 - Boundary of the string
 *              c                   - Character to be output to the string
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Output a character into a string with boundary check.
 *
 ******************************************************************************/

static char *acpi_ut_bound_string_output(char *string, const char *end, char c)
{

	if (string < end) {
		*string = c;
	}

	++string;
	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_put_number
 *
 * PARAMETERS:  string              - Buffer to hold reverse-ordered string
 *              number              - Integer to be converted
 *              base                - Base of the integer
 *              upper               - Whether or not using upper cased digits
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Convert an integer into a string, note that, the string holds a
 *              reversed ordered number without the trailing zero.
 *
 ******************************************************************************/

static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper)
{
	const char *digits;
	u64 digit_index;
	char *pos;

	pos = string;
	digits = upper ? acpi_gbl_upper_hex_digits : acpi_gbl_lower_hex_digits;

	if (number == 0) {
		*(pos++) = '0';
	} else {
		while (number) {
			(void)acpi_ut_divide(number, base, &number,
					     &digit_index);
			*(pos++) = digits[digit_index];
		}
	}

	/* *(Pos++) = '0'; */
	return (pos);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_scan_number
 *
 * PARAMETERS:  string              - String buffer
 *              number_ptr          - Where the number is returned
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Scan a string for a decimal integer.
 *
 ******************************************************************************/

const char *acpi_ut_scan_number(const char *string, u64 *number_ptr)
{
	u64 number = 0;

	while (isdigit((int)*string)) {
		acpi_ut_short_multiply(number, 10, &number);
		number += *(string++) - '0';
	}

	*number_ptr = number;
	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_print_number
 *
 * PARAMETERS:  string              - String buffer
 *              number              - The number to be converted
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Print a decimal integer into a string.
 *
 ******************************************************************************/

const char *acpi_ut_print_number(char *string, u64 number)
{
	char ascii_string[20];
	const char *pos1;
	char *pos2;

	pos1 = acpi_ut_put_number(ascii_string, number, 10, FALSE);
	pos2 = string;

	while (pos1 != ascii_string) {
		*(pos2++) = *(--pos1);
	}

	*pos2 = 0;
	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_format_number
 *
 * PARAMETERS:  string              - String buffer with boundary
 *              end                 - Boundary of the string
 *              number              - The number to be converted
 *              base                - Base of the integer
 *              width               - Field width
 *              precision           - Precision of the integer
 *              type                - Special printing flags
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Print an integer into a string with any base and any precision.
 *
 ******************************************************************************/

static char *acpi_ut_format_number(char *string,
				   char *end,
				   u64 number,
				   u8 base, s32 width, s32 precision, u8 type)
{
	char *pos;
	char sign;
	char zero;
	u8 need_prefix;
	u8 upper;
	s32 i;
	char reversed_string[66];

	/* Parameter validation */

	if (base < 2 || base > 16) {
		return (NULL);
	}

	if (type & ACPI_FORMAT_LEFT) {
		type &= ~ACPI_FORMAT_ZERO;
	}

	need_prefix = ((type & ACPI_FORMAT_PREFIX)
		       && base != 10) ? TRUE : FALSE;
	upper = (type & ACPI_FORMAT_UPPER) ? TRUE : FALSE;
	zero = (type & ACPI_FORMAT_ZERO) ? '0' : ' ';

	/* Calculate size according to sign and prefix */

	sign = '\0';
	if (type & ACPI_FORMAT_SIGN) {
		if ((s64)number < 0) {
			sign = '-';
			number = -(s64)number;
			width--;
		} else if (type & ACPI_FORMAT_SIGN_PLUS) {
			sign = '+';
			width--;
		} else if (type & ACPI_FORMAT_SIGN_PLUS_SPACE) {
			sign = ' ';
			width--;
		}
	}
	if (need_prefix) {
		width--;
		if (base == 16) {
			width--;
		}
	}

	/* Generate full string in reverse order */

	pos = acpi_ut_put_number(reversed_string, number, base, upper);
	i = (s32)ACPI_PTR_DIFF(pos, reversed_string);

	/* Printing 100 using %2d gives "100", not "00" */

	if (i > precision) {
		precision = i;
	}

	width -= precision;

	/* Output the string */

	if (!(type & (ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT))) {
		while (--width >= 0) {
			string = acpi_ut_bound_string_output(string, end, ' ');
		}
	}
	if (sign) {
		string = acpi_ut_bound_string_output(string, end, sign);
	}
	if (need_prefix) {
		string = acpi_ut_bound_string_output(string, end, '0');
		if (base == 16) {
			string =
			    acpi_ut_bound_string_output(string, end,
							upper ? 'X' : 'x');
		}
	}
	if (!(type & ACPI_FORMAT_LEFT)) {
		while (--width >= 0) {
			string = acpi_ut_bound_string_output(string, end, zero);
		}
	}

	while (i <= --precision) {
		string = acpi_ut_bound_string_output(string, end, '0');
	}
	while (--i >= 0) {
		string = acpi_ut_bound_string_output(string, end,
						     reversed_string[i]);
	}
	while (--width >= 0) {
		string = acpi_ut_bound_string_output(string, end, ' ');
	}

	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    vsnprintf
 *
 * PARAMETERS:  string              - String with boundary
 *              size                - Boundary of the string
 *              format              - Standard printf format
 *              args                - Argument list
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a string using argument list pointer.
 *
 ******************************************************************************/

int vsnprintf(char *string, acpi_size size, const char *format, va_list args)
{
	u8 base;
	u8 type;
	s32 width;
	s32 precision;
	char qualifier;
	u64 number;
	char *pos;
	char *end;
	char c;
	const char *s;
	const void *p;
	s32 length;
	int i;

	pos = string;
	end = string + size;

	for (; *format; ++format) {
		if (*format != '%') {
			pos = acpi_ut_bound_string_output(pos, end, *format);
			continue;
		}

		type = 0;
		base = 10;

		/* Process sign */

		do {
			++format;
			if (*format == '#') {
				type |= ACPI_FORMAT_PREFIX;
			} else if (*format == '0') {
				type |= ACPI_FORMAT_ZERO;
			} else if (*format == '+') {
				type |= ACPI_FORMAT_SIGN_PLUS;
			} else if (*format == ' ') {
				type |= ACPI_FORMAT_SIGN_PLUS_SPACE;
			} else if (*format == '-') {
				type |= ACPI_FORMAT_LEFT;
			} else {
				break;
			}

		} while (1);

		/* Process width */

		width = -1;
		if (isdigit((int)*format)) {
			format = acpi_ut_scan_number(format, &number);
			width = (s32)number;
		} else if (*format == '*') {
			++format;
			width = va_arg(args, int);
			if (width < 0) {
				width = -width;
				type |= ACPI_FORMAT_LEFT;
			}
		}

		/* Process precision */

		precision = -1;
		if (*format == '.') {
			++format;
			if (isdigit((int)*format)) {
				format = acpi_ut_scan_number(format, &number);
				precision = (s32)number;
			} else if (*format == '*') {
				++format;
				precision = va_arg(args, int);
			}

			if (precision < 0) {
				precision = 0;
			}
		}

		/* Process qualifier */

		qualifier = -1;
		if (*format == 'h' || *format == 'l' || *format == 'L') {
			qualifier = *format;
			++format;

			if (qualifier == 'l' && *format == 'l') {
				qualifier = 'L';
				++format;
			}
		}

		switch (*format) {
		case '%':

			pos = acpi_ut_bound_string_output(pos, end, '%');
			continue;

		case 'c':

			if (!(type & ACPI_FORMAT_LEFT)) {
				while (--width > 0) {
					pos =
					    acpi_ut_bound_string_output(pos,
									end,
									' ');
				}
			}

			c = (char)va_arg(args, int);
			pos = acpi_ut_bound_string_output(pos, end, c);

			while (--width > 0) {
				pos =
				    acpi_ut_bound_string_output(pos, end, ' ');
			}
			continue;

		case 's':

			s = va_arg(args, char *);
			if (!s) {
				s = "<NULL>";
			}
			length = (s32)acpi_ut_bound_string_length(s, precision);
			if (!(type & ACPI_FORMAT_LEFT)) {
				while (length < width--) {
					pos =
					    acpi_ut_bound_string_output(pos,
									end,
									' ');
				}
			}

			for (i = 0; i < length; ++i) {
				pos = acpi_ut_bound_string_output(pos, end, *s);
				++s;
			}

			while (length < width--) {
				pos =
				    acpi_ut_bound_string_output(pos, end, ' ');
			}
			continue;

		case 'o':

			base = 8;
			break;

		case 'X':

			type |= ACPI_FORMAT_UPPER;
			/* FALLTHROUGH */

		case 'x':

			base = 16;
			break;

		case 'd':
		case 'i':

			type |= ACPI_FORMAT_SIGN;

		case 'u':

			break;

		case 'p':

			if (width == -1) {
				width = 2 * sizeof(void *);
				type |= ACPI_FORMAT_ZERO;
			}

			p = va_arg(args, void *);
			pos =
			    acpi_ut_format_number(pos, end, ACPI_TO_INTEGER(p),
						  16, width, precision, type);
			continue;

		default:

			pos = acpi_ut_bound_string_output(pos, end, '%');
			if (*format) {
				pos =
				    acpi_ut_bound_string_output(pos, end,
								*format);
			} else {
				--format;
			}
			continue;
		}

		if (qualifier == 'L') {
			number = va_arg(args, u64);
			if (type & ACPI_FORMAT_SIGN) {
				number = (s64)number;
			}
		} else if (qualifier == 'l') {
			number = va_arg(args, unsigned long);
			if (type & ACPI_FORMAT_SIGN) {
				number = (s32)number;
			}
		} else if (qualifier == 'h') {
			number = (u16)va_arg(args, int);
			if (type & ACPI_FORMAT_SIGN) {
				number = (s16)number;
			}
		} else {
			number = va_arg(args, unsigned int);
			if (type & ACPI_FORMAT_SIGN) {
				number = (signed int)number;
			}
		}

		pos = acpi_ut_format_number(pos, end, number, base,
					    width, precision, type);
	}

	if (size > 0) {
		if (pos < end) {
			*pos = '\0';
		} else {
			end[-1] = '\0';
		}
	}

	return ((int)ACPI_PTR_DIFF(pos, string));
}

/*******************************************************************************
 *
 * FUNCTION:    snprintf
 *
 * PARAMETERS:  string              - String with boundary
 *              size                - Boundary of the string
 *              Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a string.
 *
 ******************************************************************************/

int snprintf(char *string, acpi_size size, const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vsnprintf(string, size, format, args);
	va_end(args);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    sprintf
 *
 * PARAMETERS:  string              - String with boundary
 *              Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a string.
 *
 ******************************************************************************/

int sprintf(char *string, const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vsnprintf(string, ACPI_UINT32_MAX, format, args);
	va_end(args);

	return (length);
}

#ifdef ACPI_APPLICATION
/*******************************************************************************
 *
 * FUNCTION:    vprintf
 *
 * PARAMETERS:  format              - Standard printf format
 *              args                - Argument list
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to stdout using argument list pointer.
 *
 ******************************************************************************/

int vprintf(const char *format, va_list args)
{
	acpi_cpu_flags flags;
	int length;

	flags = acpi_os_acquire_lock(acpi_gbl_print_lock);
	length = vsnprintf(acpi_gbl_print_buffer,
			   sizeof(acpi_gbl_print_buffer), format, args);

	(void)fwrite(acpi_gbl_print_buffer, length, 1, ACPI_FILE_OUT);
	acpi_os_release_lock(acpi_gbl_print_lock, flags);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    printf
 *
 * PARAMETERS:  Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to stdout.
 *
 ******************************************************************************/

int printf(const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vprintf(format, args);
	va_end(args);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    vfprintf
 *
 * PARAMETERS:  file                - File descriptor
 *              format              - Standard printf format
 *              args                - Argument list
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a file using argument list pointer.
 *
 ******************************************************************************/

int vfprintf(FILE * file, const char *format, va_list args)
{
	acpi_cpu_flags flags;
	int length;

	flags = acpi_os_acquire_lock(acpi_gbl_print_lock);
	length = vsnprintf(acpi_gbl_print_buffer,
			   sizeof(acpi_gbl_print_buffer), format, args);

	(void)fwrite(acpi_gbl_print_buffer, length, 1, file);
	acpi_os_release_lock(acpi_gbl_print_lock, flags);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    fprintf
 *
 * PARAMETERS:  file                - File descriptor
 *              Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a file.
 *
 ******************************************************************************/

int fprintf(FILE * file, const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vfprintf(file, format, args);
	va_end(args);

	return (length);
}
#endif