前の記事の続き。アニメ「結城友奈は勇者である」の8話、9話などに登場する、瀬戸大橋記念館(の展望台)に行って来た。 続きを読む

たまたま四国に旅行に行く機会があったので、アニメ「結城友奈は勇者である」の舞台である観音寺市に寄って聖地巡礼をしてきた。
(たまたま四国に行く機会があったから旅程に組み入れただけで、聖地巡礼が目的で四国に行ったわけではない) 続きを読む
C言語にはワイド文字で入出力を行う関数が用意されている。
※ワイド文字:C言語のワイド文字 (wchar_t) とは、不憫な子である。Windows だと Unicode のコードポイント1個すら表せない16ビットだったり、Unix だとそもそも使われている気配があまりなかったり(もっぱら UTF-8 か UTF-16 が使われている印象がある)する。2010年代の後半にもなってワイド文字なんぞを真面目に扱うブログというのは時代錯誤も甚だしい。
ワイド文字で入出力と言っても、対象がファイルの場合は最終的にはバイト列を読み書きしているわけで、どこかの段階でバイト列とワイド文字列との変換が行われているはずである。この変換方法はどうやって決まっているのか。あるいは、ワイド文字の入出力関数とバイト列 (char) の入出力関数を混在させるとどうなるのか。
また、Visual C++ や glibc の場合は fopen の第2引数に ,ccs=UTF-8
みたいな文字列を設定できるという謎の仕様がある。これを指定した場合は何が UTF-8 になるのか。
こういった細かい仕様は、ワイド文字自体がオワコンなこともあり、あまり知られていないように思う。少なくとも筆者は知らなかった。というわけで、
LuaTeX 以前の TeX 処理系では \write18 によって TeX 文書中から外部コマンドを実行できた。しかし、 LuaTeX では Lua の機能 (os.execute) によって外部コマンドの実行ができるため、現在の LuaTeX からは \write18 による外部コマンド実行機能は削除されている。
詳しくは以下のブログ記事を参照されたい:
新しい LuaTeX だって \write18 したい – マクロツイーター
対策 (2) :外部コマンドが実行されない → shellesc パッケージ!
要するに、 shellesc パッケージを使えば \write の定義が書き換えられて、従来の \immediate\write18 がそのまま動く。\ShellEscape, \DelayedShellEscape というコマンドも提供されている。(\immediate なしの \write18 相当のことをするには \write18 そのままではなく \DelayedShellEscape を使う必要がある)
また、pdftexcmds パッケージで提供されている \pdf@system コマンドを使うという手もある。
というわけで、一般の利用者および LaTeX パッケージを書く人にとっては、これらは既に済んだ話である。しかし、TeX の実行を補助するツールを作る人にとっては、話はまだ終わっていない。
従来の \write18 によるコマンド実行の場合は、ログファイルに、実行したコマンドが
runsystem(ほにゃらら)...executed.
という感じで書き出されていた。このような実行ログは、 TeX の実行を補助するツールにおいて役に立つ場合がある。
しかし、LuaTeX における os.execute はログファイルに何も出力しない。これは困る。
LuaTeX で外部コマンド実行の際にログファイルにコマンドを吐き出すようにするには、
という手段が考えられる。(LuaTeX 本体の os.execute の定義を書き換えるのは、ハードルが高そうなので考えないことにする)
pdftexcmds パッケージの \pdf@system コマンドは、既に、実行時に
system(ほにゃらら) executed.
というメッセージを出力するようになっている。微妙に書式が違うが、まあ十分だろう。
一方で、 shellesc パッケージが提供する \write18 および \ShellEscape, \DelayedShellEscape コマンドは、実行するコマンドを書き出すという処理は特に行なっていない。
以前書いたような外部コマンドを実行する LaTeX パッケージのうち、 epstopdf パッケージは pdftexcmds パッケージの \pdf@system コマンドを使うので、ログファイルを調べることで実行されたコマンドを取得することができる。
epstopdf 以外の外部コマンドを実行する LaTeX パッケージは、基本的に「shellesc パッケージを読み込みつつ、従来通り \immediate\write18 を使用」していると思われるので、実行されたコマンド文字列をログファイルから取得する手段がない。
外部コマンドを実行するパッケージが、 shellesc パッケージに頼らずに直接 \directlua していた場合も同様である。
Lua コードによって os.execute の定義を置き換えてしまえば、 shellesc パッケージが使われていようが、直接 \directlua していようが、実行されるコマンド文字列を取得できる。
というわけで、 TeX 文書を処理する際に次のような TeX コードを実行しておけば、既存の TeX エンジンと同様にログファイルに出力してくれる:
\directlua{ local e=os.execute if e then local s=status.shell_escape or e() local function h(c,r,...) if c then texio.write_nl("log","runsystem("..c..")..."..(s==0 and"disabled"or(s==1 and"executed"or(r==nil and"disabled (restricted)"or"executed safely (allowed)")))..".\noexpand\n") end return r,... end function os.execute(c) return h(c,e(c)) end end }
(LuaTeX で外部コマンドを実行する関数は、 os.execute 以外にもいくつか存在するが、見なかったことにする。どうせ使われてないよね…?)
本家 Lua の os.execute の戻り値の仕様は、Lua 5.1 と Lua 5.2 で少し変化している。具体的には、 Lua 5.1 では C の system 関数の戻り値を整数としてそのまま返していたのが、 Lua 5.2 では、(POSIX の場合に)POSIX の仕様に沿って system 関数の戻り値を解釈するようになった。
LuaTeX はと言うと、ベースとなっている Lua のバージョンは 5.2 なのだが、 os.execute 関数の戻り値の仕様は Lua 5.1 当時のままである。
LuaTeX の os.execute 関数は本家 Lua のものではなく、独自に実装されたものなので、使用する Lua を 5.2 にアップグレードする際に変更し忘れたか、あるいは既存の Lua コードの互換性を考えてそのままにしたのだと思われる。
LuaTeX における os.execute 関数の実装は loslibext.c というファイルに入っている。
TeX の実行を自動化するスクリプトというのは latexmk を始めとしてすでに色々世の中に存在するが、新しく作った。 続きを読む
スクリプト言語で書いたプログラムをシェルコマンドとして実行したい時、 Unix の場合は shebang と呼ばれる行を書けば良い。
しかし、 Windows のコマンドインタープリター (cmd.exe) の場合はそういう風にはいかない。代わりに、バッチファイル (.bat) なり、バイナリの実行ファイル (.exe) を用意して、その中でスクリプト言語のインタープリターを呼び出す、という手法を使うことになる。
この場合、配布するファイルがバッチファイルと実行したいスクリプトファイルの2つになり、単独の実行ファイルを配布する場合に比べて2倍面倒である。1つのファイルを、バッチファイルとしてもスクリプトファイルとしても実行できれば良いのではないか。(このような、複数のプログラミング言語で解釈できるプログラムを polyglot と呼ぶことがあるようだ)
今回、対象とするスクリプト言語は Lua である。Lua スクリプトとバッチファイルの双方として実行可能なファイルを作りたい。 続きを読む
LaTeX 文書中に \today と書くと latex コマンドを実行した日付が出てくる。このことから分かるように、 TeX 文書中では何らかの形で現在時刻を取得できる。では実際のところ、時刻に関してどの程度の情報を取得できるのか。また、 TeX 文書に与えられる「現在時刻」を変更することはできるだろうか。 続きを読む