Plan 9 from Bell Labs’s /sys/src/games/aprep/main.c

Copyright © 2021 Plan 9 Foundation
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <audio.h>
#include <pool.h>

extern int parens;

/*
	bugs:
	sort shorter first
*/

void
main(int argc, char *argv[])
{
	int i;
	Group *g;
	char *ofile, *ifile;

//	mainmem->flags |= POOL_PARANOIA;
	strdot = strdict("./");
	strnull = strdict("");
	strartist = strdict("artist");
	strclass = strdict("class");
	strfile = strdict("file");
	strdupl = strdict("dupl");
	strpath = strdict("path");
	strrat = strdict("rat");
	strref = strdict("ref");
	strmusic = strdict("music");
	strtitle = strdict("title");
	strvirt = strdict("virt");
	strsetup = strdict("setup");
	strnumber = strdict("number");
	strsort = strdict("sort");
	strnosplit = strdict("nosplit");
	strnocut = strdict("nocut");
	strnoword = strdict("noword");
	strmark = strdict("mark");
	strrelative = strdict("relative");
	strvarious = strdict("various");
	strvolume = strdict("volume");
	strtext = strdict("text");

	apath = strnull;
	avolume = 0;

	searchinit();

	ofile = "rawmap";
	maxgroup = Maxgroup;
	ARGBEGIN {
	default:
		fprint(2, "usage: aprep [-dfprv] [-s splitsize] [-o ofile] ifile...\n");
		exits("usage");
	case 'o':	/* output file */
		ofile = ARGF();
		break;
	case 's':	/* split size */
		maxgroup = atoi(ARGF());
		break;
	case 'f':	/* turn virts to files */
		allfile++;
		break;
	case 'v':	/* dont add volume extension */
		volflag++;
		break;
	case 'd':
		dupflag++;
		break;
	case 'r':	/* kill no-ref's; normal use for cd's */
		refflag++;
		break;
	case 'p':	/* path */
		apath = strdict(ARGF());
		break;
	} ARGEND

	openw(ofile);
	gargc = argc;
	gargv = argv;

	if(argc == 0) {
		ifile = "map";
		gargc = 1;
		gargv = &ifile;
	}
	lineno = 0;
	root = parse();

	if(root == 0 || error != 0)
		exits("error");
	if (parens)
		fprint(2, "unbalanced braces; count %d\n", parens);
poolcheck(mainmem);
	print("patch1\n");
	patch1(root);
	patch1_5(root, 0);

	i = 0;
	for(g=root->group; g; g=g->link)
		if(g->type == Ggroup)
			i++;
	if(ntitle > i)
		i = ntitle;
	if(nartist > i)
		i = nartist;
	if(nmusic > i)
		i = nmusic;
	i += 500;
	cxlist = mal(i*sizeof(*cxlist));
	ecxlist = cxlist + i;

	print("patch2\n");
	patch2(root);

	print("patch3\n");
	patch3(root);

	print("patch4\n");
	patch4(root);

	print("patch5\n");
	patch5(root);

	print("text\n");
	gentext();

	print("cuts\n");
	gencut(root, 0, 0);
	unmark(root);

	print("title\n");
	gentitle(root);

	print("split\n");
	gensplit(root);

poolcheck(mainmem);
	for(pass=1; pass<=2; pass++) {
		print("pass %d\n", pass);
		offset = 0;
		for(i=0; i<4; i++)
			putint1("admp"[i]);
		for(i=0; i<10; i++)
			putint4(aux[i]);	/* future expansion */
		offsetnone = offset-2;
		putint2(1);			/* root count */
		putint4(root->offset1);
		putint4(root->offset2);
		for(i=0; i<6; i++)
			putint1("root>"[i]);
		expand(root);
		buildtitle();
		if(pass == 1) {
			buildword(strtitle);
			buildword(strartist);
			buildword(strmusic);
			buildclass(strclass);
			buildpath();
		}
		aux[0] = doindex();
	}
	print("size = %ld\n", offset);
	for(i=0; i<2048; i++)
		putint1(0);
	closew();
poolcheck(mainmem);
	exits(0);
}

