1 /*
2 * Copyright (c) 2019-2021 Eugene Syromyatnikov <evgsyr@gmail.com>.
3 * Copyright (c) 2022-2023 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #ifndef STRACE_PRINT_UTILS_H
10 # define STRACE_PRINT_UTILS_H
11
12 # include <inttypes.h>
13
14 /* Hexadecimal output utils */
15
16 static const char hex_chars[16] = "0123456789abcdef";
17
18 /**
19 * Character array representing hexadecimal encoding of a character value.
20 *
21 * @param b_ Byte to provide representation for.
22 */
23 # define BYTE_HEX_CHARS(b_) \
24 hex_chars[((uint8_t) (b_)) >> 4], hex_chars[((uint8_t) (b_)) & 0xf]
25
26 /* Character classification utils */
27
28 static inline bool
29 is_print(uint8_t c)
30 {
31 return (c >= ' ') && (c < 0x7f);
32 }
33
34 /* Character printing functions */
35
36 /** @param unabbrev Whether to always print \ooo instead of \[[o]o]o. */
37 static inline char *
38 sprint_byte_oct(char *s, uint8_t c, bool unabbrev)
39 {
40 if (unabbrev) {
41 /* Print \ooo */
42 *s++ = '0' + (c >> 6);
43 *s++ = '0' + ((c >> 3) & 0x7);
44 } else {
45 /* Print \[[o]o]o */
46 if ((c >> 3) != 0) {
47 if ((c >> 6) != 0)
48 *s++ = '0' + (c >> 6);
49 *s++ = '0' + ((c >> 3) & 0x7);
50 }
51 }
52 *s++ = '0' + (c & 0x7);
53
54 return s;
55 }
56
57 static inline char *
58 sprint_byte_hex(char *buf, uint8_t val)
59 {
60 *buf++ = hex_chars[val >> 4];
61 *buf++ = hex_chars[val & 0xf];
62
63 return buf;
64 }
65
66 /** Maximum number of characters emitted by sprint_char */
67 # define SPRINT_CHAR_BUFSZ 7
68
69 enum sprint_char_flag_bits {
70 SCF_QUOTES_BIT,
71 SCF_NUL_BIT,
72 SCF_ESC_WS_BIT,
73 };
74
75 enum sprint_char_flags {
76 FLAG(SCF_QUOTES), /**< Whether to emit quotes */
77 FLAG(SCF_NUL), /**< Whether to terminate output with \0 */
78 FLAG(SCF_ESC_WS), /**< Whether to print \t\n\v\f\r in symbolic form */
79 };
80
81 /** Emits a character into buf (SPRINT_CHAR_BUFSZ max), returns new position. */
82 static inline char *
83 sprint_char(char *buf, const unsigned char c, const enum sprint_char_flags f)
84 {
85 if (f & SCF_QUOTES)
86 *buf++ = '\'';
87
88 if (is_print(c)) {
89 if (c == '\'' || c == '\\')
90 *buf++ = '\\';
91 *buf++ = c;
92 } else if ((f & SCF_ESC_WS) && (c >= '\t') && (c <= '\r')) {
93 static const char ws_chars[] = "tnvfr";
94
95 *buf++ = '\\';
96 *buf++ = ws_chars[c - '\t'];
97 } else {
98 *buf++ = '\\';
99 *buf++ = 'x';
100 buf = sprint_byte_hex(buf, c);
101 }
102
103 if (f & SCF_QUOTES)
104 *buf++ = '\'';
105 if (f & SCF_NUL)
106 *buf++ = '\0';
107
108 return buf;
109 }
110
111 # define print_char(c_, flags_) \
112 do { \
113 char buf[SPRINT_CHAR_BUFSZ]; \
114 \
115 sprint_char(buf, (c_), (flags_) | SCF_NUL); \
116 tprints_string(buf); \
117 } while (0)
118
119 #endif /* STRACE_PRINT_UTILS_H */