Doubly Linked List Database Application in C

This was a project from high school done with a friend that implemented a doubly linked list and used this list to manage a database of school records.

Compile with gcc *.c


This is the entry point of the program. At launch, it allocates memory for the database and prompts the user for an action.

#include "project.h"
COURSE array[255];                                         //Declare global Variables
COURSE* FIRST;
COURSE* LAST;
char filename[255];

void main(void)
{
	char choice;                                             //Declare Variables
	int i = 0;
	BOOLEAN quit = FALSE;

	FIRST = NULL;                                            //Initialize variables                         
	LAST = NULL;
	for(i = 0; i < 256; i++)
		InitializeRec(&array[i]);
	filename[0] = '\0';

	i = 0;
	
	do                                                       //menu open until quit = TRUE
	{
	choice = DisplayMainMenu();                              //Display Main Menu and Get Main Menu Choice
	
	switch(choice)                                           //Menu swithc
		{
			case 'o': OpenData();
				break;
			case 'a': AddRec();
				break;
			case 's': SearchData();
				break;
			case 'b': BrowseData();
				break;
			case 'd': printf("\nDelete Record\n");
				break;
			case 'c': CloseData();
				break;
			case 'q': quit = QuitProgram();
				break;
			default: printf("\nError\nPlease enter a valid response.\n");
				break;
		}

	}while(!quit);

	return;                                                    //Exit the program.
}

This header file declares all the functions that will be part of the program.

#ifndef PROJECT_H
	
	#define PROJECT_H
	#define TRUE -1
	#define FALSE 0

	#include "stdio.h"
	#include "string.h"
	#include "stdlib.h"

	struct RECORD
	{
		char number[17];
		char title[65];
		int	credit;
		int lab;
		struct RECORD* next;
		struct RECORD* previous;
	};
	
	typedef struct RECORD COURSE;
	typedef int BOOLEAN;

	void Header(void);
	void GetEnter(void);
	void NewDat(void);

	void OpenData(void);
	void AddRec(void);
	void SearchData(void);
	void BrowseData(void);
	void EditRec(COURSE*);
	void DeleteRec(COURSE*);
	void CloseData(void);
	BOOLEAN QuitProgram(void);

	char DisplayMainMenu(void);
	char GetMainMenuChoice(char*);

	void InitializeRec(COURSE*);

	void GetNumber(COURSE*);
	void GetTitle(COURSE*);
	void GetCredit(COURSE*);
	void GetLab(COURSE*);

	void WriteRec(COURSE*);
	void ReadRec(COURSE*);
	void DisplayRec(COURSE*);

	void LinkRec(COURSE*);
	void UnlinkRec(COURSE*);

	extern COURSE array[255];
	extern COURSE* FIRST;
	extern COURSE* LAST;
	extern char filename[255];

#endif

This function prints out the main menu and was made to make the main program more readable and modular.

#include "project.h"

char DisplayMainMenu(void)
{
	char return_value;                                       //Declare return value variable

	Header();
	printf("\nO\tOpen database");                             //Display Menu
	printf("\nA\tAdd new record");
	printf("\nS\tSearch for a record");
	printf("\nB\tBrowse the database");
	printf("\nE\tEdit a Record");
	printf("\nD\tDelete a record");
	printf("\nC\tClose the database");
	printf("\nQ\tQuit\n");

	return_value = GetMainMenuChoice("Please enter your choice: ");

	return(return_value);
}

Function to add records to the doubly linked list.

#include "project.h"

