New audio subsystem.
[jog] / aunum.c
... / ...
CommitLineData
1/* -*-c-*-
2 *
3 * $Id: aunum.c,v 1.1 2002/02/02 19:16:28 mdw Exp $
4 *
5 * Reading numbers to audio output
6 *
7 * (c) 2002 Mark Wooding
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Jog: Programming for a jogging machine.
13 *
14 * Jog is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * Jog is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Jog; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: aunum.c,v $
32 * Revision 1.1 2002/02/02 19:16:28 mdw
33 * New audio subsystem.
34 *
35 */
36
37/*----- Header files ------------------------------------------------------*/
38
39#ifdef HAVE_CONFIG_H
40# include "config.h"
41#endif
42
43#include <assert.h>
44#include <ctype.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48
49#include <mLib/dstr.h>
50
51#include "au.h"
52
53/*----- Main code ---------------------------------------------------------*/
54
55/* --- @digit@ --- *
56 *
57 * Arguments: @char x@ = single digit to read
58 *
59 * Returns: ---
60 *
61 * Use: Reads a single digit.
62 */
63
64static void digit(int x)
65{
66 static char tagbuf[4] = "n-?";
67 tagbuf[2] = x;
68 au_play(tagbuf);
69}
70
71/* --- @digits@ --- *
72 *
73 * Arguments: @const char *p@ = pointer to digits
74 * @size_t n@ = number of digits
75 *
76 * Returns: ---
77 *
78 * Use: Reads a sequence of digits.
79 */
80
81static void digits(const char *p, size_t n)
82{
83 while (n) {
84 digit(*p++);
85 n--;
86 }
87}
88
89/* --- @lasttwo@ --- *
90 *
91 * Arguments: @const char *p@ = pointer to digits
92 * @size_t n@ = number of digits
93 * @unsigned f@ = flags
94 *
95 * Returns: Nonzero if the number was nonzero.
96 *
97 * Use: Reads out a number of no more than two digits.
98 */
99
100#define f_and 1u
101
102static int lasttwo(const char *p, size_t n, unsigned f)
103{
104 static char tagbuf[5] = "n-??";
105
106 while (n && *p == '0') {
107 n--;
108 p++;
109 }
110 if (!n)
111 return (0);
112
113 if (f & f_and)
114 au_play("n-and");
115 if (n == 1)
116 digit(*p);
117 else if (*p == '1') {
118 tagbuf[2] = p[0];
119 tagbuf[3] = p[1];
120 au_play(tagbuf);
121 } else {
122 tagbuf[2] = *p++;
123 tagbuf[3] = '0';
124 au_play(tagbuf);
125 if (*p != '0')
126 digit(*p);
127 }
128 return (1);
129}
130
131/* --- @bignum@ --- *
132 *
133 * Arguments: @const char *p@ = pointer to digits
134 * @size_t n@ = number of digits
135 *
136 * Returns: Nonzero if the number was nonzero.
137 *
138 * Use: Reads out a (large) integer in English.
139 */
140
141static int bignum(const char *p, size_t n)
142{
143 int nz = 0;
144 int rc;
145
146 if (n > 6) {
147 digits(p, n);
148 return (1);
149 }
150 if (n > 3) {
151 rc = bignum(p, n - 3);
152 p += n - 3;
153 n = 3;
154 if (rc) {
155 au_play("n-thou");
156 nz = 1;
157 }
158 }
159 if (n > 2) {
160 if (*p == '0') {
161 p++;
162 } else {
163 digit(*p++);
164 au_play("n-hun");
165 nz = 1;
166 }
167 n--;
168 }
169 return (lasttwo(p, n, nz ? f_and : 0) || nz);
170}
171
172/* --- @aunum@ --- *
173 *
174 * Arguments: @const char *p@ = pointer to number's textual representation
175 *
176 * Returns: ---
177 *
178 * Use: Reads the given number aloud.
179 */
180
181void aunum(const char *p)
182{
183 size_t pl;
184 int nz;
185
186 /* --- Pick off a leading sign --- */
187
188again:
189 if (*p == '+')
190 p++;
191 else if (*p == '-') {
192 au_play("n-minus");
193 p++;
194 }
195
196 /* --- Work out how many digits we have --- */
197
198 p += strspn(p, "0");
199 pl = strspn(p, "0123456789");
200 nz = bignum(p, pl);
201 p += pl;
202
203 /* --- If the value was zero, and there's no `point', say `zero' --- */
204
205 if (*p != '.' && !nz)
206 au_play("n-0");
207 if (*p == '.') {
208 au_play("n-point");
209 p++;
210 pl = strspn(p, "0123456789");
211 digits(p, pl);
212 p += pl;
213 }
214 if (*p == 'e' || *p == 'E') {
215 au_play("n-exp");
216 p++;
217 goto again;
218 }
219
220 /* --- Run out of things to do --- */
221
222 return;
223}
224
225/* --- @aunum_ulong@ --- *
226 *
227 * Arguments: @unsigned long n@ = number to be read
228 *
229 * Returns: ---
230 *
231 * Use: Reads a number expressed as an @unsigned long@.
232 */
233
234void aunum_ulong(unsigned long n)
235{
236 dstr d = DSTR_INIT;
237
238 dstr_putf(&d, "%lu", n);
239 aunum(d.buf);
240 dstr_destroy(&d);
241}
242
243/*----- That's all, folks -------------------------------------------------*/