xref: /titanic_44/usr/src/lib/libast/common/port/astlicense.c (revision ee5416c9d7e449233197d5d20bc6b81e4ff091b2)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 /*
25  * Glenn Fowler
26  * AT&T Research
27  *
28  * generate a license comment -- see proto(1)
29  *
30  * NOTE: coded for minimal library dependence
31  *	 not so for the legal department
32  */
33 
34 #ifndef	_PPLIB_H
35 #include <ast.h>
36 #include <time.h>
37 #endif
38 
39 #undef	copy
40 #undef	BSD			/* guess who defines this */
41 #undef	END
42 #undef	INLINE
43 #undef	TEST
44 #undef	VERBOSE
45 
46 #define NONE			0
47 #define INLINE			1
48 #define TEST			2
49 #define VERBOSE			3
50 #define USAGE			4
51 #define OPEN			5
52 #define CPL			6
53 #define BSD			7
54 #define ZLIB			8
55 #define MIT			9
56 #define GPL			10
57 #define SPECIAL			11
58 #define NONEXCLUSIVE		12
59 #define NONCOMMERCIAL		13
60 #define PROPRIETARY		14
61 
62 #define AUTHOR			0
63 #define CLASS			1
64 #define COMPANY			2
65 #define CONTRIBUTOR		3
66 #define CORPORATION		4
67 #define DOMAIN			5
68 #define INCORPORATION		6
69 #define LICENSE			7
70 #define LOCATION		8
71 #define NOTICE			9
72 #define ORGANIZATION		10
73 #define PACKAGE			11
74 #define PARENT			12
75 #define QUERY			13
76 #define SINCE			14
77 #define STYLE			15
78 #define URL			16
79 #define URLMD5			17
80 #define VERSION			18
81 
82 #define IDS			64
83 
84 #define COMDATA			70
85 #define COMLINE			(COMDATA+4)
86 #define COMLONG			(COMDATA-32)
87 #define COMMENT(x,b,s,u)	comment(x,b,s,sizeof(s)-1,u)
88 
89 #define PUT(b,c)		(((b)->nxt<(b)->end)?(*(b)->nxt++=(c)):((c),(-1)))
90 #define BUF(b)			((b)->buf)
91 #define USE(b)			((b)->siz=(b)->nxt-(b)->buf,(b)->nxt=(b)->buf,(b)->siz)
92 #define SIZ(b)			((b)->nxt-(b)->buf)
93 #define END(b)			(*((b)->nxt>=(b)->end?((b)->nxt=(b)->end-1):(b)->nxt)=0,(b)->nxt-(b)->buf)
94 
95 #ifndef NiL
96 #define NiL			((char*)0)
97 #endif
98 
99 typedef struct Buffer_s
100 {
101 	char*		buf;
102 	char*		nxt;
103 	char*		end;
104 	int		siz;
105 } Buffer_t;
106 
107 typedef struct Item_s
108 {
109 	char*		data;
110 	int		size;
111 	int		quote;
112 } Item_t;
113 
114 typedef struct Id_s
115 {
116 	Item_t		name;
117 	Item_t		value;
118 } Id_t;
119 
120 /*
121  * NOTE: key[] element order must match the corresponding macro
122  */
123 
124 #define KEY(s)			{s,sizeof(s)-1,0}
125 
126 static const Item_t	key[] =
127 {
128 	KEY("author"),
129 	KEY("class"),
130 	KEY("company"),
131 	KEY("contributor"),
132 	KEY("corporation"),
133 	KEY("domain"),
134 	KEY("incorporation"),
135 	KEY("license"),
136 	KEY("location"),
137 	KEY("notice"),
138 	KEY("organization"),
139 	KEY("package"),
140 	KEY("parent"),
141 	KEY("query"),
142 	KEY("since"),
143 	KEY("type"),
144 	KEY("url"),
145 	KEY("urlmd5"),
146 	KEY("version"),
147 	{0}
148 };
149 
150 #define ITEMS			(sizeof(key)/sizeof(key[0])-1)
151 
152 #define LIC(s,c)		{s,sizeof(s)-1,c}
153 
154 static const Item_t	lic[] =
155 {
156 	LIC("none", NONE),
157 	LIC("inline", SPECIAL),
158 	LIC("test", TEST),
159 	LIC("verbose", VERBOSE),
160 	LIC("usage", USAGE),
161 	LIC("open", OPEN),
162 	LIC("cpl", OPEN),
163 	LIC("bsd", OPEN),
164 	LIC("zlib", OPEN),
165 	LIC("mit", OPEN),
166 	LIC("gpl", GPL),
167 	LIC("special", SPECIAL),
168 	LIC("nonexclusive", SPECIAL),
169 	LIC("noncommercial", SPECIAL),
170 	LIC("proprietary", PROPRIETARY),
171 	{0}
172 };
173 
174 typedef struct Notice_s
175 {
176 	int		test;
177 	int		type;
178 	int		verbose;
179 	int		ids;
180 	Item_t		item[ITEMS];
181 	Id_t		id[IDS];
182 	char		cc[3];
183 } Notice_t;
184 
185 /*
186  * return index given <name,size>
187  */
188 
189 static int
190 lookup(register const Item_t* item, const char* name, int size)
191 {
192 	register int	c;
193 	register int	i;
194 
195 	c = name[0];
196 	for (i = 0; item[i].data; i++)
197 		if (c == item[i].data[0] && size == item[i].size && !strncmp(name, item[i].data, size))
198 			return i;
199 	return -1;
200 }
201 
202 /*
203  * copy s of size n to b
204  * n<0 means 0 terminated string
205  */
206 
207 static void
208 copy(register Buffer_t* b, register char* s, int n)
209 {
210 	if (n < 0)
211 		n = strlen(s);
212 	while (n--)
213 		PUT(b, *s++);
214 }
215 
216 /*
217  * center and copy comment line s to p
218  * if s==0 then
219  *	n>0	first frame line
220  *	n=0	blank line
221  *	n<0	last frame line
222  * if u>0 then s converted to upper case
223  * if u<0 then s is left justified
224  */
225 
226 static void
227 comment(Notice_t* notice, register Buffer_t* b, register char* s, register int n, int u)
228 {
229 	register int	i;
230 	register int	m;
231 	register int	x;
232 	int		cc;
233 
234 	cc = notice->cc[1];
235 	if (!s)
236 	{
237 		if (n)
238 		{
239 			PUT(b, notice->cc[n > 0 ? 0 : 1]);
240 			for (i = 0; i < COMDATA; i++)
241 				PUT(b, cc);
242 			PUT(b, notice->cc[n > 0 ? 1 : 2]);
243 		}
244 		else
245 			s = "";
246 	}
247 	if (s)
248 	{
249 		if (n > COMDATA)
250 			n = COMDATA;
251 		PUT(b, cc);
252 		m = (u < 0) ? 1 : (COMDATA - n) / 2;
253 		if ((x = COMDATA - m - n) < 0)
254 			n--;
255 		while (m-- > 0)
256 			PUT(b, ' ');
257 		while (n-- > 0)
258 		{
259 			i = *s++;
260 			if (u > 0 && i >= 'a' && i <= 'z')
261 				i = i - 'a' + 'A';
262 			PUT(b, i);
263 		}
264 		while (x-- > 0)
265 			PUT(b, ' ');
266 		PUT(b, cc);
267 	}
268 	PUT(b, '\n');
269 }
270 
271 /*
272  * expand simple ${...}
273  */
274 
275 static void
276 expand(Notice_t* notice, register Buffer_t* b, const Item_t* item)
277 {
278 	register char*	t;
279 	register char*	e;
280 	register int	q;
281 	register char*	x;
282 	register char*	z;
283 	register int	c;
284 
285 	if (t = item->data)
286 	{
287 		q = item->quote;
288 		e = t + item->size;
289 		while (t < e)
290 		{
291 			if (*t == '$' && t < (e + 2) && *(t + 1) == '{')
292 			{
293 				x = t += 2;
294 				while (t < e && (c = *t++) != '}')
295 					if (c == '.')
296 						x = t;
297 				if ((c = lookup(key, x, t - x - 1)) >= 0 && (x = notice->item[c].data))
298 				{
299 					z = x + notice->item[c].size;
300 					while (x < z)
301 						PUT(b, *x++);
302 				}
303 			}
304 			else if (q > 0 && *t == '\\' && (*(t + 1) == q || *(t + 1) == '\\'))
305 				t++;
306 			else
307 				PUT(b, *t++);
308 		}
309 	}
310 }
311 
312 /*
313  * generate a copright notice
314  */
315 
316 static void
317 copyright(Notice_t* notice, register Buffer_t* b)
318 {
319 	register char*	x;
320 	register char*	t;
321 	time_t		clock;
322 
323 	copy(b, "Copyright (c) ", -1);
324 	if (notice->test)
325 		clock = (time_t)1000212300;
326 	else
327 		time(&clock);
328 	t = ctime(&clock) + 20;
329 	if ((x = notice->item[SINCE].data) && strncmp(x, t, 4))
330 	{
331 		expand(notice, b, &notice->item[SINCE]);
332 		PUT(b, '-');
333 	}
334 	copy(b, t, 4);
335 	if (notice->item[PARENT].data)
336 	{
337 		PUT(b, ' ');
338 		expand(notice, b, &notice->item[PARENT]);
339 	}
340 	if (notice->item[CORPORATION].data)
341 	{
342 		PUT(b, ' ');
343 		expand(notice, b, &notice->item[CORPORATION]);
344 		if (notice->item[INCORPORATION].data)
345 		{
346 			PUT(b, ' ');
347 			expand(notice, b, &notice->item[INCORPORATION]);
348 		}
349 	}
350 	else if (notice->item[COMPANY].data)
351 	{
352 		PUT(b, ' ');
353 		expand(notice, b, &notice->item[COMPANY]);
354 	}
355 }
356 
357 /*
358  * read the license file and generate a comment in p, length size
359  * license length in p returned, -1 on error
360  * -1 return places 0 terminated error string in p
361  */
362 
363 int
364 astlicense(char* p, int size, char* file, char* options, int cc1, int cc2, int cc3)
365 {
366 	register char*	s;
367 	register char*	v;
368 	register char*	x;
369 	register int	c;
370 	int		i;
371 	int		h;
372 	int		k;
373 	int		n;
374 	int		q;
375 	int		contributor;
376 	int		first;
377 	int		line;
378 	int		quote;
379 	char		tmpbuf[COMLINE];
380 	char		info[8 * 1024];
381 	Notice_t	notice;
382 	Item_t		item;
383 	Buffer_t	buf;
384 	Buffer_t	tmp;
385 
386 	buf.end = (buf.buf = buf.nxt = p) + size;
387 	tmp.end = (tmp.buf = tmp.nxt = tmpbuf) + sizeof(tmpbuf);
388 	if (file && *file)
389 	{
390 		if ((i = open(file, O_RDONLY)) < 0)
391 		{
392 			copy(&buf, file, -1);
393 			copy(&buf, ": cannot open", -1);
394 			PUT(&buf, 0);
395 			return -1;
396 		}
397 		n = read(i, info, sizeof(info) - 1);
398 		close(i);
399 		if (n < 0)
400 		{
401 			copy(&buf, file, -1);
402 			copy(&buf, ": cannot read", -1);
403 			PUT(&buf, 0);
404 			return -1;
405 		}
406 		s = info;
407 		s[n] = 0;
408 	}
409 	else if (!options)
410 		return 0;
411 	else
412 	{
413 		s = options;
414 		options = 0;
415 	}
416 	notice.test = 0;
417 	notice.type = NONE;
418 	notice.verbose = 0;
419 	notice.ids = 0;
420 	notice.cc[0] = cc1;
421 	notice.cc[1] = cc2;
422 	notice.cc[2] = cc3;
423 	for (i = 0; i < ITEMS; i++)
424 		notice.item[i].data = 0;
425 	notice.item[STYLE] = notice.item[CLASS] = lic[notice.type];
426 	notice.item[STYLE].quote = notice.item[CLASS].quote = 0;
427 	contributor = i = k = 0;
428 	line = 0;
429 	for (;;)
430 	{
431 		for (first = 1; c = *s; first = 0)
432 		{
433 			while (c == ' ' || c == '\t' || c == '\n' && ++line || c == '\r' || c == ',' || c == ';' || c == ')')
434 				c = *++s;
435 			if (!c)
436 				break;
437 			if (c == '#')
438 			{
439 				while (*++s && *s != '\n');
440 				if (*s)
441 					s++;
442 				line++;
443 				continue;
444 			}
445 			if (c == '\n')
446 			{
447 				s++;
448 				line++;
449 				continue;
450 			}
451 			if (c == '[')
452 				c = *++s;
453 			x = s;
454 			n = 0;
455 			while (c && c != '=' && c != ']' && c != ')' && c != ',' && c != ' ' && c != '\t' && c != '\n' && c != '\r')
456 				c = *++s;
457 			n = s - x;
458 			h = lookup(key, x, n);
459 			if (c == ']')
460 				c = *++s;
461 			if (c == '=' || first)
462 			{
463 				if (c == '=')
464 				{
465 					q = ((c = *++s) == '"' || c == '\'') ? *s++ : 0;
466 					if (c == '(')
467 					{
468 						s++;
469 						if (h == LICENSE)
470 							contributor = 0;
471 						else if (h == CONTRIBUTOR)
472 							contributor = 1;
473 						else
474 						{
475 							q = 1;
476 							i = 0;
477 							for (;;)
478 							{
479 								switch (*s++)
480 								{
481 								case 0:
482 									s--;
483 									break;
484 								case '(':
485 									if (!i)
486 										q++;
487 									continue;
488 								case ')':
489 									if (!i && !--q)
490 										break;
491 									continue;
492 								case '"':
493 								case '\'':
494 									if (!i)
495 										i = *(s - 1);
496 									else if (i == *(s - 1))
497 										i = 0;
498 									continue;
499 								case '\\':
500 									if (*s == i && i == '"')
501 										i++;
502 									continue;
503 								case '\n':
504 									line++;
505 									continue;
506 								default:
507 									continue;
508 								}
509 								break;
510 							}
511 						}
512 						continue;
513 					}
514 					quote = 0;
515 					v = s;
516 					while ((c = *s) && (q == '"' && (c == '\\' && (*(s + 1) == '"' || *(s + 1) == '\\') && s++ && (quote = q)) || q && c != q || !q && c != ' ' && c != '\t' && c != '\n' && c != '\r' && c != ',' && c != ';'))
517 					{
518 						if (c == '\n')
519 							line++;
520 						s++;
521 					}
522 				}
523 				else
524 				{
525 					h = STYLE;
526 					v = x;
527 				}
528 				if (c == '\n')
529 					line++;
530 				if (contributor)
531 				{
532 					for (i = 0; i < notice.ids; i++)
533 						if (n == notice.id[i].name.size && !strncmp(x, notice.id[i].name.data, n))
534 							break;
535 					if (i < IDS)
536 					{
537 						notice.id[i].name.data = x;
538 						notice.id[i].name.size = n;
539 						notice.id[i].name.quote = 0;
540 						notice.id[i].value.data = v;
541 						notice.id[i].value.size = s - v;
542 						notice.id[i].value.quote = quote;
543 						if (notice.ids <= i)
544 							notice.ids = i + 1;
545 					}
546 				}
547 				else if (h == QUERY)
548 				{
549 					if ((s - v) == 3 && v[0] == 'a' && v[1] == 'l' && v[2] == 'l')
550 					{
551 						for (i = 0; i < ITEMS; i++)
552 							if (notice.item[i].size)
553 							{
554 								expand(&notice, &buf, &key[i]);
555 								PUT(&buf, '=');
556 								for (h = 0;; h++)
557 									if (h >= notice.item[i].size)
558 									{
559 										h = 0;
560 										break;
561 									}
562 									else if (notice.item[i].data[h] == ' ' || notice.item[i].data[h] == '\t')
563 										break;
564 								if (h)
565 									PUT(&buf, '\'');
566 								expand(&notice, &buf, &notice.item[i]);
567 								if (h)
568 									PUT(&buf, '\'');
569 								PUT(&buf, '\n');
570 							}
571 					}
572 					else
573 					{
574 						if ((h = lookup(key, v, s - v)) < 0)
575 						{
576 							item.data = v;
577 							item.size = s - v;
578 							item.quote = 0;
579 							expand(&notice, &buf, &item);
580 						}
581 						else
582 							expand(&notice, &buf, &notice.item[h]);
583 						PUT(&buf, '\n');
584 					}
585 					return END(&buf);
586 				}
587 				else
588 				{
589 					if (h == STYLE)
590 						switch (c = lookup(lic, v, s - v))
591 						{
592 						case NONE:
593 							return 0;
594 						case TEST:
595 							notice.test = 1;
596 							h = -1;
597 							break;
598 						case VERBOSE:
599 							notice.verbose = 1;
600 							h = -1;
601 							break;
602 						case USAGE:
603 							notice.type = c;
604 							h = -1;
605 							break;
606 						case -1:
607 							c = SPECIAL;
608 							/*FALLTHROUGH*/
609 						default:
610 							notice.type = c;
611 							notice.item[CLASS].data = lic[lic[c].quote].data;
612 							notice.item[CLASS].size = lic[lic[c].quote].size;
613 							break;
614 						}
615 					if (h >= 0)
616 					{
617 						notice.item[h].data = (notice.item[h].size = s - v) ? v : (char*)0;
618 						notice.item[h].quote = quote;
619 						k = 1;
620 					}
621 				}
622 			}
623 			else
624 			{
625 				if (file)
626 				{
627 					copy(&buf, "\"", -1);
628 					copy(&buf, file, -1);
629 					copy(&buf, "\", line ", -1);
630 					x = &tmpbuf[sizeof(tmpbuf)];
631 					*--x = 0;
632 					line++;
633 					do *--x = ("0123456789")[line % 10]; while (line /= 10);
634 					copy(&buf, x, -1);
635 					copy(&buf, ": ", -1);
636 				}
637 				copy(&buf, "option error: assignment expected", -1);
638 				PUT(&buf, 0);
639 				return -1;
640 			}
641 			if (*s)
642 				s++;
643 		}
644 		if (!options || !*(s = options))
645 			break;
646 		options = 0;
647 	}
648 	if (!k)
649 		return 0;
650 	if (notice.type == INLINE && (!notice.verbose || !notice.item[NOTICE].data))
651 		return 0;
652 	if (notice.type != USAGE)
653 	{
654 		if (!notice.type)
655 			notice.type = SPECIAL;
656 		comment(&notice, &buf, NiL, 1, 0);
657 		comment(&notice, &buf, NiL, 0, 0);
658 		if (notice.item[PACKAGE].data)
659 		{
660 			copy(&tmp, "This software is part of the ", -1);
661 			expand(&notice, &tmp, &notice.item[PACKAGE]);
662 			copy(&tmp, " package", -1);
663 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
664 		}
665 		if (notice.type >= OPEN)
666 		{
667 			copyright(&notice, &tmp);
668 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
669 			if (notice.type >= SPECIAL)
670 				COMMENT(&notice, &buf, "All Rights Reserved", 0);
671 		}
672 		if (notice.type == CPL)
673 		{
674 			copy(&tmp, notice.item[PACKAGE].data ? "and" : "This software", -1);
675 			copy(&tmp, " is licensed under the", -1);
676 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
677 			copy(&tmp, "Common Public License", -1);
678 			if (notice.item[VERSION].data)
679 			{
680 				copy(&tmp, ", Version ", -1);
681 				expand(&notice, &tmp, &notice.item[VERSION]);
682 			}
683 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
684 			if (notice.item[CORPORATION].data || notice.item[COMPANY].data)
685 			{
686 				copy(&tmp, "by ", -1);
687 				if (notice.item[PARENT].data)
688 				{
689 					expand(&notice, &tmp, &notice.item[PARENT]);
690 					copy(&tmp, " ", -1);
691 				}
692 				if (notice.item[CORPORATION].data)
693 				{
694 					expand(&notice, &tmp, &notice.item[CORPORATION]);
695 					if (notice.item[INCORPORATION].data)
696 					{
697 						copy(&tmp, " ", -1);
698 						expand(&notice, &tmp, &notice.item[INCORPORATION]);
699 					}
700 				}
701 				else if (notice.item[COMPANY].data)
702 					expand(&notice, &tmp, &notice.item[COMPANY]);
703 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
704 			}
705 			comment(&notice, &buf, NiL, 0, 0);
706 			COMMENT(&notice, &buf, "A copy of the License is available at", 0);
707 			if (notice.item[URL].data)
708 			{
709 				expand(&notice, &tmp, &notice.item[URL]);
710 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
711 				if (notice.item[URLMD5].data)
712 				{
713 					copy(&tmp, "(with md5 checksum ", -1);
714 					expand(&notice, &tmp, &notice.item[URLMD5]);
715 					copy(&tmp, ")", -1);
716 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
717 				}
718 			}
719 			else
720 				COMMENT(&notice, &buf, "http://www.opensource.org/licenses/cpl", 0);
721 			comment(&notice, &buf, NiL, 0, 0);
722 		}
723 		else if (notice.type == OPEN)
724 		{
725 			copy(&tmp, notice.item[PACKAGE].data ? "and it" : "This software", -1);
726 			copy(&tmp, " may only be used by you under license from", -1);
727 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
728 			if (notice.item[i = CORPORATION].data)
729 			{
730 				if (notice.item[PARENT].data)
731 				{
732 					expand(&notice, &tmp, &notice.item[i = PARENT]);
733 					copy(&tmp, " ", -1);
734 				}
735 				expand(&notice, &tmp, &notice.item[CORPORATION]);
736 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
737 			}
738 			else if (notice.item[i = COMPANY].data)
739 			{
740 				if (notice.item[PARENT].data)
741 				{
742 					expand(&notice, &tmp, &notice.item[i = PARENT]);
743 					copy(&tmp, " ", -1);
744 				}
745 				expand(&notice, &tmp, &notice.item[COMPANY]);
746 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
747 			}
748 			else
749 				i = -1;
750 			if (notice.item[URL].data)
751 			{
752 				COMMENT(&notice, &buf, "A copy of the Source Code Agreement is available", 0);
753 				copy(&tmp, "at the ", -1);
754 				if (i >= 0)
755 					expand(&notice, &tmp, &notice.item[i]);
756 				copy(&tmp, " Internet web site URL", -1);
757 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
758 				comment(&notice, &buf, NiL, 0, 0);
759 				expand(&notice, &tmp, &notice.item[URL]);
760 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
761 				if (notice.item[URLMD5].data)
762 				{
763 					copy(&tmp, "(with an md5 checksum of ", -1);
764 					expand(&notice, &tmp, &notice.item[URLMD5]);
765 					copy(&tmp, ")", -1);
766 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
767 				}
768 				comment(&notice, &buf, NiL, 0, 0);
769 			}
770 			COMMENT(&notice, &buf, "If you have copied or used this software without agreeing", 0);
771 			COMMENT(&notice, &buf, "to the terms of the license you are infringing on", 0);
772 			COMMENT(&notice, &buf, "the license and copyright and are violating", 0);
773 			if (i >= 0)
774 				expand(&notice, &tmp, &notice.item[i]);
775 			copy(&tmp, "'s", -1);
776 			if (n >= COMLONG)
777 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
778 			else
779 				PUT(&tmp, ' ');
780 			copy(&tmp, "intellectual property rights.", -1);
781 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
782 			comment(&notice, &buf, NiL, 0, 0);
783 		}
784 		else if (notice.type == GPL)
785 		{
786 			comment(&notice, &buf, NiL, 0, 0);
787 			COMMENT(&notice, &buf, "This is free software; you can redistribute it and/or", 0);
788 			COMMENT(&notice, &buf, "modify it under the terms of the GNU General Public License", 0);
789 			COMMENT(&notice, &buf, "as published by the Free Software Foundation;", 0);
790 			COMMENT(&notice, &buf, "either version 2, or (at your option) any later version.", 0);
791 			comment(&notice, &buf, NiL, 0, 0);
792 			COMMENT(&notice, &buf, "This software is distributed in the hope that it", 0);
793 			COMMENT(&notice, &buf, "will be useful, but WITHOUT ANY WARRANTY;", 0);
794 			COMMENT(&notice, &buf, "without even the implied warranty of MERCHANTABILITY", 0);
795 			COMMENT(&notice, &buf, "or FITNESS FOR A PARTICULAR PURPOSE.", 0);
796 			COMMENT(&notice, &buf, "See the GNU General Public License for more details.", 0);
797 			comment(&notice, &buf, NiL, 0, 0);
798 			COMMENT(&notice, &buf, "You should have received a copy of the", 0);
799 			COMMENT(&notice, &buf, "GNU General Public License", 0);
800 			COMMENT(&notice, &buf, "along with this software (see the file COPYING.)", 0);
801 			COMMENT(&notice, &buf, "If not, a copy is available at", 0);
802 			COMMENT(&notice, &buf, "http://www.gnu.org/copyleft/gpl.html", 0);
803 			comment(&notice, &buf, NiL, 0, 0);
804 		}
805 		else if (notice.type == BSD)
806 		{
807 			comment(&notice, &buf, NiL, 0, 0);
808 			COMMENT(&notice, &buf, "Redistribution and use in source and binary forms, with or", -1);
809 			COMMENT(&notice, &buf, "without modification, are permitted provided that the following", -1);
810 			COMMENT(&notice, &buf, "conditions are met:", -1);
811 			comment(&notice, &buf, NiL, 0, 0);
812 			COMMENT(&notice, &buf, "   1. Redistributions of source code must retain the above", -1);
813 			COMMENT(&notice, &buf, "      copyright notice, this list of conditions and the", -1);
814 			COMMENT(&notice, &buf, "      following disclaimer.", -1);
815 			comment(&notice, &buf, NiL, 0, 0);
816 			COMMENT(&notice, &buf, "   2. Redistributions in binary form must reproduce the above", -1);
817 			COMMENT(&notice, &buf, "      copyright notice, this list of conditions and the", -1);
818 			COMMENT(&notice, &buf, "      following disclaimer in the documentation and/or other", -1);
819 			COMMENT(&notice, &buf, "      materials provided with the distribution.", -1);
820 			comment(&notice, &buf, NiL, 0, 0);
821 			copy(&tmp, "   3. Neither the name of ", -1);
822 			if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data || notice.item[i = COMPANY].data)
823 				expand(&notice, &tmp, &notice.item[i]);
824 			else
825 				copy(&tmp, "the copyright holder", -1);
826 			copy(&tmp, " nor the", -1);
827 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), -1);
828 			COMMENT(&notice, &buf, "      names of its contributors may be used to endorse or", -1);
829 			COMMENT(&notice, &buf, "      promote products derived from this software without", -1);
830 			COMMENT(&notice, &buf, "      specific prior written permission.", -1);
831 			comment(&notice, &buf, NiL, 0, 0);
832 			COMMENT(&notice, &buf, "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND", -1);
833 			COMMENT(&notice, &buf, "CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,", -1);
834 			COMMENT(&notice, &buf, "INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF", -1);
835 			COMMENT(&notice, &buf, "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE", -1);
836 			COMMENT(&notice, &buf, "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS", -1);
837 			COMMENT(&notice, &buf, "BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,", -1);
838 			COMMENT(&notice, &buf, "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED", -1);
839 			COMMENT(&notice, &buf, "TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,", -1);
840 			COMMENT(&notice, &buf, "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON", -1);
841 			COMMENT(&notice, &buf, "ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,", -1);
842 			COMMENT(&notice, &buf, "OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY", -1);
843 			COMMENT(&notice, &buf, "OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE", -1);
844 			COMMENT(&notice, &buf, "POSSIBILITY OF SUCH DAMAGE.", -1);
845 			comment(&notice, &buf, NiL, 0, 0);
846 		}
847 		else if (notice.type == ZLIB)
848 		{
849 			comment(&notice, &buf, NiL, 0, 0);
850 			COMMENT(&notice, &buf, "This software is provided 'as-is', without any express or implied", -1);
851 			COMMENT(&notice, &buf, "warranty. In no event will the authors be held liable for any", -1);
852 			COMMENT(&notice, &buf, "damages arising from the use of this software.", -1);
853 			comment(&notice, &buf, NiL, 0, 0);
854 			COMMENT(&notice, &buf, "Permission is granted to anyone to use this software for any", -1);
855 			COMMENT(&notice, &buf, "purpose, including commercial applications, and to alter it and", -1);
856 			COMMENT(&notice, &buf, "redistribute it freely, subject to the following restrictions:", -1);
857 			comment(&notice, &buf, NiL, 0, 0);
858 			COMMENT(&notice, &buf, " 1. The origin of this software must not be misrepresented;", -1);
859 			COMMENT(&notice, &buf, "    you must not claim that you wrote the original software. If", -1);
860 			COMMENT(&notice, &buf, "    you use this software in a product, an acknowledgment in the", -1);
861 			COMMENT(&notice, &buf, "    product documentation would be appreciated but is not", -1);
862 			COMMENT(&notice, &buf, "    required.", -1);
863 			comment(&notice, &buf, NiL, 0, 0);
864 			COMMENT(&notice, &buf, " 2. Altered source versions must be plainly marked as such,", -1);
865 			COMMENT(&notice, &buf, "    and must not be misrepresented as being the original", -1);
866 			COMMENT(&notice, &buf, "    software.", -1);
867 			comment(&notice, &buf, NiL, 0, 0);
868 			COMMENT(&notice, &buf, " 3. This notice may not be removed or altered from any source", -1);
869 			COMMENT(&notice, &buf, "    distribution.", -1);
870 			comment(&notice, &buf, NiL, 0, 0);
871 		}
872 		else if (notice.type == MIT)
873 		{
874 			comment(&notice, &buf, NiL, 0, 0);
875 			COMMENT(&notice, &buf, "Permission is hereby granted, free of charge, to any person", 0);
876 			COMMENT(&notice, &buf, "obtaining a copy of this software and associated", 0);
877 			COMMENT(&notice, &buf, "documentation files (the \"Software\"), to deal in the", 0);
878 			COMMENT(&notice, &buf, "Software without restriction, including without limitation", 0);
879 			COMMENT(&notice, &buf, "the rights to use, copy, modify, merge, publish, distribute,", 0);
880 			COMMENT(&notice, &buf, "sublicense, and/or sell copies of the Software, and to", 0);
881 			COMMENT(&notice, &buf, "permit persons to whom the Software is furnished to do so,", 0);
882 			COMMENT(&notice, &buf, "subject to the following conditions:", 0);
883 			comment(&notice, &buf, NiL, 0, 0);
884 			COMMENT(&notice, &buf, "The above copyright notice and this permission notice shall", 0);
885 			COMMENT(&notice, &buf, "be included in all copies or substantial portions of the", 0);
886 			COMMENT(&notice, &buf, "Software.", 0);
887 			comment(&notice, &buf, NiL, 0, 0);
888 			COMMENT(&notice, &buf, "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY", 0);
889 			COMMENT(&notice, &buf, "KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE", 0);
890 			COMMENT(&notice, &buf, "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR", 0);
891 			COMMENT(&notice, &buf, "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS", 0);
892 			COMMENT(&notice, &buf, "OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR", 0);
893 			COMMENT(&notice, &buf, "OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR", 0);
894 			COMMENT(&notice, &buf, "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE", 0);
895 			COMMENT(&notice, &buf, "SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", 0);
896 			comment(&notice, &buf, NiL, 0, 0);
897 		}
898 		else
899 		{
900 			if (notice.type == PROPRIETARY)
901 			{
902 				if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data || notice.item[i = COMPANY].data)
903 				{
904 					expand(&notice, &tmp, &notice.item[i]);
905 					copy(&tmp, " - ", -1);
906 				}
907 				else
908 					i = -1;
909 				copy(&tmp, "Proprietary", -1);
910 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
911 				comment(&notice, &buf, NiL, 0, 0);
912 				if (notice.item[URL].data)
913 				{
914 					copy(&tmp, "This is proprietary source code", -1);
915 					if (i >= 0)
916 						copy(&tmp, " licensed by", -1);
917 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
918 					if (notice.item[PARENT].data)
919 					{
920 						expand(&notice, &tmp, &notice.item[PARENT]);
921 						copy(&tmp, " ", -1);
922 					}
923 					if (notice.item[CORPORATION].data)
924 					{
925 						expand(&notice, &tmp, &notice.item[CORPORATION]);
926 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
927 					}
928 					else if (notice.item[COMPANY].data)
929 					{
930 						expand(&notice, &tmp, &notice.item[COMPANY]);
931 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
932 					}
933 				}
934 				else
935 				{
936 					copy(&tmp, "This is unpublished proprietary source code", -1);
937 					if (i >= 0)
938 						copy(&tmp, " of", -1);
939 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
940 					if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data)
941 						expand(&notice, &tmp, &notice.item[i]);
942 					if (notice.item[COMPANY].data)
943 					{
944 						if (SIZ(&tmp))
945 							PUT(&tmp, ' ');
946 						expand(&notice, &tmp, &notice.item[COMPANY]);
947 					}
948 					if (SIZ(&tmp))
949 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
950 					COMMENT(&notice, &buf, "and is not to be disclosed or used except in", 1);
951 					COMMENT(&notice, &buf, "accordance with applicable agreements", 1);
952 				}
953 				comment(&notice, &buf, NiL, 0, 0);
954 			}
955 			else if (notice.type == NONEXCLUSIVE)
956 			{
957 				COMMENT(&notice, &buf, "For nonexclusive individual use", 1);
958 				comment(&notice, &buf, NiL, 0, 0);
959 			}
960 			else if (notice.type == NONCOMMERCIAL)
961 			{
962 				COMMENT(&notice, &buf, "For noncommercial use", 1);
963 				comment(&notice, &buf, NiL, 0, 0);
964 			}
965 			if (notice.type >= PROPRIETARY && !notice.item[URL].data)
966 			{
967 				COMMENT(&notice, &buf, "Unpublished & Not for Publication", 0);
968 				comment(&notice, &buf, NiL, 0, 0);
969 			}
970 			if (notice.item[URL].data)
971 			{
972 				copy(&tmp, "This software is licensed", -1);
973 				if (notice.item[CORPORATION].data || notice.item[COMPANY].data)
974 				{
975 					copy(&tmp, " by", -1);
976 					if ((notice.item[PARENT].size + (notice.item[CORPORATION].data ? (notice.item[CORPORATION].size + notice.item[INCORPORATION].size) : notice.item[COMPANY].size)) >= (COMLONG - 6))
977 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
978 					else
979 						PUT(&tmp, ' ');
980 					if (notice.item[PARENT].data)
981 					{
982 						expand(&notice, &tmp, &notice.item[PARENT]);
983 						copy(&tmp, " ", -1);
984 					}
985 					if (notice.item[CORPORATION].data)
986 					{
987 						expand(&notice, &tmp, &notice.item[CORPORATION]);
988 						if (notice.item[INCORPORATION].data)
989 						{
990 							copy(&tmp, " ", -1);
991 							expand(&notice, &tmp, &notice.item[INCORPORATION]);
992 						}
993 					}
994 					else if (notice.item[COMPANY].data)
995 						expand(&notice, &tmp, &notice.item[COMPANY]);
996 				}
997 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
998 				COMMENT(&notice, &buf, "under the terms and conditions of the license in", 0);
999 				expand(&notice, &tmp, &notice.item[URL]);
1000 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1001 				if (notice.item[URLMD5].data)
1002 				{
1003 					copy(&tmp, "(with an md5 checksum of ", -1);
1004 					expand(&notice, &tmp, &notice.item[URLMD5]);
1005 					copy(&tmp, ")", -1);
1006 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1007 				}
1008 				comment(&notice, &buf, NiL, 0, 0);
1009 			}
1010 			else if (notice.type == PROPRIETARY)
1011 			{
1012 				COMMENT(&notice, &buf, "The copyright notice above does not evidence any", 0);
1013 				COMMENT(&notice, &buf, "actual or intended publication of such source code", 0);
1014 				comment(&notice, &buf, NiL, 0, 0);
1015 			}
1016 		}
1017 		if (v = notice.item[NOTICE].data)
1018 		{
1019 			x = v + notice.item[NOTICE].size;
1020 			if (*v == '\n')
1021 				v++;
1022 			item.quote = notice.item[NOTICE].quote;
1023 			do
1024 			{
1025 				for (item.data = v; v < x && *v != '\n'; v++);
1026 				if ((item.size = v - item.data) && *item.data == '\t')
1027 				{
1028 					item.data++;
1029 					item.size--;
1030 					h = 0;
1031 				}
1032 				else
1033 					h = -1;
1034 				expand(&notice, &tmp, &item);
1035 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), h);
1036 			} while (v++ < x);
1037 			if (item.size)
1038 				comment(&notice, &buf, NiL, 0, 0);
1039 		}
1040 		if (notice.item[ORGANIZATION].data)
1041 		{
1042 			expand(&notice, &tmp, &notice.item[ORGANIZATION]);
1043 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1044 			if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data)
1045 				expand(&notice, &tmp, &notice.item[i]);
1046 			if (notice.item[COMPANY].data)
1047 			{
1048 				if (SIZ(&tmp))
1049 					PUT(&tmp, ' ');
1050 				expand(&notice, &tmp, &notice.item[COMPANY]);
1051 			}
1052 			if (SIZ(&tmp))
1053 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1054 			if (notice.item[LOCATION].data)
1055 			{
1056 				expand(&notice, &tmp, &notice.item[LOCATION]);
1057 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1058 			}
1059 			comment(&notice, &buf, NiL, 0, 0);
1060 		}
1061 	}
1062 	if (v = notice.item[AUTHOR].data)
1063 	{
1064 		x = v + notice.item[AUTHOR].size;
1065 		q = (x - v) == 1 && (*v == '*' || *v == '-');
1066 		k = q && notice.type != USAGE ? -1 : 0;
1067 		for (;;)
1068 		{
1069 			if (!q)
1070 			{
1071 				while (v < x && (*v == ' ' || *v == '\t' || *v == '\r' || *v == '\n' || *v == ',' || *v == '+'))
1072 					v++;
1073 				if (v >= x)
1074 					break;
1075 				item.data = v;
1076 				while (v < x && *v != ',' && *v != '+' && *v++ != '>');
1077 				item.size = v - item.data;
1078 				item.quote = notice.item[AUTHOR].quote;
1079 			}
1080 			h = 0;
1081 			for (i = 0; i < notice.ids; i++)
1082 				if (q || item.size == notice.id[i].name.size && !strncmp(item.data, notice.id[i].name.data, item.size))
1083 				{
1084 					h = 1;
1085 					if (notice.type == USAGE)
1086 					{
1087 						copy(&buf, "[-author?", -1);
1088 						expand(&notice, &buf, &notice.id[i].value);
1089 						PUT(&buf, ']');
1090 					}
1091 					else
1092 					{
1093 						if (k < 0)
1094 						{
1095 							COMMENT(&notice, &buf, "CONTRIBUTORS", 0);
1096 							comment(&notice, &buf, NiL, 0, 0);
1097 						}
1098 						k = 1;
1099 						expand(&notice, &tmp, &notice.id[i].value);
1100 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1101 					}
1102 					if (!q)
1103 						break;
1104 				}
1105 			if (q)
1106 				break;
1107 			if (!h)
1108 			{
1109 				if (notice.type == USAGE)
1110 				{
1111 					copy(&buf, "[-author?", -1);
1112 					expand(&notice, &buf, &item);
1113 					PUT(&buf, ']');
1114 				}
1115 				else
1116 				{
1117 					if (k < 0)
1118 					{
1119 						COMMENT(&notice, &buf, "CONTRIBUTORS", 0);
1120 						comment(&notice, &buf, NiL, 0, 0);
1121 					}
1122 					k = 1;
1123 					expand(&notice, &tmp, &item);
1124 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1125 				}
1126 			}
1127 		}
1128 		if (k > 0)
1129 			comment(&notice, &buf, NiL, 0, 0);
1130 	}
1131 	if (notice.type == USAGE)
1132 	{
1133 		copy(&buf, "[-copyright?", -1);
1134 		copyright(&notice, &buf);
1135 		PUT(&buf, ']');
1136 		if (notice.item[URL].data)
1137 		{
1138 			copy(&buf, "[-license?", -1);
1139 			expand(&notice, &buf, &notice.item[URL]);
1140 			PUT(&buf, ']');
1141 		}
1142 		PUT(&buf, '\n');
1143 	}
1144 	else
1145 		comment(&notice, &buf, NiL, -1, 0);
1146 	return END(&buf);
1147 }
1148