% \iffalse meta-comment %<*COPYRIGHT> %% Copyright (C) 2011 by Martin Scharrer %% --------------------------------------------------------------------------- %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of LaTeX %% version 2005/12/01 or later. %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Martin Scharrer. %% %% This work consists of the files filemod.dtx and filemod.ins %% and the derived filebase filemod.sty. % % \fi % % \iffalse %<*dtx> \begingroup % %<*install> \input docstrip.tex \keepsilent \askforoverwritefalse \generate{% \file{filemod.sty} {\nopreamble\from{filemod.dtx} {COPYRIGHT,package,parse,exp,exe,display,aux,latex}}% \file{filemod.tex} {\nopreamble\from{filemod.dtx} {COPYRIGHT,package,parse,exp,exe,display,aux,tex}}% \file{filemod-expmin.sty} {\nopreamble\from{filemod.dtx} {COPYRIGHT,expmin,latex}}% \file{filemod-expmin.tex} {\nopreamble\from{filemod.dtx} {COPYRIGHT,expmin,tex}}% } % %\endbatchfile %<*dtx> \endgroup % % \fi % % \iffalse %<*dtx> \ProvidesFile{filemod.dtx}[% % %<*latex> %\ProvidesPackage{filemod}[% %\ProvidesPackage{filemod-expmin}[% %<*dtx|package|expmin> 2011/03/24 v1.1 % %<*dtx|package> Get and compare file modification times] % % Get and compare file modification times (expandable; minimal)] % % %<*dtx> \documentclass{ydoc} \usepackage{filemod}[2011/03/24] \usepackage{multicol} \usepackage{csquotes} \usepackage{tgpagella} \usepackage{dtklogos} \MakeShortMacroArgs\`\relax \EnableCrossrefs \CodelineIndex \RecordChanges \setcounter{tocdepth}{2} \begin{document} \DocInput{filemod.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % % \CheckSum{765} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v1.0}{2011/03/23}{First release} % \changes{v1.1}{2011/03/24}{Added Lua(La)TeX and plain eTeX support.} % % \DoNotIndex{\newcommand,\newenvironment} % % \GetFileInfo{filemod.dtx} % \author{Martin Scharrer} % \email{martin@scharrer-online.de} % \maketitle % % \begin{abstract} % This package provides macros to read and compare the modification dates of files. These files can be |.tex| files, % images or other files as long as they can be found by the \LaTeX\ compiler. It uses the |\pdffilemoddate| primitive % of pdf\LaTeX\ to receive the file modification date as PDF date string, parses it and returns the value to the user. % The functionality is provided by purely expandable macros or by faster but non-expandable ones. % % This package will work with \LaTeX{} and plain \eTeX{} as long pdf\LaTeXTeX{} (in PDF or DVI mode) or Lua\LaTeXTeX{} % is used. \XeTeX{} is not supported because it does not provide |\pdffilemoddate|. % \end{abstract} % % \begin{multicols}{2} % \tableofcontents % \end{multicols} % % \section{Introduction} % This package provides several macros to read and compare the modification dates of files. The same functionality is % provided by two groups of macros: The macros of the first group all start with a lower case letter and are fully % expandable. This means they can be used in places where a string must be provided, like in `|\input`. Because % assignments are not expandable some of these macros, like the ones for comparisons, need to reread and re-parse the % file modification dates if they are required in more than one place inside the macro. The macros of the second group % all start with a upper case letter and are not expandable because assignments are used internally. However, this % allows techniques which speed up the processing of these macros, making this macros faster than the expandable % counterparts. If expandability is not required these macros should be preferred. % % % \section{Usage} % This package can be loaded with \LaTeX{} using |\usepackage{filemod}| as usual. % With plain \eTeX{} it can be loaded using |\input filemod|. % Some required internal \LaTeX{} macros (like |\@gobble|, |\@firstofone|, etc.) are then defined. % % A minimal set of expandable macros for the comparison of file modification dates is provided by the sub-package % \pkg{filemod-expmin}. It is useful for other packages which need this functionality but don't like to load the whole package. % It can be loaded using |\usepackage{filemod-expmin}| (or |\RequirePackage|) or |\input filemod-expmin|, respectively. % % % \subsection{Print File Modification Date and Time} % The following macros can be used to print (i.e.\ typeset) the file modification date and time of files in the % document. The \Macro\formatdate and \Macro\formattime macros of the \pkg{datetime}\footnote{CTAN: % \url{http://www.ctan.org/pkg/datetime}} can be used in addition to format the dates and times in a language specific % format. See also the \pkg{getfiledate}\footnote{CTAN: \url{http://www.ctan.org/pkg/getfiledate}} package which also % prints file modification dates including adding fancy frames around it. % % \DescribeMacro{\filemodprint}{<\/filename>} % Prints the file modifications date and time using `|\filemodparse` and `|\thefilemod`. % % % \DescribeMacro{\filemodprintdate}{<\/filename>} % Prints the file modifications date using `|\filemodparse` and `|\thefilemoddate`. % % % \DescribeMacro{\filemodprinttime}{<\/filename>} % Prints the file modifications time using `|\filemodparse` and `|\thefilemodtime`. % % % \DescribeMacro{\thefilemod} % Reads the date and time as seven arguments and typesets it. This macro can be redefined to a custom format.\\ % By default it simple uses `|\thefilemoddate` and `|\thefilemodtime` separated by `|\filemodsep` (a space by default): % \enquote{\filemodprint{\jobname.dtx}} % % % \DescribeMacro{\thefilemoddate} % Receives the date as three arguments YYYY, MM and DD and typesets it. This macro can be redefined to a custom format.\\ % Default format: \enquote{\filemodprintdate{\jobname.dtx}} % % It could be redefined to use the `|\formatdate` macro of the \pkg{datetime}:\\ % |\renewcommand*{\thefilemoddate}[3]{\formatdate{#3}{#2}{#1}}| % % % \DescribeMacro{\thefilemodtime} % Receives the time and timezone as four arguments HH, mm, SS and TZ and typesets it. This macro can be redefined to a custom format.\\ % Default format: \enquote{\filemodprinttime{\jobname.dtx}} % % It could be redefined to use the `|\formattime` macro of the \pkg{datetime}:\\ % |\renewcommand*{\thefilemodtime}[4]{\formattime{#1}{#2}{#3}}| % % % % % \subsection{Get File Modification Date and Time as Number} % The following macros return both the file modification date and time as an integer number which is in the valid range for \TeX. % They can be used for numerical operations and are used internally by the comparison macros. % % \DescribeMacro{\filemodnumdate}{<\/filename>} % Expands to an integer of the form |YYYYMMDD| which can be used for numeric comparisons like `|\ifnum`. % This macros uses `|\filemodparse` and `|\filemodnotexists` will be used if the file does not exist. % % \DescribeMacro{\filemodnumtime}{<\/filename>} % Expands to an integer of the form |HHmmSS| which can be used for numeric comparisons like `|\ifnum`. % This macros uses `|\filemodparse` and `|\filemodnotexists` will be used if the file does not exist. % % \DescribeMacro{\filemodNumdate}{<\/filename>} % Expands to an integer of the form |YYYYMMDD| which can be used for numeric comparisons like `|\ifnum`. % Parses the file modification date by itself and will return |00000000| if the file does not exist. % % \DescribeMacro{\filemodNumtime}{<\/filename>} % Expands to an integer of the form |HHmmSS| which can be used for numeric comparisons like `|\ifnum`. % Parses the file modification date by itself and will return |000000| if the file does not exist. % % % \DescribeMacro{\Filemodgetnum}{<\/filename>} % Stores the file modification date and time as numbers (|YYYYMMDD| and |HHmmSS|) as well the timezone string % into the macros `|\filemoddate`, `|\filemodtime` and `|\filemodtz`. % % % % \subsection{Compare File Modification Date/Time} % The following macros allow the comparison of the file modification date/time of two files. % % \DescribeMacro{\filemodcmp}[]{<\/filename 1>}{<\/filename 2>}{}{}!\optional!{} % This macro compares the file modification date and time of the two given files and expands to the clause of the % newest file. An numerical optional argument can be given to determine the outcome if both files have the exact same % modification date/time (or both do not exists). If `` is 0, no clause will be expanded, i.e.\ the macro expands % to an empty text. If `` is 1 (default) or 2 the macro expands to the corresponding clause. % However if `` is 3, the macro will await a third clause and expands to it if both files modification dates are equal. % % This macro is fully expandable even when the optional argument is used. However, `<\/filename 1>` must not be equal to "[". % % % \DescribeMacro{\filemodCmp}{<\/filename 1>}{<\/filename 2>}{}{} % This is a simpler and therefore faster version of `|\filemodcmp`. It is fully expandable, does not take any optional % arguments and will always expand to the first clause if both file modification dates are equal (or both files do not exist). % The `|\filemodNumdate` and `|\filemodNumtime` macros are used in the comparison. % These three macros are also provided by the sub-package \pkg{filemod-expmin}. % % % \DescribeMacro{\Filemodcmp}[]{<\/filename 1>}{<\/filename 2>}{}{}!\optional!{} % This macro provides the same functionality as `|\filemodcmp`. % It is not expandable but will be processed faster. The optional % argument is processed like normally. % % \DescribeMacro{\FilemodCmp}[]{<\/filename 1>}{<\/filename 2>} % This macro will compare the two file modification dates like `|\Filemodcmp` and `|\filemodcmp` but does not take % the possible clauses as arguments, instead it stores the result into the expandable macro `|\filemodcmpresult` % which then takes `{}!\linebreak[3]!{}` (and also `{}` if `` was 3) as arguments and expand to the one % corresponding to the newest file. % This set of macros gives the user the speed benefit of `|\Filemodcmp` while still be able to use the result in an expandable context. % % % \DescribeMacro{\filemodoptdefault} % Holds the default number (i.e.\ 1) for the optional argument of the previous and following macros. % This macro can be redefined with a number or a numeric expression valid for |\ifcase|. It should not contain any % trailing spaces. Note that some commands only accept 1 or 2 as valid optional argument. % % % % \subsection{Return Newest or Oldest File from a List} % The following macros return the newest or oldest file. % Note that the optional arguments of the following macros should only be either 1 or 2. % If no optional argument is provided the value of `|\filemodoptdefault` is used. % % \DescribeMacro{\filemodnewest}[]{<\/filename 1>}{<\/filename 2>} % Expands the filename of the newest given file or filename `` if both file modification dates are identical. % The catcode of the filenames is not changed. % % \DescribeMacro{\filemodoldest}[]{<\/filename 1>}{<\/filename 2>} % Expands the filename of the oldest given file or filename `` if both file modification dates are identical. % The catcode of the filenames is not changed. % % % \DescribeMacro{\filemodNewest}[]{{<\/filename 1>}{<\/filename 2>}'...'{<\/filename n>}} % Expands the filename of the newest given file. % The filename will have catcode 12 except in the case when only one filename was given which is returned unchanged. % The files are compared in pairs of two in the given order (i.e.\ first 1 and 2 and the result with 3 etc.) % The optional argument `` can be used to indicate which filename should be used if both file modification dates are identical. % % % \DescribeMacro{\filemodOldest}[]{{<\/filename 1>}{<\/filename 2>}'...'{<\/filename n>}} % Expands the filename of the oldest given file. % The filename will have catcode 12 except in the case when only one filename was given which is returned unchanged. % The files are compared in pairs of two in the given order (i.e.\ first 1 and 2 and the result with 3 etc.) % The optional argument `` can be used to indicate which filename should be used if both file modification dates are identical. % % % % \DescribeMacro{\Filemodnewest}[]{<\/filename 1>}{<\/filename 2>} % Same as `|\filemodnewest` just not expandable but faster. % Stores the newer of the two file names in `|\filemodresultfile`. Its file modification date and time is stored % in `|\filemodresultdate` and `|\filemodresulttime`. % The catcode of the filenames is not changed. % % % \DescribeMacro{\Filemodoldest}[]{<\/filename 1>}{<\/filename 2>} % Same as `|\filemodoldest` just not expandable but faster. % Stores the older of the two file names in `|\filemodresultfile`. Its file modification date and time is stored % in `|\filemodresultdate` and `|\filemodresulttime`. % The catcode of the filenames is not changed. % % % \DescribeMacro{\FilemodNewest}[]{{<\/filename 1>}{<\/filename 2>}'...'{<\/filename n>}} % Same as `|\filemodNewest` just not expandable but faster. % Stores the newest of the given file names in `|\filemodresultfile`. Its file modification date and time is stored % in `|\filemodresultdate` and `|\filemodresulttime`. % The catcode of the filenames is not changed. % % % \DescribeMacro{\FilemodOldest}[]{{<\/filename 1>}{<\/filename 2>}'...'{<\/filename n>}} % Same as `|\filemodOldest` just not expandable but faster. % Stores the oldest of the given file names in `|\filemodresultfile`. Its file modification date and time is stored % in `|\filemodresultdate` and `|\filemodresulttime`. % The catcode of the filenames is not changed. % % % % % \subsection{Parsing of the file modification date} % The format returned by the |\pdffilemoddate| primitive is \enquote{\texttt{D:}} followed by a number in the format % \enquote{\texttt{YYYYMMDDHHmmSST}} which needs to be parsed before it is useful. The letters have the following % meaning: \texttt{Y} = year, \texttt{M} = month, \texttt{D} = day, \texttt{H} = hour, \texttt{mm} = minutes, \texttt{S} % = seconds, \texttt{T} or \texttt{TZ} = timezone string. The number of letters indicates the length except for the % timezone which is of variable length. An example is \enquote{\texttt{\pdffilemoddate{\jobname.dtx}}} which is the % file modification date of the source file of this manual. Unfortunately this number is to large for TeX to be taken % as an integer for numerical comparisons, so it is broken into two numbers (\texttt{YYYYMMDD} and \texttt{HHmmSS}) % which are compared in multiple steps. % % \DescribeMacro{\filemodparse}{}{<\/filename>} % Parses the file modification datetime of the given file and passes the result to the given macro. % The macro will receive seven arguments: % \begin{quote} % `{}{}{
}{}{}{}{}` % \end{quote} % i.e.\ year, month, day, hour, minutes, seconds and the timezone as signed offset % or `Z` (catcode 12). % % % \DescribeMacro{\filemodnotexists}{} % This macro will be called by `|\filemodparse` with the original given macro when the given file does not exists. By default % it contains all zeros except `Z` (catcode 12) as timezone: % % \begin{quote} % `!\#1!{0000}{00}{00}{00}{00}{00}{Z}` % \end{quote} % The user can redefine this macro to a different content, e.g.\ to a different fall-back value or to display a warning. % Note if this macro contains non-expandable code the macros which uses it aren't expandable anymore. % % % % \subsection{Auxiliary Macros} % % \DescribeMacro{\filemodZ} % Defined to "Z" with catcode 12 as it is returned as timezone. % This might be useful for comparisons or custom definitions. % % \DescribeMacro{\filemodz} % Let (`|\let`) to "Z" with catcode 12 as it is returned as timezone. % This might be useful for comparisons or custom definitions. % % % \StopEventually{} % % \clearpage % \section{Implementation} % % \iffalse %<*package|expmin> % \fi % % Ensure correct catcode for plainTeX: % \begin{macrocode} %<*tex> \expandafter\edef\csname filemod@cat\endcsname{\noexpand\catcode`\noexpand\@=\the\catcode`\@\relax} \catcode`\@=11 % % \end{macrocode} % % Check if the \Macro\pdffilemoddate command is available. If not (e.g.\ with LuaLaTeX) the \pkg{pdftexcmds} is loaded % to provide the \Macro\pdf@filemoddate replacement. However for XeLaTeX this will fail and an error is raised. % \begin{macrocode} \ifx\filemod@directtrue\@undefined \csname newif\expandafter\endcsname\csname iffilemod@direct\endcsname \filemod@directtrue \ifx\pdffilemoddate\@undefined % \RequirePackage{pdftexcmds} % \input pdftexcmds.sty \filemod@directfalse \ifx\pdf@filemoddate\@undefined \edef\filemod@help {The required command \string\pdffilemoddate\space is not defined. This means that the used\space\space LaTeX compiler does not support it. Please make sure that pdfLaTeX 1.30.0 or\space\space\space newer or LuaLaTeX is used. XeLaTeX does not support reading file modification\space\space dates. }% % \PackageError{filemod}{Required command \string\pdffilemoddate\space is not defined!}{\filemod@help} % \errhelp\expandafter{\filemod@help} % \errmessage{filemod package: Required command \string\pdffilemoddate\space is not defined!} \fi \fi \fi % \end{macrocode} % % \iffalse % % \fi % % \iffalse %<*parse> % \fi % \subsection{Parser} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \begin{macro}{\filemodparse}[2]{Macro or tokens to process result}{file name} % \begin{macrocode} %\newcommand*\filemodparse{} \iffilemod@direct \def\filemodparse#1#2{% \expandafter\filemod@parse\pdffilemoddate{#2}\relax{#1}% } \else \def\filemodparse#1#2{% \expandafter\expandafter \expandafter\filemod@parse\pdf@filemoddate{#2}\relax{#1}% } \fi % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@parse}[2]{Expanded file mod date}{Macro} % \begin{macrocode} \def\filemod@parse#1\relax#2{% \ifx\relax#1\relax \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi {\filemodnotexists{#2}}% {\filemod@parse@#1\empty{#2}\relax}% } % \end{macrocode} % \end{macro} % % % % The "D", ":" and "Z" characters are changed to catcode 12 because this is how they appear in the string % returned by `|\pdffilemoddate`. % \begin{macrocode} \begingroup \catcode`\D=12 \catcode`\Z=12 \catcode`\:=12 % \end{macrocode} % % \begin{macro}{\filemod@parse@}[9]{Y1}{Y2}{Y3}{Y4}{M1}{M2}{D1}{D2}{Rest} % \begin{macrocode} \gdef\filemod@parse@ D:#1#2#3#4#5#6#7#8#9\relax{% \filemod@parse@@{{#1#2#3#4}{#5#6}{#7#8}}#9\relax } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemodnotexists}[1]{Macro provided to \Macro\filemodparse} % Macro which is used for non-existing files. % \begin{macrocode} %\newcommand*\filemodnotexists{} \gdef\filemodnotexists#1{% #1{0000}{00}{00}{00}{00}{00}{Z}% } % \end{macrocode} % \end{macro} % % \begin{macrocode} \endgroup % \end{macrocode} % % % % \begin{macro}{\filemod@parse@@}[9]{\{YYYY\}\{MM\}\{DD\}}{H1}{H2}{m1}{m2}{S1}{S2}{TZ}{Macro} % Reads the rest of the file mod date and places the resulting arguments in front of the given macro. % \begin{macrocode} \def\filemod@parse@@#1#2#3#4#5#6#7#8\empty#9\relax{% #9#1{#2#3}{#4#5}{#6#7}{#8}% } % \end{macrocode} % \end{macro} % % \iffalse % % \fi % % \iffalse %<*expmin> % \fi % % \subsection{Minimal set of expandable Macros} % % % The "D", ":" and "Z" characters are changed to catcode 12 because this is how they appear in the string % returned by `|\pdffilemoddate`. % \begin{macrocode} \begingroup \catcode`\D=12 \catcode`\Z=12 \catcode`\:=12 % \end{macrocode} % % \begin{macro}{\filemodNumdate} % \begin{macrocode} %\newcommand*\filemodNumdate{} \iffilemod@direct \gdef\filemodNumdate#1{% \expandafter\filemod@Numdate\pdffilemoddate{#1}D:00000000000000Z\relax } \else \gdef\filemodNumdate#1{% \expandafter\expandafter \expandafter\filemod@Numdate\pdf@filemoddate{#1}D:00000000000000Z\relax } \fi % \end{macrocode} % \end{macro} % % \begin{macro}{\filemod@Numdate} % \begin{macrocode} \gdef\filemod@Numdate D:#1#2#3#4#5#6#7#8#9\relax{% #1#2#3#4#5#6#7#8% } % \end{macrocode} % \end{macro} % % \begin{macro}{\filemodNumtime} % \begin{macrocode} %\newcommand*\filemodNumtime{} \iffilemod@direct \gdef\filemodNumtime#1{% \expandafter\filemod@Numtime\pdffilemoddate{#1}D:00000000000000Z\relax } \else \gdef\filemodNumtime#1{% \expandafter\expandafter \expandafter\filemod@Numtime\pdf@filemoddate{#1}D:00000000000000Z\relax } \fi % \end{macrocode} % \end{macro} % % \begin{macro}{\filemod@Numtime} % \begin{macrocode} \gdef\filemod@Numtime D:#1#2#3#4#5#6#7#8#9\relax{% \filemod@@Numtime#9\relax } % \end{macrocode} % \end{macro} % % \begin{macro}{\filemod@@Numtime} % \begin{macrocode} \gdef\filemod@@Numtime#1#2#3#4#5#6#7\relax{% #1#2#3#4#5#6% } % \end{macrocode} % \end{macro} % % \begin{macrocode} \endgroup % \end{macrocode} % % \begin{macro}{\filemodCmp} % \begin{macrocode} %\newcommand*\filemodCmp[2]% %\def\filemodCmp#1#2% {% \ifcase0% \ifnum\filemodNumdate{#2}>\filemodNumdate{#1} 1\else \ifnum\filemodNumdate{#2}=\filemodNumdate{#1} % \ifnum\filemodNumtime{#2}>\filemodNumtime{#1} 1\fi \fi \fi \space \expandafter\@firstoftwo \or \expandafter\@secondoftwo \fi } % \end{macrocode} % \end{macro} % % % Some required \LaTeX{} macros for the plain\TeX{} version: % \begin{macrocode} %<*tex> \long\def\@firstoftwo#1#2{#1} \long\def\@secondoftwo#1#2{#2} % % \end{macrocode} % % \iffalse % % \fi % % \iffalse %<*package> % \fi % \begin{macrocode} %\RequirePackage{filemod-expmin} %\input filemod-expmin % \end{macrocode} % \iffalse % % \fi % % \iffalse %<*exp> % \fi % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Expandable Macros} % % \subsubsection{Numeric macros} % % \begin{macro}{\filemodnumdate} % Simply calls the parse macro. % \begin{macrocode} %\newcommand*% %\def \filemodnumdate{\filemodparse\filemod@numdate} % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@numdate}[7]{YYYY}{MM}{DD}{HH}{mm}{SS}{TZ} % \begin{macrocode} % Gobbles everything except "YYYYMMDD" which is returned as number without the braces. \def\filemod@numdate#1#2#3#4#5#6#7{#1#2#3} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\filemodnumtime} % Simply calls the parse macro. % \begin{macrocode} %\newcommand*% %\def \filemodnumtime{\filemodparse\filemod@numtime} % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@numtime}[7]{YYYY}{MM}{DD}{HH}{mm}{SS}{TZ} % Gobbles everything except "HHmmSS" which is returned as number without the braces. % \begin{macrocode} \def\filemod@numtime#1#2#3#4#5#6#7{#4#5#6} % \end{macrocode} % \end{macro} % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsubsection{Optional argument handler} % % \begin{macro}{\filemod@opt}[3]{Macro to read optional argument when present}{Next macro which receives default % optional argument as first normal argument}{\texttt{[} or first mandatory argument} % This macro checks if an optional argument is present. Here |#1| and |#2| are handlers and |#3| is the first balanced % text which followed the macro, i.e.\ either "[" or the first mandatory argument. % The |\ifx| compares "[" and the first token of |#3|. There are three possible cases: % \begin{enumerate} % \item If they do not match everything until and including |\else| is skipped. Then |\remove@to@nnil@exec| is % expanded which removes the following |\@nnil|. This leaves |\empty| and the rest of the \emph{false} clause. The % |\fi| is removed using |\expandafter| and the trailing |{#3}| is read by |#2| as normal argument. % \item If |#3| is exactly "[" the |\ifx[#3| part is removed by \TeX. The |\remove@to@nnil@exec| removes the |\@nnil| % and the |\remove@to@nnil| because there was nothing before |\@nnil|. Therefore |\expandafter#1| is executed which % triggers |\else| which removes everything up to and including |\fi|. Then the optional argument handler |#1| is % expanded which receives the "[" as "{[}" which is then gobbled. % \item The |#3| starts with "[" but contains more material, i.e.\ was original a mandatory argument. Then |\ifx| % expands to the \emph{true} clause and removes the first token of |#3|. The |\remove@to@nnil@exec| gobbles the rest % of |#3| but reads and reinserts |\remove@to@nnil| which gobbles everything to the next |\@nnil| after |\else| and % therefore jumps to the \emph{false} clause. This clause is executed like normal, i.e.\ |#2| is called with the % default optional argument and |{#3}| as second argument. % \end{enumerate} % \begin{macrocode} \def\filemod@opt#1#2#3{% \expandafter \remove@to@nnil@exec \ifx[#3\@nnil\remove@to@nnil \expandafter#1% \else\@nnil\empty \expandafter#2% \expandafter\filemodoptdefault \fi {#3}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\remove@to@nnil@exec}[2]{Tokens to remove}{Following token} % Removes everything to |\@nnil| and executes the next token except if |#1| was empty. % \begin{macrocode} \def\remove@to@nnil@exec#1\@nnil#2{% \ifx\@nnil#1\@nnil\else \expandafter#2 \fi } % \end{macrocode} % \end{macro} % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \subsubsection{Compare file dates} % % \begin{macro}{\filemodcmp} % Compare two file mod dates. % Calls macros to check for an optional argument in an expandable way. % \begin{macrocode} %\newcommand*% %\def \filemodcmp{% \filemod@opt\filemod@cmp@opt\filemod@cmp } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemodoptdefault} % The default optional argument which is used if none is provided. % \begin{macrocode} %\newcommand*% %\def \filemodoptdefault{1} % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@cmp@opt}[2]{"[" wrapped in \{\}}{Content of optional argument} % Removes the brackets from the optional argument. % \begin{macrocode} \def\filemod@cmp@opt#1#2]{% \filemod@cmp{#2}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@cmp} % This saves several |\expandafter|'s in \Macro\filemod@opt. % \begin{macrocode} \def\filemod@cmp{\filemod@@cmp>} % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@@cmp}[4]{Compare sign: \texttt{>} or \texttt{<}}{Optional argument}{File name 1}{File name 2} % Compares the dates and times of the two files. The three cases are (0) file 1 newer than file 2, (1) file 2 newer than file 1, % (2) both files have the same date. % % In (2) the optional argument |#2| determines which clause is executed. % \begin{macrocode} \def\filemod@@cmp#1#2#3#4{% \ifcase0% \ifnum\filemodnumdate{#4}#1\filemodnumdate{#3} 1\else \ifnum\filemodnumdate{#4}=\filemodnumdate{#3} % \ifnum\filemodnumtime{#4}#1\filemodnumtime{#3} 1\else \ifnum\filemodnumtime{#4}=\filemodnumtime{#3} 2\fi \fi \fi \fi \space \csname @firstoft\ifnum#2>2 hree\else wo\fi\expandafter\endcsname \or \csname @secondoft\ifnum#2>2 hree\else wo\fi\expandafter\endcsname \else \csname @% \ifcase#2% gobbletwo% \or firstoftwo% \or secondoftwo% \else thirdofthree% \fi \expandafter \endcsname \fi } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@firstofthree} % Expands to the first of the next three arguments. % \begin{macrocode} \long\def\@firstofthree#1#2#3{#1} % \end{macrocode} % \end{macro} % % % \begin{macro}{\@secondofthree} % Expands to the second of the next three arguments. % \begin{macrocode} \long\def\@secondofthree#1#2#3{#2} % \end{macrocode} % \end{macro} % % Some required \LaTeX{} macros for the plain\TeX{} version: % \begin{macrocode} %<*tex> \long\def\@thirdofthree#1#2#3{#3} \long\def\@gobble#1{} \long\def\@gobbletwo#1#2{} \def\remove@to@nnil#1\@nnil{} % % \end{macrocode} % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \subsubsection{Compare file mod times and return file name} % % % \begin{macro}{\filemodnewest} % First a macro is called to handle an optional argument in an expandable way. % \begin{macrocode} %\newcommand*% %\def \filemodnewest{% \filemod@opt\filemod@newest@opt\filemod@newest } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@newest@opt}[2]{The "[" wrapped in \{\}}{Content of optional argument} % Removes braces around the optional argument. % \begin{macrocode} \def\filemod@newest@opt#1#2]{% \filemod@newest{#2}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@newest}[3]{optional argument}{file name 1}{file name 2} % Uses the normal (internal) compare macro with the file names as the result clauses. % \begin{macrocode} \def\filemod@newest#1#2#3{% \filemod@@cmp>{#1}{#2}{#3}{#2}{#3}% } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{\filemodoldest} % First a macro is called to handle an optional argument in an expandable way. % \begin{macrocode} %\newcommand*% %\def \filemodoldest{% \filemod@opt\filemod@oldest@opt\filemod@oldest } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@oldest@opt}[2]{The "[" wrapped in \{\}}{Content of optional argument} % Removes braces around the optional argument. % \begin{macrocode} \def\filemod@oldest@opt#1#2]{% \filemod@oldest{#2}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@oldest}[3]{optional argument}{file name 1}{file name 2} % Uses the normal (internal) compare macro with the file names as the result clauses. % \begin{macrocode} \def\filemod@oldest#1#2#3{% \filemod@@cmp<{#1}{#2}{#3}{#2}{#3}% } % \end{macrocode} % \end{macro} % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsubsection{Newest and oldest file of a list of files} % % \begin{macro}{\filemodNewest}[1]{Tokens between macros and opening brace} % Checks for an optional argument and substitutes the default if it is missing. % \begin{macrocode} %\newcommand*\filemodNewest{} \def\filemodNewest#1#{% \expandafter\expandafter \expandafter\@filemodNewest \csname @% \ifx\@nnil#1\@nnil first% \else second% \fi oftwo% \endcsname {[\filemodoptdefault]}% {#1}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemodOldest}[1]{Tokens between macros and opening brace} % Like \Macro\filemodNewest but returns the oldest file in the given list. % It and its sub-macros are simply copies of minor changes of the |Newest| counterparts. % This is done for the benefit of expansion speed versus memory usage. % Future versions might use common code instead. % \begin{macrocode} %\newcommand*\filemodOldest{} \def\filemodOldest#1#{% \expandafter\expandafter \expandafter\@filemodOldest \csname @% \ifx\@nnil#1\@nnil first% \else second% \fi oftwo% \endcsname {[\filemodoptdefault]}% {#1}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@filemodNewest}[2]{Optional argument}{File name list} % Removes "[]" from first and braces from the second argument (the filename list). % \begin{macrocode} \def\@filemodNewest[#1]#2{% \@@filemodNewest{#1}#2\filemod@end } % \end{macrocode} % \end{macro} % % \begin{macro}{\@filemodOldest}[2]{Optional argument}{File name list} % Like \Macro\@filemodNewest. % \begin{macrocode} \def\@filemodOldest[#1]#2{% \@@filemodOldest{#1}#2\filemod@end } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@filemodNewest}[2]{Optional argument}{First file name} % Reads the optional argument as |#1| and the first filename as |#2|. % It then reverses the order for the processing loop. % \begin{macrocode} \def\@@filemodNewest#1#2{% \filemod@Newest{#2}{#1}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\@@filemodOldest}[2]{Optional argument}{First file name} % \begin{macrocode} \def\@@filemodOldest#1#2{% \filemod@Oldest{#2}{#1}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@Newest}[3]{First file name}{Optional argument}{Second file name} % Checks if the second filename is the end marker. In this case the first filename is returned (i.e.\ expanded to). % Otherwise expands the compare macro. This is done in one step using |\csname| which is then turned into a string % which |\| is gobbled. Because of the required expandability the |\escapechar| can't be changed. % Finally it calls itself recursively with the expanded result. % \begin{macrocode} \def\filemod@Newest#1#2#3{% \iffilemod@end{#3}% {#1}% {% \expandafter\expandafter \expandafter\expandafter \expandafter\expandafter \expandafter\filemod@Newest \expandafter\expandafter \expandafter\expandafter \expandafter\expandafter \expandafter{% \expandafter\expandafter \expandafter\@gobble \expandafter\string\csname\filemod@@cmp>{#2}{#1}{#3}{#1}{#3}\endcsname}{#2}}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@Oldest}[3]{First file name}{Optional argument}{Second file name} % Like \Macro\filemode@Newest but with different compare operator. % \begin{macrocode} \def\filemod@Oldest#1#2#3{% \iffilemod@end{#3}% {#1}% {% \expandafter\expandafter \expandafter\expandafter \expandafter\expandafter \expandafter\filemod@Oldest \expandafter\expandafter \expandafter\expandafter \expandafter\expandafter \expandafter{% \expandafter\expandafter \expandafter\@gobble \expandafter\string\csname\filemod@@cmp<{#2}{#1}{#3}{#1}{#3}\endcsname}{#2}}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\iffilemod@end}[1]{Next filename or end marker} % Checks if the argument is the \Macro\filemod@end marker. % \begin{macrocode} \def\iffilemod@end#1{% \ifx\filemod@end#1% \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@end} % Unique end marker which would expand to nothing. % Could be replaced with |\@nnil|. % \begin{macrocode} \def\filemod@end{\@gobble{filemod@end}} % \end{macrocode} % \end{macro} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \iffalse % % \fi % % % \iffalse %<*exe> % \fi % % \subsection{Non-Expandable Macros} % The following macros are not expandable but contain assignments which must be % executed. This makes them faster because information can be buffered. % Some of them can return expandable results. % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsubsection{Get Numeric Representation of File Modification Date} % % \begin{macro}{\Filemodgetnum} % \begin{macrocode} %\newcommand*% %\def \Filemodgetnum{\filemodparse\Filemod@getnum} % \end{macrocode} % \end{macro} % % % \begin{macro}{\Filemod@getnum} % \begin{macrocode} \def\Filemod@getnum#1#2#3#4#5#6#7{% \def\filemoddate{#1#2#3}% \def\filemodtime{#4#5#6}% \def\filemodtz{#7}% } % \end{macrocode} % \end{macro} % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsubsection{Compare Two File Modification Dates} % % \begin{macro}{\Filemodcmp}[1]{Optional argument (default: "1")} % Calls \Macro\Filemod@cmp to execute the result at the end. % \begin{macrocode} %<*latex> \newcommand\Filemodcmp[1][1]{% \def\filemod@next{\filemodcmpresult}% \Filemod@cmp{#1}% } % % \end{macrocode} % \end{macro} % % % \begin{macro}{\FilemodCmp} % Calls \Macro\Filemod@cmp to not execute the result at the end. % Instead the user must use \Macro\filemodcmpresult explicitly. % \begin{macrocode} %<*latex> \newcommand\FilemodCmp[1][1]{% \let\filemod@next\empty \Filemod@cmp{#1}% } % % \end{macrocode} % \end{macro} % % % \begin{macro}{\Filemod@cmp}[3]{Optional argument}{File name 1}{File name 2} % Compares both files and defines \Macro\filemodcmpresult so that it expands % to the winning clause. It might be directly executed at the end or not depending % on the definition of \Macro\filemod@next which is set by the user level macros % which use this macro. % \begin{macrocode} \def\Filemod@cmp#1#2#3{% \Filemodgetnum{#2}% \let\filemoddatea\filemoddate \let\filemodtimea\filemodtime \Filemodgetnum{#3}% \ifcase0% \ifnum\filemoddate>\filemoddatea\space1\else \ifnum\filemoddate=\filemoddatea\space \ifnum\filemodtime>\filemodtimea\space1\else \ifnum\filemodtime=\filemodtimea\space2\fi \fi \fi \fi \relax % \end{macrocode} % First file is newer: % \begin{macrocode} \def\filemodresultfile{#1}% \ifnum#1>2\relax \def\filemodcmpresult##1##2##3{##1}% \else \let\filemodcmpresult\@firstoftwo \fi \or % \end{macrocode} % Second file is newer: % \begin{macrocode} \def\filemodresultfile{#2}% \ifnum#1>2\relax \def\filemodcmpresult##1##2##3{##2}% \else \let\filemodcmpresult\@secondoftwo \fi \else % \end{macrocode} % File mod dates are equal. The optional argument determines which clause is used. % \begin{macrocode} \ifcase#1\relax \let\filemodresultfile\empty \let\filemodcmpresult\@gobbletwo \or \def\filemodresultfile{#1}% \let\filemodcmpresult\@firstoftwo \or \def\filemodresultfile{#2}% \let\filemodcmpresult\@secondoftwo \else \let\filemodresultfile\empty \let\filemodcmpresult\@thirdofthree \fi \fi \filemod@next } % \end{macrocode} % \end{macro} % \begin{macro}{\filemodcmpresult} % Defined above. % \end{macro} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsubsection{Compare file mod times and return file name} % % Handlers for optional arguments for plain\TeX{}. % If none is provided the \Macro\filemodoptdefault is used. % \begin{macrocode} %<*tex> \def\filemod@chkopt#1{% \def\filemod@optcmd{#1}% \futurelet\filemod@tok\filemod@@chkopt } \def\filemod@@chkopt{% \ifx[\filemod@tok \expandafter\filemod@readopt \else \expandafter\filemod@optcmd \expandafter\filemodoptdefault \fi } \def\filemod@readopt[#1]{% \filemod@optcmd{#1}% } % % \end{macrocode} % % \begin{macro}{\Filemodnewest} % Simply uses \Macro\FilemodNewest. % \begin{macrocode} %<*latex> \newcommand*\Filemodnewest[3][\filemodoptdefault]{\FilemodNewest[{#1}]{{#2}{#3}}} % %<*tex> \def\Filemodnewest{\filemod@chkopt\Filemod@newest} \def\Filemod@newest#1#2#3{\Filemod@Newest{#1}{{#2}{#3}}} % % \end{macrocode} % \end{macro} % % % \begin{macro}{\Filemodoldest} % Simply uses \Macro\FilemodOldest. % \begin{macrocode} %<*latex> \newcommand*\Filemodoldest[3][\filemodoptdefault]{\FilemodOldest[{#1}]{{#2}{#3}}} % %<*tex> \def\Filemodoldest{\filemod@chkopt\Filemod@oldest} \def\Filemod@oldest#1#2#3{\Filemod@Oldest{#1}{{#2}{#3}}} % % \end{macrocode} % \end{macro} % % % % \begin{macro}{\FilemodNewest} % Uses \Macro\Filemod@est with a different compare sign. % Stores the optional argument for later processing. This avoids the need to pass it around as an argument. % \begin{macrocode} %\newcommand*\FilemodNewest[2][\filemodoptdefault]% %\def\FilemodNewest{\filemod@chkopt\Filemod@Newest} %\def\Filemod@Newest#1#2% {% \def\filemode@tie{#1}% \def\filemod@gl{>}% \Filemod@est#2\filemod@end } % \end{macrocode} % \end{macro} % % % \begin{macro}{\FilemodOldest} % Uses \Macro\Filemod@est with a different compare sign. % Stores the optional argument for later processing. This avoids the need to pass it around as an argument. % \begin{macrocode} %\newcommand*\FilemodOldest[2][\filemodoptdefault]% %\def\FilemodOldest{\filemod@chkopt\Filemod@Oldest} %\def\Filemod@Oldest#1#2% {% \def\filemode@tie{#1}% \def\filemod@gl{<}% \Filemod@est#2\filemod@end } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\Filemod@est}[1]{file name 1} % Initiates the macros with the name, date and time of the first file. % Then the recursive part is called. % \begin{macrocode} \def\Filemod@est#1{% \def\filemodresultfile{#1}% \Filemodgetnum{#1}% \let\filemodresultdate\filemoddate \let\filemodresulttime\filemodtime \Filemod@@est } % \end{macrocode} % \end{macro} % % % \begin{macro}{\Filemod@@est}[1]{Next filename or end marker} % Recursive part. Simple aborts (expands to nothing) if |#1| is the end-marker. % Then the resulting file is in \Macro\filemodresultfile and the date and time are in % \Macro\filemodresultdate and \Macro\filemodresulttime, respectively. % \begin{macrocode} \def\Filemod@@est#1{% \iffilemod@end{#1}{}{% \Filemodgetnum{#1}% \ifcase0% \ifnum\filemoddate\filemod@gl\filemodresultdate\space1\else \ifnum\filemoddate=\filemodresultdate\space \ifnum\filemodtime\filemod@gl\filemodresulttime\space1\else \ifnum\filemodtime=\filemodresulttime\space \ifnum\filemode@tie=1\else 1\fi \fi \fi \fi \fi \else \def\filemodresultfile{#1}% \let\filemodresultdate\filemoddate \let\filemodresulttime\filemodtime \fi \Filemod@@est }% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemod@gl} % Initial value of compare sign. Not really required to be defined here because % it is defined to the required sign every time it is used. % \begin{macrocode} \def\filemod@gl{>} % \end{macrocode} % \end{macro} % % \iffalse % % \fi % % \iffalse %<*display> % \fi % % % \subsection{Display Macros} % % \begin{macro}{\filemodprint} % \begin{macrocode} %\newcommand* %\def \filemodprint{\filemodparse\thefilemod} % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemodprintdate} % \begin{macrocode} %\newcommand* %\def \filemodprintdate{\filemodparse\the@filemoddate} % \end{macrocode} % \end{macro} % % % \begin{macro}{\filemodprinttime} % \begin{macrocode} %\newcommand* %\def \filemodprinttime{\filemodparse\the@filemodtime} % \end{macrocode} % \end{macro} % % % \begin{macro}{\thefilemod} % \begin{macrocode} %\newcommand*\thefilemod[7]% %\def\thefilemod#1#2#3#4#5#6#7% {% \thefilemoddate{#1}{#2}{#3}% \filemodsep \thefilemodtime{#4}{#5}{#6}{#7}% } % \end{macrocode} % \end{macro} % % \begin{macrocode} %\newcommand*\filemodsep{ } %\let\filemodsep\space % \end{macrocode} % % \begin{macro}{\thefilemoddate} % \begin{macrocode} %\newcommand*\thefilemoddate[3]% %\def\thefilemoddate#1#2#3% {#1/#2/#3} % \end{macrocode} % \end{macro} % % % \begin{macro}{\thefilemodtime} % \begin{macrocode} %\newcommand*\thefilemodtime[4]% %\def\thefilemodtime#1#2#3#4% {% #1:#2:#3~#4% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\the@filemoddate} % \begin{macrocode} \def\the@filemoddate#1#2#3#4#5#6#7{% \thefilemoddate{#1}{#2}{#3}% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\the@filemodtime} % \begin{macrocode} \def\the@filemodtime#1#2#3{% \thefilemodtime } % \end{macrocode} % \end{macro} % % \iffalse % % \fi % % \iffalse %<*aux> % \fi % % \subsection{Auxiliary Macros} % % The "Z" characters are changed to catcode 12 because this is how they appear in the string % returned by `|\pdffilemoddate`. % \begin{macrocode} %\newcommand*\filemodZ{} %\newcommand*\filemodz{} \begingroup \catcode`\D=12 % \end{macrocode} % % \begin{macro}{\filemodZ} % Holds "Z" with catcode 12 (\emph{other}) like it is returned by `|\pdffilemoddate`. % Requires use of |\csname| because "Z" isn't a letter at the moment. % \begin{macrocode} \expandafter\gdef\csname filemodZ\endcsname{Z}% % \end{macrocode} % \end{macro} % % \begin{macro}{\filemodz} % \begin{macrocode} \let\filemodz=Z\relax % \end{macrocode} % \end{macro} % % % \begin{macrocode} \endgroup % \end{macrocode} % % \iffalse % % \fi % % Restore catcode for plainTeX: % \begin{macrocode} %<*tex> \filemod@cat \expandafter\let\csname filemod@cat\endcsname\relax % % \end{macrocode} % % \Finale % \endinput