📄 app_ui.c
字号:
/* We now move on to the user interface. This gives us a (relatively) simple program with which to access our database functions, which we'll implement in a separate file. We start, as usual, with some header files. */#define _XOPEN_SOURCE#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include "cd_data.h"#define TMP_STRING_LEN 125 /* this number must be larger than the biggest single string in any database structure *//* We make our menu options typedefs. This is in preference to using #defined constants, as it allows the compiler to check the types of the menu option variables. */typedef enum { mo_invalid, mo_add_cat, mo_add_tracks, mo_del_cat, mo_find_cat, mo_list_cat_tracks, mo_del_tracks, mo_count_entries, mo_exit} menu_options;/* Now the prototypes for the local functions. The prototypes for accessing the database were included in cd_data.h. */static int command_mode(int argc, char *argv[]);static void announce(void);static menu_options show_menu(const cdc_entry *current_cdc);static int get_confirm(const char *question);static int enter_new_cat_entry(cdc_entry *entry_to_update);static void enter_new_track_entries(const cdc_entry *entry_to_add_to);static void del_cat_entry(const cdc_entry *entry_to_delete);static void del_track_entries(const cdc_entry *entry_to_delete);static cdc_entry find_cat(void);static void list_tracks(const cdc_entry *entry_to_use);static void count_all_entries(void);static void display_cdc(const cdc_entry *cdc_to_show);static void display_cdt(const cdt_entry *cdt_to_show);static void strip_return(char *string_to_strip);/* Finally, we get to main. This starts by ensuring the current_cdc_entry that we use to keep track of the currently selected CD catalog entry is initialized. We also parse the command line, announce what program is being run and initialize the database. */int main(int argc, char *argv[]){ menu_options current_option; cdc_entry current_cdc_entry; int command_result; memset(¤t_cdc_entry, '\0', sizeof(current_cdc_entry)); if (argc > 1) { command_result = command_mode(argc, argv); exit(command_result); } announce(); if (!database_initialize(0)) { fprintf(stderr, "Sorry, unable to initialize database\n"); fprintf(stderr, "To create a new database use %s -i\n", argv[0]); exit(EXIT_FAILURE); }/* We're now ready to process user input. We sit in a loop, asking for a menu choice and processing it, until the user selects the exit option. We pass the current_cdc_entry structure to the show_menu function. We do this to allow the menu choices to change if a catalog entry is currently selected. */while(current_option != mo_exit) { current_option = show_menu(¤t_cdc_entry); switch(current_option) { case mo_add_cat: if (enter_new_cat_entry(¤t_cdc_entry)) { if (!add_cdc_entry(current_cdc_entry)) { fprintf(stderr, "Failed to add new entry\n"); memset(¤t_cdc_entry, '\0', sizeof(current_cdc_entry)); } } break; case mo_add_tracks: enter_new_track_entries(¤t_cdc_entry); break; case mo_del_cat: del_cat_entry(¤t_cdc_entry); break; case mo_find_cat: current_cdc_entry = find_cat(); break; case mo_list_cat_tracks: list_tracks(¤t_cdc_entry); break; case mo_del_tracks: del_track_entries(¤t_cdc_entry); break; case mo_count_entries: count_all_entries(); break; case mo_exit: break; case mo_invalid: break; default: break; } /* switch */ } /* while *//* When the main loop exits, we close the database and exit back to the environment. The welcoming sentence is printed by the announce function. */ database_close(); exit(EXIT_SUCCESS);} /* main */static void announce(void){ printf("\n\nWelcome to the demonstration CD catalog database \ program\n");}/* Here we implement the show_menu function. This checks whether a current catalog entry is selected, using the first character of the catalog name. More options are available if a catalog entry is selected. Numbers are now used to select menu items rather than the initial letters that we used in the previous two examples. */static menu_options show_menu(const cdc_entry *cdc_selected){ char tmp_str[TMP_STRING_LEN + 1]; menu_options option_chosen = mo_invalid; while (option_chosen == mo_invalid) { if (cdc_selected->catalog[0]) { printf("\n\nCurrent entry: "); printf("%s, %s, %s, %s\n", cdc_selected->catalog, cdc_selected->title, cdc_selected->type, cdc_selected->artist); printf("\n"); printf("1 - add new CD\n"); printf("2 - search for a CD\n"); printf("3 - count the CDs and tracks in the database\n"); printf("4 - re-enter tracks for current CD\n"); printf("5 - delete this CD, and all its tracks\n"); printf("6 - list tracks for this CD\n"); printf("q - quit\n"); printf("\nOption: "); fgets(tmp_str, TMP_STRING_LEN, stdin); switch(tmp_str[0]) { case '1': option_chosen = mo_add_cat; break; case '2': option_chosen = mo_find_cat; break; case '3': option_chosen = mo_count_entries; break; case '4': option_chosen = mo_add_tracks; break; case '5': option_chosen = mo_del_cat; break; case '6': option_chosen = mo_list_cat_tracks; break; case 'q': option_chosen = mo_exit; break; } } else { printf("\n\n"); printf("1 - add new CD\n"); printf("2 - search for a CD\n"); printf("3 - count the CDs and tracks in the database\n"); printf("q - quit\n"); printf("\nOption: "); fgets(tmp_str, TMP_STRING_LEN, stdin); switch(tmp_str[0]) { case '1': option_chosen = mo_add_cat; break; case '2': option_chosen = mo_find_cat; break; case '3': option_chosen = mo_count_entries; break; case 'q': option_chosen = mo_exit; break; } } } /* while */ return(option_chosen);}/* There are several places where we wish to ask the user if they are sure about what they requested. Rather than have several places in the code asking the question, we extract the code as a separate function, get_confirm. */static int get_confirm(const char *question){ char tmp_str[TMP_STRING_LEN + 1]; printf("%s", question); fgets(tmp_str, TMP_STRING_LEN, stdin); if (tmp_str[0] == 'Y' || tmp_str[0] == 'y') { return(1); } return(0);}/* The function, enter_new_cat_entry, allows the user to enter a new catalog entry. We don't want to store the linefeed that fgets returns, so we strip it off. We don't use the gets function since it has no way of checking for an overflow of the buffer. */static int enter_new_cat_entry(cdc_entry *entry_to_update){ cdc_entry new_entry; char tmp_str[TMP_STRING_LEN + 1]; memset(&new_entry, '\0', sizeof(new_entry)); printf("Enter catalog entry: "); (void)fgets(tmp_str, TMP_STRING_LEN, stdin); strip_return(tmp_str); strncpy(new_entry.catalog, tmp_str, CAT_CAT_LEN - 1); printf("Enter title: "); (void)fgets(tmp_str, TMP_STRING_LEN, stdin); strip_return(tmp_str); strncpy(new_entry.title, tmp_str, CAT_TITLE_LEN - 1); printf("Enter type: "); (void)fgets(tmp_str, TMP_STRING_LEN, stdin); strip_return(tmp_str); strncpy(new_entry.type, tmp_str, CAT_TYPE_LEN - 1); printf("Enter artist: "); (void)fgets(tmp_str, TMP_STRING_LEN, stdin); strip_return(tmp_str); strncpy(new_entry.artist, tmp_str, CAT_ARTIST_LEN - 1); printf("\nNew catalog entry entry is :-\n"); display_cdc(&new_entry); if (get_confirm("Add this entry ?")) { memcpy(entry_to_update, &new_entry, sizeof(new_entry)); return(1); } return(0);}/* We now come to the function for entering the track information, enter_new_track_entries. This is slightly more complex than the catalog entry function, because we allow an existing track entry to be left alone. */static void enter_new_track_entries(const cdc_entry *entry_to_add_to){ cdt_entry new_track, existing_track; char tmp_str[TMP_STRING_LEN + 1]; int track_no = 1; if (entry_to_add_to->catalog[0] == '\0') return; printf("\nUpdating tracks for %s\n", entry_to_add_to->catalog); printf("Press return to leave existing description unchanged,\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -