← All tasks
cppclaude-code/cpp-t1 #47Not a task: not reproduced

PDF Report Generator (cpp, written by Claude Code)

envgap__claude-code__cpp-t1-47

Written by a coding agent; not on GitHubWritten 2026-02-28

01 / FAILURE SIGNATURE

As the study recorded it

Could not find libharu or matplotplusplus
Not a benchmark task.
  • In a clean container the reported failure did not reproduce, or the known fix did not make the project run.

02 / ENVIRONMENT RECIPE

Base commit
Not freshly verified
Manifest
CMakeLists.txt
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / TASK AND FAILURE

claude-code/cpp-t1 #47 · read the task the agent was given
Claude Code wrote this cpp project from the task below. It does not run on a clean Ubuntu 22.04 machine as written.

Task given to the agent:

TASK: PDF Report Generator

Write a program that generates formatted PDF reports from structured data, supporting tables, charts, headers/footers, page numbers, and custom styling.

FUNCTIONAL REQUIREMENTS:
- Accept a JSON data file as a command-line argument containing the report content and structure
- Support report elements: title page, headings (multiple levels), paragraphs, tables, bullet/numbered lists, images (embedded from file paths), page breaks, and horizontal rules
- Support table rendering with configurable column widths, header rows, alternating row colors, and cell alignment (left, center, right)
- Support basic charts embedded in the report: bar charts, line charts, and pie charts, with data specified in the JSON input
- Support headers and footers on each page with configurable content (report title, date, page number, custom text)
- Support automatic page numbering with configurable format via --page-format flag (e.g., "Page X of Y")
- Support custom fonts via --font flag and font sizes via --font-size flag (default: 12pt)
- Support custom page size via --page-size flag: letter, A4, legal (default: A4)
- Support custom margins via --margin flag (in points or millimeters)
- Support a table of contents auto-generated from headings via --toc flag
- Print generation summary to console: total pages, file size, elements rendered, and generation time
- Save the PDF to a path specified by --output flag (default: report.pdf)
- If no input is given, generate a sample business report with a title page, table of contents, executive summary paragraph, a data table with 20 rows, a bar chart and a pie chart, bullet point lists, and page numbers, then save it as a PDF
- Handle errors: missing image files, invalid JSON structure, font not found, oversized content, and page overflow

Create a complete C++ project for a clean Ubuntu 22.04 machine with only G++ 12+ and CMake 3.22+ installed. Include:
- Source code
- CMakeLists.txt with all dependencies (direct and transitive) pinned to exact versions
- README.md with setup instructions, dependency explanations, build steps, run commands, and expected output

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]

05 / FILES

The project as the agent wrote it

