Home | History | Annotate | Line # | Download | only in number
number.c revision 1.1.1.3
      1      1.1  cgd /*
      2  1.1.1.2  cgd  * Copyright (c) 1988, 1993, 1994
      3  1.1.1.2  cgd  *	The Regents of the University of California.  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.1.2  cgd static char copyright[] =
     36  1.1.1.2  cgd "@(#) Copyright (c) 1988, 1993, 1994\n\
     37  1.1.1.2  cgd 	The Regents of the University of California.  All rights reserved.\n";
     38      1.1  cgd #endif /* not lint */
     39      1.1  cgd 
     40      1.1  cgd #ifndef lint
     41  1.1.1.3  tls static char sccsid[] = "@(#)number.c	8.3 (Berkeley) 5/4/95";
     42      1.1  cgd #endif /* not lint */
     43      1.1  cgd 
     44  1.1.1.2  cgd #include <sys/types.h>
     45  1.1.1.2  cgd 
     46      1.1  cgd #include <ctype.h>
     47  1.1.1.3  tls #include <err.h>
     48  1.1.1.2  cgd #include <stdio.h>
     49  1.1.1.2  cgd #include <stdlib.h>
     50  1.1.1.2  cgd #include <string.h>
     51  1.1.1.3  tls #include <unistd.h>
     52      1.1  cgd 
     53  1.1.1.2  cgd #define	MAXNUM		65		/* Biggest number we handle. */
     54      1.1  cgd 
     55      1.1  cgd static char	*name1[] = {
     56      1.1  cgd 	"",		"one",		"two",		"three",
     57      1.1  cgd 	"four",		"five",		"six",		"seven",
     58      1.1  cgd 	"eight",	"nine",		"ten",		"eleven",
     59      1.1  cgd 	"twelve",	"thirteen",	"fourteen",	"fifteen",
     60      1.1  cgd 	"sixteen",	"seventeen",	"eighteen",	"nineteen",
     61      1.1  cgd },
     62      1.1  cgd 		*name2[] = {
     63      1.1  cgd 	"",		"ten",		"twenty",	"thirty",
     64      1.1  cgd 	"forty",	"fifty",	"sixty",	"seventy",
     65      1.1  cgd 	"eighty",	"ninety",
     66      1.1  cgd },
     67      1.1  cgd 		*name3[] = {
     68      1.1  cgd 	"hundred",	"thousand",	"million",	"billion",
     69      1.1  cgd 	"trillion",	"quadrillion",	"quintillion",	"sextillion",
     70      1.1  cgd 	"septillion",	"octillion",	"nonillion",	"decillion",
     71      1.1  cgd 	"undecillion",	"duodecillion",	"tredecillion",	"quattuordecillion",
     72      1.1  cgd 	"quindecillion",		"sexdecillion",
     73      1.1  cgd 	"septendecillion",		"octodecillion",
     74      1.1  cgd 	"novemdecillion",		"vigintillion",
     75      1.1  cgd };
     76      1.1  cgd 
     77  1.1.1.2  cgd void	convert __P((char *));
     78  1.1.1.2  cgd int	number __P((char *, int));
     79  1.1.1.2  cgd void	pfract __P((int));
     80  1.1.1.2  cgd void	toobig __P((void));
     81  1.1.1.2  cgd int	unit __P((int, char *));
     82  1.1.1.2  cgd void	usage __P((void));
     83  1.1.1.2  cgd 
     84  1.1.1.2  cgd int lflag;
     85  1.1.1.2  cgd 
     86  1.1.1.2  cgd int
     87  1.1.1.2  cgd main(argc, argv)
     88  1.1.1.2  cgd 	int argc;
     89  1.1.1.2  cgd 	char *argv[];
     90  1.1.1.2  cgd {
     91  1.1.1.2  cgd 	int ch, first;
     92  1.1.1.2  cgd 	char line[256];
     93  1.1.1.2  cgd 
     94  1.1.1.2  cgd 	lflag = 0;
     95  1.1.1.2  cgd 	while ((ch = getopt(argc, argv, "l")) != EOF)
     96  1.1.1.2  cgd 		switch (ch) {
     97  1.1.1.2  cgd 		case 'l':
     98  1.1.1.2  cgd 			lflag = 1;
     99  1.1.1.2  cgd 			break;
    100  1.1.1.2  cgd 		case '?':
    101  1.1.1.2  cgd 		default:
    102  1.1.1.2  cgd 			usage();
    103      1.1  cgd 		}
    104  1.1.1.2  cgd 	argc -= optind;
    105  1.1.1.2  cgd 	argv += optind;
    106  1.1.1.2  cgd 
    107  1.1.1.2  cgd 	if (*argv == NULL)
    108  1.1.1.2  cgd 		for (first = 1;
    109  1.1.1.2  cgd 		    fgets(line, sizeof(line), stdin) != NULL; first = 0) {
    110  1.1.1.2  cgd 			if (strchr(line, '\n') == NULL)
    111  1.1.1.2  cgd 				errx(1, "line too long.");
    112  1.1.1.2  cgd 			if (!first)
    113  1.1.1.2  cgd 				(void)printf("...\n");
    114      1.1  cgd 			convert(line);
    115  1.1.1.2  cgd 		}
    116  1.1.1.2  cgd 	else
    117  1.1.1.2  cgd 		for (first = 1; *argv != NULL; first = 0, ++argv) {
    118  1.1.1.2  cgd 			if (!first)
    119  1.1.1.2  cgd 				(void)printf("...\n");
    120  1.1.1.2  cgd 			convert(*argv);
    121      1.1  cgd 		}
    122      1.1  cgd 	exit(0);
    123      1.1  cgd }
    124      1.1  cgd 
    125  1.1.1.2  cgd void
    126      1.1  cgd convert(line)
    127  1.1.1.2  cgd 	char *line;
    128      1.1  cgd {
    129  1.1.1.2  cgd 	register flen, len, rval;
    130  1.1.1.2  cgd 	register char *p, *fraction;
    131  1.1.1.2  cgd 
    132  1.1.1.2  cgd 	fraction = NULL;
    133  1.1.1.2  cgd 	for (p = line; *p != '\0' && *p != '\n'; ++p) {
    134  1.1.1.2  cgd 		if (isblank(*p)) {
    135  1.1.1.2  cgd 			if (p == line) {
    136  1.1.1.2  cgd 				++line;
    137  1.1.1.2  cgd 				continue;
    138      1.1  cgd 			}
    139  1.1.1.2  cgd 			goto badnum;
    140  1.1.1.2  cgd 		}
    141  1.1.1.2  cgd 		if (isdigit(*p))
    142  1.1.1.2  cgd 			continue;
    143  1.1.1.2  cgd 		switch (*p) {
    144  1.1.1.2  cgd 		case '.':
    145  1.1.1.2  cgd 			if (fraction != NULL)
    146  1.1.1.2  cgd 				goto badnum;
    147  1.1.1.2  cgd 			fraction = p + 1;
    148  1.1.1.2  cgd 			*p = '\0';
    149  1.1.1.2  cgd 			break;
    150  1.1.1.2  cgd 		case '-':
    151  1.1.1.2  cgd 			if (p == line)
    152  1.1.1.2  cgd 				break;
    153  1.1.1.2  cgd 			/* FALLTHROUGH */
    154  1.1.1.2  cgd 		default:
    155  1.1.1.2  cgd badnum:			errx(1, "illegal number: %s", line);
    156  1.1.1.2  cgd 			break;
    157  1.1.1.2  cgd 		}
    158  1.1.1.2  cgd 	}
    159  1.1.1.2  cgd 	*p = '\0';
    160  1.1.1.2  cgd 
    161  1.1.1.2  cgd 	if ((len = strlen(line)) > MAXNUM ||
    162  1.1.1.2  cgd 	    fraction != NULL && (flen = strlen(fraction)) > MAXNUM)
    163  1.1.1.2  cgd 		errx(1, "number too large, max %d digits.", MAXNUM);
    164  1.1.1.2  cgd 
    165      1.1  cgd 	if (*line == '-') {
    166  1.1.1.2  cgd 		(void)printf("minus%s", lflag ? " " : "\n");
    167      1.1  cgd 		++line;
    168      1.1  cgd 	}
    169  1.1.1.2  cgd 
    170  1.1.1.2  cgd 	rval = len > 0 ? unit(len, line) : 0;
    171  1.1.1.2  cgd 	if (fraction != NULL && flen != 0)
    172  1.1.1.2  cgd 		for (p = fraction; *p != '\0'; ++p)
    173  1.1.1.2  cgd 			if (*p != '0') {
    174  1.1.1.2  cgd 				if (rval)
    175  1.1.1.2  cgd 					(void)printf("%sand%s",
    176  1.1.1.2  cgd 					    lflag ? " " : "",
    177  1.1.1.2  cgd 					    lflag ? " " : "\n");
    178  1.1.1.2  cgd 				if (unit(flen, fraction)) {
    179  1.1.1.2  cgd 					if (lflag)
    180  1.1.1.2  cgd 						(void)printf(" ");
    181  1.1.1.2  cgd 					pfract(flen);
    182  1.1.1.2  cgd 					rval = 1;
    183      1.1  cgd 				}
    184      1.1  cgd 				break;
    185      1.1  cgd 			}
    186  1.1.1.2  cgd 	if (!rval)
    187  1.1.1.2  cgd 		(void)printf("zero%s", lflag ? "" : ".\n");
    188  1.1.1.2  cgd 	if (lflag)
    189  1.1.1.2  cgd 		(void)printf("\n");
    190      1.1  cgd }
    191      1.1  cgd 
    192  1.1.1.2  cgd int
    193  1.1.1.2  cgd unit(len, p)
    194  1.1.1.2  cgd 	register int len;
    195  1.1.1.2  cgd 	register char *p;
    196      1.1  cgd {
    197  1.1.1.2  cgd 	register int off, rval;
    198      1.1  cgd 
    199  1.1.1.2  cgd 	rval = 0;
    200      1.1  cgd 	if (len > 3) {
    201      1.1  cgd 		if (len % 3) {
    202      1.1  cgd 			off = len % 3;
    203      1.1  cgd 			len -= off;
    204  1.1.1.2  cgd 			if (number(p, off)) {
    205  1.1.1.2  cgd 				rval = 1;
    206  1.1.1.2  cgd 				(void)printf(" %s%s",
    207  1.1.1.2  cgd 				    name3[len / 3], lflag ? " " : ".\n");
    208      1.1  cgd 			}
    209  1.1.1.2  cgd 			p += off;
    210      1.1  cgd 		}
    211  1.1.1.2  cgd 		for (; len > 3; p += 3) {
    212      1.1  cgd 			len -= 3;
    213  1.1.1.2  cgd 			if (number(p, 3)) {
    214  1.1.1.2  cgd 				rval = 1;
    215  1.1.1.2  cgd 				(void)printf(" %s%s",
    216  1.1.1.2  cgd 				    name3[len / 3], lflag ? " " : ".\n");
    217      1.1  cgd 			}
    218      1.1  cgd 		}
    219      1.1  cgd 	}
    220  1.1.1.2  cgd 	if (number(p, len)) {
    221  1.1.1.2  cgd 		if (!lflag)
    222  1.1.1.2  cgd 			(void)printf(".\n");
    223  1.1.1.2  cgd 		rval = 1;
    224      1.1  cgd 	}
    225  1.1.1.2  cgd 	return (rval);
    226      1.1  cgd }
    227      1.1  cgd 
    228  1.1.1.2  cgd int
    229  1.1.1.2  cgd number(p, len)
    230  1.1.1.2  cgd 	register char *p;
    231  1.1.1.2  cgd 	int len;
    232      1.1  cgd {
    233  1.1.1.2  cgd 	register int val, rval;
    234      1.1  cgd 
    235  1.1.1.2  cgd 	rval = 0;
    236  1.1.1.2  cgd 	switch (len) {
    237      1.1  cgd 	case 3:
    238  1.1.1.2  cgd 		if (*p != '0') {
    239  1.1.1.2  cgd 			rval = 1;
    240  1.1.1.2  cgd 			(void)printf("%s hundred", name1[*p - '0']);
    241      1.1  cgd 		}
    242  1.1.1.2  cgd 		++p;
    243  1.1.1.2  cgd 		/* FALLTHROUGH */
    244      1.1  cgd 	case 2:
    245  1.1.1.2  cgd 		val = (p[1] - '0') + (p[0] - '0') * 10;
    246      1.1  cgd 		if (val) {
    247  1.1.1.2  cgd 			if (rval)
    248  1.1.1.2  cgd 				(void)printf(" ");
    249      1.1  cgd 			if (val < 20)
    250  1.1.1.2  cgd 				(void)printf("%s", name1[val]);
    251      1.1  cgd 			else {
    252  1.1.1.2  cgd 				(void)printf("%s", name2[val / 10]);
    253      1.1  cgd 				if (val % 10)
    254  1.1.1.2  cgd 					(void)printf("-%s", name1[val % 10]);
    255      1.1  cgd 			}
    256  1.1.1.2  cgd 			rval = 1;
    257      1.1  cgd 		}
    258      1.1  cgd 		break;
    259      1.1  cgd 	case 1:
    260  1.1.1.2  cgd 		if (*p != '0') {
    261  1.1.1.2  cgd 			rval = 1;
    262  1.1.1.2  cgd 			(void)printf("%s", name1[*p - '0']);
    263      1.1  cgd 		}
    264      1.1  cgd 	}
    265  1.1.1.2  cgd 	return (rval);
    266      1.1  cgd }
    267      1.1  cgd 
    268  1.1.1.2  cgd void
    269      1.1  cgd pfract(len)
    270  1.1.1.2  cgd 	int len;
    271      1.1  cgd {
    272  1.1.1.2  cgd 	static char *pref[] = { "", "ten-", "hundred-" };
    273      1.1  cgd 
    274      1.1  cgd 	switch(len) {
    275      1.1  cgd 	case 1:
    276  1.1.1.2  cgd 		(void)printf("tenths.\n");
    277      1.1  cgd 		break;
    278      1.1  cgd 	case 2:
    279  1.1.1.2  cgd 		(void)printf("hundredths.\n");
    280      1.1  cgd 		break;
    281      1.1  cgd 	default:
    282  1.1.1.2  cgd 		(void)printf("%s%sths.\n", pref[len % 3], name3[len / 3]);
    283  1.1.1.2  cgd 		break;
    284      1.1  cgd 	}
    285      1.1  cgd }
    286      1.1  cgd 
    287  1.1.1.2  cgd void
    288  1.1.1.2  cgd usage()
    289      1.1  cgd {
    290  1.1.1.2  cgd 	(void)fprintf(stderr, "usage: number [# ...]\n");
    291  1.1.1.2  cgd 	exit(1);
    292      1.1  cgd }
    293