1 //===- Diagnostic.cpp -----------------------------------------------------===//
2 //
3 // The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "mcld/LD/Diagnostic.h"
10
11 #include <llvm/Support/ErrorHandling.h>
12 #include <llvm/Support/raw_ostream.h>
13 #include <llvm/ADT/Twine.h>
14
15 #include <algorithm>
16
17 #include <ctype.h>
18
19 namespace mcld {
20
21 //===----------------------------------------------------------------------===//
22 // Diagnostic
Diagnostic(DiagnosticEngine & pEngine)23 Diagnostic::Diagnostic(DiagnosticEngine& pEngine) : m_Engine(pEngine) {
24 }
25
~Diagnostic()26 Diagnostic::~Diagnostic() {
27 }
28
29 // format - format this diagnostic into string, subsituting the formal
30 // arguments. The result is appended at on the pOutStr.
format(std::string & pOutStr) const31 void Diagnostic::format(std::string& pOutStr) const {
32 // we've not implemented DWARF LOC messages yet. So, keep pIsLoC false
33 llvm::StringRef desc = m_Engine.infoMap().getDescription(getID(), false);
34
35 format(desc.begin(), desc.end(), pOutStr);
36 }
37
findMatch(char pVal,const char * pBegin,const char * pEnd) const38 const char* Diagnostic::findMatch(char pVal,
39 const char* pBegin,
40 const char* pEnd) const {
41 unsigned int depth = 0;
42 for (; pBegin != pEnd; ++pBegin) {
43 if (depth == 0 && *pBegin == pVal)
44 return pBegin;
45 if (depth != 0 && *pBegin == '}')
46 --depth;
47
48 if (*pBegin == '%') {
49 ++pBegin;
50 if (pBegin == pEnd)
51 break;
52
53 if (!isdigit(*pBegin) && !ispunct(*pBegin)) {
54 ++pBegin;
55 while (pBegin != pEnd && !isdigit(*pBegin) && *pBegin != '{')
56 ++pBegin;
57
58 if (pBegin == pEnd)
59 break;
60 if (*pBegin == '{')
61 ++depth;
62 }
63 }
64 } // end of for
65 return pEnd;
66 }
67
68 // format - format the given formal string, subsituting the formal
69 // arguments. The result is appended at on the pOutStr.
format(const char * pBegin,const char * pEnd,std::string & pOutStr) const70 void Diagnostic::format(const char* pBegin,
71 const char* pEnd,
72 std::string& pOutStr) const {
73 const char* cur_char = pBegin;
74 while (cur_char != pEnd) {
75 if (*cur_char != '%') {
76 const char* new_end = std::find(cur_char, pEnd, '%');
77 pOutStr.append(cur_char, new_end);
78 cur_char = new_end;
79 continue;
80 } else if (ispunct(cur_char[1])) {
81 pOutStr.push_back(cur_char[1]); // %% -> %.
82 cur_char += 2;
83 continue;
84 }
85
86 // skip the %.
87 ++cur_char;
88
89 const char* modifier = NULL;
90 size_t modifier_len = 0;
91
92 // we get a modifier
93 if (!isdigit(*cur_char)) {
94 modifier = cur_char;
95 while (*cur_char == '-' || (*cur_char >= 'a' && *cur_char <= 'z'))
96 ++cur_char;
97 modifier_len = cur_char - modifier;
98
99 // we get an argument
100 if (*cur_char == '{') {
101 ++cur_char; // skip '{'
102 cur_char = findMatch('}', cur_char, pEnd);
103
104 if (cur_char == pEnd) {
105 // DIAG's format error
106 llvm::report_fatal_error(
107 llvm::Twine("Mismatched {} in the diagnostic: ") +
108 llvm::Twine(getID()));
109 }
110
111 ++cur_char; // skip '}'
112 }
113 }
114 if (!isdigit(*cur_char)) {
115 llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
116 llvm::Twine(getID()) + llvm::Twine(": ") +
117 llvm::Twine(pBegin) +
118 llvm::Twine("\nNo given arugment number:\n"));
119 }
120
121 unsigned int arg_no = *cur_char - '0';
122 ++cur_char; // skip argument number
123
124 DiagnosticEngine::ArgumentKind kind = getArgKind(arg_no);
125 switch (kind) {
126 case DiagnosticEngine::ak_std_string: {
127 if (modifier_len != 0) {
128 llvm::report_fatal_error(
129 llvm::Twine("In diagnostic: ") + llvm::Twine(getID()) +
130 llvm::Twine(": ") + llvm::Twine(pBegin) +
131 llvm::Twine("\nNo modifiers for strings yet\n"));
132 }
133 const std::string& str = getArgStdStr(arg_no);
134 pOutStr.append(str.begin(), str.end());
135 break;
136 }
137 case DiagnosticEngine::ak_c_string: {
138 if (modifier_len != 0) {
139 llvm::report_fatal_error(
140 llvm::Twine("In diagnostic: ") + llvm::Twine(getID()) +
141 llvm::Twine(": ") + llvm::Twine(pBegin) +
142 llvm::Twine("\nNo modifiers for strings yet\n"));
143 }
144 const char* str = getArgCStr(arg_no);
145 if (str == NULL)
146 str = "(null)";
147 pOutStr.append(str);
148 break;
149 }
150 case DiagnosticEngine::ak_sint: {
151 int val = getArgSInt(arg_no);
152 llvm::raw_string_ostream(pOutStr) << val;
153 break;
154 }
155 case DiagnosticEngine::ak_uint: {
156 unsigned int val = getArgUInt(arg_no);
157 llvm::raw_string_ostream(pOutStr) << val;
158 break;
159 }
160 case DiagnosticEngine::ak_ulonglong: {
161 unsigned long long val = getArgUInt(arg_no);
162 llvm::raw_string_ostream(pOutStr) << val;
163 break;
164 }
165 case DiagnosticEngine::ak_bool: {
166 bool val = getArgBool(arg_no);
167 if (val)
168 pOutStr.append("true");
169 else
170 pOutStr.append("false");
171 break;
172 }
173 } // end of switch
174 } // end of while
175 }
176
177 } // namespace mcld
178