☰
curl 项目 curldown 文档格式详解:从 Markdown 式源码到 nroff 手册页的自动化管线
2026/10/16 21:26:45 网站建设 项目流程

curl 项目 curldown 文档格式详解:从 Markdown 式源码到 nroff 手册页的自动化管线

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

curldown 是 curl 项目中用于编写 libcurl 手册页(man pages)的一种 Markdown 风格文本格式,它在 docs/CURLDOWN.md 中被完整定义。本文以该文档为主线,结合仓库内 scripts/cd2nroff、scripts/nroff2cd、scripts/cd2cd、scripts/cdall 四个 Perl 转换脚本的源码实现,系统讲解 curldown 的语法规范、元数据约束、转换工具链与已知边界,帮助文档贡献者快速上手并为已有 nroff 手册页的维护提供可复用的工程思路。

一、为什么需要 curldown:设计初衷与目标

curl 的历史文档长期以 nroff 格式(groff排版语言)维护,这种格式对普通贡献者极不友好,容易写错宏命令、难以阅读源码。curldown 的出现正是为了解决这一系列痛点,其目标可以归纳为:

  • 降低贡献门槛:采用人们熟悉的 Markdown 式语法书写 libcurl 文档,让贡献者"所见即所得",不再需要学习 nroff 宏;
  • 减少语法错误:通过受限的、结构化的语法,从源头上抑制拼写与排版错误;
  • 保持输出一致:借助脚本自动生成 nroff 手册页,生成结果与历史手工编写的 nroff 文件几乎逐字节一致,从而让既有的测试用例、HTML 转换流程(如roffit)和网站基础设施基本不受影响;
  • 便于修复历史问题:nroff 由程序统一生成后,诸如"转义连字符-防止 man 渲染为 Unicode 破折号"这类问题只需在生成器里修一次,即可全量生效;
  • 携带结构化元数据:每个文件头部包含结构化字段(如 See-also 关联信息、协议范围、引入版本),为生成更高质量的 nroff 输出(如自动生成 SEE ALSO、PROTOCOLS、AVAILABILITY 段落)和让工具链"知道这个文件讲什么"提供了基础。

