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;
     91     size_t modifier_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         cur_char = findMatch('}', cur_char, pEnd);
    104 
    105         if (cur_char == pEnd) {
    106           // DIAG's format error
    107           llvm::report_fatal_error(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 (0 != modifier_len) {
    128           llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
    129                                    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 (0 != modifier_len) {
    139           llvm::report_fatal_error(llvm::Twine("In diagnostic: ") +
    140                                    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 (NULL == str)
    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