summaryrefslogtreecommitdiff
path: root/macros/lamstex/inputs/dvipaste.tex
blob: 465f9cd47386872bea9daeecc467560317d0ad92 (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
% Copyright (C) The TeXplorators Corporation 1989

% This is DVIPASTE.TEX, to be used with DVIPASTE.EXE, which is
% Copyright (C) The TeXplorators Corporation 1989.

% First we want to have a control sequence that stands for the current
% category code of @, so that we can restore this category code at the end,
% after temporarily making @ a letter (PLAIN makes @ category 12, but
% AmS-TeX, for example, makes @ category 13). Using \csname CCC@\endcsname,
% we can even let this control sequence be called \CCC@, before actually
% making @ a letter, except that this won't work when @ has category 
% code 13, so instead we have to use the \uccode and \uppercase trick.

{\uccode`\Z=`\@
 \uppercase{\expandafter\xdef\csname CCCZ\endcsname{\the\catcode`\@}}
}

% Now we make @ a letter.

\catcode`\@=11  


% \eat@ gobbles a token; it is the same as in AmS-TeX.

\def\eat@#1{}


% We need to know if a \sendout or \paste has already occurred.  The
% following are made true once the respective condition has occurred.

\newif\ifsendout@  
\newif\ifpaste@    


% We need to allocate places for writing or reading the .dat file.

\newwrite\writedata@    
\newread\readdata@      


% The definition of \sendout has the following features (%1, %2, etc.
% refer to lines so marked within the definition of \sendout):

%1  If \paste has occurred, we won't allow a \sendout to occur, because
%   these shouldn't both occur in the same file; in fact, files having
%   \sendout's will redefine the \output routine.

%   In the \errmessage, we can't say \string\sendout, because \sendout is
%   outer.  So we use \expandafter\eat@\string\\ to get the \, and then
%   spell out sendout.

%2  If a \paste hasn't occurred, we see if a previous \sendout has occurred,
%   and if it hasn't, we do the following:
    
%3  Open the .dat file for writing.
    
%4  Declare \t@nrm to use for the name of the file and the page number
%   in the footline (it is possible that no font with the necessary
%   characters in it has been used in the file); the declaration is made 
%   \global, just in case \sendout was used in a group, though it really 
%   shouldn't be.
    
%5  Set \topskip to 0pt.

%6  Change the \output routine, to simply \shipout the current page,
%   followed by a line 2pc below with the name of the file, and the
%   page number.
    
%7  We also want to redefine \bye, to close out the .dat file.  We can't
%   put \gdef\bye within the definition of \sendout, since \bye is outer,
%   but we can say \expandafter\gdef\csname bye\endcsname !
    
%8  And we make \ifsendout@ true.
    
%9  In any case (i.e., whether or not a previous \sendout has occurred),
%   we now put #1 in \box0, so that we can refer to its height, depth and
%   width (usually #1 will be a \box, but we don't know which one).
    
%10 Then we write this data to the .dat file; each \space will expand to a
%   space (PLAIN has \def\space{ }).
    
%11 We start the page with an invisible \hrule (so that the next \vskip
%   won't disappear).
    
%12 We move down to the bottom of the page.

%13 We emit a special, which tells where the .dvi instructions for
%   printing \box0 begin.
    
%14 We set the dimensions of \box0 to 0pt.
    
%15 We start an unindented paragraph with \box0.

%16 Then we emit another special, which tells where the .dvi instructions
%   for printing \box0 end.
    
%17 Finally, we put in a smashed (and tiny) \vrule.  Since this \vrule
%   has to occur exactly at the same position where the \noindent began,
%   the .dvi instructions for printing \box0 will bring us right back to
%   the position we started at.
    
%18 Then we \eject, so that the \output routine will simply print \box0 on 
%   a separate page.

\outer\def\sendout#1{%          
  \ifpaste@                                                                 %1
    \errmessage{\expandafter\eat@\string\\sendout and 
      \string\paste\space not allowed in same file 
      (\string\paste\space has already appeared)}%
  \else                                                                     %2
    \ifsendout@                                                             
    \else                                                                   
      \immediate\openout\writedata@=\jobname.dat                            %3
     \global\font\t@nrm=cmr10                                              %4
      \global\topskip\z@                                                    %5
      \global\output{\shipout\vbox{\vbox to\vsize{\unvbox255 }%             %6
      \baselineskip2pc
      \line{\hfil\t@nrm File [\jobname], \#\number\pageno\hfil}}%
        \global\advance\pageno\@ne}%
      \expandafter\gdef\csname bye\endcsname                                %7
        {\immediate\closeout\writedata@\par\vfill\supereject\end}%
      \global\sendout@true                                                  %8
    \fi
    \setbox\z@\hbox{#1}%                                                    %9
    \immediate\write\writedata@
      {\the\ht\z@\space\the\dp\z@\space\the\wd\z@}%                        %10
    \hrule height\z@                                                       %11
    \vskip\vsize                                                           %12
    \special{beginpaste:}%                                                 %13
    \ht\z@=\z@\dp\z@=\z@\wd\z@=\z@                                         %14
    \noindent\box\z@                                                       %15
    \special{endpaste:}%                                                   %16
    \smash{\vrule height1sp width1sp depth\z@}%                            %17
    \eject                                                                 %18
  \fi}


% The scratch tokens \toks@@ are already used in AmS-TeX.

\toksdef\toks@@=2


% \rightappend@ is from The TeXbook, page 378.

\long\def\rightappend@#1\to#2{\toks@{\\{#1}}%
  \toks@@=\expandafter{#2}\xdef#2{\the\toks@@\the\toks@}}


% \ifreading@ will be true while still reading the data file; it is simply
% the opposite of \ifeof, but we need an \if... with these reversed values,
% to use within a \loop.

\newif\ifreading@  


% The last line of the data file will produce a \par, so we need to have
% something to test against \par.

\def\Par@{\par}    


% The definition of \paste has the following features:

%1  If \sendout has occurred, we won't allow a \paste to occur.

%2  If a \paste hasn't occurred, we do the following:

%3  We make \ifpaste@ true.

%4  When we read in a data file `file'.dat, we will record all the data
%   in a control sequence \`file'@dat. This will be a list macro, as in 
%   The TeXbook, page 378.

%   To see whether we have read in the data file yet, we just see whether
%   this control sequence, as specified by \csname, is \relax.

%5  If not, we haven't read the file yet, so we immediately open it for
%   reading.

%6  We use \ifeof to test whether the file really exists.

%7  Assuming the file does exist, we do the following.

%8  We are going to temporarily store the data in the control sequence
%   \next@, and at the end \let\`file'@dat=\next@.  We do this because it
%   is rather awkward to continually refer to the control sequence
%   \`file'@dat, which can only be named using \csname.  We begin by
%   setting \next@ to be empty.

%9  We set \ifreading@ to be true (it will be false when we get to the
%   end of the data file).

%10 We read using a \loop.

%11 The \loop needs a test that is true if we are going to keep reading,
%   so we set \ifreading@ false when \ifeof gives true.

%12 If we are still reading the file, we read a line to \next@ii.  

%13 The file has a \par at the end, so \ifx\next@ii\Par@ is true when we
%   are at the last line. 

%14 If that is not the case, then we want to add the data in \next@ii to
%   \next@.  We need \expandafter\rightappend@; otherwise we would just
%   get \next@ii in the token list, rather than the values it now has.

%15 And we just keep doing that until the file is all read.

%16 Then we close the file.

%17 And then we want to \global\let\`file'@dat=\next@.  We need to expand
%   the \csname...\endcsname after a \global\let, which requires the
%   triple \expandafter trick of The TeXbook, page 374.

%18 In any case (i.e., whether or not we first had to read in the data
%   file), we now want to apply the \getdata@ construction, defined
%   below, to \`file'@dat and the second argument #2 of \paste.  This
%   also requires an \expandafter.

%19 \ifgetdata@ will be true if #2 is actually the number of a line in
%   the data file.

%20 In this case, the three pieces of data will be stored in \data@ht,
%   \data@dp, and \data@wd, and we will want to put in a box of that
%   height, depth and width.  The easiest way is to lower a box of that
%   height+depth by the depth, so we first set \dimen@ to that sum.

%21 We make an \hbox containing the special, and then the empty box with 
%   the desired dimensions. NOTE: It is important to put the \special
%   in the \hbox, in case this empty box turns out to be the first
%   thing on the page.  For some reason, \tex\ doesn't position such
%   an empty box at the right place, although it does position anything
%   that will actually appear on the page in the right place; a box
%   with a \special in it is NOT treated as an empty box in this process.

%22 If #2 is not the number of a line in the data file, we just give an
%   error message ``No data for File [<data file>], #[<value of #2>]''
%   In order to have # appear in the error message, rather than ##, we
%   temporarily make # the \lccode of Z, put Z where we want the # to 
%   appear, and then \lowercase the \errmessage.  However, we want to
%   have uppercase N and F in this message, so we have to also set
%   the \lccode of N to N, and of F to F.


\def\paste#1#2{%
  \ifsendout@                                                              %1
    \errmessage{\string\paste\space and
      \expandafter\eat@\string\\sendout not allowed in same file
      (\expandafter\eat@\string\\sendout has already appeared)}%
  \else                                                                    %2
    \global\paste@true                                                     %3
    \expandafter\ifx\csname #1@dat\endcsname\relax                         %4
      \immediate\openin\readdata@=#1.dat                                   %5
      \ifeof\readdata@\errmessage{No file #1.dat}%                         %6
      \else                                                                %7
        \def\next@{}%                                                      %8
        \reading@true                                                      %9
        \loop                                                              %10
          \ifeof\readdata@\reading@false\fi                                %11
          \ifreading@                                                      %12
          \read\readdata@ to\next@ii  
          \ifx\next@ii\Par@\else                                           %13
            \expandafter\rightappend@\next@ii\to\next@\fi                  %14
        \repeat                                                            %15
        \immediate\closein\readdata@                                       %16
        \expandafter\expandafter\expandafter\global\expandafter
          \let\csname#1@dat\endcsname\next@                                %17
      \fi
    \fi
    \expandafter\getdata@\csname#1@dat\endcsname{#2}%                      %18
    \ifgetdata@                                                            %19
      \dimen@=\data@ht\advance\dimen@\data@dp                              %20
      \hbox{\special{dvipaste: #1 #2}%                                     %21
      \lower\data@dp\vbox to\dimen@{\hbox to\data@wd{\hfil}\vfil}}%
    \else                                                                  %22
     {\lccode`\Z=`\#\lccode`\N=`\N\lccode`\F=`\F%
     \lowercase{\errmessage{No data for File [#1], Z#2}}}%
    \fi
  \fi}


% \data@ht, \data@dp, and \data@wd are registers in which \getdata@ will
% store the data gotten.

\newdimen\data@ht
\newdimen\data@dp
\newdimen\data@wd


% We also use a flag \ifgetdata@ to tell whether there was data on the line
% requested.

\newif\ifgetdata@


%  Argument #1 for \getdata@ is a list macro, and #2 a number.

%1 We start by setting the counter \count@ to 0, and \ifgetdata@ to
%  false.

%2 We temporarily (i.e., within a group), define \\ to: (a) advance
%  \count@ by 1 (so that \count@ is k when we are looking at the kth
%  thing on the list); (b) if \count@=#2 (we are at the element of the
%  lists specified by #2), set \ifgetdata@ true (so it is true only if
%  there are at least #2 pieces of data); (c) and then use \getdata@@ to
%  get the data out of this piece.  

%3 And then we apply this \\ to the list.


\def\getdata@#1#2{\count@\z@\getdata@false                                 %1
  {\def\\##1{\advance\count@\@ne\ifnum\count@=#2\relax\global\getdata@true
     \getdata@@##1\getdata@@\fi                                            %2
  }#1}}                                                                    %3


% The elements of the list macro will be of the form

%   [...]pt [...]pt [...]pt

%  with a space after the first and second pt, so we just have \getdata@
%  delimit its first two arguments with spaces.


\def\getdata@@#1 #2 #3\getdata@@{%
  \global\data@ht=#1\relax\global\data@dp=#2\relax\global\data@wd=#3\relax}


% Finally, we return @ to its old \catcode.

\catcode`\@\CCC@