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 ---