| /* |
| * Copyright (C) 2015 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 <algorithm> |
| #include <iostream> |
| #include <sstream> |
| |
| #include "Utilities.h" |
| |
| using namespace std; |
| |
| const char LEGAL_NOTICE[] = |
| "/*\n" |
| " * Copyright (C) 2016 The Android Open Source Project\n" |
| " *\n" |
| " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" |
| " * you may not use this file except in compliance with the License.\n" |
| " * You may obtain a copy of the License at\n" |
| " *\n" |
| " * http://www.apache.org/licenses/LICENSE-2.0\n" |
| " *\n" |
| " * Unless required by applicable law or agreed to in writing, software\n" |
| " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" |
| " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" |
| " * See the License for the specific language governing permissions and\n" |
| " * limitations under the License.\n" |
| " */\n\n"; |
| |
| const char AUTO_GENERATED_WARNING[] = |
| "Don't edit this file! It is auto-generated by frameworks/rs/api/generate.sh."; |
| |
| string capitalize(const string& source) { |
| int length = source.length(); |
| string result; |
| bool capitalize = true; |
| for (int s = 0; s < length; s++) { |
| if (source[s] == '_') { |
| capitalize = true; |
| } else if (capitalize) { |
| result += toupper(source[s]); |
| capitalize = false; |
| } else { |
| result += source[s]; |
| } |
| } |
| return result; |
| } |
| |
| void trimSpaces(string* s) { |
| const size_t end = s->find_last_not_of(" "); |
| if (end == string::npos) { |
| // All spaces |
| s->erase(); |
| return; |
| } else { |
| s->erase(end + 1); |
| } |
| const size_t start = s->find_first_not_of(" "); |
| if (start > 0) { |
| s->erase(0, start); |
| } |
| } |
| |
| string stringReplace(string s, string match, string rep) { |
| while (1) { |
| // This is not efficient but we don't care, as this program runs very rarely. |
| size_t p = s.find(match); |
| if (p == string::npos) break; |
| |
| s.erase(p, match.size()); |
| s.insert(p, rep); |
| } |
| return s; |
| } |
| |
| bool charRemoved(char c, string* s) { |
| size_t p = s->find(c); |
| if (p != string::npos) { |
| s->erase(p, 1); |
| return true; |
| } |
| return false; |
| } |
| |
| string stripHtml(const string& html) { |
| string in = stringReplace(html, "<li>", "- "); |
| string out; |
| for (size_t start = 0; start < in.size(); start++) { |
| size_t lt = in.find('<', start); |
| if (lt == string::npos) { |
| out += in.substr(start); |
| break; |
| } |
| out += in.substr(start, lt - start); |
| if (isalpha(in[lt + 1]) || in[lt + 1] == '/') { |
| // It's an HTML tag. Search for the end. |
| start = in.find('>', lt + 1); |
| if (start == string::npos) { |
| break; |
| } |
| } else { |
| out += '<'; |
| } |
| } |
| out = stringReplace(out, ">", ">"); |
| out = stringReplace(out, "<", "<"); |
| out = stringReplace(out, " ", " "); |
| out = stringReplace(out, "&", "&"); |
| return out; |
| } |
| |
| string hashString(const string& s) { |
| long hash = 0; |
| for (size_t i = 0; i < s.length(); i++) { |
| hash = hash * 43 + s[i]; |
| } |
| stringstream stream; |
| stream << "0x" << std::hex << hash << "l"; |
| return stream.str(); |
| } |
| |
| bool testAndSet(const string& flag, set<string>* set) { |
| if (set->find(flag) == set->end()) { |
| set->insert(flag); |
| return false; |
| } |
| return true; |
| } |
| |
| double maxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) { |
| /* Double has only 52 bits of precision (53 implied). So for longs, we want |
| * to create smaller values to avoid a round up. Same for floats and halfs. |
| */ |
| int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize); |
| unsigned long l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits)) |
| << lowZeroBits; |
| return (double)l; |
| } |
| |
| // Add the value to the stream, prefixed with a ", " if needed. |
| static void addCommaSeparated(const string& value, ostringstream* stream, bool* needComma) { |
| if (value.empty()) { |
| return; |
| } |
| if (*needComma) { |
| *stream << ", "; |
| } |
| *stream << value; |
| *needComma = true; |
| } |
| |
| string makeAttributeTag(const string& userAttribute, const string& additionalAttribute, |
| unsigned int deprecatedApiLevel, const string& deprecatedMessage) { |
| ostringstream stream; |
| bool needComma = false; |
| if (userAttribute[0] == '=') { |
| /* If starts with an equal, we don't automatically add additionalAttribute. |
| * This is because of the error we made defining rsUnpackColor8888(). |
| */ |
| addCommaSeparated(userAttribute.substr(1), &stream, &needComma); |
| } else { |
| addCommaSeparated(userAttribute, &stream, &needComma); |
| addCommaSeparated(additionalAttribute, &stream, &needComma); |
| } |
| if (deprecatedApiLevel > 0) { |
| stream << "\n#if (defined(RS_VERSION) && (RS_VERSION >= " << deprecatedApiLevel << "))\n"; |
| addCommaSeparated("deprecated", &stream, &needComma); |
| if (!deprecatedMessage.empty()) { |
| // Remove any @ that's used for generating documentation cross references. |
| string s = deprecatedMessage; |
| s.erase(std::remove(s.begin(), s.end(), '@'), s.end()); |
| stream << "(\"" << s << "\")"; |
| } |
| stream << "\n#endif\n"; |
| } |
| if (stream.tellp() == 0) { |
| return ""; |
| } |
| return " __attribute__((" + stream.str() + "))"; |
| } |
| |
| // Opens the stream. Reports an error if it can't. |
| bool GeneratedFile::start(const string& directory, const string& name) { |
| const string path = directory + "/" + name; |
| open(path.c_str(), ios::out | ios::trunc); |
| if (!is_open()) { |
| cerr << "Error. Can't open the output file: " << path << "\n"; |
| return false; |
| } |
| return true; |
| } |
| |
| void GeneratedFile::writeNotices() { |
| *this << LEGAL_NOTICE; |
| *this << "// " << AUTO_GENERATED_WARNING << "\n\n"; |
| } |
| |
| void GeneratedFile::increaseIndent() { |
| mIndent.append(string(TAB_SIZE, ' ')); |
| } |
| |
| void GeneratedFile::decreaseIndent() { |
| mIndent.erase(0, TAB_SIZE); |
| } |