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

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


#include "audio.h"

int parens;

Info*
info(char *n, char *v)
{
	Info *i;

	i = mal(sizeof(Info));
	i->name = n;
	i->value = v;
	if(i->name == strtitle)
		ntitle++;
	else
	if(i->name == strartist)
		nartist++;
	else
	if(i->name == strmusic)
		nmusic++;
	return i;
}

void*
mal(long n)
{
	void *v;

	totalmal += n;
	v = malloc(n);
	if(v == 0)
		sysfatal("out of mem");
	memset(v, 0, n);
	return v;
}

Sym*
symdict(char *name)
{
	Sym *s;
	ulong h;
	int c, c0;
	char *p;

loop:
	h = 0;
	for(p = name; c = *p; p++)
		h = h*3 + (uchar)c;
	if(p - name >= Strsize-10) {
		name[Strsize-11] = 0;
		goto loop;
	}

	if((long)h < 0)
		h = ~h;
	h %= nelem(hash);
	c0 = name[0];
	for(s = hash[h]; s; s = s->link)
		if(s->name[0] == c0)
			if(strcmp(s->name, name) == 0)
				return s;

	c = (p-name)+1;
	if(c > nstringsp) {
		nstringsp = 5000;
		stringsp = mal(nstringsp);
	}
	s = mal(sizeof(Sym));
	s->name = stringsp;
	stringsp += c;
	nstringsp -= c;
	strcpy(s->name, name);

	s->label = 0;
	s->link = hash[h];
	hash[h] = s;

	return s;
}

char*
strdict(char *name)
{
	return symdict(name)->name;
}

int
mapchar(char **key)
{
	Runeinf ri;
	int c;

loop:
	c = getrune(key);
	runeinf(c, &ri);
	switch(ri.class) {
	case Alpha:
		if(ri.lower != c)
			runeinf(ri.lower, &ri);
	case Numer:
		if(ri.latin[0])
			c = ri.latin[0];
		break;
	case Space:
		c = ' ';
		break;
	case Null:
		c = 0;
		break;
	default:
		goto loop;
	}
	return c;
}

int
tiebreak(Group *g1, Group *g2)
{
	Cut *c;
	int n1, n2;

	if(g1 == 0) {
		if(g2 == 0)
			return 0;
		return -1;
	}
	if(g2 == 0)
		return +1;
	n1 = 0;
	for(c=g1->cut; c; c=c->link)
		n1++;
	n2 = 0;
	for(c=g2->cut; c; c=c->link)
		n2++;
	return n2-n1;
}

int
cxcmp(void *vv1, void *vv2)
{
	Cxlist *v1, *v2;
	char *k1, *k2;
	int n1, n2;
	char buf[1000], *b2;

	v1 = vv1;
	v2 = vv2;
	k1 = v1->info->value;
	k2 = v2->info->value;

	for(;;) {
		n1 = mapchar(&k1);
		n2 = mapchar(&k2);
		if(n1 > n2)
			return +1;
		if(n1 < n2)
			return -1;
		if(n1 == 0) {
			strncpy(buf, titstring(v1->group), sizeof(buf));
			b2 = titstring(v2->group);
			n1 = strcmp(buf, b2);
			if(n1)
				return n1;
			break;
		}
	}
	return 0;
}

int
cxcmp1(void *vv1, void *vv2)
{
	Cxlist *v1, *v2;
	int n;

	v1 = vv1;
	v2 = vv2;
	n = cxcmp(v1, v2);
	if(n == 0)
		return tiebreak(v1->group, v2->group);
	return 0;
}

int
cxcmp2(void *vv1, void *vv2)
{
	Cxlist *v1, *v2;
	int n;

	v1 = vv1;
	v2 = vv2;
	n = cxcmp(v1, v2);
	if(n)
		return n;
	if(v1->group->type == Gdupl) {
		if(v2->group->type == Gdupl)
			return 0;
		return +1;
	}
	if(v2->group->type == Gdupl)
		return -1;
	return 0;
}

int
cutcmp(void *vv1, void *vv2)
{
	Cxlist *v1, *v2;
	Cut *u1, *u2;

	v1 = vv1;
	v2 = vv2;
	u1 = v1->cut;
	u2 = v2->cut;
	if(u1->title != u2->title)
		return strcmp(u2->title, u1->title);
	return 0;
}

int
cutcmp1(void *vv1, void *vv2)
{
	Cxlist *v1, *v2;
	Cut *u1, *u2;

	v1 = vv1;
	v2 = vv2;
	u1 = v1->cut;
	u2 = v2->cut;
	if(u1->title != u2->title)
		return strcmp(u2->title, u1->title);
	return u2->cut - u1->cut;
}

int
titcmp(void *vv1, void *vv2)
{
	Cxlist *v1, *v2;
	char *k1, *k2;
	int n;

	v1 = vv1;
	v2 = vv2;
	k1 = v1->group->title;
	k2 = v2->group->title;
	if(k1 == 0) {
		if(k2 == 0)
			return tiebreak(v1->group, v2->group);
		return -1;
	}
	if(k2 == 0)
		return +1;
	n = strcmp(k1, k2);
	if(n)
		return n;
	return tiebreak(v1->group, v2->group);
}

