Основы программирования в Linux - Нейл Мэтью
Шрифт:
Интервал:
Закладка:
keypad(stdscr, FALSE);
nocbreak();
echo();
if (key == 'q') selected = 'q';
return(selected);
}
2. Обратите внимание на то, как две локальные функции clear_all_screen и draw_menu вызываются внутри функции getchoice. Первой рассмотрим функцию draw_menu:
void draw_menu(char* options[], int current_highlight, int start_row, int start_col) {
int current_row = 0;
char **option_ptr;
char *txt_ptr;
option_ptr = options;
while (*option_ptr) {
if (current_row == current_highlight) attron(A_STANDOUT);
txt_ptr = options[current_row];
txt_ptr++;
mvprintw(start_row + current_row, start_col, "%s", txt_ptr);
if (current_row == current_highlight) attroff(A_STANDOUT);
current_row++;
option_ptr++;
}
mvprintw(start_row + current_row + 3, start_col,
"Move highlight then press Return ");
refresh();
}
3. Далее рассмотрим функцию clear_all_screen, которая, как ни странно, очищает экран и перезаписывает заголовок. Если компакт-диск выбран, отображаются его данные:
void clear all_screen() {
clear();
mvprintw(2, 20, "%s", "CD Database Application");
if (current_cd[0]) {
mvprintw(ERROR_LINE, 0, "Current CD: %s: %sn", current_cat, current_cd);
}
refresh();
}
Управление базой данных
В этом разделе описаны функции пополнения или обновления базы данных компакт-дисков. Функции add_record, update_cd и remove_cd вызываются из функции main.
Добавление записей1. Добавьте сведения о новом компакт-диске в базу данных.
void add_record {
char catalog_number[MAX_STRING];
char cd_title[MAX_STRING];
char cd_type[MAX_STRING];
char cd_artist[MAX_STRING];
char cd_entry[MAX_STRING];
int screenrow = MESSAGE_LINE;
int screencol = 10;
clear_all_screen();
mvprintw(screenrow, screencol, "Enter new CD details");
screenrow += 2;
mvprintw(screenrow, screencol, "Catalog Number: " );
get_string(catalog_number);
screenrow++;
mvprintw(screenrow, screencol, " CD Title: ");
get_string(cd_title);
screenrow++;
mvprintw(screenrow, screencol, " CD Type: ");
get_string(cd_type);
screenrow++;
mvprintw(screenrow, screencol, " Artist: ");
get_string(cd_artist);
screenrow++;
mvprintw(PROMPT_LINE-2, 5, "About to add this new entry:");
sprintf(cd_entry, "%s, %s, %s, %s",
catalog_number, cd_title, cd_type, cd_artist);
mvprintw(PROMPT_LINE, 5, "%s", cd_entry);
refresh();
move(PROMPT_LINE, 0);
if (get_confirm()) {
insert_title(cd_entry);
strcpy(current_cd, cd_title);
strcpy(current_cat, catalog_number);
}
}
2. Функция get_string приглашает к вводу и считывает строку из текущей позиции экрана. Она также удаляет завершающую новую пустую строку:
void get_string(char* string) {
int len;
wgetnstr(stdscr, string, MAX_STRING);
len = strlen(string);
if (len > 0 && string[len - 1] == 'n') string[len - 1] = ' ';
}
3. Функция get_confirm запрашивает и считывает пользовательское подтверждение. Она читает введенную пользователем строку и проверяет, первый символ — Y или у. Если она обнаруживает другой символ, то не дает подтверждения.
int get_confirm() {
int confirmed = 0;
char first_char;
mvprintw(Q_LINE, 5, "Are you sure? ");
clrtoeol();
refresh();
cbreak();
first_char = getch();
if (first_char == 'Y' || first_char == 'y') {
confirmed = 1;
}
nocbreak();
if (!confirmed) {
mvprintw(Q_LINE, 1, " Cancelled");
clrtoeol();
refresh();
sleep(1);
}
return confirmed;
}
4. Последней рассмотрим функцию insert_title. Она вставляет в базу данных компакт-дисков заголовок, добавляя строку с заголовком в конец файла заголовков:
void insert_title(char* cdtitle) {
FILE *fp = fopen(title_file, "a");
if (!fp) {
mvprintw(ERROR_LINE, 0, "cannot open CD titles database");
} else {
fprintf(fp, "%sn", cdtitle);
fclose(fp);
}
}
Обновление записей1. Продолжим рассмотрение других управляющих функций, вызываемых из функции main. Следующая из них — функция update_cd. Эта функция использует обведенное рамкой вложенное окно с прокруткой и нуждается в нескольких константах, которые объявляются как глобальные, поскольку они позже потребуются функции list_tracks.
#define BOXED_LINES 11
#define BOXED_ROWS 60
#define BOX_LINE_POS 8
#define BOX_ROW_POS 2
2. Функция update_cd позволяет пользователю заново ввести сведения о дорожках текущего компакт-диска. Удалив предыдущие записи о дорожках, она приглашает ввести новую информацию.
void update_cd() {
FILE *tracks_fp;
char track_name[MAX_STRING];
int len;
int track = 1;
int screen_line = 1;
WINDOW *box_window_ptr;
WINDOW *sub_window_ptr;
clear_all_screen();
mvprintw(PROMPT_LINE, 0, "Re-entering tracks for CD. ");
if (!get_confirm())
return;
move(PROMP_TLINE, 0);
clrtoeol();
remove_tracks();
mvprintw(MESSAGE_LINE, 0, "Enter a blank line to finish");
tracks_fp = fopen(tracks_file, "a");
ПримечаниеЛистинг будет продолжен через минуту; мы хотим сделать краткую паузу, чтобы обратить ваше внимание на ввод данных в обрамленное окно с прокруткой. Хитрость заключается в формировании вложенного окна, рисовании рамки по его краю и создании внутри этого окна нового вложенного окна с прокруткой.
box_window_ptr = subwin(stdscr, BOXED_LINES + 2, BOXED_ROWS + 2,
BOX_LINE_POS - 1, BOX_ROW_POS - 1);
if (!box_window_ptr) return;
box(box_window_ptr, ACS_VLINE, ACS_HLINE);
sub_window_ptr = subwin(stdscr, BOXED_LINES, BOXED_ROWS,
BOX_LINE_POS, BOX_ROW_POS);
if (!sub_window_ptr) return;
scrollok(sub_window_ptr, TRUE);
werase(sub_window_ptr);
touchwin(stdscr);
do {
mvwprintw(sub_window_ptr, screen_line++, BOX_ROW_POS + 2,
"Track %d: ", track);
clrtoeol();
refresh();
wgetnstr(sub_window_ptr, track_name, MAX_STRING);
len = strlen(track_name);
if (len > 0 && track_name[len - 1] = 'n')
track_name[len - 1] = ' ';
if (*track_name)
fprintf(tracks_fp, "%s, %d, %sn", current_cat, track, track_name);
track++;
if (screen_line > BOXED__LINES - 1) {
/* время начать прокрутку */
scroll(sub_window_ptr);
screen_line--;
}
} while (*track_name);
delwin(sub_window_ptr);
fclose(tracks_fp);
}
Удаление записей1. remove_cd — последняя функция, вызываемая из функции main.
void remove_cd() {
FILE *titles_fp, *temp_fp;
char entry[MAX_ENTRY];
int cat_length;
if (current_cd[0] == ' ') return;
clear_all_screen();
mvprintw(PROMPT_LINE, 0, "About to remove CD %s: %s. ", current_cat, current_cd);
if (!get_confirm())
return;
cat_length = strlen(current_cat);
/* Файл заголовков копируется во временный, игнорируя данный CD */
titles_fp = fopen(title_file, "r");
temp_fp = fopen(temp_flie, "w");
while(fgets(entry, MAX_ENTRY, titles_fp)) {
/* Сравнивает номер в каталоге и копирует элемент, если не
найдено совпадение */
if (strncmp(current_cat, entry, cat_length) != 0)
fputs(entry, temp_fp);
}
fclose(titles_fp);
fclose(temp_fp);
/* Удаляет файл заголовков и переименовывает временный файл */
unlink(title_file);
rename(temp_file, title_file);
/* Теперь делает то же самое для файла дорожек */
remove_tracks();
/* Устанавливает 'None' для текущего CD */
current_cd[0] = ' ';
}
2. Теперь вам только нужен программный код функции remove_tracks, удаляющей дорожки текущего компакт-диска. Она вызывается двумя функциями — update_cd и remove_cd.
void remove_tracks() {
FILE *tracks_fp, *temp_fp;
char entry[MAX_ENTRY];
int cat_length;
if (current_cd[0] == ' ') return;
cat_length = strlen(current_cat);
tracks_fp = fopen(tracks_file, "r");
if (tracks_fp == (FILE *)NULL) return;
temp_fp = fopen(temp_file, "w");
while (fgets(entry, MAX_ENTRY, tracks_fp)) {
/* Сравнивает номер в каталоге и копирует элемент, если не
найдено совпадение */
if (strncmp(current_cat, entry, cat_length) != 0)