void
gensplit(Group *r)
{
	Group *g;
	int n;

	switch(r->type) {
	default:
		print("unknown group type-1 %d\n", r->type);
		break;

	case Gref:
	case Grat:
	case Glink:
		if(r->group)
			gensplit(r->group);
		break;

	case Gtitle:
	case Gartist:
	case Gmusic:
	case Ggroup:
		if(r->setup & Swassplit)
			break;
		r->setup |= Swassplit;
		n = 0;
		for(g=r->group; g; g=g->link) {
			n++;
			gensplit(g);
		}
		splitgroup(r, n);
		break;

	case Gfile:
	case Gdupl:
	case Gvirt:
		break;

	}
}

void
gentitle(Group *r)
{
	Group *g;

	switch(r->type) {
	default:
		print("unknown group type-2 %d\n", r->type);
		break;

	case Gref:
	case Grat:
	case Glink:
//		if(r->group)
//			gentitle(r->group);
		break;

	case Gtitle:
	case Gartist:
	case Gmusic:
	case Ggroup:
		for(g=r->group; g; g=g->link) {
			gentitle(g);
			switch(g->type) {
			case Gtitle:
			case Gartist:
			case Gmusic:
				addtitle(g, r, 0);
				break;
			default:
				addtitle(g, r, g->ordinal);
			}
		}
		break;

	case Gfile:
	case Gdupl:
	case Gvirt:
		break;
	}
}

void
expand(Group *r)
{
	int n, c;
	char *p;
	Cut *u;
	Group *g, *rg;
	Info *f;

	if(pass == 1) {
		if(r->offset1)
			return;
		r->offset1 = offset;
	} else {
		if(r->setup & Soff2)
			return;
		r->setup |= Soff2;
		if(r->offset1 != offset) {
			print("expand phase error %ld %ld\n",
				r->offset1, offset);
			offset = r->offset1;
		}
	}

	rg = r->group;
	switch(r->type) {
	default:
		print("unknown group type-3 %d\n", r->type);
		putint2(0);
		break;

	case Gref:
	case Grat:
	case Glink:
		if(rg)
			expand(rg);
		break;

	case Ggroup:
	case Gtitle:
	case Gartist:
	case Gmusic:
		n = 0;
		for(g=rg; g; g=g->link)
			n++;
		r->count = n;
		putint2(r->count);
		for(g=rg; g; g=g->link)
			prgroup(g);
		for(g=rg; g; g=g->link)
			expand(g);
		gpath(r);
		break;

	case Gfile:
	case Gdupl:
	case Gvirt:
		putint2(r->count);
		n = 0;
		prpath(r);
		n++;
		for(f=r->info; f; f=f->link) {
			prinfo(f);
			n++;
		}
		if(pass == 1)
			sortcut(r);
		for(u=r->cut; u; u=u->link) {
			prcut(u);
			n++;
		}
		r->count = n;

		for(f=r->info; f; f=f->link)
			if(f->group)
				expand(f->group);
		gpath(r);
		switch(r->type) {
		case Gfile:
		case Gdupl:
			goff2(r);
		}
		break;

	case Gtext:
		n = 0;
		for(f=r->info; f; f=f->link)
			n++;
		r->count = n;
		putint2(r->count);
		for(f=r->info; f; f=f->link) {
			putint4(offsetnone);
			putint4(offsetnone);
			p = f->value;
			if(p != nil) {
				while(c = *p++) {
					if(c == '\t') {
						putint1(' ');
						putint1(' ');
						putint1(' ');
						putint1(' ');
					} else
						putint1(c);
				}
			}
			putint1(0);
		}
		break;


	}
	if(r->offset2 == 0)
		r->offset2 = offsetnone;
}

void
goff2(Group *g)
{
	char *p;
	int c;

	g->off2str = offset;
	putint4(g->offset1);
	putint4(g->offset2);

	p = titstring(g);
	while(c = *p++)
		putint1(c);
	putint1(0);

	p = g->path;
	if(p)
		while(c = *p++)
			putint1(c);
	p = g->file;
	if(p)
		while(c = *p++)
			putint1(c);
	p = g->volume;
	if(p) {
		putint1(' ');
		while(c = *p++)
			putint1(c);
	}
	putint1(0);
}

