1 // Copyright (c) 1994, 1995 James Clark
2 // See the file COPYING for copying permission.
3 #pragma ident "%Z%%M% %I% %E% SMI"
4
5 #ifdef __GNUG__
6 #pragma implementation
7 #endif
8
9 #include "splib.h"
10 #include "MessageReporter.h"
11 #include "MessageReporterMessages.h"
12 #include "ExtendEntityManager.h"
13 #include "StorageManager.h"
14 #include "macros.h"
15
16 #include <string.h>
17
18 #ifdef SP_NAMESPACE
19 namespace SP_NAMESPACE {
20 #endif
21
22 const OutputCharStream::Newline nl = OutputCharStream::newline;
23
MessageReporter(OutputCharStream * os)24 MessageReporter::MessageReporter(OutputCharStream *os)
25 : os_(os), options_(0)
26 {
27 }
28
~MessageReporter()29 MessageReporter::~MessageReporter()
30 {
31 delete os_;
32 }
33
setMessageStream(OutputCharStream * os)34 void MessageReporter::setMessageStream(OutputCharStream *os)
35 {
36 if (os != os_) {
37 delete os_;
38 os_ = os;
39 }
40 }
41
addOption(Option option)42 void MessageReporter::addOption(Option option)
43 {
44 options_ |= option;
45 }
46
dispatchMessage(const Message & message)47 void MessageReporter::dispatchMessage(const Message &message)
48 {
49 Offset off;
50 const ExternalInfo *externalInfo = locationHeader(message.loc, off);
51 if (programName_.size())
52 os() << programName_ << ':';
53 if (externalInfo) {
54 printLocation(externalInfo, off);
55 os() << ':';
56 }
57 if (options_ & messageNumbers)
58 os() << (unsigned long)message.type->module() << "."
59 << (unsigned long)message.type->number() << ":";
60 switch (message.type->severity()) {
61 case MessageType::info:
62 formatFragment(MessageReporterMessages::infoTag, os());
63 break;
64 case MessageType::warning:
65 formatFragment(MessageReporterMessages::warningTag, os());
66 break;
67 case MessageType::quantityError:
68 formatFragment(MessageReporterMessages::quantityErrorTag, os());
69 break;
70 case MessageType::idrefError:
71 formatFragment(MessageReporterMessages::idrefErrorTag, os());
72 break;
73 case MessageType::error:
74 formatFragment(MessageReporterMessages::errorTag, os());
75 break;
76 default:
77 CANNOT_HAPPEN();
78 }
79 os() << ": ";
80 formatMessage(*message.type, message.args, os());
81 os() << nl;
82 if (!message.auxLoc.origin().isNull()) {
83 Offset off;
84 const ExternalInfo *externalInfo = locationHeader(message.auxLoc, off);
85 if (programName_.size())
86 os() << programName_ << ':';
87 if (externalInfo) {
88 printLocation(externalInfo, off);
89 os() << ": ";
90 }
91 formatMessage(message.type->auxFragment(), message.args, os());
92 os() << nl;
93 }
94 if ((options_ & openElements) && message.openElementInfo.size() > 0) {
95 if (programName_.size())
96 os() << programName_ << ':';
97 if (externalInfo) {
98 printLocation(externalInfo, off);
99 os() << ": ";
100 }
101 formatFragment(MessageReporterMessages::openElements, os());
102 os() << ':';
103 formatOpenElements(message.openElementInfo, os());
104 os() << nl;
105 }
106 os().flush();
107 }
108
109 // Note this is written so as not to change any reference counts.
110
locationHeader(const Location & loc,Offset & off)111 const ExternalInfo *MessageReporter::locationHeader(const Location &loc,
112 Offset &off)
113 {
114 return locationHeader(loc.origin().pointer(), loc.index(), off);
115 }
116
locationHeader(const Origin * origin,Index index,Offset & off)117 const ExternalInfo *MessageReporter::locationHeader(const Origin *origin,
118 Index index,
119 Offset &off)
120 {
121 if (!(options_ & openEntities)) {
122 while (origin) {
123 const ExternalInfo *externalInfo = origin->externalInfo();
124 if (externalInfo) {
125 off = origin->startOffset(index);
126 return externalInfo;
127 }
128 const Location &loc = origin->parent();
129 if (loc.origin().isNull()) {
130 if (!origin->defLocation(origin->startOffset(index), origin, index))
131 break;
132 }
133 else {
134 index = loc.index() + origin->refLength();
135 origin = loc.origin().pointer();
136 }
137 }
138 }
139 else {
140 Boolean doneHeader = 0;
141 while (origin) {
142 if (origin->entityName() || origin->parent().origin().isNull()) {
143 if (!doneHeader) {
144 Offset parentOff;
145 const Location &parentLoc = origin->parent();
146 const ExternalInfo *parentInfo
147 = locationHeader(parentLoc.origin().pointer(),
148 parentLoc.index() + origin->refLength(),
149 parentOff);
150 if (parentInfo) {
151 StringC text;
152 if (getMessageText(origin->entityName()
153 ? MessageReporterMessages::inNamedEntity
154 : MessageReporterMessages::inUnnamedEntity,
155 text)) {
156 for (size_t i = 0; i < text.size(); i++) {
157 if (text[i] == '%') {
158 if (i + 1 < text.size()) {
159 i++;
160 if (text[i] == '1')
161 os() << *origin->entityName();
162 else if (text[i] == '2')
163 printLocation(parentInfo, parentOff);
164 else if (text[i] >= '3' && text[i] <= '9')
165 ;
166 else
167 os().put(text[i]);
168 }
169 }
170 else
171 os().put(text[i]);
172 }
173 os() << nl;
174 }
175 }
176 doneHeader = 1;
177 }
178 off = origin->startOffset(index);
179 const ExternalInfo *externalInfo = origin->externalInfo();
180 if (externalInfo)
181 return externalInfo;
182 if (!origin->defLocation(off, origin, index))
183 break;
184 }
185 else {
186 const Location &loc = origin->parent();
187 index = loc.index() + origin->refLength();
188 origin = loc.origin().pointer();
189 }
190 }
191 }
192 return 0;
193 }
194
printLocation(const ExternalInfo * externalInfo,Offset off)195 void MessageReporter::printLocation(const ExternalInfo *externalInfo,
196 Offset off)
197 {
198 if (!externalInfo) {
199 formatFragment(MessageReporterMessages::invalidLocation, os());
200 return;
201 }
202 StorageObjectLocation soLoc;
203 if (!ExtendEntityManager::externalize(externalInfo, off, soLoc)) {
204 formatFragment(MessageReporterMessages::invalidLocation, os());
205 return;
206 }
207 if (strcmp(soLoc.storageObjectSpec->storageManager->type(), "OSFILE") != 0)
208 os() << '<' << soLoc.storageObjectSpec->storageManager->type() << '>';
209 os() << soLoc.actualStorageId;
210 if (soLoc.lineNumber == (unsigned long)-1) {
211 os() << ": ";
212 formatFragment(MessageReporterMessages::offset, os());
213 os() << soLoc.storageObjectOffset;
214 }
215 else {
216 os() << ':' << soLoc.lineNumber;
217 if (soLoc.columnNumber != 0 && soLoc.columnNumber != (unsigned long)-1)
218 os() << ':' << soLoc.columnNumber - 1;
219 }
220 #if 0
221 if (soLoc.byteIndex != (unsigned long)-1)
222 os() << ':' << soLoc.byteIndex;
223 #endif
224 }
225
getMessageText(const MessageFragment & frag,StringC & str)226 Boolean MessageReporter::getMessageText(const MessageFragment &frag,
227 StringC &str)
228 {
229 const char *p = frag.text();
230 if (!p)
231 return 0;
232 str.resize(0);
233 for (; *p; p++)
234 str += Char((unsigned char)*p);
235 return 1;
236 }
237
238 #ifdef SP_NAMESPACE
239 }
240 #endif
241