346 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/ctype.h>3#include "spk_types.h"4#include "spk_priv.h"5#include "speakup.h"6 7static struct st_var_header var_headers[] = {8 { "version", VERSION, VAR_PROC, NULL, NULL },9 { "synth_name", SYNTH, VAR_PROC, NULL, NULL },10 { "keymap", KEYMAP, VAR_PROC, NULL, NULL },11 { "silent", SILENT, VAR_PROC, NULL, NULL },12 { "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL },13 { "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL },14 { "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL },15 { "delimiters", DELIM, VAR_PROC, NULL, NULL },16 { "repeats", REPEATS, VAR_PROC, NULL, NULL },17 { "ex_num", EXNUMBER, VAR_PROC, NULL, NULL },18 { "characters", CHARS, VAR_PROC, NULL, NULL },19 { "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL },20 { "caps_start", CAPS_START, VAR_STRING, spk_str_caps_start, NULL },21 { "caps_stop", CAPS_STOP, VAR_STRING, spk_str_caps_stop, NULL },22 { "delay_time", DELAY, VAR_TIME, NULL, NULL },23 { "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },24 { "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },25 { "full_time", FULL, VAR_TIME, NULL, NULL },26 { "flush_time", FLUSH, VAR_TIME, NULL, NULL },27 { "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL },28 { "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL },29 { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL },30 { "bleep_time", BLEEP_TIME, VAR_TIME, &spk_bleep_time, NULL },31 { "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL },32 { "punc_level", PUNC_LEVEL, VAR_NUM, &spk_punc_level, NULL },33 { "reading_punc", READING_PUNC, VAR_NUM, &spk_reading_punc, NULL },34 { "say_control", SAY_CONTROL, VAR_NUM, &spk_say_ctrl, NULL },35 { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &spk_say_word_ctl, NULL },36 { "no_interrupt", NO_INTERRUPT, VAR_NUM, &spk_no_intr, NULL },37 { "key_echo", KEY_ECHO, VAR_NUM, &spk_key_echo, NULL },38 { "bell_pos", BELL_POS, VAR_NUM, &spk_bell_pos, NULL },39 { "rate", RATE, VAR_NUM, NULL, NULL },40 { "pitch", PITCH, VAR_NUM, NULL, NULL },41 { "inflection", INFLECTION, VAR_NUM, NULL, NULL },42 { "vol", VOL, VAR_NUM, NULL, NULL },43 { "tone", TONE, VAR_NUM, NULL, NULL },44 { "punct", PUNCT, VAR_NUM, NULL, NULL },45 { "voice", VOICE, VAR_NUM, NULL, NULL },46 { "freq", FREQUENCY, VAR_NUM, NULL, NULL },47 { "lang", LANG, VAR_NUM, NULL, NULL },48 { "chartab", CHARTAB, VAR_PROC, NULL, NULL },49 { "direct", DIRECT, VAR_NUM, NULL, NULL },50 { "pause", PAUSE, VAR_STRING, spk_str_pause, NULL },51 { "cur_phonetic", CUR_PHONETIC, VAR_NUM, &spk_cur_phonetic, NULL },52};53 54static struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL };55 56static struct punc_var_t punc_vars[] = {57 { PUNC_SOME, 1 },58 { PUNC_MOST, 2 },59 { PUNC_ALL, 3 },60 { DELIM, 4 },61 { REPEATS, 5 },62 { EXNUMBER, 6 },63 { -1, -1 },64};65 66int spk_chartab_get_value(char *keyword)67{68 int value = 0;69 70 if (!strcmp(keyword, "ALPHA"))71 value = ALPHA;72 else if (!strcmp(keyword, "B_CTL"))73 value = B_CTL;74 else if (!strcmp(keyword, "WDLM"))75 value = WDLM;76 else if (!strcmp(keyword, "A_PUNC"))77 value = A_PUNC;78 else if (!strcmp(keyword, "PUNC"))79 value = PUNC;80 else if (!strcmp(keyword, "NUM"))81 value = NUM;82 else if (!strcmp(keyword, "A_CAP"))83 value = A_CAP;84 else if (!strcmp(keyword, "B_CAPSYM"))85 value = B_CAPSYM;86 else if (!strcmp(keyword, "B_SYM"))87 value = B_SYM;88 return value;89}90 91void speakup_register_var(struct var_t *var)92{93 static char nothing[2] = "\0";94 int i;95 struct st_var_header *p_header;96 97 BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS);98 if (!var_ptrs[0]) {99 for (i = 0; i < MAXVARS; i++) {100 p_header = &var_headers[i];101 var_ptrs[p_header->var_id] = p_header;102 p_header->data = NULL;103 }104 }105 p_header = var_ptrs[var->var_id];106 if (p_header->data)107 return;108 p_header->data = var;109 switch (p_header->var_type) {110 case VAR_STRING:111 spk_set_string_var(nothing, p_header, 0);112 break;113 case VAR_NUM:114 case VAR_TIME:115 spk_set_num_var(0, p_header, E_DEFAULT);116 break;117 default:118 break;119 }120}121 122void speakup_unregister_var(enum var_id_t var_id)123{124 struct st_var_header *p_header;125 126 BUG_ON(var_id < 0 || var_id >= MAXVARS);127 p_header = var_ptrs[var_id];128 p_header->data = NULL;129}130 131struct st_var_header *spk_get_var_header(enum var_id_t var_id)132{133 struct st_var_header *p_header;134 135 if (var_id < 0 || var_id >= MAXVARS)136 return NULL;137 p_header = var_ptrs[var_id];138 if (!p_header->data)139 return NULL;140 return p_header;141}142EXPORT_SYMBOL_GPL(spk_get_var_header);143 144struct st_var_header *spk_var_header_by_name(const char *name)145{146 int i;147 148 if (!name)149 return NULL;150 151 for (i = 0; i < MAXVARS; i++) {152 if (strcmp(name, var_ptrs[i]->name) == 0)153 return var_ptrs[i];154 }155 return NULL;156}157 158struct var_t *spk_get_var(enum var_id_t var_id)159{160 BUG_ON(var_id < 0 || var_id >= MAXVARS);161 BUG_ON(!var_ptrs[var_id]);162 return var_ptrs[var_id]->data;163}164EXPORT_SYMBOL_GPL(spk_get_var);165 166struct punc_var_t *spk_get_punc_var(enum var_id_t var_id)167{168 struct punc_var_t *rv = NULL;169 struct punc_var_t *where;170 171 where = punc_vars;172 while ((where->var_id != -1) && (!rv)) {173 if (where->var_id == var_id)174 rv = where;175 else176 where++;177 }178 return rv;179}180 181/* handlers for setting vars */182int spk_set_num_var(int input, struct st_var_header *var, int how)183{184 int val;185 int *p_val = var->p_val;186 char buf[32];187 char *cp;188 struct var_t *var_data = var->data;189 190 if (!var_data)191 return -ENODATA;192 193 val = var_data->u.n.value;194 switch (how) {195 case E_NEW_DEFAULT:196 if (input < var_data->u.n.low || input > var_data->u.n.high)197 return -ERANGE;198 var_data->u.n.default_val = input;199 return 0;200 case E_DEFAULT:201 val = var_data->u.n.default_val;202 break;203 case E_SET:204 val = input;205 break;206 case E_INC:207 val += input;208 break;209 case E_DEC:210 val -= input;211 break;212 }213 214 if (val < var_data->u.n.low || val > var_data->u.n.high)215 return -ERANGE;216 217 var_data->u.n.value = val;218 if (var->var_type == VAR_TIME && p_val) {219 *p_val = msecs_to_jiffies(val);220 return 0;221 }222 if (p_val)223 *p_val = val;224 if (var->var_id == PUNC_LEVEL) {225 spk_punc_mask = spk_punc_masks[val];226 }227 if (var_data->u.n.multiplier != 0)228 val *= var_data->u.n.multiplier;229 val += var_data->u.n.offset;230 231 if (!synth)232 return 0;233 if (synth->synth_adjust && synth->synth_adjust(synth, var))234 return 0;235 if (var->var_id < FIRST_SYNTH_VAR)236 return 0;237 238 if (!var_data->u.n.synth_fmt)239 return 0;240 if (var->var_id == PITCH)241 cp = spk_pitch_buff;242 else243 cp = buf;244 if (!var_data->u.n.out_str)245 sprintf(cp, var_data->u.n.synth_fmt, (int)val);246 else247 sprintf(cp, var_data->u.n.synth_fmt,248 var_data->u.n.out_str[val]);249 synth_printf("%s", cp);250 return 0;251}252EXPORT_SYMBOL_GPL(spk_set_num_var);253 254int spk_set_string_var(const char *page, struct st_var_header *var, int len)255{256 struct var_t *var_data = var->data;257 258 if (!var_data)259 return -ENODATA;260 if (len > MAXVARLEN)261 return -E2BIG;262 if (!len) {263 if (!var_data->u.s.default_val)264 return 0;265 if (!var->p_val)266 var->p_val = var_data->u.s.default_val;267 if (var->p_val != var_data->u.s.default_val)268 strcpy((char *)var->p_val, var_data->u.s.default_val);269 return -ERESTART;270 } else if (var->p_val) {271 strcpy((char *)var->p_val, page);272 } else {273 return -E2BIG;274 }275 return 0;276}277 278/*279 * spk_set_mask_bits sets or clears the punc/delim/repeat bits,280 * if input is null uses the defaults.281 * values for how: 0 clears bits of chars supplied,282 * 1 clears allk, 2 sets bits for chars283 */284int spk_set_mask_bits(const char *input, const int which, const int how)285{286 u_char *cp;287 short mask = spk_punc_info[which].mask;288 289 if (how & 1) {290 for (cp = (u_char *)spk_punc_info[3].value; *cp; cp++)291 spk_chartab[*cp] &= ~mask;292 }293 cp = (u_char *)input;294 if (!cp) {295 cp = spk_punc_info[which].value;296 } else {297 for (; *cp; cp++) {298 if (*cp < SPACE)299 break;300 if (mask < PUNC) {301 if (!(spk_chartab[*cp] & PUNC))302 break;303 } else if (spk_chartab[*cp] & B_NUM) {304 break;305 }306 }307 if (*cp)308 return -EINVAL;309 cp = (u_char *)input;310 }311 if (how & 2) {312 for (; *cp; cp++)313 if (*cp > SPACE)314 spk_chartab[*cp] |= mask;315 } else {316 for (; *cp; cp++)317 if (*cp > SPACE)318 spk_chartab[*cp] &= ~mask;319 }320 return 0;321}322 323char *spk_strlwr(char *s)324{325 char *p;326 327 if (!s)328 return NULL;329 330 for (p = s; *p; p++)331 *p = tolower(*p);332 return s;333}334 335char *spk_s2uchar(char *start, char *dest)336{337 int val;338 339 /* Do not replace with kstrtoul: here we need start to be updated */340 val = simple_strtoul(skip_spaces(start), &start, 10);341 if (*start == ',')342 start++;343 *dest = (u_char)val;344 return start;345}346