/*
* Soubor: proj1.c
* Datum: 9.11.2004
* Autor: Kamil Dudka, xdudka00@stud.fit.vutbr.cz
*
* Prosím, neodevzdávejte zdrojové kódy, které jsou zde k dispozici,
* jako Vaše školní projekty. Děkuji :-)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DELKA 33 // Staci pro nacteni cisla ULONG_MAX ve dvojkove soustave (retezec je ukoncen nulou)
#define CHYBA_VSTUPU 64 // Musi byt vzdy vetsi nez zaklad soustavy
#define CHYBA_PRETECENI 128 // Musi byt vzdy vetsi nez zaklad soustavy
// Prototypy pouzitych funkci
unsigned int ctiVSoustave (char *, unsigned int, unsigned int);
int doDesitkove (unsigned long *, char *, unsigned int);
int zDesitkove (char *, unsigned long, unsigned int, unsigned int);
unsigned char cisloZCifry (unsigned char);
unsigned char cifraZCisla (unsigned char);
void otocRetezec (char *);
// Hlavni program
int main (int argc, char *argv[])
{
unsigned long zakladVstup;
unsigned long zakladVystup;
unsigned long desitkovaSoustava;
char jinaSoustava [DELKA];
unsigned int kodChyby = EXIT_SUCCESS; // nebyla zjistena zadna chyba
// Osetreni poctu vstupnich parametru
if (argc<3)
{ // Pokud je zadano mene nez dva parametry vypise se help - vyhnu se tim zbytecnym chybam a splnuje to zadani !!!
printf("Program císelné soustavy.\n"
"Autor: Kamil Dudka\n"
"Program provádí prevody mezi císelnými soustavami. císlo, které\n"
"má program zpracovat se nacítá ze standardního vstupu.\n"
"Pou?ití: proj1 -h\n"
" proj1 Z1 Z2\n"
"Popis parametr?:\n"
" -h Vypíse tuto obrazovku s nápov?dou.\n"
" Z1 Základ císelné soustavy vstupního císla (2-36).\n"
" Z2 Základ císelné soustavy výstupního císla (2-36).\n"
);
return EXIT_FAILURE;
}
if (argc>3)
{
fprintf (stderr,"Prilis mnoho parametru!\n");
return EXIT_FAILURE;
}
// Ostereni prvniho parametru
if (0 != doDesitkove (&zakladVstup, argv[1], 10)) // Prevod retezce na cislo - vyuzivam stejny podprogram jako pro prevod
{
fprintf (stderr,"Neplatny parametr 1!\n");
kodChyby = EXIT_FAILURE;
}
else if ((zakladVstup<2)|(zakladVstup>36))
{
fprintf (stderr,"Neplatny zaklad ciselne soustavy pro vstupni hodnotu\n");
kodChyby = EXIT_FAILURE;
}
// Ostereni druheho parametru
if (0 != doDesitkove (&zakladVystup, argv[2], 10)) // Prevod retezce na cislo - vyuzivam stejny podprogram jako pro prevod
{
fprintf (stderr,"Neplatny parametr 2!\n");
kodChyby = EXIT_FAILURE;
}
else if ((zakladVystup<2)|(zakladVystup>36))
{
fprintf (stderr,"Neplatny zaklad ciselne soustavy pro vystupni hodnotu\n");
kodChyby = EXIT_FAILURE;
}
// Pokud byla zjistena nejaka chyba, program skonci
if (kodChyby == EXIT_FAILURE)
return EXIT_FAILURE;
// Nacteni vstupniho cisla
if (0==ctiVSoustave (jinaSoustava, DELKA, zakladVstup))
{
fprintf(stderr,"Chyba vstupu\n");
return EXIT_FAILURE;
}
// Prevod cisla do desitkove soustavy
kodChyby = doDesitkove (&desitkovaSoustava, jinaSoustava, zakladVstup);
if (kodChyby != 0)
{ // behem prevodu doslo k chybe
if (kodChyby==CHYBA_VSTUPU)
fprintf(stderr,"Chyba vstupu!\n");
if (kodChyby==CHYBA_PRETECENI)
fprintf(stderr,"Chyba preteceni\n");
return EXIT_FAILURE;
}
// Prevod cisla z desitkove soustavy
if (0!= zDesitkove (jinaSoustava, desitkovaSoustava, zakladVystup, DELKA))
{ // behem prevodu doslo k chybe
fprintf (stderr,"Chyba preteceni!\n");
return EXIT_FAILURE;
}
printf ("%s\n",jinaSoustava);
return EXIT_SUCCESS; // K zadne chybe nedoslo
}
// Cteni vstupniho cisla v dane soustave - vraci pocet nactenych znaku
unsigned int ctiVSoustave (char *jinaSoustava, unsigned int delka, unsigned int zaklad)
{
int znak; // pro znak je zvolen typ int aby bylo mozno detekovat znak EOF
unsigned int i=0; // inkrementacni promennou budu potrebovat i vne cyklu FOR
// cylkus nacte cislo po jednom znaku a u kazdeho kontroluje jestli je platny pro danou soustavu
while (i<delka-1)
{
znak = getchar ();
// ukonceni cyklu
if ((znak=='\n')|(znak==EOF))
break;
// kontrola znaku
if (cisloZCifry ((char) znak) >= zaklad) // hodnota CHBYBA_VSTUPU musi byt samozrejme taky vetsi nez zaklad - tim usetrim jednu podminku
return 0;
// vlastni zapis znaku do pameti a inkrementace ukazatele
jinaSoustava[i]=znak;
i++;
}
// zakonceni retezce nulou (kontroluji velikost zasobniku predanou parametrem "delka")
if (delka>0)
jinaSoustava[i] = 0;
return i;
}
// Prevod do desitkove soustavy
int doDesitkove (unsigned long *vystup, char *vstup, unsigned int zaklad)
{
// inicializace promennych
unsigned long stradac;
unsigned long nasobitel = 1; // Zacnu od cifry z nejnizsi hodnotou, tj. Z na nultou je vzdy 1
unsigned long proKontrolu = 0; // pomocna promenna pro kontrolu preteceni jednotlivyc operaci
int nasobitelPretekl = 0;
*vystup = 0;
// Hlavni cyklus prevodu - zacinam od cifry z nejnizsi hodnotou
for (int i = strlen (vstup) - 1; i >= 0; i--)
{
// kontrola preteceni nasobitele
if (nasobitel/zaklad != proKontrolu)
nasobitelPretekl = 1;
// nacteni hodnoty aktualni cifry
if ((proKontrolu = stradac = cisloZCifry (vstup[i]))!=0)
{ // pokud je aktualni cifra rovna nule, tak nemusim resp. nemuzu spoustu veci vubec testovat
// kontrola preteceni nasobitele z predchoziho kroku - tim umoznim zpracovani cisla pred kterym je hodne nul
if (nasobitelPretekl)
return CHYBA_PRETECENI;
// Neplata vstupni data - cyklus se okamzite ukonci
if ((stradac == CHYBA_VSTUPU)|(stradac >= zaklad))
return CHYBA_VSTUPU;
// kontroluji jestli neni cislo stradac*nasobitel mimo rozsah unsigned long
stradac *= nasobitel;
if (stradac/proKontrolu != nasobitel)
return CHYBA_PRETECENI;
}
// hodnotu cisla *vystup z predchoziho kroku si ulozim do promenne
proKontrolu = *vystup;
// kontorluji preteceni vystupni promenne
*vystup += stradac;
if (*vystup < proKontrolu)
return CHYBA_PRETECENI;
proKontrolu = nasobitel;
nasobitel *= zaklad; // Z kazdou dalsi cifrou zvysim mocninu zakladu (nasobitel)
}
return EXIT_SUCCESS;
}
// Funkce vraci cislo, ktere cifra predstavuje, pro neplatnou cifru vraci hodnotu CHYBA_VSTUPU
unsigned char cisloZCifry (unsigned char cifra)
{
if (cifra<'0')
return CHYBA_VSTUPU;
// cislo
if (cifra<='9')
return cifra-'0';
if (cifra<'A')
return CHYBA_VSTUPU;
// velke pismeno
if (cifra<='Z')
return cifra-'A'+10;
if (cifra<'a')
return CHYBA_VSTUPU;
// male pismeno
if (cifra<='z')
return cifra-'a'+10;
return CHYBA_VSTUPU;
}
// Funkce prevadi cislo z desitkove soustavy
int zDesitkove (char *vystup, unsigned long vstup, unsigned int zaklad, unsigned int delka)
{
unsigned int i=0; // Inkrementacni promenna - budu ji pouzivat i mimo cyklus
do {
// kontrola rozsahu pole pro vystupni data (jeden znak si rezervuji jako ukoncovaci)
if (i<delka-1)
{
vystup[i] = cifraZCisla (vstup % zaklad); // zbytek po deleni zakladem prevedu o5 na znak a ulizim do danne cifry
vstup /= zaklad;
}
else
{ // vysledek je neplatny - cyklus skonci
vystup[i] = 0;
return CHYBA_PRETECENI;
}
i++;
} while (vstup>0);
vystup[i]=0; // vznikly retezec zakonci nulou
otocRetezec (vystup); // pro spravne zobrazeni cisla je treba retezec otocit
return EXIT_SUCCESS;
}
// Funkce vraci znak odpovidajicimu zadanemu cislu
unsigned char cifraZCisla (unsigned char cislo)
{
// pro hodnotu >35 funkce vraci nulu - k tomu prakticky nikdy nedojde
if (cislo>35)
return 0;
// provede vypocet podle toho jestli se jedna o cislici nebo pismenko
if (cislo>9)
return cislo+'A'-10;
else
return cislo+'0';
}
// Funkce otaci retezec dany ukazatelem - funkce neni zadnym zpusobem optimalizovana !!!
void otocRetezec (char *retezec)
{
unsigned int delka = strlen(retezec); // Delku retezce zjistuje jen jednou a to na zacatku funkce
unsigned int i;
for (i=0; i<(delka/2); i++) // cyklus se provede jen s polovicnim poctem cyklu nez je delka retezce
{
// vlastni vymena dvou prvku
retezec[i] ^= retezec[delka-i-1];
retezec[delka-i-1] ^= retezec[i];
retezec[i] ^= retezec[delka-i-1];
}
}