Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / nsgmls / nsgmls.C
1 /* $XConsortium: nsgmls.C /main/1 1996/07/29 17:08:59 cde-hp $ */
2 // Copyright (c) 1994, 1995 James Clark
3 // See the file COPYING for copying permission.
4
5 #include "config.h"
6 #include "Event.h"
7 #include "MessageEventHandler.h"
8 #include "SgmlsEventHandler.h"
9 #include "RastEventHandler.h"
10 #include "OutputCharStream.h"
11 #include "Boolean.h"
12 #include "NsgmlsMessages.h"
13 #include "MessageArg.h"
14 #include "ErrnoMessageArg.h"
15 #include "ParserApp.h"
16 #include "sptchar.h"
17 #include "macros.h"
18
19 #include <iostream.h>
20 #include <fstream.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <limits.h>
25
26 #ifdef SP_NAMESPACE
27 using namespace SP_NAMESPACE;
28 #endif
29
30 class NsgmlsApp : public ParserApp {
31 public:
32   NsgmlsApp();
33   int processArguments(int argc, AppChar **argv);
34   ErrorCountEventHandler *makeEventHandler();
35   void processOption(AppChar opt, const AppChar *arg);
36   void allLinkTypesActivated();
37 private:
38   Boolean suppressOutput_;
39   Boolean prologOnly_;
40   unsigned outputFlags_;
41   String<AppChar> rastFile_;
42   const AppChar *rastOption_;
43   Boolean batchMode_;
44 };
45
46 SP_DEFINE_APP(NsgmlsApp)
47
48 class PrologMessageEventHandler : public MessageEventHandler {
49 public:
50   PrologMessageEventHandler(Messenger *messenger);
51   void endProlog(EndPrologEvent *);
52 };
53
54 class XRastEventHandler : public RastEventHandler {
55 public:
56   XRastEventHandler(SgmlParser *,
57                     const AppChar *filename,
58                     const StringC &filenameStr,
59                     const OutputCodingSystem *,
60                     Messenger *messenger);
61   ~XRastEventHandler();
62   void message(MessageEvent *);
63   void truncateOutput();
64   void allLinkTypesActivated();
65 private:
66   Messenger *messenger_;
67   // file_ must come before os_ so it gets inited first
68   filebuf file_;
69   IosOutputCharStream os_;
70   const AppChar *filename_;
71   const StringC filenameStr_;
72 };
73
74 NsgmlsApp::NsgmlsApp()
75 : suppressOutput_(0),
76   batchMode_(0),
77   prologOnly_(0),
78   outputFlags_(0),
79   rastOption_(0)
80 {
81   registerOption('B');
82   registerOption('d');
83   registerOption('l');
84   registerOption('m', SP_T("catalog_sysid"));
85   registerOption('o', SP_T("output_option"));
86   registerOption('p');
87   registerOption('r');
88   registerOption('s');
89   registerOption('t', SP_T("rast_file"));
90   registerOption('u');
91 }
92
93 void NsgmlsApp::processOption(AppChar opt, const AppChar *arg)
94 {
95   switch (opt) {
96   case 'B':
97     batchMode_ = 1;
98     break;
99   case 'd':
100     // warn about duplicate entity declarations
101     options_.warnDuplicateEntity = 1;
102     break;
103   case 'l':
104     // output L commands
105     outputFlags_ |= SgmlsEventHandler::outputLine;
106     break;
107   case 'm':
108     processOption(SP_T('c'), arg);
109     break;
110   case 'o':
111     {
112       static struct {
113         const AppChar *name;
114         unsigned flag;
115       } outputOptions[] = {
116         { SP_T("line"), SgmlsEventHandler::outputLine },
117         { SP_T("entity"), SgmlsEventHandler::outputEntity },
118         { SP_T("id"), SgmlsEventHandler::outputId },
119         { SP_T("included"), SgmlsEventHandler::outputIncluded },
120         { SP_T("notation-sysid"), SgmlsEventHandler::outputNotationSysid },
121       };
122       Boolean found = 0;
123       for (size_t i = 0; i < SIZEOF(outputOptions); i++)
124         if (tcscmp(arg, outputOptions[i].name) == 0) {
125           outputFlags_ |= outputOptions[i].flag;
126           found = 1;
127           break;
128         }
129       if (!found)
130         message(NsgmlsMessages::unknownOutputOption,
131                 StringMessageArg(convertInput(arg)));
132     }
133     break;
134   case 'p':
135     prologOnly_ = 1;
136     break;
137   case 'r':
138     // warn about defaulted entity reference
139     options_.warnDefaultEntityReference = 1;
140     break;
141   case 's':
142     suppressOutput_ = 1;
143     break;
144   case 't':
145     rastOption_ = arg;
146     break;
147   case 'u':
148     // warn about undefined elements
149     options_.warnUndefinedElement = 1;
150     break;
151   default:
152     ParserApp::processOption(opt, arg);
153     break;
154   }
155 }
156
157 int NsgmlsApp::processArguments(int argc, AppChar **argv)
158 {
159   if (batchMode_) {
160     int ret = 0;
161     for (int i = 0; i < argc; i++) {
162       if (rastOption_) {
163         rastFile_.assign(rastOption_, tcslen(rastOption_));
164         rastFile_.append(argv[i], tcslen(argv[i]));
165         rastFile_ += SP_T('\0');
166       }
167       int tem = ParserApp::processArguments(1, argv + i);
168       if (tem > ret)
169         ret = tem;
170     }
171     return ret;
172   }
173   else
174     return ParserApp::processArguments(argc, argv);
175 }
176
177 void NsgmlsApp::allLinkTypesActivated()
178 {
179   if (!rastOption_)
180     ParserApp::allLinkTypesActivated();
181 }
182
183 ErrorCountEventHandler *NsgmlsApp::makeEventHandler()
184 {
185   if (prologOnly_)
186     return new PrologMessageEventHandler(this);
187   else if (rastOption_) {
188     const AppChar *s = batchMode_ ? rastFile_.data() : rastOption_;
189     return new XRastEventHandler(&parser_, s, convertInput(s),
190                                  outputCodingSystem_, this);
191   }
192   else if (suppressOutput_)
193     return new MessageEventHandler(this, &parser_);
194   else
195     return new SgmlsEventHandler(&parser_,
196                                  makeStdOut(),
197                                  this,
198                                  outputFlags_);
199 }
200
201 PrologMessageEventHandler::PrologMessageEventHandler(Messenger *messenger)
202 : MessageEventHandler(messenger)
203 {
204 }
205
206 void PrologMessageEventHandler::endProlog(EndPrologEvent *event)
207 {
208   cancel();
209   delete event;
210 }
211
212 XRastEventHandler::XRastEventHandler(SgmlParser *parser,
213                                      const AppChar *filename,
214                                      const StringC &filenameStr,
215                                      const OutputCodingSystem *codingSystem,
216                                      Messenger *messenger)
217 : RastEventHandler(parser, messenger),
218   messenger_(messenger),
219   filename_(filename),
220   filenameStr_(filenameStr)
221 {
222   errno = 0;
223   if (!CmdLineApp::openFilebufWrite(file_, filename)) {
224     messenger->message(NsgmlsMessages::cannotOpenOutputError,
225                       StringMessageArg(filenameStr),
226                       ErrnoMessageArg(errno));
227     exit(1);
228   }
229   os_.open(&file_, codingSystem);
230   setOutputStream(&os_);
231 }
232
233 XRastEventHandler::~XRastEventHandler()
234 {
235   end();
236 }
237
238 void XRastEventHandler::truncateOutput()
239 {
240   os_.flush();
241   errno = 0;
242   if (!file_.close())
243     messenger_->message(NsgmlsMessages::closeOutputError,
244                         StringMessageArg(filenameStr_),
245                         ErrnoMessageArg(errno));
246   errno = 0;
247   if (!CmdLineApp::openFilebufWrite(file_, filename_)) {
248     messenger_->message(NsgmlsMessages::cannotOpenOutputError,
249                         StringMessageArg(filenameStr_),
250                         ErrnoMessageArg(errno));
251     exit(1);
252   }
253 }
254
255 void XRastEventHandler::message(MessageEvent *event)
256 {
257   messenger_->dispatchMessage(event->message());
258   ErrorCountEventHandler::message(event);
259 }