void
gpath(Group *r)
{
	int n;
	Cxlist *c;

	listp = cxlist;
	genpath(r);
	unmark(r);
	n = listp - cxlist;
	r->offset2 = offsetnone;
	if(n > 0) {
		r->offset2 = offset;
		putint2(n);
		for(c=cxlist; c<listp; c++)
			putint4(c->group->off2str);
	}
}

Group*
incr(Group *g)
{
	Group *t;

	if(g) {
		t = g->egroup;
		if(t->setup & Sgnext)
			return t;
	}
	return 0;
}

void
addspan(Group *r)
{
	Group *u, *t, *g5, *g25, *g125, *g625, *g3125;
	int i;

	g5 = r;
	for(i=0; g5 && i<5; i++)
		g5 = incr(g5);

	g25 = g5;
	for(i=0; g25 && i<25-5; i++)
		g25 = incr(g25);

	g125 = g25;
	for(i=0; g125 && i<125-25; i++)
		g125 = incr(g125);

	g625 = g125;
	for(i=0; g625 && i<625-125; i++)
		g625 = incr(g625);

	g3125 = g625;
	for(i=0; g3125 && i<3125-625; i++)
		g3125 = incr(g3125);

	if (i >= 3125-625)
		fprint(2, "addspan: %s: i >= 3125-625\n", r->title);

	while(g5) {
		t = incr(r);
		u = mal(sizeof(Group));
		u->title = ">> 5";
		u->type = Glink;
		u->group = g5;
		r->egroup->link = u;
		r->egroup = u;
		if(g25) {
			u = mal(sizeof(Group));
			u->title = ">> 25";
			u->type = Glink;
			u->group = g25;
			r->egroup->link = u;
			r->egroup = u;
			if(g125) {
				u = mal(sizeof(Group));
				u->title = ">> 125";
				u->type = Glink;
				u->group = g125;
				r->egroup->link = u;
				r->egroup = u;
				if(g625) {
					u = mal(sizeof(Group));
					u->title = ">> 625";
					u->type = Glink;
					u->group = g625;
					r->egroup->link = u;
					r->egroup = u;
					if(g3125) {
						u = mal(sizeof(Group));
						u->title = ">> 3125";
						u->type = Glink;
						u->group = g3125;
						r->egroup->link = u;
						r->egroup = u;
						g3125 = incr(g3125);
					}
					g625 = incr(g625);
				}
				g125 = incr(g125);
			}
			g25 = incr(g25);
		}
		g5 = incr(g5);
		r = t;
	}
}

void
splitgroup(Group *r, int n)
{
	int i;
	Group *g, *u, *t, *r0;

	if(maxgroup == 0 || n <= maxgroup)
		return;

	i = 1;
	r0 = r;
	for(g=r->group; g; g=g->link) {
		i++;
		if(i < maxgroup)
			continue;
		if(g->link == 0 || g->link->link == 0)
			break;

		u = mal(sizeof(Group));
		u->title = ">>>";
		u->type = r->type;
		u->setup |= Sgnext;

		t = mal(sizeof(Group));
		t->title = "<<<";
		t->type = Glink;

		t->link = g->link;
		g->link = u;
		u->group = t;
		u->egroup = r->egroup;
		r->egroup = u;
		t->group = r;
		r = u;
		g = t;
		i = 2;
	}
	addspan(r0);
}

void
prcut(Cut *u)
{
	Group *r, *g;
	char buf[100];
	int c;
	long n, m1, m5, m25;
	char *p;

	r = u->parent;
	if(pass == 2 && r->setup & Swassplit) {
		/* adjust cut backpointer to point at
		 * correct page of split group */
		m1 = maxgroup-2;
		m5 = m1 * 5;
		m25 = m1 * 25;
		n = u->cut - 1;
		while(n > m1) {
			if(r->type == Ggroup)
				for(g=r->group; g; g=g->link) {
					if(g->setup & Sgnext) {
						r = g;
						break;
					}
			}
			if(n > m25 &&
			   r->link != 0 &&
			   r->link->link != 0 &&
			   r->link->link->type == Glink) {
				r = r->link->link->group;
				n -= m25;
			} else
			if(n > m5 &&
			   r->link != 0 &&
			   r->link->type == Glink) {
				r = r->link->group;
				n -= m5;
			} else
				n -= m1;
		}
	}
	putint4(r->offset1);
	putint4(r->offset2);
	buf[sizeof(buf)-1] = 0;
	snprint(buf, sizeof(buf)-1, "%-16s %d", u->title, u->cut);
	assert(buf[sizeof(buf)-1] == 0);
	for(p=buf; c=*p; p++)
		putint1(c);
	putint1(0);
}

