도서 관리 프로그램 소스 코드

다음은 이번 실습에서 작성한 도서 관리 프로그램의 소스 코드입니다.

// ehcommon.h
#pragma once
typedef enum _key key;
enum _key
{
    NO_DEFINED, F1, F2, F3, F4, F5, F6, F7, F8, F9,F10, ESC
};
void clrscr();
int getkey();
//ehcommon.c
#pragma warning(disable:4996)
#include "ehcommon.h"
#include <conio.h>
#include <stdio.h>
#include <process.h>
void clrscr()
{
    system("cls");
}
 
int getkey()
{
    int key = 0;
    key = getch();
    if(key == 27)
    {
        return ESC;
    }
    if(key == 0)
    {
        key = getch();
        switch(key)
        {
        case 59: return F1;case 60: return F2;case 61: return F3;case 62: return F4;
        case 63: return F5;case 64: return F6;case 65: return F7;case 66: return F8;
        case 67: return F9; case 68: return F10;
        }
    }
    return NO_DEFINED;
}  
// EHArray.h
#pragma once
typedef struct _EHArray EHArray;
typedef void *Element; //요소 형식명을 Element로 정의
typedef Element * Iterator;
struct _EHArray
{
    Element *base; //저장소의 위치 정보
    int capacity;     //현재 저장소의 크기
    int size;           //현재 보관한 요소 개수
};
 
EHArray *NewEHArray(int init_capa,Element init_value); //동적으로 배열 생성
void DeleteEHArray(EHArray *arr); //배열 소멸
int EHArrayGetCapacity(EHArray *arr); //저장소의 크기 가져오기
int EHArrayGetSize(EHArray *arr);       //보관한 요소 개수 가져오기
void EHArrayPushBack(EHArray *arr,Element data); //순차적으로 자료 보관
Element EHArrayGetAt(EHArray *arr,int index); //보관한 요소 가져오기
void EHArraySetAt(EHArray *arr,int index, Element data); //보관한 요소 설정하기
Iterator EHArrayBegin(EHArray *arr); //저장소의 시작 위치
Iterator EHArrayEnd(EHArray *arr); //저장소의 마지막 위치(보관할 위치)
void EHArrayErase(EHArray *arr,Iterator it);//보관한 요소 제거하기
//EHArray.c
#include "EHArray.h"
#include <stdlib.h>
 
void EHArrayEHArray(EHArray *arr,int init_capa,Element init_value);
void EHArrayReserve(EHArray *arr,int capacity);
void EHArrayPushBacks(EHArray *arr,int n,Element value);
void EHArrayTEHArray(EHArray *arr);
 
EHArray *NewEHArray(int init_capa,Element init_value)
{
    EHArray *arr = (EHArray *)malloc(sizeof(EHArray));
    EHArrayEHArray(arr,init_capa,init_value);
    return arr;
}  
 
void EHArrayEHArray(EHArray *arr,int init_capa,Element init_value)
{
    arr->base = 0;
    arr->capacity = 0;
    arr->size = 0;
    if(init_capa>0)
    {
        EHArrayReserve(arr,init_capa);
        EHArrayPushBacks(arr,init_capa,init_value);
    }
}
void EHArrayReserve(EHArray *arr,int capacity)
{
    arr->base = (Element *)realloc(arr->base,sizeof(Element)*capacity);
    arr->capacity = capacity;
}
void EHArrayPushBacks(EHArray *arr,int n,Element value)
{
    int i = 0;
    for(i=0;i<n;i++)
    {
        EHArrayPushBack(arr,value);
    }
}
void DeleteEHArray(EHArray *arr)
{
    EHArrayTEHArray(arr);
    free(arr);
}  
 
void EHArrayTEHArray(EHArray *arr)
{
    if(arr->base)
    {
        free(arr->base);
    }
}
int EHArrayGetCapacity(EHArray *arr)
{
    return arr->capacity;
}
int EHArrayGetSize(EHArray *arr)
{
    return arr->size;
}


