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
16using namespace mcld;
17
18//===----------------------------------------------------------------------===//
19//  Diagnostic
20Diagnostic::Diagnostic(DiagnosticEngine& pEngine)
21  : m_Engine(pEngine) {
22}
23
24Diagnostic::~Diagnostic()
25{
26}
27
28// format - format this diagnostic into string, subsituting the formal
29// arguments. The result is appended at on the pOutStr.
30void 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
38const 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.
70void 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