#include #include #include #include #include #define PROG_NAME "numericx" /* ||COMPILATION FLAGS|| */ /* * Show debug message of step by step * incrementation of the number */ #ifndef DEBUG #define DEBUG false #endif /* * Configuration of the corresponding numeral system * to have the units place of the end (on the right) */ #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 /* * Configuration of the corresponding numeral system * to start counting on the second number, being the * first number void */ #ifndef TO_FIRST_NUMBER_VOID #define TO_FIRST_NUMBER_VOID false #endif #ifndef FROM_FIRST_NUMBER_VOID #define FROM_FIRST_NUMBER_VOID false #endif /* Configuration of the corresponding numeral system * to have the first number as an infinite number, * for example, if the first number is 'A', then * A == AA == AAA == AAAA ... */ #ifndef TO_INFINITE_BASE #define TO_INFINITE_BASE false #endif #ifndef FROM_INFINITE_BASE #define FROM_INFINITE_BASE false #endif /* ||DATA STRUCTURE|| */ typedef struct NumeralPtr { char const* symbol; struct NumeralPtr *next; struct NumeralPtr *previous; } numeral_ptr; /* ||FUNCTIONS|| */ /* * Creates new digit for numeral_ptr. * It needs the last_numeral ('last_numeral') into which will * add the new numeral, and also need to know the symbol of the * new numeral ('to_first'). * * 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; } /* * Creates a number of the form numeral_ptr that * begins with 'case' number of cases, and all cases * are set to 'to_first' char. * * Returns pointer to numeral_ptr. * Returns NULL in case of no memory (because depends * on new_digit() ). */ 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; } /* Increments numeral_ptr 'numeral' one unit up. * It needs 'num_first' as the first numeral of the numerical * system. Also needs 'num_last' as the last numeral of the * numerical system. * If incrementing, the function adds a new digit/numeral, it * will use the 'brand_new_digit' as its numeral/digit. */ 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); } /* * Decrements a string 'number' by one unit. * It needs to know the first numeral ('first_numeral') and also the * last numeral ('last_numeral'). It also needs the numeral system in * form of a string ('numeral_system') to know which is the numeral * before the actual numeral that needs decrementation. */ void decrement_number_string(char* number, char* first_numeral, char* last_numeral, char* numeral_system) { while( *number == *first_numeral ) { *number = *last_numeral; ++number; } if( *number == '\0' ) { *(--number) = '\0'; } else { while( !(*numeral_system == *number) ) ++numeral_system; *number = *(--numeral_system); } } /* * Compares if a numeral_ptr ('numeral') matches the string ('number_arg'). * * Return true if matches, false if numeral_ptr doesn't match the string. */ 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; } /* * Prints to standard output numeral_ptr ('numeral'). */ 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; } } } /* * Reverse a string. */ 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; } } /* * Check if string 'number' belongs to the numerical * system ('numeral_system'), which is also a string. * Belonging mean all the symbols of 'number' are included * in 'numeral_system'. * * Return true if it belongs, false otherwise. */ 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; } /* * Free up numeral_ptr ('numeral'). */ void free_numeral(numeral_ptr* numeral) { numeral_ptr* tmp = NULL; while( !(numeral == NULL) ) { tmp = numeral->next; free(numeral); numeral = tmp; } } /* ||MAIN FUNCTION|| */ int main(int argc, char* argv[]) { /* argument processing */ if( !(argc == 2) ) { fprintf(stderr, "usage: %s \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; }