void AddRec(void)
{
	COURSE course1;                                          //Declare Variables
	COURSE course2;
	int i = 0;
	char prompt_yn;
	char temp[10];

	if(filename[0])                                          //If database open
	{
		Header();
		printf("\nAdd Record\n");

		EditRec(&course1);                                     //Edit Record and Write record
		WriteRec(&course1);
		ReadRec(&course2);
		DisplayRec(&course2);

		while(array[i].number[0] != '\0')                      //Find opening in array
			i++;
		
		RecCpy(&array[i], &course2);                           //Put record in opening
		
		LinkRec(&array[i]);                                   //Link new record
		printf("\nNew record added sucessfully!");
	}
	else{
		printf("\nError\nNo database is open.\n");                //Error if no database is open
		while(1){						  //Ask the user if they would like to make one
			printf("\nWould you like to create a new database? [y/n] ");
			fgets(temp, 10, stdin);
			if(strlen(temp) > 2) printf("\nERROR: INVALID RESPONSE LENGTH\n");
			else prompt_yn = temp[0];
			if(prompt_yn == 'y'){NewDat(); AddRec();}
			else if(prompt_yn == 'n') break;
			else{
				printf("\nERROR: INVALID RESPONSE\n");
			}
		}
	}

	GetEnter();
	return;
}

This function gives the user the ability to view the records contained in the doubly linked list in order.

#include "project.h"

void BrowseData(void)
{
	BOOLEAN quit = FALSE;                                    //Declare Variables
	BOOLEAN flag = FALSE;
	COURSE* current;
	char buff[255];

	if(FIRST)                                 //If database is open with atleast 1 record
	{
		Header();
		printf("\nBrowse the Database\n");
		current = FIRST;

		while(!quit)                                           //Display records until q is pressed
		{
			flag = FALSE;
			DisplayRec(current);

			if(current == FIRST && current != LAST && !flag)
			{
				printf("\nN  %8s", "Next");
				printf("\nD  %8s\tE  %8s", "Delete", "Edit");
				printf("\nQ  %8s\n", "Quit");

				fgets(buff, 255, stdin);
				buff[0] = tolower(buff[0]);
			
				if(buff[1] == '\n')
				{
					switch(buff[0])
					{
						case 'n': current = current -> next;
							break;
						case 'd': DeleteRec(current);
							quit = TRUE;
							break;
						case 'e': UnlinkRec(current);
							EditRec(current);
							LinkRec(current);
							quit = TRUE;
							break;
						case 'q': quit = TRUE;
							break;
						default: printf("\nError\nPlease enter a valid response.\n");
					}
				}
				else
					printf("\nError\nPlease enter a valid response.\n");

				flag = TRUE;
			}

			if(current == FIRST && current == LAST && !flag)
			{
				printf("\nD  %8s\tE  %8s", "Delete", "Edit");
				printf("\nQ  %8s\n", "Quit");

				fgets(buff, 255, stdin);
				buff[0] = tolower(buff[0]);
			
				if(buff[1] == '\n')
				{
					switch(buff[0])
					{
						case 'd': DeleteRec(current);
							quit = TRUE;
							break;
						case 'e': UnlinkRec(current);
							EditRec(current);
							LinkRec(current);
							quit = TRUE;
							break;
						case 'q': quit = TRUE;
							break;
						default: printf("\nError\nPlease enter a valid response.\n");
					}
				}
				else
					printf("\nError\nPlease enter a valid response.\n");

				flag = TRUE;
			}

			if(current != FIRST && current != LAST && !flag)
			{
				printf("\nP  %8s\tN  %8s", "Previous", "Next");
				printf("\nD  %8s\tE  %8s", "Delete", "Edit");
				printf("\nQ  %8s\n", "Quit");

				fgets(buff, 255, stdin);
				buff[0] = tolower(buff[0]);
			
				if(buff[1] == '\n')
				{
					switch(buff[0])
					{
						case 'p': current = current -> previous;
							break;
						case 'n': current = current -> next;
							break;
						case 'd': DeleteRec(current);
							quit = TRUE;
							break;
						case 'e': UnlinkRec(current);
							EditRec(current);
							LinkRec(current);
							quit = TRUE;
							break;
						case 'q': quit = TRUE;
							break;
						default: printf("\nError\nPlease enter a valid response.\n");
					}
				}
				else
					printf("\nError\nPlease enter a valid response.\n");

				flag = TRUE;
			}

			if(current == LAST && current != FIRST && !flag)
			{
				printf("\nP  %8s", "Previous");
				printf("\nD  %8s\tE  %8s", "Delete", "Edit");
				printf("\nQ  %8s\n", "Quit");

				fgets(buff, 255, stdin);
				buff[0] = tolower(buff[0]);
			
				if(buff[1] == '\n')
				{
					switch(buff[0])
					{
						case 'p': current = current -> previous;
							break;
						case 'd': DeleteRec(current);
							quit = TRUE;
							break;
						case 'e': UnlinkRec(current);
							EditRec(current);
							LinkRec(current);
							quit = TRUE;
							break;
						case 'q': quit = TRUE;
							break;
						default: printf("\nError\nPlease enter a valid response.\n");
					}
				}
				else
					printf("\nError\nPlease enter a valid response.\n");

				flag = TRUE;
			}
		}
	}
	else
		printf("\nError\nNo database is open or no records in database.\n");

	GetEnter();
	return;
}

