Untitled

mail@pastecode.io avatar
unknown
plain_text
7 months ago
41 kB
2
Indexable
Never
/*
	Trabalho final
	Color code:
		Any errors will be printed in red \033[1;31m
		When the user is required a input it will be asked in blue \033[1;34m
		The rest will be normal white
*/
#include <stdio.h>	
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAX_NUM_RECORDS 500

/*
	Function to generate random number
*/
int random_number (int min, int max)
{
    return (rand() % (max - min + 1));
}

/*
	Function to clear the input buffer
	Substitute of __fpurge(stdin)
*/
void clear_input_buffer()
{
    int c;
    while ((c = getchar()) != '\n' && c != EOF)
    {
    }
}

/*
	Struct to store all the info from the dat file (registos.dat)
	The file consists of x amount of structs:
		This structs consist of 6 4 bytes integers, 6 characters and 2 empty bytes	
		The empty bytes will be ignore when reading so we dont have to allocate space for them
*/
struct Arguments
{
	int registo_int[6];
	char registo_ch[6];
};

/*
	Function to ask the user for a text file with the purpose of reading said file
	To call the function you must enter the default_word (the output if user presses enter) and where you want to save the result
	and the operation type - meaning "r" "w" "a" "rb" "wb" "ab" which correspond to 1, 2, 3, 4, 5 and 6 respectivly, and we should also
	give a value to read_or_write which defines that word that appear in the request in the terminal
	The function loops through a request of a filename and tries to open it in read text mode, if it cant open it:
		It prints a error message and asks again
	If it opens it sucessefuly:
		Stop the loop, closes the file, and saves the user input to the pointer given for the result var
	
	Sintax: pedir_ficheiro("default_file.txt", nome_var_to_save_result, operation_type)
*/
void pedir_ficheiro(char *default_word, char *result, int operation_type, int read_or_write)
{
	char ficheiro_texto[100];
	FILE *ft;
	do
	{
		if (read_or_write == 1)
		{
			printf("\033[1;34mEscreva o nome do ficheiro a ler (ou enter para \"%s\"): \033[0m", default_word);
		}
		if (read_or_write == 2)
		{
			printf("\033[1;34mEscreva o nome do ficheiro a escrever (ou enter para \"%s\"): \033[0m", default_word);
		}
		else if (read_or_write < 1 || read_or_write > 2)
		{
			printf("\033[1;32mErro no valor read or write\033[0m");
		}
		fgets(ficheiro_texto, sizeof(ficheiro_texto), stdin);


		int tamanho_filename = strlen(ficheiro_texto);

		if (tamanho_filename > 0 && ficheiro_texto[tamanho_filename - 1] == '\n')
		{
			ficheiro_texto[tamanho_filename - 1] = '\0';
		}

		if (ficheiro_texto[0] == '\0')
		{
			strcpy(ficheiro_texto, default_word);
		}

		if (operation_type < 1 || operation_type > 6)
		{
			printf("\033[1;31mValor de entrada na chamada da funcao invalido (deve ser de 1 a 6)");
		}

		if (operation_type == 1)
		{
		ft = fopen(ficheiro_texto, "r");
		}

		else if (operation_type == 2)
		{
		ft = fopen(ficheiro_texto, "w");
		}

		else if (operation_type == 3)
		{
		ft = fopen(ficheiro_texto, "a");
		}

		if (operation_type == 4)
		{
		ft = fopen(ficheiro_texto, "rb");
		}

		else if (operation_type == 5)
		{
		ft = fopen(ficheiro_texto, "wb");
		}

		else if (operation_type == 6)
		{
		ft = fopen(ficheiro_texto, "ab");
		}

		if (ft == NULL)
		{
			printf("\033[1;31mErro ao abrir ficheiro %s para leitura\n\033[0m", ficheiro_texto);
		}
	} while (ft == NULL);

	strcpy(result, ficheiro_texto);
	fclose(ft);
}

/*
	Function to read the .dat and save it to the data base defined by the struct arguments
		read from char *ficheiro_dat_ptr, save to struct Arguments database []
	Sintax: read_database(nome_ficheirodat, nome_struct_tipo_Arguments)
*/
void read_database(char *ficheiro_dat_ptr, struct Arguments database[])
{
    FILE *dataFilePtr = fopen(ficheiro_dat_ptr, "rb");

    if (dataFilePtr == NULL)
    {
        printf("\033[1;31mErro ao abrir ficheiro %s para leitura\033[0m\n", ficheiro_dat_ptr);
        exit(1);
    }

    // Read up to MAX_NUM_RECORDS records or until EOF is reached
    for (int i = 0; i < MAX_NUM_RECORDS && fread(&database[i], sizeof(struct Arguments), 1, dataFilePtr) == 1; i++)
    {
        // Continue reading until EOF
    }

    fclose(dataFilePtr);
}

