カテゴリー別アーカイブ: TeX

TeX, LaTeX 関連の記事

LuaTeX における外部コマンド実行とログ出力

前置き

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 で外部コマンド実行の際にログファイルにコマンドを吐き出すようにするには、

  • \write18 の代替となるコマンドで、ログを出力するようにする
  • LuaTeX の os.execute を乗っ取って、ログ出力も行うようにする

という手段が考えられる。(LuaTeX 本体の os.execute の定義を書き換えるのは、ハードルが高そうなので考えないことにする)

\write18 の代替となるコマンドでの対処

pdftexcmds パッケージの \pdf@system コマンドは、既に、実行時に

system(ほにゃらら) executed.

というメッセージを出力するようになっている。微妙に書式が違うが、まあ十分だろう。

一方で、 shellesc パッケージが提供する \write18 および \ShellEscape, \DelayedShellEscape コマンドは、実行するコマンドを書き出すという処理は特に行なっていない。

以前書いたような外部コマンドを実行する LaTeX パッケージのうち、 epstopdf パッケージは pdftexcmds パッケージの \pdf@system コマンドを使うので、ログファイルを調べることで実行されたコマンドを取得することができる。

epstopdf 以外の外部コマンドを実行する LaTeX パッケージは、基本的に「shellesc パッケージを読み込みつつ、従来通り \immediate\write18 を使用」していると思われるので、実行されたコマンド文字列をログファイルから取得する手段がない。

外部コマンドを実行するパッケージが、 shellesc パッケージに頼らずに直接 \directlua していた場合も同様である。

os.execute を乗っ取る

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 以外にもいくつか存在するが、見なかったことにする。どうせ使われてないよね…?)

余談: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 における日付と時刻

LaTeX 文書中に \today と書くと latex コマンドを実行した日付が出てくる。このことから分かるように、 TeX 文書中では何らかの形で現在時刻を取得できる。では実際のところ、時刻に関してどの程度の情報を取得できるのか。また、 TeX 文書に与えられる「現在時刻」を変更することはできるだろうか。 続きを読む

LaTeX 文書から処理系を推定する(主に日本語)

前回の記事では、 LaTeX 文書にマジックコメントとして処理系やメインファイルを記述するやり方について書いた。今回は、マジックコメントがない場合に処理系を推定する方法について考える。

LaTeX 文書の処理系(エンジン)には色々あるが、このブログの読者が使うのは次の6種類のうちのどれかだろう(最近はデフォルトで e-TeX 拡張が使えるみたいなのでその辺の細かい区別は必要ない)

  • pdfLaTeX
  • XeLaTeX
  • LuaLaTeX
  • LaTeX + dviware (e.g. dvipdfmx)
  • pLaTeX + dviware (e.g. dvipdfmx)
  • upLaTeX + dviware (e.g. dvipdfmx)

(この他に、最近は pTeX-ng なる代物もあるらしいが、筆者はよく知らないのでこの記事では無視する)

日本語の場合は、文書が特定の処理系専用になることが多く、ドキュメントクラス等を調べることによって判別できる(できてしまう)ことが多い。逆に、欧文の文書を pdfLaTeX, XeLaTeX, LuaLaTeX のどれで処理すべきか判別するのは難しいと思われる(まあ、「どれでも処理できる」のであればデフォルトの処理系で処理するというので問題ないのだが)。

ドキュメントクラスから処理系を判定する

日本語の文書向けのドキュメントクラスは、特定の処理系専用に作られているか、もしくはクラスオプションで処理系を指定するようになっていることが多い。

pLaTeX 用:

  • jarticle, jbook, jreport
  • tarticle, tbook, treport
  • jsarticle, jsbook (without ‘uplatex’ option)

upLaTeX 用:

  • ujarticle, ujbook, ujreport
  • utarticle, utbook, utreport
  • jsarticle, jsbook (with ‘uplatex’ option)

LuaTeX 用 (LuaTeX-ja) :

  • ltjarticle, ltjbook, ltjreport
  • ltjsarticle, ltjsbook
  • ltjtarticle, ltjtbook, ltjtreport

BXjscls:

  • bxjsarticle, bxjsbook, bxjsreport, bxjsslide
  • クラスオプションとして処理系を指定: latex,platex,uplatex,lualatex,xelatex,autodetect-engine のいずれか
  • DVI 出力の場合、クラスオプションとして dviware を指定: dvips,dviout,xdvi,dvipdfmx のいずれか
  • autodetect-engine が使用されていた場合は、文書から処理系を判定することはできない。

