Logo Search packages:      
Sourcecode: bayonne version File versions  Download package

russian.cpp

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include <bayonne.h>
#include <cc++/strchar.h>
#ifdef      HAVE_SSTREAM
#include <sstream>
#else
#include <strstream>
#endif

#ifdef      HAVE_SSTREAM
#define     strstream   ostringstream
#endif

#ifdef  CCXX_NAMESPACES
namespace ost {
using namespace std;
#endif

class RussianTranslator : public Translator
{
private:
      char *getName(void)     { return "russian"; };
public:
      RussianTranslator();
      char *speak(Trunk *trunk);
} russian;

RussianTranslator::RussianTranslator() :
Translator("/bayonne/russian")
{
      slog(Slog::levelDebug) << "TTS: loading russian phrasebooks..." <<  endl;
}

static void spell(strstream *s, const char *text);

static int lownumber(strstream *s, int num)
{
      int divider = 100;

      while(num > 19)
      {
            if (num < divider)
            {
                  divider /= 10;
            }
            if (num / divider)
            {
                  *s << ',' << divider * ( num / divider );
            }
            num %= divider;
      }

      if (num) *s << ',' << num;

      return num;
}

static char* quantity_suffix(int num)
{
            switch (num)
            {
              case 1:
                  return "";
              case 2:
              case 3:
              case 4:
                  return "-case_1";
            }

      return "-multiple-case_1";
}

static char* gender_suffix(int num, char gender)
{
            switch (gender)
            {
              case 'f':
                if (num == 1 || num == 2) return "-feminine";
                  break;
              case 'n':
                  if (num == 1) return "-neuter";
                  break;
            }

      return "";
}

static int number(strstream *s, const char *text)
{
      unsigned long num;
      int last_num = 0;
      bool zero = true;
      float val;
      char buf[50];
      char *fact;

      if (!text)
            return true;

      if (!*text)
            return true;

      if (*text == '-')
      {
            *s << ",minus";
            ++text;
      }

      num = atol(text);

      if (num > 999999999)
      {
            zero = false;
            last_num = lownumber(s, num / 1000000000);
            *s << ",milliard" << quantity_suffix(last_num);
            last_num = 1000000000;
            num %= last_num;
      }
      if (num > 999999)
      {
            zero = false;
            last_num = lownumber(s, num / 1000000);
            *s << ",million" << quantity_suffix(last_num);
            last_num = 1000000;
            num %= last_num;
      }
      if (num > 999)
      {
            zero = false;
            last_num = lownumber(s, num / 1000);
            *s << gender_suffix(last_num, 'f');
            *s << ",1000" << quantity_suffix(last_num);
            last_num = 1000;
            num %= last_num;
      }

      if (num || zero)
            last_num = lownumber(s, num);

      if (num) zero = false;

      sscanf(text, "%f", &val);
      val = val - int(val);

      if(val)
      {
            *s << gender_suffix(last_num, 'f');

            *s << ",celaya";

            if(last_num > 1) *s << "-multiple-case_1";

            snprintf(buf, sizeof(buf), "%.3f", val);
            fact = strchr(buf, '.');

            char *tail;

            for(tail = strchr(fact, '\0'); tail > fact; tail--)
            {
                  if(*(tail - 1) != '0')
                  {
                        *tail = '\0';
                        break;
                  }
            }

            last_num = number(s, ++fact);
            *s << gender_suffix(last_num, 'f');

            switch (strlen(fact))
            {
                  case 1:
                        *s << ",desyataya";
                        break;
                  case 2:
                        *s << ",sotaya";
                        break;
                  case 3:
                        *s << ",tisyachnaya";
                        break;
            }

            if(last_num > 1) *s << "-multiple-case_1";
            last_num = 2;
      }

      if(zero)
            return -1;
      else
            return last_num;
}

static void order(strstream *s, int num)
{
      lownumber(s, num);
      *s << "-order";
}

static char* symname(const char ch)
{
      typedef struct {
            char value;
            char* name;
      } sym_t;

      sym_t syms[] = {
            {'', "cyrillic_a"},
            {'', "cyrillic_be"},
            {'', "cyrillic_ve"},
            {'', "cyrillic_ghe"},
            {'', "cyrillic_de"},
            {'', "cyrillic_ie"},
            {'', "cyrillic_io"},
            {'', "cyrillic_zhe"},
            {'', "cyrillic_ze"},
            {'', "cyrillic_i"},
            {'', "cyrillic_shorti"},
            {'', "cyrillic_ka"},
            {'', "cyrillic_el"},
            {'', "cyrillic_em"},
            {'', "cyrillic_en"},
            {'', "cyrillic_o"},
            {'', "cyrillic_pe"},
            {'', "cyrillic_er"},
            {'', "cyrillic_es"},
            {'', "cyrillic_te"},
            {'', "cyrillic_u"},
            {'', "cyrillic_ef"},
            {'', "cyrillic_ha"},
            {'', "cyrillic_tse"},
            {'', "cyrillic_che"},
            {'', "cyrillic_sha"},
            {'', "cyrillic_shcha"},
            {'', "cyrillic_softsign"},
            {'', "cyrillic_hardsign"},
            {'', "cyrillic_yi"},
            {'', "cyrillic_e"},
            {'', "cyrillic_yu"},
            {'', "cyrillic_ya"}
      };

      for (unsigned i = 0; i < sizeof(syms)/sizeof(sym_t); i++)
      {
            if (syms[i].value == ch)
                  return syms[i].name;
      }

      return 0L;
}

static void spell(strstream *s, const char *text)
{

      char ch;

      if(!text) return;

      while((ch = *(text++)))
      {
            char* name = 0L;

            if(ch >= 'A' && ch <= 'Z')
                  ch += 32;
            if(ch >= '' && ch <= '')
                  ch -= 32;

            if(ch >= '0' && ch <= '9')
                  *s << ',' << ch;
            else if(ch >= 'a' && ch <= 'z')
                  *s << ',' << ch;
            else if(name == symname(ch))
                  *s << ',' << name;
            else if(ch == '.')
                  *s << ",tochka";
      }
}

static void parsedate(const char *text, int *month, int *day, int *year)
{
      if(text[2] == '/')
            sscanf(text, "%02d/%02d/%04d", &month, &day, &year);
      else if(text[2] == '.')
            sscanf(text, "%02d.%02d.%04d", &day, &month, &year);
      else if(text[4] == '-')
            sscanf(text, "%04d-%02d-%02d", &year, &month, &day);
      else
            sscanf(text, "%04d%02d%02d", &year, &month, &day);
}

static void saydate(strstream *s, const char *text)
{
      static char *months[] = {
            "yanvar", "fevral", "mart", "aprel",
            "mai", "iyun", "iyul", "avgust",
            "sentyabr", "oktyabr", "noyabr", "dekabr"};

      int month, day, year;
      char buf[5];

      parsedate(text, &month, &day, &year);

      --month;

      lownumber(s, day);

      *s << "-order-neuter";
      *s << ',' << months[month];
      *s << "-case_1";

      if(year != 2000)
      {
            sprintf(buf, "%d", year);
            number(s, buf);
      }
      else
      {
            *s << ",2000";
      }

      *s << "-order-case_1,god-case_1";
}

static void sayweekday(strstream *s, const char *text)
{
      static char *days[] = {
            "voskresenie", "ponedelnik", "vtornik", "sreda",
            "chetverg", "pyatnica", "subbota"};

      time_t cl;
      struct tm *ti;

      time(&cl);
      ti = localtime (&cl);

      parsedate(text, &ti->tm_mon, &ti->tm_mday, &ti->tm_year);

      if(ti->tm_year > 1000) ti->tm_year -= 1900;

      --ti->tm_mon;

      mktime(ti);

      *s << ',' << days[ti->tm_wday];
}

static char *getchange(const char *text, int dec, char *ch)
{
      int len;
      text = strchr(text, '.');

      if(!text)
            return NULL;

      ++text;
      memset(ch, '0', dec);
      ch[dec] = 0;

      len = strlen(text);

      if(len > dec) len = dec;

      strncpy(ch, text, len);

      return ch;
}

static void sayvalue(strstream *s, const char *cu, char g1,
      const char *ch, char g2, int dec, const char *text)
{
      char chbuf[dec + 1];
      int currency = atoi(text);
      int last_num;
      char cbuf[11];
      const char *change = getchange(text, dec, chbuf);

      if(currency)
      {
            sprintf(cbuf, "%d", currency);
            last_num = number(s, cbuf);
            *s << gender_suffix(last_num, g1);
            *s << ',' << cu << quantity_suffix(last_num);
      }

      if(atoi(change))
      {
            last_num = number(s, change);
            *s << gender_suffix(last_num, g2);
            *s << ',' << ch << quantity_suffix(last_num);
      }
}

static bool sayprimary(strstream *s, const char *text)
{
      const char *cu    = keylocal.getLast("primarycurrency");
      const char *ch    = keylocal.getLast("primarychange");
      const char *d     = keylocal.getLast("primarydecimal");
      const char *g1    = keylocal.getLast("primarycurrencygender");
      const char *g2    = keylocal.getLast("primarychangegender");

      if(!d)
            d = "2";

      if(!g1)
            g1 = "m";

      if(!g2)
            g2 = "m";

      if(!cu)
            return false;

      sayvalue(s, cu, g1[0], ch, g2[0], atoi(d), text);
      return true;
}

static bool saylocal(strstream *s, double v, bool orflag)
{
      char tbuf[33];
      const char *cu    = keylocal.getLast("localcurrency");
      const char *ch    = keylocal.getLast("localchange");
      const char *d     = keylocal.getLast("localdecimal");
      const char *cvt   = keylocal.getLast("convertcurrency");
      const char *g1    = keylocal.getLast("localcurrencygender");
      const char *g2    = keylocal.getLast("localchangegender");

      if(!d)
            d = "2";

      if(!g1)
            g1 = "m";

      if(!g2)
            g2 = "f";

      if(!cu)
            return true;

      if(cvt && orflag)
      {
            v *= atof(cvt);
            sprintf(tbuf, "%f", v);
      }
      else
            sprintf(tbuf, "%f", v);

      if(!v)
            return false;

      if (orflag)
            *s << ",ili";

      sayvalue(s, cu, g1[0], ch, g2[0], atoi(d), tbuf);

      return true;
}

static void saycurrency(strstream *s, const char *text)
{
      saylocal(s, atof(text), sayprimary(s, text));
}

static bool sayduration(strstream *s, const char *text)
{
      int hour = 0, minute = 0, second = 0;
      int last_num;

      if(strchr(text, ':'))
      {
            sscanf(text, "%d:%02d:%02d", &hour, &minute, &second);
      }
      else
      {
            if(strlen(text) > 4)
                  sscanf(text, "%02d%02d%02d",
                        &hour, &minute, &second);
            else
                  sscanf(text, "%02d%02d",
                        &hour, &minute);
      }
      if(hour)
      {
            last_num = lownumber(s, hour);
            *s << ",chas" << quantity_suffix(last_num);
      }
      if(minute)
      {
            last_num = lownumber(s, minute);
            *s << gender_suffix(last_num, 'f');
            *s << ",minuta" << quantity_suffix(last_num);
      }
      if(second)
      {
            last_num = lownumber(s, second);
            *s << gender_suffix(last_num, 'f');
            *s << ",secunda" << quantity_suffix(last_num);
      }

      if(hour || minute || second) return false;

      return true;
}

static void saytime(strstream *s, const char *text)
{
      int hour = 0, minute = 0;
      int last_num;

      if(text[2] == ':')
            sscanf(text, "%02d:%02d", &hour, &minute);
      else
            sscanf(text, "%02d%02d", &hour, &minute);

      last_num = lownumber(s, hour);

      if (!hour)
      {
            *s << "0";
      }

      *s << ",chas" << quantity_suffix(last_num);

      if (minute)
      {
            last_num = lownumber(s, minute);
            *s << gender_suffix(last_num, 'f');
            *s << ",minuta" << quantity_suffix(last_num);
      }
}

char *RussianTranslator::speak(Trunk *trunk)
{
      char *pbuf = getPlayBuffer(trunk);
#ifdef      HAVE_SSTREAM
      ostringstream str;
#else
      strstream str(pbuf, 254);
#endif
      char rules[256];
      const char *rule = NULL;
      const char *phrase;
      bool skip = false;
      long last_num = 0;
      int last_digit = 0;
      char gender = 'm';
      char *text;
      ScriptImage *cmd = trunk->getImage();

      while(NULL != (rule = trunk->getValue(NULL)))
      {
            if(*rule != '&')
            {
                  str << ',' << rule;
                  continue;
            }
            phrase = getLast(rule + 1);
            if(!phrase)
            {
                  snprintf(rules, 256, "_russian_%s", rule + 1);
                  phrase = cmd->getLast(rules);
            }
            if(!phrase)
            {
                  snprintf(rules, 256, "_all_%s", rule + 1);
                  phrase = cmd->getLast(rules);
            }
            if(!phrase)
                  phrase = rule;

            strncpy(rules, phrase, 254);
            rules[255] = 0;
            rule = strtok(rules, " ;,\t\n");
            while(rule)
            {
                  if(!stricmp(rule, "&exit"))
                  {
                        if(skip)
                              return NULL;
                  }
                  else if(!stricmp(rule, "&ignore"))
                  {
                        trunk->getValue(NULL);
                  }
                  else if(!stricmp(rule, "&use"))
                  {
                        text = trunk->getValue(NULL);
                        if(text)
                              str << ',' << text;
                  }
                  else if(!stricmp(rule, "&skip"))
                  {
                        if(skip)
                              trunk->getValue(NULL);
                  }
                  else if(!stricmp(rule, "&single") || !stricmp(rule, "&singular"))
                  {
                        text = trunk->getValue(NULL);
                        if(last_digit == 1 && !skip && text)
                              str << ',' << text;
                  }
                  else if(!stricmp(rule, "&some") || !stricmp(rule, "&several"))
                  {
                        text = trunk->getValue(NULL);
                        if(last_digit > 1 && last_digit < 5 && !skip && text)
                              str << ',' << text;
                  }
                  else if(!stricmp(rule, "&plural"))
                  {
                        text = trunk->getValue(NULL);
                        if((last_digit > 4 || last_digit == 0) && !skip && text)
                              str << ',' << text;
                  }
                  else if(!stricmp(rule, "&masculine"))
                  {
                        gender = 'm';
                  }
                  else if(!stricmp(rule, "&feminine"))
                  {
                        gender = 'f';
                  }
                  else if(!stricmp(rule, "&neuter"))
                  {
                        gender = 'n';
                  }
                  else if(!stricmp(rule, "&spell"))
                  {
                        skip = false;
                        spell(&str, trunk->getValue(""));
                  }
                  else if(!stricmp(rule, "&number"))
                  {
                        text = trunk->getValue(NULL);
                        if(text)
                        {
                              last_num = atol(text);
                              last_digit = number(&str, text);

                              if (!strchr(text, '.'))
                              {
                                    str << gender_suffix(last_digit, gender);
                              }

                              skip = last_digit < 0;
                        }
                  }
                  else if(!stricmp(rule, "&order"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(text)
                        {
                              order(&str, atoi(text));
                              str << gender_suffix(1, gender);
                        }
                  }
                  else if(!stricmp(rule, "&duration"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(text)
                              skip = sayduration(&str, text);
                  }
                  else if(!stricmp(rule, "&time"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(text)
                              saytime(&str, text);
                  }
                  else if(!stricmp(rule, "&date"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(text)
                              saydate(&str, text);
                  }
                  else if(!stricmp(rule, "&weekday"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(text)
                              sayweekday(&str, text);
                  }
                  else if(!stricmp(rule, "&unit"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(text)
                        {
                              last_num = atol(text);
                              last_digit = number(&str, text);
                              if(last_digit < 0)
                              {
                                    str << ",0";
                                    str << gender_suffix(last_digit, 'N');
                              }
                              else if (!strchr(text, '.'))
                              {
                                    str << gender_suffix(last_digit, gender);
                              }
                        }
                  }
                  else if(!stricmp(rule, "&zero"))
                  {
                        skip = false;
                        text = trunk->getValue(NULL);
                        if(!last_num && text)
                              str << ',' << text;
                  }
                  else if(!stricmp(rule, "&currency"))
                  {
                        skip = false;
                        last_num = 1;
                        text = trunk->getValue(NULL);
                        if(text)
                        {
                              if(atof(text))
                                    saycurrency(&str, text);
                              else
                                    last_num = 0;
                        }
                  }
                  else if(!stricmp(rule, "&primary"))
                  {
                        skip = false;
                        last_num = 1;
                        text = trunk->getValue(NULL);
                        if(text)
                        {
                              if(atof(text))
                                    sayprimary(&str, text);
                              else
                                    last_num = 0;
                        }
                  }
                  else if(!stricmp(rule, "&local"))
                  {
                        skip = false;
                        last_num = 1;
                        text = trunk->getValue(NULL);
                        if(text)
                        {
                              if(!saylocal(&str, atof(text), false))
                                    last_num = 0;
                        }
                  }
                  else
                  {
                        skip = false;
                        str << ',' << rule;
                  }
                  rule = strtok(NULL, " ;,\t\n");
            }
      }

#ifdef      HAVE_SSTREAM
      snprintf(pbuf, 256, "%s", str.str().c_str());
#else
      str << ends;
      pbuf[255] = 0;
#endif
      while(*pbuf)
      {
            *pbuf = tolower(*pbuf);
            ++pbuf;
      }

      return NULL;
}

#ifdef  CCXX_NAMESPACES
};
#endif


Generated by  Doxygen 1.6.0   Back to index