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 - 2023, 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 |
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 | |
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 | |
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(in_dividend: number, in_divisor: base, out_quotient: &number, |
118 | out_remainder: &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 | |
140 | const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) |
141 | { |
142 | u64 number = 0; |
143 | |
144 | while (isdigit(c: (int)*string)) { |
145 | acpi_ut_short_multiply(in_multiplicand: number, multiplier: 10, outproduct: &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 | |
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(string: ascii_string, number, base: 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 | |
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(string: 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, c: ' '); |
270 | } |
271 | } |
272 | if (sign) { |
273 | string = acpi_ut_bound_string_output(string, end, c: sign); |
274 | } |
275 | if (need_prefix) { |
276 | string = acpi_ut_bound_string_output(string, end, c: '0'); |
277 | if (base == 16) { |
278 | string = |
279 | acpi_ut_bound_string_output(string, end, |
280 | c: upper ? 'X' : 'x'); |
281 | } |
282 | } |
283 | if (!(type & ACPI_FORMAT_LEFT)) { |
284 | while (--width >= 0) { |
285 | string = acpi_ut_bound_string_output(string, end, c: zero); |
286 | } |
287 | } |
288 | |
289 | while (i <= --precision) { |
290 | string = acpi_ut_bound_string_output(string, end, c: '0'); |
291 | } |
292 | while (--i >= 0) { |
293 | string = acpi_ut_bound_string_output(string, end, |
294 | c: reversed_string[i]); |
295 | } |
296 | while (--width >= 0) { |
297 | string = acpi_ut_bound_string_output(string, end, c: ' '); |
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 | |
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 | 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(string: pos, end, c: *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(c: (int)*format)) { |
375 | format = acpi_ut_scan_number(string: format, number_ptr: &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(c: (int)*format)) { |
392 | format = acpi_ut_scan_number(string: format, number_ptr: &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(string: pos, end, c: '%'); |
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(string: pos, |
429 | end, |
430 | c: ' '); |
431 | } |
432 | } |
433 | |
434 | c = (char)va_arg(args, int); |
435 | pos = acpi_ut_bound_string_output(string: pos, end, c); |
436 | |
437 | while (--width > 0) { |
438 | pos = |
439 | acpi_ut_bound_string_output(string: pos, end, c: ' '); |
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(string: s, count: precision); |
450 | if (!(type & ACPI_FORMAT_LEFT)) { |
451 | while (length < width--) { |
452 | pos = |
453 | acpi_ut_bound_string_output(string: pos, |
454 | end, |
455 | c: ' '); |
456 | } |
457 | } |
458 | |
459 | for (i = 0; i < length; ++i) { |
460 | pos = acpi_ut_bound_string_output(string: pos, end, c: *s); |
461 | ++s; |
462 | } |
463 | |
464 | while (length < width--) { |
465 | pos = |
466 | acpi_ut_bound_string_output(string: pos, end, c: ' '); |
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(string: pos, end, ACPI_TO_INTEGER(p), |
504 | base: 16, width, precision, type); |
505 | continue; |
506 | |
507 | default: |
508 | |
509 | pos = acpi_ut_bound_string_output(string: pos, end, c: '%'); |
510 | if (*format) { |
511 | pos = |
512 | acpi_ut_bound_string_output(string: pos, end, |
513 | c: *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(string: 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: snprintf |
560 | * |
561 | * PARAMETERS: string - String with boundary |
562 | * size - Boundary of the string |
563 | * Format, ... - Standard printf format |
564 | * |
565 | * RETURN: Number of bytes actually written. |
566 | * |
567 | * DESCRIPTION: Formatted output to a string. |
568 | * |
569 | ******************************************************************************/ |
570 | |
571 | int 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(buf: string, size, fmt: format, args); |
578 | va_end(args); |
579 | |
580 | return (length); |
581 | } |
582 | |
583 | /******************************************************************************* |
584 | * |
585 | * FUNCTION: sprintf |
586 | * |
587 | * PARAMETERS: string - String with boundary |
588 | * Format, ... - Standard printf format |
589 | * |
590 | * RETURN: Number of bytes actually written. |
591 | * |
592 | * DESCRIPTION: Formatted output to a string. |
593 | * |
594 | ******************************************************************************/ |
595 | |
596 | int sprintf(char *string, const char *format, ...) |
597 | { |
598 | va_list args; |
599 | int length; |
600 | |
601 | va_start(args, format); |
602 | length = vsnprintf(buf: string, ACPI_UINT32_MAX, fmt: format, args); |
603 | va_end(args); |
604 | |
605 | return (length); |
606 | } |
607 | |
608 | #ifdef ACPI_APPLICATION |
609 | /******************************************************************************* |
610 | * |
611 | * FUNCTION: vprintf |
612 | * |
613 | * PARAMETERS: format - Standard printf format |
614 | * args - Argument list |
615 | * |
616 | * RETURN: Number of bytes actually written. |
617 | * |
618 | * DESCRIPTION: Formatted output to stdout using argument list pointer. |
619 | * |
620 | ******************************************************************************/ |
621 | |
622 | int 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: printf |
640 | * |
641 | * PARAMETERS: Format, ... - Standard printf format |
642 | * |
643 | * RETURN: Number of bytes actually written. |
644 | * |
645 | * DESCRIPTION: Formatted output to stdout. |
646 | * |
647 | ******************************************************************************/ |
648 | |
649 | int 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: vfprintf |
664 | * |
665 | * PARAMETERS: file - File descriptor |
666 | * format - Standard printf format |
667 | * args - Argument list |
668 | * |
669 | * RETURN: Number of bytes actually written. |
670 | * |
671 | * DESCRIPTION: Formatted output to a file using argument list pointer. |
672 | * |
673 | ******************************************************************************/ |
674 | |
675 | int 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: fprintf |
693 | * |
694 | * PARAMETERS: file - File descriptor |
695 | * Format, ... - Standard printf format |
696 | * |
697 | * RETURN: Number of bytes actually written. |
698 | * |
699 | * DESCRIPTION: Formatted output to a file. |
700 | * |
701 | ******************************************************************************/ |
702 | |
703 | int 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 | #endif |
715 | |