You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.7 KiB
207 lines
5.7 KiB
/* |
|
* Copyright (C) 2016 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include "Formatter.h" |
|
|
|
#include <assert.h> |
|
|
|
namespace android { |
|
|
|
Formatter::Formatter(FILE *file) |
|
: mFile(file == NULL ? stdout : file), |
|
mIndentDepth(0), |
|
mAtStartOfLine(true) { |
|
} |
|
|
|
Formatter::~Formatter() { |
|
if (mFile != stdout) { |
|
fclose(mFile); |
|
} |
|
mFile = NULL; |
|
} |
|
|
|
void Formatter::indent(size_t level) { |
|
mIndentDepth += level; |
|
} |
|
|
|
void Formatter::unindent(size_t level) { |
|
assert(mIndentDepth >= level); |
|
mIndentDepth -= level; |
|
} |
|
|
|
Formatter &Formatter::indent(size_t level, std::function<void(void)> func) { |
|
this->indent(level); |
|
func(); |
|
this->unindent(level); |
|
return *this; |
|
} |
|
|
|
Formatter &Formatter::indent(std::function<void(void)> func) { |
|
return this->indent(1, func); |
|
} |
|
|
|
Formatter &Formatter::block(std::function<void(void)> func) { |
|
(*this) << "{\n"; |
|
this->indent(func); |
|
return (*this) << "}"; |
|
} |
|
|
|
void Formatter::setLinePrefix(const std::string &prefix) { |
|
mLinePrefix = prefix; |
|
} |
|
|
|
void Formatter::unsetLinePrefix() { |
|
mLinePrefix = ""; |
|
} |
|
|
|
Formatter &Formatter::endl() { |
|
return (*this) << "\n"; |
|
} |
|
|
|
Formatter &Formatter::sIf(const std::string &cond, std::function<void(void)> block) { |
|
(*this) << "if (" << cond << ") "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sElseIf(const std::string &cond, std::function<void(void)> block) { |
|
(*this) << " else if (" << cond << ") "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sElse(std::function<void(void)> block) { |
|
(*this) << " else "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sFor(const std::string &stmts, std::function<void(void)> block) { |
|
(*this) << "for (" << stmts << ") "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sTry(std::function<void(void)> block) { |
|
(*this) << "try "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sCatch(const std::string &exception, std::function<void(void)> block) { |
|
(*this) << " catch (" << exception << ") "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sFinally(std::function<void(void)> block) { |
|
(*this) << " finally "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::sWhile(const std::string &cond, std::function<void(void)> block) { |
|
(*this) << "while (" << cond << ") "; |
|
return this->block(block); |
|
} |
|
|
|
Formatter &Formatter::operator<<(const std::string &out) { |
|
const size_t len = out.length(); |
|
size_t start = 0; |
|
while (start < len) { |
|
size_t pos = out.find("\n", start); |
|
|
|
if (pos == std::string::npos) { |
|
if (mAtStartOfLine) { |
|
fprintf(mFile, "%s", mLinePrefix.c_str()); |
|
fprintf(mFile, "%*s", (int)(4 * mIndentDepth), ""); |
|
mAtStartOfLine = false; |
|
} |
|
|
|
output(out.substr(start)); |
|
break; |
|
} |
|
|
|
if (pos == start) { |
|
fprintf(mFile, "\n"); |
|
mAtStartOfLine = true; |
|
} else if (pos > start) { |
|
if (mAtStartOfLine) { |
|
fprintf(mFile, "%s", mLinePrefix.c_str()); |
|
fprintf(mFile, "%*s", (int)(4 * mIndentDepth), ""); |
|
} |
|
|
|
output(out.substr(start, pos - start + 1)); |
|
|
|
mAtStartOfLine = true; |
|
} |
|
|
|
start = pos + 1; |
|
} |
|
|
|
return *this; |
|
} |
|
|
|
#define FORMATTER_INPUT_INTEGER(__type__) \ |
|
Formatter &Formatter::operator<<(__type__ n) { \ |
|
return (*this) << std::to_string(n); \ |
|
} \ |
|
|
|
FORMATTER_INPUT_INTEGER(short); |
|
FORMATTER_INPUT_INTEGER(unsigned short); |
|
FORMATTER_INPUT_INTEGER(int); |
|
FORMATTER_INPUT_INTEGER(unsigned int); |
|
FORMATTER_INPUT_INTEGER(long); |
|
FORMATTER_INPUT_INTEGER(unsigned long); |
|
FORMATTER_INPUT_INTEGER(long long); |
|
FORMATTER_INPUT_INTEGER(unsigned long long); |
|
FORMATTER_INPUT_INTEGER(float); |
|
FORMATTER_INPUT_INTEGER(double); |
|
FORMATTER_INPUT_INTEGER(long double); |
|
|
|
#undef FORMATTER_INPUT_INTEGER |
|
|
|
#define FORMATTER_INPUT_CHAR(__type__) \ |
|
Formatter &Formatter::operator<<(__type__ c) { \ |
|
return (*this) << std::string(1, (char)c); \ |
|
} \ |
|
|
|
FORMATTER_INPUT_CHAR(char); |
|
FORMATTER_INPUT_CHAR(signed char); |
|
FORMATTER_INPUT_CHAR(unsigned char); |
|
|
|
#undef FORMATTER_INPUT_CHAR |
|
|
|
void Formatter::setNamespace(const std::string &space) { |
|
mSpace = space; |
|
} |
|
|
|
void Formatter::output(const std::string &text) const { |
|
const size_t spaceLength = mSpace.size(); |
|
if (spaceLength > 0) { |
|
// Remove all occurences of "mSpace" and output the filtered result. |
|
size_t matchPos = text.find(mSpace); |
|
if (matchPos != std::string::npos) { |
|
std::string newText = text.substr(0, matchPos); |
|
size_t startPos = matchPos + spaceLength; |
|
while ((matchPos = text.find(mSpace, startPos)) |
|
!= std::string::npos) { |
|
newText.append(text.substr(startPos, matchPos - startPos)); |
|
startPos = matchPos + spaceLength; |
|
} |
|
newText.append(text.substr(startPos)); |
|
fprintf(mFile, "%s", newText.c_str()); |
|
return; |
|
} |
|
} |
|
|
|
fprintf(mFile, "%s", text.c_str()); |
|
} |
|
|
|
} // namespace android
|
|
|