void
prpath(Group *g)
{
	int c;
	char *p;

	putint4(g->offset1);
	putint4(g->offset2);
	for(p="path             "; c=*p; p++)
		putint1(c);
	if(p=g->path) {
		for(; c=*p; p++)
			putint1(c);
	}
	if(p=g->file)
		for(; c=*p; p++)
			putint1(c);
	if(p=g->volume) {
		putint1(' ');
		for(; c=*p; p++)
			putint1(c);
	}
	putint1(0);
}

void
prinfo(Info *f)
{
	int c;
	char *p;
	Group *g;

	g = f->group;
	if(g) {
		putint4(g->offset1);
		putint4(g->offset2);
	} else {
		putint4(offsetnone);
		putint4(offsetnone);
	}
	snprint(buf, sizeof(buf), "%-16s %s", f->name, f->value);
	for(p=buf; c=*p; p++)
		putint1(c);
	putint1(0);
}

void
prgroup(Group *g)
{
	int c;
	char *p;

	p = g->title;

loop:
	if(g == 0) {
		putint4(offsetnone);
		putint4(offsetnone);
		putint1(0);
		return;
	}
	switch(g->type) {
	case Gref:
	case Grat:
	case Glink:
		g = g->group;
		goto loop;
	}

	putint4(g->offset1);
	putint4(g->offset2);
	while(c = *p++)
		putint1(c);
	putint1(0);
}

void
addtitle(Group *g, Group *r, int o)
{
	char buf[1000];
	Group *g0;

	if(g->title)
		return;
	buf[0] = buf[sizeof buf - 1] = 0;
	if(o != 0 && (r->setup & Snumber))
		snprint(buf, sizeof(buf), "%d. ", o);
	g0 = g;

loop:
	switch(g->type) {
	default:
		print("unknown %d %s\n", g->type, titstring(g));
		strncat(buf, "unknown", sizeof(buf));
		break;
	case Grat:
		strncat(buf, g->ref->name, sizeof(buf));
		break;
	case Gref:
		if(g = g->group)
			goto loop;
		break;
	case Gtitle:
		strncat(buf, "title>", sizeof(buf));
		break;
	case Gmusic:
		strncat(buf, "music>", sizeof(buf));
		break;
	case Gartist:
		strncat(buf, "artist>", sizeof(buf));
		break;
	case Ggroup:
		strncat(buf, titstring(g), sizeof(buf));
		strncat(buf, ">", sizeof(buf));
		break;
	case Gvirt:
		strncat(buf, titstring(g), sizeof(buf));
		strncat(buf, "*", sizeof(buf));
		break;
	case Gfile:
	case Gdupl:
		strncat(buf, titstring(g), sizeof(buf));
		break;
	}
	assert(buf[sizeof buf - 1] == 0);
	g0->title = strdup(buf);
}

void
sortcut(Group *g)
{
	Cut *u;
	Cxlist *c;

	listp = cxlist;
	for(u=g->cut; u; u=u->link) {
		u->title = getstrinfo(u->parent->info, strtitle);
		listp->cut = u;
		listp++;
	}
//	usort(cutcmp, cutcmp1);
	qsort(cxlist, listp-cxlist, sizeof(Cxlist), cutcmp1);
	g->cut = 0;
	for(c=cxlist; c<listp; c++) {
		u = c->cut;
		u->link = g->cut;
		g->cut = u;
	}
}

void
gencut(Group *g, Group *p, int cut)
{
	Cut *c;

	if(p) {
		c = mal(sizeof(Cut));
		c->parent = p;
		c->cut = cut;
		c->link = g->cut;
		g->cut = c;
	}

	if(g->setup & Srecur)
		return;
	g->setup |= Srecur;

	switch(g->type) {
	case Grat:
	case Gref:
		if(g->group)
			gencut(g->group, p, cut);
		break;
	case Ggroup:
		if(g->setup & Snocut)
			break;
		if(getinfo(g->info, strtitle) == 0) {
			for(g=g->group; g; g=g->link)
				gencut(g, p, cut);
			break;
		}

		p = g;
		for(g=g->group; g; g=g->link)
			gencut(g, p, g->ordinal);
		break;
	}
}

