1 /* Copyright (C) 2014 SkySQL Ab, MariaDB Corporation Ab 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; version 2 of the License. 6 7 This program is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 GNU General Public License for more details. 11 12 You should have received a copy of the GNU General Public License 13 along with this program; if not, write to the Free Software 14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ 15 16 class Json_writer; 17 18 /* 19 Single_line_formatting_helper is used by Json_writer to do better formatting 20 of JSON documents. 21 22 The idea is to catch arrays that can be printed on one line: 23 24 arrayName : [ "boo", 123, 456 ] 25 26 and actually print them on one line. Arrrays that occupy too much space on 27 the line, or have nested members cannot be printed on one line. 28 29 We hook into JSON printing functions and try to detect the pattern. While 30 detecting the pattern, we will accumulate "boo", 123, 456 as strings. 31 32 Then, 33 - either the pattern is broken, and we print the elements out, 34 - or the pattern lasts till the end of the array, and we print the 35 array on one line. 36 */ 37 38 class Single_line_formatting_helper 39 { 40 enum enum_state 41 { 42 INACTIVE, 43 ADD_MEMBER, 44 IN_ARRAY, 45 DISABLED 46 }; 47 48 /* 49 This works like a finite automaton. 50 51 state=DISABLED means the helper is disabled - all on_XXX functions will 52 return false (which means "not handled") and do nothing. 53 54 +->-+ 55 | v 56 INACTIVE ---> ADD_MEMBER ---> IN_ARRAY--->-+ 57 ^ | 58 +------------------<--------------------+ 59 60 For other states: 61 INACTIVE - initial state, we have nothing. 62 ADD_MEMBER - add_member() was called, the buffer has "member_name\0". 63 IN_ARRAY - start_array() was called. 64 65 66 */ 67 enum enum_state state; 68 enum { MAX_LINE_LEN= 80 }; 69 char buffer[80]; 70 71 /* The data in the buffer is located between buffer[0] and buf_ptr */ 72 char *buf_ptr; 73 uint line_len; 74 75 Json_writer *owner; 76 public: Single_line_formatting_helper()77 Single_line_formatting_helper() : state(INACTIVE), buf_ptr(buffer) {} 78 init(Json_writer * owner_arg)79 void init(Json_writer *owner_arg) { owner= owner_arg; } 80 81 bool on_add_member(const char *name); 82 83 bool on_start_array(); 84 bool on_end_array(); 85 void on_start_object(); 86 // on_end_object() is not needed. 87 88 bool on_add_str(const char *str); 89 90 void flush_on_one_line(); 91 void disable_and_flush(); 92 }; 93 94 95 /* 96 A class to write well-formed JSON documents. The documents are also formatted 97 for human readability. 98 */ 99 100 class Json_writer 101 { 102 public: 103 /* Add a member. We must be in an object. */ 104 Json_writer& add_member(const char *name); 105 106 /* Add atomic values */ 107 void add_str(const char* val); 108 void add_str(const String &str); 109 110 void add_ll(longlong val); 111 void add_ull(ulonglong val); 112 void add_size(longlong val); 113 void add_double(double val); 114 void add_bool(bool val); 115 void add_null(); 116 117 private: 118 void add_unquoted_str(const char* val); 119 public: 120 /* Start a child object */ 121 void start_object(); 122 void start_array(); 123 124 void end_object(); 125 void end_array(); 126 Json_writer()127 Json_writer() : 128 indent_level(0), document_start(true), element_started(false), 129 first_child(true) 130 { 131 fmt_helper.init(this); 132 } 133 private: 134 // TODO: a stack of (name, bool is_object_or_array) elements. 135 int indent_level; 136 enum { INDENT_SIZE = 2 }; 137 138 friend class Single_line_formatting_helper; 139 friend class Json_writer_nesting_guard; 140 bool document_start; 141 bool element_started; 142 bool first_child; 143 144 Single_line_formatting_helper fmt_helper; 145 146 void append_indent(); 147 void start_element(); 148 void start_sub_element(); 149 150 //const char *new_member_name; 151 public: 152 String output; 153 }; 154 155 156 /* 157 RAII-based helper class to detect incorrect use of Json_writer. 158 159 The idea is that a function typically must leave Json_writer at the same 160 identation level as it was when it was invoked. Leaving it at a different 161 level typically means we forgot to close an object or an array 162 163 So, here is a way to guard 164 void foo(Json_writer *writer) 165 { 166 Json_writer_nesting_guard(writer); 167 .. do something with writer 168 169 // at the end of the function, ~Json_writer_nesting_guard() is called 170 // and it makes sure that the nesting is the same as when the function was 171 // entered. 172 } 173 */ 174 175 class Json_writer_nesting_guard 176 { 177 #ifdef DBUG_OFF 178 public: Json_writer_nesting_guard(Json_writer *)179 Json_writer_nesting_guard(Json_writer *) {} 180 #else 181 Json_writer* writer; 182 int indent_level; 183 public: 184 Json_writer_nesting_guard(Json_writer *writer_arg) : 185 writer(writer_arg), 186 indent_level(writer->indent_level) 187 {} 188 189 ~Json_writer_nesting_guard() 190 { 191 DBUG_ASSERT(indent_level == writer->indent_level); 192 } 193 #endif 194 }; 195 196 197