void EHArrayPushBack(EHArray *arr,Element data)
{
    if(arr->capacity == arr->size)
    {
        if(arr->capacity)
        {
            EHArrayReserve(arr,arr->capacity*2);
        }
        else
        {
            EHArrayReserve(arr,1);
        }
    }
    arr->base[arr->size] = data;
    arr->size++;
}
Element EHArrayGetAt(EHArray *arr,int index)
{
    if((index>=0)&&(index<arr->size))
    {
        return arr->base[index];
    }
    return 0;
}
void EHArraySetAt(EHArray *arr,int index, Element data)
{
    if((index>=0)&&(index<arr->size))
    {
        arr->base[index] = data;
    }
}
Iterator EHArrayBegin(EHArray *arr)
{
    return arr->base;   
}
Iterator EHArrayEnd(EHArray *arr)
{
    return arr->base + arr->size;
}
void EHArrayErase(EHArray *arr,Iterator it)
{
    Iterator end;
    arr->size--;
    end = arr->base + arr->size;
    for(  ; it != end; it++)
    {
        (*it) = *(it+1);
    }
}
// Book.h
#pragma once
#include <stdio.h>
typedef struct _Book Book;
#define MAX_TNAME_LEN     100
#define MAX_ANAME_LEN 20
struct _Book
{
    char title[MAX_TNAME_LEN+1];
    char author[MAX_ANAME_LEN+1];
    int bnum;
};
Book *NewBook(int bnum,const char *title,const char *author);
Book *NewBook2(FILE *fp);
void DeleteBook(Book *book);
void BookView(Book *book);
int BookGetNum(Book *book);
const char *BookGetTitle(Book *book);
void BookSerialize(Book *book,FILE *fp);
//Book.c
#pragma warning(disable:4996)
#include "Book.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void BookBook(Book *book,int bnum,const char *title,const char *author);
Book *NewBook(int bnum,const char *title,const char *author)
{
    Book *book = 0;
    book = (Book *)malloc(sizeof(Book));
    BookBook(book,bnum,title,author);
    return book;
}
void BookDeserialize(Book *book,FILE *fp);
Book *NewBook2(FILE *fp)
{
    Book *book = 0;
    book = NewBook(0,"","");
    BookDeserialize(book,fp);
    return book;
}
void BookDeserialize(Book *book,FILE *fp)
{
    fread(book,sizeof(Book),1,fp);
}


void BookBook(Book *book,int bnum,const char *title,const char *author)
{
    book->bnum = bnum;
    memset(book->title,0,sizeof(book->title));
    strncpy(book->title,title,MAX_TNAME_LEN);
    memset(book->author,0,sizeof(book->author));
    strncpy(book->author,author,MAX_ANAME_LEN);
}
void DeleteBook(Book *book)
{
    free(book);
}
void BookView(Book *book)
{
    printf("제목:%s\n",book->title);
    printf("\t도서번호:%d 저자명:%s\n",book->bnum,book->author);
}
int BookGetNum(Book *book)
{
    return book->bnum;
}

const char *BookGetTitle(Book *book)
{
    return book->title;
} 
void BookSerialize(Book *book,FILE *fp)
{
    fwrite(book,sizeof(Book),1,fp);
}
// Gerne.h 
#pragma once
#include "Book.h"
#include "EHArray.h"
typedef struct _Genre Genre;
#define MAX_GNAME_LEN 20
struct _Genre
{
    char name[MAX_GNAME_LEN+1];
    int gnum;
    int last_bnum;
    EHArray *books;
};
Genre *NewGenre(int gnum,const char *gname);
Genre *NewGenre2(FILE *fp);
void DeleteGenre(Genre *genre);
const char *GenreGetName(Genre *genre);
void GenreView(Genre *genre);
void GenreAddBook(Genre *genre,const char *title,const char *author);
void GenreViewAll(Genre *genre);
Book *GenreFindBookByNum(Genre *genre,int bnum);
Book *GenreFindBookByTitle(Genre *genre,const char *title);
void GenreSerialize(Genre *genre,FILE *fp);
//Genre.c
#pragma warning(disable:4996)
#include "Genre.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