/*
 * this is same as access in database
 * must be constant and portable
 */
int
srchash(char *s)
{
	ulong h;
	int c;

	h = 0;
	for(; c = *s; s++)
		h = h*3 + (c & 0xff);
	return h & 0xff;
}

Group*
parse(void)
{
	char *p, *q;
	Group *g, *r;
	Sym *s1, *s;
	Info *f, *f0;
	int t, setup, xsetup;

	r = mal(sizeof(Group));
	r->type = Ggroup;

	setup = 0;
	xsetup = 0;
	f0 = 0;
	f = 0;
	while ((p = getline()) != nil) {
		q = strchr(p, ':');
		if(q) {
			*q++ = 0;
			s1 = trim(p);
			if(s1 == 0)
				continue;
			p = s1->name;
			s = trim1(q);
			if(s == 0) {
				/* BOTCH probably r isnt the labeled object! */
				if(s1->label)
					fprint(2, "%ld: dual label %s\n", lineno, s1->name);
				s1->label = r;
				continue;
			}
			if(p == strsetup) {
				p = s->name;
				if(p == strsort)
					setup |= Ssort;
				else
				if(p == strtitle)
					setup |= Stitle;
				else
				if(p == strartist)
					setup |= Sartist;
				else
				if(p == strmusic)
					setup |= Smusic;
				else
				if(p == strnosplit)
					setup |= Snosplit;
				else
				if(p == strnocut)
					setup |= Snocut;
				else
				if(p == strnoword)
					setup |= Snoword;
				else
				if(p == strmark)
					setup |= Smark;
				else
				if(p == strnumber)
					setup |= Snumber;
				else
				if(p == strrelative)
					setup |= Srelative;
				else
					print("unknown setup: %s\n",  p);
				if(f0 == 0) {
					xsetup |= setup;
					setup = 0;
				}
				continue;
			}
			if(p == strpath) {
				apath = s->name;
				if(apath == strdot)
					apath = strnull;
				continue;
			}
			if(p == strvolume) {
				avolume = s->name;
				continue;
			}
			if(p == strfile) {
				t = Gfile;
				goto mkg1;
			}
			if(p == strdupl) {
				t = Gdupl;
				goto mkg1;
			}
			if(p == strvirt) {
				t = Gvirt;
				if(allfile)
					t = Gfile;
				goto mkg1;
			}
			if(p == strrat) {
				g = mal(sizeof(Group));
				g->type = Grat;
				g->ref = s;
				if(f0)
					fprint(2, "%ld: rat shouldnt have info\n", lineno);
				goto mkg2;
			}
			if(p == strref) {
				g = mal(sizeof(Group));
				g->type = Gref;
				g->ref = s;
				if(f0)
					fprint(2, "%ld: ref shouldnt have info\n", lineno);
				goto mkg2;
			}
			if(p == strtext) {
				gettext(s);
				continue;
			}
			if(f0 == 0) {
				f = info(p, s->name);
				f0 = f;
			} else {
				f->link = info(p, s->name);
				f = f->link;
			}
			continue;

		mkg1:
			g = mal(sizeof(Group));
			g->type = t;
			g->path = apath;
			g->volume = avolume;
			avolume = 0;
			g->file = s->name;
			if(s->label == 0)
				s->label = g;

		mkg2:
			g->setup = setup;
			g->info = f0;
			if(r->group == 0)
				r->group = g;
			else
				r->egroup->link = g;
			r->egroup = g;
			f = 0;
			f0 = 0;
			setup = 0;
			continue;
		}
		q = strchr(p, '{');
		if(q) {
			parens++;
			g = parse();
			if(g == nil)		/* parse error? */
				continue;
			goto mkg2;
		}
		q = strchr(p, '}');
		if(q) {
			parens--;
			break;
		}
	}
	if(r->group == nil) {
		fprint(2, "%ld: syntax (empty set)\n", lineno);
//		error++;
		return nil;
	}
	r->setup = xsetup;
	return r;
}

Sym*
trim(char *p)
{
	char *q;
	int c;

	for(;;) {
		c = p[0];
		if(c != ' ' && c != '\t')
			break;
		p++;
	}
	q = strchr(p, 0);
	while(q > p) {
		c = q[-1];
		if(c != ' ' && c != '\t')
			break;
		q--;
	}
	if(q == p)
		return 0;
	*q = 0;
	return symdict(p);
}

Sym*
trim1(char *p)
{
	char *q;

	q = strchr(p, '~');
	if(q == 0)
		return trim(p);
	*q++ = 0;
	strncpy(buf, q, sizeof(buf));
	q = strchr(buf, 0);
	while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
		q--;
	while(*p == ' ' || *p == '\t')
		p++;
	q[0] = ',';
	q[1] = ' ';
	strcpy(q+2, p);
	return trim(buf);
}

char*
getstrinfo(Info *f, char *name)
{
	f = getinfo(f, name);
	if(f && f->value)
		return f->value;
	return "<none>";
}