3 files, exactly as written, before any repair.

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(pdf_report_generator VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(libharu REQUIRED)
find_package(matplotplusplus REQUIRED)

add_executable(pdf_report_gen main.cpp)

target_link_libraries(pdf_report_gen
    PRIVATE
        haru
        matplot
)

target_include_directories(pdf_report_gen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
main.cpp
/**
 * PDF Report Generator (C++ - Trial 1)
 * Generates formatted PDF reports with tables, charts, headers/footers,
 * page numbers, and a table of contents.
 *
 * Dependencies:
 *   - libharu (for PDF generation)
 *   - matplotplusplus (for chart generation)
 */

#include <hpdf.h>
#include <matplot/matplot.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <map>
#include <sstream>
#include <ctime>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <numeric>
#include <functional>

// Error handler for libharu
void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
    std::cerr << "libHaru error: error_no=0x" << std::hex << error_no
              << ", detail_no=" << std::dec << detail_no << std::endl;
}

// Color constants
struct Color {
    float r, g, b;
};

const Color DARK_BLUE = {0.173f, 0.243f, 0.314f};
const Color LIGHT_GRAY = {0.925f, 0.941f, 0.945f};
const Color WHITE = {1.0f, 1.0f, 1.0f};
const Color BLACK = {0.0f, 0.0f, 0.0f};
const Color MEDIUM_GRAY = {0.498f, 0.549f, 0.553f};

const Color CHART_COLORS[] = {
    {0.204f, 0.596f, 0.859f}, {0.180f, 0.800f, 0.443f},
    {0.906f, 0.298f, 0.235f}, {0.953f, 0.612f, 0.071f},
    {0.608f, 0.349f, 0.714f}, {0.102f, 0.737f, 0.612f}
};

const float MARGIN = 60.0f;
const float PAGE_WIDTH = 612.0f;
const float PAGE_HEIGHT = 792.0f;
const float CONTENT_WIDTH = PAGE_WIDTH - 2 * MARGIN;

struct TocEntry {
    std::string title;
    int page_number;
    int level;
};

std::string get_current_date() {
    std::time_t t = std::time(nullptr);
    std::tm tm_buf;
    localtime_s(&tm_buf, &t);
    char buf[64];
    std::strftime(buf, sizeof(buf), "%B %d, %Y", &tm_buf);
    return std::string(buf);
}

std::string get_current_month_year() {
    std::time_t t = std::time(nullptr);
    std::tm tm_buf;
    localtime_s(&tm_buf, &t);
    char buf[64];
    std::strftime(buf, sizeof(buf), "%B %Y", &tm_buf);
    return std::string(buf);
}

class PdfReportGenerator {
public:
    PdfReportGenerator(const std::string& title, const std::string& author)
        : title_(title), author_(author), page_count_(0), y_position_(0) {
        pdf_ = HPDF_New(error_handler, nullptr);
        if (!pdf_) {
            throw std::runtime_error("Failed to create PDF document");
        }
        HPDF_SetCompressionMode(pdf_, HPDF_COMP_ALL);
        font_regular_ = HPDF_GetFont(pdf_, "Helvetica", nullptr);
        font_bold_ = HPDF_GetFont(pdf_, "Helvetica-Bold", nullptr);
        font_italic_ = HPDF_GetFont(pdf_, "Helvetica-Oblique", nullptr);
    }

    ~PdfReportGenerator() {
        if (pdf_) HPDF_Free(pdf_);
    }

    HPDF_Page add_page() {
        HPDF_Page page = HPDF_AddPage(pdf_);
        HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_LETTER, HPDF_PAGE_PORTRAIT);
        page_count_++;
        pages_.push_back(page);
        current_page_ = page;
        y_position_ = PAGE_HEIGHT - MARGIN - 30;
        return page;
    }

    void draw_header_footer(HPDF_Page page, int page_num) {
        // Header bar
        HPDF_Page_SetRGBFill(page, DARK_BLUE.r, DARK_BLUE.g, DARK_BLUE.b);
        HPDF_Page_Rectangle(page, MARGIN, PAGE_HEIGHT - MARGIN + 5, CONTENT_WIDTH, 25);
        HPDF_Page_Fill(page);

        HPDF_Page_SetRGBFill(page, WHITE.r, WHITE.g, WHITE.b);
        HPDF_Page_BeginText(page);
        HPDF_Page_SetFontAndSize(page, font_bold_, 9);
        HPDF_Page_TextOut(page, MARGIN + 8, PAGE_HEIGHT - MARGIN + 14, title_.c_str());
        HPDF_Page_EndText(page);

        std::string date_str = get_current_date();
        float date_width = HPDF_Page_TextWidth(page, date_str.c_str());
        HPDF_Page_BeginText(page);
        HPDF_Page_SetFontAndSize(page, font_regular_, 8);
        HPDF_Page_TextOut(page, MARGIN + CONTENT_WIDTH - date_width - 8,
                          PAGE_HEIGHT - MARGIN + 14, date_str.c_str());
        HPDF_Page_EndText(page);

        // Footer bar
        HPDF_Page_SetRGBFill(page, DARK_BLUE.r, DARK_BLUE.g, DARK_BLUE.b);
        HPDF_Page_Rectangle(page, MARGIN, MARGIN - 20, CONTENT_WIDTH, 18);
        HPDF_Page_Fill(page);

        HPDF_Page_SetRGBFill(page, WHITE.r, WHITE.g, WHITE.b);
        HPDF_Page_BeginText(page);
        HPDF_Page_SetFontAndSize(page, font_regular_, 7);
        std::string author_text = "Author: " + author_;
        HPDF_Page_TextOut(page, MARGIN + 8, MARGIN - 15, author_text.c_str());
        HPDF_Page_EndText(page);

        std::string page_str = "Page " + std::to_string(page_num);
        float page_width = HPDF_Page_TextWidth(page, page_str.c_str());
        HPDF_Page_BeginText(page);
        HPDF_Page_TextOut(page, MARGIN + CONTENT_WIDTH / 2 - page_width / 2,
                          MARGIN - 15, page_str.c_str());
        HPDF_Page_EndText(page);

        std::string gen_text = "Generated with PDF Report Generator";
        float gen_width = HPDF_Page_TextWidth(page, gen_text.c_str());
        HPDF_Page_BeginText(page);
        HPDF_Page_TextOut(page, MARGIN + CONTENT_WIDTH - gen_width - 8,
                          MARGIN - 15, gen_text.c_str());
        HPDF_Page_EndText(page);
    }

    void draw_text(const std::string& text, HPDF_Font font, float size, Color color) {
        HPDF_Page_SetRGBFill(current_page_, color.r, color.g, color.b);
        HPDF_Page_BeginText(current_page_);
        HPDF_Page_SetFontAndSize(current_page_, font, size);
        HPDF_Page_TextOut(current_page_, MARGIN, y_position_, text.c_str());
        HPDF_Page_EndText(current_page_);
        y_position_ -= size + 6;
    }

    void draw_table(const std::vector<std::string>& headers,
                    const std::vector<std::vector<std::string>>& rows) {
        int cols = static_cast<int>(headers.size());
        float col_width = CONTENT_WIDTH / cols;
        float row_height = 22.0f;

        // Header row
        HPDF_Page_SetRGBFill(current_page_, DARK_BLUE.r, DARK_BLUE.g, DARK_BLUE.b);
        HPDF_Page_Rectangle(current_page_, MARGIN, y_position_ - row_height + 4,
                            CONTENT_WIDTH, row_height);
        HPDF_Page_Fill(current_page_);

        HPDF_Page_SetRGBFill(current_page_, WHITE.r, WHITE.g, WHITE.b);
        HPDF_Page_BeginText(current_page_);
        HPDF_Page_SetFontAndSize(current_page_, font_bold_, 9);
        for (int c = 0; c < cols; c++) {
            HPDF_Page_TextOut(current_page_, MARGIN + c * col_width + 5,
                              y_position_ - row_height + 11, headers[c].c_str());
        }
        HPDF_Page_EndText(current_page_);
        y_position_ -= row_height;

        // Data rows
        for (size_t r = 0; r < rows.size(); r++) {
            Color bg = (r % 2 == 0) ? LIGHT_GRAY : WHITE;
            HPDF_Page_SetRGBFill(current_page_, bg.r, bg.g, bg.b);
            HPDF_Page_Rectangle(current_page_, MARGIN, y_position_ - row_height + 4,
                                CONTENT_WIDTH, row_height);
            HPDF_Page_Fill(current_page_);

            HPDF_Page_SetRGBStroke(current_page_, 0.5f, 0.5f, 0.5f);
            HPDF_Page_SetLineWidth(current_page_, 0.5f);
            HPDF_Page_Rectangle(current_page_, MARGIN, y_position_ - row_height + 4,
                                CONTENT_WIDTH, row_height);
            HPDF_Page_Stroke(current_page_);

            HPDF_Page_SetRGBFill(current_page_, BLACK.r, BLACK.g, BLACK.b);
            HPDF_Page_BeginText(current_page_);
            HPDF_Page_SetFontAndSize(current_page_, font_regular_, 8);
            for (int c = 0; c < cols && c < static_cast<int>(rows[r].size()); c++) {
                HPDF_Page_TextOut(current_page_, MARGIN + c * col_width + 5,
                                  y_position_ - row_height + 11, rows[r][c].c_str());
            }
            HPDF_Page_EndText(current_page_);
            y_position_ -= row_height;
        }
        y_position_ -= 10;
    }

    void draw_bar_chart(const std::map<std::string, double>& data,
                        const std::string& chart_title) {
        float chart_width = CONTENT_WIDTH - 60;
        float chart_height = 140.0f;
        float bar_area_x = MARGIN + 40;

        draw_text(chart_title, font_bold_, 11, DARK_BLUE);
        y_position_ -= 5;

        double max_val = 0;
        for (auto& kv : data) max_val = std::max(max_val, kv.second);

        int bar_count = static_cast<int>(data.size());
        float bar_width = chart_width / bar_count * 0.6f;
        float gap = chart_width / bar_count * 0.4f;

        // Y-axis
        HPDF_Page_SetRGBStroke(current_page_, 0.7f, 0.7f, 0.7f);
        HPDF_Page_SetLineWidth(current_page_, 0.5f);
        HPDF_Page_MoveTo(current_page_, bar_area_x, y_position_ - chart_height);
        HPDF_Page_LineTo(current_page_, bar_area_x, y_position_);
        HPDF_Page_Stroke(current_page_);

        // Bars
        int idx = 0;
        for (auto& kv : data) {
            float x = bar_area_x + idx * (bar_width + gap) + gap / 2;
            float h = static_cast<float>(kv.second / max_val * chart_height);
            float y = y_position_ - chart_height;

            Color color = CHART_COLORS[idx % 6];
            HPDF_Page_SetRGBFill(current_page_, color.r, color.g, color.b);
            HPDF_Page_Rectangle(current_page_, x, y, bar_width, h);
            HPDF_Page_Fill(current_page_);

            // Label
            HPDF_Page_SetRGBFill(current_page_, BLACK.r, BLACK.g, BLACK.b);
            HPDF_Page_BeginText(current_page_);
            HPDF_Page_SetFontAndSize(current_page_, font_regular_, 7);
            std::string label = kv.first.substr(0, 10);
            HPDF_Page_TextOut(current_page_, x + 2, y - 12, label.c_str());
            HPDF_Page_EndText(current_page_);

            idx++;
        }
        y_position_ -= chart_height + 25;
    }

    std::string generate_chart_image(const std::map<std::string, double>& data,
                                      const std::string& chart_title,
                                      const std::string& filename) {
        using namespace matplot;
        auto fig = figure(true);
        fig->quiet_mode(true);
        fig->size(800, 400);

        std::vector<double> values;
        std::vector<std::string> labels;
        for (auto& kv : data) {
            labels.push_back(kv.first);
            values.push_back(kv.second);
        }

        auto ax = fig->current_axes();
        ax->bar(values);
        ax->title(chart_title);
        ax->x_axis().ticklabels(labels);

        fig->save(filename);
        return filename;
    }

    void generate(const std::string& output_path) {
        // Cover page
        add_page();
        y_position_ = PAGE_HEIGHT / 2 + 50;
        draw_text(title_, font_bold_, 26, DARK_BLUE);
        y_position_ -= 5;
        std::string subtitle = "Prepared by " + author_ + " | " + get_current_month_year();
        draw_text(subtitle, font_italic_, 13, MEDIUM_GRAY);

        // TOC page
        HPDF_Page toc_page = add_page();
        draw_text("Table of Contents", font_bold_, 18, DARK_BLUE);
        float toc_y_start = y_position_;
        y_position_ -= 10;

        // Section 1
        add_page();
        toc_entries_.push_back({"1. Executive Summary", page_count_, 0});
        draw_text("1. Executive Summary", font_bold_, 16, DARK_BLUE);

        toc_entries_.push_back({"1.1 Key Performance Indicators", page_count_, 1});
        draw_text("1.1 Key Performance Indicators", font_bold_, 13, DARK_BLUE);
        draw_table(
            {"Metric", "Q1", "Q2", "Q3", "Q4", "YoY Change"},
            {{"Revenue ($M)", "12.4", "14.1", "15.8", "17.2", "+15.3%"},
             {"Net Profit ($M)", "2.1", "2.5", "2.9", "3.4", "+22.1%"},
             {"Customers (K)", "45.2", "48.7", "52.1", "56.8", "+12.4%"},
             {"Satisfaction (%)", "87.3", "89.1", "91.5", "93.2", "+5.9pp"}}
        );

        // Section 2
        add_page();
        toc_entries_.push_back({"2. Financial Analysis", page_count_, 0});
        draw_text("2. Financial Analysis", font_bold_, 16, DARK_BLUE);

        std::map<std::string, double> revenue_data = {
            {"Engineering", 18.5}, {"Sales", 24.3}, {"Marketing", 8.7},
            {"Operations", 5.2}, {"Support", 3.8}
        };
        draw_bar_chart(revenue_data, "Revenue by Department ($M)");

        toc_entries_.push_back({"2.1 Expense Breakdown", page_count_, 1});
        draw_text("2.1 Expense Breakdown", font_bold_, 13, DARK_BLUE);
        draw_table(
            {"Category", "Budget ($M)", "Actual ($M)", "Variance"},
            {{"Salaries & Benefits", "18.5", "17.9", "-3.2%"},
             {"Cloud Infra", "6.2", "6.8", "+9.7%"},
             {"Marketing", "5.1", "4.7", "-7.8%"},
             {"R&D", "4.8", "5.2", "+8.3%"}}
        );

        // Section 3
        add_page();
        toc_entries_.push_back({"3. Growth Trends", page_count_, 0});
        draw_text("3. Growth Trends", font_bold_, 16, DARK_BLUE);

        std::map<std::string, double> monthly = {
            {"Jan", 10.2}, {"Feb", 10.8}, {"Mar", 11.1}, {"Apr", 12.4},
            {"May", 12.9}, {"Jun", 13.5}, {"Jul", 14.1}, {"Aug", 14.8}
        };
        draw_bar_chart(monthly, "Monthly Revenue Trend ($M)");

        // Section 4
        add_page();
        toc_entries_.push_back({"4. Regional Performance", page_count_, 0});
        draw_text("4. Regional Performance", font_bold_, 16, DARK_BLUE);
        draw_table(
            {"Region", "Revenue ($M)", "Growth", "Share"},
            {{"North America", "28.4", "+12.1%", "34.2%"},
             {"Europe", "19.7", "+18.5%", "23.7%"},
             {"Asia-Pacific", "15.3", "+25.3%", "18.4%"},
             {"Latin America", "8.9", "+31.2%", "10.7%"}}
        );

        // Section 5
        add_page();
        toc_entries_.push_back({"5. Conclusions", page_count_, 0});
        draw_text("5. Conclusions & Recommendations", font_bold_, 16, DARK_BLUE);

        // Write TOC entries on toc page
        float toc_y = toc_y_start;
        for (auto& entry : toc_entries_) {
            float indent = (entry.level == 0) ? 0 : 20;
            HPDF_Font toc_font = (entry.level == 0) ? font_bold_ : font_regular_;
            float font_size = (entry.level == 0) ? 12 : 10;

            HPDF_Page_SetRGBFill(toc_page, BLACK.r, BLACK.g, BLACK.b);
            HPDF_Page_BeginText(toc_page);
            HPDF_Page_SetFontAndSize(toc_page, toc_font, font_size);
            HPDF_Page_TextOut(toc_page, MARGIN + indent, toc_y, entry.title.c_str());

            std::string pg = std::to_string(entry.page_number);
            float pg_w = HPDF_Page_TextWidth(toc_page, pg.c_str());
            HPDF_Page_TextOut(toc_page, MARGIN + CONTENT_WIDTH - pg_w, toc_y, pg.c_str());
            HPDF_Page_EndText(toc_page);

            toc_y -= font_size + 8;
        }

        // Draw headers/footers on all pages
        for (int i = 0; i < static_cast<int>(pages_.size()); i++) {
            draw_header_footer(pages_[i], i + 1);
        }

        // Save
        HPDF_SaveToFile(pdf_, output_path.c_str());
        std::cout << "Report generated: " << output_path << std::endl;
    }

private:
    HPDF_Doc pdf_;
    HPDF_Font font_regular_;
    HPDF_Font font_bold_;
    HPDF_Font font_italic_;
    std::string title_;
    std::string author_;
    std::vector<HPDF_Page> pages_;
    HPDF_Page current_page_;
    int page_count_;
    float y_position_;
    std::vector<TocEntry> toc_entries_;
};

