• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015, 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 #include "code_writer.h"
17 
18 #include "logging.h"
19 
20 #include <stdarg.h>
21 #include <fstream>
22 #include <iostream>
23 #include <sstream>
24 #include <unordered_map>
25 #include <vector>
26 
27 #include <android-base/stringprintf.h>
28 
29 namespace android {
30 namespace aidl {
31 
CodeWriter(std::unique_ptr<std::ostream> ostream)32 CodeWriter::CodeWriter(std::unique_ptr<std::ostream> ostream) : ostream_(std::move(ostream)) {}
33 
ApplyIndent(const std::string & str)34 std::string CodeWriter::ApplyIndent(const std::string& str) {
35   std::string output;
36   if (!start_of_line_ || str == "\n") {
37     output = str;
38   } else {
39     output = std::string(indent_level_ * 2, ' ') + str;
40   }
41   start_of_line_ = !output.empty() && output.back() == '\n';
42   return output;
43 }
44 
Write(const char * format,...)45 bool CodeWriter::Write(const char* format, ...) {
46   va_list ap;
47   va_start(ap, format);
48   std::string formatted;
49   android::base::StringAppendV(&formatted, format, ap);
50   va_end(ap);
51 
52   // extract lines. empty line is preserved.
53   std::vector<std::string> lines;
54   size_t pos = 0;
55   while (pos < formatted.size()) {
56     size_t line_end = formatted.find('\n', pos);
57     if (line_end != std::string::npos) {
58       lines.push_back(formatted.substr(pos, (line_end - pos) + 1));
59       pos = line_end + 1;
60     } else {
61       lines.push_back(formatted.substr(pos));
62       break;
63     }
64   }
65 
66   std::string indented;
67   for (const auto& line : lines) {
68     indented.append(ApplyIndent(line));
69   }
70 
71   (*ostream_) << indented;
72   return !ostream_->fail();
73 }
74 
Indent()75 void CodeWriter::Indent() {
76   indent_level_++;
77 }
Dedent()78 void CodeWriter::Dedent() {
79   AIDL_FATAL_IF(indent_level_ <= 0, "Mismatched dedent");
80 
81   indent_level_--;
82 }
83 
Close()84 bool CodeWriter::Close() {
85   if (ostream_.get()->rdbuf() != std::cout.rdbuf()) {
86     // if the steam is for file (not stdout), do the close.
87     static_cast<std::fstream*>(ostream_.get())->close();
88     return !ostream_->fail();
89   }
90   return true;
91 }
92 
operator <<(const char * s)93 CodeWriter& CodeWriter::operator<<(const char* s) {
94   Write("%s", s);
95   return *this;
96 }
97 
operator <<(const std::string & str)98 CodeWriter& CodeWriter::operator<<(const std::string& str) {
99   Write("%s", str.c_str());
100   return *this;
101 }
102 
ForFile(const std::string & filename)103 CodeWriterPtr CodeWriter::ForFile(const std::string& filename) {
104   std::unique_ptr<std::ostream> stream;
105   if (filename == "-") {
106     stream = std::unique_ptr<std::ostream>(new std::ostream(std::cout.rdbuf()));
107   } else {
108     stream = std::unique_ptr<std::ostream>(
109         new std::fstream(filename, std::fstream::out | std::fstream::binary));
110   }
111   return CodeWriterPtr(new CodeWriter(std::move(stream)));
112 }
113 
ForString(std::string * buf)114 CodeWriterPtr CodeWriter::ForString(std::string* buf) {
115   // This class is defined inside this static function of CodeWriter
116   // in order to have access to private constructor and private member
117   // ostream_.
118   class StringCodeWriter : public CodeWriter {
119    public:
120     StringCodeWriter(std::string* buf)
121         : CodeWriter(std::unique_ptr<std::ostream>(new std::stringstream())), buf_(buf) {}
122     ~StringCodeWriter() override { Close(); }
123     bool Close() override {
124       // extract whats written to the stringstream to the external buffer.
125       // we are sure that ostream_ is indeed stringstream.
126       *buf_ = static_cast<std::stringstream*>(ostream_.get())->str();
127       return true;
128     }
129 
130    private:
131     std::string* buf_;
132   };
133   return CodeWriterPtr(new StringCodeWriter(buf));
134 }
135 
QuotedEscape(const std::string & str)136 std::string QuotedEscape(const std::string& str) {
137   std::string result;
138   result += '"';
139   static const std::unordered_map<char, std::string> escape = {
140       {'"', "\\\""}, {'\\', "\\\\"}, {'\n', "\\n"}, {'\r', "\\r"}, {'\t', "\\t"}, {'\v', "\\v"},
141   };
142   for (auto c : str) {
143     auto it = escape.find(c);
144     if (it != escape.end()) {
145       result += it->second;
146     } else {
147       result += c;
148     }
149   }
150   result += '"';
151   return result;
152 }
153 
154 }  // namespace aidl
155 }  // namespace android
156