Info*
getinfo(Info *f, char *name)
{

	for(; f; f=f->link)
		if(f->name == name)
			return f;
	return 0;
}

char*
xtitle(Cxlist *c, int flag)
{
	char buf[1000];
	char *p;
	Info *f, *o;
	Group* g;

	g = c->group;
	o = c->info;
	for(f=g->info; f; f=f->link)
		if(f == o) {
			if(f->name == strtitle)
				goto foundt;
			if(f->name == strartist)
				goto founda;
		}
	p = titstring(g);
	goto addterm;

foundt:
	buf[0] = buf[sizeof buf - 1] = 0;
	if(!flag)
		strncpy(buf, f->value, sizeof(buf));
	for(f=g->info; f; f=f->link)
		if(f->name == strartist) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	for(f=g->info; f; f=f->link)
		if(f != o && f->name == strtitle) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	p = buf;
	goto addterm;

founda:
	buf[0] = 0;
	if(!flag)
		strncpy(buf, f->value, sizeof(buf));
	for(f=g->info; f; f=f->link)
		if(f->name == strtitle) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	for(f=g->info; f; f=f->link)
		if(f != o && f->name == strartist) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	p = buf;
	goto addterm;

addterm:
	if(g->type == Ggroup)
		strncat(p, ">", sizeof(buf));
	else
	if(g->type == Gvirt)
		strncat(p, "*", sizeof(buf));
	assert(buf[sizeof buf - 1] == 0);
	return strdup(p);
}

char*
titstring(Group *g)
{
	Info *f;
	static char buf[1000];

	if(g == nil)
		return "gnil1";
	while(g->type == Gref || g->type == Grat) {
		g = g->group;
		if(g == nil)
			return "gnil2";
	}

	buf[0] = buf[sizeof buf - 1] = '\0';
	for(f=g->info; f; f=f->link)
		if(f->name == strtitle) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	for(f=g->info; f; f=f->link)
		if(f->name == strartist) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	assert(buf[sizeof buf - 1] == '\0');
	if(!buf[0]) {
		if(g->type == Ggroup)
			return titstring(g->group);
		snprint(buf, sizeof(buf), "noname/type=%d", g->type);
	}
	assert(buf[sizeof buf - 1] == '\0');
	return buf;
}

char*
artstring(Group *g)
{
	Info *f;
	static char buf[1000];

	buf[sizeof buf - 1] = '\0';
	while(g->type == Gref || g->type == Grat)
		g = g->group;

	buf[0] = 0;
	for(f=g->info; f; f=f->link)
		if(f->name == strartist) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	for(f=g->info; f; f=f->link)
		if(f->name == strtitle) {
			if(buf[0])
				strncat(buf, "; ", sizeof(buf));
			strncat(buf, f->value, sizeof(buf));
		}
	if(!buf[0])
		snprint(buf, sizeof(buf), "noname/type=%d", g->type);
	assert(buf[sizeof buf - 1] == '\0');
	return buf;
}

void
gettext(Sym *s)
{
	char *p, *q;
	Info *i0, *in, *i;
	Group *g;
	Symlink *l;

	g = mal(sizeof(*g));
	g->link = textlist;
	textlist = g;
	g->type = Gtext;
	g->title = strtext;
	l = mal(sizeof(*l));
	l->sym = s;
	g->symlink = l;

	/*
	 * multiple text
	 */
	for(;;) {
		p = getline();
		if(p == 0)
			return;
		q = strstr(p, "text:");
		if(!q)
			break;
		q += 5;
		s = trim1(q);
		l = mal(sizeof(*l));
		l->sym = s;
		l->link = g->symlink;
		g->symlink = l;
	}

	/*
	 * title
	 */
	q = strstr(p, "title:");
	if(q) {
		q += 6;
		s = trim1(q);
		g->title = s->name;
		p = getline();
		if(p == 0) {
			fprint(2, "%ld: title after text\n", lineno);
			return;
		}
	}

	/*
	 * left quote {
	 */
	q = strchr(p, '{');
	if(!q) {
		fprint(2, "%ld: no { after text\n", lineno);
		error++;
	}

	/*
	 * all up to right quote }
	 */
	i0 = 0;
	in = 0;
	for(;;) {
		p = getline();
		if(p == 0) {
			fprint(2, "%ld: no } after {\n", lineno);
			error++;
			return;
		}
		q = strchr(p, '}');
		if(q)
			break;
		if(*p == '\t')
			p++;
		i = mal(sizeof(*i));
		i->value = strdict(p);
		if(in)
			in->link = i;
		else
			i0 = i;
		in = i;
	}
	g->info = i0;
}

char*	typename[] =
{
	[Ggroup]	= "Ggroup",
	[Gfile]		= "Gfile",
	[Gdupl]		= "Gdupl",
	[Gvirt]		= "Gvirt",
	[Grat]		= "Grat",
	[Gref]		= "Gref",
	[Glink]		= "Glink",
	[Gcut]		= "Gcut",
	[Gtext]		= "Gtext",
};

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.