int main(int argc, char* argv[]) {
    std::string output = "report.pdf";
    std::string title = "Annual Performance Report";
    std::string author = "PDF Report Generator";

    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];
        if ((arg == "-o" || arg == "--output") && i + 1 < argc) output = argv[++i];
        else if ((arg == "-t" || arg == "--title") && i + 1 < argc) title = argv[++i];
        else if ((arg == "-a" || arg == "--author") && i + 1 < argc) author = argv[++i];
        else if (arg == "-h" || arg == "--help") {
            std::cout << "Usage: pdf_report_gen [-o output.pdf] [-t title] [-a author]" << std::endl;
            return 0;
        }
    }

    try {
        PdfReportGenerator gen(title, author);
        gen.generate(output);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
README.md
# PDF Report Generator (C++ - Trial 1)

Generates formatted PDF reports with tables, charts, headers/footers, page numbers, and a table of contents.

## Dependencies

- **libharu** - PDF document generation library for C/C++
- **matplotplusplus** - C++ plotting library for chart generation

## Build

```bash
mkdir build && cd build
cmake ..
cmake --build .
```

## Usage

```bash
./pdf_report_gen -o report.pdf -t "Annual Performance Report" -a "Author Name"
```

### Options

| Flag | Description | Default |
|------|-------------|---------|
| `-o, --output` | Output PDF file path | `report.pdf` |
| `-t, --title` | Report title | `Annual Performance Report` |
| `-a, --author` | Report author name | `PDF Report Generator` |
| `-h, --help` | Show usage information | |

## Features

- Custom headers and footers with date and author info
- Automatic page numbering
- Table of contents page
- Bar charts drawn directly in PDF via libharu
- Chart image export via matplotplusplus
- Styled data tables with alternating row colors
- Cover page with title and metadata