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