#
/*	Voice Synthesizer Program "Speak"			*/
/*								*/
/*	Language: C						*/
/*	Programmer: M. D. McIlroy				*/
/*								*/
/*	For description of method see "Synthetic English	*/
/*	Speech by Rule", M. D. McIlroy, Bell Telephone		*/
/*	Laboratories, Inc. 1974					*/
/*		 modified for QMC synthesiser			*/
/*	George Coulouris	7 June 76			*/
/*	further alterations sept 76 j.d. for spout ****j*** 	*/
#define NT 800
#define NS 9500
#	define	FLAG	""
#	define	BELL	07
#define NRULE 20
#define	NETMODE	042	/*raw no echo, no mappings*/
# define	CR	015	/*term for spout*/

char *diags[] {
	0,
	"bad option",
	"no vocabulary",
	"can't create",
	"too many words",
	"too many chars" };

char *aeiou "aeiou";
char *aeiouy "aeiouy";
char *aeiouwxy "aeiouwxy";
char *aeo "aeo";
char *aou "aou";
char *bcdfgkpt "bcdfgkpt";
char *sendch  "\n\r \t";
#define	USRBRK	02000
#define ALL8	04000
#define NORMAL	0332
#define ITT	0100000
int	savetty, savebrks[8];
struct mode {
	char m_inspeed;
	char m_outspeed;
	char m_erase;
	char m_kill;
	int m_flags;
	char m_nldelay;
	char m_crdelay;
	char m_tbdelay;
	char m_vtdelay;
	char m_width;
	char m_length;
	int m_brk[8];
}	tty;

setbreak()
{
	register char *sp;
	int i;
	if(gterm(0,&tty) != -1) {
		savetty = tty.m_flags;
		for (i = 0; i<8; i++)	savebrks[i] = tty.m_brk[i];
		tty.m_flags =| USRBRK;
		sp = sendch;
		do setbit(&tty.m_brk[0], *sp) ;while(*++sp);
		sterm(0, &tty);
	}
}

setcook()
{
	int i;
	tty.m_flags = savetty;
	for(i = 0; i<8; i++) tty.m_brk[i] = savebrks[i];
	sterm(0, &tty);
	exit();
}

struct rec {
	int word,phon;
};
int recsize 4;
struct rec table[NT];
/*this table is an index to strings itgives the address of each word and each*/
/*phoneme in strings.*/
char strings[NS];
/*The index and the strings are read in from a file eng.m at the start of */
/* the program the strings are of the form */
/*   0'%''#'010   to represent ' ''%''#''cr'',''%''cr'  001 replaces % on rhs*/
/* 0'%''#''U''n'01'u''n'   to represent '%''#''U''n''cr'',''%'u''n'	*/
/* 0'%''#''U''n''I'01'U''n''i'0  for  ' ''%''#''U''n''I''cr'',''%''U''n''i' */
/* and so forth*/
/*The table entries for this are  0 0    1 4   6 11 etc*/
/* to make this file di : speak -v null<eng.v    */

int ttop 1;
int stop 1;
/*tops of above table and strings during creation of compressed file*/
char *buf;

char qbuf[300];	/**j** twice as long as before as durations are also sent */

