summaryrefslogtreecommitdiff
path: root/tools/ccanlint/licenses.c
blob: ca8bc73d0d58e0be508ab6e5f4cc5352a0af1072 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "licenses.h"
#include "ccanlint.h"
#include <ccan/str/str.h>
#include <ccan/tal/tal.h>
#include <ccan/tal/str/str.h>

const struct license_info licenses[] = {
	{ "LGPLv2+", "LGPL",
	  "GNU LGPL version 2 (or later)",
	  { "gnu lesser general public license",
	    "version 2",
	    "or at your option any later version"
	  }
	},
	{ "LGPLv2", "LGPL",
	  "GNU LGPL version 2",
	  { "gnu lesser general public license",
	    "version 2",
	    NULL
	  }
	},
	{ "LGPLv3", "LGPL",
	  "GNU LGPL version 3",
	  { "gnu lesser general public license",
	    "version 3",
	    NULL
	  }
	},
	{ "LGPL", "LGPL",
	  "GNU LGPL",
	  { "gnu lesser general public license",
	    NULL,
	    NULL
	  }
	},
	{ "GPLv2+", "GPL",
	  "GNU GPL version 2 (or later)",
	  { "gnu general public license",
	    "version 2",
	    "or at your option any later version"
	  }
	},
	{ "GPLv2", "GPL",
	  "GNU GPL version 2",
	  { "gnu general public license",
	    "version 2",
	    NULL
	  }
	},
	{ "GPLv3", "GPL",
	  "GNU GPL version 3 (or later)",
	  { "gnu general public license",
	    "version 3",
	    NULL
	  }
	},
	{ "GPL", "GPL",
	  "GNU GPL",
	  { "gnu general public license",
	    NULL,
	    NULL
	  }
	},
	{ "BSD-3CLAUSE", "BSD",
	  "3-clause BSD license",
	  { "redistributions of source code must retain",
	    "redistributions in binary form must reproduce",
	    "endorse or promote"
	  }
	},
	{ "BSD-MIT", "MIT",
	  "MIT (BSD) license",
	  { "without restriction",
	    "above copyright notice",
	    "without warranty"
	  }
	},
	{ "CC0", "CC0",
	  "CC0 license (public domain)",
	  { "Waiver.",
	    "unconditionally waives",
	    NULL
	  }
	},
	{ "Public domain", "Public domain",
	  NULL,
	  { NULL, NULL, NULL  }
	},
	{ "Unknown license", "Unknown license",
	  NULL,
	  { NULL, NULL, NULL  }
	},
};

/* License compatibilty chart (simplified: we don't test that licenses between
 * files are compatible). */
#define O true
#define X false
bool license_compatible[LICENSE_UNKNOWN+1][LICENSE_UNKNOWN] = {
/*     LGPL2+   LGPL3   GPL2+   GPL3     BSD     CC0
            LGPL2    LGPL   GPL2     GPL     MIT     PD   */
/* _info says: LGPL2+ */
	{ O,  X,  X,  O,  X,  X,  X,  X,  O,  O,  O,  O },
/* _info says: LGPL2 only */
	{ O,  O,  X,  O,  X,  X,  X,  X,  O,  O,  O,  O },
/* _info says: LGPL3 (or any later version) */
	{ O,  X,  O,  O,  X,  X,  X,  X,  O,  O,  O,  O },
/* _info says: LGPL (no version specified) */
	{ O,  O,  O,  O,  X,  X,  X,  X,  O,  O,  O,  O },
/* _info says: GPL2+ */
	{ O,  O,  O,  O,  O,  X,  X,  O,  O,  O,  O,  O },
/* _info says: GPL2 only */
	{ O,  O,  O,  O,  O,  O,  X,  O,  O,  O,  O,  O },
/* _info says: GPL3 (or any later version) */
	{ O,  O,  O,  O,  O,  X,  O,  O,  O,  O,  O,  O },
/* _info says: GPL (unknown version) */
	{ O,  O,  O,  O,  O,  O,  O,  O,  O,  O,  O,  O },
/* _info says: BSD (3-clause) */
	{ X,  X,  X,  X,  X,  X,  X,  X,  O,  O,  O,  O },
/* _info says: MIT */
	{ X,  X,  X,  X,  X,  X,  X,  X,  X,  O,  O,  O },
/* _info says: CC0 */
	{ X,  X,  X,  X,  X,  X,  X,  X,  X,  X,  O,  O },
/* _info says: Public domain */
	{ X,  X,  X,  X,  X,  X,  X,  X,  X,  X,  O,  O },
/* _info says something we don't understand */
	{ X,  X,  X,  X,  X,  X,  X,  X,  X,  X,  O,  O }
};
#undef X
#undef O

