summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3io.dtx
blob: ae155f4d2b39a379f6398a5059d40ea96e745e04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
% \iffalse
%% File: l3io.dtx Copyright (C) 1990-1998 LaTeX3 project
%
%<*dtx>
          \ProvidesFile{l3io.dtx}
%</dtx>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{l3io}
%<driver> \ProvidesFile{l3io.drv}
% \fi
%         \ProvidesFile{l3io.dtx}
          [1998/04/20 v1.0c L3 Experimental i/o module]
%
% \iffalse
%<*driver>
\documentclass{l3doc}

\begin{document}
\DocInput{l3io.dtx}
\end{document}
%</driver>
% \fi
%
% \section{Low-level file i/o}
%
% \TeX{} is capable of reading from and writing up to 16 individual
% streams. These i/o operations are accessable in \LaTeX3 with functions
% from the "\io.."  modules. In most cases it will be
% sufficiant for the programmer to use the functions provided by the
% auxiliary file module, but here are the necessary functions for
% manipulating private streams.
%
% Sometimes it is not know beforehand how much text is going to be
% written with a single call. As a result some internal \TeX{} buffer
% may overflow. To avoid this kind of problem, \LaTeX3 maintains beside
% direct write operations like "\iow_expanded:Nn" also so called ``long''
% writes where the output is broken into individual lines on every blank
% in the text to be written. The resulting files are difficult to read
% for humans but since they usually serve only as internal storage this
% poses no problem.
%
% Beside the functions that immediately act (e.g., "\iow_expanded:Nn",
% etc.) we also have deferred operations that are saved away until the
% next page is finished. This allow to expand the <tokens> at the right
% time to get correct page numbers etc.
%
% \subsection{Functions for output streams}
%
% \begin{function}{\iow_new:N |
%                  \iow_new:c
% }
% \begin{syntax}
%   "\iow_new:N" <stream>
% \end{syntax}
% Defines <stream> to be a new identifer denoting an output stream for
% use in subsequent functions.
% \begin{texnote}
% "\iow_new:N" corresponds to the plain \TeX{} \tn{newwrite}
% allocation routine.
% \end{texnote}
% \end{function}
%
% \begin{function}{\iow_open:Nn |
%                  \iow_open:cn
% }
% \begin{syntax}
%   "\iow_open:Nn" <stream> "{" <file name> "}"
% \end{syntax}
% Opens output stream <stream> to write to <file name>. The output
% stream is immediately available for use. If the <stream> was already
% used as an output stream to some other file, this file gets closed
% first.\footnote{This is a precaution since on some OS it is possible
% to open the same file for output more than once which then results in
% some internal errors at the end of the run.} Also, all output streams
% still open at the end of the \TeX{} run will be automatically closed.
% \end{function}
%
% \begin{function}{\iow_expanded:Nn |
%                  \iow_unexpanded:Nn
% }
% \begin{syntax}
%  "\iow_expanded:Nn" <stream> "{" <tokens> "}"
% \end{syntax}
% This function immediately writes the expansion of <tokens> to the
% output stream <stream>. If <stream> is not open output goes to the
% terminal. The variant "\iow_unexpanded:Nn" writes out <tokens> without any
% further expansion (verbatim).
% \end{function}
%
% \begin{function}{\iow_expanded_log:n |
%                  \iow_expanded_term:n |
%                  \iow_unexpanded_term:n
% }
% \begin{syntax}
%  "\iow_expanded_log:n" "{" <tokens> "}"
% \end{syntax}
% These functions write to the transcript or to the terminal
% respectively. So they are equivalent to "\iow_expanded:Nn" where <stream>
% is the transcript file ("\c_iow_log_stream") or the terminal
% ("\c_io_term_stream").
% \end{function}
%
% \begin{function}{\iow_long_expanded:Nx |
%                  \iow_long_unexpanded:Nn
% }
% \begin{syntax}
%  "\iow_long_expanded:Nn" <stream> "{" <tokens> "}"
% \end{syntax}
% Like "\iow_expanded:Nn" but splits <tokens> at every blank into separate
% lines.
% \end{function}
%
% \begin{function}{\iow_unexpanded_if_avail:Nn|
%                  \iow_unexpanded_if_avail:cn|}
% \begin{syntax}
%  "\iow_unexpanded_if_avail:Nn" <stream> "{" <tokens> "}"
% \end{syntax}
% This special function first checks if the <stream> is open of writing.
% If not it does nothing otherwise it behaves like "\iow_unexpanded:Nn".
% \end{function}
%
% \begin{function}{\iow_deferred_expanded:Nn |
%                  \iow_deferred_unexpanded:Nn}
% \begin{syntax}
%   "\iow_deferred_expanded:Nn"  <stream> "{" <tokens> "}"
% \end{syntax}
% These functions save away <tokens> until the next page is ready to be
% shipped out. Then, in case of "\iow_deferred_expanded:Nn" <tokens> get
% expanded and afterwards written to <stream>. "\iow_deferred_expanded:Nn"
% also always needs "{}" around the second argument. The use of
% "\iow_deferred_unexpanded:Nn" is probably seldom necessary.
% \begin{texnote}
% "\iow_deferred_expanded:Nn" was known as \tn{write}.
% \end{texnote}
% \end{function}
%
% \begin{function}{\iow_newline:}
% \begin{syntax}
%   "\iow_newline:"
% \end{syntax}
% Function that produces a new line when used within the <token list>
% that gets written some output stream in non-verbatim mode.
% \end{function}
%
% \subsection{Functions for input streams}
%
% \begin{function}{\ior_new:N
% }
% \begin{syntax}
%   "\ior_new:N" <stream>
% \end{syntax}
% This function defines <stream> to be a new input stream constant.
% \begin{texnote}
% This is the new name and new implementation for plain \TeX's
% \tn{newread}.
% \end{texnote}
% \end{function}
%
% \begin{function}{\ior_open:Nn}
% \begin{syntax}
%   "\ior_open:Nn" <stream> "{" <file name> "}"
% \end{syntax}
% This function opens <stream> as an input stream for the external file
% <file name>. If <file name> doesn't exist or is an empty file the
% stream is considered to be fully read, a condition which can be tested
% with "\ior_eof:NTF" etc. If <stream> was already used to read from some
% other file this file will be closed first. The input stream is ready
% for immediate use.
% \end{function}
%
% \begin{function}{\ior_close:N}
% \begin{syntax}
%   "\ior_close:N" <stream>
% \end{syntax}
% This function closes the read stream <stream>.
% \begin{texnote}
% This is a new name for \tn{closein} but it is considered bad practice
% to make use of this knowledge :-)
% \end{texnote}
% \end{function}
%
% \begin{function}{\ior_eof:NTF |
%                  \ior_eof:NF}
% \begin{syntax}
%   "\ior_eof:NTF" <stream> "{" <true code> "}{" <false code> "}"
% \end{syntax}
% Conditional that tests if some input stream is fully read. The
% condition is also true if the input stream is not open.
% \end{function}
%
% \begin{function}{\if_eof:w}
% \begin{syntax}
%   "\if_eof:w" <stream> <true code> "\else:" <false code> "\fi:"
% \end{syntax}
% \begin{texnote}
% This is the primitive \tn{ifeof} but we allow only a <stream> and not
% a plain number after it.
% \end{texnote}
% \end{function}
%
% \begin{function}{\ior_to:NN |
%                  \ior_gto:NN}
% \begin{syntax}
%   "\ior_to:NN" <stream> <tlp>
% \end{syntax}
% Functions that reads one or more lines (until an equal number of left
% and right braces are found) from the input stream <stream> and places
% the result locally or globally into <tlp>. If <stream> is not open
% input is requested from the terminal.
% \end{function}
%
% \subsection{Constants}
%
% \begin{variable}{\c_iow_comment_char |
%                  \c_iow_lbrace_char  |
%                  \c_iow_rbrace_char}
% Constants that can be used to represent comment character, left and
% right brace in token lists that should be written to a file.
% \end{variable}
%
% \begin{variable}{\c_io_term_stream}
% Input or output stream denoting the terminal. If used as an input
% stream the user is prompted with the name of the <tlp> (that is used
% in the call "\ior_to:NN" or "\ior_gto:NN") followed by an equal sign.
% If you don't want an automatic prompt of this sort ``misuse''
% "\c_iow_log_stream" as an input stream.
% \end{variable}
%
% \begin{variable}{\c_iow_log_stream}
% Output stream that writes only to the transcript file (e.g., the
% {\tt.log} file on most systems). You may ``misuse'' this stream as an
% input stream. In this case it acts as a terminal stream without user
% prompting.
% \end{variable}
%
% \begin{variable}{\g_iow_newline_code}
% Global variable holding the character number of the character that
% denotes a new line when something is written to an output stream.
% \begin{texnote}
% A.k.a \tn{newlinechar}.
% \end{texnote}
% \end{variable}
%
% \subsection{Internal functions}
%
% \begin{function}{\iow_long_expanded_aux:w}
%  Function used to implement immediate writing where a new line is
% started at every blank.
% \end{function}
%
% \begin{function}{%
%                  \tex_read:D |
%                  \tex_immediate:D |
%                  \tex_closeout:D |
%                  \tex_openin:D |
%                  \tex_openout:D |
% }
% These are the functions of the primitive interface to \TeX.
% \begin{texnote}
% The \TeX{} primitives \tn{read}, \tn{immediate}, \tn{closeout},
% \tn{openin}, and \tn{openout} are all renamed and should not be used
% by a programmer since the functionality is covered by the \LaTeX3
% functions above.
% \end{texnote}
% \end{function}
%
%
% \section{Lowlevel i/o-commands}
%
%    We start by ensuring that the required packages are loaded.
%    \begin{macrocode}
%<package&check>\RequirePackage{l3chk}\par
%<package>\RequirePackage{l3toks}\par
%<*package>
%    \end{macrocode}
%
% This section is primarily concerned with input and output streams.
% The naming conventions for i/o streams is |ior| (for read) and |iow|
% (for write) as module names. e.g.\ |\c_ior_test_stream| is an input stream
% variable called `test'.
%
% \subsection{Output streams}
%
% \begin{macro}{\iow_new:N}
% \begin{macro}{\iow_new:c}
%    Allocation of new output streams is done by these functions.
%    As we currently do not distribute a new allocation module we nick
%    the |\newwrite| function.
%    \begin{macrocode}
\def_new:Npn \iow_new:N {}
\let:NN \iow_new:N \newwrite
\def_new:Npn \iow_new:c {\exp_args:Nc \iow_new:N}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\iow_open:Nn}
% \begin{macro}{\iow_open:cn}
%    To open streams for reading or writing the following two functions
%    are provided. The streams are opened immediately.
%
%    From some bad experiences on the mainframe, I learned that it is
%    better to force the close before opening a dataset for writing. 
%    We have to check whether this is also necessary in case of
%    |\tex_openin:D|.
%    \begin{macrocode}
\def_new:Npn \iow_open:Nn #1#2{\iow_close:N #1
     \tex_immediate:D\tex_openout:D#1#2\scan_stop:}
\def_new:Npn \iow_open:cn {\exp_args:Nc \iow_open:Nn}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\iow_close:N}
%    Since we close output streams prior to opening, a separate closing
%    operation is probably not necessary. But here it is, just in
%    case\ldots. Actually you will need this if you intend to write
%    and then read in the same pass from some stream.
%    \begin{macrocode}
\def_new:Npn \iow_close:N {\tex_immediate:D\tex_closeout:D}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\c_io_term_stream}
% \begin{macro}{\c_iow_log_stream}
%    Here we allocate two output streams for writing to the transcript
%    file only (|\c_iow_log_stream|) and to both the terminal and transcript
%    file (|\c_io_term_stream|). The latter can also be used to read
%    from therefore it is called |..io_..|.
%    \begin{macrocode}
\let_new:NN \c_io_term_stream \c_sixteen
\let_new:NN \c_iow_log_stream \c_minus_one
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsubsection{Immediate writing}
%
% \begin{macro}{\iow_expanded:Nn}
%    An abbreviation for an often used operation, which immediately
%    writes its second argument to the output stream.
%    \begin{macrocode}
\def_new:Npn \iow_expanded:Nn {\tex_immediate:D\iow_deferred_expanded:Nn}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\iow_unexpanded:Nn}
%    This routine writes the second argument verbatim onto the output
%    stream. If this stream isn't open, the output goes to the terminal.
%    If the first argument is no output stream at all, we get an
%    internal error.
%    \begin{macrocode}
\def_new:Npn \iow_unexpanded:Nn #1#2{\toks_gset:Nn \g_tmpa_toks {#2}
   \iow_expanded:Nn #1{\toks_use:N \g_tmpa_toks}}
%    \end{macrocode}
% \end{macro}
%
%
%  \begin{macro}{\iow_expanded_log:n}
%  \begin{macro}{\iow_expanded_term:n}
%    Now we redefine two functions for which we needed a definition
%    very early on. They both write their second argument fully
%    expanded to the output stream.
%    \begin{macrocode}
\def:Npn \iow_expanded_log:n {\iow_expanded:Nn \c_iow_log_stream}
\def:Npn \iow_expanded_term:n{\iow_expanded:Nn \c_io_term_stream}
%    \end{macrocode}
%    The second one isn't exactly equivalent to the old |\typeout| since
%    we need to control expansion in the function we provide for the user.
%  \end{macro}
%  \end{macro}

% \begin{macro}{\iow_unexpanded_term:n}
%    This function writes its argument verbatim to the the terminal.
%    \begin{macrocode}
\def_new:Npn \iow_unexpanded_term:n {\iow_unexpanded:Nn \c_io_term_stream}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\iow_unexpanded_if_avail:Nn}
% \begin{macro}{\iow_unexpanded_if_avail:cn}
%    |\iow_unexpanded_if_avail:Nn | \m{stream} \m{code}.  This routine writes
%    its second argument unexpanded to the stream given by the first
%    argument, provided that this stream was opened for writing. Note,
%    that |#| characters get doubled within \m{code}.
%    \begin{macrocode}
\def_new:Npn \iow_unexpanded_if_avail:Nn #1{
%    \end{macrocode}
%    In this routine we have to check whether or not the output stream
%    that was requested is defined at all. 
%    So we check if the name is still free.
%    \begin{macrocode}
  \cs_free:NTF #1\use_none:n {\iow_unexpanded:Nn #1}}
%    \end{macrocode}
%    Note: the next function could be streamlined for speed if we use
%    the faster |\cs_free:cTF|. (space viz time).
%    \begin{macrocode}
\def_new:Npn \iow_unexpanded_if_avail:cn {
         \exp_args:Nc \iow_unexpanded_if_avail:Nn }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\iow_long_expanded:Nn}
% \begin{macro}{\iow_long_unexpanded:Nn}
% \begin{macro}{\iow_long_expanded_aux:w}
%    Another type of writing onto an output stream is used for
%    potentially long token sequences. We break the output lines at
%    every blank in the second argument. This avoids the problem of
%    buffer overflow when reading back, or badly broken lines on
%    systems with limited file records.  The only thing we have to
%    take care of, is the danger of two blanks in succession since
%    these get converted into a |\par| when we read the stuff back.
%    But this can happen only if things like
%    two spaces find their way into the second argument.
%    Usually, multiple spaces are removed by \TeX's scanner.
%
%    \begin{macrocode}
\def_new:Npn \iow_long_expanded_aux:w #1#2#3{
   \group_begin:\g_iow_newline_code`\ #1#2{#3}\group_end:}
