Převod čísel

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
 
const char rimsky[]={'I','V','X','L','C','D','M','S','Q'};
char *in=NULL;
 
unsigned int readLine(char **pLine, unsigned int *N, FILE *stream);
 
//arabsky na rimsky
char ar(void) {
  unsigned int len;
  unsigned int delka = readLine(&in, &len, stdin);
  if (delka==1) {
    fprintf(stderr,"CHYBA: Nic nezadano!\n");
    free(in);
    return EXIT_FAILURE;
  }
  short nuly=0;
 
  //nejdriv zjistime jestli je zadane cislo, a je ve spravnem rozsahu...
  for (short pozice_v_cisle=delka; pozice_v_cisle>1; pozice_v_cisle--) {
    char cislice=in[delka-pozice_v_cisle]; //potrebujem to brat odzadu (jinak dostanem EOF a je to v ...)
 
    //kontrola jestli bylo zadano cislo
    if (cislice<'0' || cislice>'9') {
      fprintf(stderr,"CHYBA: Spatne zadani (%c neni cislice)!\n", cislice); //trosku paradoxni pojmenovani promenne :)
      free(in);
      return EXIT_FAILURE;
    }
 
    //kontrola jestli nebyla zadana nula
    if (cislice=='0') {
      nuly++;
      if (nuly==delka-1) {
        fprintf(stderr,"CHYBA: Spatne zadani (0)!\n");
        free(in);
        return EXIT_FAILURE;
      }
    }
  }
 
  //...a teprve potom zacnem neco resit
  for (short pozice_v_cisle=delka; pozice_v_cisle>1; pozice_v_cisle--) {
    char cislice=in[delka-pozice_v_cisle];
    short pozice_v_poli=(pozice_v_cisle-2)*2; //cerna magie, ale funguje :)
    if (cislice>'3' && pozice_v_poli+1>8) {
      fprintf(stderr,"CHYBA: Spatne zadani (overflow)!\n");
      free(in);
      return EXIT_FAILURE;
    }
 
    //pokud je vstup mensi jak 4 (a vetsi jak 0)
    if (cislice<'4' && cislice>'0') {
      for (short i=cislice; i>'0'; i--){
        printf("%c",rimsky[pozice_v_poli]); //napis tolikrat I
      }
    }
 
    //kdyz je 4 (tak trosku vyjimka)
    if (cislice=='4') printf("%c%c",rimsky[pozice_v_poli],rimsky[pozice_v_poli+1]);
 
    //kdyz je vstup v rozsahu 5--8
    if (cislice>'4' && cislice<'9') {
      printf("%c",rimsky[pozice_v_poli+1]);
      for (short i=cislice-5; i>'0'; i--) {
        printf("%c",rimsky[pozice_v_poli]);
      }
    }
 
    //kdyz je vstup 9 (dalsi "vyjimka")
   if (cislice=='9') printf("%c%c",rimsky[pozice_v_poli],rimsky[pozice_v_poli+2]);
  }
  printf("\n"); // http://www.lamer.cz/quotes/show/12
  free(in);
  return EXIT_SUCCESS;
}
 