void
genpath(Group *r)
{
	Group *g, *rg;

	if(r->setup & Srecur)
		return;
	r->setup |= Srecur;
	rg = r->group;
	switch(r->type) {
	case Grat:
	case Gref:
		if(rg)
			genpath(rg);
		break;

	case Gfile:
	case Gdupl:
		if(listp >= ecxlist) {
			print("oops: genpath\n");
			break;
		}
		listp->group = r;
		listp++;
		break;

	case Ggroup:
		for(g=rg; g; g=g->link)
			if(g->type != Gtitle && g->type != Gartist)
				genpath(g);
		for(g=rg; g; g=g->link)
			if(g->type == Gtitle || g->type == Gartist)
				genpath(g);
		break;
	}
}

void
genlist(Group *g, char *str)
{
	Info *f;

	if(g->setup & Srecur)
		return;
	g->setup |= Srecur;

	if(g->type == Gref || g->type == Grat) {
		if(g->group)
			genlist(g->group, str);
		return;
	}
	for(f=g->info; f; f=f->link) {
		if(f->name == str) {
			if(listp >= ecxlist) {
				print("oops: genlist\n");
				continue;
			}
			listp->group = g;
			listp->info = f;
			listp++;
		}
	}
	if(g->type == Ggroup)
		for(g=g->group; g; g=g->link)
			genlist(g, str);
}

void
unmark(Group *g)
{
	if((g->setup & Srecur) == 0)
		return;
	g->setup &= ~Srecur;

	switch(g->type) {
	case Grat:
	case Gref:
		if(g->group)
			unmark(g->group);
		break;
	case Ggroup:
		for(g=g->group; g; g=g->link)
			unmark(g);
		break;
	}
}

Group*
igroup(Cxlist *x1, Cxlist *x2, int type, int flag)
{
	Group *g1, *g2;
	Cxlist *ox;
	int n;

	n = x2 - x1;
	if(n == 0) {
		print("n = 0\n");
		return 0;
	}
	g1 = mal(sizeof(Group));
	g1->type = type;
	n = 0;
	ox = 0;
	while(x1 < x2) {
		if(x1->group->type != Ggroup) {
			if(ox == 0 || cxcmp1(ox, x1) != 0) {
				g2 = mal(sizeof(Group));
				g2->type = Gref;
				g2->group = x1->group;
				g2->title = xtitle(x1, flag);
			
				if(g1->egroup == 0)
					g1->group = g2;
				else
					g1->egroup->link = g2;
				g1->egroup = g2;
				n++;
			}
			ox = x1;
		}
		x1++;
	}
	g1->setup |= Swassplit;
	splitgroup(g1, n);
	return g1;
}

/*
 * patch refs to defines put in ordinals
 */
void
patch1(Group *r)
{
	Group *g, *g0, *g1;
	int n, any;
	Sym *s;

	switch(r->type) {
	case Ggroup:
		/* rebuild group with non-null subgroups */
		g0 = nil;
		g1 = nil;
		n = 0;
		any = 0;
		for(g=r->group; g; g=g->link) {
			patch1(g);
			switch(g->type) {
			case Gtitle:
			case Gartist:
			case Gmusic:
			case Grat:
				break;

			case Ggroup:
			case Gref:
				n++;
				if(g->group == nil)
					continue;
				any = 1;
				g->ordinal = n;
				break;

			default:
				n++;
				any = 1;
				g->ordinal = n;
				break;
			}
			if(g0 == nil)
				g0 = g;
			else
				g1->link = g;
			g1 = g;
		}
		if(any == 0) {
			r->group = nil;
			break;
		}
		r->group = g0;
		g1->link = nil;
		break;

	case Gref:
		s = r->ref;
		if(s == 0) {
			if(!refflag)
				print("no ref\n");
			break;
		}
		if(s->label == 0) {
			if(!refflag)
				print("no ref %s\n", s->name);
			break;
		}
		r->group = s->label;
		break;
	}
}

/*
 * patch refs to defines put in ordinals
 */
