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   outputStream* _log_only;       // like text, except does not copy to the tty
 74   xmlTextStream _text_init;
 75 
 76   // for subclasses
 77   xmlStream() {}
 78   void initialize(outputStream* out);
 79 
 80   // protect this from public use:
 81   outputStream* out()                            { return _out; }
 82 
 83   // helpers for writing XML elements
 84   void          va_tag(bool push, const char* format, va_list ap) ATTRIBUTE_PRINTF(3, 0);
 85   virtual void see_tag(const char* tag, bool push) NOT_DEBUG({});
 86   virtual void pop_tag(const char* tag) NOT_DEBUG({});
 87 
 88 #ifdef ASSERT
 89   // in debug mode, we verify matching of opening and closing tags
 90   int   _element_depth;              // number of unfinished elements
 91   char* _element_close_stack_high;   // upper limit of down-growing stack
 92   char* _element_close_stack_low;    // upper limit of down-growing stack
 93   char* _element_close_stack_ptr;    // pointer of down-growing stack
 94 #endif
 95 
 96  public:
 97   // creation
 98   xmlStream(outputStream* out) { initialize(out); }
 99   DEBUG_ONLY(virtual ~xmlStream();)
100 
101   bool is_open() { return _out != nullptr; }
102 
103   // text output
104   bool inside_attrs() { return _markup_state != BODY; }
105   bool inside_attrs_or_error();
106 
107   // flushing
108   virtual void flush();  // flushes out, sets _last_flush = count()
109   virtual void write(const char* s, size_t len);
110   void    write_text(const char* s, size_t len);  // used by xmlTextStream
111   int unflushed_count() { return (int)(out()->count() - _last_flush); }
112 
113   // writing complete XML elements
114   void          elem(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
115   void    begin_elem(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
116   void      end_elem(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
117   void      end_elem();
118   void          head(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
119   void    begin_head(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
120   void      end_head(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
121   void      end_head();
122   void          done(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);  // xxx_done event, plus tail
123   void          done_raw(const char * kind);
124   void          tail(const char* kind);
125 
126   // va_list versions
127   void       va_elem(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
128   void va_begin_elem(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
129   void       va_head(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
130   void va_begin_head(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
131   void       va_done(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
132 
133   // write text (with quoting of special XML characters <>&'" etc.)
134   outputStream* text() { return _text; }
135   void          text(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
136   void       va_text(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0) {
137     text()->vprint(format, ap);
138   }
139 
140   // write attr with formatted contents
141   void          attr(const char* attr, const char* format, ...) ATTRIBUTE_PRINTF(3, 4);
142   void       va_attr(const char* attr, const char* format, va_list ap) ATTRIBUTE_PRINTF(3, 0) {
143     print_raw(" ");
144     print_raw(attr);
145     print_raw("='");
146     va_text(format, ap);
147     print_raw("='");
148   }
149 
150   outputStream* log_only() { return _log_only; }
151   // report if a given random stream is really part of this XML stream
152   bool owns(outputStream* st) {
153     return st == this || st == _text || st == _log_only || st == _out;
154   }
155 
156   // commonly used XML attributes
157   void          stamp();                 // stamp='1.234'
158   void          method(Method* m, const char* pfx=""); // method='k n s' ...
159   void          klass(Klass* k, const char* pfx="");   // klass='name'
160   void          loader(oop cl, const char* pfx="");   // loader='...'
161   void          name(const Symbol* s, const char* pfx="");   // name='n'
162   void          signature(const Symbol* s, const char* pfx="");   // signature='...'
163   void          object(const char* attr, Metadata* val);
164   void          object(const char* attr, Handle val);
165   void          thread(Thread* t = nullptr, const char* pfx=""); // thread='NNN'
166 
167   // print the text alone (sans ''):
168   void          method_text(Method* m);
169   void          klass_text(Klass* k);         // java.lang.String
170   void          symbol_text(const Symbol* s);   // (utf8 bytes)...
171   void          loader_text(oop cl);
172   void          object_text(Metadata* x);
173   void          object_text(Handle x);
174   void          string_text(oop str);
175 
176   /*  Example uses:
177 
178       // Empty element, simple case.
179       elem("X Y='Z'");          <X Y='Z'/> \n
180 
181       // Empty element, general case.
182       begin_elem("X Y='Z'");    <X Y='Z'
183       ...attrs...               ...attrs...
184       end_elem();               />
185 
186       // Compound element, simple case.
187       head("X Y='Z'");          <X Y='Z'> \n
188       ...body...                ...body...
189       tail("X");                </X> \n
190 
191       // Compound element, general case.
192       begin_head("X Y='Z'");    <X Y='Z'
193       ...attrs...               ...attrs...
194       end_head();               > \n
195       ...body...                ...body...
196       tail("X");                </X> \n
197 
198       // Printf-style formatting:
199       elem("X Y='%s'", "Z");    <X Y='Z'/> \n
200 
201    */
202 
203 };
204 
205 // Standard log file, null if no logging is happening.
206 extern xmlStream* xtty;
207 
208 static inline bool xtty_owns(outputStream* st) {
209   return xtty != nullptr && xtty->owns(st);
210 }
211 
212 // Note:  If ::xtty != nullptr, ::tty == ::xtty->text().
213 
214 #endif // SHARE_UTILITIES_XMLSTREAM_HPP