47 lines
7.3 KiB
Markdown
47 lines
7.3 KiB
Markdown
# Project Analysis: proj
|
|
|
|
## Tech Stack & Layout
|
|
- Language (strict C90 / ANSI C89), no build system (simple compilation with standards-compliant compilers like gcc -ansi or Turbo C++), supported platforms (modern Unix, macOS, Windows via MinGW or Cygwin, 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 ensure it "does one thing well" like a Unix tool, avoiding external libs for broad compatibility and simplicity)
|
|
- High-level directory structure and purpose of each major directory/file
|
|
- `.` (root): Contains Git configuration for version control, with remotes pointing to a Gitea repository for source hosting
|
|
- `src/`: Core source code directory; contains `main.c` as the single entry point for the entire program, handling all logic from CLI parsing to output
|
|
|
|
## Module & Function Relationships
|
|
- How modules and functions relate to each other: With only a single source file (`src/main.c`), all functions are defined inline or as static helpers within `main.c`; the program flows from `main()` entry point to utility functions for argument parsing, data processing, and output, promoting a monolithic yet portable structure
|
|
- Shared utilities and internal code organization (`src/`, `include/`, common helpers): No separate `include/` directory (headers are minimal or inlined); common helpers in `main.c` include string manipulation, CSV parsing routines, and terminal detection functions that are called sequentially from `main()`; utilities are not modularized into separate files to minimize compilation complexity on legacy systems like DOS
|
|
|
|
## Function & Method Reference
|
|
**Grouped by responsibility in `src/main.c` (CLI Parsing and Main Loop):**
|
|
- `main(int argc, char *argv[])`: Serves as the program entry point, parsing command-line arguments to determine actions like adding or listing notes; it orchestrates data flow by calling helpers for CSV I/O and output formatting
|
|
- How it works (key logic, string/CSV handling, memory management, terminal width detection, etc.): Uses manual string comparison (e.g., `strcmp`) for args, allocates memory with `malloc` for note storage, detects terminal width via `getenv("COLUMNS")` or fallback to 80 chars for portability, and handles CSV by tokenizing strings with custom loops avoiding `strtok` for C90 purity
|
|
- Why it exists (design rationale, portability concern, Unix philosophy, or immutability requirement): Embodies Unix "do one thing well" by being a simple CLI tool; ensures portability by avoiding non-standard APIs, and enforces immutability by appending to CSV without deletions
|
|
|
|
**CSV Handling Functions:**
|
|
- `parse_csv_line(char *line, char **fields, int max_fields)`: Tokenizes a CSV line into fields without external libs
|
|
- How it works (key logic, string/CSV handling, memory management, terminal width detection, etc.): Iterates through the string with pointers, handling quotes and commas manually; allocates arrays with `malloc` and frees them explicitly to manage memory in C90 style
|
|
- Why it exists (design rationale, portability concern, Unix philosophy, or immutability requirement): Provides self-contained CSV parsing for note storage, avoiding dependencies for portability across platforms like DOS where libs may not exist; supports immutable archiving by reading without modifying source files
|
|
|
|
- `write_csv_note(FILE *fp, const char *note)`: Appends a new note to a CSV file
|
|
- How it works (key logic, string/CSV handling, memory management, terminal width detection, etc.): Escapes special characters in the note string, formats as CSV row, and writes via `fprintf`; no memory allocation needed beyond stack usage for simplicity
|
|
- Why it exists (design rationale, portability concern, Unix philosophy, or immutability requirement): Enables immutable logging where notes are appended only, never deleted or edited, aligning with archival safety; uses standard `stdio.h` for cross-platform file I/O
|
|
|
|
**Output and Utility Functions:**
|
|
- `print_notes(char **notes, int count)`: Displays notes adapted to terminal width
|
|
- How it works (key logic, string/CSV handling, memory management, terminal width detection, etc.): Queries terminal width with portable methods (e.g., `ioctl` fallback or env var), wraps lines manually using string length checks, and outputs via `printf`
|
|
- Why it exists (design rationale, portability concern, Unix philosophy, or immutability requirement): Ensures readable CLI output without curses dependency, promoting shell composability; handles portability by providing DOS-safe fallbacks like fixed-width output
|
|
|
|
- `archive_note(const char *note_id)`: Moves a note to an archive CSV without deletion
|
|
- How it works (key logic, string/CSV handling, memory management, terminal width detection, etc.): Reads source CSV, copies non-matching rows to a temp file, appends the matched note to archive, then renames files; manages buffers with `malloc`/`free`
|
|
- Why it exists (design rationale, portability concern, Unix philosophy, or immutability requirement): Implements immutable archiving (notes are never truly deleted, just relocated) for data integrity; avoids modern file APIs for C90 compliance
|
|
|
|
## Object & Data Flow
|
|
- Main data structures (especially how notes are stored and manipulated in CSV format): Notes stored as simple CSV files (e.g., rows with ID, timestamp, text); in-memory representation uses arrays of `char*` allocated via `malloc` for lists of notes, with manual indexing instead of structs for C90 simplicity
|
|
- Flow of data from command-line arguments → processing → output or archive: Args parsed in `main()` → CSV file read/parsed into memory arrays → processing (e.g., append or archive via helper functions) → output formatted for terminal or written back to CSV/archive file; immutability ensures original data is appended to, not overwritten
|
|
- Error handling and safety patterns used under strict C90 constraints: Checks return values of all functions (e.g., `fopen` != NULL), uses `errno` for I/O errors, manual cleanup with `free` in error paths; no exceptions, so flow control via early returns and status codes for portability
|
|
|
|
## Learning Path & Gotchas
|
|
- Recommended order to read and understand the codebase: Start with `main()` to grasp CLI flow, then study CSV parsing helpers for data handling, followed by output functions for portability tricks, and end with archiving logic to understand immutability
|
|
- Common pitfalls for newcomers to strict C90 / legacy-compatible C: Forgetting manual `free` after `malloc` leading to leaks; assuming C99 features like variable-length arrays (use fixed sizes instead); overlooking pointer arithmetic in string handling
|
|
- Portability gotchas (DOS vs Unix differences, Turbo C++ quirks, `getenv`, `system()`, file I/O): DOS limits file paths and lacks `getenv` for some vars (use fallbacks); Turbo C++ may require `#define` for ANSI compliance; `system()` behaves differently (e.g., no shell on DOS); file I/O must handle text/binary modes with `fopen "rb"/"wb"` for cross-platform consistency
|
|
- Why certain design decisions were made (immutability, no external libs, single-purpose tools): Immutability prevents data loss in archival tools; no libs ensure portability to minimal environments like DOS; single-purpose design follows Unix philosophy for composable CLI utilities, keeping the codebase lean and educational |