Remove Unixware and openserver support
[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 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 /*      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), f_ignoring_element(0),
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(linux) && \
249     !defined(CSRG_BASED) && \
250     !defined(sun)
251             volatile
252 #endif
253             AttributeList *attrs = 0;
254 #if !defined(SC3) &&  \
255     !defined(__osf__) && \
256     !defined(_IBMR2) && \
257     !defined(linux) && \
258     !defined(CSRG_BASED) && \
259     !defined(sun)
260             volatile
261 #endif
262             AttributeList *olias_attrs = 0;
263
264             mtry
265               {
266                 process_attributes(input, output, attrs, olias_attrs);
267
268                 if (!f_ignoring_element)
269                   {
270 //////////////////////////////
271 // this node with attributes
272 //////////////////////////////
273                     ignore = f_resolver.beginElement(new Element(name,
274                                                                  sibling_number,
275                                                                  attrs,
276                                                                  olias_attrs, 
277                                                                  this_sibling_number
278                                                         ));
279                     f_ignoring_element = ignore ;
280                   }
281               }
282             mcatch_any()
283               {
284 /*
285                 delete attrs ;
286                 delete olias_attrs ;
287 */
288                 attrs = 0 ;
289                 olias_attrs = 0 ;
290               }
291             end_try;
292           }
293           break;
294         case OliasAttribute:
295           throw(CASTDPUTEXCEPT docParserUnexpectedTag());
296           break;
297
298         case NoTag:
299           {
300             if (!f_ignoring_element)
301               {
302 // this node
303                 ignore = f_resolver.beginElement(new Element(name,
304                                                              sibling_number,
305                                                              0, 0, this_sibling_number)); 
306                 f_ignoring_element = ignore ;
307               }
308             // process data 
309             read_data(input, output);
310
311             if (!f_ignoring_element)
312               {
313                 //  the str() call seems to add the null byte to the stream
314                 //  and increment the pcount, so we must make sure it gets
315                 //  called first
316 #if defined(SC3) || defined(__osf__)
317                 char *pstring = terminate(f_output).str();
318                 int   size = f_output.pcount();
319                 f_resolver.data(pstring, size);
320                 f_output.rdbuf()->freeze(0);
321 #else
322                 pstring = f_output.str().c_str();
323                 int   size = pstring.size() + 1;
324                 f_resolver.data(pstring.c_str(), size);
325 #endif
326               }
327           }
328           break;
329         }
330       
331       while ((tt = read_tag(input, output)) != EndTag)
332         switch (tt)
333           {
334           case StartTag:
335             {
336 /////////////////////////////
337 // second child and beyond.
338 /////////////////////////////
339               data = f_output.str().c_str();
340 #if defined(SC3) || defined(__osf__)
341               f_output.rdbuf()->freeze(0);
342 #endif
343
344 /*
345 MESSAGE(cerr, "StartTag case2");
346 debug(cerr, data);
347 debug(cerr, f_output.str().size());
348 */
349
350               Symbol name(gElemSymTab->intern(data.c_str()));
351               update_last_seen_child_name(last_seen_child_name, 
352                                  child_relative_sibling_number, name);
353
354               process(input, output, name, child++, child_relative_sibling_number);
355             }
356             break;
357           case EndTag:          // should never get this 
358             break;
359             // we have already processed these for this tag
360           case AttributeSection:
361           case OliasAttribute: 
362             throw(CASTDPUTEXCEPT docParserUnexpectedTag());
363             break;
364           case NoTag:
365             {
366               read_data(input, output);
367
368               if (!f_ignoring_element)
369                 {
370                   //  the str() call seems to add the null byte to the stream
371                   //  and increment the pcount, so we must make sure it gets
372                   //  called first
373 #if defined(SC3) || defined(__osf__)
374                   char *pstring = f_output.str();
375                   int   size = f_output.pcount();
376                   *(pstring + size) = 0;
377                   f_resolver.data(pstring, size);
378                   f_output.rdbuf()->freeze(0);
379 #else
380                   pstring = f_output.str().c_str();
381                   int   size = pstring.size() + 1;
382                   f_resolver.data(pstring.c_str(), size);
383 #endif
384                 }
385             }
386           }
387 #ifdef DEBUG
388       {
389 #if defined(SC3) || defined(__osf__)
390         data = terminate(f_output).str();
391         f_output.rdbuf()->freeze(0);
392 #else
393         data = f_output.str().c_str();
394 #endif
395         cerr << "EndTag: " << data.c_str() << endl;
396         assert(gElemSymTab->intern(data.c_str()) == name);
397       }
398 #endif
399       // hit end tag, end processing
400       if (!f_ignoring_element)
401         f_resolver.endElement(name);
402
403       // if we set ignore flag, unset it 
404       if (ignore)
405         f_ignoring_element = 0;
406     }
407   mcatch_any()
408     {
409       rethrow;
410     }
411   end_try;
412   ON_DEBUG(cerr << "exit process: " << name << endl);
413   delete last_seen_child_name; 
414 }
415
416
417 void
418 DocParser::process_attributes(istream &input, ostringstream &output,
419                               AttributeList *&attrs,
420                               AttributeList *&olias_attrs)
421 {
422 #if !defined(SC3) && !defined(__osf__)
423   string theData;
424 #endif
425   TagType tt ;
426
427   Attribute* newAttribute = 0;
428
429   AttributeList* orig_attrs = attrs;
430   AttributeList* orig_olias_attrs = olias_attrs;
431
432   mtry {
433      while ((tt = read_tag(input,output)) != NoTag)
434        {
435          switch (tt)
436         {
437         case StartTag:
438           {
439 #if !defined(SC3) && !defined(__osf__)
440           theData = f_output.str().c_str();
441 #endif
442           if (!attrs)
443             attrs = new AttributeList ;
444
445           newAttribute = 
446                 process_attribute(input, output,
447 #if defined(SC3) || defined(__osf__)
448                                   gSymTab->intern(terminate(f_output).str()),
449                                   gSymTab->intern(f_streambuf->str()),
450 #else
451                                   gSymTab->intern(theData.c_str()),
452 #endif
453                                   StartTag
454                                  );
455           attrs->add(newAttribute);
456           break;
457           }
458         case EndTag:
459           return ;              // EXIT FUNCTION
460    
461         case AttributeSection:
462           throw(CASTDPUTEXCEPT docParserUnexpectedTag());
463           break;
464         case OliasAttribute:
465 #if !defined(SC3) && !defined(__osf__)
466           theData = f_output.str().c_str();
467 #endif
468           // mirrors attribute 
469           if (!olias_attrs)
470             olias_attrs = new AttributeList ;
471
472           newAttribute = 
473                 process_attribute(input, output,
474 #if defined(SC3) || defined(__osf__)
475                                   gSymTab->intern(terminate(f_output).str()),
476                                   gSymTab->intern(f_streambuf->str()),
477 #else
478                                   gSymTab->intern(theData.c_str()),
479 #endif
480                                   OliasAttribute
481                                  );
482
483           olias_attrs->add(newAttribute);
484           break;
485         case NoTag:
486           throw(CASTDPUDEXCEPT docParserUnexpectedData());
487           break;
488         }
489        }
490    }
491    mcatch_any()
492    {
493      delete newAttribute;
494
495      if ( orig_attrs == 0 ) {
496         delete attrs;
497         attrs = 0;
498      }
499
500      if ( orig_olias_attrs == 0 ) {
501         delete olias_attrs;
502         olias_attrs = 0;
503      }
504
505      rethrow;
506    }
507    end_try;
508 }
509
510 Attribute *
511 DocParser::process_attribute(istream &input, ostringstream &output,
512                              const Symbol &name, TagType tt)
513 {
514   string data;
515
516   //ON_DEBUG(cerr << "process_attribute: " << name << endl);
517
518 // If the attribute is OLIAS internal, we use DocParser's 
519 // read_data(). This is to prevent the attribte value 
520 // from change in a call to specific renderer engine's 
521 // read_data().
522 //
523 // Example: LoutDocparser::read_data() quotes any '.' char
524 // which changes the graphic locator value if the element
525 // is OLIAS internal attribute #GRAPHIC.
526
527   if ( tt == OliasAttribute ) {
528     DocParser::read_data(input, output);
529   } else 
530     (void)read_data(input, output);
531 #if defined(SC3) || defined(__osf__)
532   char *data = f_output.str();
533   *(data + f_output.pcount()) = 0;
534   f_output.rdbuf()->freeze(0);
535   Attribute *attr = new Attribute(name, strdup(data));
536 #else
537   data = f_output.str().c_str();
538   Attribute *attr = new Attribute(name, strdup(data.c_str()));
539 #endif
540
541   switch (read_tag(input, output))
542     {
543     case StartTag:
544     case AttributeSection:
545     case OliasAttribute:
546       delete attr ;
547       throw(CASTDPUTEXCEPT docParserUnexpectedTag());
548       break;
549     case NoTag:
550       delete attr;
551       throw(CASTDPUDEXCEPT docParserUnexpectedData());
552       break;
553     case EndTag:
554       break;
555     }
556
557   return attr ;
558   
559 }
560
561
562 DocParser::TagType
563 DocParser::read_tag(istream &input, ostringstream &output)
564 {
565   output.seekp(streampos(0));
566
567   TagType tt = StartTag;
568
569   char c ;
570
571   // strip newlines before/after tags
572   while ((input >> c) && (c == '\n'));
573   if (input.eof())
574     throw(CASTDPUEEXCEPT docParserUnexpectedEof());
575
576   if (c != '<')
577     {
578       input.putback(c);
579       return NoTag;
580     }
581
582
583   input >> c ;
584
585   switch (c)
586     {
587     case '/':
588       tt = EndTag ;
589       break;
590     case '#':
591       input >> c;
592       if (c == '>')
593         return AttributeSection ; // EXIT 
594       else
595         {
596           tt = OliasAttribute ;
597           output << c;          // keep char we just read 
598         }
599       break;
600     case '>':
601       throw(CASTUTEXCEPT unknownTagException());
602       // NOT REACHED 
603       break;
604     default:
605       output << c ;             // keep char we just read 
606       break;
607     }
608
609
610   // get (remainder of) tag name 
611   while ((input >> c) && (c != '>'))
612     output << c ;
613   output << ends;
614
615   return tt ;
616 }
617
618
619 void
620 DocParser::read_data(istream &input, ostringstream &output)
621 {
622   char c ;
623
624   output.seekp(streampos(0));
625
626   while ((input >> c) && (c != '<'))
627     {
628       // handle entities 
629       if (c == '&')
630         {
631           char tmpbuf[64];
632           unsigned int tmplen = 0;
633           while ((input >> c ) && (c != ';'))
634             {
635               tmpbuf[tmplen++] = c ;
636               if (tmplen > 63)
637                 {
638                   cerr << "Temp Buf overflow (ampersand problem)" << endl;
639                   throw(CASTEXCEPT Exception());
640                 }
641             }
642           if (input.eof())
643             throw(CASTDPUEEXCEPT docParserUnexpectedEof());
644             
645           tmpbuf[tmplen] = 0 ;
646
647 #ifdef ENTITY_DEBUG
648           cerr << "Entity: " << tmpbuf << endl;
649 #endif
650
651           if ((!strcmp(tmpbuf, "hardreturn")) ||
652               (!strcmp(tmpbuf, "lnfeed")))
653             c = '\n';
654           else
655             if ((!strcmp(tmpbuf, "lang")) ||
656                 (!strcmp(tmpbuf, "lt")))
657               c = '<' ;
658             else
659               if (!strcmp(tmpbuf, "amp"))
660                 c = '&' ;
661               else
662                 if (!strcmp(tmpbuf, "nbsp")) // non-break space 
663                   c = (char)0xA0 ;
664                 else
665                   c = ' ';
666
667         }
668
669       output << c;
670     }
671
672   output << ends;
673
674   // can never run out of input while reading data, tags must be balanced
675   if (input.eof())
676     throw(CASTDPUEEXCEPT docParserUnexpectedEof());
677             
678   input.putback(c);
679
680 }