Home | History | Annotate | Line # | Download | only in number
number.c revision 1.1
      1  1.1  cgd /*
      2  1.1  cgd  * Copyright (c) 1988 Regents of the University of California.
      3  1.1  cgd  * All rights reserved.
      4  1.1  cgd  *
      5  1.1  cgd  * Redistribution and use in source and binary forms, with or without
      6  1.1  cgd  * modification, are permitted provided that the following conditions
      7  1.1  cgd  * are met:
      8  1.1  cgd  * 1. Redistributions of source code must retain the above copyright
      9  1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     10  1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11  1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     12  1.1  cgd  *    documentation and/or other materials provided with the distribution.
     13  1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     14  1.1  cgd  *    must display the following acknowledgement:
     15  1.1  cgd  *	This product includes software developed by the University of
     16  1.1  cgd  *	California, Berkeley and its contributors.
     17  1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     18  1.1  cgd  *    may be used to endorse or promote products derived from this software
     19  1.1  cgd  *    without specific prior written permission.
     20  1.1  cgd  *
     21  1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  1.1  cgd  * SUCH DAMAGE.
     32  1.1  cgd  */
     33  1.1  cgd 
     34  1.1  cgd #ifndef lint
     35  1.1  cgd char copyright[] =
     36  1.1  cgd "@(#) Copyright (c) 1988 Regents of the University of California.\n\
     37  1.1  cgd  All rights reserved.\n";
     38  1.1  cgd #endif /* not lint */
     39  1.1  cgd 
     40  1.1  cgd #ifndef lint
     41  1.1  cgd static char sccsid[] = "@(#)number.c	5.1 (Berkeley) 2/28/91";
     42  1.1  cgd #endif /* not lint */
     43  1.1  cgd 
     44  1.1  cgd #include <stdio.h>
     45  1.1  cgd #include <ctype.h>
     46  1.1  cgd 
     47  1.1  cgd #define	YES		1
     48  1.1  cgd #define	NO		0
     49  1.1  cgd #define	EOS		'\0'
     50  1.1  cgd #define	MAXNUM		65		/* biggest number we handle */
     51  1.1  cgd 
     52  1.1  cgd static char	*name1[] = {
     53  1.1  cgd 	"",		"one",		"two",		"three",
     54  1.1  cgd 	"four",		"five",		"six",		"seven",
     55  1.1  cgd 	"eight",	"nine",		"ten",		"eleven",
     56  1.1  cgd 	"twelve",	"thirteen",	"fourteen",	"fifteen",
     57  1.1  cgd 	"sixteen",	"seventeen",	"eighteen",	"nineteen",
     58  1.1  cgd },
     59  1.1  cgd 		*name2[] = {
     60  1.1  cgd 	"",		"ten",		"twenty",	"thirty",
     61  1.1  cgd 	"forty",	"fifty",	"sixty",	"seventy",
     62  1.1  cgd 	"eighty",	"ninety",
     63  1.1  cgd },
     64  1.1  cgd 		*name3[] = {
     65  1.1  cgd 	"hundred",	"thousand",	"million",	"billion",
     66  1.1  cgd 	"trillion",	"quadrillion",	"quintillion",	"sextillion",
     67  1.1  cgd 	"septillion",	"octillion",	"nonillion",	"decillion",
     68  1.1  cgd 	"undecillion",	"duodecillion",	"tredecillion",	"quattuordecillion",
     69  1.1  cgd 	"quindecillion",		"sexdecillion",
     70  1.1  cgd 	"septendecillion",		"octodecillion",
     71  1.1  cgd 	"novemdecillion",		"vigintillion",
     72  1.1  cgd };
     73  1.1  cgd 
     74  1.1  cgd main(argc,argv)
     75  1.1  cgd 	int	argc;
     76  1.1  cgd 	char	**argv;
     77  1.1  cgd {
     78  1.1  cgd 	register int	cnt;
     79  1.1  cgd 	char	line[MAXNUM * 2 + 2];		/* MAXNUM '.' MAXNUM '\0' */
     80  1.1  cgd 
     81  1.1  cgd 	if (argc > 1)
     82  1.1  cgd 		for (cnt = 1;cnt < argc;++cnt) {
     83  1.1  cgd 			convert(argv[cnt]);
     84  1.1  cgd 			puts("...");
     85  1.1  cgd 		}
     86  1.1  cgd 	else
     87  1.1  cgd 		while (fgets(line,sizeof(line),stdin)) {
     88  1.1  cgd 			convert(line);
     89  1.1  cgd 			puts("...");
     90  1.1  cgd 		}
     91  1.1  cgd 	exit(0);
     92  1.1  cgd }
     93  1.1  cgd 
     94  1.1  cgd convert(line)
     95  1.1  cgd 	char	*line;
     96  1.1  cgd {
     97  1.1  cgd 	register int	len,
     98  1.1  cgd 			ret;
     99  1.1  cgd 	register char	*C,
    100  1.1  cgd 			*fraction;
    101  1.1  cgd 
    102  1.1  cgd 	for (fraction = NULL, C = line;*C && *C != '\n';++C)
    103  1.1  cgd 		if (!isdigit(*C))
    104  1.1  cgd 			switch(*C) {
    105  1.1  cgd 			case '-':
    106  1.1  cgd 				if (C != line)
    107  1.1  cgd 					usage(NO);
    108  1.1  cgd 				break;
    109  1.1  cgd 			case '.':
    110  1.1  cgd 				if (!fraction) {
    111  1.1  cgd 					fraction = C + 1;
    112  1.1  cgd 					*C = EOS;
    113  1.1  cgd 					break;
    114  1.1  cgd 				}
    115  1.1  cgd 			default:
    116  1.1  cgd 				usage(NO);
    117  1.1  cgd 			}
    118  1.1  cgd 	*C = EOS;
    119  1.1  cgd 	if (*line == '-') {
    120  1.1  cgd 		puts("minus");
    121  1.1  cgd 		++line;
    122  1.1  cgd 	}
    123  1.1  cgd 	ret = NO;
    124  1.1  cgd 	if (len = strlen(line)) {
    125  1.1  cgd 		if (len > MAXNUM)
    126  1.1  cgd 			usage(YES);
    127  1.1  cgd 		ret = unit(len,line);
    128  1.1  cgd 	}
    129  1.1  cgd 	if (fraction && (len = strlen(fraction))) {
    130  1.1  cgd 		if (len > MAXNUM)
    131  1.1  cgd 			usage(YES);
    132  1.1  cgd 		for (C = fraction;*C;++C)
    133  1.1  cgd 			if (*C != '0') {
    134  1.1  cgd 				if (ret)
    135  1.1  cgd 					puts("and");
    136  1.1  cgd 				if (unit(len,fraction)) {
    137  1.1  cgd 					++ret;
    138  1.1  cgd 					pfract(len);
    139  1.1  cgd 				}
    140  1.1  cgd 				break;
    141  1.1  cgd 			}
    142  1.1  cgd 	}
    143  1.1  cgd 	if (!ret)
    144  1.1  cgd 		puts("zero.");
    145  1.1  cgd }
    146  1.1  cgd 
    147  1.1  cgd unit(len,C)
    148  1.1  cgd 	register int	len;
    149  1.1  cgd 	register char	*C;
    150  1.1  cgd {
    151  1.1  cgd 	register int	off,
    152  1.1  cgd 			ret;
    153  1.1  cgd 
    154  1.1  cgd 	ret = NO;
    155  1.1  cgd 	if (len > 3) {
    156  1.1  cgd 		if (len % 3) {
    157  1.1  cgd 			off = len % 3;
    158  1.1  cgd 			len -= off;
    159  1.1  cgd 			if (number(C,off)) {
    160  1.1  cgd 				ret = YES;
    161  1.1  cgd 				printf(" %s.\n",name3[len / 3]);
    162  1.1  cgd 			}
    163  1.1  cgd 			C += off;
    164  1.1  cgd 		}
    165  1.1  cgd 		for (;len > 3;C += 3) {
    166  1.1  cgd 			len -= 3;
    167  1.1  cgd 			if (number(C,3)) {
    168  1.1  cgd 				ret = YES;
    169  1.1  cgd 				printf(" %s.\n",name3[len / 3]);
    170  1.1  cgd 			}
    171  1.1  cgd 		}
    172  1.1  cgd 	}
    173  1.1  cgd 	if (number(C,len)) {
    174  1.1  cgd 		puts(".");
    175  1.1  cgd 		ret = YES;
    176  1.1  cgd 	}
    177  1.1  cgd 	return(ret);
    178  1.1  cgd }
    179  1.1  cgd 
    180  1.1  cgd number(C,len)
    181  1.1  cgd 	register char	*C;
    182  1.1  cgd 	int	len;
    183  1.1  cgd {
    184  1.1  cgd 	register int	val,
    185  1.1  cgd 			ret;
    186  1.1  cgd 
    187  1.1  cgd 	ret = 0;
    188  1.1  cgd 	switch(len) {
    189  1.1  cgd 	case 3:
    190  1.1  cgd 		if (*C != '0') {
    191  1.1  cgd 			++ret;
    192  1.1  cgd 			printf("%s hundred",name1[*C - '0']);
    193  1.1  cgd 		}
    194  1.1  cgd 		++C;
    195  1.1  cgd 		/*FALLTHROUGH*/
    196  1.1  cgd 	case 2:
    197  1.1  cgd 		val = (C[1] - '0') + (C[0] - '0') * 10;
    198  1.1  cgd 		if (val) {
    199  1.1  cgd 			if (ret++)
    200  1.1  cgd 				putchar(' ');
    201  1.1  cgd 			if (val < 20)
    202  1.1  cgd 				fputs(name1[val],stdout);
    203  1.1  cgd 			else {
    204  1.1  cgd 				fputs(name2[val / 10],stdout);
    205  1.1  cgd 				if (val % 10)
    206  1.1  cgd 					printf("-%s",name1[val % 10]);
    207  1.1  cgd 			}
    208  1.1  cgd 		}
    209  1.1  cgd 		break;
    210  1.1  cgd 	case 1:
    211  1.1  cgd 		if (*C != '0') {
    212  1.1  cgd 			++ret;
    213  1.1  cgd 			fputs(name1[*C - '0'],stdout);
    214  1.1  cgd 		}
    215  1.1  cgd 	}
    216  1.1  cgd 	return(ret);
    217  1.1  cgd }
    218  1.1  cgd 
    219  1.1  cgd pfract(len)
    220  1.1  cgd 	register int	len;
    221  1.1  cgd {
    222  1.1  cgd 	static char	*pref[] = { "", "ten-", "hundred-" };
    223  1.1  cgd 
    224  1.1  cgd 	switch(len) {
    225  1.1  cgd 	case 1:
    226  1.1  cgd 		puts("tenths.");
    227  1.1  cgd 		break;
    228  1.1  cgd 	case 2:
    229  1.1  cgd 		puts("hundredths.");
    230  1.1  cgd 		break;
    231  1.1  cgd 	default:
    232  1.1  cgd 		printf("%s%sths.\n",pref[len % 3],name3[len / 3]);
    233  1.1  cgd 	}
    234  1.1  cgd }
    235  1.1  cgd 
    236  1.1  cgd usage(toobig)
    237  1.1  cgd 	int	toobig;
    238  1.1  cgd {
    239  1.1  cgd 	if (toobig)
    240  1.1  cgd 		fprintf(stderr,"number: number too large, max %d digits.\n",MAXNUM);
    241  1.1  cgd 	fputs("usage: number # ...\n",stderr);
    242  1.1  cgd 	exit(-1);
    243  1.1  cgd }
    244