//===- Diagnostic.cpp -----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <mcld/LD/Diagnostic.h> #include <llvm/Support/ErrorHandling.h> #include <llvm/Support/raw_ostream.h> #include <llvm/ADT/Twine.h> #include <ctype.h> #include <algorithm> using namespace mcld; //===----------------------------------------------------------------------===// // Diagnostic Diagnostic::Diagnostic(DiagnosticEngine& pEngine) : m_Engine(pEngine) { } Diagnostic::~Diagnostic() { } // format - format this diagnostic into string, subsituting the formal // arguments. The result is appended at on the pOutStr. void Diagnostic::format(std::string& pOutStr) const { // we've not implemented DWARF LOC messages yet. So, keep pIsLoC false llvm::StringRef desc = m_Engine.infoMap().getDescription(getID(), false); format(desc.begin(), desc.end(), pOutStr); } const char* Diagnostic::findMatch(char pVal, const char* pBegin, const char* pEnd ) const { unsigned int depth = 0; for (; pBegin != pEnd; ++pBegin) { if (0 == depth && *pBegin == pVal) return pBegin; if (0 != depth && *pBegin == '}') --depth; if ('%' == *pBegin) { ++pBegin; if (pBegin == pEnd) break; if (!isdigit(*pBegin) && !ispunct(*pBegin)) { ++pBegin; while (pBegin != pEnd && !isdigit(*pBegin) && *pBegin != '{') ++pBegin; if (pBegin == pEnd) break; if ('{' == *pBegin) ++depth; } } } // end of for return pEnd; } // format - format the given formal string, subsituting the formal // arguments. The result is appended at on the pOutStr. void Diagnostic::format(const char* pBegin, const char* pEnd, std::string& pOutStr) const { const char* cur_char = pBegin; while (cur_char != pEnd) { if ('%' != *cur_char) { const char* new_end = std::find(cur_char, pEnd, '%'); pOutStr.append(cur_char, new_end); cur_char = new_end; continue; } else if (ispunct(cur_char[1])) { pOutStr.push_back(cur_char[1]); // %% -> %. cur_char += 2; continue; } // skip the %. ++cur_char; const char* modifier = NULL; size_t modifier_len = 0; // we get a modifier if (!isdigit(*cur_char)) { modifier = cur_char; while (*cur_char == '-' || (*cur_char >= 'a' && *cur_char <= 'z')) ++cur_char; modifier_len = cur_char - modifier; // we get an argument if ('{' == *cur_char) { ++cur_char; // skip '{' cur_char = findMatch('}', cur_char, pEnd); if (cur_char == pEnd) { // DIAG's format error llvm::report_fatal_error(llvm::Twine("Mismatched {} in the diagnostic: ") + llvm::Twine(getID())); } ++cur_char; // skip '}' } } if (!isdigit(*cur_char)) { llvm::report_fatal_error(llvm::Twine("In diagnostic: ") + llvm::Twine(getID()) + llvm::Twine(": ") + llvm::Twine(pBegin) + llvm::Twine("\nNo given arugment number:\n")); } unsigned int arg_no = *cur_char - '0'; ++cur_char; // skip argument number DiagnosticEngine::ArgumentKind kind = getArgKind(arg_no); switch (kind) { case DiagnosticEngine::ak_std_string: { if (0 != modifier_len) { llvm::report_fatal_error(llvm::Twine("In diagnostic: ") + llvm::Twine(getID()) + llvm::Twine(": ") + llvm::Twine(pBegin) + llvm::Twine("\nNo modifiers for strings yet\n")); } const std::string& str = getArgStdStr(arg_no); pOutStr.append(str.begin(), str.end()); break; } case DiagnosticEngine::ak_c_string: { if (0 != modifier_len) { llvm::report_fatal_error(llvm::Twine("In diagnostic: ") + llvm::Twine(getID()) + llvm::Twine(": ") + llvm::Twine(pBegin) + llvm::Twine("\nNo modifiers for strings yet\n")); } const char* str = getArgCStr(arg_no); if (NULL == str) str = "(null)"; pOutStr.append(str); break; } case DiagnosticEngine::ak_sint: { int val = getArgSInt(arg_no); llvm::raw_string_ostream(pOutStr) << val; break; } case DiagnosticEngine::ak_uint: { unsigned int val = getArgUInt(arg_no); llvm::raw_string_ostream(pOutStr) << val; break; } case DiagnosticEngine::ak_ulonglong: { unsigned long long val = getArgUInt(arg_no); llvm::raw_string_ostream(pOutStr) << val; break; } case DiagnosticEngine::ak_bool: { bool val = getArgBool(arg_no); if (val) pOutStr.append("true"); else pOutStr.append("false"); break; } } // end of switch } // end of while }