numericx/numericx.c

331 lines
6.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#define PROG_NAME "numericx"
#ifndef DEBUG
#define DEBUG false
#endif
#ifndef TO_UNITS_ON_THE_END
#define TO_UNITS_ON_THE_END false
#endif
#ifndef FROM_UNITS_ON_THE_END
#define FROM_UNITS_ON_THE_END false
#endif
#ifndef TO_FIRST_NUMBER_VOID
#define TO_FIRST_NUMBER_VOID false
#endif
#ifndef FROM_FIRST_NUMBER_VOID
#define FROM_FIRST_NUMBER_VOID false
#endif
#ifndef TO_INFINITE_BASE
#define TO_INFINITE_BASE false
#endif
#ifndef FROM_INFINITE_BASE
#define FROM_INFINITE_BASE false
#endif
typedef struct NumeralPtr
{
char const* symbol;
struct NumeralPtr *next;
struct NumeralPtr *previous;
} numeral_ptr;
/*
* Creates new digit for numeral_ptr
* Return pointer to new numeral_ptr
* Returns NULL in case of no memory
*/
numeral_ptr*
new_digit(numeral_ptr* last_numeral, char const* to_first)
{
numeral_ptr* starting_point = malloc(sizeof(numeral_ptr));
if(starting_point == NULL)
{
fprintf(stderr, "error: %s: %s!", PROG_NAME, strerror(ENOMEM));
return NULL;
}
starting_point->symbol = to_first;
starting_point->previous = last_numeral;
starting_point->next = NULL;
return starting_point;
}
numeral_ptr*
numeral_infinity(char const* to_first, size_t cases)
{
numeral_ptr* starting_case = new_digit(NULL, to_first);
numeral_ptr* other_case = starting_case;
for(size_t i = 2; i <= cases; ++i)
{
other_case->next = new_digit(other_case, to_first);
other_case = other_case->next;
}
return starting_case;
}
void
increment(numeral_ptr* numeral, char* num_first, char* num_last, char* brand_new_digit)
{
bool cycled = false;
if( numeral->symbol == num_last )
{
if( numeral->next == NULL )
numeral->next = new_digit(numeral, brand_new_digit);
else
increment(numeral->next, num_first, num_last, brand_new_digit);
cycled = true;
}
if( cycled )
numeral->symbol = num_first;
else
++(numeral->symbol);
}
void
decrement_number_string(char* number, char* first_number, char* last_number, char* numeral_system)
{
while( *number == *first_number )
{
*number = *last_number;
++number;
}
if( *number == '\0' )
{
*(--number) = '\0';
}
else
{
while( !(*numeral_system == *number) )
++numeral_system;
*number = *(--numeral_system);
}
}
bool
is_the_same(numeral_ptr* numeral, char* number_arg)
{
while( !(numeral == NULL) )
{
if( *(numeral->symbol) == *(number_arg) )
{
numeral = numeral->next;
++(number_arg);
continue;
}
return false;
}
return (*number_arg == '\0') ? true : false;
}
void
print_numeral(numeral_ptr* numeral)
{
if( TO_UNITS_ON_THE_END )
{
while( !(numeral->next == NULL) )
numeral = numeral->next;
while( !(numeral == NULL) )
{
printf("%c", *(numeral->symbol));
numeral = numeral->previous;
}
}
else
{
while( !(numeral == NULL) )
{
printf("%c", *(numeral->symbol));
numeral = numeral->next;
}
}
}
void
reverse_string(char* string)
{
char tmp;
char* string_end = string + strlen(string);
while ( --string_end > string )
{
tmp = *string;
*string++ = *string_end;
*string_end = tmp;
}
}
bool
is_valid_number(char* numeral_system, char *number)
{
/*
if( *number == '-' || *number == '+' )
++number;
*/
while( !(*number == '\0') )
{
if( strchr(numeral_system, *number) == NULL )
return false;
++number;
}
return true;
}
void
free_numeral(numeral_ptr* numeral)
{
numeral_ptr* tmp = NULL;
while( !(numeral == NULL) )
{
tmp = numeral->next;
free(numeral);
numeral = tmp;
}
}
int
main(int argc, char* argv[])
{
/* argument processing */
if( !(argc == 2) )
{
fprintf(stderr, "usage: %s <number>\n", PROG_NAME);
exit(EXIT_FAILURE);
}
/* Numeral System variables from MACROS */
char* from = malloc( (strlen(FROM_NUMERICALS) + 1) * sizeof(char) );
char* to = malloc( (strlen(TO_NUMERICALS) + 1) * sizeof(char) );
strcpy(from, FROM_NUMERICALS);
strcpy(to, TO_NUMERICALS);
/* Number variables to be converted */
char* number = argv[1];
/* Check if number belongs to it's numerical system */
if( !is_valid_number(from, number) )
{
fprintf(stderr, "error: %s: %s.\nValid numerals are: \"%s\"\n",
PROG_NAME, strerror(EDOM), from);
free(from);
free(to);
exit(EDOM);
}
/* _first and _last variables */
char* from_first = from;
char* from_last = from + (strlen(from) - 1);
char* to_first = to;
char* to_last = to + (strlen(to) - 1);
if( FROM_UNITS_ON_THE_END )
{
reverse_string(number);
}
/* initializing counting and result */
numeral_ptr* counting = NULL;
numeral_ptr* result = NULL;
if( FROM_INFINITE_BASE )
counting = numeral_infinity(from_first, strlen(number));
else
counting = numeral_infinity(from_first, 1);
result = numeral_infinity(to_first, 1);
/* first number void */
if( !(FROM_FIRST_NUMBER_VOID && TO_FIRST_NUMBER_VOID) )
{
if( FROM_FIRST_NUMBER_VOID )
{
if( strlen(number) == 1 && *number == *from_first )
{
free(from);
free(to);
free_numeral(counting);
free_numeral(result);
fprintf(stderr, "error: %s: unrepresentable void number\n", PROG_NAME);
exit(EXIT_FAILURE);
}
decrement_number_string(number, from_first, from_last, from_first);
}
if( TO_FIRST_NUMBER_VOID )
increment(result, to_first, to_last, to_first);
}
/* minor optimization for the cycle below */
char* to_second = NULL;
if( TO_INFINITE_BASE )
to_second = to_first + 1;
/* increments until it finishes */
while( !is_the_same(counting, number) )
{
if(DEBUG)
print_numeral(result);
if( TO_INFINITE_BASE )
increment(result, to_first, to_last, to_second);
else
increment(result, to_first, to_last, to_first);
if(DEBUG)
{
printf(" | ");
print_numeral(counting);
printf("\n");
}
increment(counting, from_first, from_last, from_first);
}
/* print */
if(DEBUG)
{
print_numeral(result);
printf(" | ");
print_numeral(counting);
printf("\n");
}
print_numeral(result);
printf("\n");
/* free memory */
free(from);
free(to);
free_numeral(counting);
free_numeral(result);
return EXIT_SUCCESS;
}