/* See GPLv2 and v2 (basically same wording) for interpreting versions:
 * the "any later version" means the recepient can choose. */
enum license which_license(struct doc_section *d)
{
	if (!d)
		return LICENSE_UNKNOWN;

	/* This means "user chooses what version", including GPLv1! */
	if (streq(d->lines[0], "GPL"))
		return LICENSE_GPL;
	/* This means "v2 only". */
	if (streq(d->lines[0], "GPLv2"))
		return LICENSE_GPLv2;
	/* This means "v2 or above" at user's choice. */
	if (streq(d->lines[0], "GPL (v2 or any later version)"))
		return LICENSE_GPLv2_PLUS;
	/* This means "v3 or above" at user's choice. */
	if (streq(d->lines[0], "GPL (v3 or any later version)"))
		return LICENSE_GPLv3;

	/* This means "user chooses what version" */
	if (streq(d->lines[0], "LGPL"))
		return LICENSE_LGPL;
	/* This means "v2.1 only". */
	if (streq(d->lines[0], "LGPLv2.1"))
		return LICENSE_LGPLv2;
	/* This means "v2.1 or above" at user's choice. */
	if (streq(d->lines[0], "LGPL (v2.1 or any later version)"))
		return LICENSE_LGPLv2_PLUS;
	/* This means "v3 or above" at user's choice. */
	if (streq(d->lines[0], "LGPL (v3 or any later version)"))
		return LICENSE_LGPLv3;

	if (streq(d->lines[0], "BSD-MIT") || streq(d->lines[0], "MIT"))
		return LICENSE_MIT;
	if (streq(d->lines[0], "BSD (3 clause)"))
		return LICENSE_BSD;
	if (streq(d->lines[0], "CC0"))
		return LICENSE_CC0;
	if (tal_strreg(NULL, d->lines[0], "CC0 \\([Pp]ublic [Dd]omain\\)",
		       NULL))
		return LICENSE_CC0;
	if (tal_strreg(NULL, d->lines[0], "[Pp]ublic [Dd]omain"))
		return LICENSE_PUBLIC_DOMAIN;

	return LICENSE_UNKNOWN;
}

const char *get_ccan_simplified(struct ccan_file *f)
{
	if (!f->simplified) {
		unsigned int i, j;

		/* Simplify for easy matching: only alnum and single spaces. */
		f->simplified = tal_strdup(f, get_ccan_file_contents(f));
		for (i = 0, j = 0; f->simplified[i]; i++) {
			if (cisupper(f->simplified[i]))
				f->simplified[j++] = tolower(f->simplified[i]);
			else if (cislower(f->simplified[i]))
				f->simplified[j++] = f->simplified[i];
			else if (cisdigit(f->simplified[i]))
				f->simplified[j++] = f->simplified[i];
			else if (cisspace(f->simplified[i])) {
				if (j != 0 && f->simplified[j-1] != ' ')
					f->simplified[j++] = ' ';
			}
		}
		f->simplified[j] = '\0';
	}
	return f->simplified;
}

bool find_boilerplate(struct ccan_file *f, enum license license)
{
	unsigned int i;

	for (i = 0; i < NUM_CLAUSES; i++) {
		if (!licenses[license].clause[i])
			break;

		if (!strstr(get_ccan_simplified(f),
			    licenses[license].clause[i])) {
			return false;
		}
	}
	return true;
}

struct doc_section *find_license_tag(const struct manifest *m)
{
	struct doc_section *d;

	list_for_each(get_ccan_file_docs(m->info_file), d, list) {
		if (!streq(d->function, m->modname))
			continue;
		if (streq(d->type, "license"))
			return d;
	}
	return NULL;
}

const char *get_license_oneliner(const tal_t *ctx, enum license license)
{
	return tal_fmt(ctx, "/* %s - see LICENSE file for details */",
		       licenses[license].describe);
}