Link with C++ linker
[oweals/cde.git] / cde / programs / nsgmls / SgmlsEventHandler.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 librararies 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: SgmlsEventHandler.C /main/1 1996/07/29 17:04:20 cde-hp $ */
24 // Copyright (c) 1994 James Clark
25 // See the file COPYING for copying permission.
26
27 #include "config.h"
28 #include "SgmlsEventHandler.h"
29 #include "SgmlParser.h"
30 #include "ParserOptions.h"
31 #include "Entity.h"
32 #include "Notation.h"
33 #include "Attribute.h"
34 #include "ExtendEntityManager.h"
35 #include "StorageManager.h"
36 #include "macros.h"
37
38 #ifdef SP_NAMESPACE
39 namespace SP_NAMESPACE {
40 #endif
41
42 const char dataCode = '-';
43 const char piCode = '?';
44 const char conformingCode = 'C';
45 const char appinfoCode = '#';
46 const char startElementCode = '(';
47 const char endElementCode = ')';
48 const char referenceEntityCode = '&';
49 const char attributeCode = 'A';
50 const char dataAttributeCode = 'D';
51 const char linkAttributeCode = 'a';
52 const char defineNotationCode = 'N';
53 const char defineExternalEntityCode = 'E';
54 const char defineInternalEntityCode = 'I';
55 const char defineSubdocEntityCode = 'S';
56 const char defineExternalTextEntityCode = 'T';
57 const char pubidCode = 'p';
58 const char sysidCode = 's';
59 const char startSubdocCode = '{';
60 const char endSubdocCode = '}';
61 const char fileCode = 'f';
62 const char locationCode = 'L';
63 const char includedElementCode = 'i';
64
65 const OutputCharStream::Newline nl = OutputCharStream::newline;
66
67 const char space = ' ';
68 const Char re = '\r';
69
70 inline
71 void SgmlsEventHandler::startData()
72 {
73   if (!haveData_) {
74     os() << dataCode;
75     haveData_ = 1;
76   }
77 }
78
79 inline
80 void SgmlsEventHandler::flushData()
81 {
82   if (haveData_) {
83     os() << nl;
84     haveData_ = 0;
85   }
86 }
87
88 inline
89 void SgmlsEventHandler::outputLocation(const Location &loc)
90 {
91   if (outputLine_)
92     outputLocation1(loc);
93 }
94
95 SgmlsEventHandler::SgmlsEventHandler(const SgmlParser *parser,
96                                      OutputCharStream *os,
97                                      Messenger *messenger,
98                                      unsigned outputFlags)
99 : SgmlsSubdocState(parser), os_(os), messenger_(messenger),
100   outputLine_((outputFlags & outputLine) != 0),
101   outputEntity_((outputFlags & outputEntity) != 0),
102   outputId_((outputFlags & outputId) != 0),
103   outputNotationSysid_((outputFlags & outputNotationSysid) != 0),
104   outputIncluded_((outputFlags & outputIncluded) != 0),
105   haveData_(0), lastSos_(0)
106 {
107   os_->setEscaper(escape);
108 }
109
110 SgmlsEventHandler::~SgmlsEventHandler()
111 {
112   flushData();
113   if (errorCount() == 0)
114     os() << conformingCode << nl;
115   delete os_;
116 }
117
118 void SgmlsEventHandler::message(MessageEvent *event)
119 {
120   messenger_->dispatchMessage(event->message());
121   ErrorCountEventHandler::message(event);
122 }
123
124 void SgmlsEventHandler::appinfo(AppinfoEvent *event)
125 {
126   const StringC *str;
127   if (event->literal(str)) {
128     outputLocation(event->location());
129     flushData();
130     os() << appinfoCode;
131     outputString(*str);
132     os() << nl;
133   }
134   delete event;
135 }
136
137 void SgmlsEventHandler::endProlog(EndPrologEvent *event)
138 {
139   if (outputEntity_) {
140     flushData();
141     const Dtd &dtd = event->dtd();
142     Dtd::ConstEntityIter iter(dtd.generalEntityIter());
143     for (;;) {
144       const Entity *entity = iter.next().pointer();
145       if (!entity)
146         break;
147       defineEntity(entity);
148     }
149   }
150   if (!event->lpdPointer().isNull()) {
151     linkProcess_.init(event->lpdPointer());
152     haveLinkProcess_ = 1;
153     flushData();
154   }
155   for (size_t i = 0; i < event->simpleLinkNames().size(); i++) {
156     flushData();
157     attributes(event->simpleLinkAttributes()[i],
158                linkAttributeCode,
159                &event->simpleLinkNames()[i]);
160   }
161   delete event;
162 }
163
164 void SgmlsEventHandler::entityDefaulted(EntityDefaultedEvent *event)
165 {
166   if (outputEntity_) {
167     flushData();
168     defineEntity(event->entityPointer().pointer());
169   }
170   delete event;
171 }
172
173 void SgmlsEventHandler::uselink(UselinkEvent *event)
174 {
175   linkProcess_.uselink(event->linkSet(),
176                        event->restore(),
177                        event->lpd().pointer());
178   delete event;
179 }
180
181 void SgmlsEventHandler::sgmlDecl(SgmlDeclEvent *event)
182 {
183   sd_ = event->sdPointer();
184   syntax_ = event->instanceSyntaxPointer(); // FIXME which syntax?
185   delete event;
186 }
187
188 void SgmlsEventHandler::data(DataEvent *event)
189 {
190   outputLocation(event->location());
191   startData();
192   outputString(event->data(), event->dataLength());
193   delete event;
194 }
195
196 void SgmlsEventHandler::sdataEntity(SdataEntityEvent *event)
197 {
198   outputLocation(event->location());
199   startData();
200   os() << "\\|";
201   outputString(event->data(), event->dataLength());
202   os() << "\\|";
203   delete event;
204 }
205
206 void SgmlsEventHandler::pi(PiEvent *event)
207 {
208   outputLocation(event->location());
209   flushData();
210   os() << piCode;
211   outputString(event->data(), event->dataLength());
212   os() << nl;
213   delete event;
214 }
215
216 void SgmlsEventHandler::startElement(StartElementEvent *event)
217 {
218   flushData();
219   currentLocation_ = event->location();
220   if (haveLinkProcess_) {
221     const AttributeList *linkAttributes;
222     const ResultElementSpec *resultElementSpec;
223     linkProcess_.startElement(event->elementType(),
224                               event->attributes(),
225                               event->location(),
226                               *this, // Messenger &
227                               linkAttributes,
228                               resultElementSpec);
229     if (linkAttributes)
230       attributes(*linkAttributes, linkAttributeCode, &linkProcess_.name());
231   }
232   attributes(event->attributes(), attributeCode, 0);
233   currentLocation_.clear();
234   if (outputIncluded_ && event->included())
235     os() << includedElementCode << nl;
236   outputLocation(event->location());
237   os() << startElementCode << event->name() << nl;
238   delete event;
239 }
240
241 void SgmlsEventHandler::attributes(const AttributeList &attributes,
242                                    char code,
243                                    const StringC *ownerName)
244 {
245   size_t nAttributes = attributes.size();
246   for (size_t i = 0; i < nAttributes; i++) {
247     const Text *text;
248     const StringC *string;
249     const AttributeValue *value = attributes.value(i);
250     if (value) {
251       switch (value->info(text, string)) {
252       case AttributeValue::implied:
253         startAttribute(attributes.name(i), code, ownerName);
254         os() << "IMPLIED" << nl;
255         break;
256       case AttributeValue::tokenized:
257         {
258           const char *typeString = "TOKEN";
259           const AttributeSemantics *semantics = attributes.semantics(i);
260           if (semantics) {
261             ConstPtr<Notation> notation
262               = semantics->notation();
263             if (!notation.isNull()) {
264               defineNotation(notation.pointer());
265               typeString = "NOTATION";
266             }
267             else {
268               size_t nEntities = semantics->nEntities();
269               if (nEntities) {
270                 typeString = "ENTITY";
271                 if (!outputEntity_)
272                   for (size_t i = 0; i < nEntities; i++) {
273                     const Entity *entity = semantics->entity(i).pointer();
274                     if (!markEntity(entity))
275                       defineEntity(entity);
276                   }
277               }
278             }
279           }
280           if (outputId_ && attributes.id(i))
281             typeString = "ID";
282           startAttribute(attributes.name(i), code, ownerName);
283           os() << typeString << space << *string << nl;
284         }
285         break;
286       case AttributeValue::cdata:
287         {
288           startAttribute(attributes.name(i), code, ownerName);
289           os() << "CDATA ";
290           TextIter iter(*text);
291           TextItem::Type type;
292           const Char *p;
293           size_t length;
294           const Location *loc;
295           while (iter.next(type, p, length, loc))
296             switch (type) {
297             case TextItem::data:
298             case TextItem::cdata:
299               outputString(p, length);
300               break;
301             case TextItem::sdata:
302               os() << "\\|";
303               outputString(p, length);
304               os() << "\\|";
305               break;
306             default:
307               break;
308             }
309           os() << nl;
310         }
311         break;
312       }
313     }
314   }
315 }
316
317 void SgmlsEventHandler::startAttribute(const StringC &name,
318                                        char code,
319                                        const StringC *ownerName)
320 {
321   os() << code;
322   if (ownerName)
323     os() << *ownerName << space;
324   os() << name << space;
325 }
326
327 void SgmlsEventHandler::endElement(EndElementEvent *event)
328 {
329   flushData();
330   if (haveLinkProcess_)
331     linkProcess_.endElement();
332   outputLocation(event->location());
333   os() << endElementCode << event->name() << nl;
334   delete event;
335 }
336
337 void SgmlsEventHandler::externalDataEntity(ExternalDataEntityEvent *event)
338 {
339   currentLocation_ = event->location();
340   outputLocation(event->location());
341   flushData();
342   if (!outputEntity_ && !markEntity(event->entity()))
343     defineExternalDataEntity(event->entity());
344   currentLocation_.clear();
345   os() << referenceEntityCode << event->entity()->name() << nl;
346   delete event;
347 }
348
349 void SgmlsEventHandler::subdocEntity(SubdocEntityEvent *event)
350 {
351   currentLocation_ = event->location();
352   outputLocation(event->location());
353   flushData();
354   const SubdocEntity *entity = event->entity();
355   if (!outputEntity_ && !markEntity(entity))
356     defineSubdocEntity(entity);
357   currentLocation_.clear();
358   os() << startSubdocCode << entity->name() << nl;
359   SgmlParser::Params params;
360   params.subdocInheritActiveLinkTypes = 1;
361   params.subdocReferenced = 1;
362   params.origin = event->entityOrigin()->copy();
363   params.parent = parser_;
364   params.sysid = entity->externalId().effectiveSystemId();
365   params.entityType = SgmlParser::Params::subdoc;
366   SgmlParser parser(params);
367   SgmlsSubdocState oldState;
368   SgmlsSubdocState::swap(oldState);
369   SgmlsSubdocState::init(&parser);
370   parser.parseAll(*this);
371   oldState.swap(*this);
372   os() << endSubdocCode << entity->name() << nl;
373   delete event;
374 }
375
376 void SgmlsEventHandler::defineEntity(const Entity *entity)
377 {
378   const InternalEntity *internalEntity = entity->asInternalEntity();
379   if (internalEntity)
380     defineInternalEntity(internalEntity);
381   else {
382     switch (entity->dataType()) {
383     case Entity::cdata:
384     case Entity::sdata:
385     case Entity::ndata:
386       defineExternalDataEntity(entity->asExternalDataEntity());
387       break;
388     case Entity::subdoc:
389       defineSubdocEntity(entity->asSubdocEntity());
390       break;
391     case Entity::sgmlText:
392       defineExternalTextEntity(entity->asExternalEntity());
393       break;
394     default:
395       CANNOT_HAPPEN();
396     }
397   }
398 }
399
400 void SgmlsEventHandler::defineExternalDataEntity(const ExternalDataEntity *entity)
401 {
402   const Notation *notation = entity->notation();
403   defineNotation(notation);
404   externalId(entity->externalId());
405   const char *typeString;
406   switch (entity->dataType()) {
407   case Entity::cdata:
408     typeString = "CDATA";
409     break;
410   case Entity::sdata:
411     typeString = "SDATA";
412     break;
413   case Entity::ndata:
414     typeString = "NDATA";
415     break;
416   default:
417     CANNOT_HAPPEN();
418   }
419   os() << defineExternalEntityCode << entity->name()
420        << space << typeString
421        << space << notation->name()
422        << nl;
423   attributes(entity->attributes(), dataAttributeCode, &entity->name());
424 }
425
426 void SgmlsEventHandler::defineSubdocEntity(const SubdocEntity *entity)
427 {
428   externalId(entity->externalId());
429   os() << defineSubdocEntityCode << entity->name() << nl;
430 }
431
432 void SgmlsEventHandler::defineExternalTextEntity(const ExternalEntity *entity)
433 {
434   externalId(entity->externalId());
435   os() << defineExternalTextEntityCode << entity->name() << nl;
436 }
437
438 void SgmlsEventHandler::defineInternalEntity(const InternalEntity *entity)
439 {
440   os() << defineInternalEntityCode << entity->name() << space;
441   const char *s;
442   switch (entity->dataType()) {
443   case Entity::sdata:
444     s = "SDATA";
445     break;
446   case Entity::cdata:
447     s = "CDATA";
448     break;
449   case Entity::sgmlText:
450     s = "TEXT";
451     break;
452   case Entity::pi:
453     s = "PI";
454     break;
455   default:
456     CANNOT_HAPPEN();
457   }
458   os() << s << space;
459   outputString(entity->string());
460   os() << nl;
461 }
462
463 void SgmlsEventHandler::defineNotation(const Notation *notation)
464 {
465   if (markNotation(notation))
466     return;
467   externalId(notation->externalId(), outputNotationSysid_);
468   os() << defineNotationCode << notation->name() << nl;
469 }
470
471 void SgmlsEventHandler::externalId(const ExternalId &id, Boolean outputFile)
472 {
473   const StringC *str = id.publicIdString();
474   if (str) {
475     os() << pubidCode;
476     outputString(*str);
477     os() << nl;
478   }
479   str = id.systemIdString();
480   if (str) {
481     os() << sysidCode;
482     outputString(*str);
483     os() << nl;
484   }
485   if (outputFile && id.effectiveSystemId().size()) {
486     os() << fileCode;
487     outputString(id.effectiveSystemId());
488     os() << nl;
489   }
490 }
491
492 Boolean SgmlsEventHandler::markEntity(const Entity *entity)
493 {
494   return definedEntities_.add(entity->name());
495 }
496
497 Boolean SgmlsEventHandler::markNotation(const Notation *notation)
498 {
499   return definedNotations_.add(notation->name());
500 }
501
502 void SgmlsEventHandler::outputString(const Char *p, size_t n)
503 {
504   for (; n > 0; p++, n--) {
505     switch (*p) {
506     case '\\':                  // FIXME we're punning Chars and chars
507       os() << "\\\\";
508       break;
509     case re:
510       os() << "\\n";
511       if (outputLine_ && haveData_)
512         lastLineno_++;
513       break;
514     default:
515       // FIXME not clear what to do here given possibility of wide characters
516       if (*p < 040) {
517         static const char digits[] = "0123456789";
518         os() << "\\0" << digits[*p / 8] << digits[*p % 8];
519       }
520       else
521         os().put(*p);
522       break;
523     }
524   }
525 }
526
527 void SgmlsEventHandler::escape(OutputCharStream &s, Char c)
528 {
529   s << "\\#" << (unsigned long)c << ";";
530 }
531
532 void SgmlsEventHandler::outputLocation1(const Location &loc)
533 {
534   const Origin *origin = loc.origin().pointer();
535   const InputSourceOrigin *inputSourceOrigin;
536   const ExternalInfo *info;
537   Index index = loc.index();
538   for (;;) {
539     if (!origin)
540       return;
541     inputSourceOrigin = origin->asInputSourceOrigin();
542     if (inputSourceOrigin) {
543       info = inputSourceOrigin->externalInfo();
544       if (info)
545         break;
546     }
547     const Location &loc = origin->parent();
548     index = loc.index();
549     origin = loc.origin().pointer();
550   }
551   Offset off = inputSourceOrigin->startOffset(index);
552   StorageObjectLocation soLoc;
553   if (!ExtendEntityManager::externalize(info, off, soLoc))
554     return;
555   if (soLoc.lineNumber == (unsigned long)-1)
556     return;
557   if (soLoc.storageObjectSpec == lastSos_) {
558     if (soLoc.lineNumber == lastLineno_)
559       return;
560     flushData();
561     os() << locationCode << soLoc.lineNumber << nl;
562     lastLineno_ = soLoc.lineNumber;
563   }
564   else {
565     flushData();
566     os() << locationCode << soLoc.lineNumber << space;
567     outputString(soLoc.storageObjectSpec->id);
568     os() << nl;
569     lastLineno_ = soLoc.lineNumber;
570     lastSos_ = soLoc.storageObjectSpec;
571     lastLoc_ = loc;             // make sure lastSos_ doesn't get freed
572   }
573 }
574
575 void SgmlsEventHandler::dispatchMessage(Message &msg)
576 {
577   dispatchMessage((const Message &) msg);
578 }
579
580 void SgmlsEventHandler::dispatchMessage(const Message &msg)
581 {
582   if (!cancelled()) {
583     noteMessage(msg);
584     messenger_->dispatchMessage(msg);
585   }
586 }
587
588 void SgmlsEventHandler::initMessage(Message &msg)
589 {
590   msg.loc = currentLocation_;
591 }
592
593 SgmlsSubdocState::SgmlsSubdocState()
594 : haveLinkProcess_(0), parser_(0)
595 {
596 }
597
598 SgmlsSubdocState::SgmlsSubdocState(const SgmlParser *parser)
599 : haveLinkProcess_(0), parser_(parser)
600 {
601 }
602
603 void SgmlsSubdocState::init(const SgmlParser *parser)
604 {
605   parser_ = parser;
606   definedNotations_.clear();
607   definedEntities_.clear();
608   haveLinkProcess_ = 0;
609   linkProcess_.clear();
610 }
611
612 void SgmlsSubdocState::swap(SgmlsSubdocState &to)
613 {
614   {
615     const SgmlParser *tem = to.parser_;
616     to.parser_ = parser_;
617     parser_ = tem;
618   }
619   {
620     Boolean tem = to.haveLinkProcess_;
621     to.haveLinkProcess_ = haveLinkProcess_;
622     haveLinkProcess_ = tem;
623   }
624   linkProcess_.swap(to.linkProcess_);
625   definedNotations_.swap(to.definedNotations_);
626   definedEntities_.swap(to.definedEntities_);
627 }
628
629 #ifdef SP_NAMESPACE
630 }
631 #endif