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