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
17const int boost_license_lines = 3;
18static 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
24fileview::const_iterator
25context_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
45fileview::const_iterator
46context_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
62static std::string
63find_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
82static std::string
83html_escape(fileview::const_iterator first, fileview::const_iterator last)
84{
85 std::string result;
86 while (first != last) {
87 switch (*first) {
88 case '<': result += "&lt;"; break;
89 case '>': result += "&gt;"; break;
90 case '&': result += "&amp;"; break;
91 default: result += *first;
92 }
93 ++first;
94 }
95 return result;
96}
97
98static bool is_non_bsl_license(int index)
99{
100 return index > 2;
101}
102
103void 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(first: v.begin(), last: v.end(), m, e: 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(index: 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(x: 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(fmt: licenses.first[i].copyright_formatter, flags: 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(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(x: name);
160 // add file to author index:
161 m_author_data[name].insert(x: 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(x: name) == m_bsl_authors.end()) {
168 ++nonbsl_author_count;
169 m_authors_for_bsl_migration.insert(x: 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(x: p);
197 if(license_count && !author_count)
198 m_unknown_authors.insert(x: 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: start_of_license);
207 fileview::const_iterator context_end =
208 context_after_license(v, end: 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_line: 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(first: context_start, last: start_of_license);
218 before_conversion += "<b>";
219 before_conversion += html_escape(first: start_of_license, last: end_of_license);
220 before_conversion += "</b>";
221 before_conversion += html_escape(first: end_of_license, last: context_end);
222
223 std::string after_conversion =
224 html_escape(first: context_start, last: 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(first: end_of_license, last: context_end);
235
236 m_converted_to_bsl[p] =
237 std::make_pair(x&: before_conversion, y&: after_conversion);
238
239 // Perform the actual conversion
240 if (m_bsl_convert_mode) {
241 try{
242 std::ofstream out((m_boost_path / p).string().c_str());
243 if (!out) {
244 std::string msg("Cannot open file for license conversion: ");
245 msg += p.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(x: p);
271 else m_can_migrate_to_bsl.insert(x: p);
272 }
273 }
274}
275
276

source code of boost/tools/bcp/scan_licence.cpp