summaryrefslogtreecommitdiff
path: root/macros/generic/midnight/dolines.tex
blob: 6237893bb1f610af915fa5807c8c899686f57eed (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
\ifx\DOLINES\relax\endinput\else\let\DOLINES=\relax\fi % \input only once
%
% dolines.tex: Meta-macros to separate arguments by newlines and by
%	       empty lines.
% version: 1.0  release: 15 April 1991
%
% copyright (c) 1991 Marcel R. van der Goot
%	You can use these macros to typeset documents. You may
%	distribute this file freely, provided that you also distribute
%	the accompanying documentation.
%	    You may make changes to this file, or extract portions
%	of it for inclusion in other files, provided that
%	    (1) you change the name of the file;
%	    (2) you give proper credit and include copyright
%		information where applicable;
%	    (3) explain how an unchanged version can be obtained; and
%	    (4) document the usage of your macros/changes (if usage
%		of your macros is not worth documenting, they must not
%		be worth using).
%	You are not allowed to use the name ``Midnight Macros'' for
%	any changed files.
%	    The above rules for making changes do not apply where it
%	is explicitly noted in this file that something can be changed
%	to conform to your local installation.
%
% USAGE:
%   See the file dolines.doc
%   You need Midnight/loop.tex to use these macros.
%
% original: csvax.cs.caltech.edu [131.215.131.131] in pub/tex
%	    (use anonymous ftp). Also in various archives.
%
% Caltech, Pasadena  ---  Marcel van der Goot
%			  marcel@cs.caltech.edu
%			    Caltech 256--80
%			    Pasadena, CA 91125
%			    USA
%			    (818) 356--4603
%

% update history:
% version 1.0: This one.
%	release 15 April 1991: This one.
%	release 8 February 1991: Used \next instead of \do_next, which
%		occasionally conflicted with use of \next in other macros.

%%%%%% CODE: (you don't need to read this to use the macros)

\input Midnight/loop % CHANGE this filename to correspond to your installation

%%%%%%% Reading from a different file
% This is relatively simple, it can be done with a loop. The read function
% reads a single line (that is what \read does). A file that is being
% \read always ends with an empty line, therefore no test for eof(lines_in)
% is needed in the inner loop.
%
%	 while (!eof(lines_in))
%	   {
%	     read(lines_in, _ln);
%	     if (_ln != empty_ln)
%		{
%		  beforelines();
%		  do { everyline(_ln);
%		       read(lines_in, _ln);
%		  } while (_ln != empty_ln);
%		  afterlines();
%		}
%	   }
%

{\catcode`\^^M=12 \endlinechar=-1 % 12 = other
\catcode`\_=11 % 11 = letter (used to make macros private)

\newread\lines_in

\globaldefs=1

\def\empty_ln{\par}

\def\filedolines#1%
   {{\openin\lines_in=#1 %
     \ifeof\lines_in\message{File #1 not found.}\fi
     \Loop\ifeof\lines_in \Break1 \fi
          \read\lines_in to\_ln
          \ifx\_ln\empty_ln
          \else {\beforelines
	         \Loop\everyline{\_ln}%
		      \read\lines_in to\_ln
		      \ifx\_ln\empty_ln \Break1 \fi
	         \Pool
	         \afterlines
	        }%
          \fi
     \Pool
     \closein\lines_in
   }}

} % restore \catcode`\^^M, \catcode`\_, etc.


%%%%%%% Reading from the current file
% This is more complicated. The problem is that a line can only be
% read at the end of a macro, because otherwise a part of the macro
% itself will be read. Therefore, the above solution with \Loop cannot
% be used. Instead, this is implemented as a finite state machine. The
% FSM has two major states, outer_loop and inner_loop, corresponding to the
% program above. In these states, the value of _ln is used to determine
% what actions to take, and what the next state is. The next state
% is indicated by the control-sequence \do_next.
%    There are two minor states, get_out and get_in. In each of them
% the next line is read into _ln. After get_out, the next state is always
% outer_loop; after get_in it is always inner_loop.
%    Here is a ``picure.'' `(...)' is a state, `...?' denotes the value
% of _ln, and other texts are actions. ctrl-M stands for an empty line.
%
%				 /---<----\
%			    (get_out)	  |
%				 \      ctrl-M?
%   begindolines		  V      /
%     \->bgroup -> (get_out) -> (outer_loop) -> enddolines? -> egroup
%				 ^   |    ^		        \-> (finish)
%				/    |	   \
%		  afterlines --/   other?   \-- afterlines
%			^	     V		     ^
%			|	beforelines	     |
%	            ctrl-M? <--\     |      /--> enddolines?
%				\    V     /
%				(inner_loop)
%				  /     ^
%			     other?      \
%			      |        (get_in)
%			      V            |
%			      \-everyline->/
%


{\catcode`\^^M=12 \endlinechar=-1 % 12 = other
\catcode`\_=11 % 11 = letter (used to make macros private)
\globaldefs=1


\long\def\get_out#1^^M% here a line is read (as #1)
   {\gdef\_ln{#1}%
    \outer_loop
   }

\long\def\get_in#1^^M% here a line is read (as #1)
   {\gdef\_ln{#1}%
    \inner_loop
   }

\def\outer_loop
   {\ifx\_ln\enddolines \egroup\let\do_next=\finishdolines
    \else\ifx\_ln\empty \let\do_next=\get_out
    \else \beforelines\let\do_next=\inner_loop
    \fi  \fi
    \do_next
   }

\def\inner_loop
   {\ifx\_ln\enddolines \afterlines\let\do_next=\outer_loop
    \else\ifx\_ln\empty \afterlines\let\do_next=\outer_loop
    \else \everyline\_ln\let\do_next=\get_in
    \fi  \fi
    \do_next
   }

\def\begindolines
   {\bgroup
    \catcode`\^^M=12 %
    \get_out
   }

} % restore \catcode`\^^M, \catcode`\_, etc.

% We define \finishdolines and \enddolines, in case someone forgets:

\let\finishdolines=\relax
\def\enddolines{\enddolines}