49c68155f08735f5d0c100d64a950a32cba85eb8
[oweals/cde.git] / cde / programs / nsgmls / parseSd.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: parseSd.C /main/2 1996/08/12 15:47:30 mgreess $ */
24 // Copyright (c) 1994, 1995 James Clark
25 // See the file COPYING for copying permission.
26
27 #include "splib.h"
28 #include "Parser.h"
29 #include "macros.h"
30 #include "SdFormalError.h"
31 #include "MessageBuilder.h"
32 #include "ParserMessages.h"
33 #include "MessageArg.h"
34 #include "CharsetRegistry.h"
35 #include "ISetIter.h"
36 #include "token.h"
37 #include "TokenMessageArg.h"
38 #include "constant.h"
39 #include "SdText.h"
40 #include "NumericCharRefOrigin.h"
41
42 #ifdef SP_NAMESPACE
43 namespace SP_NAMESPACE {
44 #endif
45
46 class CharSwitcher {
47 public:
48   CharSwitcher();
49   void addSwitch(WideChar from, WideChar to);
50   SyntaxChar subst(WideChar c);
51   size_t nSwitches() const;
52   Boolean switchUsed(size_t i) const;
53   WideChar switchFrom(size_t i) const;
54   WideChar switchTo(size_t i) const;
55 private:
56   Vector<PackedBoolean> switchUsed_;
57   Vector<WideChar> switches_;
58 };
59
60 // Information about the SGML declaration being built.
61
62 struct SdBuilder {
63   SdBuilder();
64   void addFormalError(const Location &, const MessageType1 &, const StringC &);
65   Ptr<Sd> sd;
66   Ptr<Syntax> syntax;
67   CharsetDecl syntaxCharsetDecl;
68   CharsetInfo syntaxCharset;
69   CharSwitcher switcher;
70   Boolean externalSyntax;
71   Boolean valid;
72   IList<SdFormalError> formalErrorList;
73 };
74
75 class CharsetMessageArg : public MessageArg {
76 public:
77   CharsetMessageArg(const ISet<WideChar> &set);
78   MessageArg *copy() const;
79   void append(MessageBuilder &) const;
80 private:
81   ISet<WideChar> set_;
82 };
83
84 struct SdParam {
85   typedef unsigned char Type;
86   enum {
87     invalid,
88     eE,
89     minimumLiteral,
90     mdc,
91     ellipsis,
92     number,
93     capacityName,
94     name,
95     paramLiteral,
96     generalDelimiterName,
97     referenceReservedName,
98     quantityName,
99     reservedName                // Sd::ReservedName is added to this
100   };
101   Type type;
102   StringC token;
103   Text literalText;
104   String<SyntaxChar> paramLiteralText;
105   union {
106     Number n;
107     Sd::Capacity capacityIndex;
108     Syntax::Quantity quantityIndex;
109     Syntax::ReservedName reservedNameIndex;
110     Syntax::DelimGeneral delimGeneralIndex;
111   };
112 };
113
114 class AllowedSdParams {
115 public:
116   AllowedSdParams(SdParam::Type,
117                   SdParam::Type = SdParam::invalid,
118                   SdParam::Type = SdParam::invalid,
119                   SdParam::Type = SdParam::invalid,
120                   SdParam::Type = SdParam::invalid,
121                   SdParam::Type = SdParam::invalid);
122   Boolean param(SdParam::Type) const;
123   SdParam::Type get(int i) const;
124 private:
125   enum { maxAllow = 6 };
126   SdParam::Type allow_[maxAllow];
127 };
128
129 class AllowedSdParamsMessageArg : public MessageArg {
130 public:
131   AllowedSdParamsMessageArg(const AllowedSdParams &allow,
132                             const ConstPtr<Sd> &sd);
133   MessageArg *copy() const;
134   void append(MessageBuilder &) const;
135 private:
136   AllowedSdParams allow_;
137   ConstPtr<Sd> sd_;
138 };
139
140 struct StandardSyntaxSpec {
141   struct AddedFunction {
142     const char *name;
143     Syntax::FunctionClass functionClass;
144     SyntaxChar syntaxChar;
145   };
146   const AddedFunction *addedFunction;
147   size_t nAddedFunction;
148   Boolean shortref;
149 };
150
151 static StandardSyntaxSpec::AddedFunction coreFunctions[] = {
152   { "TAB", Syntax::cSEPCHAR, 9 },
153 };
154
155 static StandardSyntaxSpec coreSyntax = {
156   coreFunctions, SIZEOF(coreFunctions), 0
157 };
158
159 static StandardSyntaxSpec refSyntax = {
160   coreFunctions, SIZEOF(coreFunctions), 1
161 };
162
163 void Parser::doInit()
164 {
165   if (cancelled()) {
166     allDone();
167     return;
168   }
169   // When document entity doesn't exist, don't give any errors
170   // other than the cannot open error.
171   if (currentInput()->get(messenger()) == InputSource::eE) {
172     if (currentInput()->accessError()) {
173       allDone();
174       return;
175     }
176   }
177   else
178     currentInput()->ungetToken();
179   const CharsetInfo &initCharset = sd().docCharset();
180   ISet<WideChar> missing;
181   findMissingMinimum(initCharset, missing);
182   if (!missing.isEmpty()) {
183     message(ParserMessages::sdMissingCharacters, CharsetMessageArg(missing));
184     giveUp();
185     return;
186   }
187   Boolean found = 0;
188   StringC systemId;
189   if (scanForSgmlDecl(initCharset))
190     found = 1;
191   else {
192     currentInput()->ungetToken();
193     if (entityCatalog().sgmlDecl(initCharset, messenger(), systemId)) {
194       InputSource *in = entityManager().open(systemId,
195                                              initCharset,
196                                              new InputSourceOrigin,
197                                              0,
198                                              messenger());
199       if (in) {
200         pushInput(in);
201         if (scanForSgmlDecl(initCharset))
202           found = 1;
203         else {
204           message(ParserMessages::badDefaultSgmlDecl);
205           popInputStack();
206         }
207       }
208     }
209   }
210   if (found) {
211     if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation())) {
212       size_t nS = currentInput()->currentTokenLength() - 6;
213       for (size_t i = 0; i < nS; i++)
214         currentMarkup()->addS(currentInput()->currentTokenStart()[i]);
215       currentMarkup()->addDelim(Syntax::dMDO);
216       currentMarkup()->addSdReservedName(Sd::rSGML,
217                                         currentInput()->currentTokenStart()
218                                         + (currentInput()->currentTokenLength() - 4),
219                                         4);
220     }
221     Syntax *syntaxp = new Syntax(sd());
222     CharSwitcher switcher;
223     if (!setStandardSyntax(*syntaxp, refSyntax, sd().docCharset(),
224                            switcher)) {
225       giveUp();
226       return;
227     }
228     syntaxp->implySgmlChar(sd().docCharset());
229     setSyntax(syntaxp);
230     compileSdModes();
231     ConstPtr<Sd> refSd(sdPointer());
232     ConstPtr<Syntax> refSyntax(syntaxPointer());
233     if (!parseSgmlDecl()) {
234       giveUp();
235       return;
236     }
237     // queue an SGML declaration event
238     eventHandler().sgmlDecl(new (eventAllocator())
239                             SgmlDeclEvent(sdPointer(),
240                                           syntaxPointer(),
241                                           instanceSyntaxPointer(),
242                                           refSd,
243                                           refSyntax,
244                                           currentInput()->nextIndex(),
245                                           systemId,
246                                           markupLocation(),
247                                           currentMarkup()));
248     if (inputLevel() == 2) {
249       // FIXME perhaps check for junk after SGML declaration
250       popInputStack();
251     }
252   }
253   else {
254     if (!implySgmlDecl()) {
255       giveUp();
256       return;
257     }
258     // queue an SGML declaration event
259     eventHandler().sgmlDecl(new (eventAllocator())
260                             SgmlDeclEvent(sdPointer(),
261                                           syntaxPointer()));
262   }
263                                                       
264   // Now we have sd and syntax set up, prepare to parse the prolog.
265   compilePrologModes();
266   setPhase(prologPhase);
267 }
268
269 Boolean Parser::implySgmlDecl()
270 {
271   Syntax *syntaxp = new Syntax(sd());
272   const StandardSyntaxSpec *spec;
273   if (options().shortref)
274     spec = &refSyntax;
275   else
276     spec = &coreSyntax;
277   CharSwitcher switcher;
278   if (!setStandardSyntax(*syntaxp, *spec, sd().docCharset(), switcher))
279     return 0;
280   syntaxp->implySgmlChar(sd().docCharset());
281   for (int i = 0; i < Syntax::nQuantity; i++)
282     syntaxp->setQuantity(i, options().quantity[i]);
283   setSyntax(syntaxp);
284   return 1;
285 }
286
287 Boolean Parser::setStandardSyntax(Syntax &syn,
288                                   const StandardSyntaxSpec &spec,
289                                   const CharsetInfo &docCharset,
290                                   CharSwitcher &switcher)
291 {
292   static UnivCharsetDesc::Range syntaxCharsetRanges[] = {
293     { 0, 128, 0 },
294   };
295   static UnivCharsetDesc syntaxCharsetDesc(syntaxCharsetRanges,
296                                            SIZEOF(syntaxCharsetRanges));
297   static CharsetInfo syntaxCharset(syntaxCharsetDesc);
298
299   Boolean valid = 1;
300   if (!checkSwitches(switcher, syntaxCharset))
301     valid = 0;
302   size_t i;
303   for (i = 0; i < switcher.nSwitches(); i++)
304     if (switcher.switchTo(i) >= 128)
305       message(ParserMessages::switchNotInCharset,
306               NumberMessageArg(switcher.switchTo(i)));
307   static const Char shunchar[] = {
308     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
309     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
310     127, 255
311     };
312   
313   for (i = 0; i < SIZEOF(shunchar); i++)
314     syn.addShunchar(shunchar[i]);
315   syn.setShuncharControls();
316   static Syntax::StandardFunction standardFunctions[3] = {
317     Syntax::fRE, Syntax::fRS, Syntax::fSPACE
318   };
319   static SyntaxChar functionChars[3] = { 13, 10, 32 };
320   for (i = 0; i < 3; i++) {
321     Char docChar;
322     if (translateSyntax(switcher,
323                         syntaxCharset,
324                         docCharset,
325                         functionChars[i],
326                         docChar)
327         && checkNotFunction(syn, docChar))
328       syn.setStandardFunction(standardFunctions[i], docChar);
329     else
330       valid = 0;
331   }
332   for (i = 0; i < spec.nAddedFunction; i++) {
333     Char docChar;
334     if (translateSyntax(switcher,
335                         syntaxCharset,
336                         docCharset,
337                         spec.addedFunction[i].syntaxChar,
338                         docChar)
339         && checkNotFunction(syn, docChar))
340       syn.addFunctionChar(docCharset.execToDesc(spec.addedFunction[i].name),
341                           spec.addedFunction[i].functionClass,
342                           docChar);
343     else
344       valid = 0;
345   }
346   
347   static SyntaxChar nameChars[2] = { 45, 46 }; // '-' '.'
348   ISet<Char> nameCharSet;
349   for (i = 0; i < 2; i++) {
350     Char docChar;
351     if (translateSyntax(switcher,
352                         syntaxCharset,
353                         docCharset,
354                         nameChars[i],
355                         docChar))
356         nameCharSet.add(docChar);
357     else
358       valid = 0;
359   }
360   if (!checkNmchars(nameCharSet, syn))
361     valid = 0;
362   else
363     syn.addNameCharacters(nameCharSet);
364   syn.setNamecaseGeneral(1);
365   syn.setNamecaseEntity(0);
366   if (!setRefDelimGeneral(syn, syntaxCharset, docCharset, switcher))
367     valid = 0;
368   setRefNames(syn, docCharset);
369   syn.enterStandardFunctionNames();
370   if (spec.shortref
371       && !addRefDelimShortref(syn, syntaxCharset, docCharset, switcher))
372     valid = 0;
373   return valid;
374 }
375
376 Boolean Parser::setRefDelimGeneral(Syntax &syntax,
377                                    const CharsetInfo &syntaxCharset,
378                                    const CharsetInfo &docCharset,
379                                    CharSwitcher &switcher)
380 {
381   // Column 3 from Figure 3
382   static const char delims[][2] = {
383     { 38 },
384     { 45, 45 },
385     { 38, 35 },
386     { 93 },
387     { 91 },
388     { 93 },
389     { 91 },
390     { 38 },
391     { 60, 47 },
392     { 41 },
393     { 40 },
394     { 34 },
395     { 39 },
396     { 62 },
397     { 60, 33 },
398     { 45 },
399     { 93, 93 },
400     { 47 },
401     { 63 },
402     { 124 },
403     { 37 },
404     { 62 },
405     { 60, 63 },
406     { 43 },
407     { 59 },
408     { 42 },
409     { 35 },
410     { 44 },
411     { 60 },
412     { 62 },
413     { 61 },
414   };
415   Boolean valid = 1;
416   ISet<WideChar> missing;
417   for (int i = 0; i < Syntax::nDelimGeneral; i++)
418     if (syntax.delimGeneral(i).size() == 0) {
419       StringC delim;
420       size_t j;
421       for (j = 0; j < 2 && delims[i][j] != '\0'; j++) {
422         UnivChar univChar = translateUniv(delims[i][j], switcher,
423                                           syntaxCharset);
424         Char c;
425         if (univToDescCheck(docCharset, univChar, c))
426           delim += c;
427         else {
428           missing += univChar;
429           valid = 0;
430         }
431       }
432       if (delim.size() == j) {
433         if (checkGeneralDelim(syntax, delim))
434           syntax.setDelimGeneral(i, delim);
435         else
436           valid = 0;
437       }
438     }
439   if (!missing.isEmpty())
440     message(ParserMessages::missingSignificant646, CharsetMessageArg(missing));
441   return valid;
442 }
443
444 void Parser::setRefNames(Syntax &syntax, const CharsetInfo &docCharset)
445 {
446   static const char *const referenceNames[] = {
447     "ANY",
448     "ATTLIST",
449     "CDATA",
450     "CONREF",
451     "CURRENT",
452     "DEFAULT",
453     "DOCTYPE",
454     "ELEMENT",
455     "EMPTY",
456     "ENDTAG",
457     "ENTITIES",
458     "ENTITY",
459     "FIXED",
460     "ID",
461     "IDLINK",
462     "IDREF",
463     "IDREFS",
464     "IGNORE",
465     "IMPLIED",
466     "INCLUDE",
467     "INITIAL",
468     "LINK",
469     "LINKTYPE",
470     "MD",
471     "MS",
472     "NAME",
473     "NAMES",
474     "NDATA",
475     "NMTOKEN",
476     "NMTOKENS",
477     "NOTATION",
478     "NUMBER",
479     "NUMBERS",
480     "NUTOKEN",
481     "NUTOKENS",
482     "O",
483     "PCDATA",
484     "PI",
485     "POSTLINK",
486     "PUBLIC",
487     "RCDATA",
488     "RE",
489     "REQUIRED",
490     "RESTORE",
491     "RS",
492     "SDATA",
493     "SHORTREF",
494     "SIMPLE",
495     "SPACE",
496     "STARTTAG",
497     "SUBDOC",
498     "SYSTEM",
499     "TEMP",
500     "USELINK",
501     "USEMAP"
502     };
503
504   int i;
505   for (i = 0; i < Syntax::nNames; i++) {
506     StringC docName(docCharset.execToDesc(referenceNames[i]));
507     Syntax::ReservedName tem;
508     if (syntax.lookupReservedName(docName, &tem))
509       message(ParserMessages::nameReferenceReservedName,
510               StringMessageArg(docName));
511     if (syntax.reservedName(Syntax::ReservedName(i)).size() == 0)
512       syntax.setName(i, docName);
513   }
514 }
515
516 Boolean Parser::addRefDelimShortref(Syntax &syntax,
517                                     const CharsetInfo &syntaxCharset,
518                                     const CharsetInfo &docCharset,
519                                     CharSwitcher &switcher)
520 {
521   // Column 2 from Figure 4
522   static const char delimShortref[][3] = {
523     { 9 },
524     { 13 },
525     { 10 },
526     { 10, 66 },
527     { 10, 13 },
528     { 10, 66, 13 },
529     { 66, 13 },
530     { 32 },
531     { 66, 66 },
532     { 34 },
533     { 35 },
534     { 37 },
535     { 39 },
536     { 40 },
537     { 41 },
538     { 42 },
539     { 43 },
540     { 44 },
541     { 45 },
542     { 45, 45 },
543     { 58 },
544     { 59 },
545     { 61 },
546     { 64 },
547     { 91 },
548     { 93 },
549     { 94 },
550     { 95 },
551     { 123 },
552     { 124 },
553     { 125 },
554     { 126 },
555   };
556   ISet<WideChar> missing;
557
558   for (size_t i = 0; i < SIZEOF(delimShortref); i++) {
559     StringC delim;
560     
561     size_t j;
562     for (j = 0; j < 3 && delimShortref[i][j] != '\0'; j++) {
563       Char c;
564       UnivChar univChar = translateUniv(delimShortref[i][j], switcher,
565                                         syntaxCharset);
566       if (univToDescCheck(docCharset, univChar, c))
567         delim += c;
568       else
569         missing += univChar;
570     }
571     if (delim.size() == j) {
572       if (switcher.nSwitches() > 0 && syntax.isValidShortref(delim))
573         message(ParserMessages::duplicateDelimShortref,
574                 StringMessageArg(delim));
575       else
576         syntax.addDelimShortref(delim, docCharset);
577     }
578   }
579   if (!missing.isEmpty())
580     message(ParserMessages::missingSignificant646, CharsetMessageArg(missing));
581   return 1;
582 }
583
584 // Determine whether the document starts with an SGML declaration.
585 // There is no current syntax at this point.
586
587 Boolean Parser::scanForSgmlDecl(const CharsetInfo &initCharset)
588 {
589   Char rs;
590   if (!univToDescCheck(initCharset, UnivCharsetDesc::rs, rs))
591     return 0;
592   Char re;
593   if (!univToDescCheck(initCharset, UnivCharsetDesc::re, re))
594     return 0;
595   Char space;
596   if (!univToDescCheck(initCharset, UnivCharsetDesc::space, space))
597     return 0;
598   Char tab;
599   if (!univToDescCheck(initCharset, UnivCharsetDesc::tab, tab))
600     return 0;
601   InputSource *in = currentInput();
602   Xchar c = in->get(messenger());
603   while (c == rs || c == space || c == re || c == tab)
604     c = in->tokenChar(messenger());
605   if (c != initCharset.execToDesc('<'))
606     return 0;
607   if (in->tokenChar(messenger()) != initCharset.execToDesc('!'))
608     return 0;
609   c = in->tokenChar(messenger());
610   if (c != initCharset.execToDesc('S')
611       && c != initCharset.execToDesc('s'))
612     return 0;
613   c = in->tokenChar(messenger());
614   if (c != initCharset.execToDesc('G')
615       && c != initCharset.execToDesc('g'))
616     return 0;
617   c = in->tokenChar(messenger());
618   if (c != initCharset.execToDesc('M')
619       && c != initCharset.execToDesc('m'))
620     return 0;
621   c = in->tokenChar(messenger());
622   if (c != initCharset.execToDesc('L')
623       && c != initCharset.execToDesc('l'))
624     return 0;
625   c = in->tokenChar(messenger());
626   // Don't recognize this if SGML is followed by a name character.
627   if (c == InputSource::eE)
628     return 1;
629   in->endToken(in->currentTokenLength() - 1);
630   if (c == initCharset.execToDesc('-'))
631     return 0;
632   if (c == initCharset.execToDesc('.'))
633     return 0;
634   UnivChar univ;
635   if (!initCharset.descToUniv(c, univ)) 
636     return 1;
637   if (UnivCharsetDesc::a <= univ && univ < UnivCharsetDesc::a + 26)
638     return 0;
639   if (UnivCharsetDesc::A <= univ && univ < UnivCharsetDesc::A + 26)
640     return 0;
641   if (UnivCharsetDesc::zero <= univ && univ < UnivCharsetDesc::zero + 10)
642     return 0;
643   return 1;
644 }
645             
646 void Parser::findMissingMinimum(const CharsetInfo &charset,
647                                 ISet<WideChar> &missing)
648 {
649   Char to;
650   size_t i;
651   for (i = 0; i < 26; i++) {
652     if (!univToDescCheck(charset, UnivCharsetDesc::A + i, to))
653       missing += UnivCharsetDesc::A + i;
654     if (!univToDescCheck(charset, UnivCharsetDesc::a + i, to))
655       missing += UnivCharsetDesc::a + i;
656   }
657   for (i = 0; i < 10; i++) {
658     Char to;
659     if (!univToDescCheck(charset, UnivCharsetDesc::zero + i, to))
660       missing += UnivCharsetDesc::zero + i;
661   }
662   static const UnivChar special[] = {
663     39, 40, 41, 43, 44, 45, 46, 47, 58, 61, 63
664     };
665
666   for (i = 0; i < SIZEOF(special); i++)
667     if (!univToDescCheck(charset, special[i], to))
668       missing += special[i];
669 }
670
671
672 Boolean Parser::parseSgmlDecl()
673 {
674   SdParam parm;
675   SdBuilder sdBuilder;
676
677   if (!parseSdParam(AllowedSdParams(SdParam::minimumLiteral), parm))
678     return 0;
679   StringC version(sd().execToDoc("ISO 8879:1986"));
680   if (parm.literalText.string() != version)
681     message(ParserMessages::standardVersion,
682             StringMessageArg(parm.literalText.string()));
683   sdBuilder.sd = new Sd;
684   typedef Boolean (Parser::*SdParser)(SdBuilder &, SdParam &);
685   static SdParser parsers[] = {
686     &Parser::sdParseDocumentCharset,
687     &Parser::sdParseCapacity,
688     &Parser::sdParseScope,
689     &Parser::sdParseSyntax,
690     &Parser::sdParseFeatures,
691     &Parser::sdParseAppinfo,
692   };
693   for (size_t i = 0; i < SIZEOF(parsers); i++) {
694     if (!(this->*(parsers[i]))(sdBuilder, parm))
695       return 0;
696     if (!sdBuilder.valid)
697       return 0;
698   }
699   if (!parseSdParam(AllowedSdParams(SdParam::mdc), parm))
700     return 0;
701   if (sdBuilder.sd->formal()) {
702     while (!sdBuilder.formalErrorList.empty()) {
703       SdFormalError *p = sdBuilder.formalErrorList.get();
704       ParserState *state = this; // work around lcc 3.0 bug
705       p->send(*state);
706       delete p;
707     }
708   }
709   setSd(sdBuilder.sd.pointer());
710   if (sdBuilder.sd->scopeInstance()) {
711     Syntax *proSyntax = new Syntax(sd());
712     CharSwitcher switcher;
713     setStandardSyntax(*proSyntax, refSyntax, sd().docCharset(), switcher);
714     proSyntax->setSgmlChar(*sdBuilder.syntax->charSet(Syntax::sgmlChar));
715     ISet<WideChar> invalidSgmlChar;
716     proSyntax->checkSgmlChar(sdBuilder.sd->docCharset(),
717                              sdBuilder.syntax.pointer(),
718                              invalidSgmlChar);
719     sdBuilder.syntax->checkSgmlChar(sdBuilder.sd->docCharset(),
720                                     proSyntax,
721                                     invalidSgmlChar);
722     if (!invalidSgmlChar.isEmpty())
723       message(ParserMessages::invalidSgmlChar, CharsetMessageArg(invalidSgmlChar));
724     setSyntaxes(proSyntax, sdBuilder.syntax.pointer());
725   }
726   else
727     setSyntax(sdBuilder.syntax.pointer());
728   if (syntax().multicode())
729     currentInput()->setMarkupScanTable(syntax().markupScanTable());
730   return 1;
731 }
732
733 Boolean Parser::sdParseDocumentCharset(SdBuilder &sdBuilder, SdParam &parm)
734 {
735   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rCHARSET),
736                     parm))
737     return 0;
738   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rBASESET),
739                     parm))
740     return 0;
741   CharsetDecl decl;
742   UnivCharsetDesc desc;
743   if (!sdParseCharset(sdBuilder, parm, 1, decl, desc))
744     return 0;
745   ISet<WideChar> missing;
746   findMissingMinimum(desc, missing);
747   if (!missing.isEmpty()) {
748     message(ParserMessages::missingMinimumChars,
749             CharsetMessageArg(missing));
750     return 0;
751   }
752   ISet<Char> sgmlChar;
753   decl.usedSet(sgmlChar);
754   sdBuilder.sd->setDocCharsetDesc(desc);
755   sdBuilder.sd->setDocCharsetDecl(decl);
756   sdBuilder.syntax = new Syntax(*sdBuilder.sd);
757   sdBuilder.syntax->setSgmlChar(sgmlChar);
758   return 1;
759 }
760
761 Boolean Parser::sdParseCharset(SdBuilder &sdBuilder,
762                                SdParam &parm,
763                                Boolean isDocument,
764                                CharsetDecl &decl,
765                                UnivCharsetDesc &desc)
766 {
767   decl.clear();
768   ISet<WideChar> multiplyDeclared;
769   // This is for checking whether the syntax reference character set
770   // is ISO 646 when SCOPE is INSTANCE.
771   Boolean maybeISO646 = 1;
772   do {
773     if (!parseSdParam(AllowedSdParams(SdParam::minimumLiteral), parm))
774       return 0;
775     UnivCharsetDesc baseDesc;
776     PublicId id;
777     Boolean found;
778     PublicId::TextClass textClass;
779     const MessageType1 *err;
780     if (!id.init(parm.literalText, sd().docCharset(), syntax().space(), err))
781       sdBuilder.addFormalError(currentLocation(),
782                                *err,
783                                id.string());
784     else if (id.getTextClass(textClass)
785              && textClass != PublicId::CHARSET)
786       sdBuilder.addFormalError(currentLocation(),
787                                ParserMessages::basesetTextClass,
788                                id.string());
789     Boolean givenError;
790     if (referencePublic(id, PublicId::CHARSET, givenError))
791       found = sdParseExternalCharset(*sdBuilder.sd, baseDesc);
792     else if (!givenError) {
793       found = CharsetRegistry::findCharset(id, sd().docCharset(), baseDesc);
794       if (!found && options().warnSgmlDecl)
795         message(ParserMessages::unknownBaseset, StringMessageArg(id.string()));
796     }
797     else
798       found = 0;
799     if (!found)
800       maybeISO646 = 0;
801     decl.addSection(id);
802     if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rDESCSET),
803                       parm))
804       return 0;
805     if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
806       return 0;
807     do {
808       WideChar min = parm.n;
809       if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
810         return 0;
811       Number count = parm.n;
812       Number adjCount;
813       if (options().warnSgmlDecl && count == 0)
814         message(ParserMessages::zeroNumberOfCharacters);
815       decl.rangeDeclared(min, count, multiplyDeclared);
816       if (isDocument
817           && count > 0
818           && (min > charMax || count - 1 > charMax - min)) {
819         message(ParserMessages::documentCharMax, NumberMessageArg(charMax));
820         adjCount = min > charMax ? 0 : 1 + (charMax - min);
821         sdBuilder.valid = 0;
822         maybeISO646 = 0;
823       }
824       else
825         adjCount = count;
826       if (!parseSdParam(AllowedSdParams(SdParam::number,
827                                         SdParam::minimumLiteral,
828                                         SdParam::reservedName + Sd::rUNUSED),
829                         parm))
830         return 0;
831       switch (parm.type) {
832       case SdParam::number:
833         decl.addRange(min, count, parm.n);
834         if (found && adjCount > 0) {
835           ISet<WideChar> baseMissing;
836           desc.addBaseRange(baseDesc, min, min + (adjCount - 1), parm.n,
837                             baseMissing);
838           if (!baseMissing.isEmpty() && options().warnSgmlDecl)
839             message(ParserMessages::basesetCharsMissing,
840                     CharsetMessageArg(baseMissing));
841         }
842         break;
843       case SdParam::reservedName + Sd::rUNUSED:
844         decl.addRange(min, count);
845         break;
846       case SdParam::minimumLiteral:
847         {
848           UnivChar c = sdBuilder.sd->nameToUniv(parm.literalText.string());
849           if (adjCount > 256) {
850             message(ParserMessages::tooManyCharsMinimumLiteral);
851             adjCount = 256;
852           }
853           for (Number i = 0; i < adjCount; i++)
854             desc.addRange(min + i, min + i, c);
855         }
856         maybeISO646 = 0;
857         decl.addRange(min, count, parm.literalText.string());
858         break;
859       default:
860         CANNOT_HAPPEN();                         
861       }
862       SdParam::Type follow = (isDocument
863                               ? SdParam::reservedName + Sd::rCAPACITY
864                               : SdParam::reservedName + Sd::rFUNCTION);
865       if (!parseSdParam(AllowedSdParams(SdParam::number,
866                                         SdParam::reservedName + Sd::rBASESET,
867                                         follow),
868                         parm))
869         return 0;
870         
871     } while (parm.type == SdParam::number);
872   } while (parm.type == SdParam::reservedName + Sd::rBASESET);
873   if (!multiplyDeclared.isEmpty())
874     message(ParserMessages::duplicateCharNumbers,
875             CharsetMessageArg(multiplyDeclared));
876   ISet<WideChar> declaredSet;
877   decl.declaredSet(declaredSet);
878   ISetIter<WideChar> iter(declaredSet);
879   WideChar min, max, lastMax;
880   if (iter.next(min, max)) {
881     ISet<WideChar> holes;
882     lastMax = max;
883     while (iter.next(min, max)) {
884       if (min - lastMax > 1)
885         holes.addRange(lastMax + 1, min - 1);
886       lastMax = max;
887     }
888     if (!holes.isEmpty())
889       message(ParserMessages::codeSetHoles, CharsetMessageArg(holes));
890   }
891   if (!isDocument && sdBuilder.sd->scopeInstance()) {
892     // If scope is INSTANCE, syntax reference character set
893     // must be same as reference.
894     UnivCharsetDescIter iter(desc);
895     WideChar descMin, descMax;
896     UnivChar univMin;
897     if (!iter.next(descMin, descMax, univMin)
898         || descMin != 0
899         || descMax != 127
900         || univMin != 0
901         || !maybeISO646)
902       message(ParserMessages::scopeInstanceSyntaxCharset);
903   }
904   return 1;
905 }
906
907 Boolean Parser::sdParseExternalCharset(Sd &sd, UnivCharsetDesc &desc)
908 {
909   SdParam parm;
910   for (;;) {
911     if (!parseSdParam(AllowedSdParams(SdParam::number, SdParam::eE),
912                      parm))
913       break;
914     if (parm.type == SdParam::eE)
915       return 1;
916     WideChar min = parm.n;
917     if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
918       break;
919     Number count = parm.n;
920     if (!parseSdParam(AllowedSdParams(SdParam::number,
921                                       SdParam::minimumLiteral,
922                                       SdParam::reservedName + Sd::rUNUSED),
923                      parm))
924       break;
925     if (parm.type == SdParam::number) {
926       if (count > 0)
927         desc.addRange(min, min + (count - 1), parm.n);
928     }
929     else if (parm.type == SdParam::minimumLiteral) {
930       UnivChar c = sd.nameToUniv(parm.literalText.string());
931       if (count > 256) {
932         message(ParserMessages::tooManyCharsMinimumLiteral);
933         count = 256;
934       }
935       for (Number i = 0; i < count; i++)
936         desc.addRange(min + i, min + i, c);
937     }
938   }
939   popInputStack();
940   return 0;
941 }
942
943 Boolean Parser::sdParseCapacity(SdBuilder &sdBuilder, SdParam &parm)
944 {
945   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rPUBLIC,
946                                     SdParam::reservedName + Sd::rSGMLREF),
947                     parm))
948     return 0;
949   Boolean pushed = 0;
950   if (parm.type == SdParam::reservedName + Sd::rPUBLIC) {
951     if (!parseSdParam(AllowedSdParams(SdParam::minimumLiteral), parm))
952       return 0;
953     PublicId id;
954     PublicId::TextClass textClass;
955     const MessageType1 *err;
956     if (!id.init(parm.literalText, sd().docCharset(), syntax().space(), err))
957       sdBuilder.addFormalError(currentLocation(),
958                                *err,
959                                id.string());
960     else if (id.getTextClass(textClass)
961              && textClass != PublicId::CAPACITY)
962       sdBuilder.addFormalError(currentLocation(),
963                                ParserMessages::capacityTextClass,
964                                id.string());
965     const StringC &str = id.string();
966     if (str != sd().execToDoc("ISO 8879-1986//CAPACITY Reference//EN")
967         && str != sd().execToDoc("ISO 8879:1986//CAPACITY Reference//EN")) {
968       Boolean givenError;
969       if (referencePublic(id, PublicId::CAPACITY, givenError))
970         pushed = 1;
971       else if (!givenError)
972         message(ParserMessages::unknownCapacitySet, StringMessageArg(str));
973     }
974     if (!pushed)
975       return parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSCOPE),
976                           parm);
977   }
978
979   PackedBoolean capacitySpecified[Sd::nCapacity];
980   int i;
981   for (i = 0; i < Sd::nCapacity; i++)
982     capacitySpecified[i] = 0;
983   if (!parseSdParam(AllowedSdParams(SdParam::capacityName), parm))
984     return 0;
985   do {
986     Sd::Capacity capacityIndex = parm.capacityIndex;
987     if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
988       return 0;
989     
990     if (!capacitySpecified[capacityIndex]) {
991       sdBuilder.sd->setCapacity(capacityIndex, parm.n);
992       capacitySpecified[capacityIndex] = 1;
993     }
994     else if (options().warnSgmlDecl)
995       message(ParserMessages::duplicateCapacity,
996               StringMessageArg(sd().capacityName(i)));
997     int final = pushed ? int(SdParam::eE) : SdParam::reservedName + Sd::rSCOPE;
998     if (!parseSdParam(AllowedSdParams(SdParam::capacityName, final),
999                       parm))
1000       return 0;
1001   } while (parm.type == SdParam::capacityName);
1002   Number totalcap = sdBuilder.sd->capacity(0);
1003   for (i = 1; i < Sd::nCapacity; i++)
1004     if (sdBuilder.sd->capacity(i) > totalcap)
1005       message(ParserMessages::capacityExceedsTotalcap,
1006               StringMessageArg(sd().capacityName(i)));
1007   if (pushed)
1008     return parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSCOPE),
1009                         parm);
1010   return 1;
1011 }
1012
1013 Boolean Parser::referencePublic(const PublicId &id,
1014                                 PublicId::TextClass entityType,
1015                                 Boolean &givenError)
1016 {
1017   givenError = 0;
1018   StringC sysid;
1019   if (entityCatalog().lookupPublic(id.string(),
1020                                    sd().docCharset(),
1021                                    messenger(),
1022                                    sysid)) {
1023     Location loc = currentLocation();
1024     eventHandler().sgmlDeclEntity(new (eventAllocator())
1025                                   SgmlDeclEntityEvent(id,
1026                                                       entityType,
1027                                                       sysid,
1028                                                       loc));
1029     Ptr<EntityOrigin> origin(new EntityOrigin(loc));
1030     if (currentMarkup())
1031       currentMarkup()->addEntityStart(origin);
1032     InputSource *in = entityManager().open(sysid,
1033                                            sd().docCharset(),
1034                                            origin.pointer(),
1035                                            0,
1036                                            messenger());
1037     if (!in) {
1038       givenError = 1;
1039       return 0;
1040     }
1041     pushInput(in);
1042     return 1;
1043   }
1044   return 0;
1045 }
1046
1047 Boolean Parser::sdParseScope(SdBuilder &sdBuilder, SdParam &parm)
1048 {
1049   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rINSTANCE,
1050                                     SdParam::reservedName + Sd::rDOCUMENT),
1051                     parm))
1052     return 0;
1053   if (parm.type == SdParam::reservedName + Sd::rINSTANCE)
1054     sdBuilder.sd->setScopeInstance();
1055   return 1;
1056 }
1057
1058 Boolean Parser::sdParseSyntax(SdBuilder &sdBuilder, SdParam &parm)
1059 {
1060   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSYNTAX),
1061                     parm))
1062     return 0;
1063   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSHUNCHAR,
1064                                     SdParam::reservedName + Sd::rPUBLIC),
1065                     parm))
1066     return 0;
1067
1068   if (parm.type == SdParam::reservedName + Sd::rPUBLIC) {
1069     if (!parseSdParam(AllowedSdParams(SdParam::minimumLiteral), parm))
1070       return 0;
1071     PublicId id;
1072     const MessageType1 *err;
1073     PublicId::TextClass textClass;
1074     if (!id.init(parm.literalText, sd().docCharset(), syntax().space(), err))
1075       sdBuilder.addFormalError(currentLocation(),
1076                                *err,
1077                                id.string());
1078     else if (id.getTextClass(textClass)
1079              && textClass != PublicId::SYNTAX)
1080       sdBuilder.addFormalError(currentLocation(),
1081                                ParserMessages::syntaxTextClass,
1082                                id.string());
1083     if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rFEATURES,
1084                                       SdParam::reservedName + Sd::rSWITCHES),
1085                       parm))
1086       return 0;
1087     Vector<UnivChar> charSwitches;
1088     if (parm.type == SdParam::reservedName + Sd::rSWITCHES) {
1089       if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
1090         return 0;
1091       for (;;) {
1092         SyntaxChar c = parm.n;
1093         if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
1094           return 0;
1095         sdBuilder.switcher.addSwitch(c, parm.n);
1096         if (!parseSdParam(AllowedSdParams(SdParam::number,
1097                                           SdParam::reservedName
1098                                           + Sd::rFEATURES),
1099                           parm))
1100           return 0;
1101         if (parm.type != SdParam::number)
1102           break;
1103       }
1104     }
1105     const StandardSyntaxSpec *spec = lookupSyntax(id);
1106     if (spec) {
1107       if (!setStandardSyntax(*sdBuilder.syntax,
1108                              *spec,
1109                              sdBuilder.sd->docCharset(),
1110                              sdBuilder.switcher))
1111         sdBuilder.valid = 0;
1112     }
1113     else {
1114       Boolean givenError;
1115       if (referencePublic(id, PublicId::SYNTAX, givenError)) {
1116         sdBuilder.externalSyntax = 1;
1117         SdParam parm2;
1118         if (!parseSdParam(AllowedSdParams(SdParam::reservedName
1119                                           + Sd::rSHUNCHAR),
1120                           parm2))
1121           return 0;
1122         if (!sdParseExplicitSyntax(sdBuilder, parm2))
1123           return 0;
1124       }
1125       else {
1126         if (!givenError)
1127           message(ParserMessages::unknownPublicSyntax,
1128                   StringMessageArg(id.string()));
1129         sdBuilder.valid = 0;
1130       }
1131     }
1132   }
1133   else {
1134     if (!sdParseExplicitSyntax(sdBuilder, parm))
1135       return 0;
1136   }
1137   if (!sdBuilder.sd->scopeInstance()) {
1138     // we know the significant chars now
1139     ISet<WideChar> invalidSgmlChar;
1140     sdBuilder.syntax->checkSgmlChar(sdBuilder.sd->docCharset(),
1141                                     0,
1142                                     invalidSgmlChar);
1143     if (!invalidSgmlChar.isEmpty())
1144       message(ParserMessages::invalidSgmlChar, CharsetMessageArg(invalidSgmlChar));
1145   }
1146   checkSyntaxNamelen(*sdBuilder.syntax);
1147   checkSwitchesMarkup(sdBuilder.switcher);
1148   return 1;
1149 }
1150
1151 Boolean Parser::sdParseExplicitSyntax(SdBuilder &sdBuilder,
1152                                       SdParam &parm)
1153 {
1154   typedef Boolean (Parser::*SdParser)(SdBuilder &, SdParam &);
1155   static SdParser parsers[] = {
1156     &Parser::sdParseShunchar,
1157     &Parser::sdParseSyntaxCharset,
1158     &Parser::sdParseFunction,
1159     &Parser::sdParseNaming,
1160     &Parser::sdParseDelim,
1161     &Parser::sdParseNames,
1162     &Parser::sdParseQuantity
1163     };
1164   for (size_t i = 0; i < SIZEOF(parsers); i++)
1165     if (!(this->*(parsers[i]))(sdBuilder, parm))
1166       return 0;
1167   return 1;
1168 }
1169
1170 const StandardSyntaxSpec *Parser::lookupSyntax(const PublicId &id)
1171 {
1172   PublicId::OwnerType ownerType;
1173   if (!id.getOwnerType(ownerType) || ownerType != PublicId::ISO)
1174     return 0;
1175   StringC str;
1176   if (!id.getOwner(str))
1177     return 0;
1178   if (str != sd().execToDoc("ISO 8879:1986")
1179       && str != sd().execToDoc("ISO 8879-1986"))
1180     return 0;
1181   PublicId::TextClass textClass;
1182   if (!id.getTextClass(textClass) || textClass != PublicId::SYNTAX)
1183     return 0;
1184   if (!id.getDescription(str))
1185     return 0;
1186   if (str == sd().execToDoc("Reference"))
1187     return &refSyntax;
1188   if (str == sd().execToDoc("Core"))
1189     return &coreSyntax;
1190   return 0;
1191 }
1192
1193 Boolean Parser::sdParseSyntaxCharset(SdBuilder &sdBuilder, SdParam &parm)
1194 {
1195   UnivCharsetDesc desc;
1196   if (!sdParseCharset(sdBuilder, parm, 0, sdBuilder.syntaxCharsetDecl, desc))
1197     return 0;
1198   sdBuilder.syntaxCharset.set(desc);
1199   checkSwitches(sdBuilder.switcher, sdBuilder.syntaxCharset);
1200   for (size_t i = 0; i < sdBuilder.switcher.nSwitches(); i++)
1201     if (!sdBuilder.syntaxCharsetDecl.charDeclared(sdBuilder.switcher.switchTo(i)))
1202       message(ParserMessages::switchNotInCharset,
1203               NumberMessageArg(sdBuilder.switcher.switchTo(i)));
1204   ISet<WideChar> missing;
1205   findMissingMinimum(sdBuilder.syntaxCharset, missing);
1206   if (!missing.isEmpty())
1207     message(ParserMessages::missingMinimumChars,
1208             CharsetMessageArg(missing));
1209   return 1;
1210 }
1211
1212 Boolean Parser::sdParseShunchar(SdBuilder &sdBuilder, SdParam &parm)
1213 {
1214   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rNONE,
1215                                     SdParam::reservedName + Sd::rCONTROLS,
1216                                     SdParam::number), parm))
1217     return 0;
1218   if (parm.type == SdParam::reservedName + Sd::rNONE) {
1219     if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rBASESET),
1220                       parm))
1221       return 0;
1222     return 1;
1223   }
1224   if (parm.type == SdParam::reservedName + Sd::rCONTROLS)
1225     sdBuilder.syntax->setShuncharControls();
1226   else {
1227     if (parm.n <= charMax)
1228       sdBuilder.syntax->addShunchar(Char(parm.n));
1229   }
1230   for (;;) {
1231     if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rBASESET,
1232                                       SdParam::number), parm))
1233       return 0;
1234     if (parm.type != SdParam::number)
1235       break;
1236     if (parm.n <= charMax)
1237       sdBuilder.syntax->addShunchar(Char(parm.n));
1238   }
1239   return 1;
1240 }
1241
1242 Boolean Parser::sdParseFunction(SdBuilder &sdBuilder, SdParam &parm)
1243 {
1244   static Sd::ReservedName standardNames[3] = {
1245     Sd::rRE, Sd::rRS, Sd::rSPACE
1246   };
1247   for (int i = 0; i < 3; i++) {
1248     if (!parseSdParam(AllowedSdParams(SdParam::reservedName
1249                                       + standardNames[i]),
1250                       parm))
1251       return 0;
1252     if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
1253       return 0;
1254     Char c;
1255     if (translateSyntax(sdBuilder, parm.n, c)) {
1256       if (checkNotFunction(*sdBuilder.syntax, c))
1257         sdBuilder.syntax->setStandardFunction(Syntax::StandardFunction(i), c);
1258       else
1259         sdBuilder.valid = 0;
1260     }
1261   }
1262   Boolean haveMsichar = 0;
1263   Boolean haveMsochar = 0;
1264   for (;;) {
1265     if (!parseSdParam(sdBuilder.externalSyntax
1266                       ? AllowedSdParams(SdParam::name, SdParam::paramLiteral)
1267                       : AllowedSdParams(SdParam::name),
1268                       parm))
1269       return 0;
1270     Boolean nameWasLiteral;
1271     Boolean invalidName = 0;
1272     StringC name;
1273     if (parm.type == SdParam::paramLiteral) {
1274       nameWasLiteral = 1;
1275       if (!translateSyntax(sdBuilder, parm.paramLiteralText, name))
1276         invalidName = 1;
1277     }
1278     else {
1279       parm.token.swap(name);
1280       nameWasLiteral = 0;
1281     }
1282     if (!parseSdParam(nameWasLiteral
1283                       ? AllowedSdParams(SdParam::reservedName + Sd::rFUNCHAR,
1284                                         SdParam::reservedName + Sd::rMSICHAR,
1285                                         SdParam::reservedName + Sd::rMSOCHAR,
1286                                         SdParam::reservedName + Sd::rMSSCHAR,
1287                                         SdParam::reservedName + Sd::rSEPCHAR)
1288                       : AllowedSdParams(SdParam::reservedName + Sd::rFUNCHAR,
1289                                         SdParam::reservedName + Sd::rMSICHAR,
1290                                         SdParam::reservedName + Sd::rMSOCHAR,
1291                                         SdParam::reservedName + Sd::rMSSCHAR,
1292                                         SdParam::reservedName + Sd::rSEPCHAR,
1293                                         SdParam::reservedName + Sd::rLCNMSTRT),
1294                       parm))
1295       return 0;
1296     if (parm.type == SdParam::reservedName + Sd::rLCNMSTRT) {
1297       if (name != sd().reservedName(Sd::rNAMING))
1298         message(ParserMessages::namingBeforeLcnmstrt,
1299                 StringMessageArg(name));
1300       break;
1301     }
1302     if (!nameWasLiteral) {
1303       StringC tem;
1304       name.swap(tem);
1305       if (!translateName(sdBuilder, tem, name))
1306         invalidName = 1;
1307     }
1308     Syntax::FunctionClass functionClass;
1309     switch (parm.type) {
1310     case SdParam::reservedName + Sd::rFUNCHAR:
1311       functionClass = Syntax::cFUNCHAR;
1312       break;
1313     case SdParam::reservedName + Sd::rMSICHAR:
1314       haveMsichar = 1;
1315       functionClass = Syntax::cMSICHAR;
1316       break;
1317     case SdParam::reservedName + Sd::rMSOCHAR:
1318       haveMsochar = 1;
1319       functionClass = Syntax::cMSOCHAR;
1320       break;
1321     case SdParam::reservedName + Sd::rMSSCHAR:
1322       functionClass = Syntax::cMSSCHAR;
1323       break;
1324     case SdParam::reservedName + Sd::rSEPCHAR:
1325       functionClass = Syntax::cSEPCHAR;
1326       break;
1327     default:
1328       CANNOT_HAPPEN();
1329     }
1330     if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
1331       return 0;
1332     Char c;
1333     if (translateSyntax(sdBuilder, parm.n, c)
1334         && checkNotFunction(*sdBuilder.syntax, c)
1335         && !invalidName) {
1336       Char tem;
1337       if (sdBuilder.syntax->lookupFunctionChar(name, &tem))
1338         message(ParserMessages::duplicateFunctionName, StringMessageArg(name));
1339       else
1340         sdBuilder.syntax->addFunctionChar(name, functionClass, c);
1341     }
1342   }
1343   if (haveMsochar && !haveMsichar)
1344     message(ParserMessages::msocharRequiresMsichar);
1345   return 1;
1346 }
1347
1348 Boolean Parser::sdParseNaming(SdBuilder &sdBuilder, SdParam &parm)
1349 {
1350   static Sd::ReservedName keys[4] = {
1351     Sd::rUCNMSTRT, Sd::rLCNMCHAR, Sd::rUCNMCHAR, Sd::rNAMECASE
1352   };
1353   int isNamechar = 0;
1354   ISet<Char> nameStartChar;
1355   ISet<Char> nameChar;
1356   do {
1357     String<SyntaxChar> lc;
1358     Vector<size_t> rangeIndex;
1359     Boolean first = 1;
1360     Boolean allowThrough = 0;
1361     for (;;) {
1362       if (!parseSdParam(sdBuilder.externalSyntax
1363                         ? AllowedSdParams(SdParam::reservedName
1364                                           + keys[isNamechar * 2],
1365                                           SdParam::paramLiteral,
1366                                           SdParam::number,
1367                                           SdParam::ellipsis)
1368                         : (first
1369                            ? AllowedSdParams(SdParam::paramLiteral)
1370                            : AllowedSdParams(SdParam::reservedName
1371                                              + keys[isNamechar * 2])),
1372                         parm))
1373         return 0;
1374       first = 0;
1375       Boolean wasRange = 0;
1376       sdParamConvertToLiteral(parm);
1377       if (parm.type == SdParam::ellipsis) {
1378         if (!allowThrough)
1379           message(ParserMessages::sdInvalidEllipsis);
1380         if (!parseSdParam(AllowedSdParams(SdParam::paramLiteral,
1381                                           SdParam::number),
1382                           parm))
1383           return 0;
1384         sdParamConvertToLiteral(parm);
1385         if (parm.paramLiteralText.size() == 0)
1386           message(ParserMessages::sdInvalidEllipsis);
1387         else if (allowThrough) {
1388           SyntaxChar n = parm.paramLiteralText[0];
1389           if (n < lc[lc.size() - 1])
1390             message(ParserMessages::sdInvalidRange);
1391           else if (n > lc[lc.size() - 1] + 1)
1392             rangeIndex.push_back(lc.size() - 1);
1393         }
1394         wasRange = 1;
1395       }
1396       if (parm.type != SdParam::paramLiteral)
1397         break;
1398       lc += parm.paramLiteralText;
1399       allowThrough = (parm.paramLiteralText.size() - wasRange) > 0;
1400     }
1401     size_t lcPos = 0;
1402     size_t rangeIndexPos = 0;
1403     unsigned long rangeLeft = 0;
1404     SyntaxChar nextRangeChar;
1405     ISet<Char> &set = isNamechar ? nameChar : nameStartChar;
1406     String<SyntaxChar> chars;
1407     Boolean runOut = 0;
1408     first = 1;
1409     for (;;) {
1410       if (!parseSdParam(sdBuilder.externalSyntax
1411                         ? AllowedSdParams(SdParam::reservedName
1412                                           + keys[isNamechar * 2 + 1],
1413                                           SdParam::paramLiteral,
1414                                           SdParam::number,
1415                                           SdParam::ellipsis)
1416                         : (first
1417                            ? AllowedSdParams(SdParam::paramLiteral)
1418                            : AllowedSdParams(SdParam::reservedName
1419                                              + keys[isNamechar * 2 + 1])),
1420                         parm))
1421         return 0;
1422       sdParamConvertToLiteral(parm);
1423       first = 0;
1424       Boolean isRange = parm.type == SdParam::ellipsis;
1425       size_t nChars = chars.size();
1426       if (nChars)
1427         nChars -= isRange;
1428       for (size_t i = 0; i < nChars; i++) {
1429         if (rangeLeft == 0
1430             && rangeIndexPos < rangeIndex.size()
1431             && rangeIndex[rangeIndexPos] == lcPos) {
1432           rangeLeft = 1 + lc[lcPos + 1] - lc[lcPos];
1433           nextRangeChar = lc[lcPos];
1434           lcPos += 2;
1435           rangeIndexPos += 1;
1436         }
1437         Char c;
1438         if (rangeLeft > 0) {
1439           rangeLeft--;
1440           c = nextRangeChar++;
1441         }
1442         else if (lcPos < lc.size())
1443           c = lc[lcPos++];
1444         else {
1445           runOut = 1;
1446           c = chars[i];
1447         }
1448         // map from c to chars[i]
1449         Char transLc, transUc;
1450         if (translateSyntax(sdBuilder, c, transLc)
1451             && translateSyntax(sdBuilder, chars[i], transUc)) {
1452           set.add(transLc);
1453           if (transLc != transUc) {
1454             set.add(transUc);
1455             sdBuilder.syntax->addSubst(transLc, transUc);
1456           }
1457         }
1458       }
1459       if (isRange) {
1460         if (!parseSdParam(AllowedSdParams(SdParam::paramLiteral,
1461                                           SdParam::number),
1462                           parm))
1463           return 0;
1464         sdParamConvertToLiteral(parm);
1465         if (chars.size() == 0 || parm.paramLiteralText.size() == 0)
1466           message(ParserMessages::sdInvalidEllipsis);
1467         else {
1468           SyntaxChar start = chars[chars.size() - 1];
1469           SyntaxChar end = parm.paramLiteralText[0];
1470           if (start > end)
1471             message(ParserMessages::sdInvalidRange);
1472           else {
1473             size_t count = end + 1 - start;
1474             while (count > 0) {
1475               if (rangeLeft == 0
1476                   && rangeIndexPos < rangeIndex.size()
1477                   && rangeIndex[rangeIndexPos] == lcPos) {
1478                 rangeLeft = 1 + lc[lcPos + 1] - lc[lcPos];
1479                 nextRangeChar = lc[lcPos];
1480                 lcPos += 2;
1481                 rangeIndexPos += 1;
1482               }
1483               Char c;
1484               if (rangeLeft > 0) {
1485                 rangeLeft--;
1486                 c = nextRangeChar++;
1487               }
1488               else if (lcPos < lc.size())
1489                 c = lc[lcPos++];
1490               else {
1491                 c = start;
1492                 runOut = 1;
1493               }
1494               if (c == start && count > 1 && (runOut || rangeLeft > 0)) {
1495                 size_t n;
1496                 if (runOut)
1497                   n = count;
1498                 else if (rangeLeft < count)
1499                   n = rangeLeft + 1;
1500                 else
1501                   n = count;
1502                 translateRange(sdBuilder, start, start + (count - 1), set);
1503                 count -= n;
1504                 start += n;
1505               }
1506               else {
1507                 Char transLc, transUc;
1508                 if (translateSyntax(sdBuilder, c, transLc)
1509                     && translateSyntax(sdBuilder, start, transUc)) {
1510                   set.add(transLc);
1511                   if (transLc != transUc) {
1512                     set.add(transUc);
1513                     sdBuilder.syntax->addSubst(transLc, transUc);
1514                   }
1515                 }
1516                 count--;
1517                 start++;
1518               }
1519             }
1520           }
1521         }
1522         chars.resize(0);
1523         if (parm.type != SdParam::paramLiteral)
1524           break;
1525         chars.append(parm.paramLiteralText.data() + 1,
1526                      parm.paramLiteralText.size() - 1);
1527       }
1528       else if (parm.type == SdParam::paramLiteral)
1529         parm.paramLiteralText.swap(chars);
1530       else
1531         break;
1532     }
1533     if ((runOut && !sdBuilder.externalSyntax)
1534         || rangeLeft > 0 || lcPos < lc.size())
1535       message(isNamechar
1536               ? ParserMessages::nmcharLength
1537               : ParserMessages::nmstrtLength);
1538     if (!checkNmchars(set, *sdBuilder.syntax))
1539       sdBuilder.valid = 0;
1540   } while (!isNamechar++);
1541   ISet<WideChar> bad;
1542   intersectCharSets(nameStartChar, nameChar, bad);
1543   if (!bad.isEmpty()) {
1544     sdBuilder.valid = 0;
1545     message(ParserMessages::nmcharNmstrt, CharsetMessageArg(bad));
1546   }
1547   sdBuilder.syntax->addNameStartCharacters(nameStartChar);
1548   sdBuilder.syntax->addNameCharacters(nameChar);
1549   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rGENERAL),
1550                     parm))
1551     return 0;
1552   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rNO,
1553                                     SdParam::reservedName + Sd::rYES),
1554                     parm))
1555     return 0;
1556   sdBuilder.syntax->setNamecaseGeneral(parm.type
1557                                        == SdParam::reservedName + Sd::rYES);
1558
1559   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rENTITY),
1560                     parm))
1561     return 0;
1562   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rNO,
1563                                     SdParam::reservedName + Sd::rYES),
1564                     parm))
1565     return 0;
1566   sdBuilder.syntax->setNamecaseEntity(parm.type
1567                                       == SdParam::reservedName + Sd::rYES);
1568   return 1;
1569 }
1570
1571 Boolean Parser::checkNmchars(const ISet<Char> &set, const Syntax &syntax)
1572 {
1573   Boolean valid = 1;
1574   ISet<WideChar> bad;
1575   intersectCharSets(set, *syntax.charSet(Syntax::nameStart), bad);
1576   if (!bad.isEmpty()) {
1577     message(ParserMessages::nmcharLetter, CharsetMessageArg(bad));
1578     valid = 0;
1579     bad.clear();
1580   }
1581   intersectCharSets(set, *syntax.charSet(Syntax::digit), bad);
1582   if (!bad.isEmpty()) {
1583     message(ParserMessages::nmcharDigit, CharsetMessageArg(bad));
1584     valid = 0;
1585     bad.clear();
1586   }
1587   Char funChar;
1588   if (syntax.getStandardFunction(Syntax::fRE, funChar)
1589       && set.contains(funChar)) {
1590     message(ParserMessages::nmcharRe, NumberMessageArg(funChar));
1591     valid = 0;
1592   }
1593   if (syntax.getStandardFunction(Syntax::fRS, funChar)
1594       && set.contains(funChar)) {
1595     message(ParserMessages::nmcharRs, NumberMessageArg(funChar));
1596     valid = 0;
1597   }
1598   if (syntax.getStandardFunction(Syntax::fSPACE, funChar)
1599       && set.contains(funChar)) {
1600     message(ParserMessages::nmcharSpace, NumberMessageArg(funChar));
1601     valid = 0;
1602   }
1603   intersectCharSets(set, *syntax.charSet(Syntax::sepchar), bad);
1604   if (!bad.isEmpty()) {
1605     message(ParserMessages::nmcharSepchar, CharsetMessageArg(bad));
1606     valid = 0;
1607   }
1608   return valid;
1609 }
1610
1611 // Result is a ISet<WideChar>, so it can be used with CharsetMessageArg.
1612
1613 void Parser::intersectCharSets(const ISet<Char> &s1, const ISet<Char> &s2,
1614                                ISet<WideChar> &inter)
1615 {
1616   ISetIter<Char> i1(s1);
1617   ISetIter<Char> i2(s2);
1618   Char min1, max1, min2, max2;
1619   if (!i1.next(min1, max1))
1620     return;
1621   if (!i2.next(min2, max2))
1622     return;
1623   for (;;) {
1624     if (max1 < min2) {
1625       if (!i1.next(min1, max1))
1626         break;
1627     }
1628     else if (max2 < min1) {
1629       if (!i2.next(min2, max2))
1630         break;
1631     }
1632     else {
1633       // min2 <= max1
1634       // min1 <= max2
1635       Char min = min1 > min2 ? min1 : min2;
1636       Char max = max1 < max2 ? max1 : max2;
1637       inter.addRange(min, max);
1638       if (!i1.next(min1, max1))
1639         break;
1640       if (!i2.next(min2, max2))
1641         break;
1642     }
1643   }
1644 }
1645
1646 Boolean Parser::sdParseDelim(SdBuilder &sdBuilder, SdParam &parm)
1647 {
1648   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rDELIM),
1649                     parm))
1650     return 0;
1651   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rGENERAL),
1652                     parm))
1653     return 0;
1654   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSGMLREF),
1655                     parm))
1656     return 0;
1657   PackedBoolean delimGeneralSpecified[Syntax::nDelimGeneral];
1658   for (int i = 0; i < Syntax::nDelimGeneral; i++)
1659     delimGeneralSpecified[i] = 0;
1660   for (;;) {
1661     if (!parseSdParam(AllowedSdParams(SdParam::generalDelimiterName,
1662                                       SdParam::reservedName + Sd::rSHORTREF),
1663                       parm))
1664       return 0;
1665     if (parm.type == SdParam::reservedName + Sd::rSHORTREF)
1666       break;
1667     Syntax::DelimGeneral delimGeneral = parm.delimGeneralIndex;
1668     if (delimGeneralSpecified[delimGeneral])
1669       message(ParserMessages::duplicateDelimGeneral,
1670               StringMessageArg(sd().generalDelimiterName(delimGeneral)));
1671     if (!parseSdParam(sdBuilder.externalSyntax
1672                       ? AllowedSdParams(SdParam::paramLiteral,
1673                                         SdParam::number)
1674                       : AllowedSdParams(SdParam::paramLiteral),
1675                       parm))
1676       return 0;
1677     sdParamConvertToLiteral(parm);
1678     StringC str;
1679     if (parm.paramLiteralText.size() == 0)
1680         message(ParserMessages::sdEmptyDelimiter);
1681     else if (translateSyntax(sdBuilder, parm.paramLiteralText, str)) {
1682       const SubstTable<Char> *table = sdBuilder.syntax->generalSubstTable();
1683       for (size_t i = 0; i < str.size(); i++)
1684         table->subst(str[i]);
1685       if (checkGeneralDelim(*sdBuilder.syntax, str)
1686           && !delimGeneralSpecified[delimGeneral])
1687         sdBuilder.syntax->setDelimGeneral(delimGeneral, str);
1688       else
1689         sdBuilder.valid = 0;
1690     }
1691     delimGeneralSpecified[delimGeneral] = 1;
1692   }
1693   if (!setRefDelimGeneral(*sdBuilder.syntax,
1694                           sdBuilder.syntaxCharset,
1695                           sdBuilder.sd->docCharset(),
1696                           sdBuilder.switcher))
1697     sdBuilder.valid = 0;
1698   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSGMLREF,
1699                                     SdParam::reservedName + Sd::rNONE),
1700                     parm))
1701     return 0;
1702   if (parm.type == SdParam::reservedName + Sd::rSGMLREF) {
1703     if (!addRefDelimShortref(*sdBuilder.syntax,
1704                              sdBuilder.syntaxCharset,
1705                              sdBuilder.sd->docCharset(),
1706                              sdBuilder.switcher))
1707       sdBuilder.valid = 0;
1708   }
1709   String<SyntaxChar> lastLiteral;
1710   for (;;) {
1711     if (!parseSdParam(sdBuilder.externalSyntax
1712                       ? AllowedSdParams(SdParam::paramLiteral,
1713                                         SdParam::number,
1714                                         SdParam::ellipsis,
1715                                         SdParam::reservedName + Sd::rNAMES)
1716                       : AllowedSdParams(SdParam::paramLiteral,
1717                                         SdParam::reservedName + Sd::rNAMES),
1718                       parm))
1719       return 0;
1720     sdParamConvertToLiteral(parm);
1721     if (parm.type == SdParam::ellipsis) {
1722       if (!parseSdParam(AllowedSdParams(SdParam::paramLiteral,
1723                                         SdParam::number),
1724                         parm))
1725         return 0;
1726       sdParamConvertToLiteral(parm);
1727       if (parm.paramLiteralText.size() == 0)
1728         message(ParserMessages::sdEmptyDelimiter);
1729       else if (lastLiteral.size() != 1
1730                || parm.paramLiteralText.size() != 1)
1731         message(ParserMessages::sdInvalidEllipsis);
1732       else if (parm.paramLiteralText[0] < lastLiteral[0])
1733         message(ParserMessages::sdInvalidRange);
1734       else if (parm.paramLiteralText[0] != lastLiteral[0]) {
1735         ISet<Char> shortrefChars;
1736         translateRange(sdBuilder,
1737                        lastLiteral[0] + 1,
1738                        parm.paramLiteralText[0],
1739                        shortrefChars);
1740         ISet<WideChar> duplicates;
1741         intersectCharSets(shortrefChars,
1742                           sdBuilder.syntax->delimShortrefSimple(),
1743                           duplicates);
1744         int nComplexShortrefs = sdBuilder.syntax->nDelimShortrefComplex();
1745         for (int i = 0; i < nComplexShortrefs; i++) {
1746           const StringC &delim = sdBuilder.syntax->delimShortrefComplex(i);
1747           if (delim.size() == 1 && shortrefChars.contains(delim[0]))
1748             duplicates.add(delim[0]);
1749         }
1750         if (!duplicates.isEmpty())
1751           message(ParserMessages::duplicateDelimShortrefSet,
1752                   CharsetMessageArg(duplicates));
1753         sdBuilder.syntax->addDelimShortrefs(shortrefChars,
1754                                             sdBuilder.sd->docCharset());
1755       }
1756       lastLiteral.resize(0);
1757     }
1758     else if (parm.type == SdParam::paramLiteral) {
1759       parm.paramLiteralText.swap(lastLiteral);
1760       StringC str;
1761       if (lastLiteral.size() == 0)
1762         message(ParserMessages::sdEmptyDelimiter);
1763       else if (translateSyntax(sdBuilder, lastLiteral, str)) {
1764         const SubstTable<Char> *table = sdBuilder.syntax->generalSubstTable();
1765         for (size_t i = 0; i < str.size(); i++)
1766           table->subst(str[i]);
1767         if (str.size() == 1
1768             || checkShortrefDelim(*sdBuilder.syntax,
1769                                   sdBuilder.sd->docCharset(),
1770                                   str)) {
1771           if (sdBuilder.syntax->isValidShortref(str))
1772             message(ParserMessages::duplicateDelimShortref,
1773                     StringMessageArg(str));
1774           else
1775             sdBuilder.syntax->addDelimShortref(str,
1776                                                sdBuilder.sd->docCharset());
1777         }
1778       }
1779     }
1780     else
1781       break;
1782   }
1783   return 1;
1784 }
1785
1786 Boolean Parser::sdParseNames(SdBuilder &sdBuilder, SdParam &parm)
1787 {
1788   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSGMLREF),
1789                     parm))
1790     return 0;
1791   for (;;) {
1792     if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rQUANTITY,
1793                                       SdParam::referenceReservedName),
1794                       parm))
1795       return 0;
1796     if (parm.type == SdParam::reservedName + Sd::rQUANTITY)
1797       break;
1798     Syntax::ReservedName reservedName = parm.reservedNameIndex;
1799     if (!parseSdParam(sdBuilder.externalSyntax
1800                       ? AllowedSdParams(SdParam::name, SdParam::paramLiteral)
1801                       : AllowedSdParams(SdParam::name),
1802                       parm))
1803       return 0;
1804     StringC transName;
1805     if (parm.type == SdParam::name
1806         ? translateName(sdBuilder, parm.token, transName)
1807         : translateSyntax(sdBuilder, parm.paramLiteralText, transName)) {
1808       Syntax::ReservedName tem;
1809       if (sdBuilder.syntax->lookupReservedName(transName, &tem))
1810         message(ParserMessages::ambiguousReservedName,
1811                 StringMessageArg(transName));
1812       else {
1813         if (transName.size() == 0
1814             || !sdBuilder.syntax->isNameStartCharacter(transName[0])) {
1815           message(ParserMessages::reservedNameSyntax,
1816                   StringMessageArg(transName));
1817           transName.resize(0);
1818         }
1819         size_t i;
1820         // Check that its a valid name in the declared syntax
1821         // (- and . might not be name characters).
1822         for (i = 1; i < transName.size(); i++)
1823           if (!sdBuilder.syntax->isNameCharacter(transName[i])) {
1824             message(ParserMessages::reservedNameSyntax,
1825                     StringMessageArg(transName));
1826             transName.resize(0);
1827             break;
1828           }
1829         for (i = 0; i < transName.size(); i++)
1830           sdBuilder.syntax->generalSubstTable()->subst(transName[i]);
1831         if (sdBuilder.syntax->reservedName(reservedName).size() > 0)
1832           message(ParserMessages::duplicateReservedName,
1833                   StringMessageArg(syntax().reservedName(reservedName)));
1834         else if (transName.size() > 0)
1835           sdBuilder.syntax->setName(reservedName, transName);
1836         else
1837           sdBuilder.valid = 0;
1838       }
1839     }
1840   }
1841   setRefNames(*sdBuilder.syntax, sdBuilder.sd->docCharset());
1842   static Syntax::ReservedName functionNameIndex[3] = {
1843     Syntax::rRE, Syntax::rRS, Syntax::rSPACE
1844   };
1845   for (int i = 0; i < 3; i++) {
1846     const StringC &functionName
1847       = sdBuilder.syntax->reservedName(functionNameIndex[i]);
1848     Char tem;
1849     if (sdBuilder.syntax->lookupFunctionChar(functionName, &tem))
1850       message(ParserMessages::duplicateFunctionName, StringMessageArg(functionName));
1851   }
1852   sdBuilder.syntax->enterStandardFunctionNames();
1853   return 1;
1854 }
1855
1856 Boolean Parser::sdParseQuantity(SdBuilder &sdBuilder, SdParam &parm)
1857 {
1858   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rSGMLREF),
1859                     parm))
1860     return 0;
1861   for (;;) {
1862     int final = (sdBuilder.externalSyntax
1863                  ? int(SdParam::eE)
1864                  : SdParam::reservedName + Sd::rFEATURES);
1865     if (!parseSdParam(AllowedSdParams(SdParam::quantityName, final), parm))
1866       return 0;
1867     if (parm.type != SdParam::quantityName)
1868       break;
1869     Syntax::Quantity quantity = parm.quantityIndex;
1870     if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
1871       return 0;
1872     sdBuilder.syntax->setQuantity(quantity, parm.n);
1873   }
1874   if (sdBuilder.sd->scopeInstance()) {
1875     for (int i = 0; i < Syntax::nQuantity; i++)
1876       if (sdBuilder.syntax->quantity(Syntax::Quantity(i))
1877           < syntax().quantity(Syntax::Quantity(i)))
1878         message(ParserMessages::scopeInstanceQuantity,
1879                 StringMessageArg(sd().quantityName(Syntax::Quantity(i))));
1880   }
1881   return 1;
1882 }
1883
1884 Boolean Parser::sdParseFeatures(SdBuilder &sdBuilder, SdParam &parm)
1885 {
1886   struct FeatureInfo {
1887     Sd::ReservedName name;
1888     enum {
1889       __none,
1890       __boolean,
1891       __number
1892     } arg;
1893   };
1894   static FeatureInfo features[] = {
1895     { Sd::rMINIMIZE, FeatureInfo::__none },
1896     { Sd::rDATATAG, FeatureInfo::__boolean },
1897     { Sd::rOMITTAG, FeatureInfo::__boolean },
1898     { Sd::rRANK, FeatureInfo::__boolean },
1899     { Sd::rSHORTTAG, FeatureInfo::__boolean },
1900     { Sd::rLINK, FeatureInfo::__none },
1901     { Sd::rSIMPLE, FeatureInfo::__number },
1902     { Sd::rIMPLICIT, FeatureInfo::__boolean },
1903     { Sd::rEXPLICIT, FeatureInfo::__number },
1904     { Sd::rOTHER, FeatureInfo::__none },
1905     { Sd::rCONCUR, FeatureInfo::__number },
1906     { Sd::rSUBDOC, FeatureInfo::__number },
1907     { Sd::rFORMAL, FeatureInfo::__boolean }
1908   };
1909   int booleanFeature = 0;
1910   int numberFeature = 0;
1911   for (size_t i = 0; i < SIZEOF(features); i++) {
1912     if (!parseSdParam(AllowedSdParams(SdParam::reservedName
1913                                       + features[i].name), parm))
1914       return 0;
1915     if (features[i].arg != FeatureInfo::__none) {
1916       if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rNO,
1917                                         SdParam::reservedName + Sd::rYES),
1918                         parm))
1919         return 0;
1920 #if 0
1921       if (features[i].name == Sd::rDATATAG
1922           && parm.type == (SdParam::reservedName + Sd::rYES))
1923         message(ParserMessages::datatagNotImplemented);
1924 #endif
1925       if (features[i].arg == FeatureInfo::__number) {
1926         if (parm.type == SdParam::reservedName + Sd::rYES) {
1927           if (!parseSdParam(AllowedSdParams(SdParam::number), parm))
1928             return 0;
1929           sdBuilder.sd->setNumberFeature(Sd::NumberFeature(numberFeature++),
1930                                          parm.n);
1931         }
1932         else
1933           sdBuilder.sd->setNumberFeature(Sd::NumberFeature(numberFeature++),
1934                                          0);
1935       }
1936       else
1937           sdBuilder.sd->setBooleanFeature(Sd::BooleanFeature(booleanFeature++),
1938                                           parm.type == (SdParam::reservedName
1939                                                         + Sd::rYES));
1940     }
1941   }
1942   return 1;
1943 }
1944
1945 Boolean Parser::sdParseAppinfo(SdBuilder &, SdParam &parm)
1946 {
1947   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rAPPINFO),
1948                     parm))
1949     return 0;
1950   Location location(currentLocation());
1951   if (!parseSdParam(AllowedSdParams(SdParam::reservedName + Sd::rNONE,
1952                                     SdParam::minimumLiteral),
1953                     parm))
1954     return 0;
1955   AppinfoEvent *event;
1956   if (parm.type == SdParam::minimumLiteral)
1957     event = new (eventAllocator()) AppinfoEvent(parm.literalText, location);
1958   else
1959     event = new (eventAllocator()) AppinfoEvent(location);
1960   eventHandler().appinfo(event);
1961   return 1;
1962 }
1963
1964 Boolean Parser::translateSyntax(CharSwitcher &switcher,
1965                                 const CharsetInfo &syntaxCharset,
1966                                 const CharsetInfo &docCharset,
1967                                 WideChar syntaxChar,
1968                                 Char &docChar)
1969 {
1970   syntaxChar = switcher.subst(syntaxChar);
1971   UnivChar univChar;
1972   if (syntaxCharset.descToUniv(syntaxChar, univChar)
1973       && univToDescCheck(docCharset, univChar, docChar))
1974     return 1;
1975   message(ParserMessages::translateSyntaxChar, NumberMessageArg(syntaxChar));
1976   return 0;
1977 }
1978
1979 void Parser::translateRange(SdBuilder &sdBuilder, SyntaxChar start,
1980                             SyntaxChar end, ISet<Char> &chars)
1981 {
1982 #if 0
1983   do {
1984     Char docChar;
1985     if (!translateSyntax(sdBuilder, start, docChar))
1986       break;
1987     chars.add(docChar);
1988   } while (start++ != end);
1989 #endif
1990   for (;;) {
1991     SyntaxChar doneUpTo = end;
1992     Boolean gotSwitch = 0;
1993     WideChar firstSwitch;
1994     for (size_t i = 0; i < sdBuilder.switcher.nSwitches(); i++) {
1995       WideChar c = sdBuilder.switcher.switchFrom(i);
1996       if (start <= c && c <= end) {
1997         if (!gotSwitch) {
1998           gotSwitch = 1;
1999           firstSwitch = c;
2000         }
2001         else if (c < firstSwitch)
2002           firstSwitch = c;
2003       }
2004     }
2005     if (gotSwitch && firstSwitch == start) {
2006       doneUpTo = start;
2007       Char docChar;
2008       if (translateSyntax(sdBuilder, start, docChar))
2009         chars.add(docChar);
2010     }
2011     else {
2012       if (gotSwitch)
2013         doneUpTo = firstSwitch - 1;
2014       Char docChar;
2015       Number count;
2016       if (translateSyntaxNoSwitch(sdBuilder, start, docChar, count)) {
2017         if (count - 1 < doneUpTo - start)
2018           doneUpTo = start + (count - 1);
2019         chars.addRange(docChar, docChar + (doneUpTo - start));
2020       }
2021     }
2022     if (doneUpTo == end)
2023       break;
2024     start = doneUpTo + 1;
2025   }
2026 }
2027
2028 Boolean Parser::translateSyntax(SdBuilder &sdBuilder,
2029                                 WideChar syntaxChar, Char &docChar)
2030 {
2031   Number count;
2032   return translateSyntaxNoSwitch(sdBuilder,
2033                                  sdBuilder.switcher.subst(syntaxChar),
2034                                  docChar,
2035                                  count);
2036 }
2037
2038 Boolean Parser::translateSyntaxNoSwitch(SdBuilder &sdBuilder,
2039                                         WideChar syntaxChar, Char &docChar,
2040                                         Number &count)
2041 {
2042   Number n;
2043   StringC str;
2044   CharsetDeclRange::Type type;
2045   const PublicId *id;
2046   if (sdBuilder.syntaxCharsetDecl.getCharInfo(syntaxChar,
2047                                               id,
2048                                               type,
2049                                               n,
2050                                               str,
2051                                               count)) {
2052     ISet<WideChar> docChars;
2053     switch (type) {
2054     case CharsetDeclRange::unused:
2055       break;
2056     case CharsetDeclRange::string:
2057       sdBuilder.sd->docCharsetDecl().stringToChar(str, docChars);
2058       break;
2059     case CharsetDeclRange::number:
2060       {
2061         Number count2;
2062         sdBuilder.sd->docCharsetDecl().numberToChar(id, n, docChars, count2);
2063         if (!docChars.isEmpty() && count2 < count)
2064           count = count2;
2065       }
2066       break;
2067     default:
2068       CANNOT_HAPPEN();
2069     }
2070     if (!docChars.isEmpty()) {
2071       if (!docChars.isSingleton() && options().warnSgmlDecl)
2072         message(ParserMessages::ambiguousDocCharacter,
2073                 CharsetMessageArg(docChars));
2074       ISetIter<WideChar> iter(docChars);
2075       WideChar min, max;
2076       if (iter.next(min, max) && min <= charMax) {
2077         docChar = Char(min);
2078         return 1;
2079       }
2080     }
2081   }
2082   UnivChar univChar;
2083   WideChar alsoMax, count2;
2084   if (sdBuilder.syntaxCharset.descToUniv(syntaxChar, univChar, alsoMax)
2085       && univToDescCheck(sdBuilder.sd->docCharset(), univChar, docChar,
2086                          count2)) {
2087     count = (alsoMax - syntaxChar) + 1;
2088     if (count2 < count)
2089       count = count2;
2090     return 1;
2091   }
2092   sdBuilder.valid = 0;
2093   message(ParserMessages::translateSyntaxChar, NumberMessageArg(syntaxChar));
2094   return 0;
2095 }
2096
2097
2098 Boolean Parser::translateSyntax(SdBuilder &sdBuilder,
2099                                 const String<SyntaxChar> &syntaxString,
2100                                 StringC &docString)
2101 {
2102   docString.resize(0);
2103   int ret = 1;
2104   for (size_t i = 0; i < syntaxString.size(); i++) {
2105     Char c;
2106     if (translateSyntax(sdBuilder, syntaxString[i], c))
2107       docString += c;
2108     else
2109       ret = 0;
2110   }
2111   return ret;
2112 }
2113
2114 Boolean Parser::translateName(SdBuilder &sdBuilder,
2115                               const StringC &name,
2116                               StringC &str)
2117 {
2118   str.resize(name.size());
2119   for (size_t i = 0; i < name.size(); i++) {
2120     UnivChar univChar;
2121     Boolean ret = sd().docCharset().descToUniv(name[i], univChar);
2122     // Might switch hyphen or period.
2123     univChar = translateUniv(univChar, sdBuilder.switcher,
2124                              sdBuilder.syntaxCharset);
2125     ASSERT(ret != 0);
2126     if (!univToDescCheck(sdBuilder.sd->docCharset(), univChar, str[i])) {
2127       message(ParserMessages::translateDocChar, NumberMessageArg(univChar));
2128       sdBuilder.valid = 0;
2129       return 0;
2130     }
2131   }
2132   return 1;
2133 }
2134
2135 UnivChar Parser::translateUniv(UnivChar univChar,
2136                                CharSwitcher &switcher,
2137                                const CharsetInfo &syntaxCharset)
2138 {
2139   WideChar syntaxChar;
2140   ISet<WideChar> syntaxChars;
2141   if (syntaxCharset.univToDesc(univChar, syntaxChar, syntaxChars) != 1) {
2142     message(ParserMessages::missingSyntaxChar,
2143             NumberMessageArg(univChar));
2144     return univChar;
2145   }
2146   SyntaxChar tem = switcher.subst(syntaxChar);
2147   if (tem != syntaxChar && !syntaxCharset.descToUniv(tem, univChar))
2148     message(ParserMessages::translateSyntaxChar, NumberMessageArg(tem));
2149   return univChar;
2150 }
2151
2152 Boolean Parser::checkNotFunction(const Syntax &syn, Char c)
2153 {
2154   if (syn.charSet(Syntax::functionChar)->contains(c)) {
2155     message(ParserMessages::oneFunction, NumberMessageArg(c));
2156     return 0;
2157   }
2158   else
2159     return 1;
2160 }
2161
2162
2163 // Check that it has at most one B sequence and that it
2164 // is not adjacent to a blank sequence.
2165
2166 Boolean Parser::checkShortrefDelim(const Syntax &syn,
2167                                    const CharsetInfo &charset,
2168                                    const StringC &delim)
2169 {
2170   Boolean hadB = 0;
2171   Char letterB = charset.execToDesc('B');
2172   const ISet<Char> *bSet = syn.charSet(Syntax::blank);
2173   for (size_t i = 0; i < delim.size(); i++)
2174     if (delim[i] == letterB) {
2175       if (hadB) {
2176         message(ParserMessages::multipleBSequence, StringMessageArg(delim));
2177         return 0;
2178       }
2179       hadB = 1;
2180       if (i > 0 && bSet->contains(delim[i - 1])) {
2181         message(ParserMessages::blankAdjacentBSequence,
2182                 StringMessageArg(delim));
2183         return 0;
2184       }
2185       while (i + 1 < delim.size() && delim[i + 1] == letterB)
2186         i++;
2187       if (i < delim.size() - 1 && bSet->contains(delim[i + 1])) {
2188         message(ParserMessages::blankAdjacentBSequence,
2189                 StringMessageArg(delim));
2190         return 0;
2191       }
2192     }
2193   return 1;
2194 }
2195
2196 Boolean Parser::checkGeneralDelim(const Syntax &syn, const StringC &delim)
2197 {
2198   const ISet<Char> *functionSet = syn.charSet(Syntax::functionChar);
2199   if (delim.size() > 0) {
2200     Boolean allFunction = 1;
2201     for (size_t i = 0; i < delim.size(); i++)
2202       if (!functionSet->contains(delim[i]))
2203         allFunction = 0;
2204     if (allFunction) {
2205       message(ParserMessages::generalDelimAllFunction,
2206               StringMessageArg(delim));
2207       return 0;
2208     }
2209   }
2210   return 1;
2211 }
2212
2213 Boolean Parser::checkSwitches(CharSwitcher &switcher,
2214                               const CharsetInfo &syntaxCharset)
2215 {
2216   Boolean valid = 1;
2217   for (size_t i = 0; i < switcher.nSwitches(); i++) {
2218     WideChar c[2];
2219     c[0] = switcher.switchFrom(i);
2220     c[1] = switcher.switchTo(i);
2221     for (int j = 0; j < 2; j++) {
2222       UnivChar univChar;
2223       if (syntaxCharset.descToUniv(c[j], univChar)) {
2224         // Check that it is not Digit Lcletter or Ucletter
2225         if ((UnivCharsetDesc::a <= univChar
2226              && univChar < UnivCharsetDesc::a + 26)
2227             || (UnivCharsetDesc::A <= univChar
2228                 && univChar < UnivCharsetDesc::A + 26)
2229             || (UnivCharsetDesc::zero <= univChar
2230                 && univChar < UnivCharsetDesc::zero + 10)) {
2231           message(ParserMessages::switchLetterDigit,
2232                   NumberMessageArg(univChar));
2233           valid = 0;
2234         }
2235       }
2236     }
2237   }
2238   return valid;
2239 }
2240
2241 Boolean Parser::checkSwitchesMarkup(CharSwitcher &switcher)
2242 {
2243   Boolean valid = 1;
2244   size_t nSwitches = switcher.nSwitches();
2245   for (size_t i = 0; i < nSwitches; i++)
2246     if (!switcher.switchUsed(i)) {
2247       // If the switch wasn't used,
2248       // then the character wasn't a markup character.
2249       message(ParserMessages::switchNotMarkup,
2250               NumberMessageArg(switcher.switchFrom(i)));
2251       valid = 0;
2252     }
2253   return valid;
2254 }
2255
2256 void Parser::checkSyntaxNamelen(const Syntax &syn)
2257 {
2258   size_t namelen = syn.namelen();
2259   int i;
2260   for (i = 0; i < Syntax::nDelimGeneral; i++)
2261     if (syn.delimGeneral(i).size() > namelen)
2262       message(ParserMessages::delimiterLength,
2263               StringMessageArg(syn.delimGeneral(i)),
2264               NumberMessageArg(namelen));
2265   for (i = 0; i < syn.nDelimShortrefComplex(); i++)
2266     if (syn.delimShortrefComplex(i).size() > namelen)
2267       message(ParserMessages::delimiterLength,
2268               StringMessageArg(syn.delimShortrefComplex(i)),
2269               NumberMessageArg(namelen));
2270   for (i = 0; i < Syntax::nNames; i++)
2271     if (syn.reservedName(Syntax::ReservedName(i)).size() > namelen
2272         && options().warnSgmlDecl)
2273       message(ParserMessages::reservedNameLength,
2274               StringMessageArg(syn.reservedName(Syntax::ReservedName(i))),
2275               NumberMessageArg(namelen));
2276 }
2277
2278 Boolean Parser::univToDescCheck(const CharsetInfo &charset, UnivChar from,
2279                                 Char &to)
2280 {
2281   WideChar count;
2282   return univToDescCheck(charset, from, to, count);
2283 }
2284
2285 Boolean Parser::univToDescCheck(const CharsetInfo &charset, UnivChar from,
2286                                 Char &to, WideChar &count)
2287 {
2288   WideChar c;
2289   ISet<WideChar> descSet;
2290   unsigned ret = charset.univToDesc(from, c, descSet, count);
2291   if (ret > 1) {
2292     if (options().warnSgmlDecl)
2293       message(ParserMessages::ambiguousDocCharacter,
2294               CharsetMessageArg(descSet));
2295     ret = 1;
2296   }
2297   if (ret && c <= charMax) {
2298     to = Char(c);
2299     return 1;
2300   }
2301   return 0;
2302 }
2303
2304 Boolean Parser::parseSdParam(const AllowedSdParams &allow,
2305                              SdParam &parm)
2306 {
2307   for (;;) {
2308     Token token = getToken(mdMode);
2309     switch (token) {
2310     case tokenUnrecognized:
2311       if (reportNonSgmlCharacter())
2312         break;
2313       {
2314         message(ParserMessages::markupDeclarationCharacter,
2315                 StringMessageArg(currentToken()),
2316                 AllowedSdParamsMessageArg(allow, sdPointer()));
2317       }
2318       return 0;
2319     case tokenEe:
2320       if (allow.param(SdParam::eE)) {
2321         parm.type = SdParam::eE;
2322         if (currentMarkup())
2323           currentMarkup()->addEntityEnd();
2324         popInputStack();
2325         return 1;
2326       }
2327       message(ParserMessages::sdEntityEnd,
2328               AllowedSdParamsMessageArg(allow, sdPointer()));
2329       return 0;
2330     case tokenS:
2331       if (currentMarkup())
2332         currentMarkup()->addS(currentChar());
2333       break;
2334     case tokenCom:
2335       if (!parseComment(sdcomMode))
2336         return 0;
2337       break;
2338     case tokenDso:
2339     case tokenGrpo:
2340     case tokenMinusGrpo:
2341     case tokenPlusGrpo:
2342     case tokenRni:
2343     case tokenPeroNameStart:
2344     case tokenPeroGrpo:
2345       sdParamInvalidToken(token, allow);
2346       return 0;
2347     case tokenLcUcNmchar:
2348       if (allow.param(SdParam::ellipsis)) {
2349         extendNameToken(syntax().namelen(), ParserMessages::nameLength);
2350         getCurrentToken(syntax().generalSubstTable(), parm.token);
2351         if (parm.token == sd().execToDoc("...")) {
2352           parm.type = SdParam::ellipsis;
2353           return 1;
2354         }
2355         message(ParserMessages::sdInvalidNameToken,
2356                 StringMessageArg(parm.token),
2357                 AllowedSdParamsMessageArg(allow, sdPointer()));
2358       }
2359       else {
2360         sdParamInvalidToken(token, allow);
2361         return 0;
2362       }
2363     case tokenLita:
2364     case tokenLit:
2365       {
2366         Boolean lita = (token == tokenLita);
2367         if (allow.param(SdParam::minimumLiteral)) {
2368           if (!parseMinimumLiteral(lita, parm.literalText))
2369             return 0;
2370           parm.type = SdParam::minimumLiteral;
2371           if (currentMarkup())
2372             currentMarkup()->addLiteral(parm.literalText);
2373         }
2374         else if (allow.param(SdParam::paramLiteral)) {
2375           if (!parseSdParamLiteral(lita, parm.paramLiteralText))
2376             return 0;
2377           parm.type = SdParam::paramLiteral;
2378         }
2379         else {
2380           sdParamInvalidToken(token, allow);
2381           return 0;
2382         }
2383         return 1;
2384       }
2385     case tokenMdc:
2386       if (allow.param(SdParam::mdc)) {
2387         parm.type = SdParam::mdc;
2388         if (currentMarkup())
2389           currentMarkup()->addDelim(Syntax::dMDC);
2390         return 1;
2391       }
2392       sdParamInvalidToken(tokenMdc, allow);
2393       return 0;
2394     case tokenNameStart:
2395       {
2396         extendNameToken(syntax().namelen(), ParserMessages::nameLength);
2397         getCurrentToken(syntax().generalSubstTable(), parm.token);
2398         if (allow.param(SdParam::capacityName)) {
2399           if (sd().lookupCapacityName(parm.token, parm.capacityIndex)) {
2400             parm.type = SdParam::capacityName;
2401             if (currentMarkup())
2402               currentMarkup()->addName(currentInput());
2403             return 1;
2404           }
2405         }
2406         if (allow.param(SdParam::referenceReservedName)) {
2407           if (syntax().lookupReservedName(parm.token,
2408                                           &parm.reservedNameIndex)) {
2409             parm.type = SdParam::referenceReservedName;
2410             if (currentMarkup())
2411               currentMarkup()->addName(currentInput());
2412             return 1;
2413           }
2414         }
2415         if (allow.param(SdParam::generalDelimiterName)) {
2416           if (sd().lookupGeneralDelimiterName(parm.token,
2417                                               parm.delimGeneralIndex)) {
2418             parm.type = SdParam::generalDelimiterName;
2419             if (currentMarkup())
2420               currentMarkup()->addName(currentInput());
2421             return 1;
2422           }
2423         }
2424         if (allow.param(SdParam::quantityName)) {
2425           if (sd().lookupQuantityName(parm.token, parm.quantityIndex)) {
2426             parm.type = SdParam::quantityName;
2427             if (currentMarkup())
2428               currentMarkup()->addName(currentInput());
2429             return 1;
2430           }
2431         }
2432         for (int i = 0;; i++) {
2433           SdParam::Type t = allow.get(i);
2434           if (t == SdParam::invalid)
2435             break;
2436           if (t >= SdParam::reservedName) {
2437             Sd::ReservedName sdReservedName
2438               = Sd::ReservedName(t - SdParam::reservedName);
2439             if (parm.token == sd().reservedName(sdReservedName)) {
2440               parm.type = t;
2441               if (currentMarkup())
2442                 currentMarkup()->addSdReservedName(sdReservedName,
2443                                                   currentInput());
2444               return 1;
2445             }
2446           }
2447         }
2448         if (allow.param(SdParam::name)) {
2449           parm.type = SdParam::name;
2450           if (currentMarkup())
2451             currentMarkup()->addName(currentInput());
2452           return 1;
2453         }
2454         {
2455           message(ParserMessages::sdInvalidNameToken,
2456                   StringMessageArg(parm.token),
2457                   AllowedSdParamsMessageArg(allow, sdPointer()));
2458         }
2459         return 0;
2460       }
2461     case tokenDigit:
2462       if (allow.param(SdParam::number)) {
2463         extendNumber(syntax().namelen(), ParserMessages::numberLength);
2464         parm.type = SdParam::number;
2465         unsigned long n;
2466         if (!stringToNumber(currentInput()->currentTokenStart(),
2467                             currentInput()->currentTokenLength(),
2468                             n)
2469             || n > Number(-1)) {
2470           message(ParserMessages::numberTooBig,
2471                   StringMessageArg(currentToken()));
2472           parm.n = Number(-1);
2473         }
2474         else {
2475           if (currentMarkup())
2476             currentMarkup()->addNumber(currentInput());
2477           parm.n = Number(n);
2478         }
2479         Token token = getToken(mdMode);
2480         if (token == tokenNameStart)
2481           message(ParserMessages::psRequired);
2482         currentInput()->ungetToken();
2483         return 1;
2484       }
2485       sdParamInvalidToken(tokenDigit, allow);
2486       return 0;
2487     default:
2488       CANNOT_HAPPEN();
2489     }
2490   }
2491 }
2492
2493 // This is a separate function, because we might want SyntaxChar
2494 // to be bigger than Char.
2495
2496 Boolean Parser::parseSdParamLiteral(Boolean lita, String<SyntaxChar> &str)
2497 {
2498   Location loc(currentLocation());
2499   loc += 1;
2500   SdText text(loc, lita);       // first character of content
2501   str.resize(0);
2502   const unsigned refLitlen = Syntax::referenceQuantity(Syntax::qLITLEN);
2503
2504   Mode mode = lita ? sdplitaMode : sdplitMode;
2505   int done = 0;
2506   for (;;) {
2507     Token token = getToken(mode);
2508     switch (token) {
2509     case tokenEe:
2510       message(ParserMessages::literalLevel);
2511       return 0;
2512     case tokenUnrecognized:
2513       if (reportNonSgmlCharacter())
2514         break;
2515       if (options().errorSignificant)
2516         message(ParserMessages::sdLiteralSignificant,
2517                 StringMessageArg(currentToken()));
2518       text.addChar(currentChar(), currentLocation());
2519       break;
2520     case tokenCroDigit:
2521       {
2522         InputSource *in = currentInput();
2523         Location startLocation = currentLocation();
2524         in->discardInitial();
2525         extendNumber(syntax().namelen(), ParserMessages::numberLength);
2526         unsigned long n;
2527         Boolean valid;
2528         if (!stringToNumber(in->currentTokenStart(),
2529                             in->currentTokenLength(),
2530                             n)
2531             || n > syntaxCharMax) {
2532           message(ParserMessages::syntaxCharacterNumber,
2533                   StringMessageArg(currentToken()));
2534           valid = 0;
2535         }
2536         else
2537           valid = 1;
2538         Owner<Markup> markupPtr;
2539         if (eventsWanted().wantPrologMarkup()) {
2540           markupPtr = new Markup;
2541           markupPtr->addDelim(Syntax::dCRO);
2542           markupPtr->addNumber(in);
2543           switch (getToken(refMode)) {
2544           case tokenRefc:
2545             markupPtr->addDelim(Syntax::dREFC);
2546             break;
2547           case tokenRe:
2548             markupPtr->addRefEndRe();
2549             break;
2550           default:
2551             break;
2552           }
2553         }
2554         else
2555           (void)getToken(refMode);
2556         if (valid)
2557           text.addChar(SyntaxChar(n),
2558                        Location(new NumericCharRefOrigin(startLocation,
2559                                                          currentLocation().index()
2560                                                          + currentInput()->currentTokenLength()
2561                                                          - startLocation.index(),
2562                                                          markupPtr),
2563                                 0));
2564       }
2565       break;
2566     case tokenCroNameStart:
2567       if (!parseNamedCharRef())
2568         return 0;
2569       break;
2570     case tokenLit:
2571     case tokenLita:
2572       done = 1;
2573       break;
2574     case tokenPeroNameStart:
2575     case tokenPeroGrpo:
2576       message(ParserMessages::sdParameterEntity);
2577       {
2578         Location loc(currentLocation());
2579         const Char *p = currentInput()->currentTokenStart();
2580         for (size_t count = currentInput()->currentTokenLength();
2581              count > 0;
2582              count--) {
2583           text.addChar(*p++, loc);
2584           loc += 1;
2585         }
2586       }
2587       break;
2588     case tokenChar:
2589       if (text.string().size() > refLitlen
2590           && currentChar() == syntax().standardFunction(Syntax::fRE)) {
2591         message(ParserMessages::parameterLiteralLength, NumberMessageArg(refLitlen));
2592         // guess that the closing delimiter has been omitted
2593         message(ParserMessages::literalClosingDelimiter);
2594         return 0;
2595       }
2596       text.addChar(currentChar(), currentLocation());
2597       break;
2598     }
2599   if (done) break;
2600   }
2601   if (text.string().size() > refLitlen)
2602     message(ParserMessages::parameterLiteralLength,
2603             NumberMessageArg(refLitlen));
2604   
2605   str = text.string();
2606   if (currentMarkup())
2607     currentMarkup()->addSdLiteral(text);
2608   return 1;
2609 }
2610
2611 Boolean Parser::stringToNumber(const Char *s, size_t length,
2612                                unsigned long &result)
2613 {
2614   unsigned long n = 0;
2615   for (; length > 0; length--, s++) {
2616     int val = sd().digitWeight(*s);
2617     if (n <= ULONG_MAX/10 && (n *= 10) <= ULONG_MAX - val)
2618       n += val;
2619     else
2620       return 0;
2621   }
2622   result = n;
2623   return 1;
2624 }
2625
2626 void Parser::sdParamInvalidToken(Token token,
2627                                  const AllowedSdParams &allow)
2628 {
2629   message(ParserMessages::sdParamInvalidToken,
2630           TokenMessageArg(token, mdMode, syntaxPointer(), sdPointer()),
2631           AllowedSdParamsMessageArg(allow, sdPointer()));
2632 }
2633
2634 void Parser::sdParamConvertToLiteral(SdParam &parm)
2635 {
2636   if (parm.type == SdParam::number) {
2637     parm.type = SdParam::paramLiteral;
2638     parm.paramLiteralText.resize(1);
2639     parm.paramLiteralText[0] = parm.n;
2640   }
2641 }
2642
2643 AllowedSdParams::AllowedSdParams(SdParam::Type arg1, SdParam::Type arg2,
2644                                  SdParam::Type arg3, SdParam::Type arg4,
2645                                  SdParam::Type arg5, SdParam::Type arg6)
2646 {
2647   allow_[0] = arg1;
2648   allow_[1] = arg2;
2649   allow_[2] = arg3;
2650   allow_[3] = arg4;
2651   allow_[4] = arg5;
2652   allow_[5] = arg6;
2653 }
2654
2655 Boolean AllowedSdParams::param(SdParam::Type t) const
2656 {
2657   for (int i = 0; i < maxAllow && allow_[i] != SdParam::invalid; i++)
2658     if (t == allow_[i])
2659       return 1;
2660   return 0;
2661 }
2662
2663 SdParam::Type AllowedSdParams::get(int i) const
2664 {
2665   return i < 0 || i >= maxAllow ? SdParam::Type(SdParam::invalid) : allow_[i];
2666 }
2667
2668 AllowedSdParamsMessageArg::AllowedSdParamsMessageArg(
2669   const AllowedSdParams &allow,
2670   const ConstPtr<Sd> &sd)
2671 : allow_(allow), sd_(sd)
2672 {
2673 }
2674
2675 MessageArg *AllowedSdParamsMessageArg::copy() const
2676 {
2677   return new AllowedSdParamsMessageArg(*this);
2678 }
2679
2680 void AllowedSdParamsMessageArg::append(MessageBuilder &builder) const
2681 {
2682   for (int i = 0;; i++) {
2683     SdParam::Type type = allow_.get(i);
2684     if (type == SdParam::invalid)
2685       break;
2686     if (i != 0)
2687       builder.appendFragment(ParserMessages::listSep);
2688     switch (type) {
2689     case SdParam::eE:
2690       builder.appendFragment(ParserMessages::entityEnd);
2691       break;
2692     case SdParam::minimumLiteral:
2693       builder.appendFragment(ParserMessages::minimumLiteral);
2694       break;
2695     case SdParam::mdc:
2696       {
2697         builder.appendFragment(ParserMessages::delimStart);
2698         Char c = sd_->execToDoc('>');
2699         builder.appendChars(&c, 1);
2700         builder.appendFragment(ParserMessages::delimEnd);
2701       }
2702       break;
2703     case SdParam::number:
2704       builder.appendFragment(ParserMessages::number);
2705       break;
2706     case SdParam::name:
2707       builder.appendFragment(ParserMessages::name);
2708       break;
2709     case SdParam::paramLiteral:
2710       builder.appendFragment(ParserMessages::parameterLiteral);
2711       break;
2712     case SdParam::capacityName:
2713       builder.appendFragment(ParserMessages::capacityName);
2714       break;
2715     case SdParam::generalDelimiterName:
2716       builder.appendFragment(ParserMessages::generalDelimiteRoleName);
2717       break;
2718     case SdParam::referenceReservedName:
2719       builder.appendFragment(ParserMessages::referenceReservedName);
2720       break;
2721     case SdParam::quantityName:
2722       builder.appendFragment(ParserMessages::quantityName);
2723       break;
2724     case SdParam::ellipsis:
2725       {
2726         StringC str(sd_->execToDoc("..."));
2727         builder.appendChars(str.data(), str.size());
2728         break;
2729       }
2730     default:
2731       {
2732         StringC str(sd_->reservedName(type - SdParam::reservedName));
2733         builder.appendChars(str.data(), str.size());
2734         break;
2735       }
2736     }
2737   }
2738 }
2739
2740 SdBuilder::SdBuilder()
2741 : valid(1), externalSyntax(0)
2742 {
2743 }
2744
2745 void SdBuilder::addFormalError(const Location &location,
2746                                const MessageType1 &message,
2747                                const StringC &id)
2748 {
2749   formalErrorList.insert(new SdFormalError(location, message, id));
2750 }
2751
2752 SdFormalError::SdFormalError(const Location &location,
2753                              const MessageType1 &message,
2754                              const StringC &id)
2755 : location_(location),
2756   message_(&message),
2757   id_(id)
2758 {
2759 }
2760
2761 void SdFormalError::send(ParserState &parser)
2762 {
2763   parser.Messenger::setNextLocation(location_);
2764   parser.message(*message_, StringMessageArg(id_));
2765 }
2766
2767 CharSwitcher::CharSwitcher()
2768 {
2769 }
2770
2771 void CharSwitcher::addSwitch(WideChar from, WideChar to)
2772 {
2773   switches_.push_back(from);
2774   switches_.push_back(to);
2775   switchUsed_.push_back(0);
2776 }
2777
2778 SyntaxChar CharSwitcher::subst(WideChar c)
2779 {
2780   for (size_t i = 0; i < switches_.size(); i += 2)
2781     if (switches_[i] == c) {
2782       switchUsed_[i/2] = 1;
2783       return switches_[i + 1];
2784     }
2785   return c;
2786 }
2787
2788 size_t CharSwitcher::nSwitches() const
2789 {
2790   return switchUsed_.size();
2791 }
2792
2793 Boolean CharSwitcher::switchUsed(size_t i) const
2794 {
2795   return switchUsed_[i];
2796 }
2797
2798 WideChar CharSwitcher::switchFrom(size_t i) const
2799 {
2800   return switches_[i*2];
2801 }
2802
2803 WideChar CharSwitcher::switchTo(size_t i) const
2804 {
2805   return switches_[i*2 + 1];
2806 }
2807
2808 CharsetMessageArg::CharsetMessageArg(const ISet<WideChar> &set)
2809 : set_(set)
2810 {
2811 }
2812
2813 MessageArg *CharsetMessageArg::copy() const
2814 {
2815   return new CharsetMessageArg(*this);
2816 }
2817
2818 void CharsetMessageArg::append(MessageBuilder &builder) const
2819 {
2820   ISetIter<WideChar> iter(set_);
2821   WideChar min, max;
2822   Boolean first = 1;
2823   while (iter.next(min, max)) {
2824     if (first)
2825       first = 0;
2826     else
2827       builder.appendFragment(ParserMessages::listSep);
2828     builder.appendNumber(min);
2829     if (max != min) {
2830       builder.appendFragment(max == min + 1
2831                              ? ParserMessages::listSep
2832                              : ParserMessages::rangeSep);
2833       builder.appendNumber(max);
2834     }
2835   }
2836 }
2837
2838 #ifdef SP_NAMESPACE
2839 }
2840 #endif