Fixes for code smells from cppcheck static code analysis tool. Also includes some function refactoring.master
int c1; | int c1; | ||||
int n_bytes; | int n_bytes; | ||||
int ix; | |||||
static const unsigned char mask[4] = { 0xff, 0x1f, 0x0f, 0x07 }; | static const unsigned char mask[4] = { 0xff, 0x1f, 0x0f, 0x07 }; | ||||
// find the start of the next/previous character | // find the start of the next/previous character | ||||
n_bytes = 3; | n_bytes = 3; | ||||
c1 &= mask[n_bytes]; | c1 &= mask[n_bytes]; | ||||
int ix; | |||||
for (ix = 0; ix < n_bytes; ix++) | for (ix = 0; ix < n_bytes; ix++) | ||||
{ | { | ||||
if (!*buf) | if (!*buf) | ||||
int isspace2(unsigned int c) | int isspace2(unsigned int c) | ||||
{ | { | ||||
// can't use isspace() because on Windows, isspace(0xe1) gives TRUE ! | // can't use isspace() because on Windows, isspace(0xe1) gives TRUE ! | ||||
int c2; | |||||
if (((c2 = (c & 0xff)) == 0) || (c > ' ')) | |||||
if ( ((c & 0xff) == 0) || (c > ' ')) | |||||
return 0; | return 0; | ||||
return 1; | return 1; | ||||
} | } | ||||
{ | { | ||||
// Read 4 bytes (least significant first) into a word | // Read 4 bytes (least significant first) into a word | ||||
int ix; | int ix; | ||||
unsigned char c; | |||||
int acc = 0; | int acc = 0; | ||||
for (ix = 0; ix < 4; ix++) { | for (ix = 0; ix < 4; ix++) { | ||||
unsigned char c; | |||||
c = fgetc(f) & 0xff; | c = fgetc(f) & 0xff; | ||||
acc += (c << (ix*8)); | acc += (c << (ix*8)); | ||||
} | } |
fseek(f, 40, SEEK_SET); | fseek(f, 40, SEEK_SET); | ||||
if ((sr1 != samplerate_native) || (sr2 != sr1*2)) { | if ((sr1 != samplerate_native) || (sr2 != sr1*2)) { | ||||
int fd_temp; | |||||
char command[sizeof(path_home)+250]; | char command[sizeof(path_home)+250]; | ||||
failed = false; | failed = false; | ||||
#ifdef HAVE_MKSTEMP | #ifdef HAVE_MKSTEMP | ||||
strcpy(fname_temp, "/tmp/espeakXXXXXX"); | strcpy(fname_temp, "/tmp/espeakXXXXXX"); | ||||
int fd_temp; | |||||
if ((fd_temp = mkstemp(fname_temp)) >= 0) | if ((fd_temp = mkstemp(fname_temp)) >= 0) | ||||
close(fd_temp); | close(fd_temp); | ||||
#else | #else |
{ | { | ||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
char phonemes[55]; | char phonemes[55]; | ||||
char phonemes2[55]; | |||||
char *string1 = (char *)string; | char *string1 = (char *)string; | ||||
flags[0] = flags[1] = 0; | flags[0] = flags[1] = 0; | ||||
if (LookupDictList(tr, &string1, phonemes, flags, 0, NULL)) { | if (LookupDictList(tr, &string1, phonemes, flags, 0, NULL)) { | ||||
char phonemes2[55]; | |||||
SetWordStress(tr, phonemes, flags, -1, 0); | SetWordStress(tr, phonemes, flags, -1, 0); | ||||
DecodePhonemes(phonemes, phonemes2); | DecodePhonemes(phonemes, phonemes2); | ||||
sprintf(text_out, "[\002%s]]", phonemes2); | sprintf(text_out, "[\002%s]]", phonemes2); | ||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
char single_letter[24]; | char single_letter[24]; | ||||
char phonemes[60]; | char phonemes[60]; | ||||
char phonemes2[60]; | |||||
const char *lang_name = NULL; | const char *lang_name = NULL; | ||||
char *string; | char *string; | ||||
static char buf[60]; | static char buf[60]; | ||||
} | } | ||||
if (phonemes[0]) { | if (phonemes[0]) { | ||||
char phonemes2[60]; | |||||
if (lang_name) { | if (lang_name) { | ||||
SetWordStress(translator2, phonemes, flags, -1, 0); | SetWordStress(translator2, phonemes, flags, -1, 0); | ||||
DecodePhonemes(phonemes, phonemes2); | DecodePhonemes(phonemes, phonemes2); | ||||
// c1: the punctuation character | // c1: the punctuation character | ||||
// c2: the following character | // c2: the following character | ||||
int punct_count; | |||||
const char *punctname = NULL; | const char *punctname = NULL; | ||||
int soundicon; | int soundicon; | ||||
int attributes; | int attributes; | ||||
int len; | int len; | ||||
int bufix1; | int bufix1; | ||||
char buf[200]; | char buf[200]; | ||||
char buf2[80]; | |||||
char ph_buf[30]; | char ph_buf[30]; | ||||
c2 = *c2_ptr; | c2 = *c2_ptr; | ||||
if (punctname == NULL) | if (punctname == NULL) | ||||
return -1; | return -1; | ||||
if ((*bufix == 0) || (end_clause == 0) || (tr->langopts.param[LOPT_ANNOUNCE_PUNCT] & 2)) { | if ((*bufix == 0) || (end_clause == 0) || (tr->langopts.param[LOPT_ANNOUNCE_PUNCT] & 2)) { | ||||
punct_count = 1; | |||||
int punct_count = 1; | |||||
while (!Eof() && (c2 == c1) && (c1 != '<')) { // don't eat extra '<', it can miss XML tags | while (!Eof() && (c2 == c1) && (c1 != '<')) { // don't eat extra '<', it can miss XML tags | ||||
punct_count++; | punct_count++; | ||||
c2 = GetC(); | c2 = GetC(); | ||||
if (embedded_value[EMBED_S] < 300) | if (embedded_value[EMBED_S] < 300) | ||||
sprintf(buf, "\001+10S"); // Speak punctuation name faster, unless we are already speaking fast. It would upset Sonic SpeedUp | sprintf(buf, "\001+10S"); // Speak punctuation name faster, unless we are already speaking fast. It would upset Sonic SpeedUp | ||||
char buf2[80]; | |||||
while (punct_count-- > 0) { | while (punct_count-- > 0) { | ||||
sprintf(buf2, " %s", punctname); | sprintf(buf2, " %s", punctname); | ||||
strcat(buf, buf2); | strcat(buf, buf2); | ||||
int ix; | int ix; | ||||
int len; | int len; | ||||
void *vp; | |||||
if (wide) { | if (wide) { | ||||
len = (wcslen((const wchar_t *)name)+1)*sizeof(wchar_t); | len = (wcslen((const wchar_t *)name)+1)*sizeof(wchar_t); | ||||
if (namedata_ix+len >= n_namedata) { | if (namedata_ix+len >= n_namedata) { | ||||
// allocate more space for marker names | // allocate more space for marker names | ||||
void *vp; | |||||
if ((vp = realloc(namedata, namedata_ix+len + 1000)) == NULL) | if ((vp = realloc(namedata, namedata_ix+len + 1000)) == NULL) | ||||
return -1; // failed to allocate, original data is unchanged but ignore this new name | return -1; // failed to allocate, original data is unchanged but ignore this new name | ||||
// !!! Bug?? If the allocated data shifts position, then pointers given to user application will be invalid | // !!! Bug?? If the allocated data shifts position, then pointers given to user application will be invalid | ||||
int c1 = ' '; // current character | int c1 = ' '; // current character | ||||
int c2; // next character | int c2; // next character | ||||
int cprev = ' '; // previous character | int cprev = ' '; // previous character | ||||
int cprev2 = ' '; | |||||
int c_next; | int c_next; | ||||
int parag; | int parag; | ||||
int ix = 0; | int ix = 0; | ||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
} | } | ||||
} | } | ||||
cprev2 = cprev; | |||||
int cprev2 = cprev; | |||||
cprev = c1; | cprev = c1; | ||||
c1 = c2; | c1 = c2; | ||||
f = NULL; | f = NULL; | ||||
if ((f = fopen(fname, "rb")) != NULL) { | if ((f = fopen(fname, "rb")) != NULL) { | ||||
int ix; | int ix; | ||||
int fd_temp; | |||||
int header[3]; | int header[3]; | ||||
char command[sizeof(fname2)+sizeof(fname2)+40]; | char command[sizeof(fname2)+sizeof(fname2)+40]; | ||||
#ifdef HAVE_MKSTEMP | #ifdef HAVE_MKSTEMP | ||||
strcpy(fname_temp, "/tmp/espeakXXXXXX"); | strcpy(fname_temp, "/tmp/espeakXXXXXX"); | ||||
int fd_temp; | |||||
if ((fd_temp = mkstemp(fname_temp)) >= 0) | if ((fd_temp = mkstemp(fname_temp)) >= 0) | ||||
close(fd_temp); | close(fd_temp); | ||||
#else | #else |
static int attrcopy_utf8(char *buf, const wchar_t *pw, int len) | static int attrcopy_utf8(char *buf, const wchar_t *pw, int len) | ||||
{ | { | ||||
// Convert attribute string into utf8, write to buf, and return its utf8 length | // Convert attribute string into utf8, write to buf, and return its utf8 length | ||||
unsigned int c; | |||||
int ix = 0; | int ix = 0; | ||||
int n; | |||||
int prev_c = 0; | |||||
if (pw != NULL) { | if (pw != NULL) { | ||||
unsigned int c; | |||||
int prev_c = 0; | |||||
while ((ix < (len-4)) && ((c = *pw++) != 0)) { | while ((ix < (len-4)) && ((c = *pw++) != 0)) { | ||||
if ((c == '"') && (prev_c != '\\')) | if ((c == '"') && (prev_c != '\\')) | ||||
break; // " indicates end of attribute, unless preceded by backstroke | break; // " indicates end of attribute, unless preceded by backstroke | ||||
n = utf8_out(c, &buf[ix]); | |||||
int n = utf8_out(c, &buf[ix]); | |||||
ix += n; | ix += n; | ||||
prev_c = c; | prev_c = c; | ||||
} | } | ||||
const char *p; | const char *p; | ||||
SSML_STACK *sp; | SSML_STACK *sp; | ||||
const char *v_id; | const char *v_id; | ||||
int voice_name_specified; | |||||
int voice_found; | int voice_found; | ||||
espeak_VOICE voice_select; | espeak_VOICE voice_select; | ||||
static char voice_name[40]; | static char voice_name[40]; | ||||
char language[40]; | char language[40]; | ||||
char buf[80]; | |||||
MAKE_MEM_UNDEFINED(&voice_name, sizeof(voice_name)); | MAKE_MEM_UNDEFINED(&voice_name, sizeof(voice_name)); | ||||
for (ix = 0; ix < n_ssml_stack; ix++) { | for (ix = 0; ix < n_ssml_stack; ix++) { | ||||
sp = &ssml_stack[ix]; | sp = &ssml_stack[ix]; | ||||
voice_name_specified = 0; | |||||
int voice_name_specified = 0; | |||||
if ((sp->voice_name[0] != 0) && (SelectVoiceByName(NULL, sp->voice_name) != NULL)) { | if ((sp->voice_name[0] != 0) && (SelectVoiceByName(NULL, sp->voice_name) != NULL)) { | ||||
voice_name_specified = 1; | voice_name_specified = 1; | ||||
if ((strchr(v_id, '+') == NULL) && ((voice_select.gender == ENGENDER_UNKNOWN) || (voice_select.gender == base_voice->gender)) && (base_voice_variant_name[0] != 0)) { | if ((strchr(v_id, '+') == NULL) && ((voice_select.gender == ENGENDER_UNKNOWN) || (voice_select.gender == base_voice->gender)) && (base_voice_variant_name[0] != 0)) { | ||||
// a voice variant has not been selected, use the original voice variant | // a voice variant has not been selected, use the original voice variant | ||||
char buf[80]; | |||||
sprintf(buf, "%s+%s", v_id, base_voice_variant_name); | sprintf(buf, "%s+%s", v_id, base_voice_variant_name); | ||||
strncpy0(voice_name, buf, sizeof(voice_name)); | strncpy0(voice_name, buf, sizeof(voice_name)); | ||||
return voice_name; | return voice_name; | ||||
// a voice change. | // a voice change. | ||||
// Returns CLAUSE_TYPE_VOICE_CHANGE if there is a voice change | // Returns CLAUSE_TYPE_VOICE_CHANGE if there is a voice change | ||||
const wchar_t *lang; | |||||
const wchar_t *gender; | |||||
const wchar_t *name; | |||||
const wchar_t *age; | |||||
const wchar_t *variant; | |||||
int value; | |||||
const char *new_voice_id; | const char *new_voice_id; | ||||
static const MNEM_TAB mnem_gender[] = { | static const MNEM_TAB mnem_gender[] = { | ||||
if (n_ssml_stack > 1) | if (n_ssml_stack > 1) | ||||
n_ssml_stack--; | n_ssml_stack--; | ||||
} else { | } else { | ||||
const wchar_t *lang; | |||||
const wchar_t *gender; | |||||
const wchar_t *name; | |||||
const wchar_t *age; | |||||
const wchar_t *variant; | |||||
// add a stack frame if any voice details are specified | // add a stack frame if any voice details are specified | ||||
lang = GetSsmlAttribute(pw, "xml:lang"); | lang = GetSsmlAttribute(pw, "xml:lang"); | ||||
ssml_sp = &ssml_stack[n_ssml_stack++]; | ssml_sp = &ssml_stack[n_ssml_stack++]; | ||||
int value; | |||||
attrcopy_utf8(ssml_sp->language, lang, sizeof(ssml_sp->language)); | attrcopy_utf8(ssml_sp->language, lang, sizeof(ssml_sp->language)); | ||||
attrcopy_utf8(ssml_sp->voice_name, name, sizeof(ssml_sp->voice_name)); | attrcopy_utf8(ssml_sp->voice_name, name, sizeof(ssml_sp->voice_name)); | ||||
if ((value = attrnumber(variant, 1, 0)) > 0) | if ((value = attrnumber(variant, 1, 0)) > 0) | ||||
// Set the speech parameters from the parameter stack | // Set the speech parameters from the parameter stack | ||||
int param; | int param; | ||||
int ix; | int ix; | ||||
int value; | |||||
char buf[20]; | char buf[20]; | ||||
int new_parameters[N_SPEECH_PARAM]; | int new_parameters[N_SPEECH_PARAM]; | ||||
static const char cmd_letter[N_SPEECH_PARAM] = { 0, 'S', 'A', 'P', 'R', 0, 'C', 0, 0, 0, 0, 0, 'F' }; // embedded command letters | static const char cmd_letter[N_SPEECH_PARAM] = { 0, 'S', 'A', 'P', 'R', 0, 'C', 0, 0, 0, 0, 0, 'F' }; // embedded command letters | ||||
} | } | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) { | for (param = 0; param < N_SPEECH_PARAM; param++) { | ||||
int value; | |||||
if ((value = new_parameters[param]) != speech_parameters[param]) { | if ((value = new_parameters[param]) != speech_parameters[param]) { | ||||
buf[0] = 0; | buf[0] = 0; | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
int ix; | |||||
int letter; | int letter; | ||||
char *p; | char *p; | ||||
p = &outbuf[index]; | p = &outbuf[index]; | ||||
if ((letter = LookupMnem(keynames, p)) != 0) { | if ((letter = LookupMnem(keynames, p)) != 0) { | ||||
ix = utf8_out(letter, p); | |||||
int ix; | |||||
ix = utf8_out(letter, p); | |||||
*outix = index + ix; | *outix = index + ix; | ||||
return letter; | return letter; | ||||
} | } | ||||
static void SetProsodyParameter(int param_type, const wchar_t *attr1, PARAM_STACK *sp, PARAM_STACK *param_stack, int *speech_parameters) | static void SetProsodyParameter(int param_type, const wchar_t *attr1, PARAM_STACK *sp, PARAM_STACK *param_stack, int *speech_parameters) | ||||
{ | { | ||||
int value; | int value; | ||||
int sign; | |||||
static const MNEM_TAB mnem_volume[] = { | static const MNEM_TAB mnem_volume[] = { | ||||
{ "default", 100 }, | { "default", 100 }, | ||||
// mnemonic specifies a value as a percentage of the base pitch/range/rate/volume | // mnemonic specifies a value as a percentage of the base pitch/range/rate/volume | ||||
sp->parameter[param_type] = (param_stack[0].parameter[param_type] * value)/100; | sp->parameter[param_type] = (param_stack[0].parameter[param_type] * value)/100; | ||||
} else { | } else { | ||||
sign = attr_prosody_value(param_type, attr1, &value); | |||||
int sign = attr_prosody_value(param_type, attr1, &value); | |||||
if (sign == 0) | if (sign == 0) | ||||
sp->parameter[param_type] = value; // absolute value in Hz | sp->parameter[param_type] = value; // absolute value in Hz | ||||
unsigned int ix; | unsigned int ix; | ||||
int index; | int index; | ||||
int c; | |||||
int tag_type; | int tag_type; | ||||
int value; | int value; | ||||
int value2; | int value2; | ||||
const wchar_t *attr2; | const wchar_t *attr2; | ||||
const wchar_t *attr3; | const wchar_t *attr3; | ||||
int terminator; | int terminator; | ||||
char *uri; | |||||
int param_type; | int param_type; | ||||
char tag_name[40]; | char tag_name[40]; | ||||
char buf[160]; | char buf[160]; | ||||
}; | }; | ||||
for (ix = 0; ix < (sizeof(tag_name)-1); ix++) { | for (ix = 0; ix < (sizeof(tag_name)-1); ix++) { | ||||
int c; | |||||
if (((c = xml_buf[ix]) == 0) || iswspace(c)) | if (((c = xml_buf[ix]) == 0) || iswspace(c)) | ||||
break; | break; | ||||
tag_name[ix] = tolower((char)c); | tag_name[ix] = tolower((char)c); | ||||
sp = PushParamStack(tag_type, n_param_stack, (PARAM_STACK *)param_stack); | sp = PushParamStack(tag_type, n_param_stack, (PARAM_STACK *)param_stack); | ||||
if ((attr1 = GetSsmlAttribute(px, "src")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "src")) != NULL) { | ||||
char fname[256]; | |||||
attrcopy_utf8(buf, attr1, sizeof(buf)); | attrcopy_utf8(buf, attr1, sizeof(buf)); | ||||
if (uri_callback == NULL) { | if (uri_callback == NULL) { | ||||
if ((xmlbase != NULL) && (buf[0] != '/')) { | if ((xmlbase != NULL) && (buf[0] != '/')) { | ||||
char fname[256]; | |||||
sprintf(fname, "%s/%s", xmlbase, buf); | sprintf(fname, "%s/%s", xmlbase, buf); | ||||
index = LoadSoundFile2(fname); | index = LoadSoundFile2(fname); | ||||
} else | } else | ||||
} | } | ||||
} else { | } else { | ||||
if ((index = AddNameData(buf, 0)) >= 0) { | if ((index = AddNameData(buf, 0)) >= 0) { | ||||
char *uri; | |||||
uri = &namedata[index]; | uri = &namedata[index]; | ||||
if (uri_callback(1, uri, xmlbase) == 0) { | if (uri_callback(1, uri, xmlbase) == 0) { | ||||
sprintf(buf, "%c%dU", CTRL_EMBEDDED, index); | sprintf(buf, "%c%dU", CTRL_EMBEDDED, index); |
#include "speech.h" // for MAKE_MEM_UNDEFINED | #include "speech.h" // for MAKE_MEM_UNDEFINED | ||||
#include "translateword.h" | #include "translateword.h" | ||||
static int CalcWordLength(int source_index, int charix_top, short int *charix, WORD_TAB *words, int word_count); | |||||
static void CombineFlag(Translator *tr, WORD_TAB *wtab, char *word, int *flags, unsigned char *p, char *word_phonemes); | static void CombineFlag(Translator *tr, WORD_TAB *wtab, char *word, int *flags, unsigned char *p, char *word_phonemes); | ||||
static void SwitchLanguage(char *word, char *word_phonemes); | |||||
Translator *translator = NULL; // the main translator | Translator *translator = NULL; // the main translator | ||||
Translator *translator2 = NULL; // secondary translator for certain words | Translator *translator2 = NULL; // secondary translator for certain words | ||||
{ | { | ||||
char words_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | char words_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | ||||
char *phonemes = words_phonemes; | char *phonemes = words_phonemes; | ||||
int available = N_WORD_PHONEMES; | |||||
bool first_word = true; | |||||
int flags = TranslateWord3(tr, word_start, wtab, word_out, &any_stressed_words, current_alphabet, word_phonemes, sizeof(word_phonemes)); | int flags = TranslateWord3(tr, word_start, wtab, word_out, &any_stressed_words, current_alphabet, word_phonemes, sizeof(word_phonemes)); | ||||
if (flags & FLAG_TEXTMODE && word_out) { | if (flags & FLAG_TEXTMODE && word_out) { | ||||
strcpy(word+2, word_out); | strcpy(word+2, word_out); | ||||
word_out = word+2; | word_out = word+2; | ||||
bool first_word = true; | |||||
int available = N_WORD_PHONEMES; | |||||
while (*word_out && available > 1) { | while (*word_out && available > 1) { | ||||
int c; | int c; | ||||
utf8_in(&c, word_out); | utf8_in(&c, word_out); | ||||
{ | { | ||||
// Process embedded commands for emphasis, sayas, and break | // Process embedded commands for emphasis, sayas, and break | ||||
int embedded_cmd; | int embedded_cmd; | ||||
int value; | |||||
do { | do { | ||||
embedded_cmd = embedded_list[embedded_read++]; | embedded_cmd = embedded_list[embedded_read++]; | ||||
value = embedded_cmd >> 8; | |||||
int value = embedded_cmd >> 8; | |||||
switch (embedded_cmd & 0x1f) | switch (embedded_cmd & 0x1f) | ||||
{ | { | ||||
bool first_phoneme = true; | bool first_phoneme = true; | ||||
int source_ix; | int source_ix; | ||||
int len; | int len; | ||||
int ix; | |||||
const char *new_language; | |||||
int bad_phoneme; | int bad_phoneme; | ||||
int word_flags; | int word_flags; | ||||
int word_copy_len; | |||||
char word_copy[N_WORD_BYTES+1]; | char word_copy[N_WORD_BYTES+1]; | ||||
char word_replaced[N_WORD_BYTES+1]; | char word_replaced[N_WORD_BYTES+1]; | ||||
char old_dictionary_name[40]; | char old_dictionary_name[40]; | ||||
if ((word[0] == 0) || (word_flags & FLAG_DELETE_WORD)) { | if ((word[0] == 0) || (word_flags & FLAG_DELETE_WORD)) { | ||||
// nothing to translate. Add a dummy phoneme to carry any embedded commands | // nothing to translate. Add a dummy phoneme to carry any embedded commands | ||||
if (embedded_flag) { | if (embedded_flag) { | ||||
ph_list2[n_ph_list2].phcode = phonEND_WORD; | |||||
ph_list2[n_ph_list2].stresslevel = 0; | |||||
SetPlist2(&ph_list2[n_ph_list2], phonEND_WORD); | |||||
ph_list2[n_ph_list2].wordstress = 0; | ph_list2[n_ph_list2].wordstress = 0; | ||||
ph_list2[n_ph_list2].tone_ph = 0; | |||||
ph_list2[n_ph_list2].synthflags = embedded_flag; | |||||
ph_list2[n_ph_list2].sourceix = 0; | |||||
n_ph_list2++; | n_ph_list2++; | ||||
embedded_flag = 0; | embedded_flag = 0; | ||||
} | } | ||||
p = (unsigned char *)word_phonemes; | p = (unsigned char *)word_phonemes; | ||||
if (word_flags & FLAG_PHONEMES) { | if (word_flags & FLAG_PHONEMES) { | ||||
// The input is in phoneme mnemonics, not language text | // The input is in phoneme mnemonics, not language text | ||||
int c1; | |||||
char lang_name[12]; | |||||
if (memcmp(word, "_^_", 3) == 0) { | if (memcmp(word, "_^_", 3) == 0) { | ||||
// switch languages | |||||
word += 3; | |||||
for (ix = 0;;) { | |||||
c1 = *word++; | |||||
if ((c1 == ' ') || (c1 == 0)) | |||||
break; | |||||
lang_name[ix++] = tolower(c1); | |||||
} | |||||
lang_name[ix] = 0; | |||||
if ((ix = LookupPhonemeTable(lang_name)) > 0) { | |||||
SelectPhonemeTable(ix); | |||||
word_phonemes[0] = phonSWITCH; | |||||
word_phonemes[1] = ix; | |||||
word_phonemes[2] = 0; | |||||
} | |||||
} else | |||||
SwitchLanguage(word, word_phonemes); | |||||
} else { | |||||
EncodePhonemes(word, word_phonemes, &bad_phoneme); | EncodePhonemes(word, word_phonemes, &bad_phoneme); | ||||
} | |||||
flags = FLAG_FOUND; | flags = FLAG_FOUND; | ||||
} else { | } else { | ||||
int c2; | int c2; | ||||
ix = 0; | |||||
int ix = 0; | |||||
int word_copy_len; | |||||
while (((c2 = word_copy[ix] = word[ix]) != ' ') && (c2 != 0) && (ix < N_WORD_BYTES)) ix++; | while (((c2 = word_copy[ix] = word[ix]) != ' ') && (c2 != 0) && (ix < N_WORD_BYTES)) ix++; | ||||
word_copy_len = ix; | word_copy_len = ix; | ||||
// this word uses a different language | // this word uses a different language | ||||
memcpy(word, word_copy, word_copy_len); | memcpy(word, word_copy, word_copy_len); | ||||
const char *new_language; | |||||
new_language = (char *)(&p[1]); | new_language = (char *)(&p[1]); | ||||
if (new_language[0] == 0) | if (new_language[0] == 0) | ||||
new_language = ESPEAKNG_DEFAULT_VOICE; | new_language = ESPEAKNG_DEFAULT_VOICE; | ||||
// To allow language specific examination and replacement of characters | // To allow language specific examination and replacement of characters | ||||
int code; | int code; | ||||
int initial; | |||||
int medial; | |||||
int final; | |||||
int next2; | int next2; | ||||
static const unsigned char hangul_compatibility[0x34] = { | static const unsigned char hangul_compatibility[0x34] = { | ||||
// check for Korean Hangul letters | // check for Korean Hangul letters | ||||
if (((code = c - 0xac00) >= 0) && (c <= 0xd7af)) { | if (((code = c - 0xac00) >= 0) && (c <= 0xd7af)) { | ||||
// break a syllable hangul into 2 or 3 individual jamo | // break a syllable hangul into 2 or 3 individual jamo | ||||
initial = (code/28)/21; | |||||
medial = (code/28) % 21; | |||||
final = code % 28; | |||||
int initial = (code/28)/21; | |||||
int medial = (code/28) % 21; | |||||
int final = code % 28; | |||||
if (initial == 11) { | if (initial == 11) { | ||||
// null initial | // null initial | ||||
static int UpperCaseInWord(Translator *tr, char *word, int c) | static int UpperCaseInWord(Translator *tr, char *word, int c) | ||||
{ | { | ||||
int ix; | |||||
int len; | |||||
const char *p; | |||||
if (tr->translator_name == L('g', 'a')) { | if (tr->translator_name == L('g', 'a')) { | ||||
// Irish | |||||
int ix; | |||||
const char *p; | |||||
for (ix = 0;; ix++) { | for (ix = 0;; ix++) { | ||||
int len; | |||||
if ((p = UCase_ga[ix]) == NULL) | if ((p = UCase_ga[ix]) == NULL) | ||||
break; | break; | ||||
int c; | int c; | ||||
int cc = 0; | int cc = 0; | ||||
unsigned int source_index = 0; | unsigned int source_index = 0; | ||||
unsigned int prev_source_index = 0; | |||||
int source_index_word = 0; | int source_index_word = 0; | ||||
int prev_in; | int prev_in; | ||||
int prev_out = ' '; | int prev_out = ' '; | ||||
int prev_out2; | |||||
int prev_in_save = 0; | int prev_in_save = 0; | ||||
int next_in; | int next_in; | ||||
int next_in_nbytes; | int next_in_nbytes; | ||||
words[0].start = ix; | words[0].start = ix; | ||||
words[0].flags = 0; | words[0].flags = 0; | ||||
for (j = 0; charix[j] <= 0; j++) ; | |||||
words[0].sourceix = charix[j]; | |||||
k = 0; | |||||
while (charix[j] != 0) { | |||||
// count the number of characters (excluding multibyte continuation bytes) | |||||
if (charix[j++] != -1) | |||||
k++; | |||||
} | |||||
words[0].length = k; | |||||
words[0].length = CalcWordLength(source_index, charix_top, charix, words, 0); | |||||
int prev_out2; | |||||
while (!finished && (ix < (int)sizeof(sbuf) - 1)) { | while (!finished && (ix < (int)sizeof(sbuf) - 1)) { | ||||
prev_out2 = prev_out; | prev_out2 = prev_out; | ||||
utf8_in2(&prev_out, &sbuf[ix-1], 1); | utf8_in2(&prev_out, &sbuf[ix-1], 1); | ||||
} else if (source_index > 0) | } else if (source_index > 0) | ||||
utf8_in2(&prev_in, &source[source_index-1], 1); | utf8_in2(&prev_in, &source[source_index-1], 1); | ||||
prev_source_index = source_index; | |||||
unsigned int prev_source_index = source_index; | |||||
if (char_inserted) { | if (char_inserted) { | ||||
c = char_inserted; | c = char_inserted; | ||||
words[word_count].start = ix; | words[word_count].start = ix; | ||||
words[word_count].flags = 0; | words[word_count].flags = 0; | ||||
for (j = source_index; j < charix_top && charix[j] <= 0; j++) // skip blanks | |||||
; | |||||
words[word_count].sourceix = charix[j]; | |||||
k = 0; | |||||
while (charix[j] != 0) { | |||||
// count the number of characters (excluding multibyte continuation bytes) | |||||
if (charix[j++] != -1) | |||||
k++; | |||||
} | |||||
words[word_count].length = k; | |||||
words[word_count].length = CalcWordLength(source_index, charix_top, charix, words, word_count); | |||||
word_flags = next_word_flags; | word_flags = next_word_flags; | ||||
next_word_flags = 0; | next_word_flags = 0; | ||||
int c_temp; | int c_temp; | ||||
char *pn; | char *pn; | ||||
char *pw; | char *pw; | ||||
int nw; | |||||
char number_buf[150]; | char number_buf[150]; | ||||
WORD_TAB num_wtab[50]; // copy of 'words', when splitting numbers into parts | WORD_TAB num_wtab[50]; // copy of 'words', when splitting numbers into parts | ||||
if (n_digits > 4 && n_digits <= 32) { | if (n_digits > 4 && n_digits <= 32) { | ||||
// word is entirely digits, insert commas and break into 3 digit "words" | // word is entirely digits, insert commas and break into 3 digit "words" | ||||
int nw = 0; | |||||
number_buf[0] = ' '; | number_buf[0] = ' '; | ||||
number_buf[1] = ' '; | number_buf[1] = ' '; | ||||
number_buf[2] = ' '; | number_buf[2] = ' '; | ||||
pn = &number_buf[3]; | pn = &number_buf[3]; | ||||
nx = n_digits; | nx = n_digits; | ||||
nw = 0; | |||||
if ((n_digits > tr->langopts.max_digits) || (word[0] == '0')) | if ((n_digits > tr->langopts.max_digits) || (word[0] == '0')) | ||||
words[ix].flags |= FLAG_INDIVIDUAL_DIGITS; | words[ix].flags |= FLAG_INDIVIDUAL_DIGITS; | ||||
} | } | ||||
} | } | ||||
static int CalcWordLength(int source_index, int charix_top, short int *charix, WORD_TAB *words, int word_count) { | |||||
int j; | |||||
int k; | |||||
for (j = source_index; j < charix_top && charix[j] <= 0; j++); // skip blanks | |||||
words[word_count].sourceix = charix[j]; | |||||
k = 0; | |||||
while (charix[j] != 0) { | |||||
// count the number of characters (excluding multibyte continuation bytes) | |||||
if (charix[j++] != -1) | |||||
k++; | |||||
} | |||||
return k; | |||||
} | |||||
static void CombineFlag(Translator *tr, WORD_TAB *wtab, char *word, int *flags, unsigned char *p, char *word_phonemes) { | static void CombineFlag(Translator *tr, WORD_TAB *wtab, char *word, int *flags, unsigned char *p, char *word_phonemes) { | ||||
// combine a preposition with the following word | // combine a preposition with the following word | ||||
} | } | ||||
} | } | ||||
static void SwitchLanguage(char *word, char *word_phonemes) { | |||||
char lang_name[12]; | |||||
int ix; | |||||
word += 3; | |||||
for (ix = 0;;) { | |||||
int c1; | |||||
c1 = *word++; | |||||
if ((c1 == ' ') || (c1 == 0)) | |||||
break; | |||||
lang_name[ix++] = tolower(c1); | |||||
} | |||||
lang_name[ix] = 0; | |||||
if ((ix = LookupPhonemeTable(lang_name)) > 0) { | |||||
SelectPhonemeTable(ix); | |||||
word_phonemes[0] = phonSWITCH; | |||||
word_phonemes[1] = ix; | |||||
word_phonemes[2] = 0; | |||||
} | |||||
} | |||||
void InitText(int control) | void InitText(int control) | ||||
{ | { | ||||
count_sentences = 0; | count_sentences = 0; | ||||
if ((control & espeakKEEP_NAMEDATA) == 0) | if ((control & espeakKEEP_NAMEDATA) == 0) | ||||
InitNamedata(); | InitNamedata(); | ||||
} | |||||
} |
void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags) | void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags) | ||||
{ | { | ||||
// apply after the translation is complete | // apply after the translation is complete | ||||
int ix; | |||||
int len; | int len; | ||||
char *p; | |||||
len = strlen(phonemes); | len = strlen(phonemes); | ||||
if (tr->langopts.param[LOPT_ALT] & 2) { | if (tr->langopts.param[LOPT_ALT] & 2) { | ||||
for (ix = 0; ix < (len-1); ix++) { | |||||
for (int ix = 0; ix < (len-1); ix++) { | |||||
if (phonemes[ix] == phonSTRESS_P) { | if (phonemes[ix] == phonSTRESS_P) { | ||||
char *p; | |||||
p = &phonemes[ix+1]; | p = &phonemes[ix+1]; | ||||
if ((dict_flags & FLAG_ALT2_TRANS) != 0) { | if ((dict_flags & FLAG_ALT2_TRANS) != 0) { | ||||
if (*p == PhonemeCode('E')) | if (*p == PhonemeCode('E')) | ||||
int n_bytes; | int n_bytes; | ||||
int letter; | int letter; | ||||
int len; | int len; | ||||
int ix; | |||||
int c; | |||||
char *p2; | |||||
char *pbuf; | |||||
const char *modifier; | |||||
ALPHABET *alphabet; | ALPHABET *alphabet; | ||||
int al_offset; | int al_offset; | ||||
int al_flags; | int al_flags; | ||||
int language; | |||||
int number; | int number; | ||||
int phontab_1; | int phontab_1; | ||||
int speak_letter_number; | |||||
char capital[30]; | char capital[30]; | ||||
char ph_buf[80]; | char ph_buf[80]; | ||||
char ph_buf2[80]; | char ph_buf2[80]; | ||||
if (ph_buf[0] == 0) { | if (ph_buf[0] == 0) { | ||||
// is this a subscript or superscript letter ? | // is this a subscript or superscript letter ? | ||||
int c; | |||||
if ((c = IsSuperscript(letter)) != 0) { | if ((c = IsSuperscript(letter)) != 0) { | ||||
letter = c & 0x3fff; | letter = c & 0x3fff; | ||||
const char *modifier; | |||||
if ((control & 4 ) && ((modifier = modifiers[c >> 14]) != NULL)) { | if ((control & 4 ) && ((modifier = modifiers[c >> 14]) != NULL)) { | ||||
// don't say "superscript" during normal text reading | // don't say "superscript" during normal text reading | ||||
Lookup(tr, modifier, capital); | Lookup(tr, modifier, capital); | ||||
// caution: SetWordStress() etc don't expect phonSWITCH + phoneme table number | // caution: SetWordStress() etc don't expect phonSWITCH + phoneme table number | ||||
if (ph_buf[0] == 0) { | if (ph_buf[0] == 0) { | ||||
int language; | |||||
if ((al_offset != 0) && (al_offset == translator->langopts.alt_alphabet)) | if ((al_offset != 0) && (al_offset == translator->langopts.alt_alphabet)) | ||||
language = translator->langopts.alt_alphabet_lang; | language = translator->langopts.alt_alphabet_lang; | ||||
else if ((alphabet != NULL) && (alphabet->language != 0) && !(al_flags & AL_NOT_LETTERS)) | else if ((alphabet != NULL) && (alphabet->language != 0) && !(al_flags & AL_NOT_LETTERS)) | ||||
if ((language != tr->translator_name) || (language == L('k', 'o'))) { | if ((language != tr->translator_name) || (language == L('k', 'o'))) { | ||||
char *p3; | char *p3; | ||||
int initial, code; | |||||
//int initial, code; | |||||
char hangul_buf[12]; | char hangul_buf[12]; | ||||
// speak in the language for this alphabet (or English) | // speak in the language for this alphabet (or English) | ||||
ph_buf[2] = SetTranslator3(WordToString2(language)); | ph_buf[2] = SetTranslator3(WordToString2(language)); | ||||
if (translator3 != NULL) { | if (translator3 != NULL) { | ||||
int code; | |||||
if (((code = letter - 0xac00) >= 0) && (letter <= 0xd7af)) { | if (((code = letter - 0xac00) >= 0) && (letter <= 0xd7af)) { | ||||
// Special case for Korean letters. | // Special case for Korean letters. | ||||
// break a syllable hangul into 2 or 3 individual jamo | // break a syllable hangul into 2 or 3 individual jamo | ||||
hangul_buf[0] = ' '; | hangul_buf[0] = ' '; | ||||
p3 = &hangul_buf[1]; | p3 = &hangul_buf[1]; | ||||
int initial; | |||||
if ((initial = (code/28)/21) != 11) { | if ((initial = (code/28)/21) != 11) { | ||||
p3 += utf8_out(initial + 0x1100, p3); | p3 += utf8_out(initial + 0x1100, p3); | ||||
} | } | ||||
if (ph_buf[0] == 0) { | if (ph_buf[0] == 0) { | ||||
// character name not found | // character name not found | ||||
int speak_letter_number = 1; | |||||
if (!(al_flags & AL_NO_SYMBOL)) { | |||||
if (iswalpha(letter)) | |||||
Lookup(translator, "_?A", ph_buf); | |||||
if (ph_buf[0] == 0) { | |||||
speak_letter_number = 1; | |||||
if (!(al_flags & AL_NO_SYMBOL)) { | |||||
if (iswalpha(letter)) | |||||
Lookup(translator, "_?A", ph_buf); | |||||
if ((ph_buf[0] == 0) && !iswspace(letter)) | |||||
Lookup(translator, "_??", ph_buf); | |||||
if ((ph_buf[0] == 0) && !iswspace(letter)) | |||||
Lookup(translator, "_??", ph_buf); | |||||
if (ph_buf[0] == 0) | |||||
EncodePhonemes("l'et@", ph_buf, NULL); | |||||
} | |||||
if (ph_buf[0] == 0) | |||||
EncodePhonemes("l'et@", ph_buf, NULL); | |||||
} | |||||
if (!(control & 4) && (al_flags & AL_NOT_CODE)) { | |||||
// don't speak the character code number, unless we want full details of this character | |||||
speak_letter_number = 0; | |||||
} | |||||
if (!(control & 4) && (al_flags & AL_NOT_CODE)) { | |||||
// don't speak the character code number, unless we want full details of this character | |||||
speak_letter_number = 0; | |||||
} | |||||
if (speak_letter_number) { | |||||
if (al_offset == 0x2800) { | |||||
// braille dots symbol, list the numbered dots | |||||
p2 = hexbuf; | |||||
for (ix = 0; ix < 8; ix++) { | |||||
if (letter & (1 << ix)) | |||||
*p2++ = '1'+ix; | |||||
} | |||||
*p2 = 0; | |||||
} else { | |||||
// speak the hexadecimal number of the character code | |||||
sprintf(hexbuf, "%x", letter); | |||||
if (speak_letter_number) { | |||||
char *p2; | |||||
if (al_offset == 0x2800) { | |||||
// braille dots symbol, list the numbered dots | |||||
p2 = hexbuf; | |||||
for (int ix = 0; ix < 8; ix++) { | |||||
if (letter & (1 << ix)) | |||||
*p2++ = '1'+ix; | |||||
} | } | ||||
*p2 = 0; | |||||
} else { | |||||
// speak the hexadecimal number of the character code | |||||
sprintf(hexbuf, "%x", letter); | |||||
} | |||||
pbuf = ph_buf; | |||||
for (p2 = hexbuf; *p2 != 0; p2++) { | |||||
pbuf += strlen(pbuf); | |||||
*pbuf++ = phonPAUSE_VSHORT; | |||||
LookupLetter(translator, *p2, 0, pbuf, 1); | |||||
if (((pbuf[0] == 0) || (pbuf[0] == phonSWITCH)) && (*p2 >= 'a')) { | |||||
// This language has no translation for 'a' to 'f', speak English names using base phonemes | |||||
EncodePhonemes(hex_letters[*p2 - 'a'], pbuf, NULL); | |||||
} | |||||
char *pbuf; | |||||
pbuf = ph_buf; | |||||
for (p2 = hexbuf; *p2 != 0; p2++) { | |||||
pbuf += strlen(pbuf); | |||||
*pbuf++ = phonPAUSE_VSHORT; | |||||
LookupLetter(translator, *p2, 0, pbuf, 1); | |||||
if (((pbuf[0] == 0) || (pbuf[0] == phonSWITCH)) && (*p2 >= 'a')) { | |||||
// This language has no translation for 'a' to 'f', speak English names using base phonemes | |||||
EncodePhonemes(hex_letters[*p2 - 'a'], pbuf, NULL); | |||||
} | } | ||||
strcat(pbuf, pause_string); | |||||
} | } | ||||
strcat(pbuf, pause_string); | |||||
} | } | ||||
} | } | ||||
{ | { | ||||
int wc; | int wc; | ||||
int count = 0; | int count = 0; | ||||
int nbytes; | |||||
int ok; | |||||
int ix; | int ix; | ||||
char *word; | char *word; | ||||
char *wbuf; | char *wbuf; | ||||
wbuf = word_buf; | wbuf = word_buf; | ||||
for (;;) { | for (;;) { | ||||
ok = 0; | |||||
nbytes = utf8_in(&wc, word); | |||||
int ok = 0; | |||||
int nbytes = utf8_in(&wc, word); | |||||
if ((word[nbytes] == ' ') && IsAlpha(wc)) { | if ((word[nbytes] == ' ') && IsAlpha(wc)) { | ||||
if (word[nbytes+1] == '.') { | if (word[nbytes+1] == '.') { | ||||
if (word[nbytes+2] == ' ') | if (word[nbytes+2] == ' ') |