void GenreGenre(Genre *genre,int gnum,const char *gname);
Genre *NewGenre(int gnum,const char *gname)
{
    Genre *genre = 0;
    genre = (Genre *)malloc(sizeof(Genre));
    GenreGenre(genre,gnum,gname);
    return genre;
}
void GenreGenre(Genre *genre,int gnum,const char *gname)
{
    genre->gnum = gnum;
    memset(genre->name,0,sizeof(genre->name));
    strncpy(genre->name,gname,MAX_GNAME_LEN);
    genre->books = NewEHArray(0,0);
    genre->last_bnum = 0;
}
void GenreDeserialize(Genre *genre,FILE *fp);
Genre *NewGenre2(FILE *fp)
{
    Genre *genre = 0;
    genre = NewGenre(0,"");
    GenreDeserialize(genre,fp);
    return genre;
}
void GenreDeserialize(Genre *genre,FILE *fp)
{
    Book *book=0;
    int i = 0;
    int n = 0;
    fread(genre->name,sizeof(genre->name),1,fp);
    fread(&(genre->gnum),sizeof(int),1,fp);
    fread(&(genre->last_bnum),sizeof(int),1,fp);
    fread(&n,sizeof(int),1,fp);
    for(i=0  ;i<n; i++)
    {
        book = NewBook2(fp);
        EHArrayPushBack(genre->books,book);
    }
}
 
void GenreTGenre(Genre *genre);
void DeleteGenre(Genre *genre)
{
    GenreTGenre(genre);
    free(genre);
}
void GenreTGenre(Genre *genre)
{
    Book *book=0;
    Iterator seek= EHArrayBegin(genre->books);
    Iterator end= EHArrayEnd(genre->books);
    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);
        DeleteBook(book);
    }
    DeleteEHArray(genre->books);
}

int GenreGetNum(Genre *genre)
{
    return genre->gnum;
}

const char *GenreGetName(Genre *genre)
{
    return genre->name;
}
void GenreView(Genre *genre)
{
    printf("장르 번호:%d 장르 이름:%s\n",genre->gnum,genre->name);
}
 
void GenreAddBook(Genre *genre,const char *title,const char *author)
{
    Book *book = 0;
    genre->last_bnum++;
    book = NewBook(genre->last_bnum,title,author);
    EHArrayPushBack(genre->books,book);
    printf("도서번호:%d 로 추가하였습니다.\n",genre->last_bnum);
}
void GenreViewAll(Genre *genre)
{
    Iterator seek= EHArrayBegin(genre->books);
    Iterator end= EHArrayEnd(genre->books);
    Book *sbook=0;
    GenreView(genre);
    for(  ;seek != end; ++seek)
    {
        sbook = (Book *)(*seek);
        BookView(sbook);
    }
}

Book *GenreFindBookByNum(Genre *genre,int bnum)
{
    Iterator seek;
    Iterator end;
    Book *book=0;
 
    seek= EHArrayBegin(genre->books);
    end= EHArrayEnd(genre->books);
 
    GenreView(genre);
 
    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);
 
        if(BookGetNum(book) == bnum)
        {
            return book;
        }
    }
 
    return 0;
}
Book *GenreFindBookByTitle(Genre *genre,const char *title)
{
    Iterator seek;
    Iterator end;
    Book *book=0;
    const char *stitle = 0;
 
    seek= EHArrayBegin(genre->books);
    end= EHArrayEnd(genre->books);
 
    GenreView(genre);
    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);
        stitle = BookGetTitle(book);
        if(strcmp(stitle,title)==0)
        {
            return book;
        }
    }
    return 0;
}
void GenreSerialize(Genre *genre,FILE *fp)
{
    Iterator seek;
    Iterator end;
    Book *book=0;
    int n = 0;
 
    fwrite(genre->name,sizeof(genre->name),1,fp);
    fwrite(&(genre->gnum),sizeof(int),1,fp);
    fwrite(&(genre->last_bnum),sizeof(int),1,fp);
 
    n = EHArrayGetSize(genre->books);
    fwrite(&n,sizeof(int),1,fp);
    seek= EHArrayBegin(genre->books);
    end= EHArrayEnd(genre->books);
 
    for(  ;seek != end; ++seek)
    {
        book = (Book *)(*seek);
        BookSerialize(book,fp);
    }
}
//App.h
#pragma once
typedef struct _App    App;
#include "Genre.h"
#include "EHArray.h"
#include <stdio.h>
struct _App
{
    char fname[FILENAME_MAX];
    int last_gnum;
    EHArray *genres;
};
 
