📄 curses.c
字号:
/* CD Database Application Beginner's Guide to UNIX Programming with Linux Version: Terminals Copyright (c) 1996 Wrox Press This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Fee Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hopes that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. *//* Notes This version of the CD database application has been written using the information presented in the Terminals chapter. It is derived from the shell script presented in the Shell Programming chapter. It has not been redesigned for the C implementation, so many features of the shell original can still be seen in this version. There are some problems with this implementation that will be resolved in later revisions: It does not deal with commas in titles. It has a practical limit on tracks per CD to keep them on screen. The program deliberately uses the standard input and output file streams. It does not deal with re-directed input or output explicitly. */#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <curses.h>#define MAX_STRING (80) /* Longest allowed response */#define MAX_ENTRY (1024) /* Longest allowed database entry */#define MESSAGE_LINE 6 /* Misc. messages go here */#define ERROR_LINE 22 /* The line to use for errors */#define Q_LINE 20 /* Line for Questions */#define PROMPT_LINE 18 /* Line for prompting on *//* The variable current_cd is used to store the CD title we are working with. It is initialized so that the first character is NUL to indicate 'no CD selected'. The \0 is strictly unnecessary, but serves to emphasize the point. The variable current_cat will be used to record the catalog number of the current CD. */static char current_cd[MAX_STRING] = "\0";static char current_cat[MAX_STRING];/* File names. These files are fixed in this version to keep things simple. The temporary file name is also fixed, this would cause a problem if this program is run by two users in the same directory. A better way to obtain data base file names would be either by program arguments, or from environment variables. We need a better way to generate a unique a temporary file name. Many of these issues will be addresed in later versions. */const char *title_file = "title.cdb";const char *tracks_file = "tracks.cdb";const char *temp_file = "cdb.tmp";/* Prototypes for local functions */void clear_all_screen(void);void get_return(void);int get_confirm(void);int getchoice(char *greet, char *choices[]);void draw_menu(char *options[], int highlight, int start_row, int start_col);void insert_title(char *cdtitle);void get_string(char *string);void add_record(void);void count_cds(void);void find_cd(void);void list_tracks(void);void remove_tracks(void);void remove_cd(void);void update_cd(void);/* Menu structures. The first character is the character to return when the chice is selected, the remaining text is to be displayed. */char *main_menu[] ={ "aadd new CD", "ffind CD", "ccount CDs and tracks in the catalog", "qquit", 0,};/* The extended menu is displayed when a CD is currently selected */char *extended_menu[] ={ "aadd new CD", "ffind CD", "ccount CDs and tracks in the catalog", "llist tracks on current CD", "rremove current CD", "uupdate track information", "qquit", 0,};int main(){ int choice; initscr(); do { choice = getchoice("Options:", current_cd[0] ? extended_menu : main_menu); switch (choice) { case 'q': break; case 'a': add_record(); break; case 'c': count_cds(); break; case 'f': find_cd(); break; case 'l': list_tracks(); break; case 'r': remove_cd(); break; case 'u': update_cd(); break; } } while (choice != 'q'); endwin(); exit(EXIT_SUCCESS);} /* main *//* getchoice - ask the user to choose passed: greet, an introduction choices, an array of strings, NULL at end */int getchoice(char *greet, char *choices[]){ static int selected_row = 0; int max_row = 0; int start_screenrow = MESSAGE_LINE, start_screencol = 10; char **option; int selected; int key = 0; option = choices; while (*option) { max_row++; option++; } /* protect against menu getting shorted when CD deleted */ if (selected_row >= max_row) selected_row = 0; clear_all_screen(); mvprintw(start_screenrow - 2, start_screencol, greet); keypad(stdscr, TRUE); cbreak(); noecho(); key = 0; while (key != 'q' && key != KEY_ENTER && key != '\n') { if (key == KEY_UP) { if (selected_row == 0) selected_row = max_row - 1; else selected_row--; } if (key == KEY_DOWN) { if (selected_row == (max_row - 1)) selected_row = 0; else selected_row++; } selected = *choices[selected_row]; draw_menu(choices, selected_row, start_screenrow, start_screencol); key = getch(); } keypad(stdscr, FALSE); nocbreak(); echo(); if (key == 'q') selected = 'q'; return (selected);}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) { mvaddch(start_row + current_row, start_col - 3, ACS_BULLET); mvaddch(start_row + current_row, start_col + 40, ACS_BULLET); } else { mvaddch(start_row + current_row, start_col - 3, ' '); mvaddch(start_row + current_row, start_col + 40, ' '); } txt_ptr = options[current_row]; txt_ptr++; mvprintw(start_row + current_row, start_col, "%s", txt_ptr); current_row++; option_ptr++; } mvprintw(start_row + current_row + 3, start_col, "Move highlight then press Return "); refresh();}/* clear_all_screen Clear the screen and re-write the title. If a CD is selected then display the information. */void clear_all_screen(){ clear(); mvprintw(2, Q_LINE, "%s", "CD Database Application"); if (current_cd[0]) { mvprintw(ERROR_LINE, 0, "Current CD: %s: %s\n", current_cat, current_cd); } refresh();}/* get_return Prompt for and read a carriage return. Ignore other characters. */void get_return(){ int ch; mvprintw(23, 0, "%s", " Press return "); refresh(); while ((ch = getchar()) != '\n' && ch != EOF);}/* get_confirm Prompt for and read confirmation. Read a string and check first character for Y or y. On error or other character return no confirmation. */int get_confirm(){ int confirmed = 0; char first_char = 'N'; 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;}/* Database File Manipulation Functions *//* insert_title Add a title to the CD database Simply add the title string to the end of the titles file */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, "%s\n", cdtitle); fclose(fp); }}/* get_string At the current screen position prompt for and read a string Delete any trailing newline. */void get_string(char *string){ int len; wgetnstr(stdscr, string, MAX_STRING); len = strlen(string);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -