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