Function to save and close the database.

#include "project.h"

void CloseData(void)
{
	if(filename[0])                                          //If File open
	{
		FILE* database;                                        //Declare Variable
		int i = 0;

		Header();
		printf("\nClose the Database\n");
		database = fopen(filename, "wt");                      //Open database for writing
		for(i = 0; i < 256; i++)                               //Write file
			if(array[i].number[0] != '\0')
			{
				fprintf(database, "%s\n", array[i].number);
				fprintf(database, "%s\n", array[i].title);
				fprintf(database, "%d\n", array[i].credit);
				fprintf(database, "%d\n", array[i].lab);
			}

		fclose(database);                                      //Close file
		FIRST = NULL;                                          //Re-initialize array
		LAST = NULL;
		filename[0] = '\0';
		for(i = 0; i < 256; i++)
			InitializeRec(&array[i]);

	}
	else
		printf("\nError\nNo database is open.\n");               //Error if no is open

	GetEnter();
	return;
}

Function to delete a record from the doubly linked list and free the memory.

#include "project.h"

void DeleteRec(COURSE* record)
{
	Header();
	printf("\nDelete a Record\n");
	UnlinkRec(record);
	InitializeRec(record);

	printf("\nRecord Deleted Sucessfully!\n");

	GetEnter();
	return;
}

Function to print out the contents of a record.

#include "project.h"

void DisplayRec(COURSE* record)
{
	printf("\n\nNumber: %s", record -> number);
	printf("\nTitle: %s", record -> title);
	printf("\nCredit: %d", record -> credit);
	printf("\nLab: %d", record -> lab);

	return;
}

Function to read user input and store this in an already existing record.

#include "project.h"

void EditRec(COURSE* record)
{
	GetNumber(record);
	GetTitle(record);
	GetCredit(record);
	GetLab(record);

	return;
}

Function to read the credit value.

#include "project.h"

void GetCredit(COURSE* record)
{
	int i;                                                   //Declare variables
	char buff[255];
	BOOLEAN error;

	do                                                       //Loop if Error
	{
		error = FALSE;
		printf("Please enter the number of credits: ");
		fgets(buff, 255, stdin);
	
		sscanf(buff, "%d", &(record -> credit));

		if(record -> credit > 9 || record -> credit < 0)       //Sanity Check
		{
			printf("\nError\nPlease enter a valid response.\n");
			error = TRUE;
		}
	}while(error);
	return;
}

Function to prompt for enter to continue.

#include "project.h"

void GetEnter(void){
	char temp[2];

	printf("\nPress [Enter] to continue...");
	fgets(temp, 2, stdin);

}

Function to prompt for lab.

#include "project.h"

