代码:
1 //This is c program code! 2 /* *=+=+=+=+* *** *=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= 3 * 文档信息: *** :~/WORKM/stutyCode/linuxPrograming/manageDisk/diskManage.c 4 * 版权声明: *** :(魎魍魅魑)MIT 5 * 联络信箱: *** :guochaoxxl@163.com 6 * 创建时间: *** :2020年12月12日的上午10:43 7 * 文档用途: *** :数据结构与算法分析-c语言描述 8 * 作者信息: *** :guochaoxxl(http://cnblogs.com/guochaoxxl) 9 * 修订时间: *** :2020年第49周 12月12日 星期六 上午10:43 (第347天) 10 * 文件描述: *** :自行添加 11 * *+=+=+=+=* *** *+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+*/ 12 13 /* 14 CD Database Application 15 16 Beginning Linux Programming 17 18 Version: Terminals 19 20 Copyright (c) 1996,2007 Wrox Press 21 22 This program is free software; you can redistribute it and/or modify 23 it under the terms of the GNU General Public License as published by 24 the Fee Software Foundation; either version 2 of the License, or (at 25 your option) any later version. 26 27 This program is distributed in the hopes that it will be useful, but 28 WITHOUT ANY WARRANTY; without even the implied warranty of 29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 General Public License for more details. 31 32 You should have received a copy of the GNU General Public License 33 along with this program; if not, write to the Free Software 34 Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. 35 36 */ 37 38 /* 39 Notes 40 41 This version of the CD database application has been written 42 using the information presented in the Terminals chapter. 43 44 It is derived from the shell script presented in the Shell 45 Programming chapter. It has not been redesigned for the C 46 implementation, so many features of the shell original can 47 still be seen in this version. 48 49 There are some problems with this implementation that will 50 be resolved in later revisions: 51 52 It does not deal with commas in titles. 53 It has a practical limit on tracks per CD to keep them on screen. 54 55 The program deliberately uses the standard input and output 56 file streams. It does not deal with re-directed input or 57 output explicitly. */ 58 59 #include <unistd.h> 60 #include <stdlib.h> 61 #include <stdio.h> 62 #include <string.h> 63 #include <curses.h> 64 65 66 #define MAX_STRING (80) /* Longest allowed response */ 67 #define MAX_ENTRY (1024) /* Longest allowed database entry */ 68 69 #define MESSAGE_LINE 6 /* Misc. messages go here */ 70 #define ERROR_LINE 22 /* The line to use for errors */ 71 #define Q_LINE 20 /* Line for Questions */ 72 #define PROMPT_LINE 18 /* Line for prompting on */ 73 74 /* 75 The variable current_cd is used to store the CD title we are 76 working with. It is initialized so that the first character is NUL 77 to indicate 'no CD selected'. The \0 is strictly unnecessary, but 78 serves to emphasize the point. 79 80 The variable current_cat will be used to record the catalog number 81 of the current CD. 82 */ 83 84 static char current_cd[MAX_STRING] = "\0"; 85 static char current_cat[MAX_STRING]; 86 87 /* 88 File names. 89 90 These files are fixed in this version to keep things simple. 91 The temporary file name is also fixed, this would cause a 92 problem if this program is run by two users in the same directory. 93 94 A better way to obtain data base file names would be either by 95 program arguments, or from environment variables. 96 97 We need a better way to generate a unique a temporary file name. 98 99 Many of these issues will be addresed in later versions. 100 */ 101 102 const char *title_file = "title.cdb"; 103 const char *tracks_file = "tracks.cdb"; 104 const char *temp_file = "cdb.tmp"; 105 106 107 /* Prototypes for local functions */ 108 void clear_all_screen(void); 109 void get_return(void); 110 int get_confirm(void); 111 int getchoice(char *greet, char *choices[]); 112 void draw_menu(char *options[], int highlight, int start_row, int start_col); 113 void insert_title(char *cdtitle); 114 void get_string(char *string); 115 void add_record(void); 116 void count_cds(void); 117 void find_cd(void); 118 void list_tracks(void); 119 void remove_tracks(void); 120 void remove_cd(void); 121 void update_cd(void); 122 123 124 /* 125 Menu structures. 126 The first character is the character to return when the 127 chice is selected, the remaining text is to be displayed. 128 */ 129 char *main_menu[] = 130 { 131 "aadd new CD", 132 "ffind CD", 133 "ccount CDs and tracks in the catalog", 134 "qquit", 135 0, 136 }; 137 138 /* 139 The extended menu is displayed when a CD is currently selected 140 */ 141 char *extended_menu[] = 142 { 143 "aadd new CD", 144 "ffind CD", 145 "ccount CDs and tracks in the catalog", 146 "llist tracks on current CD", 147 "rremove current CD", 148 "uupdate track information", 149 "qquit", 150 0, 151 }; 152 153 int main() 154 { 155 int choice; 156 157 initscr(); 158 159 do { 160 161 choice = getchoice("Options:", current_cd[0] ? extended_menu : main_menu); 162 163 switch (choice) { 164 case 'q': 165 break; 166 167 case 'a': 168 add_record(); 169 break; 170 171 case 'c': 172 count_cds(); 173 break; 174 175 case 'f': 176 find_cd(); 177 break; 178 179 case 'l': 180 list_tracks(); 181 break; 182 183 case 'r': 184 remove_cd(); 185 break; 186 187 case 'u': 188 update_cd(); 189 break; 190 } 191 } while (choice != 'q'); 192 193 endwin(); 194 195 return 0; 196 } /* main */ 197 198 /* 199 getchoice - ask the user to choose 200 passed: greet, an introduction 201 choices, an array of strings, NULL at end 202 */ 203 int getchoice(char *greet, char *choices[]) 204 { 205 static int selected_row = 0; 206 int max_row = 0; 207 int start_screenrow = MESSAGE_LINE, start_screencol = 10; 208 char **option; 209 int selected; 210 int key = 0; 211 212 option = choices; 213 while (*option) { 214 max_row++; 215 option++; 216 } 217 218 /* protect against menu getting shorted when CD deleted */ 219 if (selected_row >= max_row) 220 selected_row = 0; 221 222 clear_all_screen(); 223 mvprintw(start_screenrow - 2, start_screencol, greet); 224 225 keypad(stdscr, TRUE); 226 cbreak(); 227 noecho(); 228 229 key = 0; 230 while (key != 'q' && key != KEY_ENTER && key != '\n') { 231 if (key == KEY_UP) { 232 if (selected_row == 0) 233 selected_row = max_row - 1; 234 else 235 selected_row--; 236 } 237 if (key == KEY_DOWN) { 238 if (selected_row == (max_row - 1)) 239 selected_row = 0; 240 else 241 selected_row++; 242 } 243 selected = *choices[selected_row]; 244 draw_menu(choices, selected_row, start_screenrow, start_screencol); 245 key = getch(); 246 } 247 248 keypad(stdscr, FALSE); 249 nocbreak(); 250 echo(); 251 252 if (key == 'q') 253 selected = 'q'; 254 255 return (selected); 256 257 } 258 259 void draw_menu(char *options[], int current_highlight, int start_row, int start_col) 260 { 261 int current_row = 0; 262 char **option_ptr; 263 char *txt_ptr; 264 265 option_ptr = options; 266 while (*option_ptr) { 267 if (current_row == current_highlight) attron(A_STANDOUT); 268 txt_ptr = options[current_row]; 269 txt_ptr++; 270 mvprintw(start_row + current_row, start_col, "%s", txt_ptr); 271 if (current_row == current_highlight) attroff(A_STANDOUT); 272 current_row++; 273 option_ptr++; 274 } 275 276 mvprintw(start_row + current_row + 3, start_col, "Move highlight then press Return "); 277 278 refresh(); 279 } 280 281 /* 282 clear_all_screen 283 284 Clear the screen and re-write the title. 285 If a CD is selected then display the information. 286 */ 287 void clear_all_screen() 288 { 289 clear(); 290 mvprintw(2, Q_LINE, "%s", "CD Database Application"); 291 if (current_cd[0]) { 292 mvprintw(ERROR_LINE, 0, "Current CD: %s: %s\n", current_cat, current_cd); 293 } 294 refresh(); 295 } 296 297 298 /* 299 get_return 300 301 Prompt for and read a carriage return. 302 Ignore other characters. 303 */ 304 void get_return() 305 { 306 int ch; 307 mvprintw(23, 0, "%s", " Press return "); 308 refresh(); 309 while ((ch = getchar()) != '\n' && ch != EOF); 310 } 311 312 /* 313 get_confirm 314 315 Prompt for and read confirmation. 316 Read a string and check first character for Y or y. 317 On error or other character return no confirmation. 318 */ 319 int get_confirm() 320 { 321 int confirmed = 0; 322 char first_char = 'N'; 323 324 mvprintw(Q_LINE, 5, "Are you sure? "); 325 clrtoeol(); 326 refresh(); 327 328 cbreak(); 329 first_char = getch(); 330 if (first_char == 'Y' || first_char == 'y') { 331 confirmed = 1; 332 } 333 nocbreak(); 334 335 if (!confirmed) { 336 mvprintw(Q_LINE, 1, " Cancelled"); 337 clrtoeol(); 338 refresh(); 339 sleep(1); 340 } 341 return confirmed; 342 } 343 344 345 /* 346 Database File Manipulation Functions 347 */ 348 349 /* 350 insert_title 351 352 Add a title to the CD database 353 Simply add the title string to the end of the titles file 354 355 */ 356 void insert_title(char *cdtitle) 357 { 358 FILE *fp = fopen(title_file, "a"); 359 if (!fp) { 360 mvprintw(ERROR_LINE, 0, "cannot open CD titles database"); 361 } else { 362 fprintf(fp, "%s\n", cdtitle); 363 fclose(fp); 364 } 365 } 366 367 368 /* 369 get_string 370 371 At the current screen position prompt for and read a string 372 Delete any trailing newline. 373 */ 374 void get_string(char *string) 375 { 376 int len; 377 378 wgetnstr(stdscr, string, MAX_STRING); 379 len = strlen(string); 380 if (len > 0 && string[len - 1] == '\n') 381 string[len - 1] = '\0'; 382 } 383 384 /* 385 add_record 386 387 Add a new CD to the collection 388 */ 389 390 void add_record() 391 { 392 char catalog_number[MAX_STRING]; 393 char cd_title[MAX_STRING]; 394 char cd_type[MAX_STRING]; 395 char cd_artist[MAX_STRING]; 396 char cd_entry[MAX_STRING]; 397 398 int screenrow = MESSAGE_LINE; 399 int screencol = 10; 400 401 clear_all_screen(); 402 mvprintw(screenrow, screencol, "Enter new CD details"); 403 screenrow += 2; 404 405 mvprintw(screenrow, screencol, "Catalog Number: "); 406 get_string(catalog_number); 407 screenrow++; 408 409 mvprintw(screenrow, screencol, " CD Title: "); 410 get_string(cd_title); 411 screenrow++; 412 413 mvprintw(screenrow, screencol, " CD Type: "); 414 get_string(cd_type); 415 screenrow++; 416 417 mvprintw(screenrow, screencol, " Artist: "); 418 get_string(cd_artist); 419 screenrow++; 420 421 mvprintw(15, 5, "About to add this new entry:"); 422 sprintf(cd_entry, "%s,%s,%s,%s", catalog_number, cd_title, cd_type, cd_artist); 423 mvprintw(17, 5, "%s", cd_entry); 424 refresh(); 425 426 move(PROMPT_LINE, 0); 427 if (get_confirm()) { 428 insert_title(cd_entry); 429 strcpy(current_cd, cd_title); 430 strcpy(current_cat, catalog_number); 431 } 432 } 433 434 /* 435 count_cds - scan the database and count titles and tracks 436 */ 437 void count_cds() 438 { 439 FILE *titles_fp, *tracks_fp; 440 char entry[MAX_ENTRY]; 441 int titles = 0; 442 int tracks = 0; 443 444 titles_fp = fopen(title_file, "r"); 445 if (titles_fp) { 446 while (fgets(entry, MAX_ENTRY, titles_fp)) 447 titles++; 448 fclose(titles_fp); 449 } 450 tracks_fp = fopen(tracks_file, "r"); 451 if (tracks_fp) { 452 while (fgets(entry, MAX_ENTRY, tracks_fp)) 453 tracks++; 454 fclose(tracks_fp); 455 } 456 mvprintw(ERROR_LINE, 0, "Database contains %d titles, with a total of %d tracks.", titles, tracks); 457 get_return(); 458 } 459 460 /* 461 find_cd - locate a CD in the database 462 463 prompt for a substring to match in the database 464 set current_cd to the CD title 465 466 */ 467 void find_cd() 468 { 469 char match[MAX_STRING], entry[MAX_ENTRY]; 470 FILE *titles_fp; 471 int count = 0; 472 char *found, *title, *catalog; 473 474 mvprintw(Q_LINE, 0, "Enter a string to search for in CD titles: "); 475 get_string(match); 476 477 titles_fp = fopen(title_file, "r"); 478 if (titles_fp) { 479 while (fgets(entry, MAX_ENTRY, titles_fp)) { 480 481 /* Skip past catalog number */ 482 catalog = entry; 483 if (found = strstr(catalog, ",")) { 484 *found = 0; 485 title = found + 1; 486 487 /* Zap the next comma in the entry to reduce it to title only */ 488 if (found = strstr(title, ",")) { 489 *found = '\0'; 490 491 /* Now see if the match substring is present */ 492 if (found = strstr(title, match)) { 493 count++; 494 strcpy(current_cd, title); 495 strcpy(current_cat, catalog); 496 } 497 } 498 } 499 } 500 fclose(titles_fp); 501 } 502 if (count != 1) { 503 if (count == 0) 504 mvprintw(ERROR_LINE, 0, "Sorry, no matching CD found. "); 505 if (count > 1) 506 mvprintw(ERROR_LINE, 0, "Sorry, match is ambiguous: %d CDs found. ", count); 507 current_cd[0] = '\0'; 508 get_return(); 509 } 510 } 511 512 513 /* 514 remove_tracks - delete tracks from the current CD 515 */ 516 void remove_tracks() 517 { 518 FILE *tracks_fp, *temp_fp; 519 char entry[MAX_ENTRY + 1]; 520 int cat_length; 521 522 if (current_cd[0] == '\0') 523 return; 524 525 cat_length = strlen(current_cat); 526 527 tracks_fp = fopen(tracks_file, "r"); 528 if (tracks_fp == (FILE *)NULL) return; 529 temp_fp = fopen(temp_file, "w"); 530 531 532 533 while (fgets(entry, MAX_ENTRY, tracks_fp)) { 534 /* Compare catalog number and copy entry if no match */ 535 if (strncmp(current_cat, entry, cat_length) != 0) 536 fputs(entry, temp_fp); 537 } 538 fclose(tracks_fp); 539 fclose(temp_fp); 540 541 unlink(tracks_file); 542 rename(temp_file, tracks_file); 543 } 544 545 /* 546 remove_cd - delete the current CD from the database 547 */ 548 void remove_cd() 549 { 550 FILE *titles_fp, *temp_fp; 551 char entry[MAX_ENTRY]; 552 int cat_length; 553 554 if (current_cd[0] == '\0') 555 return; 556 557 clear_all_screen(); 558 mvprintw(PROMPT_LINE, 0, "About to remove CD %s: %s. ", current_cat, current_cd); 559 if (!get_confirm()) 560 return; 561 562 cat_length = strlen(current_cat); 563 564 /* Copy the titles file to a temporary, ignoring this CD */ 565 titles_fp = fopen(title_file, "r"); 566 temp_fp = fopen(temp_file, "w"); 567 568 while (fgets(entry, MAX_ENTRY, titles_fp)) { 569 /* Compare catalog number and copy entry if no match */ 570 if (strncmp(current_cat, entry, cat_length) != 0) 571 fputs(entry, temp_fp); 572 } 573 fclose(titles_fp); 574 fclose(temp_fp); 575 576 /* Delete the titles file, and rename the temporary file */ 577 unlink(title_file); 578 rename(temp_file, title_file); 579 580 /* Now do the same for the tracks file */ 581 remove_tracks(); 582 583 /* Reset current CD to 'None' */ 584 current_cd[0] = '\0'; 585 } 586 587 588 /* 589 Some defines we use only for showing or entering the track information 590 */ 591 #define BOXED_LINES 11 592 #define BOXED_ROWS 60 593 #define BOX_LINE_POS 8 594 #define BOX_ROW_POS 2 595 /* 596 list_tracks - list the tracks for the current CD 597 */ 598 void list_tracks() 599 { 600 FILE *tracks_fp; 601 char entry[MAX_ENTRY]; 602 int cat_length; 603 int lines_op = 0; 604 WINDOW *track_pad_ptr; 605 int tracks = 0; 606 int key; 607 int first_line = 0; 608 609 if (current_cd[0] == '\0') { 610 mvprintw(ERROR_LINE, 0, "You must select a CD first. ", stdout); 611 get_return(); 612 return; 613 } 614 clear_all_screen(); 615 cat_length = strlen(current_cat); 616 617 /* First count the number of tracks for the current CD */ 618 tracks_fp = fopen(tracks_file, "r"); 619 if (!tracks_fp) 620 return; 621 while (fgets(entry, MAX_ENTRY, tracks_fp)) { 622 if (strncmp(current_cat, entry, cat_length) == 0) 623 tracks++; 624 } 625 fclose(tracks_fp); 626 627 628 /* Make a new pad, ensure that even if there is only a single 629 track the PAD is large enough so the later prefresh() is always 630 valid. 631 */ 632 track_pad_ptr = newpad(tracks + 1 + BOXED_LINES, BOXED_ROWS + 1); 633 if (!track_pad_ptr) 634 return; 635 636 tracks_fp = fopen(tracks_file, "r"); 637 if (!tracks_fp) 638 return; 639 640 mvprintw(4, 0, "CD Track Listing\n"); 641 642 /* write the track information into the pad */ 643 while (fgets(entry, MAX_ENTRY, tracks_fp)) { 644 /* Compare catalog number and output rest of entry */ 645 if (strncmp(current_cat, entry, cat_length) == 0) { 646 mvwprintw(track_pad_ptr, lines_op++, 0, "%s", entry + cat_length + 1); 647 } 648 } 649 fclose(tracks_fp); 650 651 if (lines_op > BOXED_LINES) { 652 mvprintw(MESSAGE_LINE, 0, "Cursor keys to scroll, RETURN or q to exit"); 653 } else { 654 mvprintw(MESSAGE_LINE, 0, "RETURN or q to exit"); 655 } 656 wrefresh(stdscr); 657 keypad(stdscr, TRUE); 658 cbreak(); 659 noecho(); 660 661 key = 0; 662 while (key != 'q' && key != KEY_ENTER && key != '\n') { 663 if (key == KEY_UP) { 664 if (first_line > 0) 665 first_line--; 666 } 667 if (key == KEY_DOWN) { 668 if (first_line + BOXED_LINES + 1 < tracks) 669 first_line++; 670 } 671 /* now draw the appropriate part of the pad on the screen */ 672 prefresh(track_pad_ptr, first_line, 0, 673 BOX_LINE_POS, BOX_ROW_POS, 674 BOX_LINE_POS + BOXED_LINES, BOX_ROW_POS + BOXED_ROWS); 675 /* wrefresh(stdscr); */ 676 key = getch(); 677 } 678 679 delwin(track_pad_ptr); 680 keypad(stdscr, FALSE); 681 nocbreak(); 682 echo(); 683 } 684 685 /* 686 update_cd - re-enter tracks for current CD 687 688 deletes all tracks for the current CD in the database 689 and then prompts for new ones. 690 */ 691 void update_cd() 692 { 693 FILE *tracks_fp; 694 char track_name[MAX_STRING]; 695 int len; 696 int track = 1; 697 int screen_line = 1; 698 WINDOW *box_window_ptr; 699 WINDOW *sub_window_ptr; 700 701 clear_all_screen(); 702 mvprintw(PROMPT_LINE, 0, "Re-entering tracks for CD. "); 703 if (!get_confirm()) 704 return; 705 move(PROMPT_LINE, 0); 706 clrtoeol(); 707 708 remove_tracks(); 709 710 mvprintw(MESSAGE_LINE, 0, "Enter a blank line to finish"); 711 712 tracks_fp = fopen(tracks_file, "a"); 713 714 /* Just to show how, enter the information in a scrolling, boxed, 715 window. The trick is to set-up a sub-window, draw a box around the 716 edge, then add a new, scrolling, sub-window just inside the boxed 717 sub-window. */ 718 box_window_ptr = subwin(stdscr, BOXED_LINES + 2, BOXED_ROWS + 2, 719 BOX_LINE_POS - 1, BOX_ROW_POS - 1); 720 if (!box_window_ptr) 721 return; 722 box(box_window_ptr, ACS_VLINE, ACS_HLINE); 723 724 sub_window_ptr = subwin(stdscr, BOXED_LINES, BOXED_ROWS, 725 BOX_LINE_POS, BOX_ROW_POS); 726 if (!sub_window_ptr) 727 return; 728 scrollok(sub_window_ptr, TRUE); 729 werase(sub_window_ptr); 730 touchwin(stdscr); 731 732 do { 733 734 mvwprintw(sub_window_ptr, screen_line++, BOX_ROW_POS + 2, "Track %d: ", track); 735 clrtoeol(); 736 refresh(); 737 wgetnstr(sub_window_ptr, track_name, MAX_STRING); 738 len = strlen(track_name); 739 if (len > 0 && track_name[len - 1] == '\n') 740 track_name[len - 1] = '\0'; 741 742 if (*track_name) 743 fprintf(tracks_fp, "%s,%d,%s\n", current_cat, track, track_name); 744 track++; 745 if (screen_line > BOXED_LINES - 1) { 746 /* time to start scrolling */ 747 scroll(sub_window_ptr); 748 screen_line--; 749 } 750 } while (*track_name); 751 delwin(sub_window_ptr); 752 753 fclose(tracks_fp); 754 }
这个代码的缺点非常明显,就是把所有的功能硬塞进一个代码文件中,非常不方便调试。
Makefile文件:
1 #all: curses_app 2 all: diskManage 3 4 #Uncomment and edit the line below if necessary 5 #CFLAGS=-I/usr/include/ncurses 6 7 LDFLAGS=-lcurses
不多说了。