/*These are the common routines exclusive to both the MAC and IBM MT1 programs*/
#define TONE
#include "MacTeach1.h"

short breakup(char *string, char *array[])

/* In sentence presentation, the sentence consists of groups, one of which 
is replaced by a dash.  The test is to replace the dash with a proper group
which are called psuedo-words below, but may consist of several actual works
linked with hyphens*/

/* On entry string is a sentence, and array is an array to contain the
 start points of each pseudo-word in the sentence. A count of the number
 of pseudo-words found is returned. The breakup stops if a bracket,
 indicating a comment is found. Extra spaces between words are ignored,
 but a space is the only accepted break between pseudo-words.*/

{	short count;
	char *sptr,ch;
	count = 0;
	array[count] = sptr = string;
	while ((ch = *sptr++) && ch != '[') {
		if (ch==SP) {
			*(sptr-1) = '\0';
			while (*sptr && isspace(*sptr)) *sptr++;
			if (!*sptr || *sptr=='[') { ch = *sptr; break;}
			else array[++count] = sptr;
			}
		}
	if (ch =='[') cmmt = sptr-1;
	else cmmt = 0L;
	array[++count] = '\0';
	return count;
	}


Boolean isvowel(char a)

/*Determine if the character a is a vowel*/

{	char b;
	b=tolower(a);
	return (b=='a'||b=='e'||b=='i'||b=='o'||b=='u');
	}	
	
short getn(short n)

/* Get a comment number from the engsent field.  Macteach 1 and 4 provide for 
explanatory comments for program segments when the presentation is sequential
(the default) rather than random.*/

{	short num, num1;
	num = flasharray[n].engsent[0]-'0';
	if ((num1 = flasharray[n].engsent[1]) > 0x20) num = 10*num+num1-'0';
	return num;
	}

void mainsent(char *outstr,char *instr)

/*This routine converts a string instr, which contains various
 alternative expressions into a string outstr which displays only
  those parts that the preparer of the input wishes to display as 
  the English translation.*/

{	char *os,*is;
	short copy,fl,eqflg,brct;
	os = outstr;
	is = instr;
	copy = TRUE; /*Indicates whether copying is currently in effect*/
	cflag = eqflg = fl = brct =0;
	while (*is) { // Search the entire sentence
		switch (*is) {
		case '\\': /*Remove flag of required punctuation*/
			is++;
			if (copy) *os++ = *is;
			break;
		case '/': /*Turn off copy when an alternative is reached*/
			fl = 1;
			copy = FALSE;
			cflag = 1;
			break;
		case '(' : /*Turn off copy for optional text unless it is asterisked*/
			++brct; // Increase the parenthesis count
			if (*(is+1)=='*') *is++;
			else copy = FALSE; 
			cflag = 1;
			break;
		case ')' : /*Turn on copy after all nested brackets closed*/
			--brct; // Decrease the parenthesis count
			if (!fl && !brct) copy = TRUE; break;

/* * and & may indicate the end of an alternative. Check for this and
 turn on copy if true*/
		case '=':
		case ':':
			if (fl) eqflg = 1;
		case '+':
		case '&':
			if (cflag != 2 && !eqflg && *is!='=') {
				copy = TRUE;
				fl = 0;
				}
			if (*is==':' || *is=='&') break; /*No space for these*/
		case ' ':
/*After a space we always turn on copy and reset the flags*/

			if (*is==' ') {
				copy = TRUE;
				eqflg = 0;
				fl = 0;
				}
		case '-':
			if (copy) *os++ = ' '; /* Replace '-' with space*/
			break;
		case '|': /*Turn off copy permanently with a comment marker '|'*/
			if (!cflag) cflag = 2;
			copy = FALSE;
			break;
		case '[': /*Square bracketed comments in Loglan text are copied*/
			copy = TRUE;
			*os++ = *is;
			break;
		case ']':
			copy = FALSE;
			*os++ = *is;
			break;
		default:
			if (copy) *os++ = *is;
			break;
			}
		if (*is == '|') break;
		++is;
		}
	*os = '\0';
	}

