%% Macro package `fifinddo.sty' for LaTeX2e, %% FIDO, FIND! %% copyright (C) 2009 Uwe L\"uck, %% http://www.contact-ednotes.sty.de.vu %% -- author-maintained in the sense of LPPL below -- %% for processing tex(t) files %% (checking, filtering, converting, substituting, expanding, ...) \def\fileversion{0.31} \def\filedate{2010/03/23} %% This file can be redistributed and/or modified under %% the terms of the LaTeX Project Public License; either %% version 1.3a of the License, or any later version. %% The latest version of this license is in %% %% http://www.latex-project.org/lppl.txt %% %% We did our best to help you, but there is NO WARRANTY. %% Please report bugs, problems, and suggestions via %% %% http://www.contact-ednotes.sty.de.vu %% %% For the full documentation, look for `fifinddo.pdf'. %% Its source starts in `fifinddo.tex'. %% %% === Format and package version === \NeedsTeXFormat{LaTeX2e}[1994/12/01] % 1994/12/01: \newcommand* etc. \ProvidesPackage{fifinddo}[\filedate\space v\fileversion\space filtering TeX(t) files by TeX (UL)] %% %% === Category codes === %% %% We use the ``underscore" as ``compound identifier." \catcode`\_=11 %% underscore used in control words %% %% |\MakeOther| is a synonym for `\@makeother', needed for matching %% special characters from the input file. It is exemplified by %% |\fdPatternCodes| which is the default of |\PatternCodes|. %% The latter is used in setup macros for reading patterns. \@ifundefined{MakeOther}{\let\MakeOther\@makeother}{} \newcommand*{\fdPatternCodes}{\MakeOther\&\MakeOther\$} \newcommand*{\PatternCodes}{} \let\PatternCodes\fdPatternCodes %% TODO adding/removing %% It would be bad to have `\MakeOther\%' and `\MakeOther\ ' here in %% that this may have unexpected, weird effects with arguments of %% setup macros. Therefore neither `\dospecials' nor `\@sanitize' are %% used. Curly braces remain untouched as default delimiters in setup %% macros. For matching them, you must use `\MakeOther\{' and %% `\MakeOther' in your `\PatternCodes', or |\Delimiters| to introduce %% new ones at the same time, e.g., `\Delimiters\[\]': \newcommand*{\Delimiters}[2]{% \MakeOther\{\MakeOther\}\catcode`#1=1\catcode`#2=2\relax} %% For replacing strings or for defining other strings of ``other" %% characters by `\edef', you can use some \LaTeX\ constructs---here %% are copies |\PercentChar| and |\BackslashChar| of them %% (do you need more?): \newcommand*{\PercentChar}{} \let\PercentChar\@percentchar \newcommand*{\BackslashChar}{} \let\BackslashChar\@backslashcar %% %% == File handling == \newwrite\result_file %% or write to \@mainaux!? %% |\ResultFile{}| opens (and empties) a file %% to be written into. \newcommand*{\ResultFile}[1]{% \def\result_file_name{#1}% \immediate\openout\result_file=#1} %% |\WriteResult{}| writes a line into %% (or more lines with `^^J'). \newcommand*{\WriteResult}[1]{% \immediate\write\result_file{#1}} %% |\WriteProvides| writes a `\ProvidesFile' command to the %% opened file. This should be used when %% is made as \LaTeXe\ input. \newcommand*{\WriteProvides}{% \WriteResult{% \string\ProvidesFile{\result_file_name}% [\the\year/\two@digits\month/\two@digits\day\space automatically generated with fifinddo.sty]}}% %% |\ProcessFileWith{}{}| opens a file %% and runs a loop on its lines the main body of which is . %% When the starts, a new line of is stored as macro %% %% <- the 2010/03/10 %% |\fdInputLine|. \newcommand*{\ProcessFileWith}[2]{% \openin\@inputcheck=#1% % \ifeof\@inputcheck %% bad `exists?' test % \PackageError{fifinddo}{File `#1' not here}% % {Mistyped?}% % \else \global\c@fdInputLine=\z@ %% line counter reset \begingroup \MakeOther\{\MakeOther\}\@sanitize %% from docstrip.tex: % \MakeOther\^^A\MakeOther\^^K%% irrelevant, not LaTeX \endlinechar\m@ne %% <- cf. TeXbook "extended keyboards" up-/downarrow %% -> "math specials", cf. "space specials" \MakeOther\^^I% ASCII horizontal tab -- guessed!? ^^L!? %% With v3.1, we support non-ASCII: \count@=128 \loop \ifnum\count@<\@cclvi \catcode\count@=12 \advance\count@\@ne \repeat \loop \ifeof\@inputcheck \else \read\@inputcheck to \fdInputLine \ignorespaces #2% \repeat \endgroup % \fi \closein\@inputcheck} %% |\CloseResultFile| closes . \newcommand*{\CloseResultFile}{\immediate\closeout\result_file} %% %% TODO: write EOF for debugging!?---%% 2010/03/18 %% Peter Wilson's \ctanpkgref{newfile} %% provides more powerful file handling. %% % <- TODO relevant? 2009/04/12 %% %% \pagebreak %% TODO move theory to fifinddo.tex 2009/04/12 %% == Basic handling of substring conditionals == %% \label{sec:theory} %% === ``Substring Theory" === %% \begin{flushright}\it %% I wished I could study string theory,\\ %% but I only could study substring theory. %% \end{flushright} %% A \TeX\ macro, say, `\find' whose parameter text %% (cf. \TeX book p.~203) %% starts with `#1#2&' stops \TeX\ with an error if it does %% not find and then `&'. Otherwise we have a situation %% `\find&', and `\find' reads as %% #1 and as #2. An important point to note is that %% will not contain , but possibly has more %% occurrences in . In this sense, `\find' uses the %% \emph{first} occurrence of it finds in order to delimit #1. %% Finding the \emph{last} occurrence of therefore needs a %% special idea. %% %% In order to use `\find' for a test whether is in %% , we build a ``sandbox" |\find&|, where %% contains \emph{and additionally} ---as a %% ``dummy;" so `&' delimits the search and `\find' finds %% either in or somewhere else before `&'. %% %% Consider the simple sandbox |\find&|. %% We can test #1 and #2 on being empty by `\ifx$#1$' and `\ifx$#2$'. %% If #2 is empty, is \emph{not} in . %% If #1 is empty at the same time, is empty. %% If #1 is empty and #2 is not, \emph{starts} ! %% This can be used to implement %% Wikipedia-like lists %% TODO 2009/04/11 %% and to distinguish package code from comments in 'makedoc'. %% %% If #2 is \emph{not} empty, occurs in ---or this once %% was \emph{thought}, some time in developping the present package, %% as well as in the version of 'substr.sty' marked %% `2005-11-29',\footnote{\url{http://ctan.org/pkg/substr}. %% 'substr' does not change category codes %% as 'fifinddo' does %% and uses \cs{@nil} as delimiter instead of %% our &&.} try %% (if that version still is installed)\footnote{The ``feature" has %% been fixed with v1.2 as of 2009/10/20 of %% 'substr.sty'.} %% \[`\IfSubStringInString{}{}{YES}{NO}'\] %% which works \emph{verbatim} as well as considering and %% \emph{placeholders}, e.g., for %% \begin{center} %% `\IfSubStringInString{day after day}{day after }{YES}{NO}'\footnote{% %% Likewise \texttt{t\string\^ete-\string\`a-t\string\^ete} ...}\\ %% %% <- `e' was missing 2010/03/17 %% `\IfSubStringInString{AMSTERDAM}{AMSTERD}{YES}{NO}'\\ %% `\IfSubStringInString{TORONTO}{TORON}{YES}{NO}'\\ %% `\IfSubStringInString{bonbon}{bon}{YES}{NO}'\footnote{% %% Polynesian: `aku aku', `rongorongo', `wiki wiki' ...}\\ %% `\IfSubStringInString{bonobo}{bono}{YES}{NO}' %% (an ape) %% \end{center} %% or `\IfSubStringInString{ionization}{ionizat}{YES}{NO}'.\footnote{% %% Read 'substr.sty' or try ``normal" things to convince yourself %% that the syntax indeed is %% &\IfSubStringInString{}{}{}{}.} %% Same with \LaTeX's internal `\in@':\footnote{\cs{in@} has been %% fixed after my warning on Heiko Oberdiek's proposal---at %% least in the repository.---On 2009/04/21 %% I learn from Manuel P\'egouri\'e-Gonnard %% that the first versions of his 'ted' %% had a similar bug, fixed on v1.05 essentially like here; %% Steven Segletes confirms that his 'stringstrings' doesn't %% suffer the problem (returning positions of substrings and %% numbers of occurrences).} %% \[`\makeatletter \in@{bonbon}{bon}\ifin@ YES\else NO\fi \makeatother'\] %% %% \makeatletter \in@{bonbon}{bon}\ifin@ YES\else NO\fi \makeatother %% %% \IfSubStringInString{ionization}{ionizat}{YES}{NO} %% %% In general, the previous approach \emph{fails if and exactly if} %% has a \emph{period} $p$---less than its length---in the sense of that %% the $p$th token to the right or left of each token in %% is the \emph{same} token. %% `AMSTERDAM' has a period 8, `day after day' 10, `bonbon' 3, `bonobo' 4. %% There is a counterexample of length $p$ iff %% has period $p$, namely the first substring of %% having length $p$. If the length of exceeds a multiple %% $mp$ of its period, the first $mp$ tokens of form %% a counterexample . %% %% Therefore, a sandbox must have something between and %% .\footnote{Must? Actually, I preferred this solution to %% other ideas like measuring the length of .} %% We choose |\find~$&| as standard. %% The `$' will be used as an argument delimiter to get rid of the dummy %% in , as well as to decide whether the match was %% in or in the dummy part of the sandbox. %% The `$' can be replaced by another tilde `~' in order to %% test whether \emph{ends} on a , defining a macro %% like `\findatend' whose parameter text starts with `#1~#2&'. %% %% === Plan for proceeding === %% When we check a file for several patterns, we seem to need %% \emph{two} macros for each pattern: one that has the pattern %% in its parameter text and one that stores the pattern for building %% the sandbox.\footnote{If it were for the pattern only, the parsing %% macro might suffice and the macro calling it might extract the %% pattern from a ``dummy expansion." Somewhat too much for me now; %% on the other hand the calling macro also hands some ``current" %% informations to the parsing macro---oh, even this could be %% handled by a general ``calling" macro \dots} %% %% TODO 2009/04/15 %% We use a separate \emph{``name space"} for each of %% both kinds. The parsing macro and the macro building the sandbox %% will have a common \emph{``identifier"} by which the user or %% programmer calls them. Actually, she will usually (first) call %% the sandbox box builder. The sandbox builder calls the parsing %% macro. When \emph{all} occurrences of a pattern in the target are %% looked for, the parser may call itself. %% %% Actually, the parsing macro will execute certain actions %% depending on what it finds in the sandbox, so we call it a %% \emph{``substring conditional"}. It may read additional arguments %% after the sandbox that store information gathered before. %% This is especially useful for designing \emph{``expandable"} %% chains (sequences) of conditionals where macros cannot store information in %% macros. The macro setting up the sandbox will initialize such %% extra arguments at the same time. %% %% It may be more efficient \emph{not} to use the following setup %% macros but to type the macros yourself, just using the following %% as templates. The setup macros are especially useful with patterns %% that contain ``special characters," as when you are looking for %% %% TODO repetition of single right quote not working 2010/03/19 %% lines that might be package comments. %% %% === Meta-Setup === %% %% A setup command will have the following syntax: %% \[|{}[]{}|\] %% will, in the first instance, be category code changes %% for reading overriding the settings in `\PatternCodes'. %% They are executed after the latter in a local group. %% It may be safer to redefine `\PatternCodes' instead %% of using the optional argument. %% %% A macro %% \[|\StartFDsetup{}{}[]|\] %% shared by setup commands %% may read and for . %% || will be the macro that reads (and more) %% and processes it. It must contain `\endgroup' to match %% `\begingroup' from `\FD_prepare_pattern'. %% is stored in a macro |\fdParserId|. %% The default for is \emph{nothing}. \newcommand*{\StartFDsetup}[1]{% \let\FD_do_setup#1% \afterassignment\FD_prepare_pattern \def\fdParserId} \newcommand*{\FD_prepare_pattern}[1][]{% \begingroup \PatternCodes #1\FD_do_setup} %% So should be set up about as follows: %% \begin{quote} %% `\newcommand*{}{\StartFDsetup}'\\ %% `\newcommand*{}[]{}' %% \end{quote} %% 's first argument will be the argument %% of . %% %% === Setup for conditionals === %% `substr_cond' is the ``name space" for substring conditionals. %% A colon separates it from \emph{``job identifiers"} in the actual %% macro names. \def\substr_cond{substr_cond:} %% %% |\MakeSubstringConditional{}[]{}| %% starts the definition of a conditional with identifier %% and pattern . optionally add commands to %% be executed after `\PatternCodes' in a local group. %% \newcommand*{\MakeSubstringConditional} {\StartFDsetup\mk_substr_cond} %% %% `\begingroup' |\mk_substr_cond{}| %% TODO!? 2010/03/22 %% can be directly called by other programmer setup commands when %% `\fdParserId' and have been read. \def\mk_substr_cond #1{%% #1 pattern string \endgroup \@namedef{\substr_cond \fdParserId}##1#1##2&} %% %% This really is not \LaTeX. We are starting defining a macro %% `\substr_cond:' in primitive \TeX\ with `\def' in the form %% \[`\def\substr_cond:#1#2&'\] %% where `\csname' etc. render \lq`:'\rq\ part of the macro name. %% The user or programmer macro produces the part of the definition %% until the delimiter `&' to match the sandbox. You have to add %% (maybe) #3 etc. and the `{}' %% just as with primitive \TeX. %% %% === Setup for sandboxes === %% There was a \emph{question:} will we rather see %% \emph{string macros} or \emph{strings from macro arguments}? %% The input file content always comes %% as `\fdInputLine' first, so we at least \emph{must account} for %% the possibility of string macros as input. %% %% One easy way to apply several checks and substitutions to %% `\fdInputLine' before the result is written to is %% `\let\OutputString\fdInputLine' and then let `\OutputString' %% be to what each job refers as \emph{its} %% input and output, finally `\WriteResult{\OutputString}'. %% (`\fdInputLine' might better not be touched, it could be used %% for a final test whether any change applied for some message on %% screen, even with an entirely expandable chain of actions.) %% This way each job, indeed each recursive substitution of a single %% string must start with expanding `\OutputString'. %% %% On the other hand, there is the idea of \emph{``expandable" %% chains of substitutions}. We may, e.g., define a macro, say, %% `\manysubstitutions{}', such that %% `\WriteResult{\manysubstitutions{\fdInputLine}}' %% writes to the result of applying many expandable %% substitutions to `\fdInputLine'. %% Such a macro `\manysubstitutions' may read `\fdInputLine', %% but it must not redefine any macros. %% Instead, the substitution macros it calls must read results %% of previous substitutions as \emph{arguments}. %% %% Another aspect: %% the order of substitutions should be easy to %% change. Therefore expanding of string macros should rather be %% controlled by the way a job is \emph{called}, not right here %% at the \emph{definition} of the job. For this reason, %% a variant of the sandbox builder expanding some macro was given up. %% `setup_substr_cond' is the name space for macros that build %% sandboxes and initialize arguments for conditional macros. \def\setup_substr_cond{setup_substr_cond:} %% \[|\MakeSetupSubstringCondition{}[]{}{}|\] %% % <- TODO allow `%' and ` ' for breaking code lines. %% ---same , , as for %% `\MakeSubstringConditional' (this is bad, there may be %% |\MakeSubstringConditional*{}|)---creates the %% % <- TODO: store args in \Make...Conditional %% corresponding sandbox, by default without tilde wrap. %% may contain `{#1}' to store the string that was tested, %% also `{}' for calling repetitions and `{}' for screen %% or log informations. \newcommand*{\MakeSetupSubstringCondition} {\StartFDsetup\mk_setup_substr_cond} %% `\begingroup' |\mk_setup_substr_cond{}{}| %% can be directly called by other programmer setup commands after %% `\fdParserId' and have been read: \def\mk_setup_substr_cond #1#2{%% #1 pattern string, %% #2 additional arguments, e.g., `{#1}' to keep tested string \endgroup \expandafter \edef \csname \setup_substr_cond \fdParserId \endcsname ##1{% \make_not_expanding_cs{\substr_cond \fdParserId}% %% By `\edef', the name of the substring conditional is stored here %% as a single token. The rest of the sandbox follows. ##1\noexpand~#1\dollar_tilde}% \let\dollar_tilde\sandbox_dollar} %% If a tilde `~' has been used instead of `$', the default %% is restored. \def\sandbox_dollar{$} \let\dollar_tilde\sandbox_dollar %% The following general tool |\make_not_expanding_cs| has been used %% (many definitions in 'latex.ltx' could have used it): %% 2009/04/10 \def\make_not_expanding_cs#1{% \expandafter \noexpand \csname #1\endcsname} %% %% === Getting rid of the tildes === %% |\let~\TildeGobbles| can be used to suppress dummy patterns %% (contained in ) %% in `\write'ing or with `\edef'. ... will probably become obsolete %% ... however, it is helpful in that you needn't care %% whether there is a dummy wrap left at all. (2009/04/13) \newcommand{\TildeGobbles}{} \def\TildeGobbles#1${} %% |\RemoveDummyPattern| is used to remove the dummy pattern %% \emph{immediately}, not waiting for `\write'ing %% or other ``total" expansion: %% 2009/04/13 \newcommand{\RemoveDummyPattern}{} \def\RemoveDummyPattern#1~#2${#1} %% |\RemoveDummyPatternArg{}| executes %% `\RemoveDummyPattern' in the next argument: \newcommand*{\RemoveDummyPatternArg}[2]{% \expandafter #1\expandafter {\RemoveDummyPattern #2}} %% |\RemoveTilde| is used to remove the tilde that separated %% the dummy pattern from . % %% An alternative policy is to pass % %% (as an argument) to the parsing macro. \newcommand{\RemoveTilde}{} \def\RemoveTilde#1~{#1} %% |\RemoveTildeArg{}| executes `\RemoveTilde' %% in the next argument: \newcommand*{\RemoveTildeArg}[2]{% \expandafter #1\expandafter {\RemoveTilde #2}} %% %% === Calling conditionals === %% |\ProcessStringWith{}{}| builds the sandbox %% to search for the associated with the %% parser-conditional that is identified by , the sandbox then %% calls the parser. \newcommand*{\ProcessStringWith}[2]{% \csname \setup_substr_cond #2\endcsname{#1}} %% |\ProcessExpandedWith{}{}| does the same but with %% a \emph{macro} (like `\fdInputLine' or `\OutputString') in which %% the string to be tested is stored. \newcommand*{\ProcessExpandedWith}[2]{% \csname \setup_substr_cond #2\expandafter \endcsname \expandafter{#1}} %% I would have preferred the reversed order of arguments which seems %% to be more natural, but the present is more efficient. %% Macros with reversed order are currently stored after `\endinput' %% in section~\ref{sec:pondered}, may be they once return. %% %% Anyway, most desired will be |\ProcessInputWith{}| just %% applying to `\fdInputLine': \newcommand*{\ProcessInputWith}[1]{% \csname \setup_substr_cond #1\expandafter \endcsname \expandafter{\fdInputLine}} %% (Definition almost copied for efficiency.) %% TODO: error when undefined 2009/04/07 %% %% === Copy jobs === %% A job identifier may also be considered a mere \emph{hook}, %% a \emph{placeholder} for a parsing job. What function actually is %% called may depend on conditions that change while reading the %% file. %%% On a certain condition, %% |\CopyFDconditionFromTo{}{}| %% \emph{creates or redefines a sandbox builder} with identifier %% that afterwards behaves like the sandbox builder . %% So you can store a certain behaviour as in advance in order %% once to change the behaviour of into that of . \newcommand*{\CopyFDconditionFromTo}[2]{% \expandafter \let \csname \setup_substr_cond #2\expandafter \endcsname \csname \setup_substr_cond #1\endcsname} %% (Only the \emph{sandbox} is copied here---what about %% changing conditionals?) %% TODO %% %% An ``almost" example is typesetting documentation from a package %% file where the ``Legalese" header might be typeset verbatim %% although it is marked as ``comment." (The present %% 2009/04/07 %% example changes ``hand-made" macros instead.) %% %% This feature could have been placed more below as a ``programming %% tool." %% %% == Programming tools == %% === Tails of conditionals === %% \label{sec:tails} %% When creating complex \emph{expandable} conditionals, %% this may amount to have primitive `\if' ... `\fi' conditionals %% nested quite deeply, once perhaps too deep for \TeX's memory. %% To avoid this, you can apply the common `\expandafter' trick %% which finishes the current `\if' ... `\fi' before an inside %% macro is executed (cf. \TeX book p.~219 on ``tail recursion"). %% %% Internally tests whether certain strings are present at certain %% places will be carried out by tests on emptiness or %% %% onwards) %% !? 2009/12/28 %% on starting with `~'. E.g., %% ``#1~=~ empty" indicates that either the %% starts a line or the line is empty altogether (this must be %% decided by another test). %% %% |\IfFDempty{}{}{}| %% is used to test on emptyness (without expanding it): \newcommand*{\IfFDempty}[1]{% \ifx$#1$\expandafter \@firstoftwo \else \expandafter \@secondoftwo \fi} %% |\IfFDinputEmpty{}{}| is a variant of %% the previous to execute if the loop processing %% finds an empty line---otherwise . \newcommand*{\IfFDinputEmpty}{% \ifx\fdInputLine\@empty \expandafter \@firstoftwo \else \expandafter \@secondoftwo \fi} %% |\IfFDdollar{}{}{}| %% is another variant, testing for being `$', %% main indicator of there is a match anywhere in %% (as opposed to starting or ending match): \newcommand*{\IfFDdollar}[1]{% \ifx$#1\expandafter \@firstoftwo \else \expandafter \@secondoftwo \fi} %% It is exemplified and explained in section~\ref{sec:replchain}. %% (The whole policy requires that `~' remains active in any %% testing macros here!) %% %% However, you might always just type the replacement text %% (in one line) instead of %% such an `\If'\,... (for efficiency \dots) %% %% If expandability is not desired, you can just chain macros that %% rework (so re-define) `\OutputString' or so. %% %% 2009/04/11: tending towards combining ... %% Keeping empty input and empty arguments apart is useful in that %% \emph{one} test of emptiness per input line should suffice---it %% may be left open whether this should be the first of all tests %% \dots %% %% === Line counter === %% A \LaTeX\ counter |fdInputLine| may be useful for screen or log %% messages, moreover you can use it to control processing of the %% file ``from outside," not dependent on what the parsing %% macros find. The header of the file might be typeset verbatim, %% but we may be too lazy to define the ``header" in terms of %% what is in the file. We just decide that the first ... lines %% are the ``header," even without counting just trying whether %% the output is fine. It may be necessary to change that number %% manually when the header changes. %% %% You also can insert lines in %% which have no counterpart in ---if you know what you are %% doing. With 'makedoc', there is a hook `\EveryComment' that can %% be used to issue commands ``from outside" at a place where %% executing the command is safe or appropriate. \newcounter{fdInputLine} %% You then must insert |\CountInputLines| in the second argument %% of `\ProcessFileWith' (or in a macro called from there) %% so that the counter is stepped. %% TODO!? 2009/04/07 \newcommand*{\CountInputLines}{\global\advance\c@fdInputLine\@ne} %% At present %% 2009/04/07 TODO %% the counter is reset by `\ProcessFileWith', this may change. %% %% |\IfInputLine{}{}{}|, when called %% from the processing loop (second argument of `\ProcessFileWith') %% issues commands if `\value{fdInputLine}' %% is true, otherwise . may usually be just `='. \newcommand*{\IfInputLine}[1]{% \ifnum\c@fdInputLine#1\relax \expandafter \@firstoftwo \else \expandafter \@secondoftwo \fi} %% %% === The ``identity job" `LEAVE' === %% \label{sec:LEAVE} %% The job with identifier |LEAVE| %% \emph{leaves} an (expandable) chain of jobs %% (as expandable replacement in section~\ref{sec:replchain}) %% and \emph{leaves} the processed string without changing it %% and without the braces enclosing it: \expandafter \let \csname \setup_substr_cond LEAVE\endcsname \@firstofone %% I.e., `\ProcessStringWith{}{LEAVE}' expands to %% ... \ProcessStringWith{(Indeed!)}{LEAVE} %% == Setup for expandable chains of replacements == %% \label{sec:replchain}%% TODO makedoc: provide less visible label/ref 2009/04/11 %% By the following means, you can create macros %% (`\Transform' among them) such that, e.g., %% \[`\edef\OutputString{\Transform{}}'\] renders `\OutputString' %% the result of applying a chain (sequence) of stringwise replacements %% to . %% You can even write a transformed input to a file %% without defining anything anything after `\read to'\,.\,.\,. %% In this case however, you don't get any statistical message %% about what happened or not. With `\edef\OutputString' you can at %% least issue some `changed!' or `left!' (maybe `\message{!}' vs.\ %% `\message{.}'). %% There is an application in 'makedoc' for ``typographical upgrading" %% from plain text to \TeX\ input. %% %% |\repl_all_chain_expandable| will be the backbone of the %% replacements. It is called by some parsing macro %% and receives from the latter ~=~#1 and ~=~#2. %% #3 is the result of what happened so far. \def\repl_all_chain_expandable#1#2#3#4#5#6{% %% #1, #2 splits, #3 past, #4 substitute, %% #5 repeat parser, #6 pass to % \ifx~#2\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi %% The previous line would be somewhat faster, but let us exemplify %% `\IfFDdollar' from section~\ref{sec:tails} instead: \IfFDdollar{#2}% %% If #2 starts with `$'---with category code 3, ``math shift"!, %% it \emph{is} `$', due to not reading `$' %% from input with its standard category code 3 %% and the sandbox construction (where `$' appears with its standard %% category code). %% TODO might be explained earlier 2009/04/11 %% %% or refer to here. %% And this is the case \emph{exactly} when the from %% didn't match, again due to the input category codes. %% Now on \emph{no} match, the sandbox builder #6 is called %% with target string #3#1 where the last tested string is attached %% to previous results. The ending `~' is removed, #6 inserts a new %% wrap for the new dummy pattern. {\RemoveTildeArg #6{#3#1}}% %% Otherwise ... the \emph{sandbox builder} %% (that will be shown below) that called %% initialized #5 to be that itself. ( otherwise %% wouldn't know who it is.) So calls itself with another sandbox %% `#2&'. Note that #2 contains \lq`~$'\rq\ due to the initial %% building. {#5#2&{#3#1#4}{#4}#5#6}} %% #4 is the replacement string that passed to . %% The first argument after the `&' is previous stuff plus %% the recently skipped %% plus #4 replacing the string that was matched. %% %% Finally, #5 and #6 again ``recall" and the sandbox %% builder to which to change in case of no other match. %% %% \pagebreak[3] %% 2010/03/22 %% % TODO move following up!? 2009/04/11 %% \[|\MakeExpandableAllReplacer{}[]{}{}{}|\] %% creates sandbox and parser with common identifier and search %% pattern . Each occurrence of will be replaced by %% . When is not found, the sandbox builder for %% is called. This may be another replacing macro of the %% same kind. To return the result without further transformations, %% call job `LEAVE' (section~\ref{sec:LEAVE}). %% Optional argument changes category codes locally %% for reading and . %% %% <- added , -> 2010/03/19 \newcommand*{\MakeExpandableAllReplacer} {\StartFDsetup\mk_setup_xpdbl_all_repl} \newcommand*{\mk_setup_xpdbl_all_repl}[3]{% %% #1 pattern, #2 substitute, #3 pass to \endgroup %% We take pains to call next jobs by single %% command strings and store them this way, not by `\csname', %% as `\ProcessStringWith' would do it. `\edef\@tempa' %% is used for this purpose, but \dots \edef\@tempa{% \noexpand\mk_setup_substr_cond{#1}{% {}{#2}% \noexpand\noexpand %% That `\edef\@tempa' must \emph{not expand} the controll %% words after they have been computed from `\csname' etc. %% Moreover, expansion of the parser commands %% must be avoided another time, when `\@tempa' is executed. \make_not_expanding_cs{\substr_cond\fdParserId}% \noexpand\noexpand \make_not_expanding_cs{\setup_substr_cond #3}}}% %% Those internal setup commands start with `\endgroup' to switch back %% to standard category codes. We must match them here by %% `\begingroup'. \begingroup \@tempa \begingroup \mk_substr_cond{#1}{% \repl_all_chain_expandable{##1}{##2}}} %% The final command is the one that we explained first. %% TODO 2009/04/11 %% %% \[|\PrependExpandableAllReplacer{}[]{}{}|\] %% is hoped to be a slight relief in composing replacement chains. %% It does something like invoking `\MakeExpandableAllReplacer' %% with for the last argument %% where is the of the job that was set up most %% recently. If you have adjacent lines %% \begin{quote} %% \leavevmode\hbox to 0pt\bgroup %% `\MakeExpandableAllReplacer{}{}{}{LEAVE}'% %% \hss\egroup \\ %% `\PrependExpandableAllReplacer{}{}{}'\\ %% `\PrependExpandableAllReplacer{}{}{}' %% \end{quote} %% and call , it will call , and the latter will call %% . So you can reorder the chain my moving `\Prepend'... lines. \newcommand*{\PrependExpandableAllReplacer}{% \let\fdParserId_before\fdParserId \StartFDsetup\prep_xpdbl_all_repl} \newcommand*{\prep_xpdbl_all_repl}[2]{% \mk_setup_xpdbl_all_repl{#1}{#2}{\fdParserId_before}}% %% %% == Leave package mode == %% We restore the underscore `_' for math subscripts. %% (This might better depend on something \dots) %% TODO 2009/04/07 \catcode`\_=8 %% restores underscore use for subscripts %% \endinput %% \TeX\ ignores the rest of the file when it is \emph{input} %% ``in the sense of `\input'", as opposed to just reading %% the file line by line to a macro like `\fdInputLine'. %% %% == Pondered == %% \label{sec:pondered} %% TODO abbreviated commands (aliases) \MkSubstrCond... %% TODO \@onlypreamble!? \newcommand*{\ApplySubstringConditional}[1]{% %% #1 identifier; text to be searched expected next \csname setup_substr_cond:#1\endcsname} \newcommand*{\ApplySubstringConditionalToExpanded}[1]{% 2009/03/31+ \csname setup_substr_cond:#1\expandafter \endcsname \expandafter} \newcommand*{\ApplySubstringConditionalToInputString}[1]{% 2009/03/31+ \csname setup_substr_cond:#1\expandafter \endcsname \expandafter {\fdInputLine}} %% TODO or `\OutputString', even `\read' to `\OutputString'!? % \newcommand*{\ApplySubstringConditionalToExpanded}[2]{% % %% note: without assignments, robust! % %% BUT the `\csname ... \expandafter \endcsname' method is faster % \expandafter \reversed_apply_substr_cond % \expandafter {#2}{#1}} % \newcommand*{\reversed_apply_substr_cond}[2]{% % \ApplySubstringConditional{#2}{#1}} %% ODER: % \newcommand*{\expand_attach_arg}[2]{%% 2009/03/31 % %% #1 command with previous args, TODO cf. LaTeX3 % \expandafter \attach_arg \expandafter {#1}{#2}} % %% actually #1 may contain more than one token, % %% only first expanded % \newcommand*{\attach_arg}[2]{#2{#1}} % \newcommand*{\ApplySubstringConditionalToExpanded}[2]{% % \expandafter \attach_arg \expandafter % {#2}{\ApplySubstringConditional{#1}}} %% %% %% %% == VERSION HISTORY == %% v0.1 2009/04/03 very first version, tested on morgan.sty v0.2 2009/04/05 counter fdInputLine, \ProvidesFile moved from \ProcessFile to \ResultFile, \CopyFD..., category section first, more sectioning, suppressing empty code lines before section titles; discussion, \Delimiters 2009/04/06 more discussion 2009/04/07 more discussion, factored \WriteProvides out from \ResultFile, \ProcessExpandedWith corrected 2009/04/08 \InputString -> \fdInputline; removed \ignorespaces 2009/04/09 \WhenInputLine[2] -> \IfInputline[3], \ProcessInputWith, typos, \WriteProvides message `with' 2009/04/10 \make_not_expanding_cs DISCOVERED ``IF SUBSTRING" ALGORITHM WRONG ( in ) v0.3 2009/04/11 SOME THINGS GIVEN UP EARLIER WILL BE REMOVED, TO BE STORED IN THE COPY AS OF 2009/04/10 mainly: sandbox setup (tilde/dollar) REAL ADDITION: setup for expandable replacing 2009/04/12 played with `chain' vs. `sequence'; plain `...', `cf.', `etc.' for `mdcorr.cfg' 2009/04/13 \RemoveTilde... 2009/04/15 reworked text, same mistake \in@ v0.31 2009/04/21f. comments on ted, stringstrings 2009/12/28 "onwards)" !? "safer", not "more safe" 2010/03/10 the loop starts 2010/03/17 corr. t^ete; set up -> setup for 2010/03/18 TODO EOF, ctan.org/pkg/newfile; non-ASCII 2010/03/19 extended description of \MakeExpandableAll...; '' -> " 2010/03/20 \ctanpkgref 2010/03/22 \StartFDsetup, \Prepend... 2010/03/23 URL for `substr.sty' TODO: cleveref 2010/03/18