/*
	Function to read the clean file and the respective binary registry and print all the arterias with the name inputed.
	It works by first opening the files with the pedir_ficheiro function, creating a struct type Arguments to store all the data
	from the dat file. Calls the read_database function and uses the .dat file inputed by the user as entry parameter.
	Creates a char array to store the line info read from the txt file, a int var to store the current line number and a another
	char array to store the word the user wants to look for in the arterias. Asks the user for word they wanna look for and saves
	it to the corresponding array. Then initiates the loop that reads the txt file line by line (the loop end when EOF reached)
	Removes the \n (enter) from the end of the line and replaces with \0 so we can treat line as a string to compare it, it then
	look for the word inputed by the user inside the now formated line. If the word is found prints out the line itself and all
	the respective arguments that are different then 0.
*/
void escrever_especif_com_reg()
{
	/*
		Get the txt file from the user using the pedir_ficheiro function
	*/
	char ficheiro_limp[50];
	pedir_ficheiro("ruas.txt", ficheiro_limp, 1, 1);
	FILE *fl = fopen(ficheiro_limp, "r");

	/*
		get the dat file from the user using the pedir_ficheiro function
	*/
	char ficheiro_dat[50];
	pedir_ficheiro("registos.dat", ficheiro_dat, 4, 1);
	FILE *fd = fopen(ficheiro_dat, "rb");

	/*
		Create and load the struct with all the data inside the dat file
	*/
	struct Arguments database[MAX_NUM_RECORDS];
	read_database(ficheiro_dat, database);

	/*
		Create the varariables needed to run the rest of the function
			One to store the line read from the txt file: line
			One to store the line number: line_number
			One to store the word inputed by the user: word
	*/
	char line[100];
    int line_number = 1;
	char word [100];

	/*
		Get the word we want to look for from the user
	*/
	printf("\033[1;34mEscreva um nome (ou varios) para procura nas arterias: \033[0m");
	fgets(word, sizeof(word), stdin);
	word[strcspn(word, "\n")] = '\0';

	printf("\n");
	/*
		Loop to every line of the txt file until the end (at the end fgets returns NULL)
	*/
    while (fgets(line, sizeof(line), fl) != NULL) 
	{	
		//replaces the \n at the end of the array with a \0 so we can work with it as a string 
		int length = strlen(line);
        if (length > 0 && line[length - 1] == '\n') 
		{
            line[length - 1] = '\0';
        }

		/*
			If the string contains the word chosen, print the line itself and its arguemnts that are != 0
		*/
        if (strstr(line, word) != NULL) 
            {
                printf("\t%-50s - %d ", line, line_number);

                for (int i = 0; i < 6; i++)
                {
					if (database[line_number-1].registo_int[i] == 0)
					{
						continue;
					}
                    printf("- %d %c ", database[line_number-1].registo_int[i], database[line_number-1].registo_ch[i]);
                }

                printf("\n");
            }
		line_number++;
    }
	fclose(fl);
	fclose(fd);
}

/*
	Function that wil display how many of each type of arterias is present in the txt file and the total amount of arterias.
	It does this by first getting the txt file from the user with the pedir_ficheiro function, then initiating a 2D array to store all
	the type of arterias and creates a correspondent int array to store how many of each type exist as it reads the file. Initiates this
	int array with all 0 values, then creates a char array to store the line read from the txt file and a char array to store the first
	word of each line. Initiates reading the txt file line by line, creates a pointer that will store the postion of the first ' ' and
	if the pointer exist (if there is a ' ') calculates the size of the word by subtracting the everything after the space from the line,
	Saves the first word in the respective array by copying only the size of the first word amount of character from the line array.
	Compares the first word to the list of types, if a match is found add one to its respective postion in the int array and continue.
	Else add that word to the list and add one to the correspondent position in the int array. The max amount of types is set as 30
	Loop through all of the types and prints its name and respective amount. Adds all the int values inside the int array to output
	the total amount of arterias.
*/
void escrever_tipos_arterias()
{
	/*
		Get the txt file from the user with the function pedir_ficheiro
	*/
	char ficheiro_para_ler[100];
	pedir_ficheiro("ruas.txt", ficheiro_para_ler, 1, 1);
	FILE *fpl = fopen(ficheiro_para_ler, "r");

	printf("\n");
	/*
		Creates a list to store all the types max amount of types is 30
	*/
    char lista_tipos[30][20] = {""};

    /* 
		Creates a int array with the same size as the max amount of types
		and one to store the total amount of types read
	*/
    int quantidade_tipo_ruas[30] = {0};
	int total_tipos = 0;


	/*
		Creates the vars that will be needed to run the rest of the code
			One to store the line read from the txt file: line_buffer
			One to store the first word of the line: primeira_palavra
	*/
    char line_buffer[100];
    char primeira_palavra[50];

	/*
		Loop to every line of the txt file until the end (at the end fgets returns NULL)
	*/
    while (fgets(line_buffer, sizeof(line_buffer), fpl) != NULL) 
    {
		/*
			Creates a pointer to the position of the first ' ' calculated by the strchr function
		*/
        char *pointer_para_espaco = strchr(line_buffer, ' ');

		/*
			Checks if a ' ' exists and if it does runs the rest of the code
		*/
        if (pointer_para_espaco != NULL)
        {
			/*
				Calculates and saves the size of the first word into the tamanho_palavra var
			*/
            int tamanho_palavra = pointer_para_espaco - line_buffer;

            //same as strcpy but only copys x amount of characters (p1, p2, p3) defined by p3
            strncpy(primeira_palavra, line_buffer, tamanho_palavra);
            //Adds \0 to the end of the array so we can treat as a string (replaces the ' ')
			primeira_palavra[tamanho_palavra] = '\0';

			int encontrado = -1;

			/*
				Compares the first word to all of the words in the list
			*/
            for (int i = 0;i < sizeof(lista_tipos) / sizeof(lista_tipos[0]); i++)
            {
				/*
					If a match is found add 1 to the correspondent postion in the int array and goes to the next iteration
				*/
  				if (strcmp(primeira_palavra, lista_tipos[i]) == 0) 
				{
                    encontrado = i;
                    break;
            	}
        	}

			if (encontrado == -1)
			{
				if (total_tipos < 30)
				{
					//printf("%d\n", total_tipos);
					for (int i = 0; i < 30; i++)
					{
						if (quantidade_tipo_ruas[i] == 0) 
						{
						strcpy(lista_tipos[i], primeira_palavra);
						encontrado = i;
						total_tipos++;
						//printf("total: %d\n", total_tipos);
						break;
						}
					}
				}
				else 
				{
					printf("\033[1;31mExistem mais de 30 tipos de arterias\033[0m");
					exit(0);
				}
    		}
			
			if (encontrado != -1)
			{
				quantidade_tipo_ruas[encontrado]++; 
			}
		}
	}

	/*
		goes through all the types of arterias and prints its name and the amount of time it appears (saved in the int array)
	*/
    for (int i = 0; i < 30; ++i) 
	{
		if (quantidade_tipo_ruas[i] != 0)
		{
			printf("\033[1;33m\t\t%-10s\033[0m :  %d\n", lista_tipos[i], quantidade_tipo_ruas[i]);
		}
    }
    
	/*
		initiates a int total_tipos to calculate the total amount of arterias
	*/
    int total_tipos_to_print = 0;

	/*
		Loops through all the ints in the int array and adds them to the total_tipos var and prints the total amount
	*/
    for (int j = 0; j < 30; j ++)
    {
        total_tipos_to_print += quantidade_tipo_ruas[j];
    }
    printf("\033[1;33m\n\t\tTotal\t: %d\n\n\033[0m", total_tipos_to_print);

    fclose(fpl);
}

