Midterm Project: Build a Real CLI Tool

মিডটার্ম প্রজেক্ট — একটা বাস্তব CLI টুল

Build: ~4 hours Milestone 5 starter problems

1. Pick a Track

You have learned enough C++ to build a complete program. Pick one of the projects below and ship it: multi-file, with a CMakeLists.txt and a README. Better small and working than big and broken.

এতদিনে আপনি যথেষ্ট C++ শিখেছেন একটি সম্পূর্ণ প্রোগ্রাম তৈরি করার জন্য। নিচের যেকোনো একটি প্রজেক্ট বেছে নিয়ে শেষ করুন। আকারে ছোট হলেও সঠিকভাবে কাজ করুক — সেটাই গুরুত্বপূর্ণ।

Track A · Word Counter (wc)

  • Count lines, words, bytes in a file
  • Multiple files, totals row
  • Flags: -l, -w, -c

Track B · Todo CLI

  • add / list / done / remove subcommands
  • Persist to a text file
  • Pretty output with colors

Track C · Calculator (rpn)

  • Reverse Polish Notation
  • Stack-based evaluator
  • +, -, *, /, sqrt, pow

Track D · CSV Stats

  • Read a CSV file
  • min, max, mean, median per column
  • Format as table

2. Reading Command-line Arguments

argv.cpp
#include <iostream>
#include <string>
#include <vector>

int main(int argc, char* argv[]) {
    std::vector<std::string> args(argv, argv + argc);
    std::cout << "Program: " << args[0] << "\n";
    for (size_t i = 1; i < args.size(); ++i)
        std::cout << "  arg " << i << ": " << args[i] << "\n";
}

3. Reading a File

readfile.cpp
#include <iostream>
#include <fstream>
#include <string>

int main() {
    std::ifstream in("data.txt");
    if (!in) { std::cerr << "can't open\n"; return 1; }

    std::string line;
    int lines = 0, words = 0, bytes = 0;
    while (std::getline(in, line)) {
        ++lines;
        bytes += line.size() + 1;
        bool in_word = false;
        for (char c : line) {
            if (std::isspace(static_cast<unsigned char>(c))) in_word = false;
            else if (!in_word) { in_word = true; ++words; }
        }
    }
    std::cout << lines << " " << words << " " << bytes << "\n";
}

4. Project Structure

Recommended layout
my-cli/
├── CMakeLists.txt
├── README.md
├── src/
│   ├── main.cpp
│   ├── counter.cpp
│   └── counter.hpp
└── tests/
    └── test_counter.cpp

5. CMakeLists.txt Skeleton

CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(my_cli LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(my_cli
    src/main.cpp
    src/counter.cpp)

target_include_directories(my_cli PRIVATE src)
target_compile_options(my_cli PRIVATE -Wall -Wextra -O2)

6. Starter Exercises

  1. Print all command-line arguments, one per line.
    ✨ Show Answer

    See section 2 above.

  2. Read a file and print every line numbered.
    ✨ Show Answer
    std::ifstream in(path);
    std::string line; int n = 1;
    while (std::getline(in, line))
        std::cout << n++ << ": " << line << "\n";
  3. Implement a simple --help flag.
    ✨ Show Answer
    if (argc > 1 && std::string{argv[1]} == "--help") {
        std::cout << "Usage: my_cli [options] file\n";
        return 0;
    }
  4. Count words in a hardcoded string for testing.
    ✨ Show Answer
    wc.cpp
    #include <iostream>
    #include <sstream>
    #include <string>
    
    int main() {
        std::string text = "the quick brown fox jumps";
        std::istringstream ss(text);
        std::string word;
        int count = 0;
        while (ss >> word) ++count;
        std::cout << count << " words\n";
    }
  5. Append a line to a file.
    ✨ Show Answer
    std::ofstream out("todo.txt", std::ios::app);
    out << "new item\n";

Submission Checklist

  • Multi-file project (at least 1 source + 1 header)
  • CMakeLists.txt builds cleanly with -Wall -Wextra
  • README explains how to build and use
  • Handles --help and bad input gracefully
  • At least one unit test (or a hand-tested input file)
  • Compiles with no warnings

Next Module → Classes & Objects: Encapsulation Fundamentals.