int eflag;
int aflag;
int bflag	0;	/*o fo no spelling*/
int tflag 0;
int rulesw[NRULE];
/* suppresses selected preprocessing rules when nonzero
	1 final s
	2 final ie
	3 middle u
	4 middle ru
	5 Ation, etc
	6 bIography, etc
	7 suff0 (disyllable suffixes)
	8 suff1 (suffixes equivalent to e)
	9 suff2 (-ic -ical)
	10 final e
	11 monosyllable in e
	12 exception for -age -ege
	13 monosyllables in -i or -u  or -y
	14 simpleton
	15 racetrack
	16 middle s
*/
int code[] {
	'^',	/*silence*/	'uh',	/*above*/
	'a',	/*bud*/		'e',	/*bed*/
	'i',	/*bid*/		'o',	/*bod*/
	'u',	/*good*/	'aa',	/*bad*/
	'ee',	/*bead*/	'er',	/*bird*/
	'ar',	/*bard*/	'aw',	/*board*/
	'uu',	/*brood*/	'r',	/*rip*/
	'w',	/*win*/		'l',	/*lip*/
	'y',	/*yes*/		'm',	/*man*/
	'b',	/*ban*/		'p',	/*pan*/
	'n',	/*nip*/		'd',	/*dip*/
	't',	/*tip*/		'ng',	/*gun*/
	'g',	/*kip*/
	'k',	/*kip*/		's',	/*sip*/
	'z',	/*zip*/		'sh',	/*ship*/
	'zh',	/*azure*/	'f',	/*fan*/
	'v',	/*fan*/		'th',	/*thing*/
	'dh',	/*than*/	'ch',	/*chip*/
	'j',	/*jam*/		'h',	/*ham*/
	0,	0	/*required to terminate dencode*/
};
/*	durations for phonemes +32 in order of above	**j** */
char durcod[]{
	045,		/* for zero*/
	045,045,045,045,045,045,	/* uh a e i o u */
	052,052,052,052,052,061,	/*aa ee er ar aw uu */
	052,052,052,052,043,	/*r w l y m */
	052,052,052,052,052,	/*b p n d t */
	052,052,052,050,052,	/*ng g k s z */
	052,057,052,064,052,	/*sh zh f v th*/
	052,064,052,064,	/*dh ch j h */
};
char work[100];
char line[100];
char markers[50];
int vs 1;
int phonfil 2;
int mflag,dflag;	/*marker,display on*/

