dsdm: Change to ANSI function definitions
[oweals/cde.git] / cde / programs / nsgmls / MessageReporter.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: MessageReporter.C /main/1 1996/07/29 16:57:32 cde-hp $ */
24 // Copyright (c) 1994, 1995 James Clark
25 // See the file COPYING for copying permission.
26
27 #ifdef __GNUG__
28 #pragma implementation
29 #endif
30
31 #include "splib.h"
32 #include "MessageReporter.h"
33 #include "ExtendEntityManager.h"
34 #include "StorageManager.h"
35 #include "macros.h"
36 #include "rtti.h"
37 #include "MessageArg.h"
38 #include "ErrnoMessageArg.h"
39 #include "SearchResultMessageArg.h"
40 #include "MessageReporterMessages.h"
41
42 #include <string.h>
43 #include <errno.h>
44
45 #ifdef DECLARE_STRERROR
46 extern "C" {
47   char *strerror(int);
48 }
49 #endif
50
51 #ifdef SP_NAMESPACE
52 namespace SP_NAMESPACE {
53 #endif
54
55 const OutputCharStream::Newline nl = OutputCharStream::newline;
56
57 MessageReporter::MessageReporter(OutputCharStream *os)
58 : os_(os), options_(0)
59 {
60 }
61
62 MessageReporter::~MessageReporter()
63 {
64   delete os_;
65 }
66
67 void MessageReporter::setMessageStream(OutputCharStream *os)
68 {
69   if (os != os_) {
70     delete os_;
71     os_ = os;
72   }
73 }
74
75 void MessageReporter::addOption(Option option)
76 {
77   options_ |= option;
78 }
79
80 void MessageReporter::dispatchMessage(Message &message)
81 {
82   dispatchMessage((const Message &) message);
83 }
84
85 void MessageReporter::dispatchMessage(const Message &message)
86 {
87   Offset off;
88   const ExternalInfo *externalInfo = locationHeader(message.loc, off);
89   if (programName_.size())
90     os() << programName_ << ':';
91   if (externalInfo) {
92     printLocation(externalInfo, off);
93     os() << ':';
94   }
95   if (options_ & messageNumbers)
96     os() << (unsigned long)message.type->module() << "." 
97       << (unsigned long)message.type->number() << ":";
98   switch (message.type->severity()) {
99   case MessageType::info:
100     appendFragment(MessageReporterMessages::infoTag);
101     break;
102   case MessageType::warning:
103     appendFragment(MessageReporterMessages::warningTag);
104     break;
105   case MessageType::quantityError:
106     appendFragment(MessageReporterMessages::quantityErrorTag);
107     break;
108   case MessageType::idrefError:
109     appendFragment(MessageReporterMessages::idrefErrorTag);
110     break;
111   case MessageType::error:
112     appendFragment(MessageReporterMessages::errorTag);
113     break;
114   default:
115     CANNOT_HAPPEN();
116   }
117   os() << ": ";
118   formatMessage(*message.type, message.args);
119   os() << nl;
120   if (!message.auxLoc.origin().isNull()) {
121     Offset off;
122     const ExternalInfo *externalInfo = locationHeader(message.auxLoc, off);
123     if (programName_.size())
124       os() << programName_ << ':';
125     if (externalInfo) {
126       printLocation(externalInfo, off);
127       os() << ": ";
128     }
129     formatMessage(message.type->auxFragment(), message.args);
130     os() << nl;
131   }
132   if ((options_ & openElements) && message.openElementInfo.size() > 0) {
133     if (programName_.size())
134       os() << programName_ << ':';
135     if (externalInfo) {
136       printLocation(externalInfo, off);
137       os() << ": ";
138     }
139     appendFragment(MessageReporterMessages::openElements);
140     os() << ':';
141     unsigned nOpenElements = message.openElementInfo.size();
142     for (unsigned i = 0;; i++) {
143       if (i > 0
144           && (i == nOpenElements || message.openElementInfo[i].included)) {
145         // describe last match in previous open element
146         const OpenElementInfo &prevInfo = message.openElementInfo[i - 1];
147         if (prevInfo.matchType.size() != 0) {
148           os() << " (" << prevInfo.matchType;
149           if (prevInfo.matchIndex != 0)
150             os() << '[' << (unsigned long)prevInfo.matchIndex << ']';
151           os() << ')';
152         }
153       }
154       if (i == nOpenElements)
155         break;
156       const OpenElementInfo &e = message.openElementInfo[i];
157       os() << ' ' << e.gi;
158       if (i > 0 && !e.included) {
159         unsigned long n = message.openElementInfo[i - 1].matchIndex;
160         if (n != 0)
161           os() << '[' << n << ']';
162       }
163     }
164     os() << nl;
165   }
166   os().flush();
167 }
168
169 void MessageReporter::formatMessage(const MessageFragment &frag,
170                                     const Vector<CopyOwner<MessageArg> > &args)
171 {
172   StringC text;
173   if (!getMessageText(frag, text)) {
174     appendFragment(MessageReporterMessages::invalidMessage);
175     return;
176   }
177   size_t i = 0;
178   while (i < text.size()) {
179     if (text[i] == '%') {
180       i++;
181       if (i >= text.size())
182         break;
183       if (text[i] >= '1' && text[i] <= '9') {
184         if (unsigned(text[i] - '1') < args.size())
185           args[text[i] - '1']->append(*this);
186       }
187       else
188         os().put(text[i]);
189       i++;
190     }
191     else {
192       os().put(text[i]);
193       i++;
194     }
195   }
196 }
197
198 const ExternalInfo *MessageReporter::locationHeader(const Location &loc,
199                                                     Offset &off)
200 {
201   const Origin *origin = loc.origin().pointer();
202   Index index = loc.index();
203   if (!(options_ & openEntities)) {
204     while (origin) {
205       const InputSourceOrigin *inputSourceOrigin = origin->asInputSourceOrigin();
206       if (inputSourceOrigin) {
207         const ExternalInfo *externalInfo = inputSourceOrigin->externalInfo();
208         if (externalInfo) {
209           off = inputSourceOrigin->startOffset(index);
210           return externalInfo;
211         }
212       }
213       const Location &loc = origin->parent();
214       index = loc.index() + origin->refLength();
215       origin = loc.origin().pointer();
216     }
217   }
218   else {
219     Boolean doneHeader = 0;
220     while (origin) {
221       const InputSourceOrigin *inputSourceOrigin = origin->asInputSourceOrigin();
222       if (inputSourceOrigin) {
223         if (!doneHeader) {
224           Offset parentOff;
225           Location parentLoc = inputSourceOrigin->parent();
226           parentLoc += inputSourceOrigin->refLength();
227           const ExternalInfo *parentInfo = locationHeader(parentLoc, parentOff);
228           if (parentInfo) {
229             StringC text;
230             if (getMessageText(inputSourceOrigin->entityName()
231                                ? MessageReporterMessages::inNamedEntity
232                                : MessageReporterMessages::inUnnamedEntity,
233                                 text)) {
234               for (size_t i = 0; i < text.size(); i++) {
235                 if (text[i] == '%') {
236                   if (i + 1 < text.size()) {
237                     i++;
238                     if (text[i] == '1')
239                       os() << *inputSourceOrigin->entityName();
240                     else if (text[i] == '2')
241                       printLocation(parentInfo, parentOff);
242                     else if (text[i] >= '3' && text[i] <= '9')
243                       ;
244                     else
245                       os().put(text[i]);
246                   }
247                 }
248                 else
249                   os().put(text[i]);
250               }
251               os() << nl;
252             }
253           }
254           doneHeader = 1;
255         }
256         off = inputSourceOrigin->startOffset(index);
257         const ExternalInfo *externalInfo = inputSourceOrigin->externalInfo();
258         if (externalInfo)
259           return externalInfo;
260         Location loc;
261         if (!inputSourceOrigin->defLocation(off, loc))
262           break;
263         index = loc.index();
264         origin = loc.origin().pointer();
265       }
266       else {
267         const Location &loc = origin->parent();
268         index = loc.index() + origin->refLength();
269         origin = loc.origin().pointer();
270       }
271     }
272   }
273   return 0;
274 }
275
276 void MessageReporter::printLocation(const ExternalInfo *externalInfo,
277                                     Offset off)
278 {
279   if (!externalInfo) {
280     appendFragment(MessageReporterMessages::invalidLocation);
281     return;
282   }
283   StorageObjectLocation soLoc;
284   if (!ExtendEntityManager::externalize(externalInfo, off, soLoc)) {
285     appendFragment(MessageReporterMessages::invalidLocation);
286     return;
287   }
288   if (strcmp(soLoc.storageObjectSpec->storageManager->type(), "OSFILE") != 0)
289     os() << '<' << soLoc.storageObjectSpec->storageManager->type() << '>';
290   os() << soLoc.storageObjectSpec->id;
291   if (soLoc.lineNumber == (unsigned long)-1) {
292     os() << ": ";
293     appendFragment(MessageReporterMessages::offset);
294     os() << soLoc.storageObjectOffset;
295   }
296   else {
297     os() << ':' << soLoc.lineNumber;
298     if (soLoc.columnNumber != 0 && soLoc.columnNumber != (unsigned long)-1)
299       os() << ':' << soLoc.columnNumber - 1;
300   }
301 #if 0
302   if (soLoc.byteIndex != (unsigned long)-1)
303     os() << ':' << soLoc.byteIndex;
304 #endif
305 }
306
307 void MessageReporter::appendNumber(unsigned long n)
308 {
309   os() << n;
310 }
311
312 void MessageReporter::appendOrdinal(unsigned long n)
313 {
314   os() << n;
315   switch (n % 10) {
316   case 1:
317     appendFragment(MessageReporterMessages::ordinal1);
318     break;
319   case 2:
320     appendFragment(MessageReporterMessages::ordinal2);
321     break;
322   case 3:
323     appendFragment(MessageReporterMessages::ordinal3);
324     break;
325   default:
326     appendFragment(MessageReporterMessages::ordinaln);
327     break;
328   }
329 }
330
331 void MessageReporter::appendChars(const Char *p, size_t n)
332 {
333   os().put('"').write(p, n).put('"');
334 }
335
336 void MessageReporter::appendOther(const OtherMessageArg *p)
337 {
338   const ErrnoMessageArg *ea = DYNAMIC_CAST_CONST_PTR(ErrnoMessageArg, p);
339   
340   if (ea) {
341     os() << strerror(ea->errnum());
342     return;
343   }
344
345   const SearchResultMessageArg *sr
346     = DYNAMIC_CAST_CONST_PTR(SearchResultMessageArg, p);
347   if (sr) {
348     for (size_t i = 0; i < sr->nTried(); i++) {
349       if (i > 0)
350         os() << ", ";
351       const StringC &f = sr->filename(i);
352       appendChars(f.data(), f.size());
353       switch (sr->errnum(i)) {
354       default:
355         os() << " (";
356         os() << strerror(sr->errnum(i));
357         os() << ")";
358 #ifdef ENOENT
359       case ENOENT:
360 #endif
361         break;
362       }
363     }
364     return;
365   }
366   appendFragment(MessageReporterMessages::invalidArgumentType);
367 }
368
369 void MessageReporter::appendFragment(const MessageFragment &frag)
370 {
371   StringC text;
372   if (getMessageText(frag, text))
373     os() << text;
374 }
375
376 Boolean MessageReporter::getMessageText(const MessageFragment &frag,
377                                         StringC &str)
378 {
379   const char *p = frag.text();
380   if (!p)
381     return 0;
382   str.resize(0);
383   for (; *p; p++)
384     str += Char((unsigned char)*p);
385   return 1;
386 }
387
388 #ifdef SP_NAMESPACE
389 }
390 #endif