texjporg / platex

pLaTeX community edition
BSD 3-Clause "New" or "Revised" License
49 stars 8 forks source link

Non-ASCII symbols in labels #86

Closed aminophen closed 5 years ago

aminophen commented 5 years ago

多分「pLaTeX は inputenc UTF-8 に非対応」の一環なのでしょうが,一応 latex3/latex2e#95 に関連した件です。以下のソースを考えます。

\documentclass{article}
\usepackage{textcomp}
\begin{document}

\section{A}
\label{abß}
\label{öfoo}

\label{bar€}

Some refs: \ref{abß} and \ref{öfoo} and \ref{bar€}

\fontencoding{T1}\selectfont

Some refs: \ref{abß} and \ref{öfoo} and \ref{bar€}

\end{document}

その結果,新しい LaTeX2e なら pdflatex でエラーなく通るようになります。

ところが,platex と uplatex の挙動が不思議です。(内部コード EUC で試しています)

TL2020 の e-pTeX には \ifincsname があるのに,やはりエラーになるのはなぜでしょうか。

h-kitagawa commented 5 years ago

platex ではやはり ! Missing \endcsname inserted. エラー???

調べ方が悪いのかもしれませんが,手元では再現しませんでした.なぜだろう. バイナリ名を platex, uplatex にすると再現しました.

[追記] PC を変えてビルドしてみると再現しなくなりました.よくわからない……. [追記**2] PTEX_IN_FILTER/usr/bin/nkf -w なのが再現しない原因でした.

h-kitagawa commented 5 years ago

とりあえず platex で処理した場合の aux ファイルを見ると

\relax
\@writefile{toc}{\contentsline {section}{\numberline {1}A}{1}\protected@file@percent }
\newlabel{ab<C3>^^9f}{{1}{1}}
\newlabel{旦foo}{{1}{1}}
\newlabel{bar<E2>^^82<AC>}{{1}{1}}

となっていました(<C3> は less によるもので,本来は 0xC3 という 1 バイト.他も同じ). ö に化けているのは texjporg/tex-jp-build#81 によるものだと思います.

また,\end{document} の直前に \loggingall を入れて調べてみると,

\newlabel ->\@newl@bel r

\@newl@bel #1#2#3->\def \reserved@a {#3}\expandafter \ifx \csname #1@#2\endcsna
me \reserved@a \else \@tempswatrue \fi
#1<-r
#2<-ab^@^^9f
#3<-{1}{1}

となっているのを見つけました.^@ は(これまた less によるもので) 0x00 ですが,0xC3 がなぜこのように変わったかは気になります.

h-kitagawa commented 5 years ago

どうやらエラーは \end{document} の中で aux ファイルを読み込んだ時に,ab<C3>^^9fab<A2AF>^^9f と ptexenc によって変換されていることが原因のようです.


なぜ単独の <C3> が和文文字の 0xA2AF に変換されているかを追ってみました.

  1. (おそらく input_line2 から) get_utf8 が第一引数 i が 0xC3 の状態で呼ばれる
  2. 最初の switch 文において,UTF8length(i) は 2 なので,i2 = getcUTF8(fp); に進む
  3. i2 は EOF のまま(追っていませんが,たぶん次の文字が ^ と UTF-8 の 2 バイト以上の文字に現れないため)なので,そのまま break
  4. u=0(初期値)の状態で j = toBUFF(fromUCS(u)); が呼ばれ,ここでj=0xA2Af となる

\loggingall などで出力する祭の状況はあまり見ていませんが,おそらく 0xA2AF を出力しようとして,ptexenc で ^@ に変換されているのでしょう.


ptexenc.c に次のパッチを当てればエラーは出ないようです.

@@ -673,7 +673,8 @@ static void get_utf8(int i, FILE *fp)
         break;
     }

-    j = toBUFF(fromUCS(u));
+    j = (u != 0) ? toBUFF(fromUCS(u)) : 0;
+    // fprintf(stderr, "<%4X:%4X:%4X>",j,u,fromUCS(u));
     if (j == 0) { /* can't represent (typically umlaut o in EUC) */
         write_hex(i);
         if (i2 != EOF) write_hex(i2);
aminophen commented 5 years ago

ありがとうございます。確かにおっしゃる変更で通りました。

ptexenc.c の中で j = toBUFF(fromUCS(u)); は L.676 だけでなく L.975 にもあるのが気になりましたが,こちらは大丈夫なのでしょうか。

h-kitagawa commented 5 years ago

ptexenc.c の中で j = toBUFF(fromUCS(u)); は L.676 だけでなく L.975 にもある

見落としていました.ptenc_from_utf8_string_to_internal_enc はコマンドラインからの入力を変換する関数のようですね.よくわかりませんが,添付した ptexenc.c.diff.txt のようにすれば良さそう?

h-kitagawa commented 5 years ago

添付した ptexenc.c.diff.txt のようにすれば良さそう?

ptenc_from_utf8_string_to_internal_enc の中で次のようにしないとうまくいきませんね.失礼しました.

-if (last+4>=len) buffer = xrealloc(buffer, len=last+64);
+if (last+16>=len) buffer = xrealloc(buffer, len=last+64);
+ /* 最大で "^^xx" 型 * 4 が buffer に出力されるため */
aminophen commented 5 years ago

https://github.com/texjporg/tex-jp-build/pull/90 を r52071 でコミットしたので,冒頭のソースが「新しい LaTeX2e + TL2020 の e-(u)pTeX」で通るようになりました。ひとまず完了とします。