#include <ctype.h>
#include <stdio.h>
#include <string.h>

static int isValidNumber(const char *);

/*
 * Test harness for an implementation of the Luhn algorithm that checks the
 * validity of a credit card number.
 */
int
main(int argc, char *argv[])
{
    int i;

    if (argc < 2) {
        fprintf(stderr, "Usage: luhn <number>, ...\n");
        return 1;
    }

    for (i = 1; i < argc; ++i)
        printf("Number '%s' is%s a valid credit card number\n",
            argv[i], isValidNumber(argv[i]) ? "" : " not");

    return 0;
}

/*
 * Checks whether a string of digits is a valid credit card number according to
 * the Luhn algorithm.
 *
 * 1. Starting with the second to last digit and moving left, double the value
 *    of all the alternating digits. For any digits that thus become 10 or more,
 *    add their digits together. For example, 1111 becomes 2121, while 8763
 *    becomes 7733 (from (1+6)7(1+2)3).
 *
 * 2. Add all these digits together. For example, 1111 becomes 2121, then
 *    2+1+2+1 is 6; while 8763 becomes 7733, then 7+7+3+3 is 20.
 *
 * 3. If the total ends in 0 (put another way, if the total modulus 10 is 0),
 *    then the number is valid according to the Luhn formula, else it is not
 *    valid. So, 1111 is not valid (as shown above, it comes out to 6), while
 *    8763 is valid (as shown above, it comes out to 20).
 */
static int
isValidNumber(const char *number)
{
    int n, i, alternate, sum;

    if (!number)
        return 0;

    n = strlen(number);

    if (n < 13 || n > 19)
        return 0;

    for (alternate = 0, sum = 0, i = n - 1; i > -1; --i) {
        if (!isdigit(number[i]))
            return 0;

        n = number[i] - '0';

        if (alternate) {
            n *= 2;
            if (n > 9)
                n = (n % 10) + 1;
        }
        alternate = !alternate;

        sum += n;
    }

    return (sum % 10 == 0);
}
