// ============================================ // Final-Projekt: Todo-App in C // Ein vollständiges CLI-Programm mit CRUD-Operationen // ============================================ #include #include #include #include #include #define MAX_TODOS 100 #define MAX_TITLE 100 #define MAX_DESC 500 #define DATA_FILE "todos.dat" // Datenstruktur für ein Todo typedef struct { int id; char title[MAX_TITLE]; char description[MAX_DESC]; bool completed; time_t created_at; } Todo; // Datenstruktur für die Todo-Liste typedef struct { Todo items[MAX_TODOS]; int count; } TodoList; // Funktionsprototypen void todo_init(TodoList* list); void todo_add(TodoList* list, const char* title, const char* description); void todo_list(const TodoList* list); void todo_complete(TodoList* list, int id); void todo_delete(TodoList* list, int id); void todo_save(const TodoList* list); void todo_load(TodoList* list); void print_menu(void); void clear_input_buffer(void); // ============================================ // IMPLEMENTATION // ============================================ void todo_init(TodoList* list) { list->count = 0; for (int i = 0; i < MAX_TODOS; i++) { list->items[i].id = 0; list->items[i].title[0] = '\0'; list->items[i].description[0] = '\0'; list->items[i].completed = false; list->items[i].created_at = 0; } } void todo_add(TodoList* list, const char* title, const char* description) { if (list->count >= MAX_TODOS) { printf("Fehler: Maximale Anzahl erreicht!\n"); return; } Todo* new_todo = &list->items[list->count]; new_todo->id = list->count + 1; strncpy(new_todo->title, title, MAX_TITLE - 1); new_todo->title[MAX_TITLE - 1] = '\0'; strncpy(new_todo->description, description, MAX_DESC - 1); new_todo->description[MAX_DESC - 1] = '\0'; new_todo->completed = false; new_todo->created_at = time(NULL); list->count++; printf("Todo #%d hinzugefügt!\n", new_todo->id); } void todo_list(const TodoList* list) { if (list->count == 0) { printf("Keine Todos vorhanden.\n"); return; } printf("\n=== DEINE TODOS ===\n"); printf("%-4s | %-10s | %-30s | %-20s\n", "ID", "Status", "Titel", "Erstellt"); printf("-----+------------+--------------------------------+--------------------\n"); for (int i = 0; i < list->count; i++) { const Todo* todo = &list->items[i]; char date_str[26]; ctime_r(&todo->created_at, date_str); date_str[24] = '\0'; // Remove newline const char* status = todo->completed ? "[✓] Done " : "[ ] Open "; printf("%-4d | %s | %-30s | %.20s\n", todo->id, status, todo->title, date_str); if (strlen(todo->description) > 0) { printf(" | | %s\n", todo->description); } } printf("\n"); } void todo_complete(TodoList* list, int id) { for (int i = 0; i < list->count; i++) { if (list->items[i].id == id) { list->items[i].completed = !list->items[i].completed; printf("Todo #%d %s!\n", id, list->items[i].completed ? "abgeschlossen" : "wieder geöffnet"); return; } } printf("Fehler: Todo #%d nicht gefunden!\n", id); } void todo_delete(TodoList* list, int id) { int found_index = -1; for (int i = 0; i < list->count; i++) { if (list->items[i].id == id) { found_index = i; break; } } if (found_index == -1) { printf("Fehler: Todo #%d nicht gefunden!\n", id); return; } // Array komprimieren for (int i = found_index; i < list->count - 1; i++) { list->items[i] = list->items[i + 1]; list->items[i].id = i + 1; // ID neu zuweisen } list->count--; printf("Todo #%d gelöscht!\n", id); } void todo_save(const TodoList* list) { FILE* file = fopen(DATA_FILE, "wb"); if (!file) { printf("Fehler: Konnte Datei nicht öffnen!\n"); return; } fwrite(&list->count, sizeof(int), 1, file); fwrite(list->items, sizeof(Todo), list->count, file); fclose(file); printf("Todos gespeichert!\n"); } void todo_load(TodoList* list) { FILE* file = fopen(DATA_FILE, "rb"); if (!file) { printf("Keine gespeicherte Daten gefunden. Starte neu...\n"); return; } fread(&list->count, sizeof(int), 1, file); fread(list->items, sizeof(Todo), list->count, file); fclose(file); printf("%d Todos geladen!\n", list->count); } void print_menu(void) { printf("\n=== TODO-APP ===\n"); printf("1. Todo hinzufügen\n"); printf("2. Todos anzeigen\n"); printf("3. Todo abschließen/öffnen\n"); printf("4. Todo löschen\n"); printf("5. Speichern\n"); printf("6. Beenden\n"); printf("Wahl: "); } void clear_input_buffer(void) { int c; while ((c = getchar()) != '\n' && c != EOF); } // ============================================ // HAUPTPROGRAMM // ============================================ int main(void) { TodoList list; todo_init(&list); todo_load(&list); int choice; char title[MAX_TITLE]; char description[MAX_DESC]; int id; printf("\n📝 Willkommen zur Todo-App!\n"); while (true) { print_menu(); if (scanf("%d", &choice) != 1) { clear_input_buffer(); printf("Ungültige Eingabe!\n"); continue; } clear_input_buffer(); switch (choice) { case 1: printf("Titel: "); fgets(title, MAX_TITLE, stdin); title[strcspn(title, "\n")] = '\0'; // Remove newline printf("Beschreibung (optional): "); fgets(description, MAX_DESC, stdin); description[strcspn(description, "\n")] = '\0'; todo_add(&list, title, description); break; case 2: todo_list(&list); break; case 3: printf("Todo-ID: "); if (scanf("%d", &id) == 1) { todo_complete(&list, id); } clear_input_buffer(); break; case 4: printf("Todo-ID: "); if (scanf("%d", &id) == 1) { todo_delete(&list, id); } clear_input_buffer(); break; case 5: todo_save(&list); break; case 6: printf("Speichern vor Beenden? (j/n): "); char save_choice; scanf(" %c", &save_choice); if (save_choice == 'j' || save_choice == 'J') { todo_save(&list); } printf("Auf Wiedersehen!\n"); return 0; default: printf("Ungültige Wahl!\n"); } } return 0; }