1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | |
16 | #include "tensorflow/tsl/platform/stringprintf.h" |
17 | |
18 | #include <errno.h> |
19 | #include <stdarg.h> // For va_list and related operations |
20 | #include <stdio.h> // MSVC requires this for _vsnprintf |
21 | |
22 | namespace tsl { |
23 | namespace strings { |
24 | |
25 | void Appendv(string* dst, const char* format, va_list ap) { |
26 | // First try with a small fixed size buffer |
27 | static const int kSpaceLength = 1024; |
28 | char space[kSpaceLength]; |
29 | |
30 | // It's possible for methods that use a va_list to invalidate |
31 | // the data in it upon use. The fix is to make a copy |
32 | // of the structure before using it and use that copy instead. |
33 | va_list backup_ap; |
34 | va_copy(backup_ap, ap); |
35 | int result = vsnprintf(space, kSpaceLength, format, backup_ap); |
36 | va_end(backup_ap); |
37 | |
38 | if (result < kSpaceLength) { |
39 | if (result >= 0) { |
40 | // Normal case -- everything fit. |
41 | dst->append(space, result); |
42 | return; |
43 | } |
44 | |
45 | #ifdef _MSC_VER |
46 | // Error or MSVC running out of space. MSVC 8.0 and higher |
47 | // can be asked about space needed with the special idiom below: |
48 | va_copy(backup_ap, ap); |
49 | result = vsnprintf(nullptr, 0, format, backup_ap); |
50 | va_end(backup_ap); |
51 | #endif |
52 | |
53 | if (result < 0) { |
54 | // Just an error. |
55 | return; |
56 | } |
57 | } |
58 | |
59 | // Increase the buffer size to the size requested by vsnprintf, |
60 | // plus one for the closing \0. |
61 | int length = result + 1; |
62 | char* buf = new char[length]; |
63 | |
64 | // Restore the va_list before we use it again |
65 | va_copy(backup_ap, ap); |
66 | result = vsnprintf(buf, length, format, backup_ap); |
67 | va_end(backup_ap); |
68 | |
69 | if (result >= 0 && result < length) { |
70 | // It fit |
71 | dst->append(buf, result); |
72 | } |
73 | delete[] buf; |
74 | } |
75 | |
76 | string Printf(const char* format, ...) { |
77 | va_list ap; |
78 | va_start(ap, format); |
79 | string result; |
80 | Appendv(&result, format, ap); |
81 | va_end(ap); |
82 | return result; |
83 | } |
84 | |
85 | void Appendf(string* dst, const char* format, ...) { |
86 | va_list ap; |
87 | va_start(ap, format); |
88 | Appendv(dst, format, ap); |
89 | va_end(ap); |
90 | } |
91 | |
92 | } // namespace strings |
93 | } // namespace tsl |
94 | |