/* file ttp1s.c                                              */
/* function ttp1s(stx,sp,perr) for converting text to phones */
/* and its sub-functions.                                    */
/* Uses character functions defined in letfcns1.c            */
/* Marks stress on only a few vowels.                        */
/* Output phones are from standard phone set "phon1ax.pcd"   */
/* For proper results, run ttp_prep1() on input first.       */

#if !defined(COMPILE_ENVIRONMENT)
#include <gp/stdcenvf.h> /* std compile environment for functions */
#endif

/* local function prototypes: */
static boolean pronounceable_token(SUBSTRING *token);


  /*********************************************/
  /*  char *ttp1s(st,sp,perr)                  */
  /*  Converts text to phones                  */
  /*  Input: *st is a text string;             */
  /*  Output: *sp is an ASCII phone string;    */
  /*   (Returns sp.)                           */
  /*  Process: elementary.                     */
  /* Note: input should be padded with spaces  */
  /*  on head & tail.                          */
  /*  On return, *perr > 0 iff error.          */
  /*********************************************/
  char *ttp1s(char *st, char *sp, int *perr)
   {char *proc = "ttp1s";
    char *p;
    char sxx[LINE_LENGTH], *sx = &sxx[0];
    char sxdbx[LINE_LENGTH], *sxdb = &sxdbx[0];
    boolean lexical_level = T;
    SUBSTRING tkx, *token = &tkx;
/* code */
 db_enter_msg(proc,1); /* debug only */
if (db_level > 2) printf("%sinput='%s'\n",pdb,st);
    *perr = 0;
    *sp = '\0'; /* empty output string */
/* convert letter to phone */
    for (p = pltrimf(st); *p != '\0'; p++)
      {/* at start of token, if it's not pronounceable, spell it out */
       if ((!isspace((int)*p))&&(isspace((int)*(p-1))))
         {token->start = token->end = p;
          while (!isspace((int)*(token->end))) token->end += 1;
          token->end -= 1;
          if (!pronounceable_token(token))
            {if (db_level > 1) printf("%s unpron token = '%s'\n",pdb,
              substr_to_str(token,sxdb,LINE_LENGTH));
             while (p <= token->end)
               {sp = strcat(sp,char_name(sx,*p));
                p += 1;
               }
             continue;
         }  }
       /* otherwise map letters to phones */
       /* ignore first of a pair of geminate consonant letters */
       if (iscons1(*p)&&(*(p+1) == *(p))) continue;
/*       if (*p == ' ') sp = strcat(sp," #"); */
       /* if lone letter, say the letter name */
       if (isspace((int)*(p-1))&&isspace((int)*(p+1)))
         {sp = strcat(sp,char_name(sx,*p));
          p += 1;
          continue;
         }
       switch (*p)
         {case '\'': /* "'" */
          if (bound(*(p+1))) continue; /* warriors' */
          if (bound(*(p-1))) continue; /* 'taters   */
          if (*(p+1) == 's')
            {if ((fric1(p-1))||((*(p-1) == 'e')&& fric1(p-2)))
               {sp=strcat(sp," '0 ax z"); p++; continue;} /*boss's,face's,rage's"*/
             if (voiced(p-1))
               {sp=strcat(sp," z"); p++; continue;} /* Joe's,bag's */
             else
               {sp=strcat(sp," s"); p++; continue;} /* bat's */
            }
          if ((*(p+1) == 'l')&&(*(p+2) == 'l')&&bound(*(p+3))) /* John'll, they'll */
	    {if (lexical_level) sp = strcat(sp," '0 ax l");
             else               sp = strcat(sp," el");
             p++; p++;
            }
          continue;

	  case 'a':
          if (bound(*(p+1))) {sp = strcat(sp," '0 ax"); continue;}/* final a */
          if (*(p+1) == 'i')
            {if (*(p+2) == 'r') sp = strcat(sp," eh"); /* fair */
             else               sp = strcat(sp," ey"); /* gait */
             p++; continue;
            }
          if (*(p+1) == 'y') {sp = strcat(sp," ey"); p++; continue;}/*hay*/
          if (*(p+1) == 'u') {sp = strcat(sp," ao"); p++; continue;}/*haul*/
          if (*(p+1) == 'w') {sp = strcat(sp," ao"); p++; continue;}/*bawl*/
          if ((*(p+1) == 'l')&&(*(p+2) == 'l'))
            {sp = strcat(sp," ao"); /* all, ball, call, fall */
             continue;
            }
          if (strncmp(p+1,"ste ",4) == 0)  /* paste (long env?) */
            {sp = strcat(sp," ey"); continue;}
          if ((*(p+1) == 'h') && bound(*(p+2)))
            {sp = strcat(sp," '0 ax");
             p++;
             continue;
            }
          if (short_env(p)) sp = strcat(sp," ae");
          else              sp = strcat(sp," ey");
          continue;

	  case 'b':
          sp = strcat(sp," b");
          continue;

	  case 'c':
          if (*(p+1) == 'h')
            {if ((bound(*(p-1))&&(*(p+2) == 'l')))
	       {sp = strcat(sp," k"); p++; continue;} /* chloro- */
             sp = strcat(sp," ch"); p++; continue;
            }
          if (is_front_vowel(*(p+1))) sp = strcat(sp," s");
          else                        sp = strcat(sp," k");
          if (*(p+1) == 'k') p++; /* skip following k */
          continue;

	  case 'd':
          sp = strcat(sp," d");
          continue;

	  case 'e':
          if  (*(p+1) == 'w') {sp = strcat(sp," y uw"); p++; continue;}/*few*/
          if ((*(p+1) == 'l')&&((isspace((int)*(p+2)))||((*(p+2) == 's')&&(isspace((int)*(p+3))))
                              ||((*(p+2) == 'd')&&(isspace((int)*(p+3)))))) /* nickel[s/d] */
	    {if (lexical_level) sp = strcat(sp," '0 ax l");
             else               sp = strcat(sp," el");
             p++;
             continue;
            }
          if ((*(p+1) == 'y')&&(iscons1(*(p-1)))&&(bound(*(p-2))))
            {sp = strcat(sp," ey"); p++; continue;} /* hey */
          if ((*(p+1) == 'y')&&(iscons1(*(p-1)))&&(iscons1(*(p-2)))&&(bound(*(p-3))))
            {sp = strcat(sp," ey"); p++; continue;} /* they */
          if ((*(p+1) == 'y')&&(*(p+2) == ' ')) /* final "ey" */
            {sp = strcat(sp," iy"); p++; continue;}
          if (bound(*(p+1))) /* final "e" */
            {if (iscons1(*(p-1)))
               {if (bound(*(p-2))) {sp = strcat(sp," '1 iy"); continue;}
                if ((iscons1(*(p-2))) &&(bound(*(p-3))) )
                  {sp=strcat(sp," '1 iy"); continue;}  /* me, the */
               } 
             if (bound(*(p-1))) {sp = strcat(sp," '1 iy"); continue;}
             continue;
            }

          if ((*(p+1) == 'd')&&(bound(*(p+2)))) /* final "ed" */
            {if (bound(*(p-2))) {sp=strcat(sp," '1 eh"); continue;} /* bed */
             if ((*(p-1) == 't')||(*(p-1) == 'd'))
               {sp=strcat(sp," '0 ax d"); p++; continue;} /* batted */
             if ((*(p-1) == 'r')&&(*(p-2) == 'd'))
               {sp=strcat(sp," '0 ax d"); p++; continue;} /* hundred */
             if (voiced(p-1)) sp=strcat(sp," d");       /* bagged */
             else             sp=strcat(sp," t");       /* backed */
             p++;
             continue;
	   }
          if ((*(p+1) == 's')&&(*(p+2) == ' ')) /* final "es" */
            {if ((*(p-2) == 's')&&(*(p-1) == 't')) /* estes */
               {sp = strcat(sp," '0 ax s"); p++; continue;}
             if (fric1(p-1))
               {sp=strcat(sp," '0 ax z"); p++; continue;} /* bosses */
              if (voiced(p-1)) sp=strcat(sp," z");      /* aides */
              else             sp=strcat(sp," s");      /* crates */
              p++; continue;
            }

          if ((*(p+1) == 'r'))
            {if (*(p+2) == 'r')
               {sp = strcat(sp," eh"); /* terror */
                continue;
	       }
             if (!isvowel1(*(p+2)))
               {sp = strcat(sp," ax r"); /* herd */
                p++;
                continue;
	       }
             else
               {if (bound(*(p+3))) sp = strcat(sp," iy"); /* here */
                else               sp = strcat(sp," eh"); /* heretic */
                continue;
	    }  }
          if (*(p+1) == 'a')
            {if (*(p+2) == 'u') /* cocteau */
               {sp = strcat(sp," ow");
                p++; p++; continue;
 	       }
             if (*(p+2) == 'd') sp = strcat(sp," eh"); /* head, instead */
             else               sp = strcat(sp," iy");
             p++; continue;
            }
          if (*(p+1) == 'e') {sp = strcat(sp," iy"); p++; continue;}
          if (*(p+1) == 'i') {sp = strcat(sp," ey"); p++; continue;}
          if (short_env(p)) sp = strcat(sp," eh");
          else              sp = strcat(sp," iy");
          continue;

          case 'f':
          sp = strcat(sp," f");
          continue;

          case 'g':
          if (*(p+1) == 'h')
            {if (*(p-1) == ' ')
               {sp = strcat(sp," g"); p++; continue;} /* ghost */
             else
               {p++; continue;} /* might flight higher */
            }
          if ((*(p+1) == 'n')&&(!isvowel1(*(p+2)))) continue; /* align */
          if ((*(p-1) == 'n')&&(*(p+1) == ' ')) continue; /* -ing */
          if (*(p-1) == 'g') {sp=strcat(sp," g"); continue;} /* bagged */
          if (is_front_vowel(*(p+1))) sp = strcat(sp," jh");
          else                        sp = strcat(sp," g");
          continue;

	  case 'h':
	    if (isvowel1(*(p+1))) sp = strcat(sp," hh"); /* Hymen */
	  continue;

	  case 'i':
          if ((*(p+1) == 'g')&&(*(p+2) == 'h'))  /* igh... */
            {sp = strcat(sp," ay"); continue;}
          if (*(p+1) == 'e') {sp = strcat(sp," iy"); p++; continue;}
          if (*(p+1) == 'u') {sp = strcat(sp," iy"); continue;}
          if ((*(p+1) == 'o')&&(*(p+2) == 'n')) /* -ion */
            {if (bound(*(p-2))) /* #Cion */
               {sp = strcat(sp," '1 ay '0 ax"); p++; continue;} /* lion */
             else
               {if (*(p-1) == 'l')
                  {sp = strcat(sp," y '0 ax"); p++; continue;}/* million */
                else
                  {sp = strcat(sp," '0 ax"); p++; continue;} /* diction */
	    }  }
          if (short_env(p)) sp = strcat(sp," ih");
          else              sp = strcat(sp," ay");
          continue;

	  case 'j':
          if ((*(p-1) == 'b')&&(bound(*(p-2)))) /* Bjorn */
	    {sp = strcat(sp," y"); continue; }
          sp = strcat(sp," jh");
          continue;

	  case 'k':
          if ((*(p-1) == ' ')&&(*(p+1) == 'n')) continue;/* knee */
          sp = strcat(sp," k");
          continue;

	  case 'l':
          if ( (*(p+1) == 'e') && (iscons1(*(p-1))) )
            {if  ( bound(*(p+2)) || (((*(p+2) == 's') || (*(p+2) == 'd'))&&bound(*(p+3)))) /*rifle[s/d]*/
	       {if (lexical_level) sp = strcat(sp," '0 ax l");
                else               sp = strcat(sp," '0 el");
                p++; continue;
            }  }
          sp = strcat(sp," l");
 	  continue;

	  case 'm':
          if ((*(p-1) == ' ')&&(*(p+1) == 'c')) /* mcvey,mcintosh */
            {sp = strcat(sp," m ae k"); p++;}
          else sp = strcat(sp," m");
          continue;

	  case 'n':
          if (velar(*(p+1))) sp = strcat(sp," nx");
          else sp = strcat(sp," n");
          continue;

	  case 'o':
          switch (*(p+1))
            {case 'a': {sp = strcat(sp," ow"); p++; continue;}/*toad*/
             case 'u': {sp = strcat(sp," aw"); p++; continue;}/*loud*/
             case 'i': {sp = strcat(sp," oy"); p++; continue;}/*noise*/
             case 'y': {sp = strcat(sp," oy"); p++; continue;}/*toy*/
             case 'o': {sp = strcat(sp," uw"); p++; continue;}/*toot*/
             case 'r': {sp = strcat(sp," ao");      continue;}/*for*/
            }
          if ((*(p+1) == 'w') && (bound(*(p+2)))) /* sorrow, arrow, bow */
	    {sp = strcat(sp," ow"); p++; continue;}
          if (bound(*(p+1))) {sp = strcat(sp," ow"); continue;} /*honcho*/
          if ((*(p+1) == 's')&&(*(p+2) == ' '))
             {sp = strcat(sp," ow"); continue;} /* tomatos */
          if (short_env(p)) sp = strcat(sp," aa"); /*tot*/
          else              sp = strcat(sp," ow"); /*tote*/
          continue;

	  case 'p':
          if (*(p+1) == 'h') {sp = strcat(sp," f"); p++; continue;}
          if ((*(p+1) == 'n')&&(*(p-1) == ' ')) continue; /*pneu-*/
          if ((*(p+1) == 's')&&(*(p-1) == ' '))
            {sp = strcat(sp," s"); p++; continue;} /*psych-*/
          sp = strcat(sp," p");
          continue;

          case 'q':
          sp = strcat(sp," k w");/*Qantas*/
          if (*(p+1) == 'u') p++;/*quantity*/
          continue;

	  case 'r':
          if (*(p-1) == 'r')
            {sp=strcat(sp," r"); continue;} /* bizarre, pierre */
          if ((iscons1(*(p-1)))&&(*(p+1) == 'e'))
            {if  ( bound(*(p+2)) || (((*(p+2) == 's') || (*(p+2) == 'd'))&&bound(*(p+3)))) /*sabre[s/d]*/
	       {if (lexical_level) sp = strcat(sp," '0 ax r");
                else               sp = strcat(sp," '0 er");
                p++; continue;
            }  }


          if ((iscons1(*(p-1)))&&(*(p+1) == 'e')&&bound(*(p+2)))
            {sp=strcat(sp," '0 ax r"); p++; continue;} /* acre,centre,sabre */
          if ((iscons1(*(p-1)))&&bound(*(p+1)))
            {sp=strcat(sp," '0 ax r"); p++; break;} /* Spektr (Russian) */
          sp = strcat(sp," r");
          if ((*(p-1) == ' ')&&(*(p+1) == 'h')) p++; /* Rhode */
          continue;

	  case 's':
          if (*(p+1) == 'h') {sp = strcat(sp," sh"); p++; continue;}/*shad*/
          if ((*(p+1) == 'i')&&(*(p+2) == 'o')) /* -sio */
            {if (*(p-1) == 's') sp = strcat(sp," sh"); /*mission*/
             else               sp = strcat(sp," zh"); /*abrasion*/
             continue;
            }
          if ((*(p+1) == ' ')&& voiced(p-1))  /* bags */
            {sp=strcat(sp," z"); continue;}
          if ((*(p+1) == 'c')&&(*(p+2) == 'h')) /* sch = /sh/ */
            {sp=strcat(sp," sh"); p++; p++; continue;}
          sp = strcat(sp," s");
          continue;

	  case 't':
          if (*(p+1) == 'h') {sp = strcat(sp," th"); p++; continue;}/*thick*/
          if ((*(p+1) == 'i')&&(*(p+2) == 'o'))/*-tion*/
            {sp = strcat(sp," sh"); continue;}
          if ((*(p+1) == 'c')&&(*(p+2) == 'h')) continue; /* batch */
          sp = strcat(sp," t");
          continue;

	  case 'u':
          if (*(p+1) == 'y')
            {sp = strcat(sp," ay"); p++; continue;} /* buy, guy */
          if (short_env(p)) sp = strcat(sp," ax");
          else
            {if ((*(p-1) == 'r'))              {sp = strcat(sp," uw"); continue;} /* rune */
       /* American rule, not British or stage English: */
             if (coronal(*(p-1)))              {sp = strcat(sp," uw"); continue;} /* tune */
             if ((*(p-1)=='h')&&(*(p-2)=='j')) {sp = strcat(sp," uw"); continue;} /* Judy */
             sp = strcat(sp," y uw");
            }
          continue;

	  case 'v':
          sp = strcat(sp," v");
          continue;

	  case 'w':
          if (*(p+1) == 'h') {sp = strcat(sp," wh"); p++; continue;}/*when*/
          if (*(p+1) == 'r') continue; /* wrist */
          sp = strcat(sp," w");
          continue;

	  case 'x':
          sp = strcat(sp," k s");
          continue;

	  case 'y':
          if (isvowel1(*(p+1))) sp = strcat(sp," y"); /* yes */
          else
            {if (bound(*(p+1)))  /* final y */
               {if ((iscons1(*(p-1)))&&(bound(*(p-2))))
                  {sp = strcat(sp," '1 ay"); continue;} /*  my */
                if ((iscons1(*(p-1)))&&(iscons1(*(p-2)))&&(bound(*(p-3))))
                  {sp = strcat(sp," '1 ay"); continue;} /* fly */
                sp = strcat(sp," iy");               /* envy */
               }
             else sp = strcat(sp," ih");
            }
          continue;

	  case 'z':
          if (*(p+1) == 'h') {sp = strcat(sp," zh"); p++; continue;} /* zhivago */
          sp = strcat(sp," z");
          continue;

	  case ' ':
/*          sp = strcat(sp," #"); */
          continue;
      }  }
if (db_level > 2) printf("%soutput='%s'\n",pdb,sp);
 db_leave_msg(proc,1); /* debug only */
    return sp;
   }
