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