blob: 7532b098bcf64de322a77aa25d102d4c271178da [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)
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070045 : variable_delimiter_(variable_delimiter),
46 output_(output),
47 buffer_(NULL),
48 buffer_size_(0),
49 offset_(0),
50 at_start_of_line_(true),
51 failed_(false),
52 annotation_collector_(NULL) {}
53
54Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
55 AnnotationCollector* annotation_collector)
56 : variable_delimiter_(variable_delimiter),
57 output_(output),
58 buffer_(NULL),
59 buffer_size_(0),
60 offset_(0),
61 at_start_of_line_(true),
62 failed_(false),
63 annotation_collector_(annotation_collector) {}
temporal40ee5512008-07-10 02:12:20 +000064
65Printer::~Printer() {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000066 // Only BackUp() if we have called Next() at least once and never failed.
67 if (buffer_size_ > 0 && !failed_) {
temporal40ee5512008-07-10 02:12:20 +000068 output_->BackUp(buffer_size_);
69 }
70}
71
Jisi Liu3b3c8ab2016-03-30 11:39:59 -070072bool Printer::GetSubstitutionRange(const char* varname,
73 pair<size_t, size_t>* range) {
74 map<string, pair<size_t, size_t> >::const_iterator iter =
75 substitutions_.find(varname);
76 if (iter == substitutions_.end()) {
77 GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
78 return false;
79 }
80 if (iter->second.first > iter->second.second) {
81 GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
82 << varname;
83 return false;
84 }
85 *range = iter->second;
86 return true;
87}
88
89void Printer::Annotate(const char* begin_varname, const char* end_varname,
90 const string& file_path, const vector<int>& path) {
91 if (annotation_collector_ == NULL) {
92 // Can't generate signatures with this Printer.
93 return;
94 }
95 pair<size_t, size_t> begin, end;
96 if (!GetSubstitutionRange(begin_varname, &begin) ||
97 !GetSubstitutionRange(end_varname, &end)) {
98 return;
99 }
100 if (begin.first > end.second) {
101 GOOGLE_LOG(DFATAL) << " Annotation has negative length from " << begin_varname
102 << " to " << end_varname;
103 } else {
104 annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
105 path);
106 }
107}
108
temporal40ee5512008-07-10 02:12:20 +0000109void Printer::Print(const map<string, string>& variables, const char* text) {
110 int size = strlen(text);
111 int pos = 0; // The number of bytes we've written so far.
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700112 substitutions_.clear();
temporal40ee5512008-07-10 02:12:20 +0000113
114 for (int i = 0; i < size; i++) {
115 if (text[i] == '\n') {
116 // Saw newline. If there is more text, we may need to insert an indent
117 // here. So, write what we have so far, including the '\n'.
kenton@google.comfccb1462009-12-18 02:11:36 +0000118 WriteRaw(text + pos, i - pos + 1);
temporal40ee5512008-07-10 02:12:20 +0000119 pos = i + 1;
120
kenton@google.comfccb1462009-12-18 02:11:36 +0000121 // Setting this true will cause the next WriteRaw() to insert an indent
temporal40ee5512008-07-10 02:12:20 +0000122 // first.
123 at_start_of_line_ = true;
124
125 } else if (text[i] == variable_delimiter_) {
126 // Saw the start of a variable name.
127
128 // Write what we have so far.
kenton@google.comfccb1462009-12-18 02:11:36 +0000129 WriteRaw(text + pos, i - pos);
temporal40ee5512008-07-10 02:12:20 +0000130 pos = i + 1;
131
132 // Find closing delimiter.
133 const char* end = strchr(text + pos, variable_delimiter_);
134 if (end == NULL) {
135 GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
136 end = text + pos;
137 }
138 int endpos = end - text;
139
140 string varname(text + pos, endpos - pos);
141 if (varname.empty()) {
142 // Two delimiters in a row reduce to a literal delimiter character.
kenton@google.comfccb1462009-12-18 02:11:36 +0000143 WriteRaw(&variable_delimiter_, 1);
temporal40ee5512008-07-10 02:12:20 +0000144 } else {
145 // Replace with the variable's value.
146 map<string, string>::const_iterator iter = variables.find(varname);
147 if (iter == variables.end()) {
148 GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
149 } else {
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700150 size_t begin = offset_;
kenton@google.comfccb1462009-12-18 02:11:36 +0000151 WriteRaw(iter->second.data(), iter->second.size());
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700152 pair<map<string, pair<size_t, size_t> >::iterator, bool> inserted =
153 substitutions_.insert(
154 std::make_pair(varname, std::make_pair(begin, offset_)));
155 if (!inserted.second) {
156 // This variable was used multiple times. Make its span have
157 // negative length so we can detect it if it gets used in an
158 // annotation.
159 inserted.first->second = std::make_pair(1, 0);
160 }
temporal40ee5512008-07-10 02:12:20 +0000161 }
162 }
163
164 // Advance past this variable.
165 i = endpos;
166 pos = endpos + 1;
167 }
168 }
169
170 // Write the rest.
kenton@google.comfccb1462009-12-18 02:11:36 +0000171 WriteRaw(text + pos, size - pos);
temporal40ee5512008-07-10 02:12:20 +0000172}
173
174void Printer::Print(const char* text) {
175 static map<string, string> empty;
176 Print(empty, text);
177}
178
179void Printer::Print(const char* text,
180 const char* variable, const string& value) {
181 map<string, string> vars;
182 vars[variable] = value;
183 Print(vars, text);
184}
185
186void Printer::Print(const char* text,
187 const char* variable1, const string& value1,
188 const char* variable2, const string& value2) {
189 map<string, string> vars;
190 vars[variable1] = value1;
191 vars[variable2] = value2;
192 Print(vars, text);
193}
194
liujisi@google.com33165fe2010-11-02 13:14:58 +0000195void Printer::Print(const char* text,
196 const char* variable1, const string& value1,
197 const char* variable2, const string& value2,
198 const char* variable3, const string& value3) {
199 map<string, string> vars;
200 vars[variable1] = value1;
201 vars[variable2] = value2;
202 vars[variable3] = value3;
203 Print(vars, text);
204}
205
Feng Xiao6ef984a2014-11-10 17:34:54 -0800206void Printer::Print(const char* text,
207 const char* variable1, const string& value1,
208 const char* variable2, const string& value2,
209 const char* variable3, const string& value3,
210 const char* variable4, const string& value4) {
211 map<string, string> vars;
212 vars[variable1] = value1;
213 vars[variable2] = value2;
214 vars[variable3] = value3;
215 vars[variable4] = value4;
216 Print(vars, text);
217}
218
Bo Yang5db21732015-05-21 14:28:59 -0700219void Printer::Print(const char* text,
220 const char* variable1, const string& value1,
221 const char* variable2, const string& value2,
222 const char* variable3, const string& value3,
223 const char* variable4, const string& value4,
224 const char* variable5, const string& value5) {
225 map<string, string> vars;
226 vars[variable1] = value1;
227 vars[variable2] = value2;
228 vars[variable3] = value3;
229 vars[variable4] = value4;
230 vars[variable5] = value5;
231 Print(vars, text);
232}
233
234void Printer::Print(const char* text,
235 const char* variable1, const string& value1,
236 const char* variable2, const string& value2,
237 const char* variable3, const string& value3,
238 const char* variable4, const string& value4,
239 const char* variable5, const string& value5,
240 const char* variable6, const string& value6) {
241 map<string, string> vars;
242 vars[variable1] = value1;
243 vars[variable2] = value2;
244 vars[variable3] = value3;
245 vars[variable4] = value4;
246 vars[variable5] = value5;
247 vars[variable6] = value6;
248 Print(vars, text);
249}
250
251void Printer::Print(const char* text,
252 const char* variable1, const string& value1,
253 const char* variable2, const string& value2,
254 const char* variable3, const string& value3,
255 const char* variable4, const string& value4,
256 const char* variable5, const string& value5,
257 const char* variable6, const string& value6,
258 const char* variable7, const string& value7) {
259 map<string, string> vars;
260 vars[variable1] = value1;
261 vars[variable2] = value2;
262 vars[variable3] = value3;
263 vars[variable4] = value4;
264 vars[variable5] = value5;
265 vars[variable6] = value6;
266 vars[variable7] = value7;
267 Print(vars, text);
268}
269
270void Printer::Print(const char* text,
271 const char* variable1, const string& value1,
272 const char* variable2, const string& value2,
273 const char* variable3, const string& value3,
274 const char* variable4, const string& value4,
275 const char* variable5, const string& value5,
276 const char* variable6, const string& value6,
277 const char* variable7, const string& value7,
278 const char* variable8, const string& value8) {
279 map<string, string> vars;
280 vars[variable1] = value1;
281 vars[variable2] = value2;
282 vars[variable3] = value3;
283 vars[variable4] = value4;
284 vars[variable5] = value5;
285 vars[variable6] = value6;
286 vars[variable7] = value7;
287 vars[variable8] = value8;
288 Print(vars, text);
289}
290
temporal40ee5512008-07-10 02:12:20 +0000291void Printer::Indent() {
292 indent_ += " ";
293}
294
295void Printer::Outdent() {
296 if (indent_.empty()) {
297 GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
298 return;
299 }
300
301 indent_.resize(indent_.size() - 2);
302}
303
kenton@google.comfccb1462009-12-18 02:11:36 +0000304void Printer::PrintRaw(const string& data) {
305 WriteRaw(data.data(), data.size());
306}
307
308void Printer::PrintRaw(const char* data) {
309 if (failed_) return;
310 WriteRaw(data, strlen(data));
311}
312
313void Printer::WriteRaw(const char* data, int size) {
temporal40ee5512008-07-10 02:12:20 +0000314 if (failed_) return;
315 if (size == 0) return;
316
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000317 if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
temporal40ee5512008-07-10 02:12:20 +0000318 // Insert an indent.
319 at_start_of_line_ = false;
kenton@google.comfccb1462009-12-18 02:11:36 +0000320 WriteRaw(indent_.data(), indent_.size());
temporal40ee5512008-07-10 02:12:20 +0000321 if (failed_) return;
322 }
323
324 while (size > buffer_size_) {
325 // Data exceeds space in the buffer. Copy what we can and request a
326 // new buffer.
327 memcpy(buffer_, data, buffer_size_);
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700328 offset_ += buffer_size_;
temporal40ee5512008-07-10 02:12:20 +0000329 data += buffer_size_;
330 size -= buffer_size_;
331 void* void_buffer;
332 failed_ = !output_->Next(&void_buffer, &buffer_size_);
333 if (failed_) return;
334 buffer_ = reinterpret_cast<char*>(void_buffer);
335 }
336
337 // Buffer is big enough to receive the data; copy it.
338 memcpy(buffer_, data, size);
339 buffer_ += size;
340 buffer_size_ -= size;
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700341 offset_ += size;
temporal40ee5512008-07-10 02:12:20 +0000342}
343
344} // namespace io
345} // namespace protobuf
346} // namespace google