main(argc,argv)
char **argv; 
{
	char register *t,*u;
	char *m;
	char thisterm;	/*current sendcharacter*/
	char ch;
	int i;
	char *qbuft;	/*end of stuff in qbuf*/
	int linemode[3];
	int wtop;
	int f;
	int pflag,sflag,vflag,lflag;
/*markers on means that pitch and stress markers / ^ * nos are taken out
of the stuff being spoken and sent on with thwe phonemic representation*/
/* pron by rule, spelling ,voice op , count of lc letters inc hash*/
	int xflag,yflag,wflag,uflag;
/* flags for uc changed, trailing punctuation, hyphen removed*/
	char register *w;
	char *v;

	pflag =  eflag =sflag = vflag =dflag = 1;
	aflag=mflag = uflag = 0;
	buf= & qbuf[200];	/*use rhs qbuf for buf*/
	if(argc>1 && *argv[1]=='-') {
loop:	
		switch(*(argv[1]++)) {
		default: 
			goto loop;
		case 'e': 
			eflag = 0;	/*no english preprocessing*/
			goto loop;
		case 'f':
			for(i=1;i<NRULE;i++)
				rulesw[i] = 1;
			goto loop;
		case 'p': 
			pflag = 0;	/* no pronunciation by rule*/
			goto loop;
		case 's': 
			sflag = 0;	/*no spelling*/
			goto loop;
		case 'v': 
			vflag = 0;	/*no voice output*/
			phonfil=1;	/*can be redirected*/
			goto loop;
		case 'm':
			mflag=1;	/*no markers extracted*/
			goto loop;
		case 'd':
			dflag=0;	/*no display of phonetics*/
			goto loop;
		case 'u' :
			uflag=1;	/*cause word to be sent at sp or tab*/
			setbreak();
			signal(2, setcook);	/* catch interrupts and reset tty */
			goto loop;
		case 'a':	aflag=1;
			goto loop;
/* if a =1 slower speed: double the durations*/

		case '\0':; 
		}
		argc--; 
		argv++; 
	}
	if(vflag) {
		if(argc>2) vs= creat(argv[2],0666);
	}
	readin(argc>1 && compare(argv[1], ",") ? argv[1]:"/usr/lib/eng.m");
/*	readin ( file name for coded vocabulary)	*/
/*	  file name if argc>1 and argv[1] not , use name in arg		*/
/*			otherwise use /usr/lib/speak.m		*/
		if (vflag) write(vs,"l", 4);	/*3 bells and l for spout **j** */
	for(;;)	{

		t = line;
		do	{ 
			if(!read(0,t,1)) {

			if(vflag)
				write(vs,FLAG,1);	/*send term to   spout */
			if(uflag) setcook();
			else exit();
			}
		} 
/*text is input to 'line' until term charac  is found this is replaced by zero*/
		while( uflag ?  !oneof( *t++,sendch) : *t++ != '\n'  );
		if(t-line<2)continue;
		thisterm= *(t-1);
		*(t-1)=' ';
		*t=0;
		if(line[0]=='!') switch(line[1]) {	/*spec cases intr ! */

		case 'c':
			copy();
			break;
		case 'w':
			writeout(name());	/*write compressed file*/
		case 'r':
			t = name();	/* reads vocab from named file*/
			if(*t) readin(t);
			break;
		case 'd':
			if(phread(work,buf+1)!=buf+1) 
				decode(1,buf+1);
			else {
				tflag = 1;
				phpron(work,buf);
				tflag = 0; 
			}
			write(2,"\n",1);
			break;
		case 'f':
			t = name();
			for(i=0;*t>='0'&&*t<='9';
				i = i*10 + *t++-'0');
			if(i>=NRULE) break;
			rulesw[i] =^ 1;
			break;
		case 'p':
			decode(2,buf+1);
			write(2,"\n",1);
			break;
		case 'q':
			if (vflag) write(vs,FLAG,1);
			if(uflag) setcook();
			else exit();
		case 'l':
			i = 0;	/*list vocab*/
			while(++i<ttop) 
				list(1,&strings[table[i].word]);
			break;
		default:
			diag(1);
			break;
		}
/*this part deals with normal typed text for speech and also with*/
/*production of compressesd file speak.m from readable file speak.v*/
		else	{
			if(!replace()&&line[1]!='\0') {
/*if speech text replace is exited,   if string starts with a comma	*/
/*as in replacements in the file compression job replace is implemented*/
/*and the rest of this block is ignored*/
	m=markers;
				t = line; 
				if(*t==BELL){
					bflag=1;
					t++;
				}
				u = work; 
				*u= 0;
				lflag = 0; 
				for(;;) {
				while( oneof(*t, mflag ? " \t^/*.?" : " \t")){
					if ( mflag &&oneof(*t, "^/*.?"))*m++= *t;
						t++;
					}
					*m++= 0;
				while( !oneof(*t, mflag ?" \t^/*.?" : " \t")){
						*u= *t++;
						if(*u) {
					if('a'<=*u&&'z'>=*u ||*u=='%')
								lflag++;
							u++; 
						}
						else goto next; 
					}
					*u++ = 0; 
				}
/*by now the string has been copied to 'work' with out any blanks*/
/*letterbcount to lflag*/
next:
				wtop = u; 
				*m=0;
			}
			if(u==work) continue;
			t = work;
			if(bflag){
				u=phspell(t,buf+1);
				bflag=0;
				goto worddone;
			}
			m=markers;
			if(mflag&&dflag)while(*m)write(phonfil,m++,1);
			m++;
			while(t<wtop){
				u = phread(t,buf+1);
/*first see if the string is in the dictionary*/

				wflag=yflag=0;
/*if not in the list*/
				if(u==buf+1 && pflag) {
/*strip leading punct*/			for(v=t;oneof(*v,"([`\"");v++);
					for(w=v;*w;w++)
						if(*w=='-'&&w-v>=2
						   &&w[-1]!='\b'){
							wflag = *w;
							*w = 0;
							break;
						}
/*hyphen taht cuts off 2 or more characters treated as space*/
					if(!wflag){
						for(;oneof(*--w,".,;:?!'\"])"););
						if(*w=='\b') w++;
						yflag = *++w;
					}
/*trailing punctuation causes pause*/
					if(w<=v) goto noword;
					*w = 0;
					xflag = 0;
					if(!lflag) for(u=v;*u;u++)
						if(fold(u)) xflag++;
/*map uc to lc and remember*/
					if((yflag||xflag||wflag)&&
					    (u=phread(v,buf+1))!=buf+1);
/*if uc mapped or punctuation stripped try the dictionary again*/
					else u = phpron(v,buf+1);
					if((*w=yflag)&&u!=buf+1) {
						/*pause for punct*/
						*u++ = 040;
						*u++ = 040; 
					}
				}
noword:
				if(u==buf+1&&wflag)
					*w = wflag;
				if(u==buf+1&&sflag)
					u = phspell(t,buf+1);
				*buf = 040;	/*pause before word*/
worddone:				*u++ = 040;	/*pause for end of word*/
				*u++= 0;	/*to stopdecode*/
				while(*t++);
				if(dflag) decode (phonfil,buf+1);
				if(mflag&&dflag) while(*m)write(phonfil,m++,1);
				m++;
				if(vflag) {
				qbuft=qencode(buf,qbuf);
/*  returns no of characters in qbuf	*/
					write(vs,qbuf, qbuft- qbuf );
				}
			}/*goes back after each word in non replacement lines*/
			if(dflag) write(phonfil, &thisterm,1);
		}/*end of lines not starting with ! */
	}/*looping, reading lines, exit via !q only*/
}/*end of main*/

