dsdm: Change to ANSI function definitions
[oweals/cde.git] / cde / programs / nsgmls / parseCommon.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: parseCommon.C /main/1 1996/07/29 17:09:12 cde-hp $ */
24 // Copyright (c) 1994 James Clark
25 // See the file COPYING for copying permission.
26
27 #include "splib.h"
28 #include "Parser.h"
29 #include "token.h"
30 #include "MessageArg.h"
31 #include "ParserMessages.h"
32 #include "constant.h"
33 #include "NumericCharRefOrigin.h"
34
35 #ifdef SP_NAMESPACE
36 namespace SP_NAMESPACE {
37 #endif
38
39 Boolean Parser::parseProcessingInstruction()
40 {
41   currentInput()->startToken();
42   Location location(currentLocation());
43   StringC buf;
44   for (;;) {
45     Token token = getToken(piMode);
46     if (token == tokenPic)
47       break;
48     switch (token) {
49     case tokenEe:
50       message(ParserMessages::processingInstructionEntityEnd);
51       return 0;
52     case tokenUnrecognized:
53       reportNonSgmlCharacter();
54       // fall through
55     case tokenChar:
56       buf += *currentInput()->currentTokenStart();
57       if (buf.size()/2 > syntax().pilen()) {
58         message(ParserMessages::processingInstructionLength,
59                 NumberMessageArg(syntax().pilen()));
60         message(ParserMessages::processingInstructionClose);
61         return 0;
62       }
63       break;
64     }
65   }
66   if (buf.size() > syntax().pilen())
67     message(ParserMessages::processingInstructionLength,
68             NumberMessageArg(syntax().pilen()));
69   noteMarkup();
70   eventHandler().pi(new (eventAllocator()) ImmediatePiEvent(buf, location));
71   return 1;
72 }
73
74 Boolean Parser::parseLiteral(Mode litMode,
75                              Mode liteMode,
76                              size_t maxLength,
77                              const MessageType1 &tooLongMessage,
78                              unsigned flags,
79                              Text &text)
80 {
81   unsigned startLevel = inputLevel();
82   Mode currentMode = litMode;
83   // If the literal gets to be longer than this, then we assume
84   // that the closing delimiter has been omitted if we're at the end
85   // of a line and at the starting input level.
86   size_t reallyMaxLength = (maxLength > size_t(-1)/2
87                             ? size_t(-1)
88                             : maxLength * 2);
89   text.clear();
90   Location startLoc(currentLocation());
91   if (flags & literalDelimInfo)
92     text.addStartDelim(currentLocation());
93   for (;;) {
94     int done = 0;
95     Token token = getToken(currentMode);
96     switch (token) {
97     case tokenEe:
98       if (inputLevel() == startLevel) {
99         message(ParserMessages::literalLevel);
100         return 0;
101       }
102       text.addEntityEnd(currentLocation());
103       popInputStack();
104       if (inputLevel() == startLevel)
105         currentMode = litMode;
106       break;
107     case tokenUnrecognized:
108       if (reportNonSgmlCharacter())
109         break;
110       message(ParserMessages::literalMinimumData,
111               StringMessageArg(currentToken()));
112       break;
113     case tokenRs:
114       text.ignoreChar(currentChar(), currentLocation());
115       break;
116     case tokenRe:
117       if (text.size() > reallyMaxLength && inputLevel() == startLevel) {
118 #if 0
119         message(tooLongMessage, NumberMessageArg(maxLength));
120 #endif
121         // guess that the closing delimiter has been omitted
122         Messenger::setNextLocation(startLoc);
123         message(ParserMessages::literalClosingDelimiter);
124         return 0;
125       }
126       // fall through
127     case tokenSepchar:
128       if ((flags & literalSingleSpace)
129           && (text.size() == 0 || text.lastChar() == syntax().space()))
130         text.ignoreChar(currentChar(), currentLocation());
131       else
132         text.addChar(syntax().space(),
133                      Location(new ReplacementOrigin(currentLocation(),
134                                                     currentChar()),
135                               0));
136       break;
137     case tokenSpace:
138       if ((flags & literalSingleSpace)
139           && (text.size() == 0 || text.lastChar() == syntax().space()))
140         text.ignoreChar(currentChar(), currentLocation());
141       else
142         text.addChar(currentChar(), currentLocation());
143       break;
144     case tokenCroDigit:
145       {
146         Char c;
147         Location loc;
148         if (!parseNumericCharRef(c, loc))
149           return 0;
150         if (flags & literalDataTag) {
151           if (!syntax().isSgmlChar(c))
152             message(ParserMessages::dataTagPatternNonSgml);
153           else if (syntax().charSet(Syntax::functionChar)->contains(c))
154             message(ParserMessages::dataTagPatternFunction);
155         }
156         if ((flags & literalSingleSpace)
157             && c == syntax().space()
158             && (text.size() == 0 || text.lastChar() == syntax().space()))
159           text.ignoreChar(c, loc);
160         else
161           text.addChar(c, loc);
162       }
163       break;
164     case tokenCroNameStart:
165       if (!parseNamedCharRef())
166         return 0;
167       break;
168     case tokenEroGrpo:
169       message(inInstance() ? ParserMessages::eroGrpoStartTag : ParserMessages::eroGrpoProlog);
170       break;
171     case tokenLit:
172     case tokenLita:
173       if (flags & literalDelimInfo)
174         text.addEndDelim(currentLocation(), token == tokenLita);
175       done = 1;
176       break;
177     case tokenEroNameStart:
178     case tokenPeroNameStart:
179       {
180         ConstPtr<Entity> entity;
181         Ptr<EntityOrigin> origin;
182         if (!parseEntityReference(token == tokenPeroNameStart,
183                                   (flags & literalNoProcess) ? 2 : 0,
184                                   entity, origin))
185           return 0;
186         if (!entity.isNull())
187           entity->litReference(text, *this, origin,
188                                (flags & literalSingleSpace) != 0);
189         if (inputLevel() > startLevel)
190           currentMode = liteMode;
191       }
192       break;
193     case tokenPeroGrpo:
194       message(ParserMessages::peroGrpoProlog);
195       break;
196     case tokenChar:
197       if (text.size() > reallyMaxLength && inputLevel() == startLevel
198           && currentChar() == syntax().standardFunction(Syntax::fRE)) {
199 #if 0
200         message(tooLongMessage, NumberMessageArg(maxLength));
201 #endif
202         // guess that the closing delimiter has been omitted
203         Messenger::setNextLocation(startLoc);
204         message(ParserMessages::literalClosingDelimiter);
205         return 0;
206       }
207       text.addChar(currentChar(), currentLocation());
208       break;
209     }
210     if (done) break;
211   }
212   if ((flags & literalSingleSpace)
213       && text.size() > 0
214       && text.lastChar() == syntax().space())
215     text.ignoreLastChar();
216   if (text.size() > maxLength) {
217     switch (litMode) {
218     case alitMode:
219     case alitaMode:
220     case talitMode:
221     case talitaMode:
222       if (AttributeValue::handleAsUnterminated(text, *this))
223         return 0;
224     default:
225       break;
226     }
227     message(tooLongMessage, NumberMessageArg(maxLength));
228   }
229   return 1;
230 }
231
232 Boolean Parser::parseNamedCharRef()
233 {
234   InputSource *in = currentInput();
235   Index startIndex = currentLocation().index();
236   in->discardInitial();
237   extendNameToken(syntax().namelen(), ParserMessages::nameLength);
238   Char c;
239   Boolean valid;
240   StringC name;
241   getCurrentToken(syntax().generalSubstTable(), name);
242   if (!syntax().lookupFunctionChar(name, &c)) {
243     message(ParserMessages::functionName, StringMessageArg(name));
244     valid = 0;
245   }
246   else {
247     valid = 1;
248     if (wantMarkup())
249       getCurrentToken(name);    // the original name
250   }
251   NamedCharRef::RefEndType refEndType;
252   switch (getToken(refMode)) {
253   case tokenRefc:
254     refEndType = NamedCharRef::endRefc;
255     break;
256   case tokenRe:
257     refEndType = NamedCharRef::endRE;
258     break;
259   default:
260     refEndType = NamedCharRef::endOmitted;
261     break;
262   }
263   in->startToken();
264   if (valid)
265     in->pushCharRef(c, NamedCharRef(startIndex, refEndType, name));
266   return 1;
267 }
268
269 Boolean Parser::parseNumericCharRef(Char &ch, Location &loc)
270 {
271   InputSource *in = currentInput();
272   Location startLocation = currentLocation();
273   in->discardInitial();
274   extendNumber(syntax().namelen(), ParserMessages::numberLength);
275   Boolean valid = 1;
276   Char c = 0;
277   const Char *lim = in->currentTokenEnd();
278   for (const Char *p = in->currentTokenStart(); p < lim; p++) {
279     int val = sd().digitWeight(*p);
280     if (c <= charMax/10 && (c *= 10) <= charMax - val)
281       c += val;
282     else {
283       message(ParserMessages::characterNumber, StringMessageArg(currentToken()));
284       valid = 0;
285       break;
286     }
287   }
288   if (valid && !sd().docCharsetDecl().charDeclared(c)) {
289     valid = 0;
290     message(ParserMessages::characterNumber, StringMessageArg(currentToken()));
291   }
292   Owner<Markup> markupPtr;
293   if (wantMarkup()) {
294     markupPtr = new Markup;
295     markupPtr->addDelim(Syntax::dCRO);
296     markupPtr->addNumber(in);
297     switch (getToken(refMode)) {
298     case tokenRefc:
299       markupPtr->addDelim(Syntax::dREFC);
300       break;
301     case tokenRe:
302       markupPtr->addRefEndRe();
303       break;
304     default:
305       break;
306     }
307   }
308   else
309     (void)getToken(refMode);
310   if (valid) {
311     ch = c;
312     loc = Location(new NumericCharRefOrigin(startLocation,
313                                             currentLocation().index()
314                                             + currentInput()->currentTokenLength()
315                                             - startLocation.index(),
316                                             markupPtr),
317                    0);
318   }
319   return valid;
320 }
321
322 // ignoreLevel: 0 means don't ignore;
323 // 1 means parse name group and ignore if inactive
324 // 2 means ignore
325
326 Boolean Parser::parseEntityReference(Boolean isParameter,
327                                      int ignoreLevel,
328                                      ConstPtr<Entity> &entity,
329                                      Ptr<EntityOrigin> &origin)
330 {
331   InputSource *in = currentInput();
332   Location startLocation(in->currentLocation());
333   Owner<Markup> markupPtr;
334   if (wantMarkup()) {
335     markupPtr = new Markup;
336     markupPtr->addDelim(isParameter ? Syntax::dPERO : Syntax::dERO);
337   }
338   if (ignoreLevel == 1) {
339     Markup savedMarkup;
340     Markup *savedCurrentMarkup = currentMarkup();
341     if (savedCurrentMarkup)
342       savedCurrentMarkup->swap(savedMarkup);
343     Location savedMarkupLocation(markupLocation());
344     startMarkup(markupPtr != 0, startLocation);
345     if (markupPtr) {
346       markupPtr->addDelim(Syntax::dGRPO);
347       markupPtr->swap(*currentMarkup());
348     }
349     Boolean ignore;
350     if (!parseEntityReferenceNameGroup(ignore))
351       return 0;
352     if (markupPtr)
353       currentMarkup()->swap(*markupPtr);
354     startMarkup(savedCurrentMarkup != 0, savedMarkupLocation);
355     if (savedCurrentMarkup)
356       savedMarkup.swap(*currentMarkup());
357     if (!ignore)
358       ignoreLevel = 0;
359     in->startToken();
360     Xchar c = in->tokenChar(messenger());
361     if (!syntax().isNameStartCharacter(c)) {
362       message(ParserMessages::entityReferenceMissingName);
363       return 0;
364     }
365   }
366   in->discardInitial();
367   if (isParameter)
368     extendNameToken(syntax().penamelen(), ParserMessages::parameterEntityNameLength);
369   else
370     extendNameToken(syntax().namelen(), ParserMessages::nameLength);
371   StringC &name = nameBuffer();
372   getCurrentToken(syntax().entitySubstTable(), name);
373   if (ignoreLevel)
374     entity = new IgnoredEntity(name,
375                                isParameter
376                                ? Entity::parameterEntity
377                                : Entity::generalEntity);
378   else {
379     entity = lookupEntity(isParameter, name, startLocation, 1);
380     if (entity.isNull()) {
381       if (haveApplicableDtd())
382         message(isParameter
383                 ? ParserMessages::parameterEntityUndefined
384                 : ParserMessages::entityUndefined,
385                 StringMessageArg(name));
386       else
387         message(ParserMessages::entityApplicableDtd);
388     }
389     else if (entity->defaulted() && options().warnDefaultEntityReference)
390       message(ParserMessages::defaultEntityReference, StringMessageArg(name));
391   }
392   if (markupPtr) {
393     markupPtr->addName(in);
394     switch (getToken(refMode)) {
395     case tokenRefc:
396       markupPtr->addDelim(Syntax::dREFC);
397       break;
398     case tokenRe:
399       markupPtr->addRefEndRe();
400       break;
401     default:
402       break;
403     }
404   }
405   else
406     (void)getToken(refMode);
407   if (!entity.isNull())
408     origin = new (internalAllocator())
409                EntityOrigin(entity, startLocation,
410                             currentLocation().index()
411                             + currentInput()->currentTokenLength()
412                             - startLocation.index(),
413                             markupPtr);
414   else
415     origin = (EntityOrigin *)0;
416   return 1;
417 }
418
419 Boolean Parser::parseComment(Mode mode)
420 {
421   Location startLoc(currentLocation());
422   Markup *markup = currentMarkup();
423   if (markup)
424     markup->addCommentStart();
425   Token token;
426   while ((token = getToken(mode)) != tokenCom)
427     switch (token) {
428     case tokenUnrecognized:
429       if (!reportNonSgmlCharacter())
430         message(ParserMessages::sdCommentSignificant,
431                 StringMessageArg(currentToken()));
432       break;
433     case tokenEe:
434       message(ParserMessages::commentEntityEnd, startLoc);
435       return 0;
436     default:
437       if (markup)
438         markup->addCommentChar(currentChar());
439       break;
440     }
441   return 1;
442 }
443
444 void Parser::extendNameToken(size_t maxLength,
445                              const MessageType1 &tooLongMessage)
446 {
447   InputSource *in = currentInput();
448   size_t length = in->currentTokenLength();
449   const Syntax &syn = syntax();
450   while (syn.isNameCharacter(in->tokenChar(messenger())))
451     length++;
452   if (length > maxLength)
453     message(tooLongMessage, NumberMessageArg(maxLength));
454   in->endToken(length);
455 }
456
457
458 void Parser::extendNumber(size_t maxLength, const MessageType1 &tooLongMessage)
459 {
460   InputSource *in = currentInput();
461   size_t length = in->currentTokenLength();
462   while (syntax().isDigit(in->tokenChar(messenger())))
463     length++;
464   if (length > maxLength)
465     message(tooLongMessage, NumberMessageArg(maxLength));
466   in->endToken(length);
467 }
468
469 Boolean Parser::reportNonSgmlCharacter()
470 {
471   Char c = getChar();
472   if (!syntax().isSgmlChar(c)) {
473     message(ParserMessages::nonSgmlCharacter, NumberMessageArg(c));
474     return 1;
475   }
476   return 0;
477 }
478
479 void Parser::extendS()
480 {
481   InputSource *in = currentInput();
482   size_t length = in->currentTokenLength();
483   while (syntax().isS(in->tokenChar(messenger())))
484     length++;
485   in->endToken(length);
486 }
487
488 #ifdef SP_NAMESPACE
489 }
490 #endif