1 /*
2 * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <algorithm>
27 #include <string.h>
28 #include <cerrno>
29
30 #include "ErrorHandling.h"
31 #include "Log.h"
32
33
34 namespace {
35
getFilename(const SourceCodePos & pos)36 tstring getFilename(const SourceCodePos& pos) {
37 const std::string buf(pos.file);
38 const std::string::size_type idx = buf.find_last_of("\\/");
39 if (idx == std::string::npos) {
40 return tstrings::fromUtf8(buf);
41 }
42 return tstrings::fromUtf8(buf.substr(idx + 1));
43 }
44
reportError(const SourceCodePos & pos,const tstring & msg)45 void reportError(const SourceCodePos& pos, const tstring& msg) {
46 Logger::defaultLogger().log(Logger::LOG_ERROR, getFilename(pos).c_str(),
47 pos.lno, tstrings::fromUtf8(pos.func).c_str(), msg);
48 }
49
50 } // namespace
51
reportError(const SourceCodePos & pos,const std::runtime_error & e)52 void reportError(const SourceCodePos& pos, const std::runtime_error& e) {
53 reportError(pos, (tstrings::any() << "Exception with message \'"
54 << e.what() << "\' caught").tstr());
55 }
56
57
reportUnknownError(const SourceCodePos & pos)58 void reportUnknownError(const SourceCodePos& pos) {
59 reportError(pos, _T("Unknown exception caught"));
60 }
61
62
makeMessage(const std::runtime_error & e,const SourceCodePos & pos)63 std::string makeMessage(const std::runtime_error& e, const SourceCodePos& pos) {
64 std::ostringstream printer;
65 printer << getFilename(pos) << "(" << pos.lno << ") at "
66 << pos.func << "(): "
67 << e.what();
68 return printer.str();
69 }
70
71
72 namespace {
73
isNotSpace(int chr)74 bool isNotSpace(int chr) {
75 return isspace(chr) == 0;
76 }
77
78
79 enum TrimMode {
80 TrimLeading = 0x10,
81 TrimTrailing = 0x20,
82 TrimBoth = TrimLeading | TrimTrailing
83 };
84
85 // Returns position of the last printed character in the given string.
86 // Returns std::string::npos if nothing was printed.
printWithoutWhitespaces(std::ostream & out,const std::string & str,TrimMode mode)87 size_t printWithoutWhitespaces(std::ostream& out, const std::string& str,
88 TrimMode mode) {
89 std::string::const_reverse_iterator it = str.rbegin();
90 std::string::const_reverse_iterator end = str.rend();
91
92 if (mode & TrimLeading) {
93 // skip leading whitespace
94 std::string::const_iterator entry = std::find_if(str.begin(),
95 str.end(), isNotSpace);
96 end = std::string::const_reverse_iterator(entry);
97 }
98
99 if (mode & TrimTrailing) {
100 // skip trailing whitespace
101 it = std::find_if(it, end, isNotSpace);
102 }
103
104 if (it == end) {
105 return std::string::npos;
106 }
107
108 const size_t pos = str.rend() - end;
109 const size_t len = end - it;
110 out.write(str.c_str() + pos, len);
111 return pos + len - 1;
112 }
113
114 } // namespace
115
joinErrorMessages(const std::string & a,const std::string & b)116 std::string joinErrorMessages(const std::string& a, const std::string& b) {
117 const std::string endPhraseChars(";.,:!?");
118 const std::string space(" ");
119 const std::string dotAndSpace(". ");
120
121 std::ostringstream printer;
122 printer.exceptions(std::ios::failbit | std::ios::badbit);
123
124 size_t idx = printWithoutWhitespaces(printer, a, TrimTrailing);
125 size_t extra = 0;
126 if (idx < a.size() && endPhraseChars.find(a[idx]) == std::string::npos) {
127 printer << dotAndSpace;
128 extra = dotAndSpace.size();
129 } else if (idx != std::string::npos) {
130 printer << space;
131 extra = space.size();
132 }
133
134 idx = printWithoutWhitespaces(printer, b, TrimBoth);
135
136 const std::string str = printer.str();
137
138 if (std::string::npos == idx && extra) {
139 // Nothing printed from the 'b' message. Backout delimiter string.
140 return str.substr(0, str.size() - extra);
141 }
142 return str;
143 }
144
145
lastCRTError()146 std::string lastCRTError() {
147 #ifndef _WIN32
148 return strerror(errno);
149 #else
150 TCHAR buffer[2048];
151 if (0 == _tcserror_s(buffer, errno)) {
152 return (tstrings::any() << buffer).str();
153 }
154 return "";
155 #endif
156 }
157