1 /*
2  * YASR ("Yet Another Screen Reader") is an attempt at a lightweight,
3  * portable screen reader.
4  *
5  * Copyright (C) 2001-2003 by Michael P. Gorse. All rights reserved.
6  *
7  * YASR comes with ABSOLUTELY NO WARRANTY.
8  *
9  * This is free software, placed under the terms of the
10  * GNU Lesser General Public License, as published by the Free Software
11  * Foundation.  Please see the file COPYING for details.
12  *
13  * Web Page: http://yasr.sf.net
14  *
15  * This software is maintained by:
16  * Michael P. Gorse <mgorse@users.sourceforge.net>
17  */
18 
19 #include "yasr.h"
20 
21 /* Constants and flags for use in setting the type of an option */
22 
23 typedef struct
24 {
25   int len;
26   int lastlen;
27   int opt[10];
28   int saychar;
29   union
30   {
31     int val;
32     double val_float;
33   } v[10];
34 } Optqueue;
35 
36 static Optqueue opq;
37 
38 
options_are_equal(int i,int j)39 static int options_are_equal(int i, int j)
40 {
41   if (i == j)
42   {
43     return (1);
44   }
45 
46   /* Speakout's punctuation options are set using the same setting */
47   if ((i >= 14 && i <= 17) && (j >= 14 && j <= 17))
48   {
49     return (1);
50   }
51 
52   return (0);
53 }
54 
opt_queue_add(int num,...)55 static void opt_queue_add(int num, ...)
56 {
57   int i;
58   va_list args;
59 
60   va_start(args, num);
61   for (i = 0; i < opq.len; i++)
62   {
63     if (options_are_equal(i, num)) break;
64   }
65   if (i == 10)
66   {
67     /* tbc - give some kind of warning */
68   }
69   else
70   {
71     opq.opt[i] = num;
72     if ((opt[num].type & 0x3f) == OT_FLOAT)
73     {
74       opq.v[i].val_float = va_arg(args, double);
75     }
76     else opq.v[i].val = va_arg(args, int);
77     if (i == opq.len) opq.len++;
78     (void) alarm(1);
79   }
80   va_end(args);
81 }
82 
83 
84 Opt opt[NUMOPTS];
85 static int curopt;
86 int synthopt;
87 
88 
opt_add(void * ptr,int tree,char * name,int type,...)89 void opt_add(void *ptr, int tree, char *name, int type, ...)
90 {
91   Opt *optr;
92   va_list args;
93   int i;
94 
95   if (!strcasecmp(name, "synthesizer"))
96     synthopt = curopt;
97   optr = &opt[curopt];
98   optr->ptr = ptr;
99   optr->tree = tree;
100   optr->internal_name = name;
101   optr->localized_name = _(name);
102   optr->type = type;
103   va_start(args, type);
104   switch (type & 0x3f)
105   {
106   case OT_INT:			/* Numeric value.  Expects a min and a max. */
107     optr->v.val_int.min = va_arg(args, int);
108     optr->v.val_int.max = va_arg(args, int);
109     break;
110   case OT_FLOAT:			/* Numeric value.  Expects a min and a max. */
111     optr->v.val_float.min = va_arg(args, double);
112     optr->v.val_float.max = va_arg(args, double);
113     break;
114 
115   case OT_ENUM:		/* Toggle between several values. Expects the
116 				 * number of values followed by a name for each.
117 				 */
118     optr->v.enum_max = va_arg(args, int) - 1;
119     optr->arg = malloc((optr->v.enum_max + 1) * sizeof(char *));
120     for (i = 0; i <= optr->v.enum_max; i++)
121     {
122       optr->arg[i] = strdup(va_arg(args, char *));
123     }
124     break;
125 
126   case OT_TREE:			/* Sub-menu -- Next option is id */
127     optr->v.submenu = va_arg(args, int);
128     break;
129   }
130   if (optr->type & OT_SYNTH)
131   {
132     optr->synth = va_arg(args, int);
133     if (optr->type != (OT_TREE | OT_SYNTH))
134     {
135       optr->setstr = va_arg(args, char *);
136     }
137   } else
138   {
139     optr->synth = 0;
140   }
141   if (optr->type & OT_BITSLICE)
142   {
143     optr->shift = va_arg(args, int);
144   }
145   curopt++;
146   va_end(args);
147 }
148 
149 
150 #define opt_ptr(x) (opt[x].type & OT_SYNTH ? \
151                     (void *)(voices[opt[x].synth] + (long) opt[x].ptr) : \
152                     opt[x].ptr)
153 
154 #define data_size(x) (((x)->type & 0x3f) == OT_FLOAT? sizeof(double): sizeof(int))
155 
156 
opt_getval(int num,int flag)157 int opt_getval(int num, int flag)
158 {
159   char *p = opt_ptr(num);
160   int out = 0, count = 0;
161   int retval;
162 
163   if ((opt[num].type & OT_BITSLICE) && !flag)
164   {				/* bitslice */
165     int v = opt[num].v.enum_max;	/* assuming OT_ENUM */
166     while (v)
167     {
168       /* hmm; will this code work for enum_max > 1? */
169       out += ((*p >> (opt[num].shift + count)) & 1) << count;
170       count++;
171       v >>= 1;
172     }
173     return (out);
174   } else
175   {
176     (void) memcpy(&retval, p, data_size(&opt[num]));
177     return retval;
178   }
179 }
180 
opt_getval_float(int num,int flag)181 double opt_getval_float(int num, int flag)
182 {
183   char *p = opt_ptr(num);
184   double retval;
185 
186   (void) memcpy(&retval, p, data_size(&opt[num]));
187   return retval;
188 }
189 
opt_setval(int num,void * val)190 static void opt_setval(int num, void *val)
191 {
192   char *p = opt_ptr(num);
193   int count = 0;
194   int out = *p;
195 
196   if (opt[num].type & OT_BITSLICE)
197   {
198     int v = opt[num].v.enum_max;
199     int val_int = *(int *)val;
200     while (v)
201     {
202       out &= ~(1 << (opt[num].shift + count));
203       v >>= 1;
204     }
205     out |= val_int << opt[num].shift;
206     *p = out;
207   }
208   else (void) memcpy(p, val, data_size(&opt[num]));
209 }
210 
opt_preset(int num,char pre)211 void opt_preset(int num, char pre)
212 {
213   char *p;
214 
215   (void) strcpy((char *) buf, opt[num].arg[(int) pre]);
216   strtok((char *) buf, ":");
217   while ((p = strtok(NULL, ":")))
218   {
219     opt_read(p, tts.synth);
220   }
221 }
222 
opt_synth_update(int num,int optval)223 static void opt_synth_update(int num, int optval)
224 {
225   char *p1, *p2;
226 
227   p1 = opt[num].setstr;
228   if (!p1 && (opt[num].type & 0x3f) == OT_ENUM)
229   {
230     p1 = strstr(opt[num].arg[optval], ":") + 1;
231   }
232 
233   /* This assumes that no synth will need a \ code at the beginning of a
234    * setstr string.  If one does, then this code will need to be changed.
235    */
236   if (!strchr(p1 + 1, '\\') && !strstr(p1, "%s"))
237   {
238     (void) sprintf(ttsbuf, p1, optval);
239   }
240   else
241   {
242     p2 = ttsbuf;
243     while (*p1)
244     {
245       switch (*p1)
246       {
247       case '\\':
248 	p1++;
249 	switch (*(p1++))
250 	{
251 	case 'l':
252 	  *(p2++) = *((char *) opt_ptr(num)) + 64;
253 	  break;
254 	case 'p':
255 	  *(p2++) = opt[num].arg[(int) *((char *) opt_ptr(num))][0];
256 	  break;
257 	case '?':	/* hard-coded special handling */
258 	  switch (num)
259 	  {
260 	  case 32:	/* bns punctuation: tbd - rework using : form */
261 	    switch (*(short *) opt_ptr(num))
262 	    {
263 	    case 0:
264 	      *(p2++) = 'Z';
265 	      break;
266 	    case 1:
267 	      *(p2++) = 'S';
268 	      break;
269 	    case 2:
270 	      *(p2++) = 'M';
271 	      break;
272 	    case 3:
273 	      *(p2++) = 'T';
274 	      break;
275 	    }
276 	  }
277 	  break;
278 	}
279 	break;
280       case '%':
281 	p1++;
282 	switch (*(p1++))
283 	{
284 	case 's':	/* send string of numeric option */
285 	  strcpy(p2, opt[num].arg[optval]);
286 	  while (*p2) p2++;
287 	  break;
288 	default:
289 	  /* tbd - error */
290 	  break;
291 	}
292 	break;
293       default:
294 	*(p2++) = *(p1++);
295       }
296     }
297     *p2 = '\0';
298   }
299   tts_send(ttsbuf, strlen(ttsbuf));
300 }
301 
opt_synth_update_float(int num,double optval)302 static void opt_synth_update_float(int num, double optval)
303 {
304   int i;
305 
306   (void) sprintf(ttsbuf, opt[num].setstr, optval);
307   for (i=0; i<strlen(ttsbuf); i++)
308     {
309       if ((ttsbuf[i])==',')
310         ttsbuf[i]='.';
311     }
312 
313   tts_send(ttsbuf, strlen(ttsbuf));
314 }
315 
opt_queue_empty(int mode)316 void opt_queue_empty(int mode)
317 {
318   int i;
319   int max;
320 
321   max = (mode == 1 ? opq.lastlen : opq.len);
322   if (!max) return;
323   if (opq.saychar)
324   {
325     if (mode == 3)
326     {
327       opq.len = 0;
328       return;
329     }
330     tts_charoff();
331     opq.saychar = 0;
332   }
333   for (i = 0; i < max; i++)
334   {
335     if ((opt[opq.opt[i]].type & 0x3f) == OT_FLOAT)
336     {
337       opt_synth_update_float(opq.opt[i], opq.v[i].val_float);
338     }
339     else
340     {
341       opt_synth_update(opq.opt[i], opq.v[i].val);
342     }
343   }
344   switch (mode)
345   {
346   case 3:
347     opq.saychar = 1;
348     tts_charon();
349   case 0:
350     opq.lastlen = opq.len;
351     opq.len = 0;
352     break;
353   case 2:
354     opq.len = 0;
355   case 1:
356     opq.lastlen = 0;
357     break;
358   }
359 }
360 
opt_set(int num,void * val)361 void opt_set(int num, void *val)
362 {
363   void *p = opt_ptr(num);
364 
365   switch (opt[num].type & 0x3f)
366   {
367   case OT_STR:
368     (void) strncpy((char *) p, val, OPT_STR_SIZE);
369     break;
370 
371   case OT_PRESET:
372     opt_preset(num, 0);
373     if (*(char *) val)
374     {
375       opt_preset(num, *(char *) val);
376     }
377 
378   case OT_INT:
379   case OT_ENUM:
380   case OT_FLOAT:
381     opt_setval(num, val);
382     break;
383   }
384   if (!(opt[num].type & OT_SYNTH) || opt[num].synth != tts.synth) return;
385   switch (opt[num].type & 0x3f)
386   {
387   case OT_INT:
388   case OT_ENUM:
389     opt_queue_add(num, opt_getval(num, 1));
390     break;
391   case OT_FLOAT:
392     opt_queue_add(num, opt_getval_float(num, 1));
393     break;
394   }
395 }
396 
opt_say(int num,int flag)397 void opt_say(int num, int flag)
398 {
399   void *p = opt_ptr(num);
400 
401   if (flag)
402   {
403     (void) sprintf((char *) buf, "%s... ", opt[num].localized_name);
404     tts_say((char *) buf);
405   }
406   switch (opt[num].type & 0x3f)
407   {
408   case OT_INT:
409     (void) sprintf((char *) buf, "%d", opt_getval(num, 0));
410     tts_say((char *) buf);
411     break;
412   case OT_FLOAT:
413     (void) sprintf((char *) buf, "%f", opt_getval_float(num, 0));
414     tts_say((char *) buf);
415     break;
416   case OT_ENUM:
417     (void) strcpy((char *) buf, opt[num].arg[opt_getval(num, 0)]);
418     strtok((char *) buf, ":");
419     tts_say(_((char *) buf));
420     break;
421   case OT_STR:
422     tts_say((char *) p);
423     break;
424   }
425 }
426 
427 #define opt_usable(x) (opt[x].tree == opt[curopt].tree && \
428                       (!(opt[x].type & OT_SYNTH) || \
429                       opt[x].synth == tts.synth || \
430                       opt[i].synth == -1))
431 
optmenu(int ch)432 int optmenu(int ch)
433 {
434   int i;
435   static int state = 0;
436 
437   switch (state)
438   {
439   case 1:			/* User has just finished entering an integer */
440     if (!ui.abort)
441     {
442       int num = atoi(ui.str);
443       if (num >= opt[curopt].v.val_int.min && num <= opt[curopt].v.val_int.max)
444       {
445 	opt_set(curopt, &num);
446 	tts_say(_("Value accepted."));
447       } else
448       {
449 	tts_say(_("Value out of range."));
450       }
451     }
452     state = 0;
453     return (1);
454 
455   case 2:			/* User has just finished entering a float */
456     if (!ui.abort)
457     {
458       double num = atof(ui.str);
459       if (num >= opt[curopt].v.val_float.min && num <= opt[curopt].v.val_float.max)
460       {
461 	opt_set(curopt, &num);
462 	tts_say(_("Value accepted."));
463       } else
464       {
465 	tts_say(_("Value out of range."));
466       }
467     }
468     state = 0;
469     return (1);
470 
471   case 3:			/* User has just entered a string -- not yet implemented */
472     if (!ui.abort)
473     {
474       opt_set(curopt, &ui.buf);
475       tts_say(_("value accepted."));
476     }
477     return (1);
478   }
479 
480   switch (ch)
481   {
482   case 0:			/* initialize */
483     tts_say(_("Setting options..."));
484     opt_say(curopt = 0, 1);
485     break;
486 
487   case 0x1b5b41:		/* up arrow */
488     for (i = curopt - 1; i >= 0; i--)
489     {
490       if (opt_usable(i))
491       {
492 	curopt = i;
493 	break;
494       }
495     }
496     opt_say(curopt, 1);
497     break;
498 
499   case 0x1b5b42:		/* down arrow */
500     for (i = curopt + 1; i < NUMOPTS; i++)
501     {
502       if (opt_usable(i))
503       {
504 	curopt = i;
505 	break;
506       }
507     }
508     opt_say(curopt, 1);
509     break;
510 
511   case 0x1b5b44:		/* left arrow */
512     if (!opt[curopt].tree)
513     {
514       opt_say(curopt, 1);
515       break;
516     }
517     for (i = curopt - 1; i >= 0; i--)
518     {
519       if ((opt[i].type & 0x3f) == OT_TREE &&
520 	  opt[i].v.submenu == opt[curopt].tree &&
521 	  (!opt[i].type & OT_SYNTH ||
522 	   opt[i].synth == tts.synth || opt[i].synth == -1))
523       {
524 	curopt = i;
525 	break;
526       }
527     }
528     opt_say(curopt, 1);
529     break;
530 
531   case 0x1b5b43:		/* right arrow */
532   case 0x0d:
533   case 0x20:
534     switch (opt[curopt].type & 0x3f)
535     {
536     case OT_INT:
537       (void) sprintf((char *) buf, "%s %d %s %d.",_("Enter a number from"), opt[curopt].v.val_int.min, _("to"), opt[curopt].v.val_int.max);
538       tts_say((char *) buf);
539       ui_funcman(&ui_build_str);
540       state = 1;
541       break;
542     case OT_FLOAT:
543       (void) sprintf((char *) buf, "%s %lf %s %lf.",_("Enter a number from"), opt[curopt].v.val_float.min,_("to"),  opt[curopt].v.val_float.max);
544       tts_say((char *) buf);
545       ui_funcman(&ui_build_str);
546       state = 2;
547       break;
548 
549     case OT_ENUM:
550       i = (opt_getval(curopt, 0) + 1) % (opt[curopt].v.enum_max + 1);
551       opt_set(curopt, &i);
552       opt_say(curopt, 1);
553       break;
554 
555     case OT_STR:			/* tbd -- allow the user to enter a string here */
556       break;
557 
558     case OT_TREE:
559       for (i = curopt + 1; i < NUMOPTS; i++)
560       {
561 	if (opt[i].tree == opt[curopt].v.submenu &&
562 	    (!(opt[i].type & OT_SYNTH) ||
563 	     opt[i].synth == tts.synth || opt[i].synth == -1))
564 	{
565 	  curopt = i;
566 	  break;
567 	}
568       }
569       opt_say(curopt, 1);
570     }
571     break;
572 
573   case 27:
574     tts_say(_("exiting options menu."));
575     ui_funcman(0);
576     break;
577 
578   default:
579     if ((ch & 0xffffff00) || !isalpha(ch))
580     {
581       break;
582     }
583     ch |= 0x20;
584     for (i = (curopt + 1) % NUMOPTS; i != curopt; i = (i + 1) % NUMOPTS)
585     {
586       if ((opt[i].localized_name[0] | 0x20) == ch && opt_usable(i))
587       {
588 	curopt = i;
589 	break;
590       }
591     }
592     opt_say(curopt, 1);
593   }
594 
595   return (1);
596 }
597 
strro(char * s,char c,int j)598 static char *strro(char *s, char c, int j)
599 {
600   static char buf[500];
601   char *p = s, *q = buf;
602 
603   if (j)
604   {
605     while (*p && *p != c)
606     {
607       p++;
608     }
609     if (!*p)
610     {
611       buf[0] = '\0';
612       return (buf);
613     }
614     p++;
615   }
616   while (*p && *p != c)
617   {
618     *(q++) = *(p++);
619   }
620   *q = '\0';
621 
622   return (buf);
623 }
624 
opt_read(char * buf,int synth)625 int opt_read(char *buf, int synth)
626 {
627   int i, j;
628   void *p;
629   float float_val;
630 
631   strtok(buf, "=");
632   i = strlen(buf);
633   while (i && buf[i] == ' ')
634     buf[i--] = '\0';
635   if (!strcasecmp(buf, "synthesizer") && cl_synth)
636   {
637     cl_synth = 0;
638     return (0);
639   }
640   if (!strcasecmp(buf, "synthesizer port") && cl_synthport)
641   {
642     cl_synthport = 0;
643     return 0;
644   }
645   for (i = 0; i < NUMOPTS; i++)
646   {
647     if (!strcasecmp(buf, opt[i].internal_name) && opt[i].synth == synth)
648     {
649       break;
650     }
651   }
652   if (i == NUMOPTS)
653   {
654     return (-1);
655   }
656   if (!(p = strtok(NULL, "")))
657   {
658     return (-1);
659   }
660   switch (opt[i].type & 0x3f)
661   {
662   case OT_INT:
663     j = strtol(p, NULL, 0);
664     opt_set(i, &j);
665     break;
666 
667   case OT_FLOAT:
668     sscanf(p, "%f", &float_val);
669     opt_set(i, &float_val);
670     break;
671 
672   case OT_ENUM:
673     for (j = 0; j <= opt[i].v.enum_max; j++)
674     {
675       if (!strcasecmp(p, strro(opt[i].arg[j], ':', 0)))
676       {
677 	break;
678       }
679     }
680     if (j > opt[i].v.enum_max)
681     {
682       return (-1);
683     }
684     opt_set(i, &j);
685     break;
686   case OT_STR:
687     opt_set(i, p);
688     break;
689   }
690 
691   return (0);
692 }
693 
opt_write_single(FILE * fp,int i)694 void opt_write_single(FILE * fp, int i)
695 {
696   switch (opt[i].type & 0x3f)
697   {
698   case OT_INT:
699     (void) fprintf(fp, "%s=%d\n", opt[i].internal_name, opt_getval(i, 0));
700     break;
701   case OT_FLOAT:
702     (void) fprintf(fp, "%s=%lf\n", opt[i].internal_name, opt_getval_float(i, 0));
703     break;
704   case OT_ENUM:
705     (void) fprintf(fp, "%s=%s\n",
706 	opt[i].internal_name, strro(opt[i].arg[opt_getval(i, 0)], ':', 0));
707     break;
708   case OT_STR:
709     (void) fprintf(fp, "%s=%s\n", opt[i].internal_name, (char *) opt_ptr(i));
710     break;
711   }
712 }
713 
opt_write(FILE * fp)714 void opt_write(FILE * fp)
715 {
716   int i, j;
717 
718   for (i = 0; i < NUMOPTS; i++)
719   {
720     if (!(opt[i].type & OT_SYNTH))
721     {
722       opt_write_single(fp, i);
723     }
724   }
725   for (i = 0; i <= opt[synthopt].v.enum_max; i++)
726   {
727     (void) fprintf(fp, "[%s]\n", opt[synthopt].arg[i]);
728     for (j = 0; j < NUMOPTS; j++)
729     {
730       if ((opt[j].type & OT_SYNTH) && opt[j].synth == i)
731       {
732 	opt_write_single(fp, j);
733       }
734     }
735   }
736 }
737 
opt_init()738 void opt_init()
739 {
740   opq.len = opq.lastlen = 0;
741   opt_add(&ui.curtrack, 0, N_("cursor tracking"), OT_ENUM, 3, N_("off"), N_("arrow keys"), N_("full"));
742   opt_add(&tts.synth, 0, N_("synthesizer"), OT_ENUM, 9, N_("speakout"), N_("dectalk"), N_("Emacspeak server"), N_("doubletalk"), N_("bns"), N_("apollo"), N_("festival"), N_("Ciber232"), N_("speech dispatcher"));
743   opt_add(tts.port, 0, N_("synthesizer port"), OT_STR);
744   opt_add(&ui.kbsay, 0, N_("key echo"), OT_ENUM, 3, N_("off"), N_("keys"), N_("words"));
745   opt_add(usershell, 0, N_("shell"), OT_STR);
746 
747 /* tbd - The following is a bad hack that I use to play Angband.  It should
748  * be replaced with a more general facility for defining screen windows.
749  */
750   opt_add(&special, 255, "special", OT_ENUM, 2, "off", "on");
751 
752   opt_add(&rev.udmode, 0, N_("up and down arrows"), OT_ENUM, 3, N_("speak line"), N_("speak character"), N_("speak word"));
753 
754 /* tbd - allow the user to enter 0x to indicate a Hex number, somehow */
755   opt_add(&ui.disable, 255, N_("DisableKey"), OT_INT, 0, 0x7fffffff);
756 
757   opt_add(&ui.split_caps, 0, "Split caps", OT_ENUM, 2, "off", "on");
758 
759   opt_add(NULL, 0, N_("synthesizer options"), OT_TREE | OT_SYNTH, -1, -1);
760 
761 /* Speakout settings (first index is 10) */
762   opt_add((void *) 4, -1,N_( "rate"), OT_INT | OT_SYNTH, 0, 9, 0, "\005r%d");
763   opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 0, 9, 0, "\005p%d");
764   opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 9, 0, "\005v%d");
765   opt_add((void *) 16, -1, N_("tone"), OT_INT | OT_SYNTH, 1, 26, 0, "\005t\\l");
766   opt_add(NULL, -1, N_("Punctuation"), OT_TREE | OT_SYNTH, -2, 0);
767   opt_add(NULL, -2, N_("textual"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")":!,.:;", 0, "\005y%x", 3);
768   opt_add(NULL, -2, N_("math"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")":%^*()/-<=>+", 0, "\005y%x", 2);
769   opt_add(NULL, -2, N_("miscelaneous"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")":[]{}\\|_\"'@#$&", 0, "\005y%x", 1);
770   opt_add(NULL, -2, N_("spaces"), OT_ENUM | OT_SYNTH | OT_BITSLICE, 2, N_("off"), N_("on")": ", 0, "\005y%x", 0);
771 
772 /* DEC-Talk settings (first index is 19) */
773   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 75, 650, 1, "[:ra%d]");
774   opt_add((void *) 8, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 99, 1, "[:vol set %d]");
775   opt_add((void *) 12, -1, N_("voice"), OT_ENUM | OT_SYNTH, 10, N_("paul"), N_("harry"), N_("frank"), N_("dennis"), N_("betty"), N_("ursula"), N_("rita"), N_("wendy"), N_("kit"), N_("val"), 1, "[:n\\p]");
776   opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 3, N_("some"), N_("none"), N_("all"), 1, "[:pu \\p]");
777 
778 /* Emacspeak settings (first index is 23) */
779   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 0, 999, 2, "tts_set_speech_rate {%d}\r");
780   opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 3, N_("none"), N_("some"), N_("all"), 2, "tts_set_punctuations %s\r");
781 
782 /* DoubleTalk settings (first index is 24) */
783   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 0, 9, 3, "\001%ds");
784   opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 0, 99, 3, "\001%dp");
785   opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 9, 3, "\001%dv");
786   opt_add((void *) 16, -1, N_("tone"), OT_INT | OT_SYNTH, 0, 2, 3, "\001%dX");
787   opt_add((void *) 20, -1, N_("voice"), OT_ENUM | OT_SYNTH, 8, N_("paul"), N_("vader"), N_("bob"), N_("pete"), N_("randy"), N_("biff"), N_("skip"), N_("roborobert"), 3, "\001%dO");
788   opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 4, N_("none")":\0017b", N_("some")":\0016b", N_("most")":\0015b", N_("all")":\0014b", 3, NULL);
789 
790 /* Braille 'n Speak settings (first index is 30) */
791   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 1, 15, 4, "\005%dE");
792   opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 1, 63, 4, "\005%dP");
793   opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, 1, 15, 4, "\005%dV");
794   opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 4, N_("none"), N_("some"), N_("most"), N_("all"), 4, "\005\\?");
795 
796 /* Apollo settings (first index is 34) */
797   opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 2, N_("off"), N_("on"), 5, "@P%d");
798   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 1, 9, 5, "@W%d");
799   opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, 1, 15, 5, "@F%x");
800   opt_add((void *) 12, -1, N_("prosody"), OT_INT | OT_SYNTH, 1, 7, 5, "@R%d");
801   opt_add((void *) 16, -1, N_("word pause"), OT_INT | OT_SYNTH, 1, 9, 5, "@Q%d");
802   opt_add((void *) 20, -1, N_("sentence pause"), OT_INT | OT_SYNTH, 1, 15, 5, "@D%x");
803   opt_add((void *) 24, -1, N_("degree"), OT_INT | OT_SYNTH, 1, 8, 5, "@B%d");
804   opt_add((void *) 28, -1, N_("volume"), OT_INT | OT_SYNTH, 1, 15, 5, "@A%x");
805   opt_add((void *) 32, -1, N_("voice"), OT_INT | OT_SYNTH, 1, 6, 5, "@V%d");
806 
807   /* festival settings (first index is 44) */
808   opt_add((void *)4, -1, N_("rate"), OT_FLOAT|OT_SYNTH, (double)0.4, (double)2.5, 6, "(Parameter.set 'Duration_Stretch %e)");
809 
810 /* Ciber232 settings  (first index 44)*/
811   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, 0, 9, 7, "@b%d");
812   opt_add((void *) 8, -1, N_("volume"), OT_INT | OT_SYNTH, 0, 9, 7, "@d%d");
813   opt_add((void *) 12, -1, N_("pitch"), OT_INT | OT_SYNTH, 0, 9, 7, "@a%d");
814   opt_add((void *) 16, -1, N_("sex"), OT_INT | OT_SYNTH, 0, 1, 7, "@c%d");
815   opt_add((void *) 20, -1, N_("Voice"), OT_INT | OT_SYNTH, 0, 1, 7, "@q%d");
816   opt_add((void *) 24, -1, N_("entonation"), OT_INT | OT_SYNTH, 0, 9, 7, "@r%d");
817   opt_add((void *) 28, -1, N_("caseonwarning"), OT_INT | OT_SYNTH, 0, 1, 7, "@n%d");
818   opt_add((void *) 32, -1, N_("deviceonwarning"), OT_INT | OT_SYNTH, 0, 1, 7, "@t%d");
819 
820 /* Speech Dispatcher settings  (first index ?52?)*/
821   opt_add((void *) 4, -1, N_("rate"), OT_INT | OT_SYNTH, -100, 100, 8, "SET SELF RATE %d\r\n");
822   opt_add((void *) 8, -1, N_("pitch"), OT_INT | OT_SYNTH, -100, 100, 8, "SET SELF PITCH %d\r\n");
823   opt_add((void *) 12, -1, N_("volume"), OT_INT | OT_SYNTH, -100, 100, 8, "SET SELF VOLUME %d\r\n");
824 /* Language shouldn't be an enumeration!  Fix me! */
825 /* Available languages: English, Spanish, and Latin. */
826   opt_add((void *) 16, -1, N_("language"), OT_ENUM | OT_SYNTH, 3, N_("en"), N_("es"), N_("la"), 8, "SET SELF LANGUAGE %s\r\n");
827 /* Output module shouldn't be an enumeration, either. */
828   opt_add((void *) 20, -1, N_("output module"), OT_ENUM | OT_SYNTH, 3, N_("espeak"), N_("flite"), N_("ibmtts"), 8, "SET SELF OUTPUT_MODULE %s\r\n");
829   opt_add((void *) 0, -1, N_("punctuation"), OT_ENUM | OT_SYNTH, 3, N_("none"), N_("some"), N_("all"), 8, "SET SELF PUNCTUATION %s\r\n");
830 }
831