CLI Library Management-System C++
Tags: cpp, beginners, programming, devops
Published: 2023-07-04 22:18:25

In this article, we will explore a simple Command Line Interface (CLI) program for a Library Management System. The program allows users to register books, register library members, and perform basic operations such as printing book data and saving data to files. The program is written in C++ and demonstrates the usage of classes, vectors, file handling, and user input.

#Code Walkthrough
```c++
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>

using namespace std;

class BookEntry
{
public:
    string bookName;
    string bookAuthor;
    string publisher;
    int ISBN;
    int edition;
    int publishYear;
    int numberOfBooks;
    vector<BookEntry> books; // Store multiple books

    void registerBook();
    void printData();
    void saveBookDataToFile(const string &filename);
};

class MemberEntry
{
public:
    string memberName;
    string memberAddress;
    string memberEmail;
    int memberID;

    void registerMember();
    void saveMemberDataToFile(const string &filename);
    bool isMemberExist(const string &filename);
};

// ...
```

The code starts by including necessary libraries (`iostream`, `fstream`, `string`, `iomanip`, and `vector`) and using the `std` namespace. Then, it defines two classes: `BookEntry` and `MemberEntry`. These classes encapsulate the functionality related to book and member management, respectively.

The `BookEntry` class has member variables representing book details such as name, author, publisher, ISBN, edition, publish year, and the number of books. It also includes a `vector` named `books` to store multiple book entries. The class provides member functions to register a book, print book data, and save book data to a file.

The `MemberEntry` class contains member variables for member details like name, address, email, and member ID. It has member functions to register a member, save member data to a file, and check if a member already exists.

Now, let's take a look at the member function implementations of `BookEntry`:
```c++
void BookEntry::registerBook()
{
    cout << "Enter the number of Books this time:\n";
    cin >> numberOfBooks;

    for (int i = 0; i < numberOfBooks; ++i)
    {
        cout << "===============================\n";
        cout << "     CLI for Book Entry\n";
        cout << "===============================\n";
        cout << "Enter the Name of the Book: ";
        cin >> bookName;
        cout << "Enter the Author of the Book: ";
        cin >> bookAuthor;
        cout << "Enter the Publisher: ";
        cin >> publisher;
        cout << "Enter the ISBN number of the Book: ";
        cin >> ISBN;
        cout << "Enter the Edition (numbers only): ";
        cin >> edition;

        BookEntry book;
        book.bookName = bookName;
        book.bookAuthor = bookAuthor;
        book.publisher = publisher;
        book.ISBN = ISBN;
        book.edition = edition;
        books.push_back(book);
    }
}

void BookEntry::printData()
{
    cout << "=========================================\n";
    cout << "           Books in Library\n";
    cout << "=========================================\n";

    if (books.empty())
    {
        cout << "No books available.\n";
        return;
    }

    cout << left << setw(6) << "S.No"
         << setw(25) << "Title"
         << setw(25) << "Author"
         << setw(25) << "Publication"
         << setw(15) << "ISBN"
         << setw(10) << "Edition"
         << "\n";

    for (int i = 0; i < books.size(); i++)
    {
        if (i >= books.size() - numberOfBooks)
            cout << left << setw(6) << i + 1 << "*"
                 << setw(25) << books[i].bookName
                 << setw(25) << books[i].bookAuthor
                 << setw(25) << books[i].publisher
                 << setw(15) << books[i].ISBN
                 << setw(10) << books[i].edition
                 << "\n";
        else
            cout << left << setw(6) << i + 1
                 << setw(25) << books[i].bookName
                 << setw(25) << books[i].bookAuthor
                 << setw(25) << books[i].publisher
                 << setw(15) << books[i].ISBN
                 << setw(10) << books[i].edition
                 << "\n";
    }
}

void BookEntry::saveBookDataToFile(const string &filename)
{
    ofstream outputFile(filename);

    if (!outputFile.is_open())
    {
        cout << "Failed to open the file: " << filename << endl;
        return;
    }

    outputFile << "Books in Library\n";
    outputFile << "=========================================\n";
    outputFile << left << setw(6) << "S.No"
               << setw(25) << "Title"
               << setw(25) << "Author"
               << setw(25) << "Publication"
               << setw(15) << "ISBN"
               << setw(10) << "Edition"
               << "\n";

    for (int i = 0; i < books.size(); i++)
    {
        if (i >= books.size() - numberOfBooks)
            outputFile << left << setw(6) << i + 1 << "*"
                       << setw(25) << books[i].bookName
                       << setw(25) << books[i].bookAuthor
                       << setw(25) << books[i].publisher
                       << setw(15) << books[i].ISBN
                       << setw(10) << books[i].edition
                       << "\n";
        else
            outputFile << left << setw(6) << i + 1
                       << setw(25) << books[i].bookName
                       << setw(25) << books[i].bookAuthor
                       << setw(25) << books[i].publisher
                       << setw(15) << books[i].ISBN
                       << setw(10) << books[i].edition
                       << "\n";
    }

    cout << "Book data saved to file: " << filename << endl;

    outputFile.close();
}
```
The `registerBook()` function allows the user to register multiple books. It prompts the user to enter the number of books to register and then iterates that many times to collect book details such as name, author, publisher, ISBN, and edition. For each book, a `BookEntry` object is created and its member variables are set accordingly. The object is then added to the `books` vector.

