1 /********************* */
2 /*! \file safe_print.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Andres Noetzli, Andres Noetzli
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
11 **
12 ** \brief Definition of print functions that are safe to use in a signal
13 ** handler.
14 **
15 ** Signal handlers only allow a very limited set of operations, e.g. dynamic
16 ** memory allocation is not possible. This set of functions can be used to
17 ** print information from a signal handler. All output is written to file
18 ** descriptors using the async-signal-safe write() function.
19 **/
20
21 #include "safe_print.h"
22
23 #include <unistd.h>
24
25 /* Size of buffers used */
26 #define BUFFER_SIZE 20
27
28 namespace CVC4 {
29
30 template <>
safe_print(int fd,const std::string & msg)31 void safe_print(int fd, const std::string& msg) {
32 // Print characters one by one instead of using
33 // string::data()/string::c_str() to avoid allocations (pre-c++11)
34 for (size_t i = 0; i < msg.length(); i++) {
35 if (write(fd, &(msg[i]), 1) != 1) {
36 abort();
37 }
38 }
39 }
40
41 template <>
safe_print(int fd,const int64_t & _i)42 void safe_print(int fd, const int64_t& _i) {
43 char buf[BUFFER_SIZE];
44 int64_t i = _i;
45
46 if (i == 0) {
47 safe_print(fd, "0");
48 return;
49 } else if (i < 0) {
50 safe_print(fd, "-");
51 i *= -1;
52 }
53
54 // This loop fills the buffer from the end. The number of elements in the
55 // buffer is BUFER_SIZE - idx - 1 and they start at position idx + 1.
56 ssize_t idx = BUFFER_SIZE - 1;
57 while (i != 0 && idx >= 0) {
58 buf[idx] = '0' + i % 10;
59 i /= 10;
60 idx--;
61 }
62
63 ssize_t nbyte = BUFFER_SIZE - idx - 1;
64 if (write(fd, buf + idx + 1, nbyte) != nbyte) {
65 abort();
66 }
67 }
68
69 template <>
safe_print(int fd,const int32_t & i)70 void safe_print(int fd, const int32_t& i) {
71 safe_print<int64_t>(fd, i);
72 }
73
74 template <>
safe_print(int fd,const uint64_t & _i)75 void safe_print(int fd, const uint64_t& _i) {
76 char buf[BUFFER_SIZE];
77 uint64_t i = _i;
78
79 if (i == 0) {
80 safe_print(fd, "0");
81 return;
82 }
83
84 // This loop fills the buffer from the end. The number of elements in the
85 // buffer is BUFER_SIZE - idx - 1 and they start at position idx + 1.
86 ssize_t idx = BUFFER_SIZE - 1;
87 while (i != 0 && idx >= 0) {
88 buf[idx] = '0' + i % 10;
89 i /= 10;
90 idx--;
91 }
92
93 ssize_t nbyte = BUFFER_SIZE - idx - 1;
94 if (write(fd, buf + idx + 1, nbyte) != nbyte) {
95 abort();
96 }
97 }
98
99 template <>
safe_print(int fd,const uint32_t & i)100 void safe_print(int fd, const uint32_t& i) {
101 safe_print<uint64_t>(fd, i);
102 }
103
104 template <>
safe_print(int fd,const double & _d)105 void safe_print(int fd, const double& _d) {
106 // Note: this print function for floating-point values is optimized for
107 // simplicity, not correctness or performance.
108 char buf[BUFFER_SIZE];
109 double d = _d;
110
111 ssize_t i = 0;
112 int64_t v = static_cast<int64_t>(d);
113 d -= v;
114
115 if (d < 0.0) {
116 d *= -1.0;
117 }
118
119 safe_print<int64_t>(fd, v);
120 safe_print(fd, ".");
121
122 // Print decimal digits as long as the remaining value is larger than zero
123 // and print at least one digit.
124 while (i == 0 || (d > 0.0 && i < BUFFER_SIZE)) {
125 d *= 10.0;
126 char c = static_cast<char>(d);
127 buf[i] = '0' + c;
128 d -= c;
129 i++;
130 }
131
132 if (write(fd, buf, i) != i) {
133 abort();
134 }
135 }
136
137 template <>
safe_print(int fd,const float & f)138 void safe_print(int fd, const float& f) {
139 safe_print<double>(fd, (double)f);
140 }
141
142 template <>
safe_print(int fd,const bool & b)143 void safe_print(int fd, const bool& b) {
144 if (b) {
145 safe_print(fd, "true");
146 } else {
147 safe_print(fd, "false");
148 }
149 }
150
151 template <>
safe_print(int fd,void * const & addr)152 void safe_print(int fd, void* const& addr) {
153 safe_print_hex(fd, (uint64_t)addr);
154 }
155
156 template <>
safe_print(int fd,const timespec & t)157 void safe_print(int fd, const timespec& t) {
158 safe_print<uint64_t>(fd, t.tv_sec);
159 safe_print(fd, ".");
160 safe_print_right_aligned(fd, t.tv_nsec, 9);
161 }
162
safe_print_hex(int fd,uint64_t i)163 void safe_print_hex(int fd, uint64_t i) {
164 char buf[BUFFER_SIZE];
165
166 safe_print(fd, "0x");
167 if (i == 0) {
168 safe_print(fd, "0");
169 return;
170 }
171
172 // This loop fills the buffer from the end. The number of elements in the
173 // buffer is BUFER_SIZE - idx - 1 and they start at position idx + 1.
174 ssize_t idx = BUFFER_SIZE - 1;
175 while (i != 0 && idx >= 0) {
176 char current = i % 16;
177 if (current <= 9) {
178 buf[idx] = '0' + current;
179 } else {
180 buf[idx] = 'a' + current - 10;
181 }
182 i /= 16;
183 idx--;
184 }
185
186 ssize_t nbyte = BUFFER_SIZE - idx - 1;
187 if (write(fd, buf + idx + 1, nbyte) != nbyte) {
188 abort();
189 }
190 }
191
safe_print_right_aligned(int fd,uint64_t i,ssize_t width)192 void safe_print_right_aligned(int fd, uint64_t i, ssize_t width) {
193 char buf[BUFFER_SIZE];
194
195 // Make sure that the result fits in the buffer
196 width = (width < BUFFER_SIZE) ? width : BUFFER_SIZE;
197
198 for (ssize_t j = 0; j < width; j++) {
199 buf[j] = '0';
200 }
201
202 ssize_t idx = width - 1;
203 while (i != 0 && idx >= 0) {
204 buf[idx] = '0' + i % 10;
205 i /= 10;
206 idx--;
207 }
208
209 if (write(fd, buf, width) != width) {
210 abort();
211 }
212 }
213
214 } /* CVC4 namespace */
215