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