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