/*
	Function to create the filtered file, it does this by, ignoring all the lines that are not more then 2 characters long (avoiding
	all the one charatcer lines) and removing any characthers that come after '(' unless inside the () its written
	Lisbon or Lisboa, in that case deletes everything after the ')'. It ask the user for the file to be filtered with the function
	pedir_ficheiro then asks the user for the file he wants to save the new info too with the same function. Starts a loop that will
	go through all the lines of the file given by the user and process them if they are more then 1 character long (aka if they are not
	just one number or letter). The proessing part consist of looking for the first '(' and the first correspoding ')' saving the 
	word in the middle to a new var and comparing it to Lisbon and Lisboa, if the result is NULL (aka its neither of those words) then
	puts a \0 (ending the string) before the first '(' else if the word inside is one of the two words we are looking for add the \0
	after the first '('
*/
void criar_ficheiro_limpo(int saltar, char *ficheiro_entrada)
{
	char ficheiro_para_ler[50];
	if (saltar == 0)
	{
	/*
		Ask the user for the file to read
	*/
	pedir_ficheiro("ruas_prim.txt", ficheiro_para_ler, 1, 1);
	}
	else if (saltar == 1)
	{
		strcpy(ficheiro_para_ler, ficheiro_entrada);
	}

	/*
		Ask the user for the file to save the new info
	*/
	char ficheiro_para_escrever[50];
	pedir_ficheiro("ruas.txt", ficheiro_para_escrever, 2, 2);

	FILE *fpl = fopen(ficheiro_para_ler, "r");
	FILE *fpe = fopen(ficheiro_para_escrever, "w");

	char buffer_linha[150];

	/*
		Loop to read all the lines of the file 
	*/
	while (fgets(buffer_linha, sizeof(buffer_linha), fpl) != NULL) 
	{
		/*
			Remove the \n at the end of the line
			Add a \0 so it now ends the string and we can treat buffer_linha as a string
		*/
		int tamnho_linha = strlen(buffer_linha);
		if (tamnho_linha > 0 && buffer_linha[tamnho_linha - 1] == '\n')
		{
			buffer_linha[tamnho_linha - 1]= '\0';
		}

		/*
			By only saving if size of line > 1 we ignore the single characters across the database
			Then define that if we find Lisboa or Lisbon inside the string we end the string
		*/
		if(strlen(buffer_linha) > 1)
		{
			/*
				Looks for the first ( inside the string [strchr looks for the first character inside the string kinda like strstr]
				then uses aif statment that will run if there are ( in the string [NULL = There are no parathenses]
			*/
	 		char *parentesis_aberto = strchr(buffer_linha, '(');
            if (parentesis_aberto != NULL)
            {
				/*
					Looks for the first ) inside the string
					then uses a if statment that will if ) exists
				*/
                char *parentesis_fechado = strchr(parentesis_aberto, ')');
                if (parentesis_fechado != NULL)
                {
                    /*
						"reads" (saves what is inside the () to a new array to figure out what it is)
							strcpy(destino, fonte, numero caracteres)
							after it adds a '\0' to turn the array into a readable string
					*/
                    char conteudo_dentro_parentesis[50];
                    strncpy(conteudo_dentro_parentesis, parentesis_aberto + 1, parentesis_fechado - parentesis_aberto - 1);
                    conteudo_dentro_parentesis[parentesis_fechado - parentesis_aberto - 1] = '\0';

                    /*
						Checks if the text inside () is Lisbon or Lisboa
							strstr(texto to compare 1, texto to compare 2) returns NULL if text 1 dosent contain text 2
						Deletes it if the text inside isnt Lisboa or Lisbon
					*/
                    if (strstr(conteudo_dentro_parentesis, "Lisbon") == NULL && strstr(conteudo_dentro_parentesis, "Lisboa") == NULL)
                    {
                        /*
							Deletes the content after by placing a '\0' to end the string where the first ( would be
						*/
                        int posicao_parentesis_aberto = parentesis_aberto - buffer_linha;
						buffer_linha [posicao_parentesis_aberto] = '\0';
                    }
					else
					{
						/*
							Deletes the content after the ( by puttin a '\0' in the position after (
						*/
						int posicao_parentesis_fechado = parentesis_fechado - buffer_linha;
						buffer_linha[posicao_parentesis_fechado + 1] = '\0';
					}
                }
            }

        /*
			Saves the modifed line into the file given by the user
		*/
        fprintf(fpe, "%s\n", buffer_linha);
        }
    }

    /*
		Close all the files that were open 
	*/
    fclose(fpl);
    fclose(fpe);
}

