~kris/hacks

sparser

ref: 83b1653b13073ba220e9836d46fa0054d7ee65c3 sparser/.claude/CLAUDE.md -rw-r--r-- 3.9 KiB
83b1653b — Kris Yotam add README.md 5 months ago

#sparser — CLAUDE.md

#Project

sparser (Simple Parser) is a suckless tool that extracts external URLs from text-based files. It handles HTML, Markdown (MD/MDX), plain text, and other text files. It can process a single file, read from stdin, or recursively walk a directory tree. Outputs one URL per line to stdout.

Designed to pair with suploader for a pipeline: sparser -R /content | suploader -

#Coding Standards — Suckless C Style

All code in this project MUST follow the suckless.org coding style:

#Language

  • C99 (ISO/IEC 9899:1999), no extensions
  • POSIX.1-2008 (_POSIX_C_SOURCE 200809L)

#Indentation & Whitespace

  • Tabs for indentation (1 tab = 1 level)
  • Spaces for alignment only, never for indentation
  • No tabs except at the beginning of a line
  • Maximum line length: 79 characters

#Comments

  • Use /* */ only, never //
  • Comment fallthrough cases in switch statements

#Variables

  • All declarations at the top of the block
  • Pointer * adjacent to variable name: char *p, not char* p
  • No C99 bool; use int (0/1)
  • Global/static variables not used outside TU must be static

#Functions

  • Return type on its own line
  • Function name at column 0 on next line (enables grep ^funcname)
  • Opening { on its own line for functions
  • Functions not used outside their file: static
static void
usage(void)
{
	fprintf(stderr, "usage: sparser [-v] [-R] path\n");
	exit(1);
}

#Braces

  • Opening { on same line for control flow (if, for, while, switch)
  • Closing } on its own line unless continuing (else, do-while)
  • Use braces even for single statements when sibling branches use them

#Naming

  • lowercase_with_underscores for functions and variables
  • UPPERCASE for macros and constants
  • CamelCase for typedef'd struct types
  • No _t suffix (reserved by POSIX)
  • Prefix module functions with module name

#Control Flow

  • Space after if, for, while, switch
  • No space after ( or before )
  • Use goto for cleanup/unwind, not nested ifs
  • Return/exit early on failure
  • Test against 0, not -1: if (func() < 0)

#Error Handling

  • All allocation checked; goto cleanup on failure
  • die() for fatal errors (prints message, exits)
  • warn() for recoverable errors (prints, continues)

#File Organization Order

  1. License header
  2. System includes (alphabetical)
  3. Local includes
  4. Macros
  5. Type definitions
  6. Function declarations
  7. Global variables
  8. Function definitions (same order as declarations)

#Headers

  • System headers first, alphabetical
  • Local headers after blank line
  • No cyclic dependencies
  • Include only what is needed

#Architecture

#Module Layout

Module Prefix File Responsibility
Main sparser.c Entry point, directory walking, file dispatch
Extract extract_ extract.c URL extraction from text content
Utilities die, warn, x* util.c Memory wrappers, string ops, error handling
Config config.h Compile-time constants

#Architecture Rules

  • Separate compilation. Every .c file compiles independently.
  • No dynamic loading. All features compiled in.
  • No external dependencies. Pure C99 + POSIX.
  • Line-oriented output. One URL per line to stdout.
  • Unix pipeline friendly. Works with pipes, xargs, etc.

#Build

make            # build sparser binary
make clean      # remove build artifacts
make install    # install to /usr/local/bin

Dependencies: none (pure C99 + POSIX)

#Usage

# Extract URLs from a single file
sparser page.html

# Recursive directory scan
sparser -R /content

# Read from stdin
cat file.md | sparser -

# Verbose (show file names being processed)
sparser -v -R /content

# Deduplicate output
sparser -u -R /content

# Pipeline with suploader
sparser -u -R /content | suploader -

#Git Conventions

  • No Co-Authored-By: Claude lines
  • Commit messages: imperative, <72 chars, no period
  • One logical change per commit