1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "Formatter.h"
18
19 #include <assert.h>
20
21 #include <android-base/logging.h>
22 #include <android-base/strings.h>
23 #include <string>
24 #include <vector>
25
26 namespace android {
27
Formatter()28 Formatter::Formatter() : mFile(nullptr /* invalid */), mIndentDepth(0), mCurrentPosition(0) {}
29
Formatter(FILE * file,size_t spacesPerIndent)30 Formatter::Formatter(FILE* file, size_t spacesPerIndent)
31 : mFile(file == nullptr ? stdout : file),
32 mIndentDepth(0),
33 mSpacesPerIndent(spacesPerIndent),
34 mCurrentPosition(0) {}
35
~Formatter()36 Formatter::~Formatter() {
37 if (mFile != stdout && mFile != stdin && mFile != stderr) {
38 fclose(mFile);
39 }
40 mFile = nullptr;
41 }
42
indent(size_t level)43 void Formatter::indent(size_t level) {
44 mIndentDepth += level;
45 }
46
unindent(size_t level)47 void Formatter::unindent(size_t level) {
48 assert(mIndentDepth >= level);
49 mIndentDepth -= level;
50 }
51
indent(size_t level,const std::function<void (void)> & func)52 Formatter& Formatter::indent(size_t level, const std::function<void(void)>& func) {
53 this->indent(level);
54 func();
55 this->unindent(level);
56 return *this;
57 }
58
indent(const std::function<void (void)> & func)59 Formatter& Formatter::indent(const std::function<void(void)>& func) {
60 return this->indent(1, func);
61 }
62
block(const std::function<void (void)> & func)63 Formatter& Formatter::block(const std::function<void(void)>& func) {
64 (*this) << "{\n";
65 this->indent(func);
66 return (*this) << "}";
67 }
68
pushLinePrefix(const std::string & prefix)69 void Formatter::pushLinePrefix(const std::string& prefix) {
70 mLinePrefix.push_back(prefix);
71 }
72
popLinePrefix()73 void Formatter::popLinePrefix() {
74 mLinePrefix.pop_back();
75 }
76
endl()77 Formatter &Formatter::endl() {
78 return (*this) << "\n";
79 }
80
sIf(const std::string & cond,const std::function<void (void)> & block)81 Formatter& Formatter::sIf(const std::string& cond, const std::function<void(void)>& block) {
82 (*this) << "if (" << cond << ") ";
83 return this->block(block);
84 }
85
sElseIf(const std::string & cond,const std::function<void (void)> & block)86 Formatter& Formatter::sElseIf(const std::string& cond, const std::function<void(void)>& block) {
87 (*this) << " else if (" << cond << ") ";
88 return this->block(block);
89 }
90
sElse(const std::function<void (void)> & block)91 Formatter& Formatter::sElse(const std::function<void(void)>& block) {
92 (*this) << " else ";
93 return this->block(block);
94 }
95
sFor(const std::string & stmts,const std::function<void (void)> & block)96 Formatter& Formatter::sFor(const std::string& stmts, const std::function<void(void)>& block) {
97 (*this) << "for (" << stmts << ") ";
98 return this->block(block);
99 }
100
sTry(const std::function<void (void)> & block)101 Formatter& Formatter::sTry(const std::function<void(void)>& block) {
102 (*this) << "try ";
103 return this->block(block);
104 }
105
sCatch(const std::string & exception,const std::function<void (void)> & block)106 Formatter& Formatter::sCatch(const std::string& exception, const std::function<void(void)>& block) {
107 (*this) << " catch (" << exception << ") ";
108 return this->block(block);
109 }
110
sFinally(const std::function<void (void)> & block)111 Formatter& Formatter::sFinally(const std::function<void(void)>& block) {
112 (*this) << " finally ";
113 return this->block(block);
114 }
115
sWhile(const std::string & cond,const std::function<void (void)> & block)116 Formatter& Formatter::sWhile(const std::string& cond, const std::function<void(void)>& block) {
117 (*this) << "while (" << cond << ") ";
118 return this->block(block);
119 }
120
operator <<(const std::string & out)121 Formatter& Formatter::operator<<(const std::string& out) {
122 const size_t len = out.length();
123 size_t start = 0;
124
125 const std::string& prefix = base::Join(mLinePrefix, "");
126 while (start < len) {
127 size_t pos = out.find('\n', start);
128
129 if (pos == std::string::npos) {
130 if (mCurrentPosition == 0) {
131 fprintf(mFile, "%*s", (int)(getIndentation()), "");
132 fprintf(mFile, "%s", prefix.c_str());
133 mCurrentPosition = getIndentation() + prefix.size();
134 }
135
136 std::string sub = out.substr(start);
137 output(sub);
138 mCurrentPosition += sub.size();
139 break;
140 }
141
142 if (mCurrentPosition == 0 && (pos > start || !prefix.empty())) {
143 fprintf(mFile, "%*s", (int)(getIndentation()), "");
144 fprintf(mFile, "%s", prefix.c_str());
145 mCurrentPosition = getIndentation() + prefix.size();
146 }
147
148 if (pos == start) {
149 fprintf(mFile, "\n");
150 mCurrentPosition = 0;
151 } else if (pos > start) {
152 output(out.substr(start, pos - start + 1));
153 mCurrentPosition = 0;
154 }
155
156 start = pos + 1;
157 }
158
159 return *this;
160 }
161
printBlock(const WrappedOutput::Block & block,size_t lineLength)162 void Formatter::printBlock(const WrappedOutput::Block& block, size_t lineLength) {
163 size_t prefixSize = 0;
164 for (const std::string& prefix : mLinePrefix) {
165 prefixSize += prefix.size();
166 }
167
168 size_t lineStart = mCurrentPosition ?: (getIndentation() + prefixSize);
169 size_t blockSize = block.computeSize(false);
170 if (blockSize + lineStart < lineLength) {
171 block.print(*this, false);
172 return;
173 }
174
175 // Everything will not fit on this line. Try to fit it on the next line.
176 blockSize = block.computeSize(true);
177 if ((blockSize + getIndentation() + mSpacesPerIndent + prefixSize) < lineLength) {
178 *this << "\n";
179 indent();
180
181 block.print(*this, true);
182
183 unindent();
184 return;
185 }
186
187 if (!block.content.empty()) {
188 // Doesn't have subblocks. This means that the block itself is too big.
189 // Have to print it out.
190 *this << "\n";
191 indent();
192
193 block.print(*this, true);
194
195 unindent();
196 return;
197 }
198
199 // Everything will not fit on this line. Go through all the children
200 for (const WrappedOutput::Block& subBlock : block.blocks) {
201 printBlock(subBlock, lineLength);
202 }
203 }
204
operator <<(const WrappedOutput & wrappedOutput)205 Formatter& Formatter::operator<<(const WrappedOutput& wrappedOutput) {
206 printBlock(wrappedOutput.mRootBlock, wrappedOutput.mLineLength);
207
208 return *this;
209 }
210
211 // NOLINT to suppress missing parentheses warning about __type__.
212 #define FORMATTER_INPUT_INTEGER(__type__) \
213 Formatter& Formatter::operator<<(__type__ n) { /* NOLINT */ \
214 return (*this) << std::to_string(n); \
215 }
216
217 FORMATTER_INPUT_INTEGER(short);
218 FORMATTER_INPUT_INTEGER(unsigned short);
219 FORMATTER_INPUT_INTEGER(int);
220 FORMATTER_INPUT_INTEGER(unsigned int);
221 FORMATTER_INPUT_INTEGER(long);
222 FORMATTER_INPUT_INTEGER(unsigned long);
223 FORMATTER_INPUT_INTEGER(long long);
224 FORMATTER_INPUT_INTEGER(unsigned long long);
225 FORMATTER_INPUT_INTEGER(float);
226 FORMATTER_INPUT_INTEGER(double);
227 FORMATTER_INPUT_INTEGER(long double);
228
229 #undef FORMATTER_INPUT_INTEGER
230
231 // NOLINT to suppress missing parentheses warning about __type__.
232 #define FORMATTER_INPUT_CHAR(__type__) \
233 Formatter& Formatter::operator<<(__type__ c) { /* NOLINT */ \
234 return (*this) << std::string(1, (char)c); \
235 }
236
237 FORMATTER_INPUT_CHAR(char);
238 FORMATTER_INPUT_CHAR(signed char);
239 FORMATTER_INPUT_CHAR(unsigned char);
240
241 #undef FORMATTER_INPUT_CHAR
242
isValid() const243 bool Formatter::isValid() const {
244 return mFile != nullptr;
245 }
246
getIndentation() const247 size_t Formatter::getIndentation() const {
248 return mSpacesPerIndent * mIndentDepth;
249 }
250
output(const std::string & text) const251 void Formatter::output(const std::string &text) const {
252 CHECK(isValid());
253
254 fprintf(mFile, "%s", text.c_str());
255 }
256
Block(const std::string & content,Block * const parent)257 WrappedOutput::Block::Block(const std::string& content, Block* const parent)
258 : content(content), parent(parent) {}
259
computeSize(bool wrapped) const260 size_t WrappedOutput::Block::computeSize(bool wrapped) const {
261 CHECK(content.empty() || blocks.empty());
262
263 // There is a wrap, so the block would not be printed
264 if (printUnlessWrapped && wrapped) return 0;
265
266 size_t size = content.size();
267 for (auto block = blocks.begin(); block != blocks.end(); ++block) {
268 if (block == blocks.begin()) {
269 // Only the first one can be wrapped (since content.empty())
270 size += block->computeSize(wrapped);
271 } else {
272 size += block->computeSize(false);
273 }
274 }
275
276 return size;
277 }
278
print(Formatter & out,bool wrapped) const279 void WrappedOutput::Block::print(Formatter& out, bool wrapped) const {
280 CHECK(content.empty() || blocks.empty());
281
282 // There is a wrap, so the block should not be printed
283 if (printUnlessWrapped && wrapped) return;
284
285 out << content;
286 for (auto block = blocks.begin(); block != blocks.end(); ++block) {
287 if (block == blocks.begin()) {
288 // Only the first one can be wrapped (since content.empty())
289 block->print(out, wrapped);
290 } else {
291 block->print(out, false);
292 }
293 }
294 }
295
WrappedOutput(size_t lineLength)296 WrappedOutput::WrappedOutput(size_t lineLength)
297 : mLineLength(lineLength), mRootBlock(Block("", nullptr)) {
298 mCurrentBlock = &mRootBlock;
299 }
300
operator <<(const std::string & str)301 WrappedOutput& WrappedOutput::operator<<(const std::string& str) {
302 std::vector<Block>& blockVec = mCurrentBlock->blocks;
303 if (!blockVec.empty()) {
304 Block& last = blockVec.back();
305 if (!last.populated && last.blocks.empty()) {
306 last.content += str;
307
308 return *this;
309 }
310 }
311
312 blockVec.emplace_back(str, mCurrentBlock);
313 return *this;
314 }
315
printUnlessWrapped(const std::string & str)316 WrappedOutput& WrappedOutput::printUnlessWrapped(const std::string& str) {
317 std::vector<Block>& blockVec = mCurrentBlock->blocks;
318 if (!blockVec.empty()) {
319 blockVec.back().populated = true;
320 }
321
322 blockVec.emplace_back(str, mCurrentBlock);
323 blockVec.back().populated = true;
324 blockVec.back().printUnlessWrapped = true;
325
326 return *this;
327 }
328
group(const std::function<void (void)> & block)329 void WrappedOutput::group(const std::function<void(void)>& block) {
330 std::vector<Block>& blockVec = mCurrentBlock->blocks;
331 if (!blockVec.empty()) {
332 blockVec.back().populated = true;
333 }
334
335 blockVec.emplace_back("", mCurrentBlock);
336 mCurrentBlock = &blockVec.back();
337
338 block();
339
340 mCurrentBlock->populated = true;
341 mCurrentBlock = mCurrentBlock->parent;
342 }
343
344 } // namespace android
345