もちろん、これらのドキュメントクラス自体の改訂によってこの辺りの仕様が変わる可能性があり、今後もずっとこの判定方法に頼れるとは限らない。(実際、この記事を書いている間に jsclasses に autodetect-engine が実装されてしまった

使うパッケージによって処理系を判定する

日本語文書であっても、例えば Beamer を使う場合は、ドキュメントクラスからエンジンの推定はできない。しかし、そのような場合でも、使うパッケージによってエンジンを判定できる場合がある。

  • minijs, okumacro, jsverb, okuverb, pxjahyper, etc: (u)pTeX 専用
  • luatexja, luatexja-ruby, luatexja-otf, luatexja-preset: LuaTeX 専用
  • xltxtra, xeCJK, zxjatype: XeTeX 専用
    • xltxtra パッケージは fontspec パッケージに取って代わられたようなので、見かけることは少ないかもしれない。
  • fontspec, unicode-math: XeTeX または LuaTeX
  • 以前このブログで言及した filemod パッケージは pdfTeX または LuaTeX を必要とするものだった。(しかし、広く使われているとは思えないので、判定には利用できないだろう)

もっと色々あるだろうが、網羅的に列挙しても仕方がないので、このぐらいにしておく。

ドキュメントクラスと同じく、パッケージについても、仕様の変化や代替パッケージの登場によって、ここに書いた情報が古くなっていく可能性がある。

雑感

このような heuristics はやはり筋が悪い気がしてきたし、確実な動作を望むなら、前回書いたような方法でユーザーが明示的に指定するべきだろう。

それでもこの記事に書いたような方法で処理系の推定を行いたいのであれば、なるべく最新の動向を追いかけるようにしたい。

TeX 文書の Magic Comment

この記事では、 TeX 文書におけるマジックコメントの種類と構文についてまとめてみた。

マジックコメントとは

プログラムのソースコードというのは、プログラミング言語の処理系(実行環境)向けに書かれているものである。しかし、テキストエディターなどの周辺ツールは、そのソースコードについて、処理系が必要とする以上の情報が欲しいことがある。そういう場合に、追加の情報をソースコードのコメントとして記述してやって、周辺ツールに与えてやるということがよく行われる。このようなコメントは、俗に、マジックコメントと呼ばれる。

「追加の情報」の中で典型的なものが、文字コードである。Emacs で編集されるソースコードに -*- coding: utf-8 -*- と書かれたコメントがあるのを見たことがある方も多いだろう。

(ちなみに、 Python や Ruby などの一部のスクリプト言語処理系は、マジックコメントによってファイルの文字コードを判定する場合がある。つまり、コメントとして書かれたものが処理系にとってい意味を持つ。) 続きを読む

LaTeX の数式をターミナルで手軽に MathML に変換する

テキストエディタで HTML 文書を直書きしていて、 MathML で数式を書きたいけど MathML 直書きは嫌だ!という時。Pandoc を使えば、ターミナルで手軽に LaTeX 形式の数式を MathML に変換できる。

例:

$ pandoc -f latex -t html5 --mathml
\(\frac{1}{e^z-1}\)
^D
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mn>1</mn><mrow><msup><mi>e</mi><mi>z</mi></msup><mo>−</mo><mn>1</mn></mrow></mfrac><annotation encoding="application/x-tex">\frac{1}{e^z-1}</annotation></semantics></math></p>

太字の部分が自分で入力する部分である。(^D は Control-D の意)

\newtheorem と \autoref

\newtheorem の基本

LaTeX で数学の文章を書く際には、 \newtheorem コマンドによって定理用の環境(下の例だと theorem という名前)を定義できる。

\newtheorem{theorem}{Theorem} % theorem 環境を定義

\begin{theorem}
  人類は滅亡する。
\end{theorem}

このとき、自動的に定理番号がついて「Theorem 1  人類は滅亡する。」と出力される。

この定理を別の場所で参照したいと思った時は、定理を書くときに

\begin{theorem} \label{thm:very-important-theorem}
  人類は滅亡する。
\end{theorem}

という風にラベルをつけておく。参照するときは「Theorem \ref{thm:very-important-theorem} より」と書けば「Theorem 1 より」という風に自動的に定理番号が出力される。(ただし、定理番号を正しく出力するためには LaTeX を2回実行する必要がある)

\autoref の基本

さて、 hyperref パッケージを使うと、定理番号の部分がハイパーリンクになる。だが、「Theorem 1 より」の「1」の部分だけではなくて、「Theorem」の部分もハイパーリンクにできないものか。

そのために、 hyperref パッケージには \autoref というコマンドが用意されている。 “Theorem \ref{thm:very-important-theorem}” の代わりに “\autoref{thm:very-important-theorem}” と書くと 「Theorem 1」全体がハイパーリンクになる。

ただし、環境の名前(より正確には、カウンターの名前)が “theorem” 以外の場合は、定理番号の前の “Theorem” に相当する文字列を自前で定義してやらねばならない。また、環境(カウンター)の名前が “theorem” であっても、定理番号の前の文字列を ”Theorem” から変えたい場合は自分で上書きする必要がある。

定理番号の前の文字列は、 “\〈環境の名前〉autorefname”(より正確には “\〈カウンターの名前〉autorefname”)という名前のコマンドで定義・上書きできる。

\newtheorem{theorem}{Theorem} % theorem 環境を定義
\renewcommand{\theoremautorefname}{定理} % \theoremautorefname は hyperref によって定義済み。なので「上書き」する
\newtheorem{lemma}{Lemma} % lemma 環境を定義
\newcommand{\lemmaautorefname}{補題}

\begin{theorem} \label{thm:very-important-theorem} % → Theorem 1
  人類は滅亡する。
\end{theorem}

\begin{lemma} \label{lem:very-important-lemma} % → Lemma 1
  第 $n$ 次世界大戦($n\gg 1$)が勃発することは、人類が滅亡する十分条件である。
\end{lemma}

\autoref{thm:very-important-theorem} % → 定理 1
\autoref{lem:very-important-lemma} % → 補題 1

続きを読む