//rimsky na arabsky
char ra(void) {
  unsigned int len;
  unsigned int delka = readLine(&in, &len, stdin);
  if (delka==1) {
    fprintf(stderr,"CHYBA: Nic nezadano!\n");
    free(in);
    return EXIT_FAILURE;
  }
  short last=SHRT_MAX; //zaloz promennou pro predchozi
  short arab=0; //soucet vsech cisel je zatim 0
  short hodnota=0; //na pocatku nebylo nic
  for (short i=0; i<delka-1; i++) { //zacneme projizdet vstup
    switch(in[i]) { //zjistime s jakym cislem mame tu cest
      case 'I': hodnota=1; break;
      case 'V': hodnota=5; break;
      case 'X': hodnota=10; break;
      case 'L': hodnota=50; break;
      case 'C': hodnota=100; break;
      case 'D': hodnota=500; break;
      case 'M': hodnota=1000; break;
      case 'S': hodnota=5000; break;
      case 'Q': hodnota=10000; break;
      default: fprintf(stderr,"CHYBA: Spatne zadani! (%c neni rimska cislice)\n",in[i]); free(in); return EXIT_FAILURE; //kdyz z zadnym z vyse uvedenych, tak skoncime chybou
    }
 
    if (i>=3 && in[i]==in[i-3] && in[i-1]==in[i-2] && in[i]==in[i-1]) { //pokud jde vice jak 3 stejne znaky za sebou (treba IIII)
      fprintf(stderr,"CHYBA: Spatne zadani! (IIII)\n");
      free(in);
      return EXIT_FAILURE;
    }
 
    if (hodnota>last) { //pokud se odecita
      if (hodnota/last!=10 && hodnota/last!=5) { //dosel jsem ke zjisteni, ze pokazde kdyz ma byt odcitani platne, tak podil tech zadanych cisel je 5 nebo 10... tim se osetri chyby jako IC nebo IMM... velky dik za toto zjisteni patri me pritelkyni, ktery me k teto myslence inspirovala. :)
        fprintf(stderr,"CHYBA: Spatne zadani! (IMM)\n");
        free(in);
        return EXIT_FAILURE;
      }
      if (i>=2 && in[i-1]==in[i-2]) { //osetreni proti IIV a podobnym
        fprintf(stderr,"CHYBA: Spatne zadani! (IIV)\n");
        free(in);
        return EXIT_FAILURE;
      }
      if (i>=1 && in[i-1]==in[i+1]) { //osetreni proti IVI a podobnym
        fprintf(stderr,"CHYBA: Spatne zadani! (IVI)\n");
        free(in);
        return EXIT_FAILURE;
      }
      arab+=hodnota-2*last;
    }
    else arab+=hodnota;
    last=hodnota;
  }
  if (arab<0) {
      fprintf(stderr,"CHYBA: Spatne zadani (overflow)!\n");
      free(in);
      return EXIT_FAILURE;
    }
  printf ("%d\n",arab);
  free(in);
  return EXIT_SUCCESS;
}
 
int main(int argc, char *argv[]) {
  if (argc == 1 || (argc == 2 && strcmp("-h", argv[1]) == 0)) printf("Sepsal a v hlavni rohli sehral xkalab00\n\n-ar  Prevod z arabskych na rimska cisla\n-ra  Prevod z rimskych na arabska cisla\n-aa  Prevod z arabskych na arabska cisla (kontrola zapisu)\n-rr  Prevod z rimskych na rimska cisla (kontrola zapisu)\n");
  if (argc == 2 && strcmp("-ar", argv[1])==0) ar();
  if (argc == 2 && strcmp("-ra", argv[1])==0) ra();
  if (argc == 2 && strcmp("-aa", argv[1])==0) {
    fprintf(stderr,"CHYBA: Neimplementovana operace!\n");
    return EXIT_FAILURE;
    }
  if (argc == 2 && strcmp("-rr", argv[1])==0) {
    fprintf(stderr,"CHYBA: Neimplementovana operace!\n");
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
 
// Martinkovy bloky kodu
 
inline void testAlloc(void *ptr)
{
  if (ptr == NULL)
  { // vypise na standardni chybovy vystup chybovou hlasku.
    fprintf(stderr, "CHYBA: Nedostatek pameti!\n");
    exit(EXIT_FAILURE);
  }
} // testAlloc()
 
unsigned int readLine(char **pLine, unsigned int *N, FILE *stream)
{
 
  const int B_INCREMENT = 16;
  int blockSize = *N;
 
  if (*pLine == NULL)
  { // uzivatel nic nealokoval
    blockSize = B_INCREMENT;
    *pLine = malloc(blockSize*sizeof(char));
     testAlloc(*pLine);
  }
 
  int c;
  int i = 0;
 
  while ((c = getc(stream)) != EOF && c != '\n')
  {
    (*pLine)[i] = c;
    i += 1;
    if ((i % blockSize) == 0)
    { // pokud je na konci bloku, je potreba jej natahnout
      blockSize += B_INCREMENT;
      *pLine = realloc(*pLine, blockSize);
      testAlloc(*pLine);
    }
  }
 
  // Pozor! Pole predavane odkazem se musi indexovat takto. Bez zavorky
  // bychom indexovali pole ukazatelu, protoze operator * ma nizsi prioritu
  // nez [].
  (*pLine)[i] = '\0'; // na zaver je potreba retezec spravne ukoncit
 
  *N = blockSize;
 
  return i+1; // vraci delku retezce
}