/*
	This funtiojn prints all the arterias with a specifc argument chosen by the user. It does this by first getting both the txt files
	with the arterias themselves and the dat file with the arguents from the user using the pedir_ficheiro function. Then creates a 
	database type struct Arguments to store all the data from the dat file and uses the function read_database to load the said info
	on to the newly created struct. Then asks the user for the argument they wanna look for this argument must be a number between 1 and 60
	so we ask the user on a loop until a valid number is given. Then print the labels for the layout of the output information and starts
	a loop through all the record saved in the database, for each loop it read the correspondent line from the text file and compares
	the arguments for that line from the dat file to the argument the user is looking for, if a match is found it will print the whole
	line the line number and all its arguments that arent != 0.
*/
void print_arterias_com_x_reg()
{
	/*
		Get the txt file with the arterias from the user
		and open said file in the correct mode
	*/
	char ficheiro_limp[50];
	pedir_ficheiro("ruas.txt", ficheiro_limp, 1, 1);
	FILE *fl = fopen(ficheiro_limp, "r");

	/*
		get the dat file with the arguemnts from the user
		and open it in the correct mode
	*/
	char ficheiro_dat[50];
	pedir_ficheiro("registos.dat", ficheiro_dat, 4, 1);
	FILE *fd = fopen(ficheiro_dat, "rb");

	/*
		Create and load a database with all the info inside the dat file
	*/
	struct Arguments database[MAX_NUM_RECORDS];
	read_database(ficheiro_dat, database);

	/*
		Creates the variables need to run the code:
			One to store the argument the user wants to look for: numero_procura
			One to store the line read from the txt file: line
			One to count the lines in the text file: numero_linhas
	*/
    int numero_procura = 0;
	char line [100];
	int numero_linhas = 0;

	/*
		Ask the user for the argument they wanna look for until the input is valid
	*/
    do 
	{
        printf("\033[1;34mEscreva um numero de registo (1 a 60): \033[0m");
        scanf("%d", &numero_procura);

        if (numero_procura < 1 || numero_procura > 60) 
		{
            printf("\033[1;31mValor invalido de registo.\n\033[0m");
        }
    } while (numero_procura < 1 || numero_procura > 60);

	printf("\n");

	/*
		Counts the amount of lines by adding one to the var numero_linhas for every line read until EOF and then reopens the files
		to have it start reading in the next loop from the top again. Did this to avoid the next loop going through informationg that
		dosent exist.
	*/
	while (fgets(line, sizeof(line), fl) != NULL)
	{
		numero_linhas ++;
	}
	fclose(fl);

	fl = fopen(ficheiro_limp, "r");
	/*
		Print the layout for the colluns where the info is going to be with the first printf
		Loops explain:
			First loop (i loop): will go through all the records
			Second loop (j loop): will iterate through all 6 arguments for every record to try and find a match with the user input
			Third loop (k loop): will print in a formated way the arteria name (line) and all its respective arguments (expect the 0's)
	*/
	printf("\033[1;32m\n\n\t\t\tNome\t\t\t Linha\t\t\tArgs\n\033[0m");
	for (int i = 0; i < numero_linhas; i++)
	{
		fgets(line, sizeof(line), fl);

		//Line replaces the \n with \0 so there is no extra newline
		line[strcspn(line, "\n")] = '\0';
		
		for (int j = 0; j < 6; j++)
		{
			if (database[i].registo_int[j] == numero_procura)
			{
				// %-50s prints a string with the left alignment of 50 spaces
				printf("\t%-40s - %d   ", line, i + 1);
				for (int k = 0; k < 6; k++)
				{
						if (database[i].registo_int[k] != 0)
						{
						printf("\t- %d %c ", database[i].registo_int[k], database[i].registo_ch[k]);
						}
				}
				printf("\n");
			}
		}
	}
	/*
		Print a newline to format the output and closes all the files used
	*/
	printf("\n");
	fclose(fl);
	fclose(fd);
}

