7

I can create a \newwrite like this:

\newwrite\filehandle
\immediate\openout\filehandle=\jobname-semantically_useful_suffix.txt
\immediate\closeout\filehandle

Let's say I have languages stored in a macro: da, de, en, ... Loop each language and store it as \langcode

I need a unique file handle for each language. I would like to have something like this:

\documentclass{article}
\usepackage{fontspec}% xelatex
\usepackage{tikz}% foreach
\usepackage{morewrites}% unnecessary for this example, but useful in practice to exceed 16-write limit in TeX

\def\writelangouts{%
  \foreach \langcode in {da,de,en} {% from tikz package
    \newwrite\filehandle-\langcode
    \immediate\openout\filehandle-\langcode=\jobname-semantically_useful_suffix_\langcode.txt
    \immediate\closeout\filehandle-\langcode
  }%
}%
\AtEndDocument{\writelangouts}

\begin{document}
\jobname
\end{document}% \writelangouts executed here

I would like to have a list of naming conventions for the file handle macros (\newwrite) and file names (\openout=filename).

  1. I assume you cannot use \csname...\endcsname for file handle macros.
  2. I assume file names are dependent upon the local filesystem's naming conventions.

Notes: In reality I am defining sectioning commands (headings) to write their numbers to a macro as to create a toc-like structure for each language. Then I compare each language's output with the Unix utility diff to look for differences. This is particularly useful for cross checking translations.

e.g.

§ 1
  § 1.1
    § 1.1.1
    § 1.1.2
  § 1.2
§ 2
  § 2.1
  § 2.2
  • The usual problem of \foreach doing its job in a group can be of a hindrance. – egreg Aug 5 '16 at 8:56
  • @ChristianHupfer Oh really? I did not know you could do that. What do you mean, "given that \filehandle is defined"? I thought \newwrite is defining it. – Jonathan Komar Aug 5 '16 at 8:56
  • @macmadness86: No, you must construct the sequence name with \csname filehandle-\langcode\endcsname then – user31729 Aug 5 '16 at 8:59
  • are you using hyperref? I think there is an easy way. – touhami Aug 5 '16 at 13:35
  • @touhami At this point, you could provide an addendum with an alternative approach, but the question has been answered definitively. My goal was to learn the limits of \newwrite. – Jonathan Komar Aug 5 '16 at 13:42
10

\newwrite\foo assigns the symbolic name to be equal to a write file register, so anything that is possible with \csname ...\endcsname is also possible with \newwrite or \newread, as well as with \openout,\openin, \closein, \closeout.

\newwrite itself is no TeX primitive but assigns the next free output stream number to a macro name via a \chardef, the same is true for \newread -- both stream directions are independent of each other!

In this sense, a file handle is nothing more than a macro expanding to a number, this way \immediate\write6 etc. would be possible too. (or think of writing to the shell with \immediate\write18 (given that shell-escape is enabled)).

If there's another macro inside the \csname...\endcsname statement, use an \expandafter.

The point is now: How feasible is this approach? It can be quite tedious to repeat the \csname ... \endcsname usage all the while!

Here is a similar code from the \@starttoc command in latex.ltx:

\def\@starttoc#1{%
  \begingroup
    \makeatletter
    \@input{\jobname.#1}%
    \if@filesw
      \expandafter\newwrite\csname tf@#1\endcsname
      \immediate\openout \csname tf@#1\endcsname \jobname.#1\relax
    \fi
    \@nobreakfalse
  \endgroup}

It can be seen that the file handle of the toc - file is generated on the fly over and over again (for each \@starttoc - call)

Some points to consider:

  • My solution is only correct if opening, writing and closing is within the \foreach cycle, since this establishes a group, so the filename handle macro name isn't available outside of the \foreach - cycle. However, this procedure is not recommended.

  • Is it really necessary to use a new handle for each file? No, not really, since apparently the file handle is generated, the file opened etc. and the 'active' file is determined by the \foreach loop variable \langcode, so it's not easily possible to write to more than one file(handle) at the 'same' time.


\documentclass{article}
\usepackage{fontspec}% xelatex
\usepackage{tikz}% foreach
\usepackage{morewrites}% unnecessary for this example, but useful in practice to exceed 16-write limit in TeX


\def\writelangouts{%
  \foreach \langcode in {da,de,en} {% from tikz package
    \expandafter\newwrite\csname filehandle-\langcode\endcsname
    \immediate\openout\csname filehandle-\langcode\endcsname=\jobname-semantically_useful_suffix_\langcode.txt
    \immediate\closeout\csname filehandle-\langcode\endcsname
  }%
}%

    \def\otherwritelangouts{%
  \foreach \langcode in {da,de,en} {% from tikz package
    \def\fhandle{\csname filehandle-\langcode\endcsname}
    \newwrite\fhandle%
    \immediate\openout\fhandle=\jobname-semantically_useful_suffix_\langcode.txt
    \immediate\closeout\fhandle
  }%
}%


\AtEndDocument{\writelangouts}

\begin{document}
\jobname
\end{document}

Assuming the file above is called fhandle.tex, the .log - file shows that following file handles are generated (at the end of the document, since \writelangouts is used in \AtEndDocument)

ABD: EveryShipout initializing macros
\AtBeginShipoutBox=\box53
\filehandle-da=\write5
\openout4 = `fhandle-semantically_useful_suffix_da.txt'.

\filehandle-de=\write6
\openout4 = `fhandle-semantically_useful_suffix_de.txt'.

\filehandle-en=\write7
\openout4 = `fhandle-semantically_useful_suffix_en.txt'.
  • It doesn't generally work because of the grouping, unless all the tasks related to writing, from opening up to closing, is performed in the \foreach cycle. – egreg Aug 5 '16 at 9:18
  • Of course I assumed the writing in the \foreach cycle -- otherwise the closing right after opening would be pretty useless. I know about the \foreach issues, that's why I rarely use it. Using the whole process of opening, writing and closing in a cycle, one file handle would be enough of course. – user31729 Aug 5 '16 at 10:41
5

If your task is to open a file, write on it and close it all in the same cycle of the \foreach loop, you need just one file handle.

\documentclass{article}

\usepackage{tikz}% foreach

\newwrite\langouts
\newcommand\writelangouts{%
  \foreach \langcode in {da,de,en} {% from tikz package
    \immediate\openout\langouts=\jobname-\langcode.txt
    \immediate\write\langouts{This is \langcode}
    \immediate\closeout\langouts
  }%
} 
\AtEndDocument{\writelangouts}

\begin{document}
\jobname
\end{document}

The contents of the written files

test-da.txt

This is da

test-de.txt

This is de

test-en.txt

This is en
  • Hey that's better programming. I did not know you could use one out macro for multiple files. It seems unusual to have a macro handle for multiple files. Perhaps I do not understand \newwrite\langouts completely. – Jonathan Komar Aug 5 '16 at 9:49
  • 3
    @macmadness86 So long as you close the previous file before opening a new one, you just need one handle. – egreg Aug 5 '16 at 9:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.