/* This file is part of GDBM test suite. Copyright (C) 2011, 2017-2018 Free Software Foundation, Inc. GDBM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GDBM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GDBM. If not, see . */ #include "autoconf.h" #include #include #include #include #include const char *progname; const char *nstr[][10] = { { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }, { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }, { NULL, NULL, "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" } }; const char *short_scale[] = { "one", "thousand", "million", "billion" /* End of range for 32-bit unsigned long */ }; size_t short_scale_max = sizeof (short_scale) / sizeof (short_scale[0]); char buffer[1024]; size_t bufsize = sizeof(buffer); size_t bufoff; int delim = 0; void copy (const char *str, int dch) { size_t len = strlen (str); if (len + !!dch > bufoff) abort (); if (dch) buffer[--bufoff] = dch; bufoff -= len; memcpy (buffer + bufoff, str, len); delim = ' '; } void format_100 (unsigned long num) { if (num == 0) ; else if (num < 10) copy (nstr[0][num], delim); else if (num < 20) copy (nstr[1][num-10], delim); else { unsigned long tens = num / 10; num %= 10; if (num) { copy (nstr[0][num], delim); copy ("-", 0); copy (nstr[2][tens], 0); } else copy (nstr[2][tens], delim); } } void format_1000 (unsigned long num, int more) { size_t n = num % 100; num /= 100; format_100 (n); more |= num != 0; if (n && more) copy ("and", delim); if (num) { copy ("hundred", delim); copy (nstr[0][num], delim); } } void format_number (unsigned long num) { int s = 0; size_t off; bufoff = bufsize; buffer[--bufoff] = 0; off = bufoff; delim = 0; do { unsigned long n = num % 1000; num /= 1000; if (s > 0 && ((n && off > bufoff) || num == 0)) copy (short_scale[s], delim); s++; if (s > short_scale_max) abort (); format_1000 (n, num != 0); } while (num); if (bufoff + 1 == bufsize) copy (nstr[0][0], 0); } void print_number (unsigned long num) { format_number (num); printf ("%lu\t%s\n", num, buffer + bufoff); } void print_range (unsigned long num, unsigned long to) { for (; num <= to; num++) print_number (num); } unsigned long xstrtoul (char *arg, char **endp) { unsigned long num; char *p; errno = 0; num = strtoul (arg, &p, 10); if (errno) { fprintf (stderr, "%s: invalid number: ", progname); perror (arg); exit (2); } if (endp) *endp = p; else if (*p) { fprintf (stderr, "%s: invalid number (near %s)\n", progname, p); exit (2); } return num; } int main (int argc, char **argv) { progname = argv[0]; if (argc == 1 || strcmp (argv[1], "-h") == 0) { printf ("usage: %s NUM [NUM...]\n", progname); printf ("where NUM is a decimal number, NUM:COUNT or NUM-NUM\n"); exit (0); } while (--argc) { char *arg = *++argv; unsigned long num, num2; char *p; num = xstrtoul (arg, &p); if (*p == 0) print_number (num); else if (*p == ':') { *p++ = 0; num2 = xstrtoul (p, NULL); if (num2 == 0) { fprintf (stderr, "%s: invalid count\n", progname); exit (2); } print_range (num, num + num2 - 1); } else if (*p == '-') { *p++ = 0; num2 = xstrtoul (p, NULL); if (num2 < num) { fprintf (stderr, "%s: invalid range: %lu-%lu\n", progname, num, num2); exit (2); } print_range (num, num2); } else { fprintf (stderr, "%s: invalid argument\n", progname); exit (2); } } exit (0); }