summaryrefslogtreecommitdiff
path: root/macros/generic/bitelist/bitelist.sty
blob: 219008d69387b3257626896cb1dcdf9ae7cbe657 (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
\def\filename{bitelist}                     \def\filedate{2012/03/29} 
\def\fileversion{v0.1} \def\fileinfo{split lists in TeX's mouth (UL)}
%% Copyright (C) 2012 Uwe Lueck,
%% http://www.contact-ednotes.sty.de.vu
%% -- author-maintained in the sense of LPPL below --
%%
%% This file can be redistributed and/or modified under
%% the terms of the LaTeX Project Public License; either
%% version 1.3c of the License, or any later version.
%% The latest version of this license is in
%%     http://www.latex-project.org/lppl.txt
%% There is NO WARRANTY - this rather is somewhat experimental.
%%
%% Please report bugs, problems, and suggestions via
%%
%%   http://www.contact-ednotes.sty.de.vu
%%
%% === Proceeding without \LaTeX ===
%% Some tricks from Bernd Raichle's \CtanPkgRef{ngerman}{ngerman.sty}---I
%% need \LaTeX's `\Provides'\-`Package' for \ctanpkgref{fileinfo}, 
%% my package version tools. With 'readprov.sty', it issues `\endinput', 
%% close conditional before:
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname ProvidesPackage\endcsname\relax \else
    \edef\fileinfo{\noexpand\ProvidesPackage{\filename}%
        [\filedate\space \fileversion\space \fileinfo]}
    \expandafter\fileinfo
\fi
\chardef\atcode=\catcode`\@
\catcode`\@=11 % \makeatletter
%% Providing \LaTeX's `\@firstoftwo' and `\@secondoftwo': 
\long\def\@firstoftwo #1#2{#1}
\long\def\@secondoftwo#1#2{#2}
%% 
%% === Basic Parsing (No Braces) ===
%%
%% |\BiteMake{<def>}{<cmd>}{<find>}| provides the parameter text 
%% (\TeX book p.~203) for defining (by <def>) a macro <cmd> that will 
%% search for <find>:
\def\BiteMake#1#2#3{#1#2##1#3##2\BiteSep##3\BiteStop}
%% With |\BiteFindByIn{<find>}{<cmd>}{<list>}|, 
%% you can use a <cmd> (perhaps defined by &\BiteMake) 
%% in order to search <find> in <list>. 
%% This is expandable as promised:
\def\BiteFindByIn#1#2#3{%
    #2#3\BiteSep#1\BiteCrit\BiteSep\BiteStop}
%% Preparing a possible &\edef as <def>:
\let\BiteSep\relax  \let\BiteStop\relax
%% And this is important in any case for correct testing of 
%% occurrence:\footnote{The idea for the ``funny `Q'" 
%%                      is from the \ctanpkgref{ifmtarg} package.}
\catcode`\Q=7 \let\BiteCrit=Q \catcode`\Q=11
%% Perhaps you could increase safety of tests by using something similar to the funny `Q' 
%% for &\BiteSep and &\BiteStop.
%% %% 2012/03/28:
%% However, this would additionally require reimplementation of 
%% the macros for keeping braces (Section~\ref{sec:braces}) using `\edef'.
%% % It appears to me, however, that expandable tests like this one 
%% % never are perfectly safe; you only can say that it is safe with a 
%% % source meeting certain conditions. \ctanpkgref{fifinddo} originally 
%% % was made for ``plain text," to be read from files without assigning 
%% % \TeX's special category codes. \emph{Here} we assume that the source 
%% % (text in \cs{Provides.\empty..} arguments) will never contain such a 
%% % ``funny `Q'".
%%
%% === Simple Conditionals ===
%% By |\BiteMakeIfOnly{<def>}{<cmd>}{<find>}|, you can make a command <cmd>
%% that with
%% \[|\BiteFindByIn{<find>}{<cmd>}{<list>}{<yes>}{<no>}|\]
%% chooses <yes> if <find> occurs in <list> and <no> otherwise.
\def\BiteMakeIfOnly#1#2#3{\BiteMake{#1}{#2}{#3}{\BiteIfCrit{##2}}}
%% |\BiteIfCrit{<suffix>}{<yes>}{<no>}| 
%% is the basic test for occurrence of <find> in <list>:
\def\BiteIfCrit#1{\ifx\BiteCrit#1\expandafter\@secondoftwo
%% If <cmd>'s second argument---same as &\BiteIfCrit's first argument---is 
%% empty, &\BiteCrit is compared with &\expandafter, so <yes> is chosen.
%% That is correct, it happens when <find> is a suffix of <list>.
                           \else \expandafter\@firstoftwo \fi }
%%
%% === Passing Results Completely---No Braces ===
%% So the previous `\BiteMakeIfOnly' generates pure tests on occurrence, 
%% giving away information about prefix and suffix. 
%% It may be considered a didactical step fostering understanding of the following. 
%% % \medskip\noindent
%% % ** Generic Fundamental Splitter---No Braces **
%% %% Wrong:
%% % With the above `\BiteMakeIfOnly', the user can choose on her own
%% % information about the composition of <list> to use. 
%% % Perhaps it is not easy to understand. 
%% % `\BiteMakeIfOnlySplit{<def>}{<cmd>}{<find>}' by contrast, 
%% % should satisfy ``all needs" by providing \emph{all} the information 
%% % about splitting a <list>. It may also be a template for using 
%% % `\BiteMakeIfOnly'. 
%% When, by contrast \[|\BiteMakeIf{<def>}{<cmd>}{<find>}|\]
%% has been issued, a later 
%% $$|\BiteFindByIn{<find>}{<cmd>}{<list>}{<list>}{<yes>}{<no>}|\eqno(*)$$
%% will expand to 
%% \[`<yes>{<prefix>}{<find>}{<suffix>}'\]
%% if <list> is composed as <prefix><find><suffix>
%% and <prefix> is the shortest $\alpha$ such that there is some $\beta$
%% with $<list>=\alpha<find>\beta$. Otherwise, $(*)$ will expand to
%% \[`<no>{<list>}'\]
%% This gives all the information available. 
%% For actual applications, it may be too much, and the macro programmer 
%% may do something in between of `\BiteMakeIfOnly' and `\BiteMakeIf':
\def\BiteMakeIf#1#2#3{%
    \BiteMake{#1}{#2}{#3}##4##5##6{%
%% In the replacement text, we first do the same as with `\BiteMakeIfOnly':
      \BiteIfCrit{##2}%
%% What follows is new. <cmd>'s third argument is ignored. 
%% The fourth keeps the original <list>. 
%% <yes> is <cmd>'s fifth and <no> is its sixth argument.
      {##5{##1}{#3}{##2}}%  %% if #3 in ##4
      {##6{##4}}%           %% otherwise
    }%
}
%% In $(*)$, <list> has been doubled. That was no mistake. 
%% It is due to a shortcoming of `\BiteFindByIn'.
%% With
%% \[|\BiteFindByInIn{<find>}{<cmd>}{<list>}{<yes>}{<no>}|\]
%% you get the same result as with $(*)$:
\def\BiteFindByInIn#1#2#3{\BiteFindByIn{#1}{#2}{#3}{#3}}
%% TODO not sure about command names yet
%%
%% == Example Applications == 
%% === Splitting at Space ===
%% \label{sec:space}
%% This work actually arose from modifying `\GetFileInfo'
%% as provided by \LaTeX's \ctanpkgref{doc} package
%% so that it would deal reasonably with ``incomplete" file info---for
%% the \ctanpkgref{nicefilelist} package. 
%% `\GetFileInfo' works best when the file info contains 
%% at least \emph{two} blank spaces. But how many are there indeed?---And 
%% I wanted to do it \emph{expandably:} while `\GetFileInfo' issues 
%% \emph{definitions} of `\filedate', `\fileversion', and `\fileinfo', 
%% date, version, and info should be passed as \emph{macro arguments}.
%% \medbreak\noindent
%% |\BiteIfSpace| tries splitting at the next blank space passes results:
\BiteMake{\def}{\BiteIfSpace}{ }#4#5#6{%
    \BiteIfCrit{#2}{#5{#1}{#2}}{#6{#4}}}
%% The difference to the `\BiteMakeIf' construction is that we do not 
%% pass <find>, the space---it's not essential. 
%% (TODO names may change ...)
%%
%% Now \[|\BiteFindByInIn{ }{\BiteIfSpace}{<list>}{<yes>}{<no>}|\]
%% will pass prefix/suffix to <yes> or <list> to <no>.
%% If this is needed frequently, here is a shorthand 
%% |\BiteGetNextWord{<list>}{<yes>}{<no>}|:
\def\BiteGetNextWord{\BiteFindByInIn{ }\BiteIfSpace}
%% See a test in `bitedemo.tex' (Section~\ref{sec:demo}).
%% 
%% === Splitting at Comma ===
%% ... left as an exercise to the reader ...
%%
%% == Keeping Braces: Reasoning ==
%% \label{sec:braces}
%% Now we want to generalize task (Section~\ref{sec:task})
%% and solution (Section~\ref{sec:trick}) for the case that
%% $\tau=<list>$ has (balanced) braces 
%% (with category codes for argument delimiters), 
%% while $\sigma=<find>$ still has not (does not work with our method). 
%% So with $\tau=\alpha\sigma\beta$, 
%% $\alpha$ (``prefix") or $\beta$ (``suffix") or both 
%% may contain braces. But we consider another restriction: 
%% braces must be balanced in $\alpha$ and in $\beta$, 
%% we don't try parsing inside braces 
%% (as opposed to the search for asterisks in Appendix~D 
%%  of The~\TeX book).
%%
%% According to \TeX book p.~204, when a macro <cmd> finds an argument 
%% formed as `{<tokens>}', in <cmd>'s replacement text only <tokens>
%% is used, i.e., outer braces are removed. 
%% So when $\alpha=`{<tokens>}'$, a parser <cmd> as defined by our 
%% methods above will return <tokens> instead of `{<tokens>}'---likewise 
%% for $\beta$. We are now trying to \emph{keep} outer braces in prefix/suffix
%% by a more elaborate method.
%% 
%% The idea is to present $\tau=<list>$ with context\footnote{Perhaps 
%%      I am confusing `&\empty' and the token list containing just `&\empty' here?}
%% \[`<cmd>\empty<list><stop><sep><find><crit><sep><stop>'\]
%% or in the notation of Section~\ref{sec:trick}
%% \[`<cmd>\empty'\tau\theta\zeta\sigma\rho\zeta\theta\]
%% Then, if <find> occurs in <list>, we must remove the `\empty'
%% from the prefix that we get with the earlier method (easy)
%% and <stop> from the suffix (tricky, similar problem recurs).
%% Using old $\theta$ for a new purpose works here because 
%% <cmd> will look for $\theta$ only when it has found $\zeta$ before.
%%
%% Mere testing for occurrence is not affected. 
%% \[`\BiteMakeIfOnly' \quad \mbox{and} \quad `\BiteFindByIn'\] 
%% still can be used. 
%% We provide an improved version of 
%% \[`\BiteMakeIf'   \quad (`\BiteMakeIfBraces')\] and of
%% \[`\BiteFindInIn' \quad (`\BiteFindInBraces').\]
%%
%% == Implementation Part II    ==
%% === Keeping Braces           ===
%% \[|\BiteFindByInBraces{<find>}{<cmd>}{<list>}{<yes>}{<no>}|\] 
%% varies `\BiteFindByInIn' according to the previous:
\def\BiteFindByInBraces#1#2#3{%
    #2\empty#3\BiteStop\BiteSep#1\BiteCrit\BiteSep\BiteStop{#3}}
%% Such a <cmd> can be made by |\BiteMakeIfBraces{<def>}{<cmd>}{<find>}|:
\def\BiteMakeIfBraces#1#2#3{%
    \BiteMake{#1}{#2}{#3}##4##5##6{%
      \BiteIfCrit{##2}%
%% <no> works as before. For <yes>, first the `\empty' in the prefix
%% is expanded for vanishing. 
%% `\BiteTidyI' and `\BiteTidyII' continue tidying.
      {\expandafter \BiteTidyI                      %% if #3 in ##4
            \expandafter{##1}%                      %% prefix
%% Another `\empty' avoids that removal of `\BiteStop' in suffix 
%% by `\BiteTideII' removes outer braces:
                        {\BiteTidyII\empty##2}%     %% suffix
                        {#3}%                       %% find
                        {##5}}%                     %% yes
      {##6{##4}}%                                   %% otherwise
    }%
}
%% |\BiteTidyI{<prefix>}{<suffix>}| \ first expands `\BiteTidyII'
%% for removing `\BiteStop' in <suffix>. 
%% `\empty' from `\BiteFindByInBraces' remains and is expanded next 
%% for vanishing. Finally, `\BiteTidied' reorders arguments
%% for operation of <yes>:
\def\BiteTidyI#1#2{%
    \expandafter\expandafter\expandafter \BiteTidied 
        \expandafter\expandafter\expandafter {#2}{#1}}
\def\BiteTidyII#1\BiteStop{#1}
\def\BiteTidied#1#2#3#4{#4{#2}{#3}{#1}}
%% 
%% === Leaving the Package File ===
\catcode`\@=\atcode
\endinput
%%
%% === VERSION HISTORY ===

v0.1   2012/03/26   started
       2012/03/27   continued, restructured
       2012/03/28   continued, separate sections for "Mere Occurrence" 
                    vs. ...; keeping braces, \BiteIfCrit
       2012/03/29   proceeding without LaTeX corrected, restructured