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 <iomanip>
15#include <cstring>
16#include <stdexcept>
17#include <boost/lexical_cast.hpp>
18#include <boost/filesystem/operations.hpp>
19#include <boost/throw_exception.hpp>
20
21//
22// split_path is a small helper for outputting a path name,
23// complete with a link to that path:
24//
25struct split_path
26{
27 const fs::path& root;
28 const fs::path& file;
29 split_path(const fs::path& r, const fs::path& f)
30 : root(r), file(f){}
31private:
32 split_path& operator=(const split_path&);
33};
34
35std::ostream& operator << (std::ostream& os, const split_path& p)
36{
37 os << "<a href=\"" << (p.root / p.file).string() << "\">" << p.file.string() << "</a>";
38 return os;
39}
40
41std::string make_link_target(const std::string& s)
42{
43 // convert an arbitrary string into something suitable
44 // for an <a> name:
45 std::string result;
46 for(unsigned i = 0; i < s.size(); ++i)
47 {
48 result.append(n: 1, c: static_cast<std::string::value_type>(std::isalnum(s[i]) ? s[i] : '_'));
49 }
50 return result;
51}
52
53
54void bcp_implementation::output_license_info()
55{
56 std::pair<const license_info*, int> licenses = get_licenses();
57
58 std::map<int, license_data>::const_iterator i, j;
59 i = m_license_data.begin();
60 j = m_license_data.end();
61
62 std::ofstream os(m_dest_path.string().c_str());
63 if(!os)
64 {
65 std::string msg("Error opening ");
66 msg += m_dest_path.string();
67 msg += " for output.";
68 std::runtime_error e(msg);
69 boost::throw_exception(e);
70 }
71 os <<
72 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
73 "<html>\n"
74 "<head>\n"
75 "<title>Boost Licence Dependency Information";
76 if(m_module_list.size() == 1)
77 {
78 os << " for " << *(m_module_list.begin());
79 }
80 os <<
81 "</title>\n"
82 "</head>\n"
83 "<body>\n"
84 "<H1>Boost Licence Dependency Information";
85 if(m_module_list.size() == 1)
86 {
87 os << " for " << *(m_module_list.begin());
88 }
89 os <<
90 "</H1>\n"
91 "<H2>Contents</h2>\n"
92 "<pre><a href=\"#input\">Input Information</a>\n";
93 if(!m_bsl_summary_mode)
94 os << "<a href=\"#summary\">Licence Summary</a>\n";
95 os << "<a href=\"#details\">Licence Details</a>\n";
96
97 while(i != j)
98 {
99 // title:
100 os << " <A href=\"#" << make_link_target(s: licenses.first[i->first].license_name)
101 << "\">" << licenses.first[i->first].license_name << "</a>\n";
102 ++i;
103 }
104
105 os << "<a href=\"#files\">Files with no recognised license</a>\n"
106 "<a href=\"#authors\">Files with no recognised copyright holder</a>\n";
107 if(!m_bsl_summary_mode)
108 {
109 os <<
110 "Moving to the Boost Software License...\n"
111 " <a href=\"#bsl-converted\">Files that can be automatically converted to the Boost Software License</a>\n"
112 " <a href=\"#to-bsl\">Files that can be manually converted to the Boost Software License</a>\n"
113 " <a href=\"#not-to-bsl\">Files that can <b>NOT</b> be moved to the Boost Software License</a>\n"
114 " <a href=\"#need-bsl-authors\">Authors we need to move to the Boost Software License</a>\n"
115 "<a href=\"#copyright\">Copyright Holder Information</a>\n";
116 }
117 os <<
118 "<a href=\"#depend\">File Dependency Information</a>\n"
119 "</pre>";
120
121 //
122 // input Information:
123 //
124 os << "<a name=\"input\"></a><h2>Input Information</h2>\n";
125 if(m_scan_mode)
126 os << "<P>The following files were scanned for boost dependencies:<BR>";
127 else
128 os << "<P>The following Boost modules were checked:<BR>";
129
130 std::list<std::string>::const_iterator si = m_module_list.begin();
131 std::list<std::string>::const_iterator sj = m_module_list.end();
132 while(si != sj)
133 {
134 os << *si << "<BR>";
135 ++si;
136 }
137 os << "</p><p>The Boost path was: <code>" << m_boost_path.string() << "</code></P>";
138 //
139 // extract the boost version number from the boost directory tree,
140 // not from this app (which may have been built from a previous
141 // version):
142 //
143 fileview version_file(m_boost_path / "boost/version.hpp");
144 static const boost::regex version_regex(
145 "^[[:blank:]]*#[[:blank:]]*define[[:blank:]]+BOOST_VERSION[[:blank:]]+(\\d+)");
146 boost::cmatch what;
147 if(boost::regex_search(first: version_file.begin(), last: version_file.end(), m&: what, e: version_regex))
148 {
149 int version = boost::lexical_cast<int>(arg: what.str(sub: 1));
150 os << "<p>The Boost version is: " << version / 100000 << "." << version / 100 % 1000 << "." << version % 100 << "</P>\n";
151 }
152
153 //
154 // output each license:
155 //
156 i = m_license_data.begin();
157 j = m_license_data.end();
158 if(!m_bsl_summary_mode)
159 {
160 //
161 // start with the summary:
162 //
163 os << "<a name=\"summary\"></a><h2>Licence Summary</h2>\n";
164 while(i != j)
165 {
166 // title:
167 os <<
168 "<H3>" << licenses.first[i->first].license_name << "</H3>\n";
169 // license text:
170 os << "<BLOCKQUOTE>" << licenses.first[i->first].license_text << "</BLOCKQUOTE>";
171 // Copyright holders:
172 os << "<P>This license is used by " << i->second.authors.size()
173 << " authors and " << i->second.files.size()
174 << " files <a href=\"#" << make_link_target(s: licenses.first[i->first].license_name) << "\">(see details)</a>";
175 os << "</P></BLOCKQUOTE>\n";
176 ++i;
177 }
178 }
179 //
180 // and now the details:
181 //
182 i = m_license_data.begin();
183 j = m_license_data.end();
184 int license_index = 0;
185 os << "<a name=\"details\"></a><h2>Licence Details</h2>\n";
186 while(i != j)
187 {
188 // title:
189 os <<
190 "<H3><A name=\"" << make_link_target(s: licenses.first[i->first].license_name)
191 << "\"></a>" << licenses.first[i->first].license_name << "</H3>\n";
192 // license text:
193 os << "<BLOCKQUOTE>" << licenses.first[i->first].license_text << "</BLOCKQUOTE>";
194 if(!m_bsl_summary_mode || (license_index >= 3))
195 {
196 // Copyright holders:
197 os << "<P>This license is used by the following " << i->second.authors.size() << " copyright holders:</P>\n<BLOCKQUOTE><P>";
198 std::set<std::string>::const_iterator x, y;
199 x = i->second.authors.begin();
200 y = i->second.authors.end();
201 while(x != y)
202 {
203 os << *x << "<BR>\n";
204 ++x;
205 }
206 os << "</P></BLOCKQUOTE>\n";
207 // Files using this license:
208 os << "<P>This license applies to the following " << i->second.files.size() << " files:</P>\n<BLOCKQUOTE><P>";
209 std::set<fs::path, path_less>::const_iterator m, n;
210 m = i->second.files.begin();
211 n = i->second.files.end();
212 while(m != n)
213 {
214 os << split_path(m_boost_path, *m) << "<br>\n";
215 ++m;
216 }
217 os << "</P></BLOCKQUOTE>\n";
218 }
219 else
220 {
221 os << "<P>This license is used by " << i->second.authors.size() << " authors (list omitted for brevity).</P>\n";
222 os << "<P>This license applies to " << i->second.files.size() << " files (list omitted for brevity).</P>\n";
223 }
224 ++license_index;
225 ++i;
226 }
227 //
228 // Output list of files not found to be under license control:
229 //
230 os << "<h2><a name=\"files\"></a>Files With No Recognisable Licence</h2>\n"
231 "<P>The following " << m_unknown_licenses.size() << " files had no recognisable license information:</P><BLOCKQUOTE><P>\n";
232 std::set<fs::path, path_less>::const_iterator i2, j2;
233 i2 = m_unknown_licenses.begin();
234 j2 = m_unknown_licenses.end();
235 while(i2 != j2)
236 {
237 os << split_path(m_boost_path, *i2) << "<br>\n";
238 ++i2;
239 }
240 os << "</p></BLOCKQUOTE>";
241 //
242 // Output list of files with no found copyright holder:
243 //
244 os << "<h2><a name=\"authors\"></a>Files With No Recognisable Copyright Holder</h2>\n"
245 "<P>The following " << m_unknown_authors.size() << " files had no recognisable copyright holder:</P>\n<BLOCKQUOTE><P>";
246 i2 = m_unknown_authors.begin();
247 j2 = m_unknown_authors.end();
248 while(i2 != j2)
249 {
250 os << split_path(m_boost_path, *i2) << "<br>\n";
251 ++i2;
252 }
253 os << "</p></BLOCKQUOTE>";
254 if(!m_bsl_summary_mode)
255 {
256 //
257 // Output list of files that have been moved over to the Boost
258 // Software License, along with enough information for human
259 // verification.
260 //
261 os << "<h2><a name=\"bsl-converted\"></a>Files that can be automatically converted to the Boost Software License</h2>\n"
262 << "<P>The following " << m_converted_to_bsl.size() << " files can be automatically converted to the Boost Software License, but require manual verification before they can be committed to CVS:</P>\n";
263 if (!m_converted_to_bsl.empty())
264 {
265 typedef std::map<fs::path, std::pair<std::string, std::string>, path_less>
266 ::const_iterator conv_iterator;
267 conv_iterator i = m_converted_to_bsl.begin(),
268 ie = m_converted_to_bsl.end();
269 int file_num = 1;
270 while (i != ie)
271 {
272 os << "<P>[" << file_num << "] File: <tt>" << split_path(m_boost_path, i->first)
273 << "</tt><br>\n<table border=\"1\">\n <tr>\n <td><pre>"
274 << i->second.first << "</pre></td>\n <td><pre>"
275 << i->second.second << "</pre></td>\n </tr>\n</table>\n";
276 ++i;
277 ++file_num;
278 }
279 }
280 //
281 // Output list of files that could be moved over to the Boost Software License
282 //
283 os << "<h2><a name=\"to-bsl\"></a>Files that could be converted to the Boost Software License</h2>\n"
284 "<P>The following " << m_can_migrate_to_bsl.size() << " files could be manually converted to the Boost Software License, but have not yet been:</P>\n<BLOCKQUOTE><P>";
285 i2 = m_can_migrate_to_bsl.begin();
286 j2 = m_can_migrate_to_bsl.end();
287 while(i2 != j2)
288 {
289 os << split_path(m_boost_path, *i2) << "<br>\n";
290 ++i2;
291 }
292 os << "</p></BLOCKQUOTE>";
293 //
294 // Output list of files that can not be moved over to the Boost Software License
295 //
296 os << "<h2><a name=\"not-to-bsl\"></a>Files that can NOT be converted to the Boost Software License</h2>\n"
297 "<P>The following " << m_cannot_migrate_to_bsl.size() << " files cannot be converted to the Boost Software License because we need the permission of more authors:</P>\n<BLOCKQUOTE><P>";
298 i2 = m_cannot_migrate_to_bsl.begin();
299 j2 = m_cannot_migrate_to_bsl.end();
300 while(i2 != j2)
301 {
302 os << split_path(m_boost_path, *i2) << "<br>\n";
303 ++i2;
304 }
305 os << "</p></BLOCKQUOTE>";
306 //
307 // Output list of authors that we need permission for to move to the BSL
308 //
309 os << "<h2><a name=\"need-bsl-authors\"></a>Authors we need for the BSL</h2>\n"
310 "<P>Permission of the following authors is needed before we can convert to the Boost Software License. The list of authors that have given their permission is contained in <code>more/blanket-permission.txt</code>.</P>\n<BLOCKQUOTE><P>";
311 std::copy(first: m_authors_for_bsl_migration.begin(), last: m_authors_for_bsl_migration.end(),
312 result: std::ostream_iterator<std::string>(os, "<br>\n"));
313 os << "</p></BLOCKQUOTE>";
314 //
315 // output a table of copyright information:
316 //
317 os << "<H2><a name=\"copyright\"></a>Copyright Holder Information</H2><table border=\"1\">\n";
318 std::map<std::string, std::set<fs::path, path_less> >::const_iterator ad, ead;
319 ad = m_author_data.begin();
320 ead = m_author_data.end();
321 while(ad != ead)
322 {
323 os << "<tr><td>" << ad->first << "</td><td>";
324 std::set<fs::path, path_less>::const_iterator fi, efi;
325 fi = ad->second.begin();
326 efi = ad->second.end();
327 while(fi != efi)
328 {
329 os << split_path(m_boost_path, *fi) << " ";
330 ++fi;
331 }
332 os << "</td></tr>\n";
333 ++ad;
334 }
335 os << "</table>\n";
336 }
337
338 //
339 // output file dependency information:
340 //
341 os << "<H2><a name=\"depend\"></a>File Dependency Information</H2><BLOCKQUOTE><pre>\n";
342 std::map<fs::path, fs::path, path_less>::const_iterator dep, last_dep;
343 std::set<fs::path, path_less>::const_iterator fi, efi;
344 fi = m_copy_paths.begin();
345 efi = m_copy_paths.end();
346 // if in summary mode, just figure out the "bad" files and print those only:
347 std::set<fs::path, path_less> bad_paths;
348 if(m_bsl_summary_mode)
349 {
350 bad_paths.insert(first: m_unknown_licenses.begin(), last: m_unknown_licenses.end());
351 bad_paths.insert(first: m_unknown_authors.begin(), last: m_unknown_authors.end());
352 bad_paths.insert(first: m_can_migrate_to_bsl.begin(), last: m_can_migrate_to_bsl.end());
353 bad_paths.insert(first: m_cannot_migrate_to_bsl.begin(), last: m_cannot_migrate_to_bsl.end());
354 typedef std::map<fs::path, std::pair<std::string, std::string>, path_less>
355 ::const_iterator conv_iterator;
356 conv_iterator i = m_converted_to_bsl.begin(),
357 ie = m_converted_to_bsl.end();
358 while(i != ie)
359 {
360 bad_paths.insert(x: i->first);
361 ++i;
362 }
363 fi = bad_paths.begin();
364 efi = bad_paths.end();
365 os << "<P>For brevity, only files not under the BSL are shown</P>\n";
366 }
367 while(fi != efi)
368 {
369 os << split_path(m_boost_path, *fi);
370 dep = m_dependencies.find(x: *fi);
371 last_dep = m_dependencies.end();
372 std::set<fs::path, path_less> seen_deps;
373 if (dep != last_dep)
374 while(true)
375 {
376 os << " -> ";
377 if(fs::exists(p: m_boost_path / dep->second))
378 os << split_path(m_boost_path, dep->second);
379 else if(fs::exists(p: dep->second))
380 os << split_path(fs::path(), dep->second);
381 else
382 os << dep->second.string();
383 if(seen_deps.find(x: dep->second) != seen_deps.end())
384 {
385 os << " <I>(Circular dependency!)</I>";
386 break; // circular dependency!!!
387 }
388 seen_deps.insert(x: dep->second);
389 last_dep = dep;
390 dep = m_dependencies.find(x: dep->second);
391 if((dep == m_dependencies.end()) || (0 == compare_paths(a: dep->second, b: last_dep->second)))
392 break;
393 }
394 os << "\n";
395 ++fi;
396 }
397 os << "</pre></BLOCKQUOTE>\n";
398
399 os << "</body></html>\n";
400
401 if(!os)
402 {
403 std::string msg("Error writing to ");
404 msg += m_dest_path.string();
405 msg += ".";
406 std::runtime_error e(msg);
407 boost::throw_exception(e);
408 }
409
410}
411

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