Převod římských čísel na arabská a naopak - roman.c

#include <stdio.h>
#include <ctype.h>      // toupper
#include <stdlib.h>     // strtoul
#include <string.h>     // strchr



// Prevodni tabulky
//
#define  SROMT_INIT     "I" "V" "X" "L"  "C"  "D"  "M"
#define  SVALT_INIT     {1,  5,  10, 50, 100, 500, 1000}
//
static char const       sromt[] = SROMT_INIT;


// Maximalni velikost bufferu cislic
//
#define  RESULT_SIZE    40



/*============================================================================*\
                                RIMSKE --> ARABSKE
\*============================================================================*/


/*
 * ZJISTENI POCTU PREDCHOZICH CISLIC S MENSI HODNOTOU
 */

static int r2a_prevlessnum(int result[],
                           int ridx)
{
    int     resval,
            number;

    resval = result[ridx];
    number = 0;
    do
    {
        int     preval;

        preval = result[--ridx];
        if( preval < 0)
            preval = -preval;
        if(resval > preval)
            ++number;
    } while(ridx > 0);
    return(number);
}



/*
 * VSTUPNI BOD
 */

static void r2a(char const *valup)
{
    int                 ridx,
                        result[RESULT_SIZE];
    char const          *fndp;
    static int  const   svalt[] = SVALT_INIT;

    ridx = 0;
    do
    {
        int             sidx;

        if((fndp = strchr(sromt, toupper(*valup))) == NULL)
        {
            fprintf(stderr, "Unknown Digit: %s\n", valup);
            return;
        }
        sidx = fndp - sromt;
        result[ridx] = svalt[sidx];
        if(ridx > 0)
            switch(r2a_prevlessnum(result, ridx))
            {
            case 1:
                result[ridx - 1] = -result[ridx - 1];

            case 0:
                break;

            default:
                fprintf(stderr, "Unexpected Digit: %s\n", valup);
                return;
            }
        ++ridx;
    } while(*++valup != '\0');
    while(--ridx > 0)
        result[0] += result[ridx];
    printf("%d\n", result[0]);
}



/*============================================================================*\
                                ARABSKE --> RIMSKE
\*============================================================================*/


/*
 * VSTUPNI BOD
 */

static void a2r(unsigned value)
{
    unsigned    divisor;
    int         sidx,
                ridx;
    char        result[RESULT_SIZE];

    if(value - 1  >=  3999)
    {
        fprintf(stderr, "Bad Range: %u\n", value);
        return;
    }
    divisor = 1000;
    sidx = sizeof(sromt) / sizeof(*sromt) - 2;
    ridx = -1;
    do
    {
        unsigned    digit;

        digit = value / divisor;
        value -= digit * divisor;
        switch(digit)
        {
        case 4:
        case 9:
            result[++ridx] = sromt[sidx + 0];
            result[++ridx] = sromt[sidx + 1 + (digit == 9)];
            break;

        default:
            while(digit)
            {
                int     idx;

                idx = sidx;
                if(digit >= 5)
                {
                    ++idx;
                    digit -= 5 - 1;
                }
                result[++ridx] = sromt[idx];
                --digit;
            }
        }
        sidx -= 2;
    } while((divisor /= 10) > 0);
    result[ridx + 1] = '\0';
    puts(result);
}



/*============================================================================*\
                                    PROGRAM
\*============================================================================*/


/*
 * ZPRACOVANI JEDNOHO RETEZCE
 */

static void operate(char const *argp)
{
    unsigned    value;
    char        *endp;

    value = strtoul(argp, &endp, 10);
    if(*endp == '\0')
        a2r(value);
    else
        r2a(argp);
}



/*
 * VSTUPNI BOD
 */

int main(int argc, char *argv[])
{
    while(--argc > 0)
        operate(*++argv);
    return(0);
}