# cgit — HTML Rendering Engine
## Overview
cgit generates all HTML output through a set of low-level rendering functions
defined in `html.c` and `html.h`. These functions handle entity escaping,
URL encoding, and formatted output. Higher-level page structure is built by
`ui-shared.c`.
Source files: `html.c`, `html.h`, `ui-shared.c`, `ui-shared.h`.
## Output Model
All output functions write directly to `stdout` via `write(2)`. There is no
internal buffering beyond the standard I/O buffer. This design works because
cgit runs as a CGI process — each request is a separate process with its own
stdout connected to the web server.
## Core Output Functions
### Raw Output
```c
void html_raw(const char *data, size_t size);
```
Writes raw bytes to stdout without any escaping. Used for binary content
and pre-escaped strings.
### Escaped Text Output
```c
void html(const char *txt);
```
Writes a string with HTML entity escaping:
- `<` → `<`
- `>` → `>`
- `&` → `&`
```c
void html_txt(const char *txt);
```
Same as `html()` but also escapes:
- `"` → `"`
- `'` → `'`
Used for text content that appears inside HTML tags.
```c
void html_ntxt(const char *txt, int len);
```
Length-limited version of `html_txt()`. Writes at most `len` characters,
appending `...` if truncated.
### Attribute Escaping
```c
void html_attr(const char *txt);
```
Escapes text for use in HTML attribute values. Escapes the same characters
as `html_txt()`.
## URL Encoding
### URL Escape Table
`html.c` defines a 256-entry escape table for URL encoding:
```c
static const char *url_escape_table[256] = {
"%00", "%01", "%02", ...,
[' '] = "+",
['!'] = NULL, /* pass through */
['"'] = "%22",
['#'] = "%23",
['%'] = "%25",
['&'] = "%26",
['+'] = "%2B",
['?'] = "%3F",
/* letters, digits, '-', '_', '.', '~' pass through (NULL) */
...
};
```
Characters with a `NULL` entry pass through unmodified. All others are
replaced with their percent-encoded representations.
### URL Path Encoding
```c
void html_url_path(const char *txt);
```
Encodes a URL path component. Uses `url_escape_table` but preserves `/`
characters (they are structural in paths).
### URL Argument Encoding
```c
void html_url_arg(const char *txt);
```
Encodes a URL query parameter value. Uses `url_escape_table` including
encoding `/` characters.
## Formatted Output
### `fmt()` — Ring Buffer Formatter
```c
const char *fmt(const char *format, ...);
```
A `printf`-style formatter that returns a pointer to an internal static
buffer. Uses a ring of 8 buffers (each 8 KB) to allow multiple `fmt()`
calls in a single expression:
```c
#define FMT_BUFS 8
#define FMT_SIZE 8192
static char bufs[FMT_BUFS][FMT_SIZE];
static int bufidx;
const char *fmt(const char *format, ...)
{
bufidx = (bufidx + 1) % FMT_BUFS;
va_list args;
va_start(args, format);
vsnprintf(bufs[bufidx], FMT_SIZE, format, args);
va_end(args);
return bufs[bufidx];
}
```
This is used extensively throughout cgit for constructing strings without
explicit memory management. The ring buffer avoids use-after-free for up to
8 nested calls.
### `fmtalloc()` — Heap Formatter
```c
char *fmtalloc(const char *format, ...);
```
Like `fmt()` but allocates a new heap buffer with `xstrfmt()`. Used when
the result must outlive the ring buffer cycle.
### `htmlf()` — Formatted HTML
```c
void htmlf(const char *format, ...);
```
`printf`-style output directly to stdout. Does NOT perform HTML escaping —
the caller must ensure the format string and arguments are safe.
## Form Helpers
### Hidden Fields
```c
void html_hidden(const char *name, const char *value);
```
Generates a hidden form field:
```html
```
Values are attribute-escaped.
### Option Elements
```c
void html_option(const char *value, const char *text, const char *selected_value);
```
Generates an `
```
### Checkbox Input
```c
void html_checkbox(const char *name, int value);
```
Generates a checkbox input.
### Text Input
```c
void html_txt_input(const char *name, const char *value, int size);
```
Generates a text input field.
## Link Generation
```c
void html_link_open(const char *url, const char *title, const char *class);
void html_link_close(void);
```
Generate `` tags with optional title and class attributes. URL is
path-escaped.
## File Inclusion
```c
void html_include(const char *filename);
```
Reads a file from disk and writes its contents to stdout without escaping.
Used for header/footer file inclusion configured via the `header` and
`footer` directives.
## Page Structure (`ui-shared.c`)
### HTTP Headers
```c
void cgit_print_http_headers(void);
```
Emits HTTP response headers based on `ctx.page`:
```
Status: 200 OK
Content-Type: text/html; charset=utf-8
Last-Modified: Thu, 01 Jan 2024 00:00:00 GMT
Expires: Thu, 01 Jan 2024 01:00:00 GMT
ETag: "abc123"
```
Fields are only emitted when the corresponding `ctx.page` fields are set.
### HTML Document Head
```c
void cgit_print_docstart(void);
```
Emits the HTML5 doctype, ``, and `` section:
```html
repo - page
```
### Page Header
```c
void cgit_print_pageheader(void);
```
Renders the page header with logo, navigation tabs, and search form.
Navigation tabs are context-sensitive — repository pages show
summary/refs/log/tree/commit/diff/stats/etc.
### Page Footer
```c
void cgit_print_docend(void);
```
Closes the HTML document with footer content and closing tags.
### Full Page Layout
```c
void cgit_print_layout_start(void);
void cgit_print_layout_end(void);
```
These wrap the page content, calling `cgit_print_http_headers()`,
`cgit_print_docstart()`, `cgit_print_pageheader()`, etc. Commands with
`want_layout=1` have their output wrapped in this skeleton.
## Repository Navigation
```c
void cgit_print_repoheader(void);
```
For each page within a repository, renders:
- Repository name and description
- Navigation tabs: summary, refs, log, tree, commit, diff, stats
- Clone URLs
- Badges
## Link Functions
`ui-shared.c` provides numerous helper functions for generating
context-aware links:
```c
void cgit_summary_link(const char *name, const char *title,
const char *class, const char *head);
void cgit_tag_link(const char *name, const char *title,
const char *class, const char *tag);
void cgit_tree_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path);
void cgit_log_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path,
int ofs, const char *grep, const char *pattern,
int showmsg, int follow);
void cgit_commit_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path);
void cgit_patch_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path);
void cgit_refs_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path);
void cgit_diff_link(const char *name, const char *title,
const char *class, const char *head,
const char *new_rev, const char *old_rev,
const char *path, int toggle_hierarchical_threading);
void cgit_stats_link(const char *name, const char *title,
const char *class, const char *head,
const char *path);
void cgit_plain_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path);
void cgit_blame_link(const char *name, const char *title,
const char *class, const char *head,
const char *rev, const char *path);
void cgit_object_link(struct object *obj);
void cgit_submodule_link(const char *name, const char *path,
const char *commit);
```
Each function builds a complete `` tag with the appropriate URL, including
all required query parameters for the target page.
## Diff Output Helpers
```c
void cgit_print_diff_hunk_header(int oldofs, int oldcnt,
int newofs, int newcnt, const char *func);
void cgit_print_diff_line_prefix(int type);
```
These render diff hunks with proper CSS classes for syntax coloring (`.add`,
`.del`, `.hunk`).
## Error Pages
```c
void cgit_print_error(const char *msg);
void cgit_print_error_page(int code, const char *msg, const char *fmt, ...);
```
`cgit_print_error_page()` sets the HTTP status code and wraps the error
message in a full page layout.
## Encoding
All text output assumes UTF-8. The `Content-Type` header is always
`charset=utf-8`. There is no character set conversion.