/*
	Function to read the info from both the ficheiro_ruas and the ficheiro_args  and save it to ficheiro_novo
	Since the files where checked on the previous function, no need for error checking
	Create a new database for the info inside the dat file which is processed by the read_database function
*/
void guardar_ficheiro_nova ( char *ficheiro_ruas, char *ficheiro_args, char *ficheiro_novo)
{
	/*
		Iniciate the variables needed for the function and open the files
	*/
	FILE *fr = fopen(ficheiro_ruas, "r");
	FILE *fn = fopen(ficheiro_novo, "w");
	struct Arguments database[MAX_NUM_RECORDS];
	char line[150];
	int line_number = 0;
	/*
		Create the database with the dat file using the read_function
	*/
	read_database(ficheiro_args, database);
	/*
		Loop that will go trough each line of the clean file with the arterias name, and for each line of said file
		it will print out all non zero arguments from the respective postion in the data base, the position is calculated by subtracting
		one from the line number since that starts at 1 and the database starts at 0
	*/
	while (fgets(line, sizeof(line), fr) != NULL)
	{
		line_number ++;
        //Remove the newline character from the line so it dosent print a \n after each arteria name
		int length = strlen(line);
        if (length > 0 && line[length - 1] == '\n') 
		{
            line[length - 1] = '\0';
        }
		/*
			Print the line on to new file (fn), with a left alignment of 50 caracters (%-50s)
		*/
		fprintf(fn, "%-50s", line);
		/*
			Loop through all 6 arguments for each line and save the ones that are non zero
			It does this by going to the next iteration when registo_int == 0
		*/
        for (int i = 0; i < 6; i++)
		{
			if (database[line_number-1].registo_int[i] == 0)
			{
				continue;
			}
		/*
			Print all the arguments, that are now zero, in a row onto the new file 
		*/

		fprintf(fn, "- %d %c ", database[line_number-1].registo_int[i], database[line_number-1].registo_ch[i]);
        }
		/*
			After printing all the arguments for this line add a \n before writting the next line
		*/
		fprintf(fn, "\n");
	}
	/*
		Closes all the files 
	*/
	fclose(fn);
	fclose(fr);
}

/*
	Function that will create the file with the name of the arteria and the respective arguments (pulled from the dat file)
	It does this by reading the clean file inputed by the user which has the arteria name and reading the arguments from the dat file
	inputed by the user. Using both of this write, in the file inputed by the user, the line with a 50 character left text alignment
	followed by its corresponding arguents from the dat file. 
*/
void fazer_ficheiro_original()
{	
	/*
		Get the text file from the user using the pedir_ficheiro function
		and open said file
	*/
	char ficheiro_com_ruas[100];
	pedir_ficheiro("ruas.txt", ficheiro_com_ruas, 1, 1);
	FILE *fcr = fopen(ficheiro_com_ruas, "r");

	/*
		Get the dat file from the user using the pedir_ficheiro function
		and open said file
	*/
	char ficheiro_com_arg[100];
	pedir_ficheiro("registos.dat", ficheiro_com_arg, 4, 1);
	FILE *fca = fopen(ficheiro_com_arg, "rb");

	/*
		Get the file to save the new info from the user using the pedir_ficheiro function
		and open said file
	*/
	char ficheiro_para_guardar[100];
	pedir_ficheiro("ruas_total.txt", ficheiro_para_guardar, 2, 2);
	FILE *fpg = fopen(ficheiro_para_guardar, "w");
	
	/*
		Create a database to store the info from the dat file and load said database with the infp from the dat file given by the user
	*/
	struct Arguments database[MAX_NUM_RECORDS];
	read_database(ficheiro_com_arg, database);

	/*
		Create the variables needed to run the rest of the code:
			One to store the line read from the txt file: line
			One to store the line number: line_number
	*/
	char line[150];
	int line_number = 0;

	/*
		intiates a loop that goes through every line in the text file, and for every line:
			Remove the \n at the end if it exists (it does exist), then prints the line from the old txt file to the new (formated with
			a 50 character left alignment) and then loops through all 6 arguments from the dat file correspondent to the line printed
			and prints all of the non zero arguments to the new file, after printing the arguments print a \n to start the next line
			and moves to the next iteration of the while loop (basically the next line)
	*/
	while (fgets(line, sizeof(line), fcr) != NULL)
	{
		line_number ++;
        //Remove the newline character from the line so it dosent print a \n after each arteria name
		int length = strlen(line);
        if (length > 0 && line[length - 1] == '\n') 
		{
            line[length - 1] = '\0';
        }
		/*
			Print the line on to new file (fn), with a left alignment of 50 caracters (%-50s)
		*/
		fprintf(fpg, "%-50s", line);
		/*
			Loop through all 6 arguments for each line and save the ones that are non zero
			It does this by going to the next iteration when registo_int == 0
		*/
        for (int i = 0; i < 6; i++)
		{
			if (database[line_number-1].registo_int[i] == 0)
			{
				continue;
			}
		/*
			Print all the arguments, that are now zero, in a row onto the new file 
		*/

		fprintf(fpg, "- %d %c ", database[line_number-1].registo_int[i], database[line_number-1].registo_ch[i]);
        }
		/*
			After printing all the arguments for this line add a \n before writting the next line
		*/
		fprintf(fpg, "\n");
	}
	/*
		Closes all the files used 
	*/
	fclose(fpg);
	fclose(fcr);
	fclose(fca);
}

