xref: /linux/drivers/acpi/acpica/utprint.c (revision 3702a515edec515fcc7e085053da636fefac88d6)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: utprint - Formatted printing routines
5  *
6  * Copyright (C) 2000 - 2025, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 
13 #define _COMPONENT          ACPI_UTILITIES
14 ACPI_MODULE_NAME("utprint")
15 
16 #define ACPI_FORMAT_SIGN            0x01
17 #define ACPI_FORMAT_SIGN_PLUS       0x02
18 #define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04
19 #define ACPI_FORMAT_ZERO            0x08
20 #define ACPI_FORMAT_LEFT            0x10
21 #define ACPI_FORMAT_UPPER           0x20
22 #define ACPI_FORMAT_PREFIX          0x40
23 /* Local prototypes */
24 static acpi_size
25 acpi_ut_bound_string_length(const char *string, acpi_size count);
26 
27 static char *acpi_ut_bound_string_output(char *string, const char *end, char c);
28 
29 static char *acpi_ut_format_number(char *string,
30 				   char *end,
31 				   u64 number,
32 				   u8 base, s32 width, s32 precision, u8 type);
33 
34 static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper);
35 
36 /*******************************************************************************
37  *
38  * FUNCTION:    acpi_ut_bound_string_length
39  *
40  * PARAMETERS:  string              - String with boundary
41  *              count               - Boundary of the string
42  *
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 
49 static acpi_size
acpi_ut_bound_string_length(const char * string,acpi_size count)50 acpi_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_output
66  *
67  * PARAMETERS:  string              - String with boundary
68  *              end                 - Boundary of the string
69  *              c                   - Character to be output to the string
70  *
71  * RETURN:      Updated position for next valid character
72  *
73  * DESCRIPTION: Output a character into a string with boundary check.
74  *
75  ******************************************************************************/
76 
acpi_ut_bound_string_output(char * string,const char * end,char c)77 static 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_number
91  *
92  * PARAMETERS:  string              - Buffer to hold reverse-ordered string
93  *              number              - Integer to be converted
94  *              base                - Base of the integer
95  *              upper               - Whether or not using upper cased digits
96  *
97  * RETURN:      Updated position for next valid character
98  *
99  * DESCRIPTION: Convert an integer into a string, note that, the string holds a
100  *              reversed ordered number without the trailing zero.
101  *
102  ******************************************************************************/
103 
acpi_ut_put_number(char * string,u64 number,u8 base,u8 upper)104 static 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_number
130  *
131  * PARAMETERS:  string              - String buffer
132  *              number_ptr          - Where the number is returned
133  *
134  * RETURN:      Updated position for next valid character
135  *
136  * DESCRIPTION: Scan a string for a decimal integer.
137  *
138  ******************************************************************************/
139 
acpi_ut_scan_number(const char * string,u64 * number_ptr)140 const 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_number
156  *
157  * PARAMETERS:  string              - String buffer
158  *              number              - The number to be converted
159  *
160  * RETURN:      Updated position for next valid character
161  *
162  * DESCRIPTION: Print a decimal integer into a string.
163  *
164  ******************************************************************************/
165 
acpi_ut_print_number(char * string,u64 number)166 const 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_number
186  *
187  * PARAMETERS:  string              - String buffer with boundary
188  *              end                 - Boundary of the string
189  *              number              - The number to be converted
190  *              base                - Base of the integer
191  *              width               - Field width
192  *              precision           - Precision of the integer
193  *              type                - Special printing flags
194  *
195  * RETURN:      Updated position for next valid character
196  *
197  * DESCRIPTION: Print an integer into a string with any base and any precision.
198  *
199  ******************************************************************************/
200 
acpi_ut_format_number(char * string,char * end,u64 number,u8 base,s32 width,s32 precision,u8 type)201 static 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:    vsnprintf
306  *
307  * PARAMETERS:  string              - String with boundary
308  *              size                - Boundary of the string
309  *              format              - Standard printf format
310  *              args                - Argument list
311  *
312  * RETURN:      Number of bytes actually written.
313  *
314  * DESCRIPTION: Formatted output to a string using argument list pointer.
315  *
316  ******************************************************************************/
317 
vsnprintf(char * string,acpi_size size,const char * format,va_list args)318 int 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 	size = ACPI_MIN(size, ACPI_PTR_DIFF(ACPI_MAX_PTR, string));
337 	end = string + size;
338 
339 	for (; *format; ++format) {
340 		if (*format != '%') {
341 			pos = acpi_ut_bound_string_output(pos, end, *format);
342 			continue;
343 		}
344 
345 		type = 0;
346 		base = 10;
347 
348 		/* Process sign */
349 
350 		do {
351 			++format;
352 			if (*format == '#') {
353 				type |= ACPI_FORMAT_PREFIX;
354 			} else if (*format == '0') {
355 				type |= ACPI_FORMAT_ZERO;
356 			} else if (*format == '+') {
357 				type |= ACPI_FORMAT_SIGN_PLUS;
358 			} else if (*format == ' ') {
359 				type |= ACPI_FORMAT_SIGN_PLUS_SPACE;
360 			} else if (*format == '-') {
361 				type |= ACPI_FORMAT_LEFT;
362 			} else {
363 				break;
364 			}
365 
366 		} while (1);
367 
368 		/* Process width */
369 
370 		width = -1;
371 		if (isdigit((int)*format)) {
372 			format = acpi_ut_scan_number(format, &number);
373 			width = (s32)number;
374 		} else if (*format == '*') {
375 			++format;
376 			width = va_arg(args, int);
377 			if (width < 0) {
378 				width = -width;
379 				type |= ACPI_FORMAT_LEFT;
380 			}
381 		}
382 
383 		/* Process precision */
384 
385 		precision = -1;
386 		if (*format == '.') {
387 			++format;
388 			if (isdigit((int)*format)) {
389 				format = acpi_ut_scan_number(format, &number);
390 				precision = (s32)number;
391 			} else if (*format == '*') {
392 				++format;
393 				precision = va_arg(args, int);
394 			}
395 
396 			if (precision < 0) {
397 				precision = 0;
398 			}
399 		}
400 
401 		/* Process qualifier */
402 
403 		qualifier = -1;
404 		if (*format == 'h' || *format == 'l' || *format == 'L') {
405 			qualifier = *format;
406 			++format;
407 
408 			if (qualifier == 'l' && *format == 'l') {
409 				qualifier = 'L';
410 				++format;
411 			}
412 		}
413 
414 		switch (*format) {
415 		case '%':
416 
417 			pos = acpi_ut_bound_string_output(pos, end, '%');
418 			continue;
419 
420 		case 'c':
421 
422 			if (!(type & ACPI_FORMAT_LEFT)) {
423 				while (--width > 0) {
424 					pos =
425 					    acpi_ut_bound_string_output(pos,
426 									end,
427 									' ');
428 				}
429 			}
430 
431 			c = (char)va_arg(args, int);
432 			pos = acpi_ut_bound_string_output(pos, end, c);
433 
434 			while (--width > 0) {
435 				pos =
436 				    acpi_ut_bound_string_output(pos, end, ' ');
437 			}
438 			continue;
439 
440 		case 's':
441 
442 			s = va_arg(args, char *);
443 			if (!s) {
444 				s = "<NULL>";
445 			}
446 			length = (s32)acpi_ut_bound_string_length(s, precision);
447 			if (!(type & ACPI_FORMAT_LEFT)) {
448 				while (length < width--) {
449 					pos =
450 					    acpi_ut_bound_string_output(pos,
451 									end,
452 									' ');
453 				}
454 			}
455 
456 			for (i = 0; i < length; ++i) {
457 				pos = acpi_ut_bound_string_output(pos, end, *s);
458 				++s;
459 			}
460 
461 			while (length < width--) {
462 				pos =
463 				    acpi_ut_bound_string_output(pos, end, ' ');
464 			}
465 			continue;
466 
467 		case 'o':
468 
469 			base = 8;
470 			break;
471 
472 		case 'X':
473 
474 			type |= ACPI_FORMAT_UPPER;
475 			ACPI_FALLTHROUGH;
476 
477 		case 'x':
478 
479 			base = 16;
480 			break;
481 
482 		case 'd':
483 		case 'i':
484 
485 			type |= ACPI_FORMAT_SIGN;
486 
487 		case 'u':
488 
489 			break;
490 
491 		case 'p':
492 
493 			if (width == -1) {
494 				width = 2 * sizeof(void *);
495 				type |= ACPI_FORMAT_ZERO;
496 			}
497 
498 			p = va_arg(args, void *);
499 			pos =
500 			    acpi_ut_format_number(pos, end, ACPI_TO_INTEGER(p),
501 						  16, width, precision, type);
502 			continue;
503 
504 		default:
505 
506 			pos = acpi_ut_bound_string_output(pos, end, '%');
507 			if (*format) {
508 				pos =
509 				    acpi_ut_bound_string_output(pos, end,
510 								*format);
511 			} else {
512 				--format;
513 			}
514 			continue;
515 		}
516 
517 		if (qualifier == 'L') {
518 			number = va_arg(args, u64);
519 			if (type & ACPI_FORMAT_SIGN) {
520 				number = (s64)number;
521 			}
522 		} else if (qualifier == 'l') {
523 			number = va_arg(args, unsigned long);
524 			if (type & ACPI_FORMAT_SIGN) {
525 				number = (s32)number;
526 			}
527 		} else if (qualifier == 'h') {
528 			number = (u16)va_arg(args, int);
529 			if (type & ACPI_FORMAT_SIGN) {
530 				number = (s16)number;
531 			}
532 		} else {
533 			number = va_arg(args, unsigned int);
534 			if (type & ACPI_FORMAT_SIGN) {
535 				number = (signed int)number;
536 			}
537 		}
538 
539 		pos = acpi_ut_format_number(pos, end, number, base,
540 					    width, precision, type);
541 	}
542 
543 	if (size > 0) {
544 		if (pos < end) {
545 			*pos = '\0';
546 		} else {
547 			end[-1] = '\0';
548 		}
549 	}
550 
551 	return ((int)ACPI_PTR_DIFF(pos, string));
552 }
553 
554 /*******************************************************************************
555  *
556  * FUNCTION:    snprintf
557  *
558  * PARAMETERS:  string              - String with boundary
559  *              size                - Boundary of the string
560  *              Format, ...         - Standard printf format
561  *
562  * RETURN:      Number of bytes actually written.
563  *
564  * DESCRIPTION: Formatted output to a string.
565  *
566  ******************************************************************************/
567 
snprintf(char * string,acpi_size size,const char * format,...)568 int snprintf(char *string, acpi_size size, const char *format, ...)
569 {
570 	va_list args;
571 	int length;
572 
573 	va_start(args, format);
574 	length = vsnprintf(string, size, format, args);
575 	va_end(args);
576 
577 	return (length);
578 }
579 
580 /*******************************************************************************
581  *
582  * FUNCTION:    sprintf
583  *
584  * PARAMETERS:  string              - String with boundary
585  *              Format, ...         - Standard printf format
586  *
587  * RETURN:      Number of bytes actually written.
588  *
589  * DESCRIPTION: Formatted output to a string.
590  *
591  ******************************************************************************/
592 
sprintf(char * string,const char * format,...)593 int sprintf(char *string, const char *format, ...)
594 {
595 	va_list args;
596 	int length;
597 
598 	va_start(args, format);
599 	length = vsnprintf(string, ACPI_UINT32_MAX, format, args);
600 	va_end(args);
601 
602 	return (length);
603 }
604 
605 #ifdef ACPI_APPLICATION
606 /*******************************************************************************
607  *
608  * FUNCTION:    vprintf
609  *
610  * PARAMETERS:  format              - Standard printf format
611  *              args                - Argument list
612  *
613  * RETURN:      Number of bytes actually written.
614  *
615  * DESCRIPTION: Formatted output to stdout using argument list pointer.
616  *
617  ******************************************************************************/
618 
vprintf(const char * format,va_list args)619 int vprintf(const char *format, va_list args)
620 {
621 	acpi_cpu_flags flags;
622 	int length;
623 
624 	flags = acpi_os_acquire_lock(acpi_gbl_print_lock);
625 	length = vsnprintf(acpi_gbl_print_buffer,
626 			   sizeof(acpi_gbl_print_buffer), format, args);
627 
628 	(void)fwrite(acpi_gbl_print_buffer, length, 1, ACPI_FILE_OUT);
629 	acpi_os_release_lock(acpi_gbl_print_lock, flags);
630 
631 	return (length);
632 }
633 
634 /*******************************************************************************
635  *
636  * FUNCTION:    printf
637  *
638  * PARAMETERS:  Format, ...         - Standard printf format
639  *
640  * RETURN:      Number of bytes actually written.
641  *
642  * DESCRIPTION: Formatted output to stdout.
643  *
644  ******************************************************************************/
645 
printf(const char * format,...)646 int printf(const char *format, ...)
647 {
648 	va_list args;
649 	int length;
650 
651 	va_start(args, format);
652 	length = vprintf(format, args);
653 	va_end(args);
654 
655 	return (length);
656 }
657 
658 /*******************************************************************************
659  *
660  * FUNCTION:    vfprintf
661  *
662  * PARAMETERS:  file                - File descriptor
663  *              format              - Standard printf format
664  *              args                - Argument list
665  *
666  * RETURN:      Number of bytes actually written.
667  *
668  * DESCRIPTION: Formatted output to a file using argument list pointer.
669  *
670  ******************************************************************************/
671 
vfprintf(FILE * file,const char * format,va_list args)672 int vfprintf(FILE * file, const char *format, va_list args)
673 {
674 	acpi_cpu_flags flags;
675 	int length;
676 
677 	flags = acpi_os_acquire_lock(acpi_gbl_print_lock);
678 	length = vsnprintf(acpi_gbl_print_buffer,
679 			   sizeof(acpi_gbl_print_buffer), format, args);
680 
681 	(void)fwrite(acpi_gbl_print_buffer, length, 1, file);
682 	acpi_os_release_lock(acpi_gbl_print_lock, flags);
683 
684 	return (length);
685 }
686 
687 /*******************************************************************************
688  *
689  * FUNCTION:    fprintf
690  *
691  * PARAMETERS:  file                - File descriptor
692  *              Format, ...         - Standard printf format
693  *
694  * RETURN:      Number of bytes actually written.
695  *
696  * DESCRIPTION: Formatted output to a file.
697  *
698  ******************************************************************************/
699 
fprintf(FILE * file,const char * format,...)700 int fprintf(FILE * file, const char *format, ...)
701 {
702 	va_list args;
703 	int length;
704 
705 	va_start(args, format);
706 	length = vfprintf(file, format, args);
707 	va_end(args);
708 
709 	return (length);
710 }
711 #endif
712