void
patch1_5(Group *r, Info *d)
{
	Group *g;
	Info *f, *f1;

	switch(r->type) {
	case Ggroup:
		for(g=r->group; g; g=g->link)
			patch1_5(g, d);
		if(d != nil)
			break;
		for(f=r->info; f; f=f->link) {
			if(f->name == strmusic)
				for(g=r->group; g; g=g->link)
					patch1_5(g, f);
			if(f->name == strartist && f->value != strvarious)
				for(g=r->group; g; g=g->link)
					patch1_5(g, f);
		}
		break;

	case Gfile:
	case Gdupl:
	case Gvirt:
		if(d == nil)
			break;
		for(f=r->info; f; f=f->link)
			if(f->name == d->name && f->value == d->value)
				return;
		if(d->name == strartist)
			nartist++;
		if(d->name == strmusic)
			nmusic++;
		f1 = mal(sizeof(Info));
		f1->name = d->name;
		f1->value = d->value;
		if(r->info == 0) {
			r->info = f1;
			break;
		}
		for(f=r->info; f->link; f=f->link)
			if(f->name == d->name && f->link->name != d->name)
				break;
		f1->link = f->link;
		f->link = f1;
		break;
	}
}

void
patch2(Group *r)
{
	Group *g;

	if(r->type != Ggroup)
		return;
	for(g=r->group; g; g=g->link)
		patch2(g);
	if(r->setup & Ssort)
		sortgroup(r);
	if(r->setup & Smusic) {
		listp = cxlist;
		genlist(r, strmusic);
		unmark(r);
		if(listp-cxlist) {
			usort(cxcmp, cxcmp1);
//			qsort(cxlist, listp-cxlist, sizeof(Cxlist), cxcmp);
			g = igroup(cxlist, listp, Gmusic, 0);
			if(r->group)
				g->link = r->group;
			else
				r->egroup = g;
			r->group = g;
		}
	}
	if(r->setup & Sartist) {
		listp = cxlist;
		genlist(r, strartist);
		unmark(r);
		if(listp-cxlist) {
			usort(cxcmp, cxcmp1);
//			qsort(cxlist, listp-cxlist, sizeof(Cxlist), cxcmp);
			g = igroup(cxlist, listp, Gartist, 0);
			if(r->group)
				g->link = r->group;
			else
				r->egroup = g;
			r->group = g;
		}
	}
	if(r->setup & Stitle) {
		listp = cxlist;
		genlist(r, strtitle);
		unmark(r);
		if(listp-cxlist) {
			usort(cxcmp, cxcmp1);
//			qsort(cxlist, listp-cxlist, sizeof(Cxlist), cxcmp);
			g = igroup(cxlist, listp, Gtitle, 0);
			if(r->group)
				g->link = r->group;
			else
				r->egroup = g;
			r->group = g;
		}
	}
}

void
patch3(Group *r)
{
	Group *g, *g1;
	Info *f;
	Cxlist *x1, *x2;
	Sym *s;

	for(g = r->group; g; g = g->link) {
		switch(g->type) {
		case Ggroup:
			patch3(g);
			break;

		case Gfile:
		case Gdupl:
		case Gvirt:
			for(f = g->info; f; f = f->link) {
				if(f->group)
					continue;
				if(f->name != strartist &&
				   f->name != strtitle &&
				   f->name != strmusic)
					continue;
				listp = cxlist;
				genlist(root, f->name);
				unmark(root);
//				usort(cxcmp, cxcmp1);
				qsort(cxlist, listp-cxlist, sizeof(Cxlist), cxcmp2);
				x2 = cxlist;
				for(x1 = cxlist; x1 < listp; x1++) {
					if(x1->info->value == x2->info->value)
						continue;
					g1 = igroup(x2, x1, Ggroup, 1);
					if(f->name == strartist) {
						s = symdict(x2->info->value);
						if(s->label)
							print("rat redeclared: "
								"%s in %s\n",
								s->name,
								titstring(r));
						s->label = g1;
					}
					for(; x2 < x1; x2++)
						x2->info->group = g1;
				}
				g1 = igroup(x2, x1, Ggroup, 1);
				if(f->name == strartist) {
					s = symdict(x2->info->value);
					if(s->label)
						print("rat redeclared: %s in %s\n",
							s->name, titstring(r));
					s->label = g1;
				}
				for(; x2 < x1; x2++)
					x2->info->group = g1;
			}
			break;
		}
	}
}

