int vsnprintf()

in acpica/utprint.c [318:555]


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;

	if (size != ACPI_UINT32_MAX) {
		end = string + size;
	} else {
		end = ACPI_CAST_PTR(char, ACPI_UINT32_MAX);
	}

	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;
			ACPI_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));
}