162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/ctype.h> 362306a36Sopenharmony_ci#include "spk_types.h" 462306a36Sopenharmony_ci#include "spk_priv.h" 562306a36Sopenharmony_ci#include "speakup.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistatic struct st_var_header var_headers[] = { 862306a36Sopenharmony_ci { "version", VERSION, VAR_PROC, NULL, NULL }, 962306a36Sopenharmony_ci { "synth_name", SYNTH, VAR_PROC, NULL, NULL }, 1062306a36Sopenharmony_ci { "keymap", KEYMAP, VAR_PROC, NULL, NULL }, 1162306a36Sopenharmony_ci { "silent", SILENT, VAR_PROC, NULL, NULL }, 1262306a36Sopenharmony_ci { "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL }, 1362306a36Sopenharmony_ci { "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL }, 1462306a36Sopenharmony_ci { "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL }, 1562306a36Sopenharmony_ci { "delimiters", DELIM, VAR_PROC, NULL, NULL }, 1662306a36Sopenharmony_ci { "repeats", REPEATS, VAR_PROC, NULL, NULL }, 1762306a36Sopenharmony_ci { "ex_num", EXNUMBER, VAR_PROC, NULL, NULL }, 1862306a36Sopenharmony_ci { "characters", CHARS, VAR_PROC, NULL, NULL }, 1962306a36Sopenharmony_ci { "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL }, 2062306a36Sopenharmony_ci { "caps_start", CAPS_START, VAR_STRING, spk_str_caps_start, NULL }, 2162306a36Sopenharmony_ci { "caps_stop", CAPS_STOP, VAR_STRING, spk_str_caps_stop, NULL }, 2262306a36Sopenharmony_ci { "delay_time", DELAY, VAR_TIME, NULL, NULL }, 2362306a36Sopenharmony_ci { "trigger_time", TRIGGER, VAR_TIME, NULL, NULL }, 2462306a36Sopenharmony_ci { "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL }, 2562306a36Sopenharmony_ci { "full_time", FULL, VAR_TIME, NULL, NULL }, 2662306a36Sopenharmony_ci { "flush_time", FLUSH, VAR_TIME, NULL, NULL }, 2762306a36Sopenharmony_ci { "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL }, 2862306a36Sopenharmony_ci { "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL }, 2962306a36Sopenharmony_ci { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL }, 3062306a36Sopenharmony_ci { "bleep_time", BLEEP_TIME, VAR_TIME, &spk_bleep_time, NULL }, 3162306a36Sopenharmony_ci { "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL }, 3262306a36Sopenharmony_ci { "punc_level", PUNC_LEVEL, VAR_NUM, &spk_punc_level, NULL }, 3362306a36Sopenharmony_ci { "reading_punc", READING_PUNC, VAR_NUM, &spk_reading_punc, NULL }, 3462306a36Sopenharmony_ci { "say_control", SAY_CONTROL, VAR_NUM, &spk_say_ctrl, NULL }, 3562306a36Sopenharmony_ci { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &spk_say_word_ctl, NULL }, 3662306a36Sopenharmony_ci { "no_interrupt", NO_INTERRUPT, VAR_NUM, &spk_no_intr, NULL }, 3762306a36Sopenharmony_ci { "key_echo", KEY_ECHO, VAR_NUM, &spk_key_echo, NULL }, 3862306a36Sopenharmony_ci { "bell_pos", BELL_POS, VAR_NUM, &spk_bell_pos, NULL }, 3962306a36Sopenharmony_ci { "rate", RATE, VAR_NUM, NULL, NULL }, 4062306a36Sopenharmony_ci { "pitch", PITCH, VAR_NUM, NULL, NULL }, 4162306a36Sopenharmony_ci { "inflection", INFLECTION, VAR_NUM, NULL, NULL }, 4262306a36Sopenharmony_ci { "vol", VOL, VAR_NUM, NULL, NULL }, 4362306a36Sopenharmony_ci { "tone", TONE, VAR_NUM, NULL, NULL }, 4462306a36Sopenharmony_ci { "punct", PUNCT, VAR_NUM, NULL, NULL }, 4562306a36Sopenharmony_ci { "voice", VOICE, VAR_NUM, NULL, NULL }, 4662306a36Sopenharmony_ci { "freq", FREQUENCY, VAR_NUM, NULL, NULL }, 4762306a36Sopenharmony_ci { "lang", LANG, VAR_NUM, NULL, NULL }, 4862306a36Sopenharmony_ci { "chartab", CHARTAB, VAR_PROC, NULL, NULL }, 4962306a36Sopenharmony_ci { "direct", DIRECT, VAR_NUM, NULL, NULL }, 5062306a36Sopenharmony_ci { "pause", PAUSE, VAR_STRING, spk_str_pause, NULL }, 5162306a36Sopenharmony_ci { "cur_phonetic", CUR_PHONETIC, VAR_NUM, &spk_cur_phonetic, NULL }, 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL }; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic struct punc_var_t punc_vars[] = { 5762306a36Sopenharmony_ci { PUNC_SOME, 1 }, 5862306a36Sopenharmony_ci { PUNC_MOST, 2 }, 5962306a36Sopenharmony_ci { PUNC_ALL, 3 }, 6062306a36Sopenharmony_ci { DELIM, 4 }, 6162306a36Sopenharmony_ci { REPEATS, 5 }, 6262306a36Sopenharmony_ci { EXNUMBER, 6 }, 6362306a36Sopenharmony_ci { -1, -1 }, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciint spk_chartab_get_value(char *keyword) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int value = 0; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (!strcmp(keyword, "ALPHA")) 7162306a36Sopenharmony_ci value = ALPHA; 7262306a36Sopenharmony_ci else if (!strcmp(keyword, "B_CTL")) 7362306a36Sopenharmony_ci value = B_CTL; 7462306a36Sopenharmony_ci else if (!strcmp(keyword, "WDLM")) 7562306a36Sopenharmony_ci value = WDLM; 7662306a36Sopenharmony_ci else if (!strcmp(keyword, "A_PUNC")) 7762306a36Sopenharmony_ci value = A_PUNC; 7862306a36Sopenharmony_ci else if (!strcmp(keyword, "PUNC")) 7962306a36Sopenharmony_ci value = PUNC; 8062306a36Sopenharmony_ci else if (!strcmp(keyword, "NUM")) 8162306a36Sopenharmony_ci value = NUM; 8262306a36Sopenharmony_ci else if (!strcmp(keyword, "A_CAP")) 8362306a36Sopenharmony_ci value = A_CAP; 8462306a36Sopenharmony_ci else if (!strcmp(keyword, "B_CAPSYM")) 8562306a36Sopenharmony_ci value = B_CAPSYM; 8662306a36Sopenharmony_ci else if (!strcmp(keyword, "B_SYM")) 8762306a36Sopenharmony_ci value = B_SYM; 8862306a36Sopenharmony_ci return value; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_civoid speakup_register_var(struct var_t *var) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci static char nothing[2] = "\0"; 9462306a36Sopenharmony_ci int i; 9562306a36Sopenharmony_ci struct st_var_header *p_header; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS); 9862306a36Sopenharmony_ci if (!var_ptrs[0]) { 9962306a36Sopenharmony_ci for (i = 0; i < MAXVARS; i++) { 10062306a36Sopenharmony_ci p_header = &var_headers[i]; 10162306a36Sopenharmony_ci var_ptrs[p_header->var_id] = p_header; 10262306a36Sopenharmony_ci p_header->data = NULL; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci p_header = var_ptrs[var->var_id]; 10662306a36Sopenharmony_ci if (p_header->data) 10762306a36Sopenharmony_ci return; 10862306a36Sopenharmony_ci p_header->data = var; 10962306a36Sopenharmony_ci switch (p_header->var_type) { 11062306a36Sopenharmony_ci case VAR_STRING: 11162306a36Sopenharmony_ci spk_set_string_var(nothing, p_header, 0); 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case VAR_NUM: 11462306a36Sopenharmony_ci case VAR_TIME: 11562306a36Sopenharmony_ci spk_set_num_var(0, p_header, E_DEFAULT); 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci default: 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_civoid speakup_unregister_var(enum var_id_t var_id) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct st_var_header *p_header; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci BUG_ON(var_id < 0 || var_id >= MAXVARS); 12762306a36Sopenharmony_ci p_header = var_ptrs[var_id]; 12862306a36Sopenharmony_ci p_header->data = NULL; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct st_var_header *spk_get_var_header(enum var_id_t var_id) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct st_var_header *p_header; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (var_id < 0 || var_id >= MAXVARS) 13662306a36Sopenharmony_ci return NULL; 13762306a36Sopenharmony_ci p_header = var_ptrs[var_id]; 13862306a36Sopenharmony_ci if (!p_header->data) 13962306a36Sopenharmony_ci return NULL; 14062306a36Sopenharmony_ci return p_header; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(spk_get_var_header); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct st_var_header *spk_var_header_by_name(const char *name) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci int i; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!name) 14962306a36Sopenharmony_ci return NULL; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci for (i = 0; i < MAXVARS; i++) { 15262306a36Sopenharmony_ci if (strcmp(name, var_ptrs[i]->name) == 0) 15362306a36Sopenharmony_ci return var_ptrs[i]; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci return NULL; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistruct var_t *spk_get_var(enum var_id_t var_id) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci BUG_ON(var_id < 0 || var_id >= MAXVARS); 16162306a36Sopenharmony_ci BUG_ON(!var_ptrs[var_id]); 16262306a36Sopenharmony_ci return var_ptrs[var_id]->data; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(spk_get_var); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistruct punc_var_t *spk_get_punc_var(enum var_id_t var_id) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct punc_var_t *rv = NULL; 16962306a36Sopenharmony_ci struct punc_var_t *where; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci where = punc_vars; 17262306a36Sopenharmony_ci while ((where->var_id != -1) && (!rv)) { 17362306a36Sopenharmony_ci if (where->var_id == var_id) 17462306a36Sopenharmony_ci rv = where; 17562306a36Sopenharmony_ci else 17662306a36Sopenharmony_ci where++; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci return rv; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* handlers for setting vars */ 18262306a36Sopenharmony_ciint spk_set_num_var(int input, struct st_var_header *var, int how) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int val; 18562306a36Sopenharmony_ci int *p_val = var->p_val; 18662306a36Sopenharmony_ci char buf[32]; 18762306a36Sopenharmony_ci char *cp; 18862306a36Sopenharmony_ci struct var_t *var_data = var->data; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (!var_data) 19162306a36Sopenharmony_ci return -ENODATA; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci val = var_data->u.n.value; 19462306a36Sopenharmony_ci switch (how) { 19562306a36Sopenharmony_ci case E_NEW_DEFAULT: 19662306a36Sopenharmony_ci if (input < var_data->u.n.low || input > var_data->u.n.high) 19762306a36Sopenharmony_ci return -ERANGE; 19862306a36Sopenharmony_ci var_data->u.n.default_val = input; 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci case E_DEFAULT: 20162306a36Sopenharmony_ci val = var_data->u.n.default_val; 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case E_SET: 20462306a36Sopenharmony_ci val = input; 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case E_INC: 20762306a36Sopenharmony_ci val += input; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case E_DEC: 21062306a36Sopenharmony_ci val -= input; 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (val < var_data->u.n.low || val > var_data->u.n.high) 21562306a36Sopenharmony_ci return -ERANGE; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci var_data->u.n.value = val; 21862306a36Sopenharmony_ci if (var->var_type == VAR_TIME && p_val) { 21962306a36Sopenharmony_ci *p_val = msecs_to_jiffies(val); 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci if (p_val) 22362306a36Sopenharmony_ci *p_val = val; 22462306a36Sopenharmony_ci if (var->var_id == PUNC_LEVEL) { 22562306a36Sopenharmony_ci spk_punc_mask = spk_punc_masks[val]; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci if (var_data->u.n.multiplier != 0) 22862306a36Sopenharmony_ci val *= var_data->u.n.multiplier; 22962306a36Sopenharmony_ci val += var_data->u.n.offset; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!synth) 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci if (synth->synth_adjust && synth->synth_adjust(synth, var)) 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci if (var->var_id < FIRST_SYNTH_VAR) 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (!var_data->u.n.synth_fmt) 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci if (var->var_id == PITCH) 24162306a36Sopenharmony_ci cp = spk_pitch_buff; 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci cp = buf; 24462306a36Sopenharmony_ci if (!var_data->u.n.out_str) 24562306a36Sopenharmony_ci sprintf(cp, var_data->u.n.synth_fmt, (int)val); 24662306a36Sopenharmony_ci else 24762306a36Sopenharmony_ci sprintf(cp, var_data->u.n.synth_fmt, 24862306a36Sopenharmony_ci var_data->u.n.out_str[val]); 24962306a36Sopenharmony_ci synth_printf("%s", cp); 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(spk_set_num_var); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ciint spk_set_string_var(const char *page, struct st_var_header *var, int len) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct var_t *var_data = var->data; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!var_data) 25962306a36Sopenharmony_ci return -ENODATA; 26062306a36Sopenharmony_ci if (len > MAXVARLEN) 26162306a36Sopenharmony_ci return -E2BIG; 26262306a36Sopenharmony_ci if (!len) { 26362306a36Sopenharmony_ci if (!var_data->u.s.default_val) 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci if (!var->p_val) 26662306a36Sopenharmony_ci var->p_val = var_data->u.s.default_val; 26762306a36Sopenharmony_ci if (var->p_val != var_data->u.s.default_val) 26862306a36Sopenharmony_ci strcpy((char *)var->p_val, var_data->u.s.default_val); 26962306a36Sopenharmony_ci return -ERESTART; 27062306a36Sopenharmony_ci } else if (var->p_val) { 27162306a36Sopenharmony_ci strcpy((char *)var->p_val, page); 27262306a36Sopenharmony_ci } else { 27362306a36Sopenharmony_ci return -E2BIG; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * spk_set_mask_bits sets or clears the punc/delim/repeat bits, 28062306a36Sopenharmony_ci * if input is null uses the defaults. 28162306a36Sopenharmony_ci * values for how: 0 clears bits of chars supplied, 28262306a36Sopenharmony_ci * 1 clears allk, 2 sets bits for chars 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ciint spk_set_mask_bits(const char *input, const int which, const int how) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci u_char *cp; 28762306a36Sopenharmony_ci short mask = spk_punc_info[which].mask; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (how & 1) { 29062306a36Sopenharmony_ci for (cp = (u_char *)spk_punc_info[3].value; *cp; cp++) 29162306a36Sopenharmony_ci spk_chartab[*cp] &= ~mask; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci cp = (u_char *)input; 29462306a36Sopenharmony_ci if (!cp) { 29562306a36Sopenharmony_ci cp = spk_punc_info[which].value; 29662306a36Sopenharmony_ci } else { 29762306a36Sopenharmony_ci for (; *cp; cp++) { 29862306a36Sopenharmony_ci if (*cp < SPACE) 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci if (mask < PUNC) { 30162306a36Sopenharmony_ci if (!(spk_chartab[*cp] & PUNC)) 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci } else if (spk_chartab[*cp] & B_NUM) { 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci if (*cp) 30862306a36Sopenharmony_ci return -EINVAL; 30962306a36Sopenharmony_ci cp = (u_char *)input; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci if (how & 2) { 31262306a36Sopenharmony_ci for (; *cp; cp++) 31362306a36Sopenharmony_ci if (*cp > SPACE) 31462306a36Sopenharmony_ci spk_chartab[*cp] |= mask; 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci for (; *cp; cp++) 31762306a36Sopenharmony_ci if (*cp > SPACE) 31862306a36Sopenharmony_ci spk_chartab[*cp] &= ~mask; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cichar *spk_strlwr(char *s) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci char *p; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (!s) 32862306a36Sopenharmony_ci return NULL; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci for (p = s; *p; p++) 33162306a36Sopenharmony_ci *p = tolower(*p); 33262306a36Sopenharmony_ci return s; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cichar *spk_s2uchar(char *start, char *dest) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int val; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Do not replace with kstrtoul: here we need start to be updated */ 34062306a36Sopenharmony_ci val = simple_strtoul(skip_spaces(start), &start, 10); 34162306a36Sopenharmony_ci if (*start == ',') 34262306a36Sopenharmony_ci start++; 34362306a36Sopenharmony_ci *dest = (u_char)val; 34462306a36Sopenharmony_ci return start; 34562306a36Sopenharmony_ci} 346