Line data Source code
1 : // Protocol Buffers - Google's data interchange format
2 : // Copyright 2008 Google Inc. All rights reserved.
3 : // https://developers.google.com/protocol-buffers/
4 : //
5 : // Redistribution and use in source and binary forms, with or without
6 : // modification, are permitted provided that the following conditions are
7 : // met:
8 : //
9 : // * 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.
18 : //
19 : // 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.
30 :
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>
37 : #include <google/protobuf/stubs/common.h>
38 :
39 : namespace google {
40 : namespace protobuf {
41 : namespace io {
42 :
43 0 : Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
44 : : variable_delimiter_(variable_delimiter),
45 : output_(output),
46 : buffer_(NULL),
47 : buffer_size_(0),
48 : at_start_of_line_(true),
49 0 : failed_(false) {
50 0 : }
51 :
52 0 : Printer::~Printer() {
53 : // Only BackUp() if we have called Next() at least once and never failed.
54 0 : if (buffer_size_ > 0 && !failed_) {
55 0 : output_->BackUp(buffer_size_);
56 : }
57 0 : }
58 :
59 0 : void Printer::Print(const map<string, string>& variables, const char* text) {
60 0 : int size = strlen(text);
61 0 : int pos = 0; // The number of bytes we've written so far.
62 :
63 0 : for (int i = 0; i < size; i++) {
64 0 : if (text[i] == '\n') {
65 : // Saw newline. If there is more text, we may need to insert an indent
66 : // here. So, write what we have so far, including the '\n'.
67 0 : WriteRaw(text + pos, i - pos + 1);
68 0 : pos = i + 1;
69 :
70 : // Setting this true will cause the next WriteRaw() to insert an indent
71 : // first.
72 0 : at_start_of_line_ = true;
73 :
74 0 : } else if (text[i] == variable_delimiter_) {
75 : // Saw the start of a variable name.
76 :
77 : // Write what we have so far.
78 0 : WriteRaw(text + pos, i - pos);
79 0 : pos = i + 1;
80 :
81 : // Find closing delimiter.
82 0 : const char* end = strchr(text + pos, variable_delimiter_);
83 0 : if (end == NULL) {
84 0 : GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
85 0 : end = text + pos;
86 : }
87 0 : int endpos = end - text;
88 :
89 0 : string varname(text + pos, endpos - pos);
90 0 : if (varname.empty()) {
91 : // Two delimiters in a row reduce to a literal delimiter character.
92 0 : WriteRaw(&variable_delimiter_, 1);
93 : } else {
94 : // Replace with the variable's value.
95 0 : map<string, string>::const_iterator iter = variables.find(varname);
96 0 : if (iter == variables.end()) {
97 0 : GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
98 : } else {
99 0 : WriteRaw(iter->second.data(), iter->second.size());
100 : }
101 : }
102 :
103 : // Advance past this variable.
104 0 : i = endpos;
105 0 : pos = endpos + 1;
106 : }
107 : }
108 :
109 : // Write the rest.
110 0 : WriteRaw(text + pos, size - pos);
111 0 : }
112 :
113 0 : void Printer::Print(const char* text) {
114 0 : static map<string, string> empty;
115 0 : Print(empty, text);
116 0 : }
117 :
118 0 : void Printer::Print(const char* text,
119 : const char* variable, const string& value) {
120 0 : map<string, string> vars;
121 0 : vars[variable] = value;
122 0 : Print(vars, text);
123 0 : }
124 :
125 0 : void Printer::Print(const char* text,
126 : const char* variable1, const string& value1,
127 : const char* variable2, const string& value2) {
128 0 : map<string, string> vars;
129 0 : vars[variable1] = value1;
130 0 : vars[variable2] = value2;
131 0 : Print(vars, text);
132 0 : }
133 :
134 0 : void Printer::Print(const char* text,
135 : const char* variable1, const string& value1,
136 : const char* variable2, const string& value2,
137 : const char* variable3, const string& value3) {
138 0 : map<string, string> vars;
139 0 : vars[variable1] = value1;
140 0 : vars[variable2] = value2;
141 0 : vars[variable3] = value3;
142 0 : Print(vars, text);
143 0 : }
144 :
145 0 : void Printer::Indent() {
146 0 : indent_ += " ";
147 0 : }
148 :
149 0 : void Printer::Outdent() {
150 0 : if (indent_.empty()) {
151 0 : GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
152 0 : return;
153 : }
154 :
155 0 : indent_.resize(indent_.size() - 2);
156 : }
157 :
158 0 : void Printer::PrintRaw(const string& data) {
159 0 : WriteRaw(data.data(), data.size());
160 0 : }
161 :
162 0 : void Printer::PrintRaw(const char* data) {
163 0 : if (failed_) return;
164 0 : WriteRaw(data, strlen(data));
165 : }
166 :
167 0 : void Printer::WriteRaw(const char* data, int size) {
168 0 : if (failed_) return;
169 0 : if (size == 0) return;
170 :
171 0 : if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
172 : // Insert an indent.
173 0 : at_start_of_line_ = false;
174 0 : WriteRaw(indent_.data(), indent_.size());
175 0 : if (failed_) return;
176 : }
177 :
178 0 : while (size > buffer_size_) {
179 : // Data exceeds space in the buffer. Copy what we can and request a
180 : // new buffer.
181 0 : memcpy(buffer_, data, buffer_size_);
182 0 : data += buffer_size_;
183 0 : size -= buffer_size_;
184 : void* void_buffer;
185 0 : failed_ = !output_->Next(&void_buffer, &buffer_size_);
186 0 : if (failed_) return;
187 0 : buffer_ = reinterpret_cast<char*>(void_buffer);
188 : }
189 :
190 : // Buffer is big enough to receive the data; copy it.
191 0 : memcpy(buffer_, data, size);
192 0 : buffer_ += size;
193 0 : buffer_size_ -= size;
194 : }
195 :
196 : } // namespace io
197 : } // namespace protobuf
198 : } // namespace google
|