The `printData()` function displays the book data stored in the books vector. It first checks if the vector is empty and prints a message if there are no books. If books are available, it formats and prints the book details in a tabular format.

The `saveBookDataToFile()` function saves the book data to a file. It opens the specified file in output mode (`ofstream`) and checks if the file is successfully opened. If the file fails to open, an error message is displayed. The function then writes the book data to the file in a formatted manner. It first writes the table header, followed by the book details. For the last `numberOfBooks` books in the `books` vector, an asterisk (*) is added to indicate their availability. Finally, it displays a success message and closes the file.

Now, let's move on to the member function implementations of `MemberEntry`:
```c++
void MemberEntry::registerMember()
{
    cout << "===============================\n";
    cout << "     CLI for Member Entry\n";
    cout << "===============================\n";
    cout << "Enter the Name of the Member: ";
    cin >> memberName;
    cout << "Enter the Address of the Member: ";
    cin >> memberAddress;
    cout << "Enter the Email of the Member: ";
    cin >> memberEmail;
    cout << "Enter the Member ID: ";
    cin >> memberID;
}

void MemberEntry::saveMemberDataToFile(const string &filename)
{
    ofstream outputFile(filename, ios::app);

    if (!outputFile.is_open())
    {
        cout << "Failed to open the file: " << filename << endl;
        return;
    }

    outputFile << "Member Details\n";
    outputFile << "=========================================\n";
    outputFile << "Name: " << memberName << endl;
    outputFile << "Address: " << memberAddress << endl;
    outputFile << "Email: " << memberEmail << endl;
    outputFile << "Member ID: " << memberID << endl;
    outputFile << "--------------------------------------" << endl;

    cout << "Member data saved to file: " << filename << endl;

    outputFile.close();
}

bool MemberEntry::isMemberExist(const string &filename)
{
    ifstream inputFile(filename);

    if (!inputFile.is_open())
    {
        cout << "Failed to open the file: " << filename << endl;
        return false;
    }

    string line;
    string searchName = "Name: " + memberName;
    string searchEmail = "Email: " + memberEmail;

    while (getline(inputFile, line))
    {
        if (line.find(searchName) != string::npos || line.find(searchEmail) != string::npos)
        {
            cout << "Member already exists.\n";
            inputFile.close();
            return true;
        }
    }

    inputFile.close();
    return false;
}
```
The `registerMember()` function collects member details from the user. It prompts the user to enter the member's name, address, email, and ID. The entered values are stored in the corresponding member variables.

The `saveMemberDataToFile()` function saves the member data to a file. It opens the specified file in append mode (ofstream with ios::app flag) and checks if the file is successfully opened. If the file fails to open, an error message is displayed. The function then writes the member details to the file, including the member's name, address, email, and ID. The data is formatted with appropriate labels. Finally, it displays a success message and closes the file.

The `isMemberExist()` function checks if a member already exists in the given file. It opens the file in input mode (`ifstream`) and checks if the file is successfully opened. If the file fails to open, an error message is displayed. The function then reads the file line by line and compares each line with the search criteria (name and email) to determine if a matching member already exists. If a match is found, a message is displayed, and the function returns true to indicate that the member exists. If no match is found, the function returns false.

