Home | History | Annotate | Download | only in LD
      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 #include <llvm/Support/ErrorHandling.h>
     11 #include <llvm/Support/raw_ostream.h>
     12 #include <llvm/ADT/Twine.h>
     13 #include <ctype.h>
     14 #include <algorithm>
     15 
     16 using namespace mcld;
     17 
     18 //===----------------------------------------------------------------------===//
     19 //  Diagnostic
     20 Diagnostic::Diagnostic(DiagnosticEngine& pEngine)
     21   : m_Engine(pEngine) {
     22 }
     23 
     24 Diagnostic::~Diagnostic()
     25 {
     26 }
     27 
     28 // format - format this diagnostic into string, subsituting the formal
     29 // arguments. The result is appended at on the pOutStr.
     30 void Diagnostic::format(std::string& pOutStr) const
     31 {
     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 
     38 const char* Diagnostic::findMatch(char pVal,
     39                                   const char* pBegin, const char* pEnd ) const
     40 {
     41   unsigned int depth = 0;
     42   for (; pBegin != pEnd; ++pBegin) {
     43     if (0 == depth && *pBegin == pVal)
     44       return pBegin;
     45     if (0 != depth && *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.
     70 void Diagnostic::format(const char* pBegin, const char* pEnd,
     71                         std::string& pOutStr) const
     72 {
     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     }
     81     else if (ispunct(cur_char[1])) {
     82       pOutStr.push_back(cur_char[1]);  // %% -> %.
     83       cur_char += 2;
     84       continue;
     85     }
     86 
     87     // skip the %.
     88     ++cur_char;
     89 
     90     const char* modifier = NULL, *argument = NULL;
     91     size_t modifier_len = 0, argument_len = 0;
     92 
     93     // we get a modifier
     94     if (!isdigit(*cur_char)) {
     95       modifier = cur_char;
     96       while (*cur_char == '-' || (*cur_char >= 'a' && *cur_char <= 'z'))
     97         ++cur_char;
     98       modifier_len = cur_char - modifier;
     99 
    100       // we get an argument
    101       if ('{' == *cur_char) {
    102         ++cur_char; // skip '{'
    103         argument = cur_char;
    104         cur_char = findMatch('}', cur_char, pEnd);
    105 
    106         if (cur_char == pEnd) {
    107           // DIAG's format error
    108           llvm::report_fatal_error(llvm::Twine("Mismatched {} in the diagnostic: ") +
    109                                    llvm::Twine(getID()));
    110         }
    111 
    112         argument_len = cur_char - argument;
    113         ++cur_char; // skip '}'
    114       }
    115     }
    116     if (!isdigit(*cur_char)) {
    117       llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
    118                                llvm::Twine(getID()) + llvm::Twine(": ") +
    119                                llvm::Twine(pBegin) +
    120                                llvm::Twine("\nNo given arugment number:\n"));
    121     }
    122 
    123     unsigned int arg_no = *cur_char - '0';
    124     ++cur_char; // skip argument number
    125 
    126     DiagnosticEngine::ArgumentKind kind = getArgKind(arg_no);
    127     switch (kind) {
    128       case DiagnosticEngine::ak_std_string: {
    129         if (0 != modifier_len) {
    130           llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
    131                                    llvm::Twine(getID()) +
    132                                    llvm::Twine(": ") + llvm::Twine(pBegin) +
    133                                    llvm::Twine("\nNo modifiers for strings yet\n"));
    134         }
    135         const std::string& str = getArgStdStr(arg_no);
    136         pOutStr.append(str.begin(), str.end());
    137         break;
    138       }
    139       case DiagnosticEngine::ak_c_string: {
    140         if (0 != modifier_len) {
    141           llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
    142                                    llvm::Twine(getID()) +
    143                                    llvm::Twine(": ") + llvm::Twine(pBegin) +
    144                                    llvm::Twine("\nNo modifiers for strings yet\n"));
    145         }
    146         const char* str = getArgCStr(arg_no);
    147         if (NULL == str)
    148           str = "(null)";
    149         pOutStr.append(str);
    150         break;
    151       }
    152       case DiagnosticEngine::ak_sint: {
    153         int val = getArgSInt(arg_no);
    154         llvm::raw_string_ostream(pOutStr) << val;
    155         break;
    156       }
    157       case DiagnosticEngine::ak_uint: {
    158         unsigned int val = getArgUInt(arg_no);
    159         llvm::raw_string_ostream(pOutStr) << val;
    160         break;
    161       }
    162       case DiagnosticEngine::ak_bool: {
    163         bool val = getArgBool(arg_no);
    164         if (val)
    165           pOutStr.append("true");
    166         else
    167           pOutStr.append("false");
    168         break;
    169       }
    170     } // end of switch
    171   } // end of while
    172 }
    173 
    174