/*
	Prints out all the lines with the correspondent number and their arguments if they have 2 and only two arguments (have 4 args == 0)
	Does this by first calling the function to ask the user for the files
	Calls the function to read the database correspondent to the .dat file picked by the user
	Goes through each struct in the database and counts how many args are != 0
	If the total is 2 then print everything
*/
void escrever_arterias_2reg()
{
	/*
		Ask the user for the text file to read the arterias from
		and open said file
	*/
	char ficheiro_para_ler[100];
	pedir_ficheiro("ruas.txt", ficheiro_para_ler, 1, 1);
	FILE *fpl = fopen(ficheiro_para_ler, "r");

	/*
		Ask the user for the dat file containing the arguments for the arterias
		and open said file
	*/
	char ficheiro_para_ler_bin[100];
	pedir_ficheiro("registos.dat", ficheiro_para_ler_bin, 4, 1);
	FILE *fplb = fopen(ficheiro_para_ler_bin, "rb");
	
	printf("\n");
	/*
		Create a struct to store all the data from the dat file given by the user, and load it onto to said struct using the
		read_database function
	*/
	struct Arguments database[MAX_NUM_RECORDS];
	read_database(ficheiro_para_ler_bin, database);

	/*
		Create the variables needed to run the rest of the code
			One to store the line read from the text file: line
			One to store the total amount of arterias with 2 arguments
			One to store temporarily the amount of arguments in the line being read
			One to store the total amount of lines in the text file: nunero_linhas
	*/
	char line [150];
	int total = 0, numero_args;
	int numero_linhas = 0;

	while (fgets(line, sizeof(line), fpl) != NULL)
	{
		numero_linhas ++;
	}
	fclose(fpl);
	fpl = fopen(ficheiro_para_ler, "r");
	/*
		Starts a loop that will go through all the record in the database, and for each one: remove the \n at the end so there is no
		extra newline when printing, goes through a loop to count the amount of valid arguments (arguments that are different then 0)
		If there are only two arguments print the line and its respective arguments (that are different then 0) and add one to the count
		of total amount of arterias with 2 and only 2 arguments.
	*/
	for (int i = 0; i < numero_linhas; i ++)
	{
		fgets(line, sizeof(line), fpl);
		//Line replaces the \n with \0 so there is no extra newline and we can treat it as a string
		line[strcspn(line, "\n")] = '\0';

		/*
			Counts the amount of arguments != 0, and if the total is 2 prints out the line itself with a left alignment of 50 characters
			and its respective arguments and adds one to the total count of arterias with 2 and only 2 arguments
		*/
		for (int j = 0; j < 6; j++)
		{
			if(database[i].registo_int[j] != 0)
			{
				numero_args ++;
			}
		}
		if (numero_args == 2)
		{
			printf("\t%-50s - %d ", line, i + 1);
			for (int j = 0; j < 6; j++)
			{
				if (database[i].registo_int[j] != 0)
				{
				printf(" - %d %c", database[i].registo_int[j], database[i].registo_ch[j]);
				}
			}
			printf("\n");
			total ++;
		}
		numero_args = 0;
	}
	/*
		Print (in blue) the total amount of arterias with 2 and only 2 arguments
	*/
	printf("\033[1;34m\n\tTotal: %d\n\n\033[0m", total);

}

