groffとmandocで異なる!mdoc(7)で".Dd"にアメリカ式日付以外を与えたときの動作

# TLDR
- groffはマクロのソースコードからして、本当にアメリカ式の日付の表記しか受けつけてくれない!他には`$Mdocdate: ... $`形式にアメリカ式の日付!
  - 最後の`$`はそれ一文字とする。前の引数と分ける。
- mandocは柔軟!何でも受け付ける!
- と言いながらも両者のmdoc(7)のマニュアルからして使用が推奨される形式で、かつ両者で使える形式はこれしかなさげかも：
  - (CVSなどで管理するわけじゃない場合)`.Dd <月名を英語で> <日>, <年(4桁)>`(引数3つ)(コンマを入れよう)
  - (CVSなどで管理する場合)groffとの共存は諦めてmandocだけを使うべきかもしれない(第二版編集時点での編集)

# 使用環境
Arch GNU/Linux。yayを用いてgroffとmandocを入手。それぞれのバージョンは次のとおりである。

```terminal
$ yay -Q groff mandoc-noconflict 
groff 1.22.4-7
mandoc-noconflict 1.14.6-1
```

# 何をした
次のmdoc(7)でのマニュアルファイルがあるとする。
```one.mdoc
.Dd January 7, 2023
.Sh NAME
.Nm foo
.Nd bar
```

これは、日付と名前節と最低限の名前と最低限の説明のみからなるファイルである。
その内の1行目の`.Dd`マクロに与える引数を次のように書き替えてその結果を次のようなファイル名に置き換える。

|`.Dd`|ファイル名|
|:--|:--:|
Dd January 7, 2023`|one.mdoc|
|`.Dd WHAT WHAT`|two.mdoc|
|`.Dd`|three.mdoc|

最初の形式のみがアメリカ式の日付である。二つ目は単に引数を二つ与えただけ。三つ目は最早引数なし。

# 結果
結論からして、mandocは`.Dd`に与えた通りにレンダリングされた。一方でgroffは与えられた引数が正しい書式でないと今日の日付が表示されたり、引数なしでは`Epoch`と出るだけだったりした。

```terminal
$ for x in one.mdoc two.mdoc three.mdoc ; do
> echo "$x .Dd"; grep -F '.Dd' "$x" # 元のファイルの記載内容を表示
> echo "$x nroff"; nroff -mdoc "$x" | tail -1 # nroffでレンダリングして日付部分を取得
> echo "$x mandoc"; mandoc "$x" | tail -1 # mandocでレンダリングして日付部分を取得
> done
one.mdoc .Dd
.Dd January 7, 2023
one.mdoc nroff
                                January 7, 2023
one.mdoc mandoc
                                January 7, 2023
two.mdoc .Dd
.Dd WHAT WHAT
two.mdoc nroff
                                January 7, 2023
two.mdoc mandoc
                                   WHAT WHAT
three.mdoc .Dd
.Dd
three.mdoc nroff
                                     Epoch
three.mdoc mandoc

```

# マニュアルを読んでみた。
`.Dd`マクロの説明を読んでみた。

## man 7 groff_mdoc
groff側のmdoc(7)から引用。但しコードスパンにより模倣。

> If ‘`Dd`’ has no arguments, ‘`Epoch`’ is used for the date string. If it has exactly three arguments, they are concatenated, separated with unbreakable space:
> `.Dd January 25, 2001`
> The month's name shall not be abbreviated.
> With any other number of arguments, the current date is used, ignoring the parameters.
> As a special exception, the format
> `.Dd $Mdocdate:` ⟨month⟩ ⟨day⟩ ⟨year⟩ `$`
> is also recognized. It is used in OpenBSD manuals to automatically insert the current date when committing.
> This macro is neither callable nor parsed.

訳して要約すると、

- 引数なしだと`Epoch`と表示。
- 引数が3つあればそれぞれを分割不能な空白で結合。
- 月名は略さずに書くこと。
- 引数の数がそれ以外であれば引数を無視して今日の日付を使用する。
- 例外としてOpenBSDのマニュアル用に`$Mdocdate:`等の引数も受け付ける。
  - その際第二引数から順に月名、日、年を与えること。(第五引数は`$`)

とにかく、形式がガッチリしている。

## man 7 mandoc_mdoc
次はmandoc側のmdoc(7)のマニュアルから`.Dd`の説明を引用する。

> The *month* is the full English month name, the *day* is an integer number, and the *year* is the full four-digit year.
> 
> Other arguments are not portable; the mandoc(1) utility handles them as follows:
> 
> - To have the date automatically filled in by the OpenBSD version of cvs(1), the special string “`$Mdocdate$`” can be given as an argument.
> - The traditional, purely numeric man(7) format *year*–*month*–*day* is accepted, too.
> - If a date string cannot be parsed, it is used verbatim.
> - If no date string is given, the current date is used.

要約すると、

- 可搬性のある引数は第一引数から順に*month*,*day*,*year*を入れること。
- それ以外は可搬性がない。その場合mandoc(1)が処理する内容は次の通り：
  - cvs(1)向けに`$Mdocdate$`を引数に与えることが可能
  - 古のman(7)フォーマットである*year*-*month*-*day*も可
  - 日付としてパーズできなければ与えられた引数の通りに出力
  - 引数なしの場合は今日の日付を表示

柔軟性はあるということは分かった。といっても、groff側にも対応させたければ引数3つを、ということになる。

# まとめ
groffでもmandocでも使いたければ`.Dd <month> <day> <year>`を使おう、ということになってるっぽい。
~~mdoc(7)の標準という概念がまだ定まっていないからなんだろうかね。~~

## 愚痴
じゃあCVS使ってる人とgit使ってる人とあとなんか知らんバージョン管理システム使ってる人の間でどうやりとりするんだ？

# 参考文献
1. ["Why does this man page have today's date?"に対するStéphane Chazelasの回答](https://unix.stackexchange.com/a/432252)。Unix & Linux Stack Exchangeより。質問日2018年3月15日、回答日3月20日、回答の最終編集日3月21日。
4. [man 7 groff_mdoc](https://man.archlinux.org/man/groff_mdoc.7) Arch manual pages。core/groff 1.22.4-7添付のもの。2022年1月13日参照。
5. [man 7 mandoc_mdoc](https://man.archlinux.org/man/mandoc_mdoc.7) Arch manual pages。community/mandoc 1.14.6-1添付のもの。2022年1月13日参照。