void
patch4(Group *r)
{
	Group *g;
	Sym *s;

	switch(r->type) {
	case Ggroup:
		for(g=r->group; g; g=g->link)
			patch4(g);
		break;
	case Grat:
		s = r->ref;
		if(s == 0) {
			if(!refflag)
				print("no rat\n");
			break;
		}
		if(s->label == 0) {
			if(!refflag)
				print("no rat %s\n", s->name);
			break;
		}
		r->group = s->label;
		break;
	}
}

void
dorel(Group *g, Group *lg, Group *pg, Group *rg)
{
if (0) {
	Group *g0, *g1, *g2;

	if(g->type != Ggroup)
		return;

	g0 = mal(sizeof(Group));
	g0->type = Gref;
	g0->group = lg;

	g1 = mal(sizeof(Group));
	g1->type = Gref;
	g1->group = pg;

	g2 = mal(sizeof(Group));
	g2->type = Gref;
	g2->group = rg;

	g2->link = g->group;
	g1->link = g2;
	g0->link = g1;
	g->group = g0;
}
	USED(g);
}

void
patch5(Group *r)
{
	Group *g, *og, *ng;


	switch(r->type) {
	case Ggroup:
		og = nil;
		for(g=r->group; g; g=g->link) {
			patch5(g);
			og = g;
		}
		if(r->setup & Srelative) {
			for(g=r->group; g; g=g->link) {
				ng = g->link;
				if(ng == nil)
					ng = r->group;
				dorel(g, og, r, ng);
				og = g;
			}
		}
		break;
	}
}

void
gentext(void)
{
	Group *g, *g1;
	Symlink *l;
	Info *i, *i0;

	for(g=textlist; g; g=g->link) {
		for(l=g->symlink; l; l=l->link)
			if(g1 = l->sym->label) {
				i0 = mal(sizeof(*i0));
				i0->name = strtext;
				i0->value = g->title;
				i0->group = g;
				i = g1->info;
				if(i == 0) {
					g1->info = i;
					continue;
				}
				for(; i->link; i=i->link)
					;
				i->link = i0;
			}
	}
}

void
sortgroup(Group *r)
{
	Cxlist *x;
	Group *g;
	Info *f;

	if(r->type != Ggroup) {
		print("sort non-group: %s\n", titstring(r));
		return;
	}

	/*
	 * sort the titles just under the root
	 */
	x = cxlist;
	for(g = r->group; g; g = g->link) {
		if((f = getinfo(g->info, strtitle)) != nil ||
		    (f = getinfo(g->info, strartist)) != nil) {
			x->group = g;
			x->info = f;
			x++;
		} else
			print("sort and no tit/art: %s\n", titstring(r));
	}
	listp = x;
	usort(cxcmp, cxcmp1);
//	qsort(cxlist, listp-cxlist, sizeof(Cxlist), cxcmp);

	r->group = 0;
	r->egroup = 0;
	for(x=cxlist; x<listp; x++) {
		if(r->group == 0)
			r->group = x->group;
		else
			r->egroup->link = x->group;
		r->egroup = x->group;
	}
	if(r->group == 0) {
		print("nothing after sort: %s\n", titstring(r));
	} else
		r->egroup->link = 0;
}

int
gtype(Cxlist *x)
{
	Group *g;

	g = x->group;
	if(g == 0)
		return 0;
	if(g->type == Gref) {
		g = g->group;
		if(g == 0)
			return 0;
	}
	return g->type;
}

void
usort(int (*cmp)(void*, void*), int (*cmp1)(void*, void*))
{
	Cxlist *x, *y;

	qsort(cxlist, listp-cxlist, sizeof(Cxlist), cmp1);
	y = cxlist;
	if(y >= listp)
		return;

	for(x=y+1; x<listp; x++) {
		if(cmp(y, x) == 0) {
			if(gtype(x) == Gdupl)
				continue;
			if(gtype(y) == Gdupl) {
				*y = *x;
				continue;
			}
			if(dupflag && strchr(titstring(x->group), ';'))
				print("dup: %s\n", titstring(x->group));
		}
		y++;
		*y = *x;
	}
	listp = y+1;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@plan9.bell-labs.com.