Path: blob/master/drivers/accessibility/speakup/varhandlers.c
26282 views
// SPDX-License-Identifier: GPL-2.01#include <linux/ctype.h>2#include "spk_types.h"3#include "spk_priv.h"4#include "speakup.h"56static struct st_var_header var_headers[] = {7{ "version", VERSION, VAR_PROC, NULL, NULL },8{ "synth_name", SYNTH, VAR_PROC, NULL, NULL },9{ "keymap", KEYMAP, VAR_PROC, NULL, NULL },10{ "silent", SILENT, VAR_PROC, NULL, NULL },11{ "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL },12{ "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL },13{ "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL },14{ "delimiters", DELIM, VAR_PROC, NULL, NULL },15{ "repeats", REPEATS, VAR_PROC, NULL, NULL },16{ "ex_num", EXNUMBER, VAR_PROC, NULL, NULL },17{ "characters", CHARS, VAR_PROC, NULL, NULL },18{ "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL },19{ "caps_start", CAPS_START, VAR_STRING, spk_str_caps_start, NULL },20{ "caps_stop", CAPS_STOP, VAR_STRING, spk_str_caps_stop, NULL },21{ "delay_time", DELAY, VAR_TIME, NULL, NULL },22{ "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },23{ "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },24{ "full_time", FULL, VAR_TIME, NULL, NULL },25{ "flush_time", FLUSH, 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{ "cur_phonetic", CUR_PHONETIC, VAR_NUM, &spk_cur_phonetic, NULL },51};5253static struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL };5455static struct punc_var_t punc_vars[] = {56{ PUNC_SOME, 1 },57{ PUNC_MOST, 2 },58{ PUNC_ALL, 3 },59{ DELIM, 4 },60{ REPEATS, 5 },61{ EXNUMBER, 6 },62{ -1, -1 },63};6465int spk_chartab_get_value(char *keyword)66{67int value = 0;6869if (!strcmp(keyword, "ALPHA"))70value = ALPHA;71else if (!strcmp(keyword, "B_CTL"))72value = B_CTL;73else if (!strcmp(keyword, "WDLM"))74value = WDLM;75else if (!strcmp(keyword, "A_PUNC"))76value = A_PUNC;77else if (!strcmp(keyword, "PUNC"))78value = PUNC;79else if (!strcmp(keyword, "NUM"))80value = NUM;81else if (!strcmp(keyword, "A_CAP"))82value = A_CAP;83else if (!strcmp(keyword, "B_CAPSYM"))84value = B_CAPSYM;85else if (!strcmp(keyword, "B_SYM"))86value = B_SYM;87return value;88}8990void speakup_register_var(struct var_t *var)91{92static char nothing[2] = "\0";93int i;94struct st_var_header *p_header;9596BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS);97if (!var_ptrs[0]) {98for (i = 0; i < MAXVARS; i++) {99p_header = &var_headers[i];100var_ptrs[p_header->var_id] = p_header;101p_header->data = NULL;102}103}104p_header = var_ptrs[var->var_id];105if (p_header->data)106return;107p_header->data = var;108switch (p_header->var_type) {109case VAR_STRING:110spk_set_string_var(nothing, p_header, 0);111break;112case VAR_NUM:113case VAR_TIME:114spk_set_num_var(0, p_header, E_DEFAULT);115break;116default:117break;118}119}120121void speakup_unregister_var(enum var_id_t var_id)122{123struct st_var_header *p_header;124125BUG_ON(var_id < 0 || var_id >= MAXVARS);126p_header = var_ptrs[var_id];127p_header->data = NULL;128}129130struct st_var_header *spk_get_var_header(enum var_id_t var_id)131{132struct st_var_header *p_header;133134if (var_id < 0 || var_id >= MAXVARS)135return NULL;136p_header = var_ptrs[var_id];137if (!p_header->data)138return NULL;139return p_header;140}141EXPORT_SYMBOL_GPL(spk_get_var_header);142143struct st_var_header *spk_var_header_by_name(const char *name)144{145int i;146147if (!name)148return NULL;149150for (i = 0; i < MAXVARS; i++) {151if (strcmp(name, var_ptrs[i]->name) == 0)152return var_ptrs[i];153}154return NULL;155}156157struct var_t *spk_get_var(enum var_id_t var_id)158{159BUG_ON(var_id < 0 || var_id >= MAXVARS);160BUG_ON(!var_ptrs[var_id]);161return var_ptrs[var_id]->data;162}163EXPORT_SYMBOL_GPL(spk_get_var);164165struct punc_var_t *spk_get_punc_var(enum var_id_t var_id)166{167struct punc_var_t *rv = NULL;168struct punc_var_t *where;169170where = punc_vars;171while ((where->var_id != -1) && (!rv)) {172if (where->var_id == var_id)173rv = where;174else175where++;176}177return rv;178}179180/* handlers for setting vars */181int spk_set_num_var(int input, struct st_var_header *var, int how)182{183int val;184int *p_val = var->p_val;185char buf[32];186char *cp;187struct var_t *var_data = var->data;188189if (!var_data)190return -ENODATA;191192val = var_data->u.n.value;193switch (how) {194case E_NEW_DEFAULT:195if (input < var_data->u.n.low || input > var_data->u.n.high)196return -ERANGE;197var_data->u.n.default_val = input;198return 0;199case E_DEFAULT:200val = var_data->u.n.default_val;201break;202case E_SET:203val = input;204break;205case E_INC:206val += input;207break;208case E_DEC:209val -= input;210break;211}212213if (val < var_data->u.n.low || val > var_data->u.n.high)214return -ERANGE;215216var_data->u.n.value = val;217if (var->var_type == VAR_TIME && p_val) {218*p_val = msecs_to_jiffies(val);219return 0;220}221if (p_val)222*p_val = val;223if (var->var_id == PUNC_LEVEL) {224spk_punc_mask = spk_punc_masks[val];225}226if (var_data->u.n.multiplier != 0)227val *= var_data->u.n.multiplier;228val += var_data->u.n.offset;229230if (!synth)231return 0;232if (synth->synth_adjust && synth->synth_adjust(synth, var))233return 0;234if (var->var_id < FIRST_SYNTH_VAR)235return 0;236237if (!var_data->u.n.synth_fmt)238return 0;239if (var->var_id == PITCH)240cp = spk_pitch_buff;241else242cp = buf;243if (!var_data->u.n.out_str)244sprintf(cp, var_data->u.n.synth_fmt, (int)val);245else246sprintf(cp, var_data->u.n.synth_fmt,247var_data->u.n.out_str[val]);248synth_printf("%s", cp);249return 0;250}251EXPORT_SYMBOL_GPL(spk_set_num_var);252253int spk_set_string_var(const char *page, struct st_var_header *var, int len)254{255struct var_t *var_data = var->data;256257if (!var_data)258return -ENODATA;259if (len > MAXVARLEN)260return -E2BIG;261if (!len) {262if (!var_data->u.s.default_val)263return 0;264if (!var->p_val)265var->p_val = var_data->u.s.default_val;266if (var->p_val != var_data->u.s.default_val)267strcpy((char *)var->p_val, var_data->u.s.default_val);268return -ERESTART;269} else if (var->p_val) {270strcpy((char *)var->p_val, page);271} else {272return -E2BIG;273}274return 0;275}276277/*278* spk_set_mask_bits sets or clears the punc/delim/repeat bits,279* if input is null uses the defaults.280* values for how: 0 clears bits of chars supplied,281* 1 clears allk, 2 sets bits for chars282*/283int spk_set_mask_bits(const char *input, const int which, const int how)284{285u_char *cp;286short mask = spk_punc_info[which].mask;287288if (how & 1) {289for (cp = (u_char *)spk_punc_info[3].value; *cp; cp++)290spk_chartab[*cp] &= ~mask;291}292cp = (u_char *)input;293if (!cp) {294cp = spk_punc_info[which].value;295} else {296for (; *cp; cp++) {297if (*cp < SPACE)298break;299if (mask < PUNC) {300if (!(spk_chartab[*cp] & PUNC))301break;302} else if (spk_chartab[*cp] & B_NUM) {303break;304}305}306if (*cp)307return -EINVAL;308cp = (u_char *)input;309}310if (how & 2) {311for (; *cp; cp++)312if (*cp > SPACE)313spk_chartab[*cp] |= mask;314} else {315for (; *cp; cp++)316if (*cp > SPACE)317spk_chartab[*cp] &= ~mask;318}319return 0;320}321322char *spk_strlwr(char *s)323{324char *p;325326if (!s)327return NULL;328329for (p = s; *p; p++)330*p = tolower(*p);331return s;332}333334char *spk_s2uchar(char *start, char *dest)335{336int val;337338/* Do not replace with kstrtoul: here we need start to be updated */339val = simple_strtoul(skip_spaces(start), &start, 10);340if (*start == ',')341start++;342*dest = (u_char)val;343return start;344}345346347