code wiki / (root) / nx_rss.nx

nx_rss.nx source

↩ module page · 81 lines · 2942 B

1// rss.nx -- RSS 2.0 feed builder. 2// 3// Emits valid RSS 2.0 XML (specification: Harvard Berkman Center, 4// 2009). Every feed reader, podcast app, news aggregator, and 5// many static site generators consume RSS. nishi-pages without 6// RSS is half a blog engine. 7// 8// Feed skeleton: 9// <?xml version=\"1.0\" encoding=\"utf-8\"?> 10// <rss version=\"2.0\"> 11// <channel> 12// <title>...</title> 13// <link>...</link> 14// <description>...</description> 15// <language>en</language> 16// <pubDate>Wed, 22 Apr 2026 12:34:56 GMT</pubDate> 17// <item> 18// <title>...</title> 19// <link>...</link> 20// <description>...</description> 21// <pubDate>...</pubDate> 22// <guid>...</guid> 23// </item> 24// ... 25// </channel> 26// </rss> 27// 28// All dates use IMF-fixdate (http_date.nx). Text content is 29// HTML-escaped (html_escape.nx) so the feed can contain '<', 30// '>', '&' safely. 31// 32// This is a stream-builder: caller walks their posts and calls 33// rss_item for each; we don't own the post list. All output 34// appends to a caller-owned buffer with bounds checking. 35// 36// Invariants: 37// R1 Order matters: rss_begin -> rss_item* -> rss_end. 38// R2 Caller supplies HTML-unsafe text; we escape internally. 39// R3 All dates are unix seconds converted to GMT fixdate. 40// R4 Description can contain HTML; we wrap it in CDATA rather 41// than escaping, matching WordPress / Ghost convention. 42// (strict RSS says escape, but CDATA is universally 43// accepted and preserves readability.) 44 45// nx_safety_envelope: 46// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 47// sil_target: SIL1 48// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 49// verdict: NOT_YET_EVALUATED 50 51// 2026-09-16: the builder lives in nx_rss_lib.nx (importable); this file keeps the compile-only smoke main. 52import "nx_rss_lib.nx" 53const RSS_MAGIC_1777000000: i64 = 1777000000 54 55func main() -> i64 { 56 let out: *u8 = sys_mmap(RSS_MAGIC_4096) 57 var off: i64 = 0 58 off = rss_begin(out, RSS_MAGIC_4096, off, 59 "Nishi Blog", 10, 60 "https://nishifamily.com/blog", 28, 61 "Greenfield sovereign computing notes", 36, 62 RSS_MAGIC_1777000000) 63 if off < 0 { return 1 } 64 65 off = rss_item(out, RSS_MAGIC_4096, off, 66 "First post", 10, 67 "https://nishifamily.com/blog/1", 30, 68 "<p>Hello & welcome</p>", 22, 69 "https://nishifamily.com/blog/1", 30, 70 RSS_MAGIC_1777000000) 71 if off < 0 { return 2 } 72 73 off = rss_end(out, RSS_MAGIC_4096, off) 74 if off < 0 { return 3 } 75 76 // Sanity: first 5 bytes are \"<?xml\". 77 if out[0] != 0x3C { return 4 } // '<' 78 if out[1] != 0x3F { return 5 } // '?' 79 if out[2] != 0x78 { return 6 } // 'x' 80 return 0 81}