void marktest(short n,short count,short level,short index)

/*This routine is responsible for testing if the user response is acceptable.
 On entry n is the card being tested, count is the number of pseudo-words in the
 sentence, level is the current pseudo-word being tested, and index is a flag used in
 indicating which words are to be tested. The sentences to be compared are put
 into the same case before checking. This routine determines mainly which
 strings are to be checked, which depends on the style and whether recognition
 or recall is being tested. The styles can be selected for each card, and are
 (1) Blank words one at a time from the rear, and then the whole sentence 
 (2) Add a new blanked word each time, working from the rear, and 
 (3) Blank all little words, then blank all predicates, then blank the whole
  sentence. The actual checking is done by  mycomp.*/

{	short flag;
	flag = FALSE;
	wall = opt = 0;
	upstring(instring);
	upstring(gSentence);
	ansptr[0] = instring;
	if (rrflag=='1') {
		if (count==level || count==1) {
			mycomp(gSentence,ansptr[0]) ? promote(n,count):demote(n);
			}
		else {
			switch(gStyleFlg) {
			case '1':
			case '3':
			case '4': // Added for MT4
				mycomp(wordptr[index],ansptr[0]) ? promote(n,count) : 
					demote(n);
				break;
			case '2':
				gSentence[0] = '\0';
				for (ind1 = index; ind1<count; ++ind1) {
					strcat(gSentence,wordptr[ind1]);
					if ((ind1+1)<count) strcat(gSentence," ");
					}
				mycomp(gSentence,ansptr[0]) ? promote(n,count):demote(n);
				break;
				}
			}
		}
	else {
		if (count==level || count==1 || (gStyleFlg=='3' && level>=3)) {
			mycomp(gSentence,ansptr[0]) ? promote(n,count):demote(n);
			}
		else {
			switch(gStyleFlg) {
			case '1':
			case '4':  // added for MT4
				mycomp(wordptr[index],ansptr[0]) ? promote(n,count) : 
					demote(n);
				break;
			case '2':
				gSentence[0] = '\0';
				for (ind1 = index; ind1<count; ++ind1) {
					strcat(gSentence,wordptr[ind1]);
					if ((ind1+1)<count) strcat(gSentence," ");
					}
				mycomp(gSentence,ansptr[0]) ? promote(n,count):demote(n);
				break;
			case '3':
				ind2 = 0;
				for (ind1 = 0; ind1<count; ++ind1) {
					switch (level) {
					case 0:
						if (!pred(wordptr[ind1])) {
							if (!mycomp(wordptr[ind1],ansptr[0])) {
								flag = TRUE;
								}
							}
						break;
					case 1:
						if (pred(wordptr[ind1])) {
							if (!mycomp(wordptr[ind1],ansptr[0])) {
								flag = TRUE;
								}
							}
						break;
					case 2:
						if (!mycomp(wordptr[ind1],ansptr[0])) {
							flag = TRUE;
							}
						break;
						}
					if (flag) break;
					}
				if (ansptr[ind2]) flag = TRUE;
				(flag) ? demote(n) : promote(n,count);
				break;
			default:
				break;
				}
			}
		}
	}

Boolean pred(char *str)

/* Determine whether string str is a predicate or a little word. Predicates have a
 double consonant somewhere in the string.*/

{	char *temp;
	temp = str;
	while (*temp) 
		if (!isvowel(*temp++) && !isvowel(*temp)) return TRUE;
	if (!isvowel(*(temp-1))) return TRUE;
	return FALSE;
	}

void strcopy(char *outst,char *inst)

/* Copy inst to outst removing any comments (which follow '|')*/
{	char *os,*is;
	os = outst;
	is = inst;
	while (*is && *is != '|') *os++ = *is++;
	*os = '\0';
	}


