[12] | 1 | /* |
---|
| 2 | * |
---|
| 3 | * Copyright (c) 2003 Dr John Maddock |
---|
| 4 | * Use, modification and distribution is subject to the |
---|
| 5 | * Boost Software License, Version 1.0. (See accompanying file |
---|
| 6 | * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
| 7 | * |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | #include "licence_info.hpp" |
---|
| 11 | #include "bcp_imp.hpp" |
---|
| 12 | #include "fileview.hpp" |
---|
| 13 | #include <fstream> |
---|
| 14 | #include <iostream> |
---|
| 15 | |
---|
| 16 | |
---|
| 17 | const int boost_license_lines = 3; |
---|
| 18 | static const std::string boost_license_text[boost_license_lines] = { |
---|
| 19 | "Distributed under the Boost Software License, Version 1.0. (See", |
---|
| 20 | "accompanying file LICENSE_1_0.txt or copy at", |
---|
| 21 | "http://www.boost.org/LICENSE_1_0.txt)" |
---|
| 22 | }; |
---|
| 23 | |
---|
| 24 | fileview::const_iterator |
---|
| 25 | context_before_license(const fileview& v, fileview::const_iterator start, |
---|
| 26 | int context_lines = 3) |
---|
| 27 | { |
---|
| 28 | char last_char = '\0'; |
---|
| 29 | while (start != v.begin() && context_lines >= 0) { |
---|
| 30 | if (*start == '\r' || *start == '\n' |
---|
| 31 | && (last_char == *start || (last_char != '\r' && last_char != '\n'))) |
---|
| 32 | --context_lines; |
---|
| 33 | |
---|
| 34 | last_char = *start; |
---|
| 35 | --start; |
---|
| 36 | } |
---|
| 37 | |
---|
| 38 | // Unless we hit the beginning, we need to step forward one to start |
---|
| 39 | // on the next line. |
---|
| 40 | if (start != v.begin()) ++start; |
---|
| 41 | |
---|
| 42 | return start; |
---|
| 43 | } |
---|
| 44 | |
---|
| 45 | fileview::const_iterator |
---|
| 46 | context_after_license(const fileview& v, fileview::const_iterator end, |
---|
| 47 | int context_lines = 3) |
---|
| 48 | { |
---|
| 49 | char last_char = '\0'; |
---|
| 50 | while (end != v.end() && context_lines >= 0) { |
---|
| 51 | if (*end == '\r' || *end == '\n' |
---|
| 52 | && (last_char == *end || (last_char != '\r' && last_char != '\n'))) |
---|
| 53 | --context_lines; |
---|
| 54 | |
---|
| 55 | last_char = *end; |
---|
| 56 | ++end; |
---|
| 57 | } |
---|
| 58 | |
---|
| 59 | return end; |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | static std::string |
---|
| 63 | find_prefix(const fileview& v, fileview::const_iterator start_of_line) |
---|
| 64 | { |
---|
| 65 | while (start_of_line != v.begin() |
---|
| 66 | && *start_of_line != '\n' |
---|
| 67 | && *start_of_line != '\r') |
---|
| 68 | --start_of_line; |
---|
| 69 | if (start_of_line != v.begin()) |
---|
| 70 | ++start_of_line; |
---|
| 71 | |
---|
| 72 | fileview::const_iterator first_noncomment_char = start_of_line; |
---|
| 73 | while (*first_noncomment_char == '/' |
---|
| 74 | || *first_noncomment_char == '*' |
---|
| 75 | || *first_noncomment_char == ' ' |
---|
| 76 | || *first_noncomment_char == '#') |
---|
| 77 | ++first_noncomment_char; |
---|
| 78 | |
---|
| 79 | return std::string(start_of_line, first_noncomment_char); |
---|
| 80 | } |
---|
| 81 | |
---|
| 82 | static std::string |
---|
| 83 | html_escape(fileview::const_iterator first, fileview::const_iterator last) |
---|
| 84 | { |
---|
| 85 | std::string result; |
---|
| 86 | while (first != last) { |
---|
| 87 | switch (*first) { |
---|
| 88 | case '<': result += "<"; break; |
---|
| 89 | case '>': result += ">"; break; |
---|
| 90 | case '&': result += "&"; break; |
---|
| 91 | default: result += *first; |
---|
| 92 | } |
---|
| 93 | ++first; |
---|
| 94 | } |
---|
| 95 | return result; |
---|
| 96 | } |
---|
| 97 | |
---|
| 98 | static bool is_non_bsl_license(int index) |
---|
| 99 | { |
---|
| 100 | return index > 2; |
---|
| 101 | } |
---|
| 102 | |
---|
| 103 | void bcp_implementation::scan_license(const fs::path& p, const fileview& v) |
---|
| 104 | { |
---|
| 105 | std::pair<const license_info*, int> licenses = get_licenses(); |
---|
| 106 | // |
---|
| 107 | // scan file for all the licenses in the list: |
---|
| 108 | // |
---|
| 109 | int license_count = 0; |
---|
| 110 | int author_count = 0; |
---|
| 111 | int nonbsl_author_count = 0; |
---|
| 112 | bool has_non_bsl_license = false; |
---|
| 113 | fileview::const_iterator start_of_license = v.begin(), |
---|
| 114 | end_of_license = v.end(); |
---|
| 115 | bool start_in_middle_of_line = false; |
---|
| 116 | |
---|
| 117 | for(int i = 0; i < licenses.second; ++i) |
---|
| 118 | { |
---|
| 119 | boost::match_results<fileview::const_iterator> m; |
---|
| 120 | if(boost::regex_search(v.begin(), v.end(), m, licenses.first[i].license_signature)) |
---|
| 121 | { |
---|
| 122 | start_of_license = m[0].first; |
---|
| 123 | end_of_license = m[0].second; |
---|
| 124 | |
---|
| 125 | if (is_non_bsl_license(i) && i < licenses.second - 1) |
---|
| 126 | has_non_bsl_license = true; |
---|
| 127 | |
---|
| 128 | // add this license to the list: |
---|
| 129 | m_license_data[i].files.insert(p); |
---|
| 130 | ++license_count; |
---|
| 131 | // |
---|
| 132 | // scan for the associated copyright declarations: |
---|
| 133 | // |
---|
| 134 | boost::regex_iterator<const char*> cpy(v.begin(), v.end(), licenses.first[i].copyright_signature); |
---|
| 135 | boost::regex_iterator<const char*> ecpy; |
---|
| 136 | while(cpy != ecpy) |
---|
| 137 | { |
---|
| 138 | #if 0 |
---|
| 139 | // Not dealing with copyrights because we don't have the years |
---|
| 140 | if ((*cpy)[0].first < start_of_license) |
---|
| 141 | start_of_license = (*cpy)[0].first; |
---|
| 142 | if ((*cpy)[0].second > end_of_license) |
---|
| 143 | end_of_license = (*cpy)[0].second; |
---|
| 144 | #endif |
---|
| 145 | |
---|
| 146 | // extract the copy holders as a list: |
---|
| 147 | std::string author_list = cpy->format(licenses.first[i].copyright_formatter, boost::format_all); |
---|
| 148 | // now enumerate that list for all the names: |
---|
| 149 | static const boost::regex author_separator("(?:\\s*,(?!\\s*(?:inc|ltd)\\b)\\s*|\\s+(,\\s*)?(and|&)\\s+)|by\\s+", boost::regex::perl | boost::regex::icase); |
---|
| 150 | boost::regex_token_iterator<std::string::const_iterator> atr(author_list.begin(), author_list.end(), author_separator, -1); |
---|
| 151 | boost::regex_token_iterator<std::string::const_iterator> eatr; |
---|
| 152 | while(atr != eatr) |
---|
| 153 | { |
---|
| 154 | // get the reformatted authors name: |
---|
| 155 | std::string name = format_authors_name(*atr); |
---|
| 156 | // add to list of authors for this file: |
---|
| 157 | if(name.size() && name[0] != '-') |
---|
| 158 | { |
---|
| 159 | m_license_data[i].authors.insert(name); |
---|
| 160 | // add file to author index: |
---|
| 161 | m_author_data[name].insert(p); |
---|
| 162 | ++author_count; |
---|
| 163 | |
---|
| 164 | // If this is not the Boost Software License (license 0), and the author hasn't given |
---|
| 165 | // blanket permission, note this for the report. |
---|
| 166 | if (has_non_bsl_license |
---|
| 167 | && m_bsl_authors.find(name) == m_bsl_authors.end()) { |
---|
| 168 | ++nonbsl_author_count; |
---|
| 169 | m_authors_for_bsl_migration.insert(name); |
---|
| 170 | } |
---|
| 171 | } |
---|
| 172 | ++atr; |
---|
| 173 | } |
---|
| 174 | ++cpy; |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | while (start_of_license != v.begin() |
---|
| 178 | && *start_of_license != '\r' |
---|
| 179 | && *start_of_license != '\n' |
---|
| 180 | && *start_of_license != '.') |
---|
| 181 | --start_of_license; |
---|
| 182 | |
---|
| 183 | if (start_of_license != v.begin()) { |
---|
| 184 | if (*start_of_license == '.') |
---|
| 185 | start_in_middle_of_line = true; |
---|
| 186 | ++start_of_license; |
---|
| 187 | } |
---|
| 188 | |
---|
| 189 | while (end_of_license != v.end() |
---|
| 190 | && *end_of_license != '\r' |
---|
| 191 | && *end_of_license != '\n') |
---|
| 192 | ++end_of_license; |
---|
| 193 | } |
---|
| 194 | } |
---|
| 195 | if(license_count == 0) |
---|
| 196 | m_unknown_licenses.insert(p); |
---|
| 197 | if(license_count && !author_count) |
---|
| 198 | m_unknown_authors.insert(p); |
---|
| 199 | |
---|
| 200 | if (has_non_bsl_license) { |
---|
| 201 | bool converted = false; |
---|
| 202 | if (nonbsl_author_count == 0 |
---|
| 203 | && license_count == 1) { |
---|
| 204 | // Grab a few lines of context |
---|
| 205 | fileview::const_iterator context_start = |
---|
| 206 | context_before_license(v, start_of_license); |
---|
| 207 | fileview::const_iterator context_end = |
---|
| 208 | context_after_license(v, end_of_license); |
---|
| 209 | |
---|
| 210 | // TBD: For files that aren't C++ code, this will have to |
---|
| 211 | // change. |
---|
| 212 | std::string prefix = find_prefix(v, start_of_license); |
---|
| 213 | |
---|
| 214 | // Create enough information to permit manual verification of |
---|
| 215 | // the correctness of the transformation |
---|
| 216 | std::string before_conversion = |
---|
| 217 | html_escape(context_start, start_of_license); |
---|
| 218 | before_conversion += "<b>"; |
---|
| 219 | before_conversion += html_escape(start_of_license, end_of_license); |
---|
| 220 | before_conversion += "</b>"; |
---|
| 221 | before_conversion += html_escape(end_of_license, context_end); |
---|
| 222 | |
---|
| 223 | std::string after_conversion = |
---|
| 224 | html_escape(context_start, start_of_license); |
---|
| 225 | if (start_in_middle_of_line) |
---|
| 226 | after_conversion += '\n'; |
---|
| 227 | |
---|
| 228 | after_conversion += "<b>"; |
---|
| 229 | for (int i = 0; i < boost_license_lines; ++i) { |
---|
| 230 | if (i > 0) after_conversion += '\n'; |
---|
| 231 | after_conversion += prefix + boost_license_text[i]; |
---|
| 232 | } |
---|
| 233 | after_conversion += "</b>"; |
---|
| 234 | after_conversion += html_escape(end_of_license, context_end); |
---|
| 235 | |
---|
| 236 | m_converted_to_bsl[p] = |
---|
| 237 | std::make_pair(before_conversion, after_conversion); |
---|
| 238 | |
---|
| 239 | // Perform the actual conversion |
---|
| 240 | if (m_bsl_convert_mode) { |
---|
| 241 | try{ |
---|
| 242 | std::ofstream out((m_boost_path / p).native_file_string().c_str()); |
---|
| 243 | if (!out) { |
---|
| 244 | std::string msg("Cannot open file for license conversion: "); |
---|
| 245 | msg += p.native_file_string(); |
---|
| 246 | std::runtime_error e(msg); |
---|
| 247 | boost::throw_exception(e); |
---|
| 248 | } |
---|
| 249 | |
---|
| 250 | out << std::string(v.begin(), start_of_license); |
---|
| 251 | if (start_in_middle_of_line) |
---|
| 252 | out << std::endl; |
---|
| 253 | |
---|
| 254 | for (int j = 0; j < boost_license_lines; ++j) { |
---|
| 255 | if (j > 0) out << std::endl; |
---|
| 256 | out << prefix << boost_license_text[j]; |
---|
| 257 | } |
---|
| 258 | out << std::string(end_of_license, v.end()); |
---|
| 259 | |
---|
| 260 | converted = true; |
---|
| 261 | } |
---|
| 262 | catch(const std::exception& e) |
---|
| 263 | { |
---|
| 264 | std::cerr << e.what() << std::endl; |
---|
| 265 | } |
---|
| 266 | } |
---|
| 267 | } |
---|
| 268 | |
---|
| 269 | if (!converted) { |
---|
| 270 | if (nonbsl_author_count > 0) m_cannot_migrate_to_bsl.insert(p); |
---|
| 271 | else m_can_migrate_to_bsl.insert(p); |
---|
| 272 | } |
---|
| 273 | } |
---|
| 274 | } |
---|
| 275 | |
---|