2 # -*- tab-width: 8; indent-tabs-mode: t; cperl-indent-level: 4 -*-
3 # This script was originally based on the script of the same name from
4 # the KDE SDK (by dfaure@kde.org)
7 # Copyright (C) 2007, 2008 Adam D. Barratt
8 # Copyright (C) 2012 Francesco Poli
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License along
21 # with this program. If not, see <https://www.gnu.org/licenses/>.
23 # Originally copied from Debian's devscripts. A more modern version of
24 # this can be found at
25 # https://anonscm.debian.org/git/pkg-perl/packages/licensecheck.git/
29 licensecheck - simple license checker for source files
33 B<licensecheck> B<--help>|B<--version>
35 B<licensecheck> [B<--no-conf>] [B<--verbose>] [B<--copyright>]
36 [B<-l>|B<--lines=>I<N>] [B<-i>|B<--ignore=>I<regex>] [B<-c>|B<--check=>I<regex>]
37 [B<-m>|B<--machine>] [B<-r>|B<--recursive>] [B<-e>|B<--encoding=>I<...>]
38 I<list of files and directories to check>
42 B<licensecheck> attempts to determine the license that applies to each file
43 passed to it, by searching the start of the file for text belonging to
46 If any of the arguments passed are directories, B<licensecheck> will add
47 the files contained within to the list of files to process.
53 =item B<--verbose>, B<--no-verbose>
55 Specify whether to output the text being processed from each file before
56 the corresponding license information.
58 Default is to be quiet.
60 =item B<-l=>I<N>, B<--lines=>I<N>
62 Specify the number of lines of each file's header which should be parsed
63 for license information. (Default is 60).
67 By default, the last 5k bytes of each files are parsed to get license
68 information. You may use this option to set the size of this parsed chunk.
69 You may set this value to 0 to avoid parsing the end of the file.
71 =item B<-i=>I<regex>, B<--ignore=>I<regex>
73 When processing the list of files and directories, the regular
74 expression specified by this option will be used to indicate those which
75 should not be considered (e.g. backup files, VCS metadata).
77 =item B<-r>, B<--recursive>
79 Specify that the contents of directories should be added
82 =item B<-c=>I<regex>, B<--check=>I<regex>
84 Specify a pattern against which filenames will be matched in order to
85 decide which files to check the license of.
87 The default includes common source files.
89 =item B<-s>, B<--skipped>
91 Specify whether to show skipped files, i.e. files found which do not
92 match the check regexp (see C<--check> option). Default is to not show
95 Note that ignored files (like C<.git> or C<.svn>) are not shown even when
100 Also display copyright text found within the file
102 =item B<-e> B<--encoding>
104 Specifies input encoding of source files. By default, input files are
105 not decoded. When encoding is specified, license and copyright
106 information are printed on STDOUT as utf8, or garbage if you got the
109 =item B<-m>, B<--machine>
111 Display the information in a machine readable way, i.e. in the form
112 <file><tab><license>[<tab><copyright>] so that it can be easily sorted
113 and/or filtered, e.g. with the B<awk> and B<sort> commands.
114 Note that using the B<--verbose> option will kill the readability.
116 =item B<--no-conf>, B<--noconf>
118 Do not read any configuration files. This can only be used as the first
119 option given on the command line.
123 =head1 CONFIGURATION VARIABLES
125 The two configuration files F</etc/devscripts.conf> and
126 F<~/.devscripts> are sourced by a shell in that order to set
127 configuration variables. Command line options can be used to override
128 configuration file settings. Environment variable settings are
129 ignored for this purpose. The currently recognised variables are:
133 =item B<LICENSECHECK_VERBOSE>
135 If this is set to I<yes>, then it is the same as the B<--verbose> command
136 line parameter being used. The default is I<no>.
138 =item B<LICENSECHECK_PARSELINES>
140 If this is set to a positive number then the specified number of lines
141 at the start of each file will be read whilst attempting to determine
142 the license(s) in use. This is equivalent to the B<--lines> command line
149 This code is copyright by Adam D. Barratt <I<adam@adam-barratt.org.uk>>,
150 all rights reserved; based on a script of the same name from the KDE
151 SDK, which is copyright by <I<dfaure@kde.org>>.
152 This program comes with ABSOLUTELY NO WARRANTY.
153 You are free to redistribute this code under the terms of the GNU
154 General Public License, version 2 or later.
158 Adam D. Barratt <adam@adam-barratt.org.uk>
162 # see https://stackoverflow.com/questions/6162484/why-does-modern-perl-avoid-utf-8-by-default/6163129#6163129
169 use warnings qw
< FATAL utf8
>;
171 use Getopt
::Long
qw(:config gnu_getopt);
177 binmode STDOUT
, ':utf8';
179 my $progname = basename
($0);
182 my $default_ignore_regex = qr
!
183 # Ignore general backup files
185 # Ignore emacs recovery files
187 # Ignore vi swap files
189 # Ignore baz-style junk files or directories
190 (?
:^|/),,.*(?:$|/.*$)|
191 # File-names that should be ignored (never directories)
192 (?
:^|/)(?
:DEADJOE
|\
.cvsignore
|\
.arch
-inventory
|\
.bzrignore
|\
.gitignore
)$|
193 # File or directory names that should be ignored
194 (?
:^|/)(?
:CVS
|RCS
|\
.pc
|\
.deps
|\
{arch\
}|\
.arch
-ids
|\
.svn
|\
.hg
|_darcs
|\
.git
|
195 \
.shelf
|_MTN
|\
.bzr
(?
:\
.backup
|tags
)?
)(?
:$|/.*$)
198 # The original Debian version checks Markdown (.md and .markdown) files.
199 # If we add those extensions back, we should add Asciidoctor (.adoc) as
200 # well, and add SPDX IDs to all of those files.
201 my $default_check_regex =
203 \
.( # search for file suffix
204 c
(c
|pp
|xx
)?
# c and c++
205 |h
(h
|pp
|xx
)?
# header files for c and c++
207 |css
|less
# HTML css and similar
214 |p
(l
|m
)?
6?
|t
|xs
|pod6?
# perl5 or perl6
237 # also used to cleanup
238 my $copyright_indicator_regex
240 (?
:copyright
# The full word
241 |copr\
. # Legally-valid abbreviation
242 |\xc2\xa9 # Unicode copyright sign encoded in iso8859
243 |\x
{00a9
} # Unicode character COPYRIGHT SIGN
244 #|© # Unicode character COPYRIGHT SIGN
245 |\
(c\
) # Legally-null representation of sign
249 my $copyright_indicator_regex_with_capture = qr!$copyright_indicator_regex(?::\s*|\s+)(\S.*)$!lix;
251 # avoid ditching things like <info@foo.com>
252 my $copyright_disindicator_regex
254 \b(?
:info
(?
:rmation
)?
(?
!@
) # Discussing copyright information
255 |(notice
|statement
|claim
|string
)s?
# Discussing the notice
256 |is
|in|to
# Part of a sentence
257 |(holder
|owner
)s?
# Part of a sentence
258 |ownership
# Part of a sentence
262 my $copyright_predisindicator_regex
264 ^[#]define\s+.*\(c\) # #define foo(c) -- not copyright
267 my $modified_conf_msg;
283 my $def_tail = 5000; # roughly 60 lines of 80 chars
285 # Read configuration files and then command line
286 # This is boilerplate
288 if (@ARGV and $ARGV[0] =~ /^--no-?conf$/) {
289 $modified_conf_msg = " (no configuration files read)";
292 my @config_files = ('/etc/devscripts.conf', '~/.devscripts');
294 'LICENSECHECK_VERBOSE' => 'no',
295 'LICENSECHECK_PARSELINES' => $def_lines,
297 my %config_default = %config_vars;
301 foreach my $var (keys %config_vars) {
302 $shell_cmd .= qq[$var="$config_vars{$var}";\n];
304 $shell_cmd .= 'for file in ' . join(" ", @config_files) . "; do\n";
305 $shell_cmd .= '[ -f $file ] && . $file; done;' . "\n";
307 foreach my $var (keys %config_vars) { $shell_cmd .= "echo \$$var;\n" }
308 my $shell_out = `/bin/bash -c '$shell_cmd'`;
309 @config_vars{keys %config_vars} = split /\n/, $shell_out, -1;
312 $config_vars{'LICENSECHECK_VERBOSE'} =~ /^(yes|no)$/
313 or $config_vars{'LICENSECHECK_VERBOSE'} = 'no';
314 $config_vars{'LICENSECHECK_PARSELINES'} =~ /^[1-9][0-9]*$/
315 or $config_vars{'LICENSECHECK_PARSELINES'} = $def_lines;
317 foreach my $var (sort keys %config_vars) {
318 if ($config_vars{$var} ne $config_default{$var}) {
319 $modified_conf_msg .= " $var=$config_vars{$var}\n";
322 $modified_conf_msg ||= " (none)\n";
323 chomp $modified_conf_msg;
325 $OPT{'verbose'} = $config_vars{'LICENSECHECK_VERBOSE'} eq 'yes' ?
1 : 0;
326 $OPT{'lines'} = $config_vars{'LICENSECHECK_PARSELINES'};
344 ) or die "Usage: $progname [options] filelist\nRun $progname --help for more details\n";
346 $OPT{'lines'} = $def_lines if $OPT{'lines'} !~ /^[1-9][0-9]*$/;
347 my $ignore_regex = length($OPT{ignore
}) ?
qr/$OPT{ignore}/ : $default_ignore_regex;
349 my $check_regex = $default_check_regex;
350 $check_regex = qr/$OPT{check}/ if length $OPT{check
};
352 if ($OPT{'noconf'}) {
353 fatal
("--no-conf is only acceptable as the first command-line option!");
355 if ($OPT{'help'}) { help
(); exit 0; }
356 if ($OPT{'version'}) { version
(); exit 0; }
359 warn "$0 warning: option -text is deprecated\n"; # remove -text end 2015
362 die "Usage: $progname [options] filelist\nRun $progname --help for more details\n" unless @ARGV;
364 $OPT{'lines'} = $def_lines if not defined $OPT{'lines'};
368 my $files_count = @ARGV;
370 push @find_args, qw(-maxdepth 1) unless $OPT{'recursive'};
371 push @find_args, qw(-follow -type f -print);
374 my $file = shift @ARGV;
377 open my $FIND, '-|', 'find', $file, @find_args
378 or die "$progname: couldn't exec find: $!\n";
380 while (my $found = <$FIND>) {
382 # Silently skip empty files or ignored files
383 next if -z
$found or $found =~ $ignore_regex;
384 if ( not $check_regex or $found =~ $check_regex ) {
385 # Silently skip empty files or ignored files
386 push @files, $found ;
389 warn "skipped file $found\n" if $OPT{skipped
};
394 elsif ($file =~ $ignore_regex) {
395 # Silently skip ignored files
398 elsif ( $files_count == 1 or not $check_regex or $file =~ $check_regex ) {
402 warn "skipped file $file\n" if $OPT{skipped
};
407 my $file = shift @files;
414 my $enc = $OPT{encoding
} ;
415 my $mode = $enc ?
"<:encoding($enc)" : '<';
416 # need to use "<" when encoding is unknown otherwise we break compatibility
417 my $fh = IO
::File
->new ($file ,$mode) or die "Unable to access $file\n";
419 while ( my $line = $fh->getline ) {
420 last if ($fh->input_line_number > $OPT{'lines'});
424 my %copyrights = extract_copyright
($content);
426 print qq(----- $file header
-----\n$content----- end header
-----\n\n)
429 my $license = parselicense
(clean_cruft_and_spaces
(clean_comments
($content)));
430 $copyright = join(" / ", reverse sort values %copyrights);
432 if ( not $copyright and $license eq 'UNKNOWN') {
433 my $position = $fh->tell; # See IO::Seekable
434 my $tail_size = $OPT{tail
} // $def_tail;
435 my $jump = $st->size - $tail_size;
436 $jump = $position if $jump < $position;
439 if ( $tail_size and $jump < $st->size) {
440 $fh->seek($jump, SEEK_SET
) ; # also IO::Seekable
441 $tail .= join('',$fh->getlines);
444 print qq(----- $file tail
-----\n$tail----- end tail
-----\n\n)
447 %copyrights = extract_copyright
($tail);
448 $license = parselicense
(clean_cruft_and_spaces
(clean_comments
($tail)));
449 $copyright = join(" / ", reverse sort values %copyrights);
454 if ($OPT{'machine'}) {
455 print "$file\t$license";
456 print "\t" . ($copyright or "*No copyright*") if $OPT{'copyright'};
460 print "*No copyright* " unless $copyright;
461 print $license . "\n";
462 print " [Copyright: " . $copyright . "]\n"
463 if $copyright and $OPT{'copyright'};
464 print "\n" if $OPT{'copyright'};
468 sub extract_copyright
{
470 my @c = split /\n/, clean_comments
($content);
473 my $lines_after_copyright_block = 0;
475 my $in_copyright_block = 0;
477 my $line = shift @c ;
478 my $copyright_match = parse_copyright
($line, \
$in_copyright_block) ;
479 if ($copyright_match) {
480 while (@c and $copyright_match =~ /\d[,.]?\s*$/) {
481 # looks like copyright end with a year, assume the owner is on next line(s)
482 $copyright_match .= ' '. shift @c;
484 $copyright_match =~ s/\s+/ /g;
485 $copyright_match =~ s/\s*$//;
486 $copyrights{lc("$copyright_match")} = "$copyright_match";
488 elsif (scalar keys %copyrights) {
489 # skip remaining lines if a copyright blocks was found more than 5 lines ago.
490 # so a copyright block may contain up to 5 blank lines, but no more
491 last if $lines_after_copyright_block++ > 5;
497 sub parse_copyright
{
499 my $in_copyright_block_ref = shift;
503 if ( $data !~ $copyright_predisindicator_regex) {
504 #print "match against ->$data<-\n";
505 if ($data =~ $copyright_indicator_regex_with_capture) {
507 $$in_copyright_block_ref = 1;
508 # Ignore lines matching "see foo for copyright information" etc.
509 if ($match !~ $copyright_disindicator_regex) {
511 $match =~ s/$copyright_indicator_regex//igx;
513 $match =~ s/\s*\bby\b\s*/ /;
514 $match =~ s/([,.])?\s*$//;
515 $match =~ s/\s{2,}/ /g;
516 $match =~ s/\\//g; # de-cruft nroff files
517 $match =~ s/\s*[*#]\s*$//;
521 elsif ($$in_copyright_block_ref and $data =~ /^\d{2,}[,\s]+/) {
522 # following lines beginning with a year are supposed to be
523 # continued copyright blocks
527 $$in_copyright_block_ref = 0;
535 local $_ = shift or return q{};
537 # Remove generic comments: look for 4 or more lines beginning with
538 # regular comment pattern and trim it. Fall back to old algorithm
539 # if no such pattern found.
540 my @matches = m/^\s*((?:[^a-zA-Z0-9\s]{1,3}|\bREM\b))\s\w/mg;
542 my $comment_re = qr/\s*[\Q$matches[0]\E]{1,3}\s*/;
546 # Remove Fortran comments
549 # Remove C / C++ comments
555 sub clean_cruft_and_spaces
{
556 local $_ = shift or return q{};
560 # this also removes quotes
561 tr
% A
-Za
-z
.+,@
:;0-9\
(\
)/-%%cd;
569 Usage: $progname [options] filename [filename ...]
571 --help, -h Display this message
572 --version, -v Display version and copyright info
573 --no-conf, --noconf Don't read devscripts config files; must be
574 the first option given
575 --verbose Display the header of each file before its
577 --skipped, -s Show skipped files
578 --lines, -l Specify how many lines of the file header
579 should be parsed for license information
580 (Default: $def_lines)
581 --tail Specify how many bytes to parse at end of file
583 --check, -c Specify a pattern indicating which files should
585 (Default: '$default_check_regex')
586 --machine, -m Display in a machine readable way (good for awk)
587 --recursive, -r Add the contents of directories recursively
588 --copyright Also display the file's copyright
589 --ignore, -i Specify that files / directories matching the
590 regular expression should be ignored when
592 (Default: '$default_ignore_regex')
594 Default settings modified by devscripts configuration files:
601 This is $progname, from the Debian devscripts package, version 2.16.2
602 Copyright (C) 2007, 2008 by Adam D. Barratt <adam\@adam-barratt.org.uk>; based
603 on a script of the same name from the KDE SDK by <dfaure\@kde.org>.
605 This program comes with ABSOLUTELY NO WARRANTY.
606 You are free to redistribute this code under the terms of the
607 GNU General Public License, version 2, or (at your option) any
613 my ($licensetext) = @_;
619 if ($licensetext =~ /version ([^ ]+)(?: of the License)?,? or(?: \(at your option\))? version (\d(?:[.-]\d+)*)/) {
620 $gplver = " (v$1 or v$2)";
621 } elsif ($licensetext =~ /version ([^, ]+?)[.,]? (?:\(?only\)?.? )?(?:of the GNU (Affero )?(Lesser |Library )?General Public License )?(as )?published by the Free Software Foundation/i or
622 $licensetext =~ /GNU (?:Affero )?(?:Lesser |Library )?General Public License (?:as )?published by the Free Software Foundation[;,] version ([^, ]+?)[.,]? /i) {
625 } elsif ($licensetext =~ /GNU (?:Affero )?(?:Lesser |Library )?General Public License\s*(?:[(),GPL]+)\s*version (\d+(?:\.\d+)?)[ \.]/i) {
627 } elsif ($licensetext =~ /either version ([^ ]+)(?: of the License)?, or (?:\(at your option\) )?any later version/) {
628 $gplver = " (v$1 or later)";
629 } elsif ($licensetext =~ /GPL\sas\spublished\sby\sthe\sFree\sSoftware\sFoundation,\sversion\s([\d.]+)/i ) {
631 } elsif ($licensetext =~ /SPDX-License-Identifier:\s+GPL-([1-9])\.0-or-later/i ){
632 $gplver = " (v$1 or later)";
633 } elsif ($licensetext =~ /SPDX-License-Identifier:\s+GPL-([1-9])\.0[^+]/i ) {
635 } elsif ($licensetext =~ /SPDX-License-Identifier:\s+GPL-([1-9])\.0\+/i ) {
636 $gplver = " (v$1 or later)";
637 } elsif ($licensetext =~ /SPDX-License-Identifier:\s+LGPL-([1-9])\.[0-1]\-or-later/i ) {
638 $gplver = " (v$1 or later)";
641 if ($licensetext =~ /(?:675 Mass Ave|59 Temple Place|51 Franklin Steet|02139|02111-1307)/i) {
642 $extrainfo = " (with incorrect FSF address)$extrainfo";
645 if ($licensetext =~ /permission (?:is (also granted|given))? to link (the code of )?this program with (any edition of )?(Qt|the Qt library)/i) {
646 $extrainfo = " (with Qt exception)$extrainfo"
649 if ($licensetext =~ /As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice/) {
650 $extrainfo = " (with Bison parser exception)$extrainfo";
653 # exclude blurb found in boost license text
654 if ($licensetext =~ /(All changes made in this file will be lost|DO NOT (EDIT|delete this file)|Generated (automatically|by|from)|generated.*file)/i
655 and $licensetext !~ /unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor/) {
656 $license = "GENERATED FILE";
659 if ($licensetext =~ /(are made available|(is free software.? )?you can redistribute (it|them) and(?:\/|\s
+)or modify
(it
|them
)|is licensed
) under the terms of
(version
[^ ]+ of
)?the
(GNU
(Library
|Lesser
)General Public License
|LGPL
)/i
) {
660 $license = "LGPL$gplver$extrainfo $license";
662 # For Perl modules handled by Dist::Zilla
663 elsif ($licensetext =~ /this is free software,? licensed under:? (?:the )?(?:GNU (?:Library |Lesser )General Public License|LGPL),? version ([\d\.]+)/i) {
664 $license = "LGPL (v$1) $license";
667 if ($licensetext =~ /is free software.? you can redistribute (it|them) and(?:\/|\s
+)or modify
(it
|them
) under the terms of the
(GNU Affero General Public License
|AGPL
)/i
) {
668 $license = "AGPL$gplver$extrainfo $license";
671 if ($licensetext =~ /(is free software.? )?you (can|may) redistribute (it|them) and(?:\/|\s
+)or modify
(it
|them
) under the terms of
(?
:version
[^ ]+ (?
:\
(?only\
)?
)?of
)?the GNU General Public License
/i
) {
672 $license = "GPL$gplver$extrainfo $license";
675 if ($licensetext =~ /is distributed under the terms of the GNU General Public License,/
676 and length $gplver) {
677 $license = "GPL$gplver$extrainfo $license";
680 if ($licensetext =~ /SPDX-License-Identifier:\s+GPL/i and length $gplver) {
681 $license = "GPL$gplver$extrainfo $license";
684 if ($licensetext =~ /SPDX-License-Identifier:\s+GPL-2.0-or-later/i and length $gplver) {
685 $license = "GPL$gplver$extrainfo";
688 if ($licensetext =~ /SPDX-License-Identifier:\s+LGPL/i and length $gplver) {
689 $license = "LGPL$gplver$extrainfo $license";
692 if ($licensetext =~ /SPDX-License-Identifier:\s+Zlib/i) {
693 $license = "zlib/libpng $license";
696 if ($licensetext =~ /SPDX-License-Identifier:\s+BSD-3-Clause/i) {
697 $license = 'BSD (3 clause)';
700 if ($licensetext =~ /SPDX-License-Identifier:\s+BSD-2-Clause/i) {
701 $license = 'BSD (2 clause)';
704 if ($licensetext =~ /SPDX-License-Identifier:\s+BSD-1-Clause/i) {
705 $license = 'BSD (1 clause)';
708 if ($licensetext =~ /SPDX-License-Identifier:\s+MIT/i) {
709 $license = 'MIT/X11 (BSD like)';
712 if ($licensetext =~ /SPDX-License-Identifier:\s+ISC/i) {
716 if ($licensetext =~ /(?:is|may be)\s(?:(?:distributed|used).*?terms|being\s+released).*?\b(L?GPL)\b/) {
717 my $v = $gplver || ' (unversioned/unknown version)';
718 $license = "$1$v $license";
721 if ($licensetext =~ /the rights to distribute and use this software as governed by the terms of the Lisp Lesser General Public License|\bLLGPL\b/ ) {
722 $license = "LLGPL $license";
725 if ($licensetext =~ /This file is part of the .*Qt GUI Toolkit. This file may be distributed under the terms of the Q Public License as defined/) {
726 $license = "QPL (part of Qt) $license";
727 } elsif ($licensetext =~ /may (be distributed|redistribute it) under the terms of the Q Public License/) {
728 $license = "QPL $license";
731 if ($licensetext =~ /opensource\.org\/licenses\
/mit-license\.php/) {
732 $license = "MIT/X11 (BSD like) $license";
733 } elsif ($licensetext =~ /Permission is hereby granted, free of charge, to any person obtaining a copy of this software and(\/or
)? associated documentation files \
(the
(Software
|Materials
)\
), to deal
in the
(Software
|Materials
)/) {
734 $license = "MIT/X11 (BSD like) $license";
735 } elsif ($licensetext =~ /Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose/) {
736 $license = "MIT/X11 (BSD like) $license";
739 if ($licensetext =~ /Permission to use, copy, modify, and(\/or
)? distribute this software
for any purpose with
or without fee is hereby granted
, provided
.*copyright notice
.*permission notice
.*all copies
/) {
740 $license = "ISC $license";
743 if ($licensetext =~ /THIS SOFTWARE IS PROVIDED .*AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY/) {
744 if ($licensetext =~ /All advertising materials mentioning features or use of this software must display the following acknowledge?ment.*This product includes software developed by/i) {
745 $license = "BSD (4 clause) $license";
746 } elsif ($licensetext =~ /(The name(?:\(s\))? .*? may not|Neither the (names? .*?|authors?) nor the names of( (its|their|other|any))? contributors may) be used to endorse or promote products derived from this software/i) {
747 $license = "BSD (3 clause) $license";
748 } elsif ($licensetext =~ /Redistributions in binary form must reproduce the above copyright notice/i) {
749 $license = "BSD (2 clause) $license";
751 $license = "BSD $license";
755 if ($licensetext =~ /Mozilla Public License,? (?:(?:Version|v\.)\s+)?(\d+(?:\.\d+)?)/) {
756 $license = "MPL (v$1) $license";
758 elsif ($licensetext =~ /Mozilla Public License,? \((?:Version|v\.) (\d+(?:\.\d+)?)\)/) {
759 $license = "MPL (v$1) $license";
763 # - the text *begins* with "The Artistic license v2.0" which is (hopefully) the actual artistic license v2.0 text.
764 # - a license grant is found. i.e something like "this is free software, licensed under the artistic license v2.0"
765 if ($licensetext =~ /(?:^\s*|(?:This is free software, licensed|Released|be used|use and modify this (?:module|software)) under (?:the terms of )?)[Tt]he Artistic License ([v\d.]*\d)/) {
766 $license = "Artistic (v$1) $license";
769 if ($licensetext =~ /is free software under the Artistic [Ll]icense/) {
770 $license = "Artistic $license";
773 if ($licensetext =~ /This program is free software; you can redistribute it and\/or modify it under the same terms as Perl itself
/) {
774 $license = "Perl $license";
777 if ($licensetext =~ /under the Apache License, Version ([^ ]+)/) {
778 $license = "Apache (v$1) $license";
781 if ($licensetext =~ /(THE BEER-WARE LICENSE)/i) {
782 $license = "Beerware $license";
785 if ($licensetext =~ /distributed under the terms of the FreeType project/i) {
786 $license = "FreeType $license"; # aka FTL see https://www.freetype.org/license.html
789 if ($licensetext =~ /This source file is subject to version ([^ ]+) of the PHP license/) {
790 $license = "PHP (v$1) $license";
793 if ($licensetext =~ /under the terms of the CeCILL /) {
794 $license = "CeCILL $license";
797 if ($licensetext =~ /under the terms of the CeCILL-([^ ]+) /) {
798 $license = "CeCILL-$1 $license";
801 if ($licensetext =~ /under the SGI Free Software License B/) {
802 $license = "SGI Free Software License B $license";
805 if ($licensetext =~ /is in the public domain/i) {
806 $license = "Public domain $license";
809 if ($licensetext =~ /terms of the Common Development and Distribution License(, Version ([^(]+))? \(the License\)/) {
810 $license = "CDDL " . ($1 ?
"(v$2) " : '') . $license;
813 if ($licensetext =~ /Microsoft Permissive License \(Ms-PL\)/) {
814 $license = "Ms-PL $license";
817 if ($licensetext =~ /Licensed under the Academic Free License version ([\d.]+)/) {
818 $license = $1 ?
"AFL-$1" : "AFL";
821 if ($licensetext =~ /This program and the accompanying materials are made available under the terms of the Eclipse Public License v?([\d.]+)/) {
822 $license = $1 ?
"EPL-$1" : "EPL";
825 # quotes were removed by clean_comments function
826 if ($licensetext =~ /Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license \(the Software\)/ or
827 $licensetext =~ /Boost Software License([ ,-]+Version ([^ ]+)?(\.))/i) {
828 $license = "BSL " . ($1 ?
"(v$2) " : '') . $license;
831 if ($licensetext =~ /PYTHON SOFTWARE FOUNDATION LICENSE (VERSION ([^ ]+))/i) {
832 $license = "PSF " . ($1 ?
"(v$2) " : '') . $license;
835 if ($licensetext =~ /The origin of this software must not be misrepresented.*Altered source versions must be plainly marked as such.*This notice may not be removed or altered from any source distribution/ or
836 $licensetext =~ /see copyright notice in zlib\.h/) {
837 $license = "zlib/libpng $license";
838 } elsif ($licensetext =~ /This code is released under the libpng license/) {
839 $license = "libpng $license";
842 if ($licensetext =~ /Do What The Fuck You Want To Public License, Version ([^, ]+)/i) {
843 $license = "WTFPL (v$1) $license";
846 if ($licensetext =~ /Do what The Fuck You Want To Public License/i) {
847 $license = "WTFPL $license";
850 if ($licensetext =~ /(License WTFPL|Under (the|a) WTFPL)/i) {
851 $license = "WTFPL $license";
854 if ($licensetext =~ /SPDX-License-Identifier:\s+\(([a-zA-Z0-9-\.]+)\s+OR\s+([a-zA-Z0-9-\.]+)\)/i) {
857 $license = parselicense
("SPDX-License-Identifier: $license1") . ";" . parselicense
("SPDX-License-Identifier: $license2");
860 $license = "UNKNOWN" if (!length($license));
862 # Remove trailing spaces.
863 $license =~ s/\s+$//;
869 my ($pack,$file,$line);
870 ($pack,$file,$line) = caller();
871 (my $msg = "$progname: fatal error at line $line:\n@_\n") =~ tr/\0//d;