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