Next, let's examine the Options class and its `options()` member function:
```c++
class Options : public BookEntry, public MemberEntry
{
public:
    void options();
};

void Options::options()
{
    char opts;
    bool running = true;

    while (running)
    {
        cout << "===============================\n";
        cout << "      CLI for Options\n";
        cout << "===============================\n";
        cout << "1. To make an Entry of Book\n";
        cout << "2. To Issue Book \n";
        cout << "3. Register a Member \n";
        cout << "Press Esc key to exit\n";
        cin >> opts;

        switch (opts)
        {
        case '1':
            registerBook();
            printData();
            saveBookDataToFile("book_data.txt");
            break;
        case '2':
            cout << "Issuing the book...\n";
            break;
        case '3':
            registerMember();
            if (!isMemberExist("member_data.txt"))
                saveMemberDataToFile("member_data.txt");
            break;
        case 27:
            running = false;
            break;
        default:
            cout << "Invalid option\n";
            break;
        }
    }
}
```
The `Options` class inherits from both `BookEntry` and `MemberEntry` classes. It provides the `options()` member function to display a menu and handle user input for different operations. Within the `options()` function, a while loop runs until the user chooses to exit by pressing the Esc key. In each iteration, the menu is displayed, and the user's choice is read into the opts variable.

Based on the user's input, the switch statement performs different actions:

- If the user chooses '1', it calls the `registerBook()` function to register books, then prints the book data using `printData()`, and finally saves the book data to a file using `saveBookDataToFile()`.

- If the user chooses '2', a placeholder message is displayed for issuing a book (you can customize this functionality).

- If the user chooses '3', it calls the `registerMember()` function to register a member. Before saving the member data, it checks if the member already exists using `isMemberExist()`. If the member does not exist, the member data is saved to a file using `saveMemberDataToFile()`.

- If the user presses the `Esc` key (27), the loop is terminated, and the program exits.

- If the user inputs any other character, an "Invalid option" message is displayed.

