xref: /titanic_41/usr/src/lib/libast/common/port/astlicense.c (revision 68c47f65208790c466e5e484f2293d3baed71c6a)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2009 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
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 		first = 1;
432 		while (c = *s)
433 		{
434 			while (c == ' ' || c == '\t' || c == '\n' && ++line || c == '\r' || c == ',' || c == ';' || c == ')')
435 				c = *++s;
436 			if (!c)
437 				break;
438 			if (c == '#')
439 			{
440 				while (*++s && *s != '\n');
441 				if (*s)
442 					s++;
443 				line++;
444 				continue;
445 			}
446 			if (c == '\n')
447 			{
448 				s++;
449 				line++;
450 				continue;
451 			}
452 			if (c == '[')
453 				c = *++s;
454 			x = s;
455 			n = 0;
456 			while (c && c != '=' && c != ']' && c != ')' && c != ',' && c != ' ' && c != '\t' && c != '\n' && c != '\r')
457 				c = *++s;
458 			n = s - x;
459 			h = lookup(key, x, n);
460 			if (c == ']')
461 				c = *++s;
462 			if (c == '=' || first)
463 			{
464 				if (c == '=')
465 				{
466 					q = ((c = *++s) == '"' || c == '\'') ? *s++ : 0;
467 					if (c == '(')
468 					{
469 						s++;
470 						if (h == LICENSE)
471 							contributor = 0;
472 						else if (h == CONTRIBUTOR)
473 							contributor = 1;
474 						else
475 						{
476 							q = 1;
477 							i = 0;
478 							for (;;)
479 							{
480 								switch (*s++)
481 								{
482 								case 0:
483 									s--;
484 									break;
485 								case '(':
486 									if (!i)
487 										q++;
488 									continue;
489 								case ')':
490 									if (!i && !--q)
491 										break;
492 									continue;
493 								case '"':
494 								case '\'':
495 									if (!i)
496 										i = *(s - 1);
497 									else if (i == *(s - 1))
498 										i = 0;
499 									continue;
500 								case '\\':
501 									if (*s == i && i == '"')
502 										i++;
503 									continue;
504 								case '\n':
505 									line++;
506 									continue;
507 								default:
508 									continue;
509 								}
510 								break;
511 							}
512 						}
513 						continue;
514 					}
515 					quote = 0;
516 					v = s;
517 					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 != ';'))
518 					{
519 						if (c == '\n')
520 							line++;
521 						s++;
522 					}
523 				}
524 				else
525 				{
526 					h = STYLE;
527 					v = x;
528 				}
529 				if (c == '\n')
530 					line++;
531 				if (contributor)
532 				{
533 					for (i = 0; i < notice.ids; i++)
534 						if (n == notice.id[i].name.size && !strncmp(x, notice.id[i].name.data, n))
535 							break;
536 					if (i < IDS)
537 					{
538 						notice.id[i].name.data = x;
539 						notice.id[i].name.size = n;
540 						notice.id[i].name.quote = 0;
541 						notice.id[i].value.data = v;
542 						notice.id[i].value.size = s - v;
543 						notice.id[i].value.quote = quote;
544 						if (notice.ids <= i)
545 							notice.ids = i + 1;
546 					}
547 				}
548 				else if (h == QUERY)
549 				{
550 					if ((s - v) == 3 && v[0] == 'a' && v[1] == 'l' && v[2] == 'l')
551 					{
552 						for (i = 0; i < ITEMS; i++)
553 							if (notice.item[i].size)
554 							{
555 								expand(&notice, &buf, &key[i]);
556 								PUT(&buf, '=');
557 								for (h = 0;; h++)
558 									if (h >= notice.item[i].size)
559 									{
560 										h = 0;
561 										break;
562 									}
563 									else if (notice.item[i].data[h] == ' ' || notice.item[i].data[h] == '\t')
564 										break;
565 								if (h)
566 									PUT(&buf, '\'');
567 								expand(&notice, &buf, &notice.item[i]);
568 								if (h)
569 									PUT(&buf, '\'');
570 								PUT(&buf, '\n');
571 							}
572 					}
573 					else
574 					{
575 						if ((h = lookup(key, v, s - v)) < 0)
576 						{
577 							item.data = v;
578 							item.size = s - v;
579 							item.quote = 0;
580 							expand(&notice, &buf, &item);
581 						}
582 						else
583 							expand(&notice, &buf, &notice.item[h]);
584 						PUT(&buf, '\n');
585 					}
586 					return END(&buf);
587 				}
588 				else
589 				{
590 					if (h == STYLE)
591 						switch (c = lookup(lic, v, s - v))
592 						{
593 						case NONE:
594 							return 0;
595 						case TEST:
596 							notice.test = 1;
597 							h = -1;
598 							break;
599 						case VERBOSE:
600 							notice.verbose = 1;
601 							h = -1;
602 							break;
603 						case USAGE:
604 							notice.type = c;
605 							h = -1;
606 							break;
607 						case -1:
608 							c = SPECIAL;
609 							/*FALLTHROUGH*/
610 						default:
611 							notice.type = c;
612 							notice.item[CLASS].data = lic[lic[c].quote].data;
613 							notice.item[CLASS].size = lic[lic[c].quote].size;
614 							break;
615 						}
616 					if (h >= 0)
617 					{
618 						notice.item[h].data = (notice.item[h].size = s - v) ? v : (char*)0;
619 						notice.item[h].quote = quote;
620 						k = 1;
621 					}
622 				}
623 			}
624 			else
625 			{
626 				if (file)
627 				{
628 					copy(&buf, "\"", -1);
629 					copy(&buf, file, -1);
630 					copy(&buf, "\", line ", -1);
631 					x = &tmpbuf[sizeof(tmpbuf)];
632 					*--x = 0;
633 					line++;
634 					do *--x = ("0123456789")[line % 10]; while (line /= 10);
635 					copy(&buf, x, -1);
636 					copy(&buf, ": ", -1);
637 				}
638 				copy(&buf, "option error: assignment expected", -1);
639 				PUT(&buf, 0);
640 				return -1;
641 			}
642 			if (*s)
643 				s++;
644 			first = 0;
645 		}
646 		if (!options || !*(s = options))
647 			break;
648 		options = 0;
649 	}
650 	if (!k)
651 		return 0;
652 	if (notice.type == INLINE && (!notice.verbose || !notice.item[NOTICE].data))
653 		return 0;
654 	if (notice.type != USAGE)
655 	{
656 		if (!notice.type)
657 			notice.type = SPECIAL;
658 		comment(&notice, &buf, NiL, 1, 0);
659 		comment(&notice, &buf, NiL, 0, 0);
660 		if (notice.item[PACKAGE].data)
661 		{
662 			copy(&tmp, "This software is part of the ", -1);
663 			expand(&notice, &tmp, &notice.item[PACKAGE]);
664 			copy(&tmp, " package", -1);
665 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
666 		}
667 		if (notice.type >= OPEN)
668 		{
669 			copyright(&notice, &tmp);
670 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
671 			if (notice.type >= SPECIAL)
672 				COMMENT(&notice, &buf, "All Rights Reserved", 0);
673 		}
674 		if (notice.type == CPL)
675 		{
676 			copy(&tmp, notice.item[PACKAGE].data ? "and" : "This software", -1);
677 			copy(&tmp, " is licensed under the", -1);
678 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
679 			copy(&tmp, "Common Public License", -1);
680 			if (notice.item[VERSION].data)
681 			{
682 				copy(&tmp, ", Version ", -1);
683 				expand(&notice, &tmp, &notice.item[VERSION]);
684 			}
685 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
686 			if (notice.item[CORPORATION].data || notice.item[COMPANY].data)
687 			{
688 				copy(&tmp, "by ", -1);
689 				if (notice.item[PARENT].data)
690 				{
691 					expand(&notice, &tmp, &notice.item[PARENT]);
692 					copy(&tmp, " ", -1);
693 				}
694 				if (notice.item[CORPORATION].data)
695 				{
696 					expand(&notice, &tmp, &notice.item[CORPORATION]);
697 					if (notice.item[INCORPORATION].data)
698 					{
699 						copy(&tmp, " ", -1);
700 						expand(&notice, &tmp, &notice.item[INCORPORATION]);
701 					}
702 				}
703 				else if (notice.item[COMPANY].data)
704 					expand(&notice, &tmp, &notice.item[COMPANY]);
705 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
706 			}
707 			comment(&notice, &buf, NiL, 0, 0);
708 			COMMENT(&notice, &buf, "A copy of the License is available at", 0);
709 			if (notice.item[URL].data)
710 			{
711 				expand(&notice, &tmp, &notice.item[URL]);
712 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
713 				if (notice.item[URLMD5].data)
714 				{
715 					copy(&tmp, "(with md5 checksum ", -1);
716 					expand(&notice, &tmp, &notice.item[URLMD5]);
717 					copy(&tmp, ")", -1);
718 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
719 				}
720 			}
721 			else
722 				COMMENT(&notice, &buf, "http://www.opensource.org/licenses/cpl", 0);
723 			comment(&notice, &buf, NiL, 0, 0);
724 		}
725 		else if (notice.type == OPEN)
726 		{
727 			copy(&tmp, notice.item[PACKAGE].data ? "and it" : "This software", -1);
728 			copy(&tmp, " may only be used by you under license from", -1);
729 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
730 			if (notice.item[i = CORPORATION].data)
731 			{
732 				if (notice.item[PARENT].data)
733 				{
734 					expand(&notice, &tmp, &notice.item[i = PARENT]);
735 					copy(&tmp, " ", -1);
736 				}
737 				expand(&notice, &tmp, &notice.item[CORPORATION]);
738 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
739 			}
740 			else if (notice.item[i = COMPANY].data)
741 			{
742 				if (notice.item[PARENT].data)
743 				{
744 					expand(&notice, &tmp, &notice.item[i = PARENT]);
745 					copy(&tmp, " ", -1);
746 				}
747 				expand(&notice, &tmp, &notice.item[COMPANY]);
748 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
749 			}
750 			else
751 				i = -1;
752 			if (notice.item[URL].data)
753 			{
754 				COMMENT(&notice, &buf, "A copy of the Source Code Agreement is available", 0);
755 				copy(&tmp, "at the ", -1);
756 				if (i >= 0)
757 					expand(&notice, &tmp, &notice.item[i]);
758 				copy(&tmp, " Internet web site URL", -1);
759 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
760 				comment(&notice, &buf, NiL, 0, 0);
761 				expand(&notice, &tmp, &notice.item[URL]);
762 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
763 				if (notice.item[URLMD5].data)
764 				{
765 					copy(&tmp, "(with an md5 checksum of ", -1);
766 					expand(&notice, &tmp, &notice.item[URLMD5]);
767 					copy(&tmp, ")", -1);
768 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
769 				}
770 				comment(&notice, &buf, NiL, 0, 0);
771 			}
772 			COMMENT(&notice, &buf, "If you have copied or used this software without agreeing", 0);
773 			COMMENT(&notice, &buf, "to the terms of the license you are infringing on", 0);
774 			COMMENT(&notice, &buf, "the license and copyright and are violating", 0);
775 			if (i >= 0)
776 				expand(&notice, &tmp, &notice.item[i]);
777 			copy(&tmp, "'s", -1);
778 			if (n >= COMLONG)
779 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
780 			else
781 				PUT(&tmp, ' ');
782 			copy(&tmp, "intellectual property rights.", -1);
783 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
784 			comment(&notice, &buf, NiL, 0, 0);
785 		}
786 		else if (notice.type == GPL)
787 		{
788 			comment(&notice, &buf, NiL, 0, 0);
789 			COMMENT(&notice, &buf, "This is free software; you can redistribute it and/or", 0);
790 			COMMENT(&notice, &buf, "modify it under the terms of the GNU General Public License", 0);
791 			COMMENT(&notice, &buf, "as published by the Free Software Foundation;", 0);
792 			COMMENT(&notice, &buf, "either version 2, or (at your option) any later version.", 0);
793 			comment(&notice, &buf, NiL, 0, 0);
794 			COMMENT(&notice, &buf, "This software is distributed in the hope that it", 0);
795 			COMMENT(&notice, &buf, "will be useful, but WITHOUT ANY WARRANTY;", 0);
796 			COMMENT(&notice, &buf, "without even the implied warranty of MERCHANTABILITY", 0);
797 			COMMENT(&notice, &buf, "or FITNESS FOR A PARTICULAR PURPOSE.", 0);
798 			COMMENT(&notice, &buf, "See the GNU General Public License for more details.", 0);
799 			comment(&notice, &buf, NiL, 0, 0);
800 			COMMENT(&notice, &buf, "You should have received a copy of the", 0);
801 			COMMENT(&notice, &buf, "GNU General Public License", 0);
802 			COMMENT(&notice, &buf, "along with this software (see the file COPYING.)", 0);
803 			COMMENT(&notice, &buf, "If not, a copy is available at", 0);
804 			COMMENT(&notice, &buf, "http://www.gnu.org/copyleft/gpl.html", 0);
805 			comment(&notice, &buf, NiL, 0, 0);
806 		}
807 		else if (notice.type == BSD)
808 		{
809 			comment(&notice, &buf, NiL, 0, 0);
810 			COMMENT(&notice, &buf, "Redistribution and use in source and binary forms, with or", -1);
811 			COMMENT(&notice, &buf, "without modification, are permitted provided that the following", -1);
812 			COMMENT(&notice, &buf, "conditions are met:", -1);
813 			comment(&notice, &buf, NiL, 0, 0);
814 			COMMENT(&notice, &buf, "   1. Redistributions of source code must retain the above", -1);
815 			COMMENT(&notice, &buf, "      copyright notice, this list of conditions and the", -1);
816 			COMMENT(&notice, &buf, "      following disclaimer.", -1);
817 			comment(&notice, &buf, NiL, 0, 0);
818 			COMMENT(&notice, &buf, "   2. Redistributions in binary form must reproduce the above", -1);
819 			COMMENT(&notice, &buf, "      copyright notice, this list of conditions and the", -1);
820 			COMMENT(&notice, &buf, "      following disclaimer in the documentation and/or other", -1);
821 			COMMENT(&notice, &buf, "      materials provided with the distribution.", -1);
822 			comment(&notice, &buf, NiL, 0, 0);
823 			copy(&tmp, "   3. Neither the name of ", -1);
824 			if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data || notice.item[i = COMPANY].data)
825 				expand(&notice, &tmp, &notice.item[i]);
826 			else
827 				copy(&tmp, "the copyright holder", -1);
828 			copy(&tmp, " nor the", -1);
829 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), -1);
830 			COMMENT(&notice, &buf, "      names of its contributors may be used to endorse or", -1);
831 			COMMENT(&notice, &buf, "      promote products derived from this software without", -1);
832 			COMMENT(&notice, &buf, "      specific prior written permission.", -1);
833 			comment(&notice, &buf, NiL, 0, 0);
834 			COMMENT(&notice, &buf, "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND", -1);
835 			COMMENT(&notice, &buf, "CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,", -1);
836 			COMMENT(&notice, &buf, "INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF", -1);
837 			COMMENT(&notice, &buf, "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE", -1);
838 			COMMENT(&notice, &buf, "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS", -1);
839 			COMMENT(&notice, &buf, "BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,", -1);
840 			COMMENT(&notice, &buf, "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED", -1);
841 			COMMENT(&notice, &buf, "TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,", -1);
842 			COMMENT(&notice, &buf, "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON", -1);
843 			COMMENT(&notice, &buf, "ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,", -1);
844 			COMMENT(&notice, &buf, "OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY", -1);
845 			COMMENT(&notice, &buf, "OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE", -1);
846 			COMMENT(&notice, &buf, "POSSIBILITY OF SUCH DAMAGE.", -1);
847 			comment(&notice, &buf, NiL, 0, 0);
848 		}
849 		else if (notice.type == ZLIB)
850 		{
851 			comment(&notice, &buf, NiL, 0, 0);
852 			COMMENT(&notice, &buf, "This software is provided 'as-is', without any express or implied", -1);
853 			COMMENT(&notice, &buf, "warranty. In no event will the authors be held liable for any", -1);
854 			COMMENT(&notice, &buf, "damages arising from the use of this software.", -1);
855 			comment(&notice, &buf, NiL, 0, 0);
856 			COMMENT(&notice, &buf, "Permission is granted to anyone to use this software for any", -1);
857 			COMMENT(&notice, &buf, "purpose, including commercial applications, and to alter it and", -1);
858 			COMMENT(&notice, &buf, "redistribute it freely, subject to the following restrictions:", -1);
859 			comment(&notice, &buf, NiL, 0, 0);
860 			COMMENT(&notice, &buf, " 1. The origin of this software must not be misrepresented;", -1);
861 			COMMENT(&notice, &buf, "    you must not claim that you wrote the original software. If", -1);
862 			COMMENT(&notice, &buf, "    you use this software in a product, an acknowledgment in the", -1);
863 			COMMENT(&notice, &buf, "    product documentation would be appreciated but is not", -1);
864 			COMMENT(&notice, &buf, "    required.", -1);
865 			comment(&notice, &buf, NiL, 0, 0);
866 			COMMENT(&notice, &buf, " 2. Altered source versions must be plainly marked as such,", -1);
867 			COMMENT(&notice, &buf, "    and must not be misrepresented as being the original", -1);
868 			COMMENT(&notice, &buf, "    software.", -1);
869 			comment(&notice, &buf, NiL, 0, 0);
870 			COMMENT(&notice, &buf, " 3. This notice may not be removed or altered from any source", -1);
871 			COMMENT(&notice, &buf, "    distribution.", -1);
872 			comment(&notice, &buf, NiL, 0, 0);
873 		}
874 		else if (notice.type == MIT)
875 		{
876 			comment(&notice, &buf, NiL, 0, 0);
877 			COMMENT(&notice, &buf, "Permission is hereby granted, free of charge, to any person", 0);
878 			COMMENT(&notice, &buf, "obtaining a copy of this software and associated", 0);
879 			COMMENT(&notice, &buf, "documentation files (the \"Software\"), to deal in the", 0);
880 			COMMENT(&notice, &buf, "Software without restriction, including without limitation", 0);
881 			COMMENT(&notice, &buf, "the rights to use, copy, modify, merge, publish, distribute,", 0);
882 			COMMENT(&notice, &buf, "sublicense, and/or sell copies of the Software, and to", 0);
883 			COMMENT(&notice, &buf, "permit persons to whom the Software is furnished to do so,", 0);
884 			COMMENT(&notice, &buf, "subject to the following conditions:", 0);
885 			comment(&notice, &buf, NiL, 0, 0);
886 			COMMENT(&notice, &buf, "The above copyright notice and this permission notice shall", 0);
887 			COMMENT(&notice, &buf, "be included in all copies or substantial portions of the", 0);
888 			COMMENT(&notice, &buf, "Software.", 0);
889 			comment(&notice, &buf, NiL, 0, 0);
890 			COMMENT(&notice, &buf, "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY", 0);
891 			COMMENT(&notice, &buf, "KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE", 0);
892 			COMMENT(&notice, &buf, "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR", 0);
893 			COMMENT(&notice, &buf, "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS", 0);
894 			COMMENT(&notice, &buf, "OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR", 0);
895 			COMMENT(&notice, &buf, "OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR", 0);
896 			COMMENT(&notice, &buf, "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE", 0);
897 			COMMENT(&notice, &buf, "SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", 0);
898 			comment(&notice, &buf, NiL, 0, 0);
899 		}
900 		else
901 		{
902 			if (notice.type == PROPRIETARY)
903 			{
904 				if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data || notice.item[i = COMPANY].data)
905 				{
906 					expand(&notice, &tmp, &notice.item[i]);
907 					copy(&tmp, " - ", -1);
908 				}
909 				else
910 					i = -1;
911 				copy(&tmp, "Proprietary", -1);
912 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
913 				comment(&notice, &buf, NiL, 0, 0);
914 				if (notice.item[URL].data)
915 				{
916 					copy(&tmp, "This is proprietary source code", -1);
917 					if (i >= 0)
918 						copy(&tmp, " licensed by", -1);
919 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
920 					if (notice.item[PARENT].data)
921 					{
922 						expand(&notice, &tmp, &notice.item[PARENT]);
923 						copy(&tmp, " ", -1);
924 					}
925 					if (notice.item[CORPORATION].data)
926 					{
927 						expand(&notice, &tmp, &notice.item[CORPORATION]);
928 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
929 					}
930 					else if (notice.item[COMPANY].data)
931 					{
932 						expand(&notice, &tmp, &notice.item[COMPANY]);
933 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
934 					}
935 				}
936 				else
937 				{
938 					copy(&tmp, "This is unpublished proprietary source code", -1);
939 					if (i >= 0)
940 						copy(&tmp, " of", -1);
941 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
942 					if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data)
943 						expand(&notice, &tmp, &notice.item[i]);
944 					if (notice.item[COMPANY].data)
945 					{
946 						if (SIZ(&tmp))
947 							PUT(&tmp, ' ');
948 						expand(&notice, &tmp, &notice.item[COMPANY]);
949 					}
950 					if (SIZ(&tmp))
951 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 1);
952 					COMMENT(&notice, &buf, "and is not to be disclosed or used except in", 1);
953 					COMMENT(&notice, &buf, "accordance with applicable agreements", 1);
954 				}
955 				comment(&notice, &buf, NiL, 0, 0);
956 			}
957 			else if (notice.type == NONEXCLUSIVE)
958 			{
959 				COMMENT(&notice, &buf, "For nonexclusive individual use", 1);
960 				comment(&notice, &buf, NiL, 0, 0);
961 			}
962 			else if (notice.type == NONCOMMERCIAL)
963 			{
964 				COMMENT(&notice, &buf, "For noncommercial use", 1);
965 				comment(&notice, &buf, NiL, 0, 0);
966 			}
967 			if (notice.type >= PROPRIETARY && !notice.item[URL].data)
968 			{
969 				COMMENT(&notice, &buf, "Unpublished & Not for Publication", 0);
970 				comment(&notice, &buf, NiL, 0, 0);
971 			}
972 			if (notice.item[URL].data)
973 			{
974 				copy(&tmp, "This software is licensed", -1);
975 				if (notice.item[CORPORATION].data || notice.item[COMPANY].data)
976 				{
977 					copy(&tmp, " by", -1);
978 					if ((notice.item[PARENT].size + (notice.item[CORPORATION].data ? (notice.item[CORPORATION].size + notice.item[INCORPORATION].size) : notice.item[COMPANY].size)) >= (COMLONG - 6))
979 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
980 					else
981 						PUT(&tmp, ' ');
982 					if (notice.item[PARENT].data)
983 					{
984 						expand(&notice, &tmp, &notice.item[PARENT]);
985 						copy(&tmp, " ", -1);
986 					}
987 					if (notice.item[CORPORATION].data)
988 					{
989 						expand(&notice, &tmp, &notice.item[CORPORATION]);
990 						if (notice.item[INCORPORATION].data)
991 						{
992 							copy(&tmp, " ", -1);
993 							expand(&notice, &tmp, &notice.item[INCORPORATION]);
994 						}
995 					}
996 					else if (notice.item[COMPANY].data)
997 						expand(&notice, &tmp, &notice.item[COMPANY]);
998 				}
999 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1000 				COMMENT(&notice, &buf, "under the terms and conditions of the license in", 0);
1001 				expand(&notice, &tmp, &notice.item[URL]);
1002 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1003 				if (notice.item[URLMD5].data)
1004 				{
1005 					copy(&tmp, "(with an md5 checksum of ", -1);
1006 					expand(&notice, &tmp, &notice.item[URLMD5]);
1007 					copy(&tmp, ")", -1);
1008 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1009 				}
1010 				comment(&notice, &buf, NiL, 0, 0);
1011 			}
1012 			else if (notice.type == PROPRIETARY)
1013 			{
1014 				COMMENT(&notice, &buf, "The copyright notice above does not evidence any", 0);
1015 				COMMENT(&notice, &buf, "actual or intended publication of such source code", 0);
1016 				comment(&notice, &buf, NiL, 0, 0);
1017 			}
1018 		}
1019 		if (v = notice.item[NOTICE].data)
1020 		{
1021 			x = v + notice.item[NOTICE].size;
1022 			if (*v == '\n')
1023 				v++;
1024 			item.quote = notice.item[NOTICE].quote;
1025 			do
1026 			{
1027 				for (item.data = v; v < x && *v != '\n'; v++);
1028 				if ((item.size = v - item.data) && *item.data == '\t')
1029 				{
1030 					item.data++;
1031 					item.size--;
1032 					h = 0;
1033 				}
1034 				else
1035 					h = -1;
1036 				expand(&notice, &tmp, &item);
1037 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), h);
1038 			} while (v++ < x);
1039 			if (item.size)
1040 				comment(&notice, &buf, NiL, 0, 0);
1041 		}
1042 		if (notice.item[ORGANIZATION].data)
1043 		{
1044 			expand(&notice, &tmp, &notice.item[ORGANIZATION]);
1045 			comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1046 			if (notice.item[i = PARENT].data || notice.item[i = CORPORATION].data)
1047 				expand(&notice, &tmp, &notice.item[i]);
1048 			if (notice.item[COMPANY].data)
1049 			{
1050 				if (SIZ(&tmp))
1051 					PUT(&tmp, ' ');
1052 				expand(&notice, &tmp, &notice.item[COMPANY]);
1053 			}
1054 			if (SIZ(&tmp))
1055 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1056 			if (notice.item[LOCATION].data)
1057 			{
1058 				expand(&notice, &tmp, &notice.item[LOCATION]);
1059 				comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1060 			}
1061 			comment(&notice, &buf, NiL, 0, 0);
1062 		}
1063 	}
1064 	if (v = notice.item[AUTHOR].data)
1065 	{
1066 		x = v + notice.item[AUTHOR].size;
1067 		q = (x - v) == 1 && (*v == '*' || *v == '-');
1068 		k = q && notice.type != USAGE ? -1 : 0;
1069 		for (;;)
1070 		{
1071 			if (!q)
1072 			{
1073 				while (v < x && (*v == ' ' || *v == '\t' || *v == '\r' || *v == '\n' || *v == ',' || *v == '+'))
1074 					v++;
1075 				if (v >= x)
1076 					break;
1077 				item.data = v;
1078 				while (v < x && *v != ',' && *v != '+' && *v++ != '>');
1079 				item.size = v - item.data;
1080 				item.quote = notice.item[AUTHOR].quote;
1081 			}
1082 			h = 0;
1083 			for (i = 0; i < notice.ids; i++)
1084 				if (q || item.size == notice.id[i].name.size && !strncmp(item.data, notice.id[i].name.data, item.size))
1085 				{
1086 					h = 1;
1087 					if (notice.type == USAGE)
1088 					{
1089 						copy(&buf, "[-author?", -1);
1090 						expand(&notice, &buf, &notice.id[i].value);
1091 						PUT(&buf, ']');
1092 					}
1093 					else
1094 					{
1095 						if (k < 0)
1096 						{
1097 							COMMENT(&notice, &buf, "CONTRIBUTORS", 0);
1098 							comment(&notice, &buf, NiL, 0, 0);
1099 						}
1100 						k = 1;
1101 						expand(&notice, &tmp, &notice.id[i].value);
1102 						comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1103 					}
1104 					if (!q)
1105 						break;
1106 				}
1107 			if (q)
1108 				break;
1109 			if (!h)
1110 			{
1111 				if (notice.type == USAGE)
1112 				{
1113 					copy(&buf, "[-author?", -1);
1114 					expand(&notice, &buf, &item);
1115 					PUT(&buf, ']');
1116 				}
1117 				else
1118 				{
1119 					if (k < 0)
1120 					{
1121 						COMMENT(&notice, &buf, "CONTRIBUTORS", 0);
1122 						comment(&notice, &buf, NiL, 0, 0);
1123 					}
1124 					k = 1;
1125 					expand(&notice, &tmp, &item);
1126 					comment(&notice, &buf, BUF(&tmp), USE(&tmp), 0);
1127 				}
1128 			}
1129 		}
1130 		if (k > 0)
1131 			comment(&notice, &buf, NiL, 0, 0);
1132 	}
1133 	if (notice.type == USAGE)
1134 	{
1135 		copy(&buf, "[-copyright?", -1);
1136 		copyright(&notice, &buf);
1137 		PUT(&buf, ']');
1138 		if (notice.item[URL].data)
1139 		{
1140 			copy(&buf, "[-license?", -1);
1141 			expand(&notice, &buf, &notice.item[URL]);
1142 			PUT(&buf, ']');
1143 		}
1144 		PUT(&buf, '\n');
1145 	}
1146 	else
1147 		comment(&notice, &buf, NiL, -1, 0);
1148 	return END(&buf);
1149 }
1150