Primitivas de entrada/saída do TeX

Primitivas de entrada/saída do TeX

Eu gostaria de escrever algumas macros simples para lidar com coisas como referência cruzada, para usá-las em TeX simples. (Sei que já existem macros dedicadas a isso, como as presentes no Eplain, mas gostaria de tentar algo diferente sozinho.) Portanto, preciso saber como ler um arquivo e como escrever em um arquivo. Quais são as primitivas do TeX que fazem essas coisas? Como eles funcionam?

Outra pergunta: o TeX pode 'chamar' outros programas enquanto está em execução? Quero dizer: existe no TeX um equivalente à função de sistema presente na linguagem C?

Responder1

TeX tem as primitivas \reade \writepara ler e escrever em arquivos e, claro, \inputpara inserir um arquivo inteiro 'aqui'. Se você observar, por exemplo, o mecanismo de referência cruzada do LaTeX é usado, \writemas evita o uso \read(linha por linha) em favor do uso \inputde arquivos secundários projetados adequadamente.

Como \inputé fácil de entender, vamos nos concentrar em \reade \write. Ambos funcionam em um fluxo de arquivos, que recebe um número, mas geralmente é alocado usando \new.... Por exemplo

\newread\myread
\openin\myread=myinput %

\newwrite\mywrite
\immediate\openout\mywrite=myoutput %

configurará uma chamada de leitura \myreade uma chamada de gravação \mywrite. Observe que usei \immediatecom o \write: devido à natureza assíncrona do construtor de páginas TeX, você precisa ter certeza de que as \writeoperações acontecem no local 'correto'. (Mais sobre isso abaixo.)

Com dois fluxos abertos podemos, por exemplo, escrever na saída. Se fizermos duas gravações, uma 'agora' e outra 'atrasada'

\def\foo{a}
\immediate\write\mywrite{\foo}
\write\mywrite{\foo}
\def\foo{b}
Hello
\bye

o resultado é myoutput.texa leitura

a
b

Isso porque \write\mywriteproduz um whatsit que só é executado quando uma página é enviada. Isso é útil se, por exemplo, o que você precisa escrever contiver um número de página, pois isso só é conhecido durante o estágio de saída. Observe também que \writeage como \edef: tudo é expandido, a menos que você evite usar \noexpandou um toks. Observe, entretanto, que esta expansão é realizada no momento em que a \writeoperação é realmente executada, portanto, é necessário garantir que as macros tenham definições adequadas ao usar um arquivo atrasado \write.

A \readprimitiva lê uma linha por vez (a menos que as chaves não correspondam) e tokeniza da maneira normal do TeX. Você pode fazer um loop em um arquivo, uma linha por vez, usando o \ifeofteste on \myread, mas como eu disse, geralmente é mais fácil simplesmente criar \inputum arquivo contendo referências cruzadas.

Se você quiser fazer uma chamada de sistema, o TeX 'puro' realmente não ajuda. No entanto, o Web2c tem há muito tempo um 'stream' especial para permitir a fuga para o sistema: \write18. Este é um risco à segurança e, portanto, como padrão, apenas um conjunto restrito de comandos é permitido nesse tipo de fuga. Você pode fazer por exemplo

pdftex --shell-escape myfile

para permitir todas as fugas: o risco, se você mesmo escreveu todo o código, é apenas cometer uma bagunça! Fazer um \write18não retorna nada ao TeX: você precisará organizar a leitura do resultado de alguma forma, provavelmente usando \readum arquivo secundário.

Conforme observado em um comentário, uma extensão de sintaxe adicional disponível é \input|"<command>". Isso é novamente restrito, \write18mas fornece um método expansível para obter entradas de comandos shell.

Responder2

Outra questão especial ao tratar de referências cruzadas via arquivo externo é a ordem de leitura, abertura, escrita e fechamento deste arquivo. O esquema básico é:

\newwrite\fileout  % allocations of the file number

\def...     ... all macros which can be used in the file must be defined
\input file ... input only when file exists (the file doesn't exist at the first run)
            ... this input stores the data from file into internal macros
\immediate\openout\fileout=file  ... this removes the data from file
                                  ... the file has zero length now

... document ... macros used in the document write (typically not immediately) 
                 data to the file

\end ... this closes the file automatically, 
         but if you need to use the data from the file at the end of the document
         (for example the TOC at the end of the document):
\vfil\eject  
\immediate\closeout\fileout
\input file ... this creates the TOC at the end of the file.
\end

O esquema acima mostra que você precisa criar uma macro que leia o arquivo somente \inputquando este arquivo existir. Você pode usar a seguinte \softinputmacro para tais fins:

\newread\testin
\def\softinput #1 {\let\next=\relax \openin\testin=#1
   \ifeof\testin \message{Warning: the file #1 does not exist}%
   \else \closein\testin \def\next{\input #1 }\fi
   \next}

informação relacionada