blob: 7d886506265fc92c4cf2d238bd5b187b6d442a55 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <google/protobuf/io/printer.h>
36#include <google/protobuf/io/zero_copy_stream.h>
Feng Xiaoeee38b02015-08-22 18:25:48 -070037#include <google/protobuf/stubs/logging.h>
temporal40ee5512008-07-10 02:12:20 +000038#include <google/protobuf/stubs/common.h>
temporal40ee5512008-07-10 02:12:20 +000039
40namespace google {
41namespace protobuf {
42namespace io {
43
44Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
45 : variable_delimiter_(variable_delimiter),
46 output_(output),
47 buffer_(NULL),
48 buffer_size_(0),
49 at_start_of_line_(true),
50 failed_(false) {
51}
52
53Printer::~Printer() {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000054 // Only BackUp() if we have called Next() at least once and never failed.
55 if (buffer_size_ > 0 && !failed_) {
temporal40ee5512008-07-10 02:12:20 +000056 output_->BackUp(buffer_size_);
57 }
58}
59
60void Printer::Print(const map<string, string>& variables, const char* text) {
61 int size = strlen(text);
62 int pos = 0; // The number of bytes we've written so far.
63
64 for (int i = 0; i < size; i++) {
65 if (text[i] == '\n') {
66 // Saw newline. If there is more text, we may need to insert an indent
67 // here. So, write what we have so far, including the '\n'.
kenton@google.comfccb1462009-12-18 02:11:36 +000068 WriteRaw(text + pos, i - pos + 1);
temporal40ee5512008-07-10 02:12:20 +000069 pos = i + 1;
70
kenton@google.comfccb1462009-12-18 02:11:36 +000071 // Setting this true will cause the next WriteRaw() to insert an indent
temporal40ee5512008-07-10 02:12:20 +000072 // first.
73 at_start_of_line_ = true;
74
75 } else if (text[i] == variable_delimiter_) {
76 // Saw the start of a variable name.
77
78 // Write what we have so far.
kenton@google.comfccb1462009-12-18 02:11:36 +000079 WriteRaw(text + pos, i - pos);
temporal40ee5512008-07-10 02:12:20 +000080 pos = i + 1;
81
82 // Find closing delimiter.
83 const char* end = strchr(text + pos, variable_delimiter_);
84 if (end == NULL) {
85 GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
86 end = text + pos;
87 }
88 int endpos = end - text;
89
90 string varname(text + pos, endpos - pos);
91 if (varname.empty()) {
92 // Two delimiters in a row reduce to a literal delimiter character.
kenton@google.comfccb1462009-12-18 02:11:36 +000093 WriteRaw(&variable_delimiter_, 1);
temporal40ee5512008-07-10 02:12:20 +000094 } else {
95 // Replace with the variable's value.
96 map<string, string>::const_iterator iter = variables.find(varname);
97 if (iter == variables.end()) {
98 GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
99 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +0000100 WriteRaw(iter->second.data(), iter->second.size());
temporal40ee5512008-07-10 02:12:20 +0000101 }
102 }
103
104 // Advance past this variable.
105 i = endpos;
106 pos = endpos + 1;
107 }
108 }
109
110 // Write the rest.
kenton@google.comfccb1462009-12-18 02:11:36 +0000111 WriteRaw(text + pos, size - pos);
temporal40ee5512008-07-10 02:12:20 +0000112}
113
114void Printer::Print(const char* text) {
115 static map<string, string> empty;
116 Print(empty, text);
117}
118
119void Printer::Print(const char* text,
120 const char* variable, const string& value) {
121 map<string, string> vars;
122 vars[variable] = value;
123 Print(vars, text);
124}
125
126void Printer::Print(const char* text,
127 const char* variable1, const string& value1,
128 const char* variable2, const string& value2) {
129 map<string, string> vars;
130 vars[variable1] = value1;
131 vars[variable2] = value2;
132 Print(vars, text);
133}
134
liujisi@google.com33165fe2010-11-02 13:14:58 +0000135void Printer::Print(const char* text,
136 const char* variable1, const string& value1,
137 const char* variable2, const string& value2,
138 const char* variable3, const string& value3) {
139 map<string, string> vars;
140 vars[variable1] = value1;
141 vars[variable2] = value2;
142 vars[variable3] = value3;
143 Print(vars, text);
144}
145
Feng Xiao6ef984a2014-11-10 17:34:54 -0800146void Printer::Print(const char* text,
147 const char* variable1, const string& value1,
148 const char* variable2, const string& value2,
149 const char* variable3, const string& value3,
150 const char* variable4, const string& value4) {
151 map<string, string> vars;
152 vars[variable1] = value1;
153 vars[variable2] = value2;
154 vars[variable3] = value3;
155 vars[variable4] = value4;
156 Print(vars, text);
157}
158
Bo Yang5db21732015-05-21 14:28:59 -0700159void Printer::Print(const char* text,
160 const char* variable1, const string& value1,
161 const char* variable2, const string& value2,
162 const char* variable3, const string& value3,
163 const char* variable4, const string& value4,
164 const char* variable5, const string& value5) {
165 map<string, string> vars;
166 vars[variable1] = value1;
167 vars[variable2] = value2;
168 vars[variable3] = value3;
169 vars[variable4] = value4;
170 vars[variable5] = value5;
171 Print(vars, text);
172}
173
174void Printer::Print(const char* text,
175 const char* variable1, const string& value1,
176 const char* variable2, const string& value2,
177 const char* variable3, const string& value3,
178 const char* variable4, const string& value4,
179 const char* variable5, const string& value5,
180 const char* variable6, const string& value6) {
181 map<string, string> vars;
182 vars[variable1] = value1;
183 vars[variable2] = value2;
184 vars[variable3] = value3;
185 vars[variable4] = value4;
186 vars[variable5] = value5;
187 vars[variable6] = value6;
188 Print(vars, text);
189}
190
191void Printer::Print(const char* text,
192 const char* variable1, const string& value1,
193 const char* variable2, const string& value2,
194 const char* variable3, const string& value3,
195 const char* variable4, const string& value4,
196 const char* variable5, const string& value5,
197 const char* variable6, const string& value6,
198 const char* variable7, const string& value7) {
199 map<string, string> vars;
200 vars[variable1] = value1;
201 vars[variable2] = value2;
202 vars[variable3] = value3;
203 vars[variable4] = value4;
204 vars[variable5] = value5;
205 vars[variable6] = value6;
206 vars[variable7] = value7;
207 Print(vars, text);
208}
209
210void Printer::Print(const char* text,
211 const char* variable1, const string& value1,
212 const char* variable2, const string& value2,
213 const char* variable3, const string& value3,
214 const char* variable4, const string& value4,
215 const char* variable5, const string& value5,
216 const char* variable6, const string& value6,
217 const char* variable7, const string& value7,
218 const char* variable8, const string& value8) {
219 map<string, string> vars;
220 vars[variable1] = value1;
221 vars[variable2] = value2;
222 vars[variable3] = value3;
223 vars[variable4] = value4;
224 vars[variable5] = value5;
225 vars[variable6] = value6;
226 vars[variable7] = value7;
227 vars[variable8] = value8;
228 Print(vars, text);
229}
230
temporal40ee5512008-07-10 02:12:20 +0000231void Printer::Indent() {
232 indent_ += " ";
233}
234
235void Printer::Outdent() {
236 if (indent_.empty()) {
237 GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
238 return;
239 }
240
241 indent_.resize(indent_.size() - 2);
242}
243
kenton@google.comfccb1462009-12-18 02:11:36 +0000244void Printer::PrintRaw(const string& data) {
245 WriteRaw(data.data(), data.size());
246}
247
248void Printer::PrintRaw(const char* data) {
249 if (failed_) return;
250 WriteRaw(data, strlen(data));
251}
252
253void Printer::WriteRaw(const char* data, int size) {
temporal40ee5512008-07-10 02:12:20 +0000254 if (failed_) return;
255 if (size == 0) return;
256
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000257 if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
temporal40ee5512008-07-10 02:12:20 +0000258 // Insert an indent.
259 at_start_of_line_ = false;
kenton@google.comfccb1462009-12-18 02:11:36 +0000260 WriteRaw(indent_.data(), indent_.size());
temporal40ee5512008-07-10 02:12:20 +0000261 if (failed_) return;
262 }
263
264 while (size > buffer_size_) {
265 // Data exceeds space in the buffer. Copy what we can and request a
266 // new buffer.
267 memcpy(buffer_, data, buffer_size_);
268 data += buffer_size_;
269 size -= buffer_size_;
270 void* void_buffer;
271 failed_ = !output_->Next(&void_buffer, &buffer_size_);
272 if (failed_) return;
273 buffer_ = reinterpret_cast<char*>(void_buffer);
274 }
275
276 // Buffer is big enough to receive the data; copy it.
277 memcpy(buffer_, data, size);
278 buffer_ += size;
279 buffer_size_ -= size;
280}
281
282} // namespace io
283} // namespace protobuf
284} // namespace google