This implementation allows users to interact with the CLI and perform operations such as registering books and members, and saving the data to files.
#Final Code 
```c++
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>

using namespace std;

class BookEntry
{
public:
    string bookName;
    string bookAuthor;
    string publisher;
    int ISBN;
    int edition;
    int publishYear;
    int numberOfBooks;
    vector<BookEntry> books; // Store multiple books

    void registerBook();
    void printData();
    void saveBookDataToFile(const string &filename);
};

class MemberEntry
{
public:
    string memberName;
    string memberAddress;
    string memberEmail;
    int memberID;

    void registerMember();
    void saveMemberDataToFile(const string &filename);
    bool isMemberExist(const string &filename);
};

void BookEntry::registerBook()
{
    cout << "Enter the number of Books this time:\n";
    cin >> numberOfBooks;

    for (int i = 0; i < numberOfBooks; ++i)
    {
        cout << "===============================\n";
        cout << "     CLI for Book Entry\n";
        cout << "===============================\n";
        cout << "Enter the Name of the Book: ";
        cin >> bookName;
        cout << "Enter the Author of the Book: ";
        cin >> bookAuthor;
        cout << "Enter the Publisher: ";
        cin >> publisher;
        cout << "Enter the ISBN number of the Book: ";
        cin >> ISBN;
        cout << "Enter the Edition (numbers only): ";
        cin >> edition;

        // Create a book object and add it to the vector of books
        BookEntry book;
        book.bookName = bookName;
        book.bookAuthor = bookAuthor;
        book.publisher = publisher;
        book.ISBN = ISBN;
        book.edition = edition;
        books.push_back(book);
    }
}

void BookEntry::printData()
{
    cout << "=========================================\n";
    cout << "           Books in Library\n";
    cout << "=========================================\n";

    if (books.empty())
    {
        cout << "No books available.\n";
        return;
    }

    cout << left << setw(6) << "S.No"
         << setw(25) << "Title"
         << setw(25) << "Author"
         << setw(25) << "Publication"
         << setw(15) << "ISBN"
         << setw(10) << "Edition"
         << "\n";

    for (int i = 0; i < books.size(); i++)
    {
        if (i >= books.size() - numberOfBooks)
            cout << left << setw(6) << i + 1 << "*"
                 << setw(25) << books[i].bookName
                 << setw(25) << books[i].bookAuthor
                 << setw(25) << books[i].publisher
                 << setw(15) << books[i].ISBN
                 << setw(10) << books[i].edition
                 << "\n";
        else
            cout << left << setw(6) << i + 1
                 << setw(25) << books[i].bookName
                 << setw(25) << books[i].bookAuthor
                 << setw(25) << books[i].publisher
                 << setw(15) << books[i].ISBN
                 << setw(10) << books[i].edition
                 << "\n";
    }
}

void BookEntry::saveBookDataToFile(const string &filename)
{
    ofstream outputFile(filename);

    if (!outputFile.is_open())
    {
        cout << "Failed to open the file: " << filename << endl;
        return;
    }

    outputFile << "Books in Library\n";
    outputFile << "=========================================\n";
    outputFile << left << setw(6) << "S.No"
               << setw(25) << "Title"
               << setw(25) << "Author"
               << setw(25) << "Publication"
               << setw(15) << "ISBN"
               << setw(10) << "Edition"
               << "\n";

    for (int i = 0; i < books.size(); i++)
    {
        if (i >= books.size() - numberOfBooks)
            outputFile << left << setw(6) << i + 1 << "*"
                       << setw(25) << books[i].bookName
                       << setw(25) << books[i].bookAuthor
                       << setw(25) << books[i].publisher
                       << setw(15) << books[i].ISBN
                       << setw(10) << books[i].edition
                       << "\n";
        else
            outputFile << left << setw(6) << i + 1
                       << setw(25) << books[i].bookName
                       << setw(25) << books[i].bookAuthor
                       << setw(25) << books[i].publisher
                       << setw(15) << books[i].ISBN
                       << setw(10) << books[i].edition
                       << "\n";
    }

    cout << "Book data saved to file: " << filename << endl;

    outputFile.close();
}

void MemberEntry::registerMember()
{
    cout << "===============================\n";
    cout << "     CLI for Member Entry\n";
    cout << "===============================\n";
    cout << "Enter the Name of the Member: ";
    cin >> memberName;
    cout << "Enter the Address of the Member: ";
    cin >> memberAddress;
    cout << "Enter the Email of the Member: ";
    cin >> memberEmail;
    cout << "Enter the Member ID: ";
    cin >> memberID;
}

void MemberEntry::saveMemberDataToFile(const string &filename)
{
    ofstream outputFile(filename, ios::app);

    if (!outputFile.is_open())
    {
        cout << "Failed to open the file: " << filename << endl;
        return;
    }

    outputFile << "Member Details\n";
    outputFile << "=========================================\n";
    outputFile << "Name: " << memberName << endl;
    outputFile << "Address: " << memberAddress << endl;
    outputFile << "Email: " << memberEmail << endl;
    outputFile << "Member ID: " << memberID << endl;
    outputFile << "--------------------------------------" << endl;

    cout << "Member data saved to file: " << filename << endl;

    outputFile.close();
}

bool MemberEntry::isMemberExist(const string &filename)
{
    ifstream inputFile(filename);

    if (!inputFile.is_open())
    {
        cout << "Failed to open the file: " << filename << endl;
        return false;
    }

    string line;
    string searchName = "Name: " + memberName;
    string searchEmail = "Email: " + memberEmail;

    while (getline(inputFile, line))
    {
        if (line.find(searchName) != string::npos || line.find(searchEmail) != string::npos)
        {
            cout << "Member already exists.\n";
            inputFile.close();
            return true;
        }
    }

    inputFile.close();
    return false;
}

class Options : public BookEntry, public MemberEntry
{
public:
    void options();
};

void Options::options()
{
    char opts; // Change the data type to char
    bool running = true;

    while (running)
    {
        cout << "===============================\n";
        cout << "      CLI for Options\n";
        cout << "===============================\n";
        cout << "1. To make an Entry of Book\n";
        cout << "2. To Issue Book \n";
        cout << "3. Register a Member \n";
        cout << "Press Esc key to exit\n";
        cin >> opts;

        switch (opts)
        {
        case '1': 
            registerBook();
            printData();
            saveBookDataToFile("book_data.txt");
            break;
        case '2':
            cout << "Issuing the book...\n";
            break;
        case '3':
            registerMember();
            if (!isMemberExist("member_data.txt"))
                saveMemberDataToFile("member_data.txt");
            break;
        case 27:
            running = false;
            break;
        default:
            cout << "Invalid option\n";
            break;
        }
    }
}

int main()
{
    Options op;
    op.options();

    return 0;
}
```