• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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