tedj@hpcilzb.HP.COM (Ted Johnson) (10/19/88)
[Number Talk Source]
This is a program called Number Talk. If you type in a number
(e.g., "-234.35"), Number Talk will spell it ("Negative Two
Hundred Thirty-Four Point Three Five") and will also speak it,
provided you have a MacinTalk driver in your System Folder.
Have fun!
-Ted C. Johnson
[Moderator's Note: The binary for this program has been posted to
comp.binaries.mac.]
---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#
# number.c
#
# This archive created: Tue Oct 18 09:35:23 1988
# By: Roger L. Long (bytebug@dhw68k.cts.com)
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'number.c'" '(8687 characters)'
if test -f 'number.c'
then
echo shar: will not over-write existing file "'number.c'"
else
sed 's/^X//' << \SHAR_EOF > 'number.c'
X/*
X*Program name: Number Talk
X*
X*Author: The guts of this program come from an unknown Unix machine.
X* There was no documentation, so the author is unknown. I did
X* a quick port to the Mac (and Lightspeed C), and added the
X* speech feature. Ted C. Johnson, August 10, 1988. As far as
X* I know, the program is Public Domain (FreeWare). Have fun!
X*
X*Compilation instructions: use Lightspeed C, v. 2.15. This program does
X* NOT use a resource file. It was tested on a
X* Mac SE HD20, running System/Finder 4.1/5.5.
X*
X*Summary: This program translates a number (e.g., -123.454) into English
X* ("Negative One Hundred Twenty-Three Point Four Five Four"),
X* and speaks it. Number Talk handles positive and negative
X* integers and floating point numbers, but does not accept commas.
X*
X* Number Talk will translate the number to either a cardinal
X* number (e.g., 4 becomes "Four") or an ordinal number (e.g.,
X* 4 becomes "Fourth".
X*
X* Type "o" for ordinal mode.
X* Type "c" for cardinal mode.
X* Type "q" to quit.
X* Type a number, hit carriage return, and Number Talk will
X* spell it and then speak it.
X*
X*NOTE: You must have the MacinTalk driver in your System Folder to
X* run this program!
X*/
X
X#include <stdio.h>
X#include <strings.h>
X#include <MacTypes.h>
X#include <MacinTalk.h>
X
X
X
X#define TRUE 1
X#define FALSE 0
X
Xchar words[BUFSIZ];
XStr255 s;
X
XSpeechHandle theSpeech;
XHandle theText;
X
X
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
Xdouble n; /* Holds number for pass to ftow */
Xchar *numb; /* Pointer to return from number */
Xint thend; /* Flag for ordinal numbers */
Xextern char *ftow();
Xextern double atof();
Xint quit = FALSE;
X
X thend = FALSE;
X
X SpeechOn("",&theSpeech);
X theText = NewHandle(0);
X
X printf("Welcome to \"Number Talk\"\n");
X say("Welcome to Number Talk", FALSE);
X say("(a public domain program ported by Ted C Johnson)", TRUE);
X printf("\n");
X say("Enter any number, and I will spell it and speak it", TRUE);
X say("Please don't use commas!", TRUE);
X say("Type c for cardinal mode", TRUE);
X say("Type o for ordinal mode", TRUE);
X say("Type q to quit", TRUE);
X printf("\n");
X say("Here we go", TRUE);
X
X printf("\n\n");
X
X for (;!quit;) {
X say("Enter a number",FALSE);
X printf("Enter a number (or a command)-->");
X gets(s);
X
X switch(s[0]) {
X case 'q':
X quit = TRUE;
X break;
X
X case 'o':
X thend = TRUE;/*ordinal numbers wanted*/
X break;
X
X case 'c':
X thend = FALSE;
X break;
X
X default:
X n = atof(s); /* Get a float for ftow */
X numb = ftow(n,thend); /* Generate the words */
X
X if (n < 0) {
X say("negative", FALSE);
X }
X
X say(s, FALSE);
X say("in words is", FALSE);
X printf("%s\n",numb); /* Print it */
X say(numb, FALSE);
X
X break;
X }
X }/*for*/
X
X SpeechOff(theSpeech);
X}
X
X
X
Xsay(s, printit)
XStr255 s;
Xint printit;
X{
X if (printit) {
X printf("%s\n", s);
X }
X Reader(theSpeech, s, (long)strlen(s), theText);
X MacinTalk(theSpeech, theText);
X}
X
X/* Table for name of each three-digit group */
Xstatic char *units[] =
X {
X " Trillion",
X " Billion",
X " Million",
X " Thousand",
X "\0\0\0\0\0"
X };
X
X
X
X/* Names of numbers that are unique */
Xstatic char *numbers[] =
X {
X "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
X "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen",
X "Sixteen", "Seventeen", "Eighteen", "Nineteen", "Twenty",
X "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"
X };
X
X
X
X/* Ordinal number coding table */
Xstatic char *ord[] =
X {
X "+th","First","Second","Third","+th","Fifth","+th","+th","+h",
X "Ninth","+th","+th","+th","+th","+th","+th","+th","+th","+th","+th"
X };
X
X
X
X/*
X*Routine to convert the number to words
X*Entry:
X*x = double precision number to convert
X*ordflag = do you want ordinal numbers? (0 = no, !0 = yes)
X*Returns:
X*A character pointer to the words
X*/
Xchar *ftow(x,ordflag)
Xdouble x;
Xint ordflag;
X{
Xregister int i; /* Loop counter */
Xchar numb[25]; /* Holds printf'ed number */
Xchar hold[30]; /* Gets 3 digit grouping */
Xint negflag = FALSE; /* Is number negative? */
Xint n; /* All around number */
X
Xextern void thcon(); /* Convert each thousands group */
X
X words[0] = '\0'; /* Initialize for strcat */
X
X /* More than one quadrillion */
X if (x >= 1e15) {
X strcpy(words,"Overflow");
X return(words);
X }
X
X /* Just tack "Negative" on, */
X if (x < 0) {
X strcpy(words,"Negative ");
X x = -x; /* and convert the positive */
X negflag = TRUE; /* But let rest of the routine know */
X }
X
X sprintf(numb,"%23.7f",x); /* Put number into printable form */
X for (i = 0; numb[i] == ' '; ++i) { /* Tack on leading zeros */
X numb[i] = '0';
X }
X
X
X if (x < 1) {
X strcat(words,numbers[0]); /* Add a "Zero" if it is less than 1 */
X }
X else {
X for (i = 0; i < 5; i++) { /* Loop through each thousands group */
X sscanf(&numb[i*3],"%3d",&n); /* Get number less than one thousand */
X thcon(hold,n); /* Convert it */
X
X /* If it isn't zero */
X if (*hold != '\0') {
X if (words[0] != '\0') { /* If it isn't the first word */
X if (!negflag) /* If the last word wasn't "Negative" */
X strcat(words,", "); /* Add a comma */
X strcat(words,hold); /* Then add the words */
X negflag = FALSE; /* No more "Negative" */
X }
X else {
X strcpy(words,hold); /* Use copy if it is the first word */
X }
X strcat(words,units[i]); /* And tack on the "Million", etc */
X }
X }
X }
Xsscanf(&numb[16],"%d",&n); /* Check for stuff after the decimal */
Xif (n != 0) /* If there is stuff */
X {
X strcat(words," Point"); /* Add decimal point */
X for (i = 16; numb[i] != '\0'; i++) /* Get to end of number */
X ;
X i--;
X while (numb[i] == '0') /* Strip off trailing zeros */
X i--;
X numb[i+1] = '\0';
X for (i= 16; numb[i] != '\0'; i++) /* Pull off one digit at a time */
X {
X strcat(words," "); /* Add the space */
X n = numb[i] - '0'; /* And convert to decimal */
X strcat(words,numbers[n]); /* Tack on the right number */
X }
X }
Xelse /* If there ain't no decimals */
X {
X if (ordflag) /* And you want ordinals */
X {
X for (i = 0; words[i] != '\0'; ++i) /* Get to end of words */
X ;
X i--;
X if (words[i] == 'y') /* If it is a "Twenty", etc */
X {
X words[i] = '\0'; /* Change the "y" to "ieth" */
X strcat(words,"ieth");
X }
X else /* Search for beginning of last word */
X {
X while(words[i-1] != ' ' && words[i-1] != '-' && i > 0)
X i--;
X for (n = 0; n < 20; n++) /* Find out what the last word is */
X if (strcmp(&words[i],numbers[n]) == 0)
X break;
X if (n > 19) /* If we can't figure out what it is */
X strcat(words,"th"); /* just add a "th" */
X else
X {
X if (ord[n][0] == '+') /* Plus = cat the rest of the string */
X strcat(words,&ord[n][1]);
X else /* Otherwise make an entire replace */
X {
X words[i] = '\0';
X strcat(words,ord[n]);
X }
X }
X }
X }
X }
X
Xfor (n = 0; ; n = i) /* Divide words up into < 80 byte */
X { /* sections separated by a newline */
X for (i = n; i < n+80; ++i)
X if (words[i] == '\0')
X return(words);
X while (words[i] != ' ')
X --i;
X words[i] = '\n';
X }
X}
X
X
X
X/*
X*Routine to convert a number less than one thousand into words. Basic
X*routine, because all groups of three digits similar.
X*Entry:
X*buf = a place to put the converted number
X*z = the number to convert
X*Return:
X*Nothing
X*/
X
Xvoid thcon(buf,z)
Xregister int z;
Xchar buf[];
X{
Xregister int d; /* The divided down number */
Xregister int spflag = FALSE; /* Do we need a space catted? */
X
X buf[0] = '\0'; /* Initialize */
X
X /* Converting zero is easy */
X if (z != 0) {
X d = z / 100; /* Find out if we need and hundreds */
X
X if (d != 0){
X strcat(buf,numbers[d]); /* Tack them on */
X strcat(buf," Hundred");
X spflag = TRUE; /* Need a space afterward */
X }
X
X z %= 100; /* The < 100 stuff */
X /* Is there any? */
X if (z != 0) {
X if (spflag) { /* Need a separator */
X strcat(buf," ");
X }
X /* Simple "Forty-Four" type construct */
X if (z > 19) {
X d = z / 10 + 18; /* Get the "Forty" part into d */
X z %= 10; /* Get the "Four" part into z */
X strcat(buf,numbers[d]); /* Cat the stuff */
X if (z != 0) {
X strcat(buf,"-");
X strcat(buf,numbers[z]);
X }
X }
X else { /* Just use "One" to "Nineteen" */
X strcat(buf,numbers[z]);
X }
X }
X }
X return;
X}
SHAR_EOF
if test 8687 -ne "`wc -c < 'number.c'`"
then
echo shar: error transmitting "'number.c'" '(should have been 8687 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
---