void GetLab(COURSE* record)
{
	int i;                                                    //Declare Variables
	char buff[255];
	BOOLEAN error;

	do                                                       //Repeat if Error
	{
		printf("Is there a lab? (Y/N): ");                    //Prompt
		fgets(buff, 255, stdin);
		error = FALSE;

		buff[0] = tolower(buff[0]);                            //lowercase input
	
		if((buff[0] == 'y' || buff[0] == 'n') && buff[1] == '\n')        //Sanity Check
			if(buff[0] == 'y')                                   //find lab value
				record -> lab = 1;
			else
				record -> lab = 0;
		else
		{
			printf("\nError\nPlease enter a valid response.\n");           //Error response
			error = TRUE;
		}
	}while(error);

	return;
}

Function to get the user's input on the main menu.

#include "stdio.h"

char GetMainMenuChoice(char* prompt)
{
	char (return_value);                                     //Declare variables
	char buff[256];

	printf("\n%s", prompt);                                  //Print Prompt
	fgets(buff, 255, stdin);
	return_value = tolower(buff[0]);                         //lowercase response

	if(buff[1] != '\n')                                      //return null if more than 1 char inputted
		return_value = '\0';
		
	return(return_value);
}

Function to read in a number from standard input.

#include "project.h"

void GetNumber(COURSE* record)
{
	int i;                                                   //Declare incrementing variable

	printf("Please enter the course number: ");
	fgets(record -> number, 17, stdin);
	
	for(i = 0; i < 17; i++)                                  //Change new line to null and upcase string
	{
		record -> number[i] = toupper(record -> number[i]);
		if(record -> number[i] == '\n')
			record -> number[i] = '\0';
	}
		

	return;
}

Function to get a course number for the database.

#include "project.h"

void GetTitle(COURSE* record)
{
	int i;                                                   //Declare incrementing variable

	printf("Please enter the course title: ");                //print prompt
	fgets(record -> title, 65, stdin);                       //get response
	
	for(i = 0; i < 65; i++)                                 //place null at end of string
		if(record -> number[i] == '\n')
			record -> number[i] = '\0';

	return;
}

Function to print a header at the program's startup.

#include "project.h"

void Header(void){
	//display the header (You can change the name to whatever you'd like Sam...)
	system("clear");
	printf("  _____        _        ______    _ _ _             \n");
	printf(" |  __ \\      | |      |  ____|  | (_) |            \n");
	printf(" | |  | | __ _| |_ __ _| |__   __| |_| |_ ___  _ __ \n");
	printf(" | |  | |/ _` | __/ _` |  __| / _` | | __/ _ \\| '__|\n");
	printf(" | |__| | (_| | || (_| | |___| (_| | | || (_) | |   \n");
	printf(" |_____/ \\__,_|\\__\\__,_|______\\__,_|_|\\__\\___/|_|   \n");
}

Function to give default values of 0 to a course record.

#include "project.h"

void InitializeRec(COURSE* CoursePointer)
{
	CoursePointer -> number[0] = 0;
	CoursePointer -> title [0] = 0;
	CoursePointer -> credit = 0;
	CoursePointer -> lab = FALSE;
	CoursePointer -> next = NULL;
	CoursePointer -> previous = NULL;

	return;
}

Function to add and link a record to the linked list.

#include "project.h"

void LinkRec(COURSE* new)
{
	COURSE* next_rec;                                        //Declare variables
	COURSE* prev_rec;

	if(!FIRST)                                              //if no records currently exist
	{
		FIRST = new;
		LAST = new;
		new->next = NULL;
		new->previous = NULL;
	}
	else
	{
		if(strcmp(new->number, FIRST->number) == -1)           //case new record will be first
		{
			new->previous = NULL;
			new->next = FIRST;
			FIRST->previous = new;
			FIRST = new;
		}
		
		if(strcmp(new->number, LAST->number) == 1)             //case new record will be last
		{
			new->next = NULL;
			new->previous = LAST;
			LAST->next = new;
			LAST = new;
		}

		if(strcmp(new->number, FIRST->number) == 1 && strcmp(new->number, LAST->number) == -1)         //case new record is in the middle
		{
			next_rec = FIRST;
			do
			{
				next_rec = (next_rec->next);
			}while(strcmp(next_rec->number, new->number) != 1);
				
		prev_rec = (next_rec->previous);
		(next_rec->previous) = new;
		(prev_rec->next) = new;
		new->next = next_rec;
		new->previous = prev_rec;				
		}
	}
	return;
}

