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