chiark / gitweb /
774fb27a1a29504f232284c0738ed2bdb8dfc183
[jog] / aunum.c
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 /*----- Header files ------------------------------------------------------*/
30
31 #ifdef HAVE_CONFIG_H
32 #  include "config.h"
33 #endif
34
35 #include <assert.h>
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <mLib/dstr.h>
42
43 #include "au.h"
44
45 /*----- Main code ---------------------------------------------------------*/
46
47 /* --- @digit@ --- *
48  *
49  * Arguments:   @char x@ = single digit to read
50  *
51  * Returns:     ---
52  *
53  * Use:         Reads a single digit.
54  */
55
56 static void digit(int x)
57 {
58   static char tagbuf[4] = "n-?";
59   tagbuf[2] = x;
60   au_play(tagbuf);
61 }
62
63 /* --- @digits@ --- *
64  *
65  * Arguments:   @const char *p@ = pointer to digits
66  *              @size_t n@ = number of digits
67  *
68  * Returns:     ---
69  *
70  * Use:         Reads a sequence of digits.
71  */
72
73 static void digits(const char *p, size_t n)
74 {
75   while (n) {
76     digit(*p++);
77     n--;
78   }
79 }
80
81 /* --- @lasttwo@ --- *
82  *
83  * Arguments:   @const char *p@ = pointer to digits
84  *              @size_t n@ = number of digits
85  *              @unsigned f@ = flags
86  *
87  * Returns:     Nonzero if the number was nonzero.
88  *
89  * Use:         Reads out a number of no more than two digits.
90  */
91
92 #define f_and 1u
93
94 static int lasttwo(const char *p, size_t n, unsigned f)
95 {
96   static char tagbuf[5] = "n-??";
97
98   while (n && *p == '0') {
99     n--;
100     p++;
101   }
102   if (!n)
103     return (0);
104
105   if (f & f_and)
106     au_play("n-and");
107   if (n == 1)
108     digit(*p);
109   else if (*p == '1') {
110     tagbuf[2] = p[0];
111     tagbuf[3] = p[1];
112     au_play(tagbuf);
113   } else {
114     tagbuf[2] = *p++;
115     tagbuf[3] = '0';
116     au_play(tagbuf);
117     if (*p != '0')
118       digit(*p);
119   }
120   return (1);
121 }
122
123 /* --- @bignum@ --- *
124  *
125  * Arguments:   @const char *p@ = pointer to digits
126  *              @size_t n@ = number of digits
127  *
128  * Returns:     Nonzero if the number was nonzero.
129  *
130  * Use:         Reads out a (large) integer in English.
131  */
132
133 static int bignum(const char *p, size_t n)
134 {
135   int nz = 0;
136   int rc;
137
138   if (n > 6) {
139     digits(p, n);
140     return (1);
141   }
142   if (n > 3) {
143     rc = bignum(p, n - 3);
144     p += n - 3;
145     n = 3;
146     if (rc) {
147       au_play("n-thou");
148       nz = 1;
149     }
150   }
151   if (n > 2) {
152     if (*p == '0') {
153       p++;
154     } else {
155       digit(*p++);
156       au_play("n-hun");
157       nz = 1;
158     }
159     n--;
160   }
161   return (lasttwo(p, n, nz ? f_and : 0) || nz);
162 }
163
164 /* --- @aunum@ --- *
165  *
166  * Arguments:   @const char *p@ = pointer to number's textual representation
167  *
168  * Returns:     ---
169  *
170  * Use:         Reads the given number aloud.
171  */
172
173 void aunum(const char *p)
174 {
175   size_t pl;
176   int nz;
177
178   /* --- Pick off a leading sign --- */
179
180 again:
181   if (*p == '+')
182     p++;
183   else if (*p == '-') {
184     au_play("n-minus");
185     p++;
186   }
187
188   /* --- Work out how many digits we have --- */
189
190   p += strspn(p, "0");
191   pl = strspn(p, "0123456789");
192   nz = bignum(p, pl);
193   p += pl;
194
195   /* --- If the value was zero, and there's no `point', say `zero' --- */
196
197   if (*p != '.' && !nz)
198     au_play("n-0");
199   if (*p == '.') {
200     au_play("n-point");
201     p++;
202     pl = strspn(p, "0123456789");
203     digits(p, pl);
204     p += pl;
205   }
206   if (*p == 'e' || *p == 'E') {
207     au_play("n-exp");
208     p++;
209     goto again;
210   }
211
212   /* --- Run out of things to do --- */
213
214   return;
215 }
216
217 /* --- @aunum_ulong@ --- *
218  *
219  * Arguments:   @unsigned long n@ = number to be read
220  *
221  * Returns:     ---
222  *
223  * Use:         Reads a number expressed as an @unsigned long@.
224  */
225
226 void aunum_ulong(unsigned long n)
227 {
228   dstr d = DSTR_INIT;
229
230   dstr_putf(&d, "%lu", n);
231   aunum(d.buf);
232   dstr_destroy(&d);
233 }
234
235 /*----- That's all, folks -------------------------------------------------*/