Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/doccheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Docstring Check
on:
pull_request:
push:
branches: [ main ]

jobs:
doccheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build doc_check tool
run: gcc -std=c99 -Wall -Wextra -o tools/doc_check tools/doc_check.c
- name: Run docstring check
run: tools/doc_check src/*.c src/*.h src/*.cpp
14 changes: 12 additions & 2 deletions src/base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
#include <vector>
#include <stdexcept>

// Base64 decoding function
/**
* @brief Decode a base64-encoded string.
*
* @param base64_str Input base64 string.
* @return Decoded binary data as a string.
*/
inline std::string base64_decode(const std::string& base64_str) {
const char* base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Expand Down Expand Up @@ -61,7 +66,12 @@ inline std::string base64_decode(const std::string& base64_str) {
}


// Base64 encoding function
/**
* @brief Encode binary data as base64.
*
* @param input Raw input string.
* @return Base64 encoded representation.
*/
inline std::string base64_encode(const std::string& input) {
const char* base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Expand Down
12 changes: 8 additions & 4 deletions src/dirdoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,14 @@ int main(int argc, char *argv[]) {
}
#endif /* !defined(UNIT_TEST) */

/*
* Implementation of get_default_output()
* Returns a default output filename based on the input directory.
* The returned string is dynamically allocated and must be freed by the caller.
/**
* @brief Returns a default output filename based on the input directory.
*
* Generates a markdown filename based on the provided directory name. The
* returned string is dynamically allocated and must be freed by the caller.
*
* @param input_dir The path of the directory being documented.
* @return char* Newly allocated output filename.
*/
char *get_default_output(const char *input_dir) {
const char *default_name = "directory_documentation.md";
Expand Down
21 changes: 17 additions & 4 deletions src/dirdoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,26 @@ typedef struct {
size_t total_tokens;
} DocumentInfo;

/* Main documentation generation function.
* Returns 0 on success, non-zero on failure.
/**
* @brief Main documentation generation function.
*
* Scans a directory and writes a markdown description of its structure and
* optionally its file contents.
*
* @param input_dir The directory to document.
* @param output_file Output markdown path or NULL for default.
* @param flags Combination of option flags (e.g., STRUCTURE_ONLY).
* @return int 0 on success, non-zero on failure.
*/
int document_directory(const char *input_dir, const char *output_file, int flags);

/* Returns a default output filename based on the input directory.
* The returned string is dynamically allocated and must be freed by the caller.
/**
* @brief Builds a default output filename based on the input directory.
*
* The returned string must be freed by the caller.
*
* @param input_dir Directory being documented.
* @return char* Newly allocated output filename.
*/
char *get_default_output(const char *input_dir);

Expand Down
60 changes: 50 additions & 10 deletions src/gitignore.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@

#define MAX_LINE_LENGTH 1024

// Helper: Escapes regex special characters in a string.
/**
* @brief Escapes regex special characters in a string.
*
* Allocates and returns a new string where characters that have special meaning
* in regular expressions are prefixed with a backslash.
*
* @param str Input string to escape.
* @return char* Newly allocated escaped string or NULL on failure.
*/
static char *escape_regex(const char *str) {
size_t len = strlen(str);
char *escaped = (char*)malloc(2 * len + 1); // worst-case: every character escaped
Expand All @@ -24,12 +32,16 @@ static char *escape_regex(const char *str) {
return escaped;
}

// Helper: Translates a gitignore pattern into a POSIX regular expression.
// This simplified translator replaces:
// - "**" with ".*" (matching across directories)
// - "*" with "[^/]*" (matching within a single directory)
// - "?" with "." (any single character)
// Change the function signature to accept dir_only flag
/**
* @brief Convert a gitignore pattern to a POSIX regular expression.
*
* This simplified translator handles `**`, `*` and `?` wildcards and optionally
* appends a directory-only suffix when `dir_only` is true.
*
* @param pattern The gitignore pattern string.
* @param dir_only Non-zero if the pattern applies only to directories.
* @return char* Newly allocated regex string or NULL on failure.
*/
static char *translate_gitignore_pattern(const char *pattern, bool dir_only) {
size_t len = strlen(pattern);
// Allocate a buffer that is large enough for worst-case expansion.
Expand Down Expand Up @@ -87,9 +99,14 @@ static char *translate_gitignore_pattern(const char *pattern, bool dir_only) {
return regex_pattern;
}

// Update the parse_gitignore_line function to pass dir_only to translate_gitignore_pattern
/* Parses a single gitignore pattern string and adds it to the provided GitignoreList.
* Returns 0 on success, -1 on error.
/**
* @brief Parse a single gitignore pattern string and add it to a list.
*
* This wrapper is shared by the line-based parser and the command line handler.
*
* @param pattern_str The gitignore pattern text.
* @param list Gitignore list to append the compiled rule to.
* @return int 0 on success, -1 on error.
*/
int parse_gitignore_pattern_string(const char *pattern_str, GitignoreList *list) {
if (!pattern_str || !list) return -1;
Expand Down Expand Up @@ -160,6 +177,13 @@ int parse_gitignore_pattern_string(const char *pattern_str, GitignoreList *list)
return 0;
}

/**
* @brief Parse a single line from a .gitignore file.
*
* @param line The raw line text.
* @param list Gitignore list to update.
* @return int 0 on success, -1 on error.
*/
static int parse_gitignore_line(const char *line, GitignoreList *list) {
// Skip leading whitespace.
while (*line && isspace((unsigned char)*line)) line++;
Expand All @@ -180,6 +204,12 @@ static int parse_gitignore_line(const char *line, GitignoreList *list) {
return result;
}

/**
* @brief Load rules from a .gitignore file located in a directory.
*
* @param dir_path Directory that may contain a .gitignore file.
* @param gitignore Gitignore list to populate.
*/
void load_gitignore(const char *dir_path, GitignoreList *gitignore) {
gitignore->rules = NULL;
gitignore->count = 0;
Expand All @@ -203,6 +233,13 @@ void load_gitignore(const char *dir_path, GitignoreList *gitignore) {
fclose(f);
}

/**
* @brief Determine if a path should be ignored by gitignore rules.
*
* @param path Relative path to test.
* @param gitignore Compiled gitignore rule list.
* @return true if the path is ignored, false otherwise.
*/
bool match_gitignore(const char *path, const GitignoreList *gitignore) {
if (!gitignore || gitignore->count == 0) return false;

Expand All @@ -218,6 +255,9 @@ bool match_gitignore(const char *path, const GitignoreList *gitignore) {
return ignored;
}

/**
* @brief Free memory associated with a GitignoreList.
*/
void free_gitignore(GitignoreList *gitignore) {
if (!gitignore) return;
for (size_t i = 0; i < gitignore->count; i++) {
Expand Down
26 changes: 19 additions & 7 deletions src/gitignore.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,34 @@ typedef struct {
size_t capacity;
} GitignoreList;

/* Loads the .gitignore file from the specified directory,
* parses each rule (supporting ** patterns, negation, etc.), and compiles a regex for each.
/**
* @brief Load gitignore rules from a directory.
*
* @param dir_path Directory containing a .gitignore file.
* @param gitignore Gitignore list to populate.
*/
void load_gitignore(const char *dir_path, GitignoreList *gitignore);

/* Parses a single gitignore pattern string and adds it to the provided GitignoreList.
* Returns 0 on success, -1 on error.
/**
* @brief Add a gitignore pattern string to a list.
*
* @param pattern Pattern text.
* @param list Gitignore list to modify.
* @return int 0 on success, -1 on error.
*/
int parse_gitignore_pattern_string(const char *pattern, GitignoreList *list);

/* Checks whether the given path should be ignored based on the compiled gitignore rules.
* Returns true if the path should be ignored.
/**
* @brief Check if a path matches gitignore rules.
*
* @param path Relative path to test.
* @param gitignore Compiled gitignore list.
* @return true if the path should be ignored.
*/
bool match_gitignore(const char *path, const GitignoreList *gitignore);

/* Frees all memory allocated for the GitignoreList and releases compiled regex resources.
/**
* @brief Free resources associated with a GitignoreList.
*/
void free_gitignore(GitignoreList *gitignore);

Expand Down
27 changes: 27 additions & 0 deletions src/reconstruct.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
#include "reconstruct.h"
#include "dirdoc.h" // for MAX_PATH_LEN and BUFFER_SIZE

/**
* @brief Recursively create directories for a given path.
*
* @param path Directory path to create.
* @return int 0 on success, non-zero on failure.
*/
static int mkdirs(const char *path) {
char tmp[MAX_PATH_LEN];
snprintf(tmp, sizeof(tmp), "%s", path);
Expand All @@ -25,6 +31,13 @@ static int mkdirs(const char *path) {
return mkdir(tmp, 0755); // final component
}

/**
* @brief Check if a line begins a fenced code block.
*
* @param line Input line from the markdown file.
* @param len Output parameter storing the fence length.
* @return int Non-zero if the line begins a fence.
*/
static int is_fence_start(const char *line, int *len) {
int i = 0;
while (line[i] == '`') i++;
Expand All @@ -35,6 +48,13 @@ static int is_fence_start(const char *line, int *len) {
return 0;
}

/**
* @brief Check if a line ends a fenced code block of a given length.
*
* @param line Input line from the markdown file.
* @param len Number of backticks that opened the fence.
* @return int Non-zero if this line closes the fence.
*/
static int is_fence_end(const char *line, int len) {
for (int i = 0; i < len; i++) {
if (line[i] != '`') return 0;
Expand All @@ -43,6 +63,13 @@ static int is_fence_end(const char *line, int len) {
return c == '\n' || c == '\0' || c == '\r';
}

/**
* @brief Reconstruct files from a dirdoc-generated markdown document.
*
* @param md_path Path to the documentation markdown.
* @param out_dir Output directory for reconstructed files.
* @return int 0 on success, non-zero on failure.
*/
int reconstruct_from_markdown(const char *md_path, const char *out_dir) {
FILE *in = fopen(md_path, "r");
if (!in) {
Expand Down
10 changes: 6 additions & 4 deletions src/reconstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
extern "C" {
#endif

/* Reconstructs a directory from a dirdoc generated markdown file.
* md_path: path to the documentation markdown
* out_dir: directory to create reconstructed files
* Returns 0 on success, non-zero on failure.
/**
* @brief Reconstruct a directory from a dirdoc markdown file.
*
* @param md_path Path to the documentation markdown.
* @param out_dir Output directory to write reconstructed files.
* @return int 0 on success, non-zero on failure.
*/
int reconstruct_from_markdown(const char *md_path, const char *out_dir);

Expand Down
44 changes: 27 additions & 17 deletions src/scanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,43 @@ typedef struct {
size_t capacity;
} FileList;

/* Initializes the given FileList structure. */
/**
* @brief Initialize a FileList structure.
*/
void init_file_list(FileList *list);

/* Adds a new file entry to the FileList.
* @param list: Pointer to the FileList.
* @param path: Relative path of the file or directory.
* @param is_dir: Boolean indicating if the entry is a directory.
* @param depth: Depth level in the directory hierarchy.
/**
* @brief Add a new file entry to a FileList.
*
* @param list List to update.
* @param path Relative path of the file or directory.
* @param is_dir Non-zero if the entry is a directory.
* @param depth Depth level within the tree.
*/
void add_file_entry(FileList *list, const char *path, bool is_dir, int depth);

/* Frees all memory associated with the FileList. */
/**
* @brief Free memory used by a FileList.
*/
void free_file_list(FileList *list);

/* Recursively scans the directory at dir_path and populates the FileList.
* @param dir_path: The absolute path of the directory to scan.
* @param rel_path: The relative path from the root directory (can be NULL).
* @param list: Pointer to the FileList to populate.
* @param depth: Current depth level.
* @param gitignore: Pointer to a GitignoreList structure (can be NULL).
* @param flags: Flags controlling scanning behavior (e.g., INCLUDE_GIT)
* @return: true if scanning was successful, false otherwise.
/**
* @brief Recursively scan a directory and populate a FileList.
*
* @param dir_path Absolute path to scan.
* @param rel_path Relative path from the root directory.
* @param list Output FileList.
* @param depth Current recursion depth.
* @param gitignore Optional gitignore rule list.
* @param flags Flags controlling scanning behavior.
* @return true if entries were found, otherwise false.
*/
bool scan_directory(const char *dir_path, const char *rel_path, FileList *list, int depth, const GitignoreList *gitignore, int flags);

/* Comparison function for qsort to order FileEntry items.
* @return: Negative if a < b, zero if equal, positive if a > b.
/**
* @brief Comparison function for ordering FileEntry items.
*
* @return Negative if a < b, zero if equal, positive if a > b.
*/
int compare_entries(const void *a, const void *b);

Expand Down
Loading
Loading