\def_new:Npn \iow_long_expanded:Nn {\iow_long_expanded_aux:w 
                                    \iow_expanded:Nn}
\def_new:Npn \iow_long_unexpanded:Nn {\iow_long_expanded_aux:w 
                                      \iow_unexpanded:Nn}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \subsubsection{Deferred writing}
%
% Deferred writing to output streams is a bit more complicated because
% there seems to be no nice hack for writing unexpanded. The only
% relatively sure bet is to use |\token_to_meaning:N| expansion of some token
% list.  That's the way the following functions are implemented.
%
% Another possibility would be to reserve a certain number of scratch
% token registers that could be used to hold the tokens until after the
% next |\tex_shipout:D|. But such an approach would probably fail because of
% the limited number of available token registers that would need to
% be reserved for this special application.
%
%
% \begin{macro}{\iow_deferred_expanded:Nn}
%    First the easy part, this is the primitive.
%    \begin{macrocode}
\let:NN \iow_deferred_expanded:Nn \tex_write:D
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\iow_deferred_unexpanded:Nn}
%    Now the harder part:
%    \begin{macrocode}
\def_new:Npn \iow_deferred_unexpanded:Nn #1#2{
  \tlp_set:Nn \l_tmpa_tlp {#2}
  \tlp_set:Nx \l_tmpb_tlp 
              {\iow_deferred_expanded:Nn #1{\tlp_to_str:N \l_tmpa_tlp}}
  \l_tmpb_tlp}
%    \end{macrocode}
% \end{macro}
%
% Long forms of these functions are not possible since the deferred
% writing will restore the value of |\g_iow_newline_code| before it will have
% a chance to act. But on the other hand it is nevertheless possible
% to make all deferred writes long by setting the |\g_iow_newline_code|
% inside the output routine just before the |\tex_shipout:D|. The only
% disadvantage of this method is the fact that messages to the
% terminal during this time will also then break at spaces. But we
% should consider this.
%
% \subsubsection{Special characters for writing}
%
%
% \begin{macro}{\c_iow_comment_char}
% \begin{macro}{\c_iow_lbrace_char}
% \begin{macro}{\c_iow_rbrace_char}
%   We also need to be able to write braces and the comment character.  We
%   achieve this by defining global constants to expand into a version of
%   these characters with |\tex_catcode:D|${}=12$.
%    \begin{macrocode}
\tex_catcode:D `\%= 12 \scan_stop:
\tlp_new:Nn \c_iow_comment_char {%}
\tex_catcode:D `\%= 14 \scan_stop:
%    \end{macrocode}
%    To avoid another allocation function which is probably only
%    necessary here we use the |\def:Npx| command directly.
%    \begin{macrocode}
\tlp_new:Nn \c_iow_lbrace_char{}
\tlp_new:Nn \c_iow_rbrace_char{}
\def:Npx\c_iow_lbrace_char {\token_to_string:N{}
\def:Npx\c_iow_rbrace_char {\token_to_string:N}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \subsection{Input streams}
%
% \begin{macro}{\ior_new:N}
%    Allocation of new input streams is done by this function.
%    As we currently do not distribute a new allocation module we nick
%    the |\newwread| function.
%    \begin{macrocode}
\def_new:Npn \ior_new:N {}
\let:NN \ior_new:N \newread
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ior_open:Nn}
%    Processing of input-streams (via |\tex_openin:D| and |closein|) is
%    always `immediate' as far as \TeX{} is concerned. An extra
%    |\tex_immediate:D| is silently ignored.
%    \begin{macrocode}
\def_new:Npn \ior_open:Nn #1#2{\ior_close:N #1\scan_stop:
                               \tex_openin:D#1#2\scan_stop:}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ior_eof:NTF}
%    |\ior_eof:NTF | \m{stream} \m{true case} \m{false case}.  To
%    test if some particular input stream is exhausted the following
%    conditional is provided:
%    \begin{macrocode}
\def_new:Npn \ior_eof:NTF #1{\if_eof:w#1
     \exp_after:NN\use_choice_i:nn \else:
     \exp_after:NN\use_choice_ii:nn \fi:}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ior_eof:NF}
%    |\ior_eof:NF | \m{stream}  \m{false case}.  Do something if
%    if there is still something to read from this file:
%    \begin{macrocode}
\def_new:Npn \ior_eof:NF #1{\if_eof:w#1
        \exp_after:NN \use_none:nn \fi: \use:n}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\ior_to:NN}
% \begin{macro}{\ior_gto:NN}
%    And here we read from files.
%    \begin{macrocode}
%<*check>
\def_new:Npn \ior_to:NN #1#2{\tex_read:D#1to#2
   \chk_local_or_pref_global:N #2}
%</check>
%<-check> \def_new:Npn \ior_to:NN #1{\tex_read:D#1to}
\def_new:Npn \ior_gto:NN {
%<*check>
   \pref_global_chk:
%</check>
%<-check> \pref_global:D
   \ior_to:NN}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
%    Show token usage:
%    \begin{macrocode}
%</package>
%<*showmemory>
\showMemUsage
%</showmemory>
%    \end{macrocode}
%
%