重构的过程记录--之原始代码:

代码:

  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

不多说了。

posted @ 2020-12-15 17:26  叕叒双又  阅读(149)  评论(0编辑  收藏  举报