App *NewApp(const char *fname);
void AppRun(App *app);
void DeleteApp(App *app);
//App.c
#pragma warning(disable:4996)
#include "App.h"
#include "ehcommon.h"
#include <malloc.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>
 
void AppApp(App *app,const char *fname);
void AppTApp(App *app);
void AppLoad(App *app);
void AppSave(App *app);
 
int AppSelectMenu(App *app);
void AppAddGenre(App *app);
void AppRemoveGenre(App *app);
void AppListGenre(App *app);
void AppListBookAtGenre(App *app); 
void AppAddBook(App *app); 
void AppFindBookByNum(App *app); 
void AppFindBookByTitle(App *app); 
void AppListAll(App *app); 
 
App *NewApp(const char *fname)
{
    App *app = 0;
    app = (App *)malloc(sizeof(App));
    AppApp(app,fname);
    return app;
}
 
void AppApp(App *app,const char *fname)
{
    memset(app->fname,0,sizeof(app->fname));
    strncpy(app->fname,fname,FILENAME_MAX);
    app->genres = NewEHArray(0,0);
    app->last_gnum = 0;
    AppLoad(app);
    printf("아무 키나 누르세요.\n");
    getkey();
}

void AppDeserialize(App *app,FILE *fp);
void AppLoad(App *app)
{
    FILE *fp = 0;
    fp = fopen(app->fname,"r");
    if(fp)
    {
        AppDeserialize(app,fp);
    }
    else
    {
        printf("환영합니다.\n");
    }
}
void AppDeserialize(App *app,FILE *fp)
{
    int n = 0;
    int i = 0;
    Genre *genre=0;
    fread(&(app->last_gnum),sizeof(int),1,fp);
    fread(&n,sizeof(int),1,fp);
    for( i=0 ;i<n;i++)
    {
        genre = NewGenre2(fp);
        EHArrayPushBack(app->genres,genre);
    }
}
 



void AppRun(App *app)
{
    int key = 0;
    while((key = AppSelectMenu(app))!=ESC)
    {
        switch(key)
        {
        case F1: AppAddGenre(app); break;
        case F2: AppRemoveGenre(app); break;
        case F3: AppListGenre(app); break;
        case F4: AppListBookAtGenre(app); break;
        case F5: AppAddBook(app); break;
        case F6: AppFindBookByNum(app); break;
        case F7: AppFindBookByTitle(app); break;
        case F8: AppListAll(app); break;
        default: printf("잘못 선택하였습니다.\n"); break;
        }
        printf("아무 키나 누르세요.\n");
        getkey();
    }
} 
int AppSelectMenu(App *app)
{
    clrscr();
    printf("장르별 도서관리 프로그램 \n");
    printf("F1:장르 추가 F2: 장르 삭제 F3: 전체 장르 보기\n");
    printf("F4: 특정 장르의 도서 목록 보기\n");
    printf("F5:도서 추가 F6: 도서 검색(일련번호) F7: 도서검색(제목)\n");
    printf("F8: 전체 도서 보기 ESC: 종료\n");
    return getkey();
}

Iterator AppFindGenre(App *app,const char *gname);
void AppAddGenre(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
 
    printf("%d번째 추가할 장르명을 입력하세요.\n",app->last_gnum+1);
    gets_s(gname,MAX_GNAME_LEN);
 
    seek = AppFindGenre(app,gname);
    if(seek != EHArrayEnd(app->genres))
    {
        printf("이미 존재하는 장르입니다.\n");
        return;
    }
    genre = NewGenre(app->last_gnum+1,gname);
    app->last_gnum++;
    EHArrayPushBack(app->genres,genre);
}
Iterator AppFindGenre(App *app,const char *gname)
{
    Iterator seek;
    Iterator end;
    Genre *sgenre=0;
    const char *sgname=0;
 
    seek = EHArrayBegin(app->genres);
    end = EHArrayEnd(app->genres);
 
    for(  ;seek != end; ++seek)
    {
        sgenre = (Genre *)(*seek);
        sgname = GenreGetName(sgenre);
        if(strcmp(sgname,gname)==0)
        {
            break;
        }
    }
    return seek;
}