/** end main function **/

/** local auxiliary functions **/


static boolean pronounceable_token(SUBSTRING *token)
/* Returns T iff token is pronounceable             */
{char *proc = "pronounceable_token";
 boolean pronounceable = T, vowel_letter_is_present = F;
 char sxdbx[LINE_LENGTH], *sxdb = &sxdbx[0];
 char *px, *py;
 char ccix[LONG_LINE], *cc = &ccix[0];
 char *cci_allowed = " bl br bh  bj ch chr cl cr cz dh dm dr dv dw fl fr gh gl gn gr gw kh khm kl kn kr kw ll mb pf ph phr pl pn pr ps rh sc sch schl schm schn schr schw scl scr sh sk shl shr sl sm sn sp sph spl spr sq sr st str sv sw th thr thw tr ts tw vl wh wr zh zl zw";
 char *ccf_allowed = " bb bs ch chs cht ck cks ct cts cs dd dds ds dst dt dth dths fs ft fts fth fths ff ffs gs gg ggs gh ghs ght ghts gn gns hm hms hn ks lb lbs l ch lch ld lds ldnt lf lfs lfth lfths lk lks ll lls lm lms ln lns lp lps ls lt lts ltz lth lths mb mbs mph ms mm mn mp mps mpt mpts mph mphs ms mt n nc nck ncs nch nct ncts nd nds ndt ndts ndth ndths ng ngs ngth ngths nk nks nn nns ns nsk nt nts nth nths nx nz p ph pp pps ps pt pts rb rbs rc rcs rch rct rcts rd rds rf rfs rg rgs rk rks rl rls rm rms rmth rn rns rp rps rr rrs rs rst rsts rsh rt rts rth rths rtz sch sh sk sks sm sms ss sp sps st sts sh tch th thm thms ths tll ts tt tts tz vs wd wds wl wls wk wn wns wth wths ws xs xt xts xths";

 db_enter_msg(proc,1); /* debug only */
if (db_level > 1) printf("%s token='%s'\n",pdb,substr_to_str(token,sxdb,LINE_LENGTH));

 /* unpronounceable if one of the characters is a digit or funny character */
 /* or if there are no vowel letters                                       */
 for (px = token->start; ((pronounceable)&&(px <= token->end)); px++)
   {if (isdigit((int)*px))  pronounceable = F;
    if (*px == '&')         pronounceable = F;
    if (isvowel1(*px)) vowel_letter_is_present = T;
   }
 if (!vowel_letter_is_present)
   {pronounceable = F;
    goto RETURN;
   }

/* unpronounceable if initial consonant cluster is verboten */
 /* build initial consonant cluster in cc[] */
 /* special check to ignore initial "mc", as in "McBeth" */
 if (strncmp("mc",token->start,2)==0) token->start += 2;
 py = cc;
 for (px = token->start; ((px <= token->end)&&(!isvowel1(*px))); px++)
   {if (*px != '\'') *(py++) = *px; 
   }
 *(py) = '\0';
if (db_level > 1) printf("%s initial cc = '%s'\n",pdb,cc);
/* check it for validity */
 if (strlen(cc) < 2) goto RETURN; /* C0 and C1 are always o.k. */
 if (strstr(cci_allowed,cc) == NULL)
   {pronounceable = F;
if (db_level > 1) printf("%s not in cci_allowed, unpronounceable\n",pdb);
    goto RETURN;
   }
if (db_level > 1) printf("%s checking final CC\n",pdb);

/* unpronounceable if final consonant cluster is verboten */
 /* build final consonant cluster in cc[] */
 /* special check to ignore possessive suffixes */
 if ((*(token->end) == 's')&&(*((token->end)-1) == '\'')) token->end -= 2;
 if ((*(token->end) == '\'')) token->end -= 1;
 px = token->end;
 while ((px >= token->start)&&(!isvowel1(*px))) px -= 1;
 px += 1;
 py = cc;
 for (px += 1; px <= token->end; px++) if (*px != '\'') *(py++) = *px; /* ignore apostrophe */
 *(py) = '\0';
if (db_level > 1) printf("%s final cc = '%s'\n",pdb,cc);
/* check it for validity */
 if (strlen(cc) < 2) goto RETURN; /* C0 and C1 are always o.k. */
 if (strstr(ccf_allowed,cc) == NULL)
   {pronounceable = F;
    goto RETURN;
   }
RETURN:
if (db_level > 1) printf("%s at return, pronounceable=%s\n",pdb,bool_print(pronounceable));
 db_leave_msg(proc,1); /* debug only */
 return (pronounceable);
}

/* end file ttp1s.c */