decode(f,s)
char *s; 
{
	int b,c;
	int register flag;
	flag = 1;
	while(c = *s++) {
		if(flag) {
			write(f,",",1);
			if(c==001) {
				flag = 0;
				c = '%'; 
			}
			else {
				c=-32;
				c= c ? code[c] : ' ' ;
			}
		}
		while(c){
			write(f,&c,1);
			c=>>8; 
		}
	}
}

/*xhoneme  code (0-36 ) +32 with ) is source */
/* code  and duration+32 is extracted from durcod*/
/*and sent in pairs to destination*/

}

/* looks at test, if it is not intro by a comma return zero*/
/*this procedure deals with replacement lines in the making of the compressed*/
/*file if it cnsists of ,% write 1 string*/
/*    if it is a replacement line put code*/
replace(){
	char register *t,*u;
	int register n;
	int b,i;
	t = line;
	u = buf;
	if(*t++!=',')return(0);
	for(;;) { 	/*if comma*/
		if(*t=='%') {
			*u++ = 001;
			while((*u = *++t) && *u!=' ') u++;
			break; /*if % get out here*/
		}
		b = 1;
		if(*t<='3') if(*t>='0')
			b = '3'-*t++;
		n = 0;
		while(*t!=',' && *t!=' ' && *t!=0) {
			i = *t++;
putchar(i);
			if(n) i=<<8;
			n =| i; 
		}
/* if , phoneme replace by code number*/
		n = dencode(&code[0],n);
		if(n) *u++ = n;
		if(*t!=',' && *t!=' ') break;
		t++; 
	}
	*u++=0;
	phwrite(work,buf);
/*puts pair of items into compressed file*/
	return(1); 
}

list(f,s)
char *s; 
{
	char register *t;
	if(phread(s,buf)==buf) return;
	write(f," ",1);
	t = s;
	while(*t) write(f,t++,1);
	write(f,"\n",1);
	decode(f,buf); 
	write(f,"\n",1); 
}

copy(){
	char buf1[100];
	phread(work,buf1);
	phwrite(name(),buf1); 
	printf("stored in vocab as");
	decode(2,buf+1);
	printf("\n");
}

name(){		/* reads name from line[2] to buf*/
	char register *u,*t;
	u = &line[2];
	while(*u==' ') u++;
	t = buf;
	while(*u && (*t = *u++)!=' ') t++;
	*t = 0;
	printf("name %s \n",buf);
	return(buf); 
}

readin(file){
	int register f;
	if((f = open(file,0))<0) {
		diag(2);
		dflag=0;	/*prevent display of phonemes*/
		mflag=0;	/*prevent removal  of markers*/
	/*this prevention is needed for making eng.m*/

		return; 
	}
	read(f,&ttop,2);
	read(f,table,recsize*ttop);
	read(f,&stop,2);
	read(f,strings,stop);
	close(f); 
}

writo1(f,u,n)
int *u; 
{
	int register i,j,k;
	i = j = *u;
	*u = n;
	k = 1;
	while(strings[i++]) k++;
	write(f,&strings[j],k);
	return(k); 
}

writeout(file) {
	int register f,i;
	int n;
	if((f=creat(file,0666))<0) {
		diag(3);
		return; 
	}
printf("created %s %d\n",file,f);
	seek(f,recsize*ttop+4,0); /*get to byte 0 of string store*/
	write(f,strings,1);	/*and put it out*/
	n = 1;
	for(i=1;i<ttop;i++) {
		n =+ writo1(f,&table[i].word,n);
		n =+ writo1(f,&table[i].phon,n); 
	}
	seek(f,0,0);
	write(f,&ttop,2);
	write(f,table,recsize*ttop);
	write(f,&n,2);	/*new value of stop */
	close(f); 
printf("closed %d\n" ,f);
}


