about summary refs log blame commit diff stats
path: root/numericx.c
blob: 344e19de53a2de47c3123e87fdd7a340947968f3 (plain) (tree)
1
2
3
4
5
6
7
8





                    

                            






                                     
             


                   



                                                    
                           


                                 
                             


                                   




                                                    







                                    




                                                    







                                


                        






                                    


                   
  






                                                               






                                                                  
                                                                               









                                                








                                                     














                                                                   






                                                             
    
                                                                                       





                                           
                                                                            
                    
                                                                                       









                                            






                                                                     
    
                                                                                                    
 
                                          
         
                                        















                                                      




                                                                           
    
















                                                         


                                                     


                                   
                                 
         















                                                         
         

 


                    













                                                   







                                                          

                                                   














                                                             


                                   












                                    


                       


                            


                                 
                                                                   


                                   









                                                                            


                                                              

                                                                               

                           


                           






                                                    



                                       

                                              








                                                                        
 






                                                                           



                                                       
                                                                                                       





                                                                                           
                                                                       

         





                                                    
                                          
                                               

                         
                                              
 
                                      
                                                                        

                                                                       

                         

                                      
                                                

                                     
 
                                                                       
         



                   

                                      
                                        
                             
         
 
                              
                     
 





                               

                            
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>

#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 <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;
}