cnotes/analyze.md
Greg Gauthier 1356b9d3e0
All checks were successful
Build / build (push) Successful in 13s
refactor(prompts): refine C90 analysis prompt to emphasize ANSI C89 and portability
- Create new .grokkit/prompts/c.md with updated structure, sections, and details for better educational focus on strict C90 constraints, immutability, and Unix philosophy.
- Delete outdated .grokkit/prompts/c90.md to avoid duplication.
- Add analyze.md as the generated Markdown report based on the refined prompt, providing a complete project analysis for cnotes.
2026-03-28 16:39:36 +00:00

47 lines
6.8 KiB
Markdown

# Project Analysis: cnotes
## Tech Stack & Layout
- Language (strict C90 / ANSI C89), build system (simple Makefile implied for Unix-like, Turbo C++ for DOS, with scripts like make-dos-zip.sh for packaging), supported platforms (modern Unix, macOS, Windows, DOS 6.22 with Turbo C++)
- Why these choices were made (portability across decades-old and modern systems without relying on C99+ features; minimal dependencies to avoid external libraries, ensuring self-contained builds; "do one thing well" by creating small, composable CLI tools for note management)
- High-level directory structure and purpose of each major directory/file
- include/: Headers like config.h (project-wide constants, e.g., file paths, buffer sizes) and platform.h (platform-specific macros for portability, e.g., file separators)
- src/: Core source files for each command (cnadd.c for adding notes, cncount.c for counting, cndel.c for archiving/deleting, cndump.c for listing, cnfind.c for searching, cnhelp.c for usage info)
- make-dos-zip.sh: Script for building and packaging a DOS-compatible ZIP archive, handling Turbo C++ compilation quirks
## Module & Function Relationships
- How the six main commands (`cnadd`, `cndump`, `cncount`, `cndel`, `cnfind`, `cnhelp`) relate to each other (each is a standalone executable focused on one task, sharing no runtime dependencies but reusing code via includes; they operate on a common CSV notes file, enabling shell piping/composition, e.g., `cnfind | cncount`)
- Shared utilities and internal code organization (`src/` houses one .c file per command for modularity; `include/` provides common helpers like string utilities, CSV parsing, and platform abstractions; no central library—code is compiled per-command to minimize footprint and embody Unix philosophy)
## Function & Method Reference
- Grouped by source file (cnadd.c)
- main(): Parses CLI args to capture a new note, appends to CSV file; uses fgets() for input, manual string concatenation for CSV formatting; exists for immutable addition without overwriting existing data, ensuring portability with stdio.h only
- append_note(): Opens file in append mode, writes timestamped CSV row; handles quoting and escaping manually via loops; designed for immutability—notes are logged forever, aligning with archiving pattern and avoiding file truncation in C90
- Grouped by source file (cndump.c)
- main(): Reads entire CSV, formats and prints notes with line wrapping; detects terminal width via ioctl() on Unix or fallback to defaults; provides readable output without external tools, emphasizing CLI composability
- print_notes(): Iterates over parsed lines, adapts output to width; uses manual memory allocation (malloc/free) for buffers; exists to handle variable terminal sizes portably, avoiding modern extensions like ncurses
- Grouped by source file (cncount.c)
- main(): Parses CSV, counts valid rows; simple loop with error checks; designed for quick stats, composable with pipes (e.g., filter then count)
- count_rows(): Scans file line-by-line using fgets(), skips headers/invalids; manual counting without arrays for C90 memory constraints; supports Unix philosophy by doing one thing (counting) efficiently
- Grouped by source file (cndel.c)
- main(): Marks note for "deletion" by archiving to a separate file; reads, filters, rewrites active CSV; immutable—original data persists in archive; rationale: prevents data loss, portable file I/O with rename() fallbacks
- archive_note(): Copies row to archive, skips in active file; uses temp files for atomicity; exists to enforce immutability under C90, avoiding direct edits that could corrupt on legacy systems like DOS
- Grouped by source file (cnfind.c)
- main(): Searches CSV for keyword matches, outputs matching rows; case-insensitive via manual tolower() loops; designed for grep-like functionality without regex libs, enhancing shell integration
- search_notes(): Parses lines, tokenizes CSV fields manually (split on commas, handle quotes); mallocs search buffers; portability-focused, avoiding strstr() pitfalls on DOS by using custom loops
- Grouped by source file (cnhelp.c)
- main(): Prints usage for all commands; static strings formatted simply; exists as a minimalist help tool, reducing need for man pages on non-Unix platforms
- Shared utilities (from includes)
- parse_csv_line(): Splits string into fields without libs, using pointers and loops; handles escaped quotes; crucial for all commands, designed for strict C90 string.h compliance
- get_terminal_width(): Platform-specific detection (e.g., TIOCGWINSZ on Unix, hardcoded for DOS); fallbacks to 80 columns; ensures readable output across environments
- error_handler(): Prints messages to stderr, exits with code; uniform error pattern without variadic functions (uses sprintf for formatting); rationale: safe, portable error handling in C90
## Object & Data Flow
- Main data structures (notes stored as CSV files with rows like "timestamp,note_text"; in-memory, uses char arrays or malloc'd buffers—no structs for C90 simplicity; archives as separate CSV for immutability)
- Flow of data from command-line arguments → processing → output or archive (args parsed via argc/argv into strings; file opened with fopen(), read line-by-line into buffers; processed (e.g., search/add/count) with manual loops; output to stdout or written back to file/archive; temp files used for safe rewrites)
- Error handling and safety patterns used under strict C90 constraints (check fopen() returns, use strerror() sparingly with fallbacks; manual buffer overflow prevention via fixed sizes; exit() on failures; no exceptions—rely on return codes and stderr for portability)
## Learning Path & Gotchas
- Recommended order to read and understand the codebase (start with include/config.h and platform.h for constants/portability; then cnhelp.c for overview; progress to cnadd.c and cndump.c for core add/read flows; finish with cndel.c and cnfind.c for advanced patterns like archiving/search; compile and test on Unix first, then DOS)
- Common pitfalls for newcomers to strict C90 / legacy-compatible C (manual memory management—always free() after malloc(), watch for leaks; no bool or variable-length arrays—use ints and fixed buffers; string handling requires null-termination checks)
- Portability gotchas (DOS vs Unix differences like CR/LF line endings—handle with custom parsing; Turbo C++ quirks such as limited stack size or no getenv()—use #ifdefs in platform.h; system() may not work on DOS, so avoid; file I/O must check modes carefully for binary/text differences)
- Why certain design decisions were made (immutability ensures data integrity without databases, fitting "do one thing well"; no external libs keeps it lightweight and buildable on 1990s systems; single-purpose tools allow Unix-style composition, like piping cnfind to cndump for filtered views)