find(in)
char *in; 
{
	int register bot,top,i;
	int z;
	bot = 0;
	top = ttop;
	z = 0;
	while((i=(bot+top)/2)>bot) {
		z = compare(in,&strings[table[i].word]);
		if(z==0) break;
		if(z<0) top = i;
		else bot = i; 
	}
	return(i); 
}

prefix(in)
char *in; 
{
	char register *u,*s;
	char *end;
	int register i;
	int pref,bot,top;
	pref = bot = 0;
	top = ttop;
	end = in+1;	/* +1 saves wasted time looking up % */
loop:	
	while((i=(bot+top)/2)>bot) {
		do {
			s = &strings[table[i].word];
			for(u=in;;u++) {
				if(*u<*s) top = i;
				else if(*u== *s++) {
					if(*u==0) return(i);
					if(*s!=0) continue;
					pref = bot = i;
					end = u+1; 
				}
				else if(u<=end) bot = i;
				else break;
				goto loop; 
			}
		} 
		while((i=(bot+i)/2)>bot);
		bot++;
		end++; 
	}
	return(pref); 
}

compare(a,b)
char *a,*b; 
{
	while(*a == *b) {
		if(*a==0) return(0);
		a++;
		b++; 
	}
	return(*a<*b ? -1 : 1); 
}

char *
phread(in,out)	/* returns address of letter after output string */
char *in,*out; 
{
	char *s;
	int i;
	i = find(in);
	if(compare(in,&strings[table[i].word])==0) {
		for(s = &strings[table[i].phon];*out = *s++;)
			out++; 
	}
	*out = 0; 
	return(out); 
}

/*makes compressed file called by replace if comma in string*/
phwrite(in,out)
char *in, *out; 
{
	int register i,j,z;
	i = find(in);
	if(0!=(z=compare(in,&strings[table[i].word]))) {
		if(*out==0) return;
		i++;
		if(ttop>=NT) {
			diag(4);
			return; 
		}
		for(j=ttop;j>i;j--) {
			table[j].word = table[j-1].word;
			table[j].phon = table[j-1].phon; 
		}
/*move table down*/
		table[i].word = stop;
		stash(in);
		ttop++; 
	}
/*copy lhs string*/
	else if(*out==0) {
		for(j=i;j<ttop;j++) {
			table[j].word = table[j+1].word;
			table[j].phon = table[j+1].phon; 
		}
		ttop--;
		return; 
	}
	table[i].phon = stop;
	stash(out); 
/*copy rhs string*/
}

/*copies anything into strings*/
stash(s)
char *s; 
{
	while(stop<NS)
		if((strings[stop++]= *s++)==0)
			return; 
	diag(5); 
}

diag(n) {
	char register *p;
	p = diags[n];
	while(*p) write(2,p++,1); 
	write(2,"\n",1); 
}

phspell(in,out)
char *in, *out; 
{
	char register *c,*t;
	c = "* \0";
	while(c[1] = *in++) {
		fold(&c[1]);	/*caps out*/
		t = phread(c,out);	/*look up letter prec by * copy to out*/
		if(t!=out) out = t;	/*if found*/
		else if( bflag==0) {
			*out++ = 071;	/* ,k ie 25+32 */
			*out++ = 043;	/* a ie 3 32 */
		}
		if(*in) *out++ = 040; 	/*pause*/
	}	/*phoneme 2-0*/
	*out = 0;
	return(out); 
}


