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 namespace android {
22
Formatter(FILE * file)23 Formatter::Formatter(FILE *file)
24 : mFile(file == NULL ? stdout : file),
25 mIndentDepth(0),
26 mAtStartOfLine(true) {
27 }
28
~Formatter()29 Formatter::~Formatter() {
30 if (mFile != stdout) {
31 fclose(mFile);
32 }
33 mFile = NULL;
34 }
35
indent(size_t level)36 void Formatter::indent(size_t level) {
37 mIndentDepth += level;
38 }
39
unindent(size_t level)40 void Formatter::unindent(size_t level) {
41 assert(mIndentDepth >= level);
42 mIndentDepth -= level;
43 }
44
indent(size_t level,std::function<void (void)> func)45 Formatter &Formatter::indent(size_t level, std::function<void(void)> func) {
46 this->indent(level);
47 func();
48 this->unindent(level);
49 return *this;
50 }
51
indent(std::function<void (void)> func)52 Formatter &Formatter::indent(std::function<void(void)> func) {
53 return this->indent(1, func);
54 }
55
block(std::function<void (void)> func)56 Formatter &Formatter::block(std::function<void(void)> func) {
57 (*this) << "{\n";
58 this->indent(func);
59 return (*this) << "}";
60 }
61
setLinePrefix(const std::string & prefix)62 void Formatter::setLinePrefix(const std::string &prefix) {
63 mLinePrefix = prefix;
64 }
65
unsetLinePrefix()66 void Formatter::unsetLinePrefix() {
67 mLinePrefix = "";
68 }
69
endl()70 Formatter &Formatter::endl() {
71 return (*this) << "\n";
72 }
73
sIf(const std::string & cond,std::function<void (void)> block)74 Formatter &Formatter::sIf(const std::string &cond, std::function<void(void)> block) {
75 (*this) << "if (" << cond << ") ";
76 return this->block(block);
77 }
78
sElseIf(const std::string & cond,std::function<void (void)> block)79 Formatter &Formatter::sElseIf(const std::string &cond, std::function<void(void)> block) {
80 (*this) << " else if (" << cond << ") ";
81 return this->block(block);
82 }
83
sElse(std::function<void (void)> block)84 Formatter &Formatter::sElse(std::function<void(void)> block) {
85 (*this) << " else ";
86 return this->block(block);
87 }
88
sFor(const std::string & stmts,std::function<void (void)> block)89 Formatter &Formatter::sFor(const std::string &stmts, std::function<void(void)> block) {
90 (*this) << "for (" << stmts << ") ";
91 return this->block(block);
92 }
93
sTry(std::function<void (void)> block)94 Formatter &Formatter::sTry(std::function<void(void)> block) {
95 (*this) << "try ";
96 return this->block(block);
97 }
98
sCatch(const std::string & exception,std::function<void (void)> block)99 Formatter &Formatter::sCatch(const std::string &exception, std::function<void(void)> block) {
100 (*this) << " catch (" << exception << ") ";
101 return this->block(block);
102 }
103
sFinally(std::function<void (void)> block)104 Formatter &Formatter::sFinally(std::function<void(void)> block) {
105 (*this) << " finally ";
106 return this->block(block);
107 }
108
sWhile(const std::string & cond,std::function<void (void)> block)109 Formatter &Formatter::sWhile(const std::string &cond, std::function<void(void)> block) {
110 (*this) << "while (" << cond << ") ";
111 return this->block(block);
112 }
113
operator <<(const std::string & out)114 Formatter &Formatter::operator<<(const std::string &out) {
115 const size_t len = out.length();
116 size_t start = 0;
117 while (start < len) {
118 size_t pos = out.find("\n", start);
119
120 if (pos == std::string::npos) {
121 if (mAtStartOfLine) {
122 fprintf(mFile, "%s", mLinePrefix.c_str());
123 fprintf(mFile, "%*s", (int)(4 * mIndentDepth), "");
124 mAtStartOfLine = false;
125 }
126
127 output(out.substr(start));
128 break;
129 }
130
131 if (pos == start) {
132 fprintf(mFile, "\n");
133 mAtStartOfLine = true;
134 } else if (pos > start) {
135 if (mAtStartOfLine) {
136 fprintf(mFile, "%s", mLinePrefix.c_str());
137 fprintf(mFile, "%*s", (int)(4 * mIndentDepth), "");
138 }
139
140 output(out.substr(start, pos - start + 1));
141
142 mAtStartOfLine = true;
143 }
144
145 start = pos + 1;
146 }
147
148 return *this;
149 }
150
151 #define FORMATTER_INPUT_INTEGER(__type__) \
152 Formatter &Formatter::operator<<(__type__ n) { \
153 return (*this) << std::to_string(n); \
154 } \
155
156 FORMATTER_INPUT_INTEGER(short);
157 FORMATTER_INPUT_INTEGER(unsigned short);
158 FORMATTER_INPUT_INTEGER(int);
159 FORMATTER_INPUT_INTEGER(unsigned int);
160 FORMATTER_INPUT_INTEGER(long);
161 FORMATTER_INPUT_INTEGER(unsigned long);
162 FORMATTER_INPUT_INTEGER(long long);
163 FORMATTER_INPUT_INTEGER(unsigned long long);
164 FORMATTER_INPUT_INTEGER(float);
165 FORMATTER_INPUT_INTEGER(double);
166 FORMATTER_INPUT_INTEGER(long double);
167
168 #undef FORMATTER_INPUT_INTEGER
169
170 #define FORMATTER_INPUT_CHAR(__type__) \
171 Formatter &Formatter::operator<<(__type__ c) { \
172 return (*this) << std::string(1, (char)c); \
173 } \
174
175 FORMATTER_INPUT_CHAR(char);
176 FORMATTER_INPUT_CHAR(signed char);
177 FORMATTER_INPUT_CHAR(unsigned char);
178
179 #undef FORMATTER_INPUT_CHAR
180
setNamespace(const std::string & space)181 void Formatter::setNamespace(const std::string &space) {
182 mSpace = space;
183 }
184
output(const std::string & text) const185 void Formatter::output(const std::string &text) const {
186 const size_t spaceLength = mSpace.size();
187 if (spaceLength > 0) {
188 // Remove all occurences of "mSpace" and output the filtered result.
189 size_t matchPos = text.find(mSpace);
190 if (matchPos != std::string::npos) {
191 std::string newText = text.substr(0, matchPos);
192 size_t startPos = matchPos + spaceLength;
193 while ((matchPos = text.find(mSpace, startPos))
194 != std::string::npos) {
195 newText.append(text.substr(startPos, matchPos - startPos));
196 startPos = matchPos + spaceLength;
197 }
198 newText.append(text.substr(startPos));
199 fprintf(mFile, "%s", newText.c_str());
200 return;
201 }
202 }
203
204 fprintf(mFile, "%s", text.c_str());
205 }
206
207 } // namespace android
208