X-Git-Url: https://git.distorted.org.uk/~mdw/jog/blobdiff_plain/b1ffb19d137241e62b4eea0e6db834bd624bdda2..e9060e7e4c0de71ef6d4b7d7b05c3167790073e3:/aunum.c diff --git a/aunum.c b/aunum.c new file mode 100644 index 0000000..4c3cc95 --- /dev/null +++ b/aunum.c @@ -0,0 +1,243 @@ +/* -*-c-*- + * + * $Id: aunum.c,v 1.1 2002/02/02 19:16:28 mdw Exp $ + * + * Reading numbers to audio output + * + * (c) 2002 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Jog: Programming for a jogging machine. + * + * Jog is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Jog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jog; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: aunum.c,v $ + * Revision 1.1 2002/02/02 19:16:28 mdw + * New audio subsystem. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include + +#include "au.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @digit@ --- * + * + * Arguments: @char x@ = single digit to read + * + * Returns: --- + * + * Use: Reads a single digit. + */ + +static void digit(int x) +{ + static char tagbuf[4] = "n-?"; + tagbuf[2] = x; + au_play(tagbuf); +} + +/* --- @digits@ --- * + * + * Arguments: @const char *p@ = pointer to digits + * @size_t n@ = number of digits + * + * Returns: --- + * + * Use: Reads a sequence of digits. + */ + +static void digits(const char *p, size_t n) +{ + while (n) { + digit(*p++); + n--; + } +} + +/* --- @lasttwo@ --- * + * + * Arguments: @const char *p@ = pointer to digits + * @size_t n@ = number of digits + * @unsigned f@ = flags + * + * Returns: Nonzero if the number was nonzero. + * + * Use: Reads out a number of no more than two digits. + */ + +#define f_and 1u + +static int lasttwo(const char *p, size_t n, unsigned f) +{ + static char tagbuf[5] = "n-??"; + + while (n && *p == '0') { + n--; + p++; + } + if (!n) + return (0); + + if (f & f_and) + au_play("n-and"); + if (n == 1) + digit(*p); + else if (*p == '1') { + tagbuf[2] = p[0]; + tagbuf[3] = p[1]; + au_play(tagbuf); + } else { + tagbuf[2] = *p++; + tagbuf[3] = '0'; + au_play(tagbuf); + if (*p != '0') + digit(*p); + } + return (1); +} + +/* --- @bignum@ --- * + * + * Arguments: @const char *p@ = pointer to digits + * @size_t n@ = number of digits + * + * Returns: Nonzero if the number was nonzero. + * + * Use: Reads out a (large) integer in English. + */ + +static int bignum(const char *p, size_t n) +{ + int nz = 0; + int rc; + + if (n > 6) { + digits(p, n); + return (1); + } + if (n > 3) { + rc = bignum(p, n - 3); + p += n - 3; + n = 3; + if (rc) { + au_play("n-thou"); + nz = 1; + } + } + if (n > 2) { + if (*p == '0') { + p++; + } else { + digit(*p++); + au_play("n-hun"); + nz = 1; + } + n--; + } + return (lasttwo(p, n, nz ? f_and : 0) || nz); +} + +/* --- @aunum@ --- * + * + * Arguments: @const char *p@ = pointer to number's textual representation + * + * Returns: --- + * + * Use: Reads the given number aloud. + */ + +void aunum(const char *p) +{ + size_t pl; + int nz; + + /* --- Pick off a leading sign --- */ + +again: + if (*p == '+') + p++; + else if (*p == '-') { + au_play("n-minus"); + p++; + } + + /* --- Work out how many digits we have --- */ + + p += strspn(p, "0"); + pl = strspn(p, "0123456789"); + nz = bignum(p, pl); + p += pl; + + /* --- If the value was zero, and there's no `point', say `zero' --- */ + + if (*p != '.' && !nz) + au_play("n-0"); + if (*p == '.') { + au_play("n-point"); + p++; + pl = strspn(p, "0123456789"); + digits(p, pl); + p += pl; + } + if (*p == 'e' || *p == 'E') { + au_play("n-exp"); + p++; + goto again; + } + + /* --- Run out of things to do --- */ + + return; +} + +/* --- @aunum_ulong@ --- * + * + * Arguments: @unsigned long n@ = number to be read + * + * Returns: --- + * + * Use: Reads a number expressed as an @unsigned long@. + */ + +void aunum_ulong(unsigned long n) +{ + dstr d = DSTR_INIT; + + dstr_putf(&d, "%lu", n); + aunum(d.buf); + dstr_destroy(&d); +} + +/*----- That's all, folks -------------------------------------------------*/