/*danger--reuses "line" to conserve space*/
char *
phpron(in,out)
char *in, *out; 
{
	char register *t,*u;
	char *s;
	char register *sout;
	char sflag;
	int i;
	sout = out;
	*sout = 0;
	s = t = line+2; 
	u = in;
	while(*s++ = *u++);
	s =- 2;
	sflag = 0;
	if(fold(t)) {
		if(sout!=(out=phread(t,out)))
			return(out);
		else while(*++in)
			if(fold(in)) goto spellit;
			/*spell all-caps words*/
	}
	if(s==t||vowel(t,s+1)<t) {
		/*spell one-letter words and vowelless words*/
		goto spellit; 
	}
	if(eflag) {	/* handle english endings*/
		if(sflag = finals(t,&s)) 
			if(sout!=(out=phread(t,out))) {
				*out++ = sflag>1?072:073;	/*s=26 s=27*/
				*out++ = 072; /*,s,s or ,z,s*/
				goto done; 
			}
		midu(t,s);
		finale(t,&s);
		mide(t,&s);
		mids(t,s);
		if(sflag) *++s = 's'; 
	}
	*--t = '#'; 
	*++s = '#'; 
	*++s = 0;
/*next section takes string from left to right applying pronunciation rules*/
/*to word fragents*/
	while(*t) {
		*--t = '%';
		i = prefix(t);
/*looks for current string in table*/
		if(i==0) {
			*sout = 0; 
			return(sout); 
		}
		u = &strings[table[i].word];
		while(*u) {
			t++;
			if(tflag) write(2,u,1);
/* decomposition of working word*/
			u++; 
		}
		if(tflag) write(2," ",1);
		s = &strings[table[i].phon];
		while(*out = *s++)
			if(*out!=001) out++;
			else	{	/*do replacement*/
				u = s;
				while(*u) u++;
				while(--u>=s) *--t = *u; 
				break; 
			}
/*string has been put as code into buffer*/
	}
/*goes back with the l.h. end missing*/
done:
	*out = 0;
	return(out); 
spellit:
	for(u=t;u<=s;u++)
		if((*u|040)<'a'||(*u|040)>'z')
			goto done;
	return(phspell(t,out));
}

char
finals(in,ls)
char *in,**ls; 
{
	char register *end;
	int *val;
	end = *ls;
	val = 0;
	if(!rulesw[1])
	if(*end=='s'&&!oneof(end[-1],"us")) {
		*end-- = 0;
		if(*end=='\'') *end-- = 0;
		val = oneof(*end,"cfkpt")+1; 
	}
	if(!rulesw[2])
	if(*end=='e'&&end[-1]=='i') {
		*end-- = 0;
		*end = 'y'; 
	}
	*ls = end;
	return(val); 
}

midu(in,end)
char *in,*end;
{
	char register *s,*t; 
	if(!rulesw[3])
	for(s=in;s<end-1;s++) if(*(t=s)=='u' && !oneof(s[-1],aeiou)) {
		if(oneof(s[1],aeiouwxy)) continue;
		if(!rulesw[4])
		if(s[2]=='r'&&oneof(s[1],bcdfgkpt)) s++;
		if(oneof(s[2]|040,aeiouy)) *t = 'U'; 
	}
	if(!rulesw[5])
	for(s=in;s<end-2;s++) if(oneof(*(t=s),aeo)) {
		if(oneof(s[1],"aeiouwxy|"))continue;
		if(th(s+1)) s++;
		if(s[2]=='r'&&s[3]=='i'&&oneof(s[1],bcdfgkpt)) s++;
		if(oneof(s[2],"ie")&&oneof(s[3]|040,aou)
		    || s[2]=='i'&&s[3]=='e'&&s[4]=='n')
			*t =^ 040; 
	}
	s = in;
	if(*s=='y') s++;
	while(!oneof(*s|040,aeiouy)&&s<end) s++;
	if(!rulesw[6])
	if(oneof(*s,"iy") && oneof(s[1],aou)) *s =^ 040; 
}

char *suff0[] {
	"la",
	"el",
	"o",
	"er",
	"su",
	"y",
	0 };
char *suff1[] {
	"elba",
	"de",
	"re",
	"gni",
	"tse",
	"ne",
	"ylba",
	"yl",
	"ro",
	"yre",
	"ye",
	"ssel",
	"ssen",
	"luf",
	"tnem",
	"ll'",
	0 };
char *suff2[] {
	"ci",
	"laci",
	0 };
char *suff3[] {
	"e",
	0 };