void AppRemoveGenre(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    AppListGenre(app);
    printf("삭제할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
         printf("잘못 선택하였습니다.\n");
        return;
    }
    genre = (Genre *)(*seek);
    DeleteGenre(genre);
    EHArrayErase(app->genres,seek);
}

void AppListGenre(App *app)
{
    Iterator seek= EHArrayBegin(app->genres);
    Iterator end= EHArrayEnd(app->genres);
    Genre *sgenre=0;
    for(  ;seek != end; ++seek)
    {
        sgenre = (Genre *)(*seek);
        GenreView(sgenre);
    }
}

void AppListBookAtGenre(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    AppListGenre(app);
    printf("도서 목록을 확인할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    genre = (Genre *)(*seek);
    GenreViewAll(genre);
}

void AppAddBook(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    char author[MAX_ANAME_LEN+1]="";
    char title[MAX_TNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    AppListGenre(app);
    printf("도서를 추가할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    printf("도서명을 입력하세요.\n");
    gets_s(title,MAX_TNAME_LEN);
    printf("저자명을 입력하세요.\n");
    gets_s(author,MAX_ANAME_LEN);
    genre = (Genre *)(*seek);
    GenreAddBook(genre,title,author);
}
void AppFindBookByNum(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    int bnum=0;
    Iterator seek = 0;
    Genre *genre = 0;
    Book *book = 0;
    AppListGenre(app);
    printf("검색할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    printf("도서 번호를 입력하세요.\n");
    scanf_s("%d", &bnum);
    genre = (Genre *)(*seek);
    book = GenreFindBookByNum(genre,bnum);
    if(book)
    {
        BookView(book);
    }
    else
    {
        printf("도서를 찾지 못했습니다.\n");
    }
}
void AppFindBookByTitle(App *app)
{
    char gname[MAX_GNAME_LEN+1]="";
    char title[MAX_TNAME_LEN+1]="";
    Iterator seek = 0;
    Genre *genre = 0;
    Book *book = 0;
 
    AppListGenre(app);
    printf("검색할 장르명을 입력하세요.\n");
    gets_s(gname,MAX_GNAME_LEN);
    seek = AppFindGenre(app,gname);
    if(seek == EHArrayEnd(app->genres))
    {
        printf("잘못 선택하였습니다.\n");
        return;
    }
    printf("도서 제목을 입력하세요.\n");
    gets_s(title,MAX_TNAME_LEN);
    genre = (Genre *)(*seek);
    book = GenreFindBookByTitle(genre,title);
    if(book)
    {
        BookView(book);
    }
    else
    {
        printf("도서를 찾지 못했습니다.\n");
    }
}
void AppListAll(App *app)
{
    Iterator seek= EHArrayBegin(app->genres);
    Iterator end= EHArrayEnd(app->genres);
    Genre *genre=0;
    for(  ;seek != end; ++seek)
    {
        genre = (Genre *)(*seek);
        GenreViewAll(genre);
    }
}

void DeleteApp(App *app)
{
    AppSave(app);
    AppTApp(app);
    free(app);
}
void AppTApp(App *app)
{
    DeleteEHArray(app->genres);
}

void AppSerialize(App *app,FILE *fp);
void AppSave(App *app)
{
    FILE *fp = 0;
    fopen_s(&fp, app->fname,"w");
    if(fp)
    {
        AppSerialize(app,fp);
    }
    else
    {
       printf("오류!!!데이터 저장 실패\n");
    }
}
 
void AppSerialize(App *app,FILE *fp)
{
    Iterator seek;
    Iterator end;
    int n = 0;
    Genre *genre=0;
    fwrite(&(app->last_gnum),sizeof(int),1,fp);
    n = EHArrayGetSize(app->genres);
    fwrite(&n,sizeof(int),1,fp);
    seek= EHArrayBegin(app->genres);
    end= EHArrayEnd(app->genres);
    for(  ;seek != end; ++seek)
    {
        genre = (Genre *)(*seek);
        GenreSerialize(genre,fp);
    }
}
//Program.c
#include "App.h"
#define DEF_FNAME    "member.ehd"
int main(int argc, char **argv)
{
    App *app = 0;
    if(argc != 2)
    {
        app = NewApp(DEF_FNAME);
    }
    else
    {
        app = NewApp(argv[1]);
    }
    AppRun(app);
    DeleteApp(app);
    return 0;
}