Function to make a new database file.

#include "project.h"

void NewDat(void){
	char temp[256] = " ";
	char buffer[262] = "touch ";
	int dot;
	FILE* my_file;
	BOOLEAN error;
	int i;
	int j;
	int len;

	do                                                     //repeat if error
	{
		Header();
		printf("\nNew Database\n");
		printf("\nPlease input a filename for this new database: ");
		fgets(temp, 256, stdin);
		temp[strlen(temp)] = '\0';
		error = FALSE;
		dot = 0;

		for(i = 0; i < 256; i++)
		{
			if(temp[i] == '.')
				dot = i;
			if(temp[i] == '\n')
				temp[i] = '\0';
		}

		if(!dot)
		{
			len = strlen(temp);
			temp[len] = '.';
			temp[len + 1] = 'd';
			temp[len + 2] = 'a';
			temp[len + 3] = 't';
			temp[len + 4] = '\0';
		}
			strcat(buffer, temp);
			printf("%s", buffer);
			GetEnter();
			system(buffer);
			my_file = fopen(temp, "rt");                       //open file
			if(!my_file)                                           //error if file does not exist
		{
			printf("\nError\nThat file does not exist.\n");
			error = TRUE;
		}
	}while(error);
}

Function to open a database file and read in the values.

#include "project.h"

void OpenData(void)
{
	if(!filename[0])                                         //if database not open
	{
		char buff[255];                                        //Declare variables
		FILE* database;
		BOOLEAN error;
		int dot;
		int i = 0;
		int j = 0;
		int len;

		Header();
		printf("\nOpen Database\n");

		do                                                     //repeat if error
		{
			error = FALSE;
			dot = 0;

			printf("\nDatabases in folder: \n");
			system("dir *.dat");
			printf("\nPlease type the name of the file you wish to open\n");
			printf("If you do not add an extension the .dat file extention will be added for you.\n");
			fgets(filename, 255, stdin);
			for(i = 0; i < 256; i++)
			{
				if(filename[i] == '.')
					dot = i;
				if(filename[i] == '\n')
					filename[i] = '\0';
			}

			if(!dot)
			{
				len = strlen(filename);
				filename[len] = '.';
				filename[len + 1] = 'd';
				filename[len + 2] = 'a';
				filename[len + 3] = 't';
				filename[len + 4] = '\0';
			}

			database = fopen(filename, "rt");                       //open file

			if(!database)                                           //error if file does not exist
			{
				printf("\nError\nThat file does not exist.\n");
				error = TRUE;
			}
		}while(error);

		while(!feof(database))                                 //place values into array until EOF
		{
			buff[0] ='\0';

			fgets(buff, 17, database);
			for(i = 0; i < 17; i++)
			{
				array[j].number[i] = buff[i];
				if(buff[i] == '\n')
					array[j].number[i] ='\0';
			}

			fgets(buff, 65, database);
			for(i = 0; i < 65; i++)
			{
				array[j].title[i] = buff[i];
				if(buff[i] == '\n')
					array[j].title[i] = '\0';
			}

			fgets(buff, 3, database);
			for(i = 0; i < 4; i++)
				if(buff[i] == '\n')
					buff[i] = '\0';
			sscanf(buff, "%d", &array[j].credit);

			fgets(buff, 3, database);
			for(i = 0; i < 4; i++)
				if(buff[i] == '\n')
					buff[i] = '\0';
			sscanf(buff, "%d", &array[j].lab);

			j++;
		}

		fclose(database);                                      //Close file
		for(i = 0; i < 256; i++)                               //Link all elements of array
			if(array[i].number[0])
				LinkRec(&array[i]);
	}
	else
		printf("\nError\nDatabase already open.\n");           //Error if database open

	GetEnter();

	return;
}

