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