/*
	Function to print a visual representation of the the amount of arguments per arterias. Show how many arterias have 0,1,2...6
	Does this by first getting from the user the file with the arterias so we can count how many arterias are in the file and therefore
	how many arguments we need to read from the dat file. Then gets the dat file from the user (we read the arguments from here)
	Saves the arguments from the dat file into a database using the read_database function. Creates a few vars, one int array to store
	the amounts of arterias which x arguments (one position in the array for each possible amount 0,1,2...6; so 7 postions), one int
	to store the total amount of arterias (numero_linhas) and one to temporarly store the count of arguments for each arteria.
	And a "temp" char to give as an input to the loop that counts the lines even though we dont need the information inside the line.
	Counts the amount of lines in the txt file (closes the txt file after since we dont need it anymore), read through the database
	for a total amount of times == to the amount of lines read before. For each struct in the database count the arguments (how many 
	are != 0) and depending on how many arguments were counted add 1 to the respective postion in the int array.
	After all the counting is done, print the "graph" by printing "█" the same amount of times as the int value in the array (do this
	for all 7 postions using a switch statment) Then prints out in a formated stated the decription of the line (the number of args)
	and its respective value from the int array, and at the end print the total amount of arterias.
*/
void imprimir_histograma()
{
	/*
		Get the text file with the streets from the user, usign the pedir_ficheiro function and opens said file in the read mode
	*/
	char ficheiro_com_ruas[100];
	pedir_ficheiro("ruas.txt", ficheiro_com_ruas, 1, 1);
	FILE *fcr = fopen(ficheiro_com_ruas, "r");

	/*
		Get the dat file with the arguments from the user, using the pedir_ficheiro function and opens said file in the readbin mode
	*/
	char ficheiro_com_args[100];
	pedir_ficheiro("registos.dat", ficheiro_com_args, 4, 1);
	FILE *fca = fopen(ficheiro_com_args, "rb");

	//Formating the output 
	printf("\n");

	/*
		Create and loads a array type struct Arguments to store all the informationg from the dat file, loads this array using the
		read_database function
	*/
	struct Arguments database[MAX_NUM_RECORDS];
	read_database(ficheiro_com_args, database);

	/*
		Inicialize the vars needed to run the rest of the code:
			One int array to store the quantity of arterias with x arguements (an array with 7 positions corresponding to 
				0,1,2,3,4,5 or 6 arguments in one arteria) - values
			One int to temporarily store the amount of args in a arteria - args
			and one to save the total number of lines in the txt file - numero_linhas
			One char array to temporarily store the info from the txt file just so we can count the amount of lines - line
	*/
	int values[] = {0,0,0,0,0,0,0};
	int args = 0, numero_linhas = 0;
	char line[100];

	/*
		Reads the txt file line by line and counts how many total lines it has by adding one to the var numero_linhas for every time
		it reads a new line, we count the lines so we know how many arguments to read from the dat file
	*/
	while (fgets(line, sizeof(line), fcr) != NULL)
	{
		numero_linhas ++;
	}
	fclose(fcr);

	/*
		Loop through the same amount of structs in the database as lines in the file (represented by the i loop) and for each struct
		counts how many arguments there are in that struct by looking for registo_int != 0, then adds one to the position of the int
		array correspondent to the total amount of args and sets the args to 0 so we can count the next line.
	*/
	for (int i = 0; i < numero_linhas; i++)
	{
		for (int j = 0; j < 6; j++)
		{
			if (database[i].registo_int[j] != 0)
			{
				args ++;
			}
		}
		values[args]++;
		args = 0;
	}

	/*
		Print the title to display the information that will be printed next
	*/
	printf("\033[1;33m\tNum. Registos   Num. de ruas\n\033[0m");

	/*
		Goes through all 7 positions of the int array and prints the amount of args it represents and the total it has saved as '█'
		characters (so we visualize it better) 
	*/
	for (int k = 0; k < 7; k++)
	{
		printf("\t      %d\t\t     %d\t\t", k, values[k]);
		for (int l = 0; l < values[k]; l++)
		{
		printf("\033[1;32m█\033[0m");
		}
		printf("\n");
	}
	
	/*
		Print the total amount of arterias read which is the number of lines read from the txt file at the start
	*/
	printf("\n\033[1;33m\t\tTotal - %d\033[0m\n", numero_linhas);
}

/*
	Function to create a randomized dat file with a average of 4 arguemnts per arteria. It does this by creating 4 x 345 arguemnts so
	there are an average of 4 arguments per arteria to be distributed, it creates this arguments by first generating a "random" number
	between 1 and 60 (which are the limitations for the values of the int args) and then generates another random number between
	1 and 23 and adds 'A' to it effectively generating a letter between 'A' and 'W' and saves it to a int array and a char array
	respectively. It then goes through every position in the struct and after generating a random number between 0 and 6 (that will
	define how many arguments each struct will have) and assigns int and chars from the arrays of arguments to that struct and
	assigns 0 or \0 to the empty int and chars in the struct. Asks the user for the name of the .dat file they wanna write to, opens
	said file and prints the whole database (the 345 structs) to the file and closes the file after. 
*/
void criar_ficheiro_dat(long ultime)
{
	/*
		Create the vars needed to run the function
			One struct Arguments array to store all the info that will be printed
			One int array to save all the arguments that will be distribueted
			and one int to define what int or char will be saved to the struct
			One char array to save all the char arguments that will be saved
	*/
	struct Arguments database[345];
    int numero_args[1380], posicao_vi = 0;
    char char_args[1380];

	/*
		Loads both arrays with random numbers and letters respectevily
	*/
    for (int i = 0; i < 1380; i++)
    {
        numero_args[i] = random_number(1, 60);
        char_args[i] = (random_number(1,23) + 'A');
    }
	/*
		Loads the structs with a random amount of arguments between 0 and 6
	*/
    for (int i = 0; i < 345; i++) 
    {
        for (int j = 0; j < 6; j++) 
        {
                database[i].registo_int[j] = 0;  
                database[i].registo_ch[j] = '\0';  
        }
    }

	while (posicao_vi < 1380)
	{
		int random_index = random_number(0, 344);

		for (int j = 0; j < 6; j++)
		{
			if (database[random_index].registo_int[j] == 0)
			{
				database[random_index].registo_int[j] = numero_args[posicao_vi];
				database[random_index].registo_ch[j] = char_args[posicao_vi];
				posicao_vi++;
				//printf("posicao vi: %d  random index: %d  empty position: %d\n", posicao_vi, random_index, j);
				break;
			}
		}
	}

	/*
    printf("\n");
    for (int i = 0; i < 345; i++)
    {
        for (int j = 0; j < 6; j++)
        {
			if (database[i].registo_int[j] != 0)
			{
            printf("\033[1;33m- %d\033[0m", database[i].registo_int[j]);
            printf("\033[1;33m%c \033[0m", database[i].registo_ch[j]);
			}
        }
        printf("\n");
    }
	printf("\n%d\n", posicao_vi);
	*/

	/*
		Get the name of the dat file the user wants to write to, opens the file and then prints the whole database to this file
	*/
	char ficheiro_novo[100];
	pedir_ficheiro("registos.dat", ficheiro_novo, 5, 2);
   	FILE *fn = fopen(ficheiro_novo, "wb");
    fwrite(database, sizeof(struct Arguments), 345, fn);

    fclose(fn);
}

