Disable all code related to libXp
[oweals/cde.git] / cde / programs / dtinfo / DtMmdb / StyleSheet / DocParser.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*      Copyright (c) 1995 FUJITSU LIMITED      */
24 /*      All Rights Reserved                     */
25
26 /* $TOG: DocParser.C /main/16 1998/04/17 11:48:07 mgreess $ */
27 #ifdef DEBUG
28 #include "assert.h"
29 #endif
30 #include "Debug.h"
31 #include "StyleSheetExceptions.h"
32 #include "DocParser.h"
33 #include "Resolver.h"
34 #include "Element.h"
35 #include "AttributeList.h"
36
37 #define DATA_BUF_SIZ 4096
38
39 #if defined(SC3) || defined(__osf__)
40 static ostrstream& terminate(ostrstream& ost)
41 {
42     char* pstring = ost.str();
43     *(pstring + ost.pcount()) = '\0';
44
45     return ost;
46 }
47 #endif
48
49 DocParser::DocParser(Resolver &r)
50 : f_resolver(r),
51 #if defined(SC3) || defined(__osf__)
52   f_buffer(new char[DATA_BUF_SIZ]),
53   f_output(f_buffer, DATA_BUF_SIZ)
54 #else
55   f_streambuf(new stringbuf()),
56   f_output()
57 #endif
58 {
59 }
60
61 DocParser::~DocParser()
62 {
63 #if defined(SC3) || defined(__osf__)
64   if (f_buffer) delete[] f_buffer;
65 #else
66   // this causes a free memory read when f_output is deleted as part of this
67   // object...nothing we can do about it
68   delete f_streambuf ;
69 #endif
70 }
71
72 unsigned int
73 DocParser::parse(istream &input)
74 {
75    f_resolver.Begin();
76    unsigned int ok = rawParse(input);
77    f_resolver.End();
78    return ok;
79 }
80
81 unsigned int
82 DocParser::rawParse(istream &input)
83 {
84   string data;
85
86   input.unsetf(ios::skipws);
87
88   f_ignoring_element = 0 ;
89
90   switch(read_tag(input, f_output))
91     {
92     case StartTag:
93       {
94 #if defined(SC3) || defined(__osf__)
95         Symbol name(gElemSymTab->intern(terminate(f_output).str()));
96         f_output.rdbuf()->freeze(0);
97 #else
98         data = f_output.str().c_str();
99
100 /*
101 MESSAGE(cerr, "StartTag case:");
102 debug(cerr, f_output.str().size());
103 debug(cerr, data.c_str());
104 */
105
106         Symbol name(gElemSymTab->intern(data.c_str()));
107 #endif
108         process(input, f_output, name, 1, 1);
109       }
110       break;
111     case EndTag:
112     case AttributeSection:
113     case OliasAttribute:
114       throw(CASTDPUTEXCEPT docParserUnexpectedTag());
115       break;
116     case NoTag:
117       throw(CASTDPUDEXCEPT docParserUnexpectedData());
118       break;
119     }      
120   return 1;
121 }
122
123                 
124 void
125 update_last_seen_child_name(Symbol*& last_seen_child_name, unsigned int& child_relative_sibling_number, const Symbol& new_child_name)
126 {
127    if ( last_seen_child_name == 0 || 
128         !(*last_seen_child_name == Symbol(new_child_name)) 
129       ) 
130    {
131      delete last_seen_child_name ;
132      last_seen_child_name = new Symbol(new_child_name);
133      child_relative_sibling_number= 1;
134    } else
135      child_relative_sibling_number++;
136
137    return;
138 }
139
140 void
141 DocParser::process(istream &input, ostringstream &output,
142                    const Symbol &name,
143                    unsigned int sibling_number, unsigned int this_sibling_number)
144 {
145   ON_DEBUG(cerr << "process(" << name << ") -> " << sibling_number << endl);
146
147   Symbol* last_seen_child_name = 0; 
148             
149   unsigned int child_relative_sibling_number = 0;
150
151   unsigned int child = 1 ;      // sibling numbers for child elements 
152
153 #if !defined(SC3) && !defined(__osf__)
154   string pstring;
155 #endif
156   string data;
157
158   char c ;
159   while ((input >> c) && (c == '\n'));
160   input.putback(c);
161
162   if (input.eof())
163     throw(CASTDPUEEXCEPT docParserUnexpectedEof());
164
165   int ignore = 0 ;
166
167   mtry
168     {
169       // process whatever comes right after start tag 
170       TagType tt = read_tag(input, output);
171       switch (tt)
172         {
173         case StartTag:
174           {
175             ON_DEBUG(cerr << "beginElement" << endl);
176             // have to begin this element before processing child elements 
177             if (!f_ignoring_element)
178               {
179                 ignore = f_resolver.beginElement(new Element(name,
180                                                              sibling_number, 0,
181                                                              0,
182                                                              this_sibling_number)); 
183                 f_ignoring_element = ignore ;
184               }
185
186                
187 /////////////////////////////
188 // first child of this node
189 /////////////////////////////
190 #if defined(SC3) || defined(__osf__)
191             Symbol name(gElemSymTab->intern(terminate(f_output).str()));
192
193             update_last_seen_child_name(last_seen_child_name, 
194                                  child_relative_sibling_number, name);
195
196             f_output.rdbuf()->freeze(0);
197
198             process(input, output, name, child++, child_relative_sibling_number);
199 #else
200             data = f_output.str().c_str();
201 //#if !defined(SC3)  && !defined(__osf__)
202 //          data[f_output.str().size()] = '\0';
203 //#endif
204             Symbol name(gElemSymTab->intern(data.c_str()));
205             update_last_seen_child_name(last_seen_child_name, 
206                                  child_relative_sibling_number, name);
207
208             process(input, output, name,
209                     child++, child_relative_sibling_number);
210 #endif
211           }
212           break;
213         case EndTag:
214           // hit an end tag right after start tag 
215 #ifdef DEBUG
216           {
217 #if defined(SC3) || defined(__osf__)
218             data = terminate(f_output).str();
219             f_output.rdbuf()->freeze(0);
220 #else
221             data = f_output.str().c_str();
222 //#ifdef _IBMR2
223 //#if !defined(SC3)  && !defined(__osf__)
224 //          data[f_output.str().size()] = '\0';
225 //#endif
226 #endif
227             cerr << "EndTag: " << data.c_str() << endl;
228             assert(gElemSymTab->intern(data.c_str()) == name);
229           }
230 #endif
231
232 // this node
233           if (!f_ignoring_element)
234             {
235               int ignore = f_resolver.beginElement(new Element(name,
236                                                                sibling_number,
237                                                                0, 0, this_sibling_number)); 
238               if (!ignore)
239                 f_resolver.endElement(name);
240             }
241           return ;              // EXIT FUNCTION 
242           break;
243         case AttributeSection:
244           {
245 #if !defined(SC3) && \
246     !defined(__osf__) && \
247     !defined(_IBMR2) && \
248     !defined(__uxp__) && \
249     !defined(USL) && \
250     !defined(linux) && \
251     !defined(CSRG_BASED) && \
252     !defined(sun)
253             volatile
254 #endif
255             AttributeList *attrs = 0;
256 #if !defined(SC3) &&  \
257     !defined(__osf__) && \
258     !defined(_IBMR2) && \
259     !defined(__uxp__) && \
260     !defined(USL) && \
261     !defined(linux) && \
262     !defined(CSRG_BASED) && \
263     !defined(sun)
264             volatile
265 #endif
266             AttributeList *olias_attrs = 0;
267
268             mtry
269               {
270                 process_attributes(input, output, attrs, olias_attrs);
271
272                 if (!f_ignoring_element)
273                   {
274 //////////////////////////////
275 // this node with attributes
276 //////////////////////////////
277                     ignore = f_resolver.beginElement(new Element(name,
278                                                                  sibling_number,
279                                                                  attrs,
280                                                                  olias_attrs, 
281                                                                  this_sibling_number
282                                                         ));
283                     f_ignoring_element = ignore ;
284                   }
285               }
286             mcatch_any()
287               {
288 /*
289                 delete attrs ;
290                 delete olias_attrs ;
291 */
292                 attrs = 0 ;
293                 olias_attrs = 0 ;
294               }
295             end_try;
296           }
297           break;
298         case OliasAttribute:
299           throw(CASTDPUTEXCEPT docParserUnexpectedTag());
300           break;
301
302         case NoTag:
303           {
304             if (!f_ignoring_element)
305               {
306 // this node
307                 ignore = f_resolver.beginElement(new Element(name,
308                                                              sibling_number,
309                                                              0, 0, this_sibling_number)); 
310                 f_ignoring_element = ignore ;
311               }
312             // process data 
313             read_data(input, output);
314
315             if (!f_ignoring_element)
316               {
317                 //  the str() call seems to add the null byte to the stream
318                 //  and increment the pcount, so we must make sure it gets
319                 //  called first
320 #if defined(SC3) || defined(__osf__)
321                 char *pstring = terminate(f_output).str();
322                 int   size = f_output.pcount();
323                 f_resolver.data(pstring, size);
324                 f_output.rdbuf()->freeze(0);
325 #else
326                 pstring = f_output.str().c_str();
327                 int   size = pstring.size() + 1;
328                 f_resolver.data(pstring.c_str(), size);
329 #endif
330               }
331           }
332           break;
333         }
334       
335       while ((tt = read_tag(input, output)) != EndTag)
336         switch (tt)
337           {
338           case StartTag:
339             {
340 /////////////////////////////
341 // second child and beyond.
342 /////////////////////////////
343               data = f_output.str().c_str();
344 #if defined(SC3) || defined(__osf__)
345               f_output.rdbuf()->freeze(0);
346 #endif
347
348 /*
349 MESSAGE(cerr, "StartTag case2");
350 debug(cerr, data);
351 debug(cerr, f_output.str().size());
352 */
353
354               Symbol name(gElemSymTab->intern(data.c_str()));
355               update_last_seen_child_name(last_seen_child_name, 
356                                  child_relative_sibling_number, name);
357
358               process(input, output, name, child++, child_relative_sibling_number);
359             }
360             break;
361           case EndTag:          // should never get this 
362             break;
363             // we have already processed these for this tag
364           case AttributeSection:
365           case OliasAttribute: 
366             throw(CASTDPUTEXCEPT docParserUnexpectedTag());
367             break;
368           case NoTag:
369             {
370               read_data(input, output);
371
372               if (!f_ignoring_element)
373                 {
374                   //  the str() call seems to add the null byte to the stream
375                   //  and increment the pcount, so we must make sure it gets
376                   //  called first
377 #if defined(SC3) || defined(__osf__)
378                   char *pstring = f_output.str();
379                   int   size = f_output.pcount();
380                   *(pstring + size) = 0;
381                   f_resolver.data(pstring, size);
382                   f_output.rdbuf()->freeze(0);
383 #else
384                   pstring = f_output.str().c_str();
385                   int   size = pstring.size() + 1;
386                   f_resolver.data(pstring.c_str(), size);
387 #endif
388                 }
389             }
390           }
391 #ifdef DEBUG
392       {
393 #if defined(SC3) || defined(__osf__)
394         data = terminate(f_output).str();
395         f_output.rdbuf()->freeze(0);
396 #else
397         data = f_output.str().c_str();
398 #endif
399         cerr << "EndTag: " << data.c_str() << endl;
400         assert(gElemSymTab->intern(data.c_str()) == name);
401       }
402 #endif
403       // hit end tag, end processing
404       if (!f_ignoring_element)
405         f_resolver.endElement(name);
406
407       // if we set ignore flag, unset it 
408       if (ignore)
409         f_ignoring_element = 0;
410     }
411   mcatch_any()
412     {
413       rethrow;
414     }
415   end_try;
416   ON_DEBUG(cerr << "exit process: " << name << endl);
417   delete last_seen_child_name; 
418 }
419
420
421 void
422 DocParser::process_attributes(istream &input, ostringstream &output,
423                               AttributeList *&attrs,
424                               AttributeList *&olias_attrs)
425 {
426 #if !defined(SC3) && !defined(__osf__)
427   string theData;
428 #endif
429   TagType tt ;
430
431   Attribute* newAttribute = 0;
432
433   AttributeList* orig_attrs = attrs;
434   AttributeList* orig_olias_attrs = olias_attrs;
435
436   mtry {
437      while ((tt = read_tag(input,output)) != NoTag)
438        {
439          switch (tt)
440         {
441         case StartTag:
442           {
443 #if !defined(SC3) && !defined(__osf__)
444           theData = f_output.str().c_str();
445 #endif
446           if (!attrs)
447             attrs = new AttributeList ;
448
449           newAttribute = 
450                 process_attribute(input, output,
451 #if defined(SC3) || defined(__osf__)
452                                   gSymTab->intern(terminate(f_output).str()),
453                                   gSymTab->intern(f_streambuf->str()),
454 #else
455                                   gSymTab->intern(theData.c_str()),
456 #endif
457                                   StartTag
458                                  );
459           attrs->add(newAttribute);
460           break;
461           }
462         case EndTag:
463           return ;              // EXIT FUNCTION
464    
465         case AttributeSection:
466           throw(CASTDPUTEXCEPT docParserUnexpectedTag());
467           break;
468         case OliasAttribute:
469 #if !defined(SC3) && !defined(__osf__)
470           theData = f_output.str().c_str();
471 #endif
472           // mirrors attribute 
473           if (!olias_attrs)
474             olias_attrs = new AttributeList ;
475
476           newAttribute = 
477                 process_attribute(input, output,
478 #if defined(SC3) || defined(__osf__)
479                                   gSymTab->intern(terminate(f_output).str()),
480                                   gSymTab->intern(f_streambuf->str()),
481 #else
482                                   gSymTab->intern(theData.c_str()),
483 #endif
484                                   OliasAttribute
485                                  );
486
487           olias_attrs->add(newAttribute);
488           break;
489         case NoTag:
490           throw(CASTDPUDEXCEPT docParserUnexpectedData());
491           break;
492         }
493        }
494    }
495    mcatch_any()
496    {
497      delete newAttribute;
498
499      if ( orig_attrs == 0 ) {
500         delete attrs;
501         attrs = 0;
502      }
503
504      if ( orig_olias_attrs == 0 ) {
505         delete olias_attrs;
506         olias_attrs = 0;
507      }
508
509      rethrow;
510    }
511    end_try;
512 }
513
514 Attribute *
515 DocParser::process_attribute(istream &input, ostringstream &output,
516                              const Symbol &name, TagType tt)
517 {
518   string data;
519
520   //ON_DEBUG(cerr << "process_attribute: " << name << endl);
521
522 // If the attribute is OLIAS internal, we use DocParser's 
523 // read_data(). This is to prevent the attribte value 
524 // from change in a call to specific renderer engine's 
525 // read_data().
526 //
527 // Example: LoutDocparser::read_data() quotes any '.' char
528 // which changes the graphic locator value if the element
529 // is OLIAS internal attribute #GRAPHIC.
530
531   if ( tt == OliasAttribute ) {
532     DocParser::read_data(input, output);
533   } else 
534     (void)read_data(input, output);
535 #if defined(SC3) || defined(__osf__)
536   char *data = f_output.str();
537   *(data + f_output.pcount()) = 0;
538   f_output.rdbuf()->freeze(0);
539   Attribute *attr = new Attribute(name, strdup(data));
540 #else
541   data = f_output.str().c_str();
542   Attribute *attr = new Attribute(name, strdup(data.c_str()));
543 #endif
544
545   switch (read_tag(input, output))
546     {
547     case StartTag:
548     case AttributeSection:
549     case OliasAttribute:
550       delete attr ;
551       throw(CASTDPUTEXCEPT docParserUnexpectedTag());
552       break;
553     case NoTag:
554       delete attr;
555       throw(CASTDPUDEXCEPT docParserUnexpectedData());
556       break;
557     case EndTag:
558       break;
559     }
560
561   return attr ;
562   
563 }
564
565
566 DocParser::TagType
567 DocParser::read_tag(istream &input, ostringstream &output)
568 {
569   output.seekp(streampos(0));
570
571   TagType tt = StartTag;
572
573   char c ;
574
575   // strip newlines before/after tags
576   while ((input >> c) && (c == '\n'));
577   if (input.eof())
578     throw(CASTDPUEEXCEPT docParserUnexpectedEof());
579
580   if (c != '<')
581     {
582       input.putback(c);
583       return NoTag;
584     }
585
586
587   input >> c ;
588
589   switch (c)
590     {
591     case '/':
592       tt = EndTag ;
593       break;
594     case '#':
595       input >> c;
596       if (c == '>')
597         return AttributeSection ; // EXIT 
598       else
599         {
600           tt = OliasAttribute ;
601           output << c;          // keep char we just read 
602         }
603       break;
604     case '>':
605       throw(CASTUTEXCEPT unknownTagException());
606       // NOT REACHED 
607       break;
608     default:
609       output << c ;             // keep char we just read 
610       break;
611     }
612
613
614   // get (remainder of) tag name 
615   while ((input >> c) && (c != '>'))
616     output << c ;
617   output << ends;
618
619   return tt ;
620 }
621
622
623 void
624 DocParser::read_data(istream &input, ostringstream &output)
625 {
626   char c ;
627
628   output.seekp(streampos(0));
629
630   while ((input >> c) && (c != '<'))
631     {
632       // handle entities 
633       if (c == '&')
634         {
635           char tmpbuf[64];
636           unsigned int tmplen = 0;
637           while ((input >> c ) && (c != ';'))
638             {
639               tmpbuf[tmplen++] = c ;
640               if (tmplen > 63)
641                 {
642                   cerr << "Temp Buf overflow (ampersand problem)" << endl;
643                   throw(CASTEXCEPT Exception());
644                 }
645             }
646           if (input.eof())
647             throw(CASTDPUEEXCEPT docParserUnexpectedEof());
648             
649           tmpbuf[tmplen] = 0 ;
650
651 #ifdef ENTITY_DEBUG
652           cerr << "Entity: " << tmpbuf << endl;
653 #endif
654
655           if ((!strcmp(tmpbuf, "hardreturn")) ||
656               (!strcmp(tmpbuf, "lnfeed")))
657             c = '\n';
658           else
659             if ((!strcmp(tmpbuf, "lang")) ||
660                 (!strcmp(tmpbuf, "lt")))
661               c = '<' ;
662             else
663               if (!strcmp(tmpbuf, "amp"))
664                 c = '&' ;
665               else
666                 if (!strcmp(tmpbuf, "nbsp")) // non-break space 
667                   c = (char)0xA0 ;
668                 else
669                   c = ' ';
670
671         }
672
673       output << c;
674     }
675
676   output << ends;
677
678   // can never run out of input while reading data, tags must be balanced
679   if (input.eof())
680     throw(CASTDPUEEXCEPT docParserUnexpectedEof());
681             
682   input.putback(c);
683
684 }