number.c 6.4 KB

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