从 scripts/cd2nroff 的实现可以看出,生成器对每一条输出规则都做了精细控制:例如-会被转义为\-、单引号转为\(aq、行首的句点会被\&转义(见 scripts/cd2nroff 中quoted函数与正文处理分支),这正是"修复 nroff 历史问题"目标的具体落地。

二、文件扩展名与目录组织

由于 curldown 的书写观感与 Markdown 高度相似,项目统一使用.md扩展名。仓库中的文档分布情况为:

  • 命令行工具手册:docs/cmdline-opts/*.md(如 alt-svc.md、aws-sigv4.md),包含以_开头的章节碎片文件(如 _NAME.md);
  • libcurl 函数手册:docs/libcurl/*.md(如 curl_easy_setopt.md、curl_easy_perform.md);
  • 选项手册:docs/libcurl/opt/目录下的CURLOPT_*.md。

各目录的编译清单统一维护在Makefile.inc中,例如 docs/cmdline-opts/Makefile.inc 同时被Makefile.am与CMakeLists.txt共享,保证 autotools 与 CMake 两套构建系统使用同一份文件列表。

三、curldown 与 nroff 的双向转换工具链

文档定义了三类转换工具,全部为 Perl 脚本,位于 scripts/ 目录:

工具方向用途源码位置
cd2nroffcurldown → nroff生成最终 man page,是日常发布用主工具scripts/cd2nroff
nroff2cdnroff → curldown仅用于历史文档的一次性初始迁移,理想情况下不再需要scripts/nroff2cd
cd2cdcurldown → curldown对现有 curldown 做规范化、清理、检查scripts/cd2cd
cdall批量转换对指定目录下所有 curldown 批量调用cd2nroff生成.3手册页scripts/cdall

3.1 cd2nroff:主生成器

cd2nroff支持的命令行选项:

Usage: cd2nroff [options] [file.md] -d <dir> 将输出写到该目录下、以元数据 Title 命名的文件,而不是 stdout -e <ext> 配合 -d 使用时,向输出文件名追加任意扩展名文本 -h 显示帮助 -v 显示版本号后退出

不指定-d时输出到标准输出,方便管道处理。日期通过SOURCE_DATE_EPOCH环境变量(若设置)或本地时间生成,并格式化为YYYY-MM-DD写入.TH宏(见 scripts/cd2nroff)。

值得注意的实现细节:

  • 头校验严格:解析头部时若缺少Title:、Section:、Source:、See-also:、C:(版权)、SPDX-License-Identifier:任一字段即报错退出;Source: libcurl的手册页还必须提供Added-in:,且版本号必须匹配^[0-9.]+[0-9]$或为n/a(见 scripts/cd2nroff 头部校验段);
  • 协议白名单:内置%knownprotos哈希表校验Protocol:列表,包含全部 URL scheme(DICT、FILE、FTP、FTPS、GOPHER、GOPHERS、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、MQTT、POP3、POP3S、RTSP、SCP、SFTP、SMB、SMBS、SMTP、SMTPS、TELNET、TFTP、WS、WSS)以及特殊值TLS、TCP、QUIC、All;
  • 自动生成段落:遇到# %PROTOCOLS%时调用outprotocols根据元数据生成 PROTOCOLS 段落(TLS会被展开为 "all TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.");遇到# %AVAILABILITY%时调用 AVAILABILITY 生成 "Added in curl x.y.z";文件末尾自动追加按字母序排列的 SEE ALSO 段落(见 scripts/cd2nroff 中outseealso、outprotocols、outtls三个子程序);
  • 正文质量检查:未转义的<或>、行内连续两个空格都会触发报错并累计$errors,最终以非零状态返回,充当 lint 角色。

3.2 nroff2cd:一次性迁移工具

nroff2cd负责把历史 nroff 手册页转换为 curldown。它解析.TH宏提取 Title/Section/Source 生成头部,将.SH转为#、.IP转为##、.B/\fB转为**、.I/\fI转为*,.nf代码区转为~~~c引块,并收集.BR中的 SEE ALSO 条目排序输出。该工具的设计定位是"仅用于最初的历史转换,理想情况下永不再用"(见 scripts/nroff2cd 头部注释)。

3.3 cd2cd:规范化与清理

cd2cd读取一个 curldown 文件,重写头部(保持 Title/Section/Source 不变,按字母序重新整理See-also:列表),并清理正文:

  • 去掉*curl_symbol(3)*这类包裹 curl 符号的多余星号(因为符号会被自动转为斜体);
  • 压缩连续空行(最多保留一个);
  • 对超过 90 字符的行发出 WARN 提示(见 scripts/cd2cd)。

用法:

cd2cd <file.md> # 规范化结果输出到 stdout cd2cd --in-place <file.md> # 原地覆盖;该模式下可一次传入多个文件,并忽略单个文件的错误

3.4 cdall:批量转换

cdall接收一个或多个目录参数,遍历每个目录下所有.md文件,逐个调用./scripts/cd2nroff -d <dir> <file.md>生成同名.3手册页:

cdall [dir1] [dir2] [dir3] ..

从源码看,它把.md后缀替换为.3作为输出文件名(见 scripts/cdall),适用于构建流程中的批量文档生成。

四、curldown 格式规范详解

4.1 头部元数据(Front Matter)

每个 curldown 文件必须以---包围的头部开始,示例如下(取自 docs/CURLDOWN.md):

--- c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. SPDX-License-Identifier: curl Title: CURLOPT_AWS_SIGV4 Section: 3 Source: libcurl Protocol: - HTTP See-also: - CURLOPT_HEADEROPT (3) - CURLOPT_HTTPAUTH (3) TLS-backend: - [name] Added-in: [version or "n/a"] ---

强制约束:

  • 所有字段必须齐全,且至少要有一条See-also:条目;
  • Title:将决定-d模式下的输出文件名($dir/$title.$section,见 scripts/cd2nroff);
  • Section: 3(库函数手册)时,Protocol:列表至少包含一个协议,可用*表示"几乎适用于一切",此时*必须是唯一列出的协议;识别的协议为 URL scheme 的大写形式,或特殊值TLS、TCP;
  • 若Protocol:中包含TLS,则必须同时提供TLS-backend:列表,取值为All或以下后端之一(依据 docs/CURLDOWN.md 及 scripts/cd2nroff 中%knowntls白名单):
TLS 后端说明
GnuTLSGnuTLS 后端
mbedTLSmbedTLS 后端
OpenSSL同时涵盖 AmiSSL、AWS-LC、BoringSSL、LibreSSL 与 quictls
rustlsRust 实现的 rustls 后端
SchannelWindows 原生 Schannel 后端
wolfSSLwolfSSL 后端
All全部 TLS 后端

实际库函数手册中可以对照真实文件观察这些字段的写法,例如 curl_easy_cleanup.md 的Added-in: 7.1、curl_easy_option_by_id.md 的Added-in: 7.73.0,命令行动态选项文件则使用Added:字段记录引入版本(如 aws-sigv4.md 中的Added: 7.75.0)。

4.2 正文排版语法

头部之后是正文,采用 Markdown 风格语法(示例来自 docs/CURLDOWN.md):

# NAME a page - this is a page describing something # SYNOPSIS ~~~c #include <curl/curl.h> CURLcode curl_easy_setopt(CURL *handle, CURLOPT_AWS_SIGV4, char *param); ~~~
  • 代码块:以~~~c开始、~~~结束,生成 nroff 的.nf段落;普通引用块可用~~~或 4 空格缩进(缩进块在 scripts/cd2nroff 中以quote == 4状态处理,同样输出.nf/.fi);
  • 标题:一级标题#转换为.SH;二级标题##转换为.IP(nroff2cd同样支持反向转换);含空格或无引号的标题在 scripts/cd2nroff 中会按是否需要加双引号分别处理;
  • 加粗:**bold**;
  • 斜体:*italics*;
  • 反引号:由于 man 不支持反引号排版,源码中的`word`在生成的 nroff 中以斜体呈现;
  • 空行:生成时多余的空行会被工具自动剔除,因此源码中可以自由使用空行提升可读性;
  • 尖括号转义:为保证 curldown 也能在普通 Markdown 渲染器中正确显示,所有字面量<、>必须用反斜杠转义为\<、\>;scripts/cd2nroff 会对未转义尖括号报错,再将其还原为字面字符输出;
  • 行首点号与引号:生成 nroff 时行首的.与'会被转义(quoted子程序),正文行首的.也会被\&保护,避免与 groff 宏混淆。

4.3 内容占位符:自动生成段落

  • # %PROTOCOLS%:根据头部Protocol:元数据自动插入 PROTOCOLS 段落;
  • # %AVAILABILITY%:根据头部Added-in:元数据自动插入 AVAILABILITY 段落(值为n/a时跳过)。

对应实现见 scripts/cd2nroff:outprotocols会生成 "This functionality affects ..." 的协议描述,若协议仅有一个且为All则输出 " supported protocols"、单个普通协议则追加 " only";outtls则根据TLS-backend:生成 "All TLS backends support this option." 或 "This option works only with the following TLS backends: ..." 等文案。若源码中直接书写了PROTOCOLS或AVAILABILITY标题,工具会打印 WARN 提示应使用占位符。

4.4 符号自动链接(Symbols)

所有拥有独立手册页的 curl 符号,如curl_easy_perform(3),无需手工加星号即可在输出中自动渲染为斜体。这一机制确保后续经roffit转 HTML 时这些符号能正确转为链接,同时让正文在提到大量符号时依然易读。

自动链接的匹配模式为:

(lib|)curl[^ ]*(3)

即匹配curl...或libcurl...且以(3)结尾的令牌。相关实现可见 scripts/cd2nroff 中正则s/((lib|)curl([^ ]*\(3\)))/\fI$1\fP/gi,而 scripts/cd2cd 则会反向移除这些符号上多余的手工星号*curl_symbol(3)*,保证两种书写方式殊途同归。

五、已知限制与注意事项

依据 docs/CURLDOWN.md 的 Known issues 部分:

  1. cd2nroff尚不支持起止标记分处两行的斜体与加粗,因此强调标记必须写在同一行内;
  2. nroff2cd为所有.fi段生成~~~c代码样式引块,因为 nroff 源格式本身不区分代码块与普通引块,迁移后需要人工判断调整;
  3. 头部校验严格且不可省略字段(如See-also:、C:、SPDX-License-Identifier:),新增或迁移手册页时应直接以完整模板起步,避免反复触发 scripts/cd2nroff 的校验报错;
  4. 尖括号必须转义,行内不得出现连续两个空格,行宽建议控制在 90 字符以内(scripts/cd2cd 会对超长行告警)。

六、实践路径:为 curl 文档贡献一页手册

综合以上规范,新增或修改手册页的推荐流程是:

  1. 在对应目录(命令行选项在docs/cmdline-opts/,库函数在docs/libcurl/或docs/libcurl/opt/)创建.md文件,完整填写头部元数据并确保See-also:非空;
  2. 按 4.2 节语法书写正文,#一级标题组织大节、##组织子项,代码用~~~c包裹,字面量尖括号加反斜杠转义;
  3. 用cd2cd做规范化检查:cd2cd file.md查看清理结果,或用--in-place直接原地整理;
  4. 用cd2nroff -d <dir> file.md生成 nroff 验证.SH、.IP、.nf/.fi结构是否符合预期;
  5. 批量场景下用cdall dir1 dir2 ...一次转换整个目录;已有 nroff 的历史页面才需要借助nroff2cd做一次性迁移,随后按 4.2 节人工复核.fi段的代码/引用分类。

整个流程中,docs/CURLDOWN.md 是语法总纲,四个脚本(cd2nroff、nroff2cd、cd2cd、cdall)是落地执行器,二者配合即可在不改动既有 nroff 生态的前提下,用现代、易读、可校验的 Markdown 风格源码持续产出高质量手册页。

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询