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 17 #include <algorithm> 18 #include <iostream> 19 #include <sstream> 20 21 #include "Utilities.h" 22 23 using namespace std; 24 25 const char LEGAL_NOTICE[] = 26 "/*\n" 27 " * Copyright (C) 2016 The Android Open Source Project\n" 28 " *\n" 29 " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" 30 " * you may not use this file except in compliance with the License.\n" 31 " * You may obtain a copy of the License at\n" 32 " *\n" 33 " * http://www.apache.org/licenses/LICENSE-2.0\n" 34 " *\n" 35 " * Unless required by applicable law or agreed to in writing, software\n" 36 " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" 37 " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" 38 " * See the License for the specific language governing permissions and\n" 39 " * limitations under the License.\n" 40 " */\n\n"; 41 42 const char AUTO_GENERATED_WARNING[] = 43 "Don't edit this file! It is auto-generated by frameworks/rs/api/generate.sh."; 44 45 string capitalize(const string& source) { 46 int length = source.length(); 47 string result; 48 bool capitalize = true; 49 for (int s = 0; s < length; s++) { 50 if (source[s] == '_') { 51 capitalize = true; 52 } else if (capitalize) { 53 result += toupper(source[s]); 54 capitalize = false; 55 } else { 56 result += source[s]; 57 } 58 } 59 return result; 60 } 61 62 void trimSpaces(string* s) { 63 const size_t end = s->find_last_not_of(" "); 64 if (end == string::npos) { 65 // All spaces 66 s->erase(); 67 return; 68 } else { 69 s->erase(end + 1); 70 } 71 const size_t start = s->find_first_not_of(" "); 72 if (start > 0) { 73 s->erase(0, start); 74 } 75 } 76 77 string stringReplace(string s, string match, string rep) { 78 while (1) { 79 // This is not efficient but we don't care, as this program runs very rarely. 80 size_t p = s.find(match); 81 if (p == string::npos) break; 82 83 s.erase(p, match.size()); 84 s.insert(p, rep); 85 } 86 return s; 87 } 88 89 bool charRemoved(char c, string* s) { 90 size_t p = s->find(c); 91 if (p != string::npos) { 92 s->erase(p, 1); 93 return true; 94 } 95 return false; 96 } 97 98 string stripHtml(const string& html) { 99 string in = stringReplace(html, "<li>", "- "); 100 string out; 101 for (size_t start = 0; start < in.size(); start++) { 102 size_t lt = in.find('<', start); 103 if (lt == string::npos) { 104 out += in.substr(start); 105 break; 106 } 107 out += in.substr(start, lt - start); 108 if (isalpha(in[lt + 1]) || in[lt + 1] == '/') { 109 // It's an HTML tag. Search for the end. 110 start = in.find('>', lt + 1); 111 if (start == string::npos) { 112 break; 113 } 114 } else { 115 out += '<'; 116 } 117 } 118 out = stringReplace(out, ">", ">"); 119 out = stringReplace(out, "<", "<"); 120 out = stringReplace(out, " ", " "); 121 out = stringReplace(out, "&", "&"); 122 return out; 123 } 124 125 string hashString(const string& s) { 126 long hash = 0; 127 for (size_t i = 0; i < s.length(); i++) { 128 hash = hash * 43 + s[i]; 129 } 130 stringstream stream; 131 stream << "0x" << std::hex << hash << "l"; 132 return stream.str(); 133 } 134 135 bool testAndSet(const string& flag, set<string>* set) { 136 if (set->find(flag) == set->end()) { 137 set->insert(flag); 138 return false; 139 } 140 return true; 141 } 142 143 double maxDoubleForInteger(int numberOfIntegerBits, int mantissaSize) { 144 /* Double has only 52 bits of precision (53 implied). So for longs, we want 145 * to create smaller values to avoid a round up. Same for floats and halfs. 146 */ 147 int lowZeroBits = max(0, numberOfIntegerBits - mantissaSize); 148 uint64_t l = (0xffffffffffffffff >> (64 - numberOfIntegerBits + lowZeroBits)) 149 << lowZeroBits; 150 return (double)l; 151 } 152 153 // Add the value to the stream, prefixed with a ", " if needed. 154 static void addCommaSeparated(const string& value, ostringstream* stream, bool* needComma) { 155 if (value.empty()) { 156 return; 157 } 158 if (*needComma) { 159 *stream << ", "; 160 } 161 *stream << value; 162 *needComma = true; 163 } 164 165 string makeAttributeTag(const string& userAttribute, const string& additionalAttribute, 166 unsigned int deprecatedApiLevel, const string& deprecatedMessage) { 167 ostringstream stream; 168 bool needComma = false; 169 if (userAttribute[0] == '=') { 170 /* If starts with an equal, we don't automatically add additionalAttribute. 171 * This is because of the error we made defining rsUnpackColor8888(). 172 */ 173 addCommaSeparated(userAttribute.substr(1), &stream, &needComma); 174 } else { 175 addCommaSeparated(userAttribute, &stream, &needComma); 176 addCommaSeparated(additionalAttribute, &stream, &needComma); 177 } 178 if (deprecatedApiLevel > 0) { 179 stream << "\n#if (defined(RS_VERSION) && (RS_VERSION >= " << deprecatedApiLevel << "))\n"; 180 addCommaSeparated("deprecated", &stream, &needComma); 181 if (!deprecatedMessage.empty()) { 182 // Remove any @ that's used for generating documentation cross references. 183 string s = deprecatedMessage; 184 s.erase(std::remove(s.begin(), s.end(), '@'), s.end()); 185 stream << "(\"" << s << "\")"; 186 } 187 stream << "\n#endif\n"; 188 } 189 if (stream.tellp() == 0) { 190 return ""; 191 } 192 return " __attribute__((" + stream.str() + "))"; 193 } 194 195 // Opens the stream. Reports an error if it can't. 196 bool GeneratedFile::start(const string& directory, const string& name) { 197 const string path = directory + "/" + name; 198 open(path.c_str(), ios::out | ios::trunc); 199 if (!is_open()) { 200 cerr << "Error. Can't open the output file: " << path << "\n"; 201 return false; 202 } 203 return true; 204 } 205 206 void GeneratedFile::writeNotices() { 207 *this << LEGAL_NOTICE; 208 *this << "// " << AUTO_GENERATED_WARNING << "\n\n"; 209 } 210 211 void GeneratedFile::increaseIndent() { 212 mIndent.append(string(TAB_SIZE, ' ')); 213 } 214 215 void GeneratedFile::decreaseIndent() { 216 mIndent.erase(0, TAB_SIZE); 217 } 218