1 /*
  2  * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_UTILITIES_XMLSTREAM_HPP
 26 #define SHARE_UTILITIES_XMLSTREAM_HPP
 27 
 28 #include "runtime/handles.hpp"
 29 #include "utilities/ostream.hpp"
 30 
 31 class xmlStream;
 32 class defaultStream;
 33 
 34 // Sub-stream for writing quoted text, as opposed to markup.
 35 // Characters written to this stream are subject to quoting,
 36 // as '<' => "&lt;", etc.
 37 class xmlTextStream : public outputStream {
 38   friend class xmlStream;
 39   friend class defaultStream; // tty
 40  private:
 41 
 42   xmlStream* _outer_xmlStream;
 43 
 44   xmlTextStream() { _outer_xmlStream = nullptr; }
 45 
 46  public:
 47    virtual void flush(); // _outer.flush();
 48    virtual void write(const char* str, size_t len); // _outer->write_text()
 49 };
 50 
 51 
 52 // Output stream for writing XML-structured logs.
 53 // To write markup, use special calls elem, head/tail, etc.
 54 // Use the xmlStream::text() stream to write unmarked text.
 55 // Text written that way will be quoted as necessary using '&lt;', etc.
 56 // Characters written directly to an xmlStream via print_cr, etc.,
 57 // are directly written to the encapsulated stream, xmlStream::out().
 58 // This can be used to produce markup directly, character by character.
 59 // (Such writes are not checked for markup syntax errors.)
 60 
 61 class xmlStream : public outputStream {
 62   friend class defaultStream; // tty
 63  public:
 64   enum MarkupState { BODY,       // after end_head() call, in text
 65                      HEAD,       // after begin_head() call, in attrs
 66                      ELEM };     // after begin_elem() call, in attrs
 67 
 68  protected:
 69   outputStream* _out;            // file stream by which it goes
 70   julong        _last_flush;     // last position of flush
 71   MarkupState   _markup_state;   // where in the elem/head/tail dance
 72   outputStream* _text;           // text stream
 73   xmlTextStream _text_init;
 74 
 75   // for subclasses
 76   xmlStream() {}
 77   void initialize(outputStream* out);
 78 
 79   // protect this from public use:
 80   outputStream* out()                            { return _out; }
 81 
 82   // helpers for writing XML elements
 83   void          va_tag(bool push, const char* format, va_list ap) ATTRIBUTE_PRINTF(3, 0);
 84   virtual void see_tag(const char* tag, bool push) NOT_DEBUG({});
 85   virtual void pop_tag(const char* tag) NOT_DEBUG({});
 86 
 87 #ifdef ASSERT
 88   // in debug mode, we verify matching of opening and closing tags
 89   int   _element_depth;              // number of unfinished elements
 90   char* _element_close_stack_high;   // upper limit of down-growing stack
 91   char* _element_close_stack_low;    // upper limit of down-growing stack
 92   char* _element_close_stack_ptr;    // pointer of down-growing stack
 93 #endif
 94 
 95  public:
 96   // creation
 97   xmlStream(outputStream* out) { initialize(out); }
 98   DEBUG_ONLY(virtual ~xmlStream();)
 99 
100   bool is_open() { return _out != nullptr; }
101 
102   // text output
103   bool inside_attrs() { return _markup_state != BODY; }
104 
105   // flushing
106   virtual void flush();  // flushes out, sets _last_flush = count()
107   virtual void write(const char* s, size_t len);
108   void    write_text(const char* s, size_t len);  // used by xmlTextStream
109   int unflushed_count() { return (int)(out()->count() - _last_flush); }
110 
111   // writing complete XML elements
112   void          elem(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
113   void    begin_elem(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
114   void      end_elem(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
115   void      end_elem();
116   void          head(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
117   void    begin_head(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
118   void      end_head(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
119   void      end_head();
120   void          done(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);  // xxx_done event, plus tail
121   void          done_raw(const char * kind);
122   void          tail(const char* kind);
123 
124   // va_list versions
125   void       va_elem(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
126   void va_begin_elem(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
127   void       va_head(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
128   void va_begin_head(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
129   void       va_done(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
130 
131   // write text (with quoting of special XML characters <>&'" etc.)
132   outputStream* text() { return _text; }
133   void          text(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
134   void       va_text(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0) {
135     text()->vprint(format, ap);
136   }
137 
138   // commonly used XML attributes
139   void          stamp();                 // stamp='1.234'
140   void          method(Method* m);       // method='k n s' ...
141   void          klass(Klass* k);         // klass='name'
142   void          name(const Symbol* s);   // name='name'
143   void          object(const char* attr, Metadata* val);
144   void          object(const char* attr, Handle val);
145 
146   // print the text alone (sans ''):
147   void          method_text(Method* m);
148   void          klass_text(Klass* k);         // klass='name'
149   void          name_text(const Symbol* s);   // name='name'
150   void          object_text(Metadata* x);
151   void          object_text(Handle x);
152 
153   /*  Example uses:
154 
155       // Empty element, simple case.
156       elem("X Y='Z'");          <X Y='Z'/> \n
157 
158       // Empty element, general case.
159       begin_elem("X Y='Z'");    <X Y='Z'
160       ...attrs...               ...attrs...
161       end_elem();               />
162 
163       // Compound element, simple case.
164       head("X Y='Z'");          <X Y='Z'> \n
165       ...body...                ...body...
166       tail("X");                </X> \n
167 
168       // Compound element, general case.
169       begin_head("X Y='Z'");    <X Y='Z'
170       ...attrs...               ...attrs...
171       end_head();               > \n
172       ...body...                ...body...
173       tail("X");                </X> \n
174 
175       // Printf-style formatting:
176       elem("X Y='%s'", "Z");    <X Y='Z'/> \n
177 
178    */
179 
180 };
181 
182 // Standard log file, null if no logging is happening.
183 extern xmlStream* xtty;
184 
185 // Note:  If ::xtty != nullptr, ::tty == ::xtty->text().
186 
187 #endif // SHARE_UTILITIES_XMLSTREAM_HPP