finale(in,ls)
char *in,**ls; 
{
	char register *t,*end,*u;
	char *s;
	char *z;
	end = *ls;
	if(!rulesw[11])
	t = suffix(in,end,suff0);
	if(!rulesw[7])
	if(t<end) t = longe(in,t);
	if(t==end||t<in||vowel(in,t)>=in||*t=='h') {
		t = end;
		if(!rulesw[8])
		while((u=suffix(in,t,suff1))!=t) {
			insert(u+1,ls);
			t = u; 
		}
		if(!rulesw[9])
		if((u=suffix(in,t,suff2))!=t) {
			insert(u+1,ls);
			return; 
		}
		if(!rulesw[10])
		if((u=suffix(in,t,suff3))!=t) {
			if(u[2]=='e') return;
			insert(u+1,ls);
			t = u; 
		}
		if(!rulesw[13])
		if(oneof(*t,"eiuy")&&vowel(in,t)<in) {
			*t =^040;	/*monosyllables in -y, */
			return; 
		}	/*perhaps suffixed*/
		if(!oneof(t[t[1]=='|'?2:1],"aeio")) return;
		t = longe(in,t);
		if(t<in) return;
		if(!rulesw[12])
		if(oneof(t[1],"cg")&&vowel(in,t)>=in) return;
		if(th(t+1)) {
			t[1] = 'T'; 
			t[2] = 'H'; 
		} 
	}
	if((t==in||!oneof(t[-1],aeo)) && !(*t=='e'&&t[1]=='l'))
		*t =^ 040; 
}

mide(in,ls)
char *in,**ls; 
{
	char register *u,*end;
	end = *ls;
	for(u=in+3;u<end-2;u++)
		if(*u=='e') {
			if(!rulesw[14])
			if(u>in+4
			    &&syltest(u+1,"aeiouy|",end)
			    &&u[-1]=='l'
			    &&oneof(u[-2],"bdfgkpt")
			    &&oneof(u[-3],"bcdfgmnprst"))
				goto shift;
			if(!rulesw[15]) 
			if(syltest(u+1,"aeinoruy|",end)
			    &&!oneof(u[-1],"aehiouwxy")
			    &&oneof(u[-2],"aiouyU")
			    &&!oneof(u[-3],"aeiu")) {
				if(u[-3]!='o') u[-2] =& ~040; 
				goto shift;
			}
			return;
shift:		
			insert(u+1,ls); 
		} 
}

mids(in,end)
char *in,*end; 
{
	if(!rulesw[16])
	while(++in<end) 
		if(*in=='s'&&oneof(in[-1]|040,"aeiouy")
		    &&oneof(in[1]|040,"aeimouy"))
			*in =^ 040; 
}

syltest(in,s,end)
char *in,*end,*s; 
{
	if(!oneof(*in|040,s))
		while(++in<end) {
			if(*in=='e'&&in[1]=='|') break;
			if(*in=='|') break;
			if(oneof(*in|040,aeiouy)) return(1); 
		}
	return(0); 
}

char *
insert(in,ls)
char *in,**ls; 
{
	char register *s,*end;
	end = *ls;
	if(*in=='e') if(*++in=='|') return;
	for(s=++end;s>=in;s--) s[1] = *s;
	*in = '|'; 
	*ls = end; 
}

char *
suffix(in,end,s)
char *in,*end,**s; 
{
	char register *t,*u;
	while(u = *s++) {
		t = end+1;
		while(*u == *--t) u++;
		if(*u==0) {
			if(vowel(in,t+1)<in) break;
			else return(t); 
		}
	}
	return(end); 
}

char *
longe(in,end)
char *in, *end; 
{
	if(th(end-1)) end--;
	return(!oneof(*end|040,aeiouwxy)&&oneof(*--end,aeiouy)?end:in-1); 
}

oneof(c,l)
char c,*l;
{ 
	while(*l) if(c == *l++) return(1);
	return(0); 
}

char *
vowel(in,end)
char *in,*end; 
{
	while(--end>=in)
		if(oneof(*end|040,aeiouy)) break;
	return(end); 
}

fold(s)
char *s;
{
	if('A'<=*s && *s <='Z') {
		*s =^ 040;
		return(1); 
	}
	return(0); 
}

th(s)
char *s; 
{

	return(*s=='t'&s[1]=='h'); 
}
