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