This is a reservations app with linked lists for insertion and BST for search. It uses CSV files for storage, recursion for printing and handles memory allocation for variable growth.
I'm looking for tips to simplify, speed up, and make code clearer.
//===== Imports =====
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
//===== Data Structures =====
typedef struct {
int y, m, d;
} Date;
typedef struct {
Date date;
char *name;
} Reservation;
typedef struct Node {
Reservation r;
struct Node* next;
} Node;
typedef struct TreeNode {
Reservation r;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
//===== Utilities =====
static char* strdupMallocChecked(const char* s) {
if (!s) s = "";
char* p = malloc(strlen(s) + 1);
if (!p) { perror("malloc"); exit(EXIT_FAILURE); }
strcpy(p, s);
return p;
}
static bool validateDate(int y, int m, int d) {
if (m < 1 || m > 12) return false;
int dm[] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (m == 2 && ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))) dm[1] = 29;
return d >= 1 && d <= dm[m-1];
}
static Date getCurrentDate(void) {
time_t t = time(NULL);
struct tm *tm_info = localtime(&t);
return (Date){ tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday };
}
static int dateCompareDate(const Date *a, const Date *b) {
if (a->y != b->y) return a->y - b->y;
if (a->m != b->m) return a->m - b->m;
return a->d - b->d;
}
static int reservationCompare(const Reservation *A, const Reservation *B) {
int d = dateCompareDate(&A->date, &B->date);
if (d != 0) return d;
return strcmp(A->name ? A->name : "", B->name ? B->name : "");
}
//===== Insert =====
static void insertListSorted(Node** head, const Reservation* r) {
Node* n = malloc(sizeof(Node));
if (!n) { perror("malloc"); exit(EXIT_FAILURE); }
n->r.date = r->date;
n->r.name = strdupMallocChecked(r->name);
n->next = NULL;
if (!*head || reservationCompare(&n->r, &(*head)->r) < 0) {
n->next = *head;
*head = n;
return;
}
Node* cur = *head;
while (cur->next && reservationCompare(&cur->next->r, &n->r) <= 0) cur = cur->next;
n->next = cur->next;
cur->next = n;
}
static void insertTreeByDate(TreeNode** root, const Reservation* r) {
TreeNode** cur = root;
while (*cur) {
int cmp = dateCompareDate(&r->date, &(*cur)->r.date);
if (cmp < 0) cur = &(*cur)->left;
else if (cmp > 0) cur = &(*cur)->right;
else cur = (strcmp(r->name, (*cur)->r.name) < 0) ? &(*cur)->left : &(*cur)->right;
}
*cur = malloc(sizeof(TreeNode));
if (!*cur) { perror("malloc"); exit(EXIT_FAILURE); }
(*cur)->r.date = r->date;
(*cur)->r.name = strdupMallocChecked(r->name);
(*cur)->left = NULL;
(*cur)->right = NULL;
}
//===== Checks =====
static bool isDateAvailable(Node* head, const Date *d) {
for (Node* n = head; n; n = n->next)
if (dateCompareDate(&n->r.date, d) == 0) return false;
return true;
}
//===== Input =====
static void readLineTrim(char **buf) {
size_t len = 0;
ssize_t n = getline(buf, &len, stdin);
if (n > 0 && (*buf)[n-1] == '\n') (*buf)[n-1] = '\0';
}
static Reservation inputReservation(void) {
Reservation r = {.date={0,0,0}, .name=NULL};
Date cur = getCurrentDate();
char *buf = NULL;
printf("Enter company name: ");
readLineTrim(&buf);
if (!buf || buf[0]=='\0') { free(buf); buf = strdupMallocChecked("unnamed"); }
r.name = strdupMallocChecked(buf);
free(buf);
for (;;) {
printf("Enter reservation date (YYYY MM DD): ");
buf = NULL;
readLineTrim(&buf);
int y,m,d;
if (sscanf(buf,"%d %d %d",&y,&m,&d)!=3) { printf("Invalid format. Try again.\n"); free(buf); continue; }
free(buf);
if (!validateDate(y,m,d)) { printf("Invalid date.\n"); continue; }
Date tmp={y,m,d};
if (dateCompareDate(&tmp,&cur)<0) { printf("Cannot choose past date.\n"); continue; }
r.date=tmp; break;
}
return r;
}
//===== CSV I/O =====
static void saveCSV(Node* head) {
FILE* f = fopen("res.csv","w");
if (!f) { perror("saveCSV"); return; }
for (Node* n=head;n;n=n->next)
fprintf(f,"%04d,%02d,%02d,%s\n",n->r.date.y,n->r.date.m,n->r.date.d,n->r.name);
fclose(f);
}
static void loadCSV(Node** head, TreeNode** root) {
FILE* f = fopen("res.csv","r");
if (!f) { perror("loadCSV"); return; }
char* lineBuf=NULL; size_t len=0;
while (getline(&lineBuf,&len,f)!=-1) {
lineBuf[strcspn(lineBuf,"\r\n")] = 0;
char* token = strtok(lineBuf,","); if(!token) continue; int y=atoi(token);
token=strtok(NULL,","); if(!token) continue; int m=atoi(token);
token=strtok(NULL,","); if(!token) continue; int d=atoi(token);
token=strtok(NULL,","); if(!token) continue; char* name=strdupMallocChecked(token);
Reservation r={{y,m,d},name};
insertListSorted(head,&r);
insertTreeByDate(root,&r);
free(name);
}
free(lineBuf);
fclose(f);
}
//===== Print =====
static void printListRecursive(const Node* n) {
if(!n) return;
printf("%04d-%02d-%02d : %s\n",n->r.date.y,n->r.date.m,n->r.date.d,n->r.name);
printListRecursive(n->next);
}
//===== Search =====
static TreeNode* searchTreeByName(const TreeNode* t,const char* key) {
if(!t) return NULL;
int cmp=strcmp(key,t->r.name);
if(cmp==0) return (TreeNode*)t;
else if(cmp<0) return searchTreeByName(t->left,key);
else return searchTreeByName(t->right,key);
}
static Node* searchListByName(const Node* n,const char* key) {
if(!n) return NULL;
if(strcmp(n->r.name,key)==0) return (Node*)n;
return searchListByName(n->next,key);
}
//===== Free =====
static void freeList(Node* n) {
while(n) {
Node* nx = n->next;
free(n->r.name);
free(n);
n = nx;
}
}
static void freeTree(TreeNode* t) {
if(!t) return;
freeTree(t->left);
freeTree(t->right);
free(t->r.name);
free(t);
}
static void cleanup(Node** head, TreeNode** root) {
freeList(*head);
*head=NULL;
freeTree(*root);
*root=NULL;
}
//===== High-level API =====
static void addReservationFlow(Node** head, TreeNode** root) {
Reservation r = inputReservation();
if(!isDateAvailable(*head,&r.date)) {
printf("Room booked.\n");
free(r.name);
return;
}
insertListSorted(head,&r);
insertTreeByDate(root,&r);
printf("Reservation successful.\n");
free(r.name);
}
//===== Menu =====
static void menuLoop(void) {
Node* head=NULL;
TreeNode* root=NULL;
loadCSV(&head,&root);
for(;;) {
puts("\n1.Add 2.Show reservations 3.Search 4.Save+Exit");
printf("Choice: ");
char* choice=NULL;
readLineTrim(&choice);
int o=atoi(choice);
free(choice);
if(o==1) {
addReservationFlow(&head,&root);
} else if(o==2) {
printListRecursive(head);
} else if(o==3) {
char* key=NULL;
printf("Enter company name to search: ");
readLineTrim(&key);
Node* resList = searchListByName(head,key);
TreeNode* resTree = searchTreeByName(root,key);
if(resList) printf("Found (list): %04d-%02d-%02d %s\n",resList->r.date.y,resList->r.date.m,resList->r.date.d,resList->r.name);
if(resTree) printf("Found (tree): %04d-%02d-%02d %s\n",resTree->r.date.y,resTree->r.date.m,resTree->r.date.d,resTree->r.name);
if(!resList && !resTree) printf("Not found.\n");
free(key);
} else {
saveCSV(head);
break;
}
}
cleanup(&head,&root);
}
//===== Main =====
int main(void) {
menuLoop();
return EXIT_SUCCESS;
}