Function to release memory and close the program.

#include "project.h"

BOOLEAN QuitProgram(void)
{
	BOOLEAN return_value;                                    //Declare return value variable
	BOOLEAN error;
	char buff[255];

	if(!filename[0])                                         //If database closed quit
	{
		printf("\nGood-bye\n");
		return_value = TRUE;
	}
	else                                                     //If database open ask to close
	{
		do
		{
			error = FALSE;
			printf("\nA database is open.\nDo you want to save before quitting? (Y/N): ");
			fgets(buff, 255, stdin);
			buff[0] = tolower(buff[0]);

			if((buff[0] != 'y' && buff[0] != 'n') || buff[1] != '\n')
			{
				printf("\nError\nPlease enter a valid response\n");
				error = TRUE;
			}
			else
			{
				if(buff[0] == 'y')
				{
					CloseData();
					return_value = QuitProgram();
				}
				else
				{
					filename[0] = '\0';
					return_value = QuitProgram();
				}
			}
		}while(error);
	}

	return(return_value);
}

Function to read a record from the file.

#include "project.h"

void ReadRec(COURSE* CoursePointer)
{
	FILE* record;                                            //Declare variables
	int i = 0;
	
	record = fopen("Record.txt", "rt");                      //Open file

	fgets(CoursePointer -> number, 17, record);             //read number
	for(i = 0; i <= 17; i++)
		if(CoursePointer -> number[i] == '\n')
			CoursePointer -> number[i] = '\0';

	fgets(CoursePointer -> title, 65, record);               //read title
	for(i = 0; i <= 65; i++)
		if(CoursePointer -> title[i] == '\n')
			CoursePointer -> title[i] = '\0';

	fscanf(record, "%d", &CoursePointer -> credit);          //read credit
	fscanf(record, "%d", &CoursePointer -> lab);             //read lab

	fclose(record);                                          //close file

	return;
}

Function to copy a record.

#include "project.h"

void RecCpy(COURSE* dest, COURSE* source)
{
	strcpy(dest -> number, source -> number);
	strcpy(dest -> title, source -> title);
	dest -> credit = source -> credit;
	dest -> lab = source -> lab;
	dest -> next = source -> next;
	dest -> previous = source -> previous;

	return;
}

Unfinished function that would have searched the database for a record.

#include "project.h"

void SearchData(void)
{
	printf("\nSearch for a Record\n");

	return;
}

Function to remove a linked list record from the list.

#include "project.h"

void UnlinkRec(COURSE* record)
{
	COURSE* record_prev;                                     //declare variables
	COURSE* record_next;
	BOOLEAN flag;

	record_prev = record -> previous;                        //intialize variables
	record_next = record -> next;
	flag = FALSE;

	if(record == FIRST && record == LAST && !flag)           //case: only record
	{
		LAST = NULL;
		FIRST = NULL;
	}

	if(record == FIRST && record != LAST && !flag)           //case: multiple records and first record
	{
		FIRST = record_next;
		record_next -> previous = NULL;
	}

	if(record != FIRST && record != LAST && !flag)           //case: multiple records and not first or last
	{
		record_prev -> next = record_next;
		record_next -> previous = record_prev;
	}

	if(record != FIRST && record == LAST && !flag)           //case: multiple records and last record
	{
		LAST = record_prev;
		record_prev -> next = NULL;
	}
	
	return;
}

Function to save a record to the file.

#include "project.h"

void WriteRec(COURSE* CoursePointer)
{
	FILE* record;                                            //Declare file pointer

	record = fopen("Record.txt", "wt");                      //Open file
	fprintf(record, "%s\n", CoursePointer -> number);
	fprintf(record, "%s\n", CoursePointer -> title);
	fprintf(record, "%d\n", CoursePointer -> credit);
	fprintf(record, "%d\n", CoursePointer -> lab);

	fclose(record);                                          //Close file

	return;
}

Comments

Popular posts from this blog

Reading Strings in C

How to Install LAMP in Ubuntu