Primitivas de entrada/salida de TeX

Primitivas de entrada/salida de TeX

Me gustaría escribir algunas macros simples para manejar cosas como referencias cruzadas, para usarlas en TeX simple. (Sé que ya hay macros dedicadas a esto, como las presentes en Eplain, pero me gustaría probar algo diferente por mi cuenta). Entonces necesito saber cómo leer de un archivo y cómo escribir en un archivo. ¿Cuáles son las primitivas TeX que hacen tales cosas? ¿Cómo trabajan?

Otra pregunta: ¿Puede TeX 'llamar' a otros programas mientras se está ejecutando? Quiero decir: ¿existe en TeX un equivalente a la función del sistema presente en el lenguaje C?

Respuesta1

TeX tiene las primitivas \ready \writepara leer y escribir en archivos y, por supuesto, \inputpara ingresar un archivo completo "aquí". Si nos fijamos, por ejemplo, se utiliza el mecanismo de referencia cruzada de LaTeX, \writepero se evita su uso \read(línea por línea) en favor de su uso \inputcon archivos secundarios diseñados adecuadamente.

Como \inputes bastante fácil de entender, centrémonos en \ready \write. Ambos funcionan en una secuencia de archivos, a la que se le asigna un número pero que generalmente se asigna mediante \new.... Por ejemplo

\newread\myread
\openin\myread=myinput %

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

configurará una lectura llamada \myready una escritura llamada \mywrite. Tenga en cuenta que lo he usado \immediatecon \write: debido a la naturaleza asincrónica del creador de páginas TeX, debe asegurarse de que \writelas operaciones se realicen en el lugar "correcto". (Más sobre esto a continuación).

Con dos flujos abiertos podemos, por ejemplo, escribir en la salida. Si hacemos dos escrituras, una 'ahora' y otra 'retrasada'

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

el resultado es myoutput.texleer

a
b

Esto se debe a que \write\mywriteproduce un whatsit que solo se ejecuta cuando se envía una página. Esto es útil si, por ejemplo, lo que necesita escribir contiene un número de página, ya que solo se conoce durante la etapa de salida. También observe que \writeactúa como \edef: todo se expande a menos que impida que use \noexpando a toks. Sin embargo, tenga en cuenta que esta expansión se realiza en el momento en que la \writeoperación realmente se ejecuta, por lo que debe asegurarse de que las macros tengan definiciones adecuadas cuando se utiliza un retardado \write.

La \readprimitiva lee una línea a la vez (a menos que las llaves no coincidan) y tokeniza en la forma normal de TeX. Puede hacer arreglos para recorrer un archivo una línea a la vez usando la \ifeofprueba en \myread, pero como digo, a menudo es más fácil simplemente \inputun archivo que contiene referencias cruzadas.

Si desea realizar una llamada al sistema, TeX 'puro' realmente no ayuda. Sin embargo, Web2c tiene desde hace mucho tiempo un 'flujo' especial para permitir el escape al sistema: \write18. Esto supone un riesgo para la seguridad y, por lo tanto, de forma estándar sólo se permite un conjunto restringido de comandos en dicho escape. Puedes hacer por ejemplo

pdftex --shell-escape myfile

para permitir que todos escapen: ¡el riesgo si usted mismo ha escrito todo el código es solo cometer un error! Hacer a \write18no envía nada a TeX: necesitarás hacer arreglos para leer el resultado de alguna manera, probablemente usándolo \readen un archivo secundario.

Como se indicó en un comentario, una extensión de sintaxis adicional disponible es \input|"<command>". Esto nuevamente está restringido por, \write18pero proporciona un método expandible para obtener información de los comandos del shell.

Respuesta2

Otra cuestión especial cuando se trata de referencias cruzadas a través de un archivo externo es el orden de lectura, apertura, escritura y cierre de este archivo. El esquema básico es:

\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

El esquema anterior muestra que necesita crear una macro que lea el archivo solo \inputcuando este archivo exista. Puede utilizar la siguiente \softinputmacro para tales fines:

\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}

información relacionada