/*
	show the menu and ask the user for a input
	Color code:
		Green for the title
		Rest follows the base color code
*/
void menu (int *ptropcao)
{
	printf("\n");
	printf("\033[1;32m\tPrograma de verificacao de correspondencia\n\n\033[0m");
	printf("0 - Sair do programa\n");
	printf("1 - Contruir o ficheiro limpo\n");
	printf("2 - Escrever as diferentes classes de artérias\n");
	printf("3 - Ler informação total (texto + binario) e escrever por nome de artéria\n\n");
	printf("4 - Selecinar as ruas que têm um certp número de registos\n");
	printf("5 - Produzir o ficheiro \"ruas_total.txt\"\n");
	printf("6 - Escrever as arterias que têm apenas dois registos\n\n");
	printf("7 - Fazer histograma con o numero de ruas por registos\n");
	printf("8 - Prodzuir o ficheiro \"registos.dat\"\n\n");
	printf("9 - Escrever ruas que tenham dois registos (numeros ou letras)\n");
	printf("10 - Ranking de ruas: das ruas com maior numero de partes de registos iguais\n");
	
	printf("\033[1;34mEscolha uma opcao: \033[0m");
	scanf(" %d", ptropcao);
	printf("\n");

	/*
		Call the function to clear the buffer, substitute of __fpurge(stdin)
	*/
	clear_input_buffer();
}

/*
	Prints all the required info for when the user run the code like "trabfin -h"
		Shows version
		Shows possible way to run the code
*/
void help_mode()
{
	printf("\n\033[1;34m---------- Version: 1.0 ----------\033[0m\n");
	printf("\nSintax:\ttrabfin\n\ttrabfin Nome_ficheiro_para_ler\n");
	exit(0);
}

int main(int argc, char *argv[])
{   
	/*
		Define vars used in main
	*/
	int opcao;

	/*
		Creates the seed for the number generator
	*/
	long ultime;
	srand ((unsigned) time(&ultime));

	/*
		Runs the code in a different manner depending of how many and what type of arguments, rules:
			If the code is ran with no extra arguementso argc = 1, run normaly
			If the code is ran with "-h" after so argc = 2, then the program will show the version of the code and the ways to run it
			If the code is ran with something else (a file name) written after the ex, the the code will try to read the file given
			If the code is ran with 3 or more arguments then prints an error and exits the code
	*/
    if (argc == 1)
	{
        //printf("\033[1;32mModo normal\033[0m\n");
    } 
	else if (argc == 2 && strcmp(argv[1], "-h") != 0)
	{
		criar_ficheiro_limpo(1, argv[1]);
    }
	else if (argc == 2 && strcmp(argv[1], "-h") == 0)
	{
        help_mode();
    }
	else
	{
        printf("\033[1;32mErro, numero de argumentos invalidos\n\033[0m");
		exit(1);
    }

	do
	{
		/*
			Run the menu on a loop until the user inputs '0'
			0 	- Leave the program
			1 	- Create the filtered file
			2 	- Write all the different classes and count them (currently working with a hardcoded list of words)
			3 	- Ler informação limpa + registos em binario e escreve todas ruas que contenham um certo nome (dado pelo user) + seus registos
			4 	- Emprime todas as ruas com o numero de arugmento dado pelo user
			5 	- Produzir o ficeiro original ruas_prim.txt
			6 	- Write all the arterias with 2 arguments
			7 	- Create a histograma with of how many arterias have x arguments 
			8 	- 
			9 	- 
			10 	- 
		*/
		menu(&opcao);
		switch (opcao)
		{
			case 0:
				printf("\033[1;31mA sair do programa\033[0m\n");
				break;
			case 1:
				criar_ficheiro_limpo(0, "dontcare");
				break;
			case 2:
				escrever_tipos_arterias();
				break;
			case 3:
				escrever_especif_com_reg();
				break;
			case 4:
				print_arterias_com_x_reg();
				break;
			case 5:
				fazer_ficheiro_original();
				break;
			case 6:
				escrever_arterias_2reg();
				break;
			case 7:
				imprimir_histograma();
				break;
			case 8:
				criar_ficheiro_dat(ultime);
				break;
			case 9:
				break;
			case 10:
				break;
		}
	}	while (opcao != 0);
	
	return 0;
}
Leave a Comment