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