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