From 9f10616edfed3b801246055ec6d06631ff60f9b1 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Sun, 21 Jun 2020 03:02:27 +0000 Subject: CTAN sync 202006210302 --- macros/generic/namedef/DEPENDS.txt | 1 + macros/generic/namedef/README.md | 73 ++ macros/generic/namedef/namedef.dtx | 1425 +++++++++++++++++++++ macros/generic/namedef/namedef.ins | 90 ++ macros/generic/namedef/namedef.pdf | Bin 0 -> 633001 bytes macros/latex/contrib/apa7/apa7.dtx | 36 +- macros/latex/contrib/apa7/apa7.pdf | Bin 522083 -> 522679 bytes macros/latex/contrib/apa7/samples/longsample.pdf | Bin 196731 -> 196731 bytes macros/latex/contrib/apa7/samples/shortsample.pdf | Bin 64110 -> 64110 bytes macros/latex/contrib/hyperxmp/hyperxmp.dtx | 491 ++++--- macros/latex/contrib/hyperxmp/hyperxmp.pdf | Bin 1326332 -> 1341156 bytes macros/latex/contrib/pict2e/README.md | 3 - macros/latex/contrib/pict2e/p2e-drivers.pdf | Bin 216020 -> 216020 bytes macros/latex/contrib/pict2e/pict2e.dtx | 83 +- macros/latex/contrib/pict2e/pict2e.pdf | Bin 887097 -> 889454 bytes 15 files changed, 2004 insertions(+), 198 deletions(-) create mode 100644 macros/generic/namedef/DEPENDS.txt create mode 100644 macros/generic/namedef/README.md create mode 100644 macros/generic/namedef/namedef.dtx create mode 100644 macros/generic/namedef/namedef.ins create mode 100644 macros/generic/namedef/namedef.pdf (limited to 'macros') diff --git a/macros/generic/namedef/DEPENDS.txt b/macros/generic/namedef/DEPENDS.txt new file mode 100644 index 0000000000..574e1c1ca4 --- /dev/null +++ b/macros/generic/namedef/DEPENDS.txt @@ -0,0 +1 @@ +hard l3kernel diff --git a/macros/generic/namedef/README.md b/macros/generic/namedef/README.md new file mode 100644 index 0000000000..5cf05c4abc --- /dev/null +++ b/macros/generic/namedef/README.md @@ -0,0 +1,73 @@ +# namedef +Named parameters in TeX definitions + +This package allows you to use names rather than numbers in TeX +definitions. Usually a definition would look like: +```tex +\def\SayHello#1% + {Hello, #1!} +``` +which is usually good enough. However sometimes when writing macros the +programmer (I, at least) has a macro with several arguments, and then +adding another argument before `#1` requires changing all the numbers +in the definition: +```tex +\def\Say#1#2% + {#1, #2!} +``` +which again, is usually fine most of the time. But sometimes the +definition is rather long, and has a handful of arguments, so changing +the order requires the programmer to change a lot of `#1` to `#2` in the +code, which is tedious, at best. + +With `namedef` you can prefix your definition with `\named`, then every +parameter should be given a name: +```tex +\named\def\SayHello#[subject]% + {Hello, #[subject]!} +``` +then adding another argument before the existing ones is trivial: +```tex +\named\def\Say#[greeting]#[subject]% + {#[greeting], #[subject]!} +``` +and to change the order of the arguments you just swap `#[greeting]` and +`#[subject]` in the ⟨parameter text⟩. No +other changes required! + +Note that this can be (ab)used for writing macros, but it should +probably be removed for publishing the code. + +--- + +This repository contains the source code `namedef.dtx` and the +installation file `namedef.ins`. To create the package file +`namedef.sty`, run: +``` +tex namedef.ins +``` +and to produce the documentation, run: +``` +pdflatex namedef.ins +``` + +--- + +Copyright (C) 2019--2020 Phelype Oleinik + +This work may be distributed and/or modified under the conditions of +the LaTeX Project Public License, either version 1.3c 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.3c or later is part of all distributions of LaTeX +version 2005/12/01 or later. + +This work is "maintained" (as per the LPPL maintenance status) +by Phelype Oleinik. + +Please send bug reports or feature requests at the project repository: +https://github.com/PhelypeOleinik/namedef +or by e-mail (contact info in the source file). diff --git a/macros/generic/namedef/namedef.dtx b/macros/generic/namedef/namedef.dtx new file mode 100644 index 0000000000..01e2cb8aec --- /dev/null +++ b/macros/generic/namedef/namedef.dtx @@ -0,0 +1,1425 @@ +% \iffalse meta-comment +% Copyright (C) 2019--2020 +% by Phelype Oleinik +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, either version 1.3c 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.3c or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work is "maintained" (as per the LPPL maintenance status) +% by Phelype Oleinik. +% +%<*package> +\def\namedefDate{2020-06-20} +\def\namedefVersion{1.0} +% +%<*driver> +\documentclass[a4paper,full,inline]{l3doc} +\usepackage[T1]{fontenc} +\usepackage{microtype} +\usepackage{namedef} +\usepackage{bookmark} +\usepackage{xcolor} + +\def\TODO#1#{\begingroup\afterassignment\TODODO\let\tmp = } +\def\TODODO{\setbox0=\vbox\bgroup\aftergroup\ENDTODO} +\def\ENDTODO{\endgroup\ignorespaces} + +\begingroup + \lccode`~=`\% + \lowercase{\endgroup + \def\VRBCodes{^^A + \catcode`~=13 + \def~{\%\global\linenofalse}} +} +\makeatletter +\define@key{FV}{labelformat}{% + \def\FV@LabelFormat{#1}% + \ifx\FV@LabelFormat\FV@None + \let\FV@LabelFormat\relax + \fi} +\def\FV@Label@ii[#1]#2\@nil{% + \def\@tempa{#1}% + \ifx\@tempa\empty + \def\FV@LabelBegin{\FV@LabelFormat#2}% + \else + \def\FV@LabelBegin{\FV@LabelFormat#1}% + \def\FV@LabelPositionBottomLine{\@ne}% + \fi + \def\FV@LabelEnd{\FV@LabelFormat#2}} +\makeatother +\DefineVerbatimEnvironment% + {example}{Verbatim} + { + gobble=3, + frame=single, + commandchars=|<>, + codes={\VRBCodes}, + numbers=left, + labelformat=\rmfamily\bfseries, + } +\def\mshow#1{> \string#1=\meaning#1} +\newif\iflineno\linenotrue%\fi +\def\theFancyVerbLine{^^A + \rmfamily + \scriptsize + \color{gray}^^A + \iflineno + \arabic{FancyVerbLine}^^A + \else + \global\addtocounter{FancyVerbLine}{-1}^^A + \fi + \global\linenotrue +} +\pdfstringdefDisableCommands{\let\footnotemark\relax} + +% Substitute lmtt/it by lmtt/sl +\DeclareFontShape{T1}{lmtt}{lc}{it}{<->ssub*lmtt/lc/sl}{} + +\begin{document} + \overfullrule=5pt + \DocInput{\jobname.dtx} +\end{document} +% +% \fi +% +% \GetFileInfo{\jobname.sty} +% +% \title{^^A +% The \pkg{namedef} package\\ +% Named parameters in \TeX{} definitions^^A +% \thanks{This file has version number \namedefVersion, +% last revised \namedefDate.} +% } +% +% \author{^^A +% Phelype H. Oleinik\thanks +% {^^A +% E-mail: +% \href{mailto:phelype.oleinik@latex-project.org} +% {phelype.oleinik\meta{at}latex-project.org}^^A +% }^^A +% } +% +% \date{Released \namedefDate} +% +% \maketitle +% +% \begin{documentation} +% +% \section{Introduction} +% +% This package provides a somewhat dubious, however useful way to make +% \TeX{} definitions using \cs{def} and the like. The usual way to +% define a ``hello world'' macro is |\def\hello#1{Hello #1!}|. Sure, +% this is easy (for people using this package, at least), but sometimes +% I stumbled upon the case where I had a macro defined with something +% like |\def\macro#1#2#3#4#5#6{#6#1#4#3#5#2}| and then I had to, for +% whatever reason, add another argument before |#1|. Oh, the pain. But +% OK, occupational hazard. And then I change my mind and needed to +% revert. This package provides a way to give a semantic meaning to the +% arguments of a definition such that it becomes clearer in meaning and +% easier to change when an argument's identifier defines what it means +% rather than its position in a list. +% +% \subsection{Features} +% +% This package defines a macro, \cs{named}, which acts like a prefix for +% \cs{def} (the same way as \cs{long} and the like), and allows one to +% rewrite the \cs{hello} macro like this: +% |\named\def\hello#[who]{Hello #[who]!}|. Sure, a macro with one +% argument won't see much benefit from it, but as soon as that number +% increases, a better description of the arguments comes in handy. +% +% The package also defines a macro \cs{NamedDelim} which allows the user +% to change the delimiter of the named parameters to their liking. For +% example, after |\NamedDelim //| the example above changes to: +% |\named\def\hello#/who/{Hello #/who/!}|. The default is +% |\NamedDelim []|. +% +% The only dependency of this package is the \LaTeX3 programming layer, +% \pkg{expl3}, thus this package works in any format and engine +% supported by \pkg{expl3}. In \LaTeXe, load it with +% |\usepackage{namedef}|, and in other formats with +% |\input namedef.sty|. +% +% \subsection{Feedback} +% +% Bugs, feature requests, or suggestions are most welcome. You can send +% them by e-mail or to the source code repository at +% \url{https://github.com/PhelypeOleinik/namedef}. +% +% \section{Usage} +% +% \begin{function}{\named} +% \begin{syntax} +% \cs{named}\meta{other~prefixes}\meta{\cs[no-index]{(e,g,x)def}}^^A +%\meta{parameter text}\marg{replacement text} +% \end{syntax} +% The \cs{named} macro will grab the \meta{other~prefixes}, the +% \cs{def} command, the \meta{parameter~text} and +% \meta{replacement~text}, and will replace every ocurrence of +% |#[|\meta{text}|]| by a suitable |#|\meta{number} for \TeX{} to +% carry on with the definition. +% +% The \meta{other~prefixes} can be any combination of \cs{long}, +% \cs{outer}, \cs{global}, and \cs{protected}. As for \TeX, their +% relative order doesn't matter, except that \cs{named} must appear +% \emph{before} any \cs{global} prefix. Other prefixes are detected +% whether placed before or after \cs{named}. +% +% The \cs{def} command can be anything. The package will not check the +% validity of the command, it will simply drag the token along until +% the point where the definition is made. This allows one to use any +% of \TeX's primitive \cs{def} commands as well as, for instance, +% \pkg{expl3}'s \cs{cs_new:Npn} or the like. However \cs{named} will +% not work with \LaTeX's \cs{newcommand} or \pkg{xparse}'s +% \cs{NewDocumentCommand} and the like because their syntax is +% completely different. +% +% The \meta{parameter~text} is the same \meta{parameter~text} that +% would be used if the \cs{named} prefix wasn't used with the +% difference that all |#|\meta{number} must be replaced by a +% |#[|\meta{name}|]|. The characters |[| and |]| are mandatory and the +% character |]| cannot appear in \meta{name}, however |[| and |]| can +% still appear in the \meta{parameter~text} without restriction; the +% special meaning is only applied after a parameter token (|#|). +% \meta{name} can be anything that when fully expanded returns a +% string of characters (anything valid in |\csname|\dots|\endcsname|). +% The \meta{parameter~text} cannot, however, contain numbered +% parameters anymore (|#1|,~|#2|,~\dots). +% \TODO{This is not enforced... What should be done in this case?} +% +% The \meta{replacement~text} is also the same \meta{replacement~text} +% that would be used otherwise, with all |#|\meta{number} replaced by +% |#[|\meta{name}|]|. +% \end{function} +% +% \begin{function}{\NamedDelim,\globalNamedDelim} +% \begin{syntax} +% \cs{NamedDelim}\meta{begin-token}\meta{end-token} +% \cs{globalNamedDelim}\meta{begin-token}\meta{end-token} +% \end{syntax} +% These macros change the delimiter of the named parameters from the +% default |#[|\meta{name}|]| to +% |#|\meta{begin-token}\meta{name}\meta{end-token}. Both delimiters +% must be one single non-macro token. Valid delimiters are character +% tokens with catcode $3$, $4$, $7$, $8$, $11$, $12$, or $13$ +% (see section~\ref{sec:delimiters}). +% +% \cs{globalNamedDelim} is the same as \cs{NamedDelim} except that the +% effect of the former has global scope, while the latter is local to +% a group. While you can use both, you should be careful not to +% interleave them too much or you might exhaust \TeX's save stack. +% +% Delimiters are matched based on their character code (using \cs{if}) +% so changes in their category code doesn't matter as long as that +% change doesn't prevent the character from becoming a token or the +% category code isn't \enquote{too special} :-) \quad (see above). +% +% The choice of delimiter is mostly ``what you like better''. Neither +% the delimter tokens nor the name of the parameter make it to the +% macro itself. They are just code-level abstractions. Thus the +% delimiter should be something that the person writing the code can +% easily distinguish from the rest of the code. For example, the code +% |\NamedDelim xz \named\def\test#xyz{xyz#xyzxyz}| works, but its +% readability is questionable. +% \end{function} +% +% \subsection{Limitations} +% +% As already stated the command does not work (and I don't intend to +% make it work) with \LaTeXe's \cs{newcommand} and its family because +% a) the argument specification is by the number of arguments, so you +% can't ``declare'' them as with \cs{def}, and b) because it's supposed +% to be used for user-level interfaces, which usually (and preferably) +% have a low argument count, so numbering shouldn't be a problem. +% That said, see section~\ref{sec:newcommand}. +% +% For \pkg{xparse}'s \cs{NewDocumentCommand} the situation is the same. +% Other than these, \cs{named} should work for whatever type of +% definition that uses \TeX's \cs{def} syntax. +% +% Another limitation that I'd like to change in a future release (but +% still don't know the best way to make the interface) is to support +% definition commands which go beyond the +% \meta{parameter~text}|{|\meta{replacement~text}|}| syntax. For +% instance, in \pkg{expl3} a conditional that checks whether its +% argument is negative can be defined like this (for integers, of +% course): +% \begin{Verbatim} +% \prg_new_conditional:Npnn \namedef_if_negative:n #1 { T, F, TF } +% { +% \if_int_compare:w #1 < 0 +% \prg_return_true: +% \else: +% \prg_return_false: +% \fi: +% } +% \end{Verbatim} +% And if one tried to use \cs{named} in that definition it would fail +% because this command takes one extra argument before the +% \meta{replacement~text}. Something could be done to allow one (or +% more) extra argument before the \meta{replacement~text}. +% +% \medskip +% One serious limitation is when used with definitions that expand their +% argument, namely \cs{edef} and \cs{xdef}. This type of definition +% expands tokens as it reads them, possibly changing their meaning +% during the process. \cs{named}, however, first grabs the definition as +% argument to process the named arguments before actually performing the +% definition, so these ``unexpected'' changes of meaning might make the +% code misbehave. While writing this manual I could think of two (and a +% half) situations which will be problematic and how to work around them +% (sorry, no solution for now; suggestions are welcome :). +% +%^^A \begingroup +% \edef\hash{\string#} +% \edef\¿{\csname @gobble\expandafter\endcsname\string\\} +% \def\nedeft{\ttfamily\¿named\¿edef\¿test} +% +% \subsubsection{\nedeft\{\¿string\#[arg]\}} +% \label{sec:edef wa1} +% +% The normal (no \cs{named}) counterpart of this one is a perfectly +% valid definition: |\edef\test{\string#1}|. While expanding the +% \meta{replacement~text}, \cs{string} turns the parameter token |#|$_6$ +% into a character |#|$_{12}$, thus defining |\test| to expand to the +% two characters |#1|. When using \cs{named}, however, the replacement +% routine doesn't know what \cs{string} does to the token next to it, so +% it goes on and treats |#[arg]| as one named argument only to find out +% that it was never defined in the \meta{parameter~text}, so it aborts +% the definition with an error. +% +% This will occur in the specific case where the user wishes to have the +% macro expand to the characters |#[arg]|, without replacement by a +% parameter. In this case the work-around is to temporarily switch the +% delimiter tokens of \cs{named}'s scanner: +% \begin{Verbatim} +% \NamedDelim|| +% \named\edef\test{\string#[arg]} +% \NamedDelim[] +% \end{Verbatim} +% in which case the scanner will still see the |#| as a parameter token +% but since it is no longer followed by a delimiter, it will be simply +% passed on to the definition. Afterwards, at the time \TeX{} tries to +% carry on with the definition, \cs{string} will do its thing to |#| +% without further problems. +% +% \subsubsection{\nedeft\#[arg]\{\¿string\}\#[arg]\}} +% \label{sec:edef wa2} +% +% This one, as the previous, works fine without \cs{named}: +% |\edef\test#1{\string}#1}|. Again, when \TeX{} scans this definition, +% it will expand \cs{string} which will turn the end group token |}|$_2$ +% into a character |}|$_{12}$, which will have \TeX{} end the definition +% with the next~|}|$_2$, after the |#1|. This only works because \TeX{} +% does not grab the whole thing as argument before expanding. Which is +% precisely what \cs{named} does. +% +% When \cs{named} grabs the definition as argument the first |}| +% ends the \meta{replacement~text}, so what \cs{named} effectively sees +% is |\edef\test#[arg]{\string}|, which is then processed (|#[arg]| is +% replaced by |#1|) and left back in the input stream for \TeX{} to do +% its thing, however the replacement |#[arg]| is never replaced: +% |\edef\test#1{\string}#[arg]}|, then when \TeX{} tries to do the +% definition it will complain about an ``! Illegal parameter number in +% definition of |\test|.'' +% +% The work-around in this case is to do a dirty brace trick to lure +% \cs{named} into grabbing the whole thing as argument, but which will +% disappear at the time \TeX{} performs the expansion and definition. +% One option is |\iffalse{\fi|: +% \begin{Verbatim} +% \named\edef\test#[arg]{% +% \iffalse{\fi \string}#[arg]} +% \end{Verbatim} +% In this example \cs{named} will process everything, but at the time of +% the definition the entire |\iffalse{\fi| thing expands to nothing and +% the final definition becomes the same as the one without \cs{named}. +% The |\iffalse{\fi| block can also be left in the definition +% \emph{without} named and the result will be the same. One could argue +% that using the brace hack is safer because it doesn't change the +% definition, yet avoid problems when grabbing the definition as +% argument in a general situation. +% +% \let\SVsubsec\thesubsubsection +% \def\thesubsubsection{^^A +% \thesubsection .\number\numexpr\value{subsubsection}-1,5} +% +% \subsubsection{\nedeft\#[arg]\{\¿string\{\#[arg]\}} +% \label{sec:edef wa3} +% +% \let\thesubsubsection\SVsubsec +%^^A \endgroup +% +% This is rather similar to the previous one, except that the brace +% later-to-be-detokenized begins a group: |\edef\test#1{\string{#1}|. +% Here \TeX{} also expands \cs{string} and makes |{|$_1$ a |{|$_{12}$ +% which does not count in the brace balancing. \cs{named}, however, will +% count it when grabbing the definition as argument and will require one +% more |}|$_2$. If the code is run as is \TeX{} will probably report a +% ``File ended while scanning use of \dots'' error unless there happens +% to be a matching |}|$_2$ somewhere else, in which case the definition +% will just go wrong. The work-around here is the same as the one +% before, with |}| instead: +% \begin{Verbatim} +% \named\edef\test#[arg]{% +% \string{#[arg]\iffalse}\fi} +% \end{Verbatim} +% This will ensure that \cs{named} will see the |}| it needs to grab the +% definition correctly and will disappear once the definition is done. +% +% \subsection{Invalid delimiters} +% \label{sec:delimiters} +% +% The delimiters that can be used should be character tokens with +% catcode $3$, $4$, $7$, $8$, $11$, $12$, or $13$. Characters with +% catcode $0$, $5$, $9$, $14$, and $15$ don't produce tokens to start +% with, so they can't possibly be used. The remaining category codes +% are currently disallowed in the code because they make the input +% ambiguous or because they make the implementation more complex with no +% real advantage. +% +% Catcodes $1$ and $2$ (begin-/end-group) cannot be used because they +% become indistinguishable from the braces that delimit the +% \meta{parameter~text} of the definition, so the input is ambiguous. +% +% Catcode $6$ (macro parameter) cannot be used because it gets hard to +% distinguish a named parameter from some text surrounded by parameter +% tokens. For example in: |\named\edef\foo#name#{\string#then#name#}|, +% \pkg{namedef} would raise an error on |#then#| (unknown parameter) +% without knowing that the first |#|$_{6}$ becomes |#|$_{12}$ and the +% actual parameter is |#name#|\dots Or is it? I'm not entirely convinced +% of my own argument, so this might be implemented in the future. +% +% Catcode $10$ (blank space) is possible but it requires a hanful of +% extra precautions to avoid losing the space when passing arguments +% around. Since it makes for a strange-looking syntax (our eyes are +% trained to ignore spaces), this is not supported. +% +% \section{Boring examples} +% +% The following examples show two definitions each, which are the same, +% but the second uses \cs{named}. The third line in each example shows +% the \cs{meaning} of the defined macro. +% +% First the basics, replacing a numbered parameter by a named one: +% \named\def\hello#[who]{Hello #[who]!} +% \begin{example}[label=Basics] +% \def\hello#1{Hello #1!} +% \named\def\hello#[who]{Hello #[who]!} +% |mshow|hello +% \end{example} +% \smallskip +% +% Prefixes can be added at will after the \cs{named} prefix: +% \named\protected\long\edef\hello#[who]{Hello #[who]!} +% \begin{example}[label=Prefixes] +% \protected\long\edef\hello#1{Hello #1!} +% \named\protected\long\edef\hello#[who]{Hello #[who]!} +% |mshow|hello +% \end{example} +% \smallskip +% +%^^A Whatever prefixes put before \cs{named} will be lost. Notice that +%^^A even though \cs{protected} is used, the macro itself is not defined +%^^A with \cs{protected}: +%^^A \protected\named\long\edef\hello#[who]{Hello #[who]!} +%^^A \begin{example}[label=Wrong Prefixes] +%^^A \protected \long\edef\hello#1{Hello #1!} +%^^A \protected\named\long\edef\hello#[who]{Hello #[who]!} +%^^A |mshow|hello +%^^A \end{example} +%^^A \smallskip +% +% This example is just to show that the named argument delimiter doesn't +% interfere with the text in the macro: +% \named\def\hello[#[who]]{Hello #[who]!} +% \begin{example}[label=Argument delimited by \texttt{[} and \texttt{]}] +% \def\hello[#1]{Hello #1!} +% \named\def\hello[#[who]]{Hello #[who]!} +% |mshow|hello +% \end{example} +% \smallskip +% +% However, for readability, the delimiter can be changed to something +% else: +% \named\def\hello[#[who]]{Hello #[who]!} +% \begin{example}[label=Argument delimited by \texttt{[} and \texttt{]}, +% commandchars=/<>,firstnumber=0] +% \NamedDelim{|}{|} +% \def\hello[#1]{Hello #1!} +% \named\def\hello[#|who|]{Hello #|who|!} +% /mshow/hello +% \end{example} +% \smallskip +% +% This example demonstrates multiple arguments and arbitrary +% \meta{parameter~text}: +% \named\def\cfbox #[color] to #[width]#[content]{% +% \fbox{\hbox to #[width]{\color{#[color]}#[content]}}} +% \begin{example}[label=More arguments] +% \def\cfbox #1 to #2#3{\fbox{\hbox to #2{\color{#1}#3}}} +% \named\def\cfbox #[color] to #[width]#[content]{% +% \fbox{\hbox to #[width]{\color{#[color]}#[content]}}} +% |mshow|cfbox +% \end{example} +% \smallskip +% +% \TeX's weird |#{| argument can be used as well: +% \named\def\cbox #[color] to #[width]#{^^A +% \hbox to #[width]\bgroup\color{#[color]}\let\next= } +% \begin{example}[label=Weird arguments] +% \def\cbox #1 to #2#{\hbox to #2\bgroup\color{#1}\let\next= } +% \named\def\cbox #[color] to #[width]#{% +% \hbox to #[width]\bgroup\color{#[color]}\let\next= } +% |mshow|cbox +% \end{example} +% \smallskip +% +% {\NamedDelim XX +% \named\xdef\test{\string#[arg]}} +% \begin{example}[commandchars=/<>, label= +% \texttt{\string\edef} workaround \ref{sec:edef wa1}] +% \edef\test{\string#[arg]} +% \NamedDelim || /global/linenofalse +% \named\edef\test{\string#[arg]} /global/linenofalse +% \NamedDelim [] +% /mshow/test +% \end{example} +% \smallskip +% +% \named\edef\test#[arg]{\iffalse{\fi\string}#[arg]} +% \begin{example}[label= +% \texttt{\string\edef} workaround \ref{sec:edef wa2}] +% \edef\test#1{\string}#1} +% \named\edef\test#[arg]{\iffalse{\fi\string}#[arg]} +% |mshow|test +% \end{example} +% \smallskip +% +% \named\edef\test#[arg]{\string{#[arg]\iffalse}\fi} +% \begin{example}[label= +% \texttt{\string\edef} workaround \ref{sec:edef wa3}] +% \edef\test#1{\string{#1} +% \named\edef\test#[arg]{\string{#[arg]\iffalse}\fi} +% |mshow|test +% \end{example} +% \smallskip +% +% \section{Interesting\protect\footnotemark\ examples} +% \footnotetext{Terms and Conditions may apply.} +% +% These examples shows a few more elaborate ways to use \pkg{namedef}. +% +% \subsection{Extended \cs{newcommand}} +% \label{sec:newcommand} +% +% Here's an implementation to allow the syntax of \pkg{namedef} in +% \cs{newcommand}. It uses \pkg{xparse} to handle optional arguments, +% and uses \cs{newcommand} itself to define (possibly) optional argument +% handling, so the resulting command uses \LaTeXe's command parsing +% machinery. +% +% The syntax of the defined command is: +% +% |\newnamedcommand|\meta{*}\cs[no-index]{\meta{cmd}}\oarg{arg-list}^^A +% [\meta{opt}=\meta{default}]\marg{definition} +% +% \noindent where everything is the same as in regular \cs{newcommand}, +% except for the optional arguments \meta{arg-list} and +% \meta{opt}=\meta{default}. \meta{arg-list} should be a +% comma-separated list of named parameters as \cs{named} would expect, +% and \meta{opt} is a named parameter, and \meta{default} is its default +% value. The usage would be something like: +% +% |\newnamedcommand\foo[#[one],#[two]][#[opt]=default]%|\par +% \quad|{#[one], #[two], and #[opt]}| +% +% \noindent which translates to: +% +% |\newcommand\foo[3][default]%|\par +% \quad|{#2, #3, and #1}| +% +% First, load \pkg{xparse} and \pkg{namedef}, and define the top-level +% commands to use a common |\NNC_newcommand:NnNnnn|. +% |\NNC_newcommand:NnNnnn| will store the mandatory arguments in +% a \texttt{seq} variable for easier access, then call +% |\__NNC_newcommand:NnNn| to do the \cs{newcommand} part of the job, +% and |\__NNC_named_def:nNnn| to \cs{named} part. +% |\new...|, |\renew...|, and |\provide...| versions are defined, but +% since a \cs{def} is used later with no checking, the behaviour is +% not exactly the same as you'd get with \cs{newcommand} in this regard. +% +% \begin{example} +% \usepackage{namedef} +% \usepackage{xparse} +% \ExplSyntaxOn +% \seq_new:N \l__NNC_args_seq +% \scan_new:N \s__NNC +% \NewDocumentCommand \newnamedcommand { s m o o m } +% { \NNC_newcommand:NnNnnn \newcommand {#1} #2 {#3} {#4} {#5} } +% \NewDocumentCommand \renewnamedcommand { s m o o m } +% { \NNC_newcommand:NnNnnn \renewcommand {#1} #2 {#3} {#4} {#5} } +% \NewDocumentCommand \providenamedcommand { s m o o m } +% { \NNC_newcommand:NnNnnn \providecommand {#1} #2 {#3} {#4} {#5} } +% \named \cs_new_protected:Npn \NNC_newcommand:NnNnnn +% #[newcmd] #[star] #[cmd] #[args] #[opt] #[defn] +% { +% \seq_clear:N \l__NNC_args_seq +% \IfValueT {#[args]} +% { \seq_set_from_clist:Nn \l__NNC_args_seq {#[args]} } +% \__NNC_newcommand:NnNn #[newcmd] {#[star]} #[cmd] {#[opt]} +% \__NNC_named_def:nNnn {#[star]} #[cmd] {#[opt]} {#[defn]} +% } +% \end{example} +% +% |\__NNC_newcommand:NnNn| does the \cs{newcommand} part of the job. It +% takes the arguments read in by \pkg{xparse}, and translates them into +% the \cs{newcommand} syntax. The number of items in the |#[args]| +% parameter is counted and left within brackets, and the default value +% of the optional argument is also left within another pair of brackets. +% This step is executed with an empty definition because the named +% parameters will cause havoc in \cs{newcommand}. +% +% \begin{example}[firstnumber=last] +% \named \cs_new_protected:Npn \__NNC_newcommand:NnNn +% #[newcmd] #[star] #[cmd] #[opt] +% { +% \use:x +% { +% \exp_not:N #[newcmd] +% \IfBooleanT {#[star]} { * } +% \exp_not:N #[cmd] +% \seq_if_empty:NF \l__NNC_args_seq +% { [ \seq_count:N \l__NNC_args_seq ] } +% \IfValueT {#[opt]} { [ \__NNC_opt_value:w #[opt] \s__NNC ] } +% { } +% } +% } +% \cs_new:Npn \__NNC_opt_value:w #1 = #2 \s__NNC {#2} +% \end{example} +% +% Now |\__NNC_named_def:nNnn| will do the \cs{named} part. +% First the |#[star]| argument (if not present) becomes \cs{long}, and +% then comes \cs{named} and \cs{def}. Then, if an optional argument was +% given, the command we need to define is |\\foo| rather than |\foo|, so +% use take care of that with \cs{token_to_str:N}, and then leave the +% named parameter given for the optional argument within brackets. +% If there's no optional argument, we just define |#[cmd]| (pretty +% boring). Then we call \cs{seq_use:Nn} on the mandatory arguments to +% lay them flat for \cs{named}, and then the parameter text (|#[defn]|), +% unexpanded. +% +% \begin{example}[firstnumber=last] +% \named \cs_new_protected:Npn \__NNC_named_def:nNnn +% #[star] #[cmd] #[opt] #[defn] +% { +% \use:x +% { +% \IfBooleanF {#[star]} { \long } +% \named \def +% \IfValueTF {#[opt]} +% { +% \exp_not:c { \token_to_str:N #[cmd] } +% [ \exp_not:o { \__NNC_opt_name:w #[opt] \s__NNC } ] +% } +% { \exp_not:N #[cmd] } +% \seq_use:Nn \l__NNC_args_seq { } +% { \exp_not:n {#[defn]} } +% } +% } +% \cs_new:Npn \__NNC_opt_name:w #1 = #2 \s__NNC {#1} +% \ExplSyntaxOff +% \end{example} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{namedef} Implementation} +% +% \begin{macrocode} +%<*package> +%<@@=namedef> +% \end{macrocode} +% +% \subsection{Loading} +% +% \begin{macro}{\@@_end_package_hook:} +% Load \pkg{expl3}, either through \cs{RequirePackage} or through +% inputting the generic loader, depending on the format in use +% (copied from Bruno Le Floch's \pkg{gtl}). +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \input expl3-generic.tex +\else + \RequirePackage{expl3}[2018-05-15] +\fi +\ExplSyntaxOn +\cs_if_exist:NTF \ProvidesExplPackage + { + \cs_new_eq:NN \@@_end_package_hook: \prg_do_nothing: + \ExplSyntaxOff + \ProvidesExplPackage + } + { + \cs_new_eq:NN \@@_end_package_hook: \ExplSyntaxOff + \group_begin: + \ExplSyntaxOff + \cs_set_protected:Npn \@@_tmp:w #1#2#3#4 + { + \group_end: + \tl_gset:cx { ver @ #1 . sty } { #2 ~ v#3 ~ #4 } + \cs_if_exist_use:NF \wlog { \iow_log:x } + { Package: ~ #1 ~ #2 ~ v#3 ~ #4 } + } + \@@_tmp:w + } + {namedef} {\namedefDate} {\namedefVersion} + {Named parameters in TeX definitions (PHO)} +% \end{macrocode} +% \end{macro} +% +% \subsection{Declarations} +% +% \begin{macro}{\flag @@_parm_count} +% A flag (mis)used as a counter to keep track of the parameter number. +% \begin{macrocode} +\flag_new:n { @@_parm_count } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\c_@@_prefix_tl} +% A prefix to use as name space for temporary macros. +% \begin{macrocode} +\tl_const:Nn \c_@@_prefix_tl { namedef~parm~-> } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_@@_macro_tl} +% A token list to store the name of the macro meing defined for error +% messages. +% \begin{macrocode} +\tl_new:N \l_@@_macro_tl +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\q_@@_mark,\q_@@_stop} +% Quarks used throughout the package. +% \begin{macrocode} +\quark_new:N \q_@@_mark +\quark_new:N \q_@@_stop +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\s_@@} +% Scan mark used to skip code. +% \begin{macrocode} +\scan_new:N \s_@@ +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_skip_to_scan_mark:w, \@@_skip_to_scan_mark:nw} +% Consume everything up to \cs{s_@@}. +% \begin{macrocode} +\cs_new:Npn \@@_skip_to_scan_mark:w #1 \s_@@ { } +\cs_new:Npn \@@_skip_to_scan_mark:nw #1 #2 \s_@@ {#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_tmp:w} +% A scratch macro. +% \begin{macrocode} +\cs_new_eq:NN \@@_tmp:w ? +% \end{macrocode} +% \end{macro} +% +% \subsection{The top-level \cs{named} macro} +% +% \begin{macro}{\named} +% \begin{macro}{\@@_grab_prefix:nN} +% Starts scanning ahead for prefixes and the definition +% command. Once finished the scanning of prefixes, call +% \cs{@@_replace_named:nNnn} to do the heavy lifting. +% \begin{macrocode} +\cs_new_protected:Npn \named { \@@_grab_prefix:nN { } } +\cs_new_protected:Npn \@@_grab_prefix:nN #1 #2 + { + \@@_if_prefix:NTF #2 + { \@@_grab_prefix:nN } + { \@@_detect_prefixes:Nn \@@_kill_outer:nN } + { #1#2 } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[pTF]{\@@_if_prefix:N} +% Checks against a list of valid prefixes and returns |true| or +% |false| accordingly. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_prefix:N #1 { TF } + { + \if_int_compare:w 0 + \if_meaning:w \tex_protected:D #1 1 \fi: + \if_meaning:w \tex_global:D #1 1 \fi: + \if_meaning:w \tex_outer:D #1 1 \fi: + \if_meaning:w \tex_long:D #1 1 \fi: + \if_meaning:w \scan_stop: #1 1 \fi: + = 1 \exp_stop_f: + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_detect_prefixes:Nn} +% \begin{macro}[rEXP]{\@@_extract_prefixes:w} +% \begin{macro}[rEXP]{ +% \@@_extract_protected:n, \@@_extract_protected_aux:w, +% \@@_extract_long:n, \@@_extract_long_aux:w, +% \@@_extract_outer:n, \@@_extract_outer_aux:w, +% } +% Defines a scratch macro \cs{@@_tmp:w} and queries its prefixes, then +% forwards them to the the next macro to perform the parameter +% replacement and definition. +% +% This code would be quite a lot simpler if \cs{outer} didn't exist. +% First extract the meaning of \cs{@@_tmp:w}, and pass the prefixes +% (before ``|macro:|'') to \cs{@@_extract_prefixes:w}, and then to +% \cs{@@_extract_protected:n}, \cs{@@_extract_long:n}, and +% \cs{@@_extract_outer:n} in turn to check if each of these prefixes +% is there. +% +% \cs{global} can't be checked this way because it's different from +% other prefixes in the sense that it affects the definition \emph{at +% the time} of the definition, rather than at the time it is used. +% I don't know if it's possible to detect a \cs{global} after it's +% already consumed by \TeX. +% +% \TODO{\cs{afterassignment} tokens are lost. It would be nice if +% it were possible to retrieve it and save until later.} +% \begin{macrocode} +\cs_new_protected:Npn \@@_detect_prefixes:Nn #1 #2 + { + \cs_set_nopar:Npn \@@_tmp:w { } + \use:x + { + \exp_not:N #1 + { + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_extract_prefixes:w + \exp_after:wN \token_to_meaning:N + \cs:w @@_tmp:w \cs_end: \s_@@ + \exp_not:n {#2} + } + } + } +\use:x + { + \cs_new:Npn \exp_not:N \@@_extract_prefixes:w ##1 + \tl_to_str:n { macro: } ##2 \s_@@ + { + \exp_not:N \@@_extract_protected:n {##1} + \exp_not:N \@@_extract_long:n {##1} + \exp_not:N \@@_extract_outer:n {##1} + } + } +\cs_set_protected:Npn \@@_tmp:w #1 #2 + { + \use:x + { + \cs_new:cpn { @@_extract_#1:n } ####1 + { + \exp_not:c { @@_extract_#1_aux:w } ####1 + \token_to_str:N #2 \scan_stop: \token_to_str:N #2 \s_@@ + } + \cs_new:cpn { @@_extract_#1_aux:w } ####1 + \token_to_str:N #2 ####2 \token_to_str:N #2 ####3 \s_@@ + { + \exp_not:N \if_meaning:w \scan_stop: ####2 + \exp_not:N \else: + \exp_not:c { tex_#1:D } + \exp_not:N \fi: + } + } + } +\@@_tmp:w { protected } { \protected } +\@@_tmp:w { long } { \long } +\@@_tmp:w { outer } { \outer } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Main routine} +% +% \begin{macro}{\@@_kill_outer:nN} +% \begin{macro}{\@@_start:nNp, \@@_replace_named:nNnn} +% \begin{macro}{\@@_replace_parameter:Nn, \@@_parameter_output:nnw} +% \begin{macro}{\@@_handle_parameter:nN} +% \begin{macro}{\@@_define:nnnN} +% Here we play dirty: abuse the fact that \cs{exp_not:N} temporarily +% makes the \cs{noexpand}ed control sequence temporarily equal to +% \cs{relax}. But rather than using it in an \cs{edef} or whatnot, +% hit \cs{exp_not:N} with \cs{exp_after:wN}, and then quickly grab +% it with \cs{@@_start:nNp}, so it's safe to grab it, even if it's +% \cs{outer}. If that wasn't bad enough, do it once again to make +% it equal to \cs{relax} in the scope of \cs{@@_replace_named:nNnn} +% so that it doesn't blow up. +% +% \TODO{Currently |\named\def{\foo}{bar}| works, but perhaps it +% shouldn't.} +% \begin{macrocode} +\cs_new_protected:Npn \@@_kill_outer:nN #1 + { + \cs_set:Npn \@@_tmp:w { \@@_start:nNp {#1} } + \exp_after:wN \@@_tmp:w \exp_not:N + } +\cs_new_protected:Npn \@@_start:nNp #1 #2 #3 # + { + \group_begin: + \int_set:Nn \tex_escapechar:D { `\\ } + \exp_after:wN \cs_set_eq:NN \exp_not:N #2 \scan_stop: + \@@_replace_named:nNnn {#1} #2 {#3} + } +% \end{macrocode} +% +% Here the actual replacement of named parameters by numbered ones +% takes place. A group is started to revert the flag and all the +% defined temporary macros. +% +% \cs{@@_replace_parameter:Nn} \cs{@@_in_parameter:nN} starts +% replacing a dummy macro in the generic parameter replacement routine +% by the macro which counts the parameters and aliases the named +% parameters with numbered ones. Finally it starts +% \cs{@@_replace_parm:Nn}, which scans the \meta{parameter~text} for +% the named parameters and replaces them by numbered ones. The second +% output argument of \cs{@@_replace_parm:Nn} is a list of definitions +% which assign a number to each named parameter so that they can be +% used in the next step. +% +% \cs{@@_replace_parameter:Nn} \cs{@@_in_replacement:nN} then starts +% by replacing the same dummy macro by one which will replace the +% named parameter by its number. Again \cs{@@_replace_parm:Nn} is +% started, and its output is the already-processed part of the +% \meta{replacement~text}. +% +% The output of both steps is inserted after \cs{@@_define:nnnN} (it's +% missing two arguments in the definition of +% \cs{@@_replace_named:nNnn}). After all that is done, all the named +% parameters were replaced by numbered ones, so \cs{@@_define:nnnN} +% can do its thing. +% +% A final quark is put in the input stream for recovery from errors. +% In a successful run this quark is removed by \cs{@@_define:nnnN}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_replace_named:nNnn #1 #2 #3 #4 + { + \tl_set:Nx \l_@@_macro_tl { \token_to_str:N #2 } + \@@_replace_parameter:Nn \@@_in_parameter:nN {#3} + \@@_replace_parameter:Nn \@@_in_replacement:nN {#4} + \@@_define:nnnN {#1} #2 + \s_@@ + } +\cs_new_protected:Npn \@@_define:nnnN #1 #2 #3 #4 + { + \group_end: + #3#4#2{#1} + } +\cs_new_protected:Npn \@@_replace_parameter:Nn #1 #2 + { + \cs_set_eq:NN \@@_handle_parameter:nN #1 + \@@_replace_parm:Nn \@@_parameter_output:nnw {#2} + } +\cs_new_eq:NN \@@_handle_parameter:nN ? +\cs_new_protected:Npn \@@_parameter_output:nnw #1 #2 + #3 \@@_define:nnnN + { #2 #3 \@@_define:nnnN {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_in_parameter:nN, \@@_in_replacement:nN} +% These two functions handle the named parameters when they are found +% in the \meta{parameter~text} and \meta{replacement~text}, +% respectively. +% +% \cs{@@_in_parameter:nN} checks if the named parameter already exists +% (with \cs{relax} being |true|) and, in such case, throws an error +% and inserts the number already set for that named parameter. +% Otherwise the parameter is \cs{let} to +% \cs{relax} so that if it is found later an error is issued. Setting +% a macro to \cs{relax} is an expandable way to define it (the same +% approach as in \pkg{l3flag}). After that, +% the \cs{flag @@_parm_count} is raised once and its height is used as +% the parameter number. The current parameter tokens and the parameter +% number are flushed to the first (left) output slot, and a definition +% |\cs_set:cpn {|\cs{c_@@_prefix_tl}~\meta{name}|} {|\meta{number}|}| +% is appended to the second (right) output slot so that the names can +% be used in the \meta{replacement~text}. +% +% In case of a repeated parameter it is tricky to do anything +% sensible. In a normal definition, when \TeX{} sees a repeated +% parameter number (like in |\def\foo#1#1{}|) it just uses the wrong +% number to a parameter number not yet taken, or ignores the parameter +% if there's already nine before that. However here we can't guess +% the name of the next parameter, so we can't do much. The easiest +% way out is to just use the same parameter number as before and go +% on with out job: at the end, \TeX{} will complain again about this. +% \begin{macrocode} +\cs_new:Npn \@@_in_parameter:nN #1 + { + \if_cs_exist:w \c_@@_prefix_tl #1 \cs_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { \msg_expandable_error:nnn { namedef } { repeated-parm } {#1} } + { + \exp_after:wN \use_none:n \cs:w \c_@@_prefix_tl #1 \cs_end: + \flag_raise:n { @@_parm_count } + } + \exp_args:Nf \@@_append_output:nnNwnn + { \flag_height:n { @@_parm_count } } + {#1} + } +% \end{macrocode} +% +% \cs{@@_in_replacement:nN} also checks if the named parameter exists, +% however now it will be \emph{not} be \cs{relax}, but the number +% defined earlier, so \cs{cs_if_exist:cTF} can be safely used. If the +% parameter does not exist it was never declared in the +% \meta{parameter~text} (somewhat like |\def#1{#2}|), then raise an +% error and abort. +% Otherwise just flush |#|\meta{number}. +% \begin{macrocode} +\cs_new:Npn \@@_in_replacement:nN #1 #2 + { + \cs_if_exist:cTF { \c_@@_prefix_tl #1 } + { + \exp_args:Nf \@@_append_output:nnNwnn + { \use:c { \c_@@_prefix_tl #1 } } + { } + } + { + \msg_expandable_error:nnn { namedef } { unknown-parm } {#1} + \exp_args:Ne \@@_append_output:nnNwnn + { #2 \@@_begin_name_token: #1 \@@_end_name_token: } + { \cs_end: { } \use_none:nn } + } + #2 + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Scanning routine} +% +% \begin{macro}[EXP]{\@@_replace_parm:Nn} +% \begin{macro}[EXP]{\@@_replace_loop:w} +% \begin{macro}[EXP]{\@@_replace_end:wnn, \@@_flush:nw} +% \begin{macro}[EXP]{\@@_append_output:nnNwnn} +% \begin{macro}[EXP]{\@@_abort_definition:w} +% \cs{@@_replace_parm:Nn} uses the same looping principle as in +% \pkg{l3tl}'s \cs{__tl_act:NNNnn}. It scans the input (here, the +% \meta{parameter~text} and \meta{replacement~text}, separately) token +% by token, differentiating spaces, braced tokens (groups), and +% \enquote{normal} tokens. +% \begin{macrocode} +\cs_new:Npn \@@_replace_parm:Nn #1 #2 + { + \exp_after:wN #1 + \exp:w + \@@_replace_loop:w #2 + \q_@@_mark \q_@@_stop { } { } + } +\cs_new:Npn \@@_replace_loop:w #1 \q_@@_stop + { + \tl_if_head_is_N_type:nTF {#1} + { \@@_replace_normal:N } + { + \tl_if_head_is_group:nTF {#1} + { \@@_replace_group:n } + { \@@_replace_space:w } + } + #1 \q_@@_stop + } +\cs_new:Npn \@@_replace_end:wnn \q_@@_stop #1 #2 + { \exp_end: {#1} {#2} } +\cs_new:Npn \@@_flush:nw #1 + #2 \q_@@_stop #3 #4 + { \@@_replace_loop:w #2 \q_@@_stop { #3 #1 } {#4} } +% \end{macrocode} +% +% \cs{@@_append_output:nnNwnn} takes three arguments (a parameter +% number, a parameter name, and a parameter token) and the two output +% slots as |#5| and |#6|. It appends the parameter token and number +% to the first output slot, and a definition +% |\cs_set:cpn {|\cs{c_@@_prefix_tl}~\meta{name}|} {|\meta{number}|}| +% to the second output slot. +% \begin{macrocode} +\cs_new:Npn \@@_append_output:nnNwnn #1 #2 #3 + #4 \q_@@_stop #5 #6 + { + \@@_replace_loop:w #4 \q_@@_stop + { #5 #3#1 } + { #6 \cs_set:cpn { \c_@@_prefix_tl #2 } {#1} } + } +% \end{macrocode} +% +% This macro doesn't really abort the definition at the time it's +% called because it's called from within an |f|-expansion context, so +% an attempt to end that prematurely will hardly end well. Instead +% it hijacks the process by inserting +% \cs{@@_skip_to_scan_mark:w} in the second output slot, so that +% the definition end as soon as the scanning ends. +% \TODO{Can be simplified further.} +% \begin{macrocode} +\cs_new:Npn \@@_abort_definition:w + #1 \q_@@_stop #2 #3 + { + \@@_replace_loop:w #1 \q_@@_stop + {#2} { #3 \group_end: \@@_skip_to_scan_mark:w } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_replace_normal:N} +% \begin{macro}[EXP]{\@@_replace_group:n, \@@_flush_group:nnw} +% \begin{macro}[EXP]{\@@_replace_space:w} +% Spaces are just passed through: they aren't parameter tokens nor +% valid delimiters, so need no special treatment. +% +% Braced tokens are recursively scanned by \cs{@@_replace_parm:Nn}, +% and the output is flushed inside a pair of braces (explicit catcode +% $1$ and $2$ tokens are normalised to |{|_$1$ and |}|_$2$, +% respectively) +% \TODO{Since \cs{__tl_act:NNNnn} isn't used anymore, this doesn't +% have to be |f|-expandable, so this restriciton can probably be +% lifted.} +% +% The remaining tokens are examined for their meaning. If the token +% is the quark \cs{q_@@_mark}, the scanning stops; if the token is a +% parameter token, what follows is examined with \cs{@@_grab_parm:Nw} +% to check if a replacement should be done; otherwise it's fluhsed to +% the output. +% \begin{macrocode} +\cs_new:Npn \@@_replace_normal:N #1 + { + \token_if_eq_meaning:NNTF \q_@@_mark #1 + { \@@_replace_end:wnn } + { + \token_if_parameter:NTF #1 + { \@@_grab_parm:Nw } + { \@@_flush:nw } + {#1} + } + } +\cs_new:Npn \@@_replace_group:n #1 + { \@@_replace_parm:Nn \@@_flush_group:nnw {#1} } +\cs_new:Npn \@@_flush_group:nnw #1 #2 + { \@@_flush:nw { {#1} } } +\exp_last_unbraced:NNo +\cs_new:Npn \@@_replace_space:w \c_space_tl + { \@@_flush:nw { ~ } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Parsing a parameter} +% +% \begin{macro}[EXP]{\@@_grab_parm:Nw} +% \begin{macro}[EXP]{\@@_grab_parm_aux:NNw, \@@_grab_parm_noop:NNw} +% \begin{macro}[EXP]{\@@_grab_parm_scan:NNw} +% \begin{macro}[EXP]{\@@_grab_parm_loop:nw, \@@_grab_parm_end:nw} +% \begin{macro}[EXP]{ +% \@@_parm_get_normal:nN, +% \@@_parm_get_group:nn, +% \@@_parm_get_space:nw +% } +% These macros are the final pieces of the parameter replacement +% routine. \cs{@@_grab_parm:Nw} checks if the next token in the stream +% is a valid |N|-type. If it is, then \cs{@@_grab_parm_aux:NNw} checks +% if its character code is equal to \cs{@@_begin_name_token:}, and if +% it is, then call \cs{@@_grab_parm_scan:NNw} to scan ahead for the +% named parameter. In all other cases, the tokens grabbed are not +% named parameters, so they are flushed to the output. +% \begin{macrocode} +\cs_new:Npn \@@_grab_parm:Nw #1 #2 \q_@@_stop + { + \tl_if_head_is_N_type:nTF {#2} + { \@@_grab_parm_aux:NNw } + { \@@_flush:nw } + #1 #2 \q_@@_stop + } +\cs_new:Npn \@@_grab_parm_aux:NNw #1 #2 + { + \exp_args:No \token_if_eq_charcode:NNTF + { \@@_begin_name_token: } #2 + { \@@_grab_parm_scan:NNw } + { \@@_grab_parm_noop:NNw } + #1 #2 + } +% \end{macrocode} +% +% Here we have to take care not to flush \cs{q_@@_mark} to the output. +% \begin{macrocode} +\cs_new:Npn \@@_grab_parm_noop:NNw #1 #2 + { + \token_if_eq_meaning:NNTF \q_@@_mark #2 + { \@@_flush:nw { #1 } #2 } + { \@@_flush:nw { #1 #2 } } + } +% \end{macrocode} +% +% Here's the actual scanning routine. It would be a lot faster to +% just define a delimiter macro with the right tokens, however this +% would have two consequences: first, missing delimiters would be +% rather catastrophic, and second, the catcode of the |end| delimiter +% would need to match. With a manual scanning, we can kill off those +% two items at the cost of some performance. +% +% The scanning routine is pretty standard: a looping macro, an output +% slot, the tokens to be scanned, \cs{q_@@_stop} to delimit the whole +% thing (\cs{q_@@_mark} is redundant here: the one from the main +% scanning rountine is already in place), and the parameter token +% safely stored at the end: +% \begin{macrocode} +\cs_new:Npn \@@_grab_parm_scan:NNw #1 #2 #3 \q_@@_stop + { \@@_grab_parm_loop:nw { } #3 \q_@@_stop {#1} } +\cs_new:Npn \@@_grab_parm_loop:nw #1 #2 \q_@@_stop + { + \tl_if_head_is_N_type:nTF {#2} + { \@@_parm_get_normal:nN } + { + \tl_if_head_is_group:nTF {#2} + { \@@_parm_get_group:nn } + { \@@_parm_get_space:nw } + } + {#1} #2 \q_@@_stop + } +% \end{macrocode} +% +% If the end of the token list was reached (signalled by +% \cs{q_@@_mark}), the |end| delimiter is missing. If so, raise an +% error and recover as gracefully as possible. Otherwise, if the +% current token is the same character as the \cs{@@_end_name_token:}, +% then the scaning is complete. +% \begin{macrocode} +\cs_new:Npn \@@_parm_get_normal:nN #1 #2 + { + \token_if_eq_meaning:NNTF \q_@@_mark #2 + { + \msg_expandable_error:nn { namedef } { missing-end } + \@@_grab_parm_end:nw {#1} #2 + } + { + \exp_args:No \token_if_eq_charcode:NNTF + { \@@_end_name_token: } #2 + { \@@_grab_parm_end:nw {#1} } + { \@@_grab_parm_loop:nw {#1#2} } + } + } +\cs_new:Npn \@@_parm_get_group:nn #1 #2 + { \@@_grab_parm_loop:nw { #1{#2} } } +\cs_new:Npn \@@_parm_get_space:nw #1 ~ + { \@@_grab_parm_loop:nw { #1~ } } +\cs_new:Npn \@@_grab_parm_end:nw #1 #2 \q_@@_stop #3 + { \@@_handle_parameter:nN {#1} #3 #2 \q_@@_stop } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Changing delimiters} +% +% \begin{macro}[EXP]{\@@_begin_name_token:, \@@_end_name_token:} +% These two hold the delimiters for named parameters. They are +% initialised here so that we can use \cs{named} (just to show off) +% ahead, and they are redefined every time \cs{NamedDelim} is used. +% \begin{macrocode} +\cs_new:Npn \@@_begin_name_token: { [ } +\cs_new:Npn \@@_end_name_token: { ] } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\NamedDelim, \globalNamedDelim} +% \begin{macro}{\@@_named_delim_set:Nnn} +% \begin{macro}{\@@_check_delimiter:n} +% At this point everything for the \cs{named} macro is set up, +% so we can start using it. Now just some syntactic sugar to +% allow the modification of the named argument delimiters. +% +% Both \cs{NamedDelim} and \cs{globalNamedDelim} take two arguments, +% an initial and final delimiters for the named argument. Both +% delimters should be single non-control sequence tokens. Some of +% these restrictions could be lifted, but it's not really necessary +% because the choice of delimiter should not influence the working of +% the code, only the readability. A code with |\NamedDelim[]| and +% |\def\test#[1][#[2]]{[#[1]][#[2]]}| should work without problems; +% the only restriction is that \cs{@@_end_name_token:} (\emph{i.e.,} +% the second argument of \cs{NamedDelim}) cannot appear in the +% parameter name. +% \begin{macrocode} +\cs_new_protected:Npn \NamedDelim + { \@@_named_delim_set:Nnn \cs_set:Npn } +\cs_new_protected:Npn \globalNamedDelim + { \@@_named_delim_set:Nnn \cs_gset:Npn } +\named \cs_new_protected:Npn \@@_named_delim_set:Nnn + #[def] #[begin] #[end] + { + \tl_trim_spaces_apply:nN {#[begin]} \@@_check_delimiter:n + \tl_trim_spaces_apply:nN {#[end]} \@@_check_delimiter:n + #[def] \@@_begin_name_token: {#[begin]} + #[def] \@@_end_name_token: {#[end]} + \s_@@ + } +% \end{macrocode} +% +% Here the \meta{token} is checked against a bunch of forbidden cases. +% \begin{macrocode} +\named \cs_new_protected:Npn \@@_check_delimiter:n #[token] + { +% \end{macrocode} +% It can't be empty (nor a space: they were trimmed above): +% \begin{macrocode} + \tl_if_empty:nT {#[token]} + { + \msg_error:nn { namedef } { blank-delim } + \@@_skip_to_scan_mark:w + } +% \end{macrocode} +% It can't be multiple tokens: +% \begin{macrocode} + \tl_if_single_token:nF {#[token]} + { + \msg_error:nnn { namedef } { multi-token-delim } {#[token]} + \@@_skip_to_scan_mark:w + } +% \end{macrocode} +% It can't be an implicit begin- or end-group token: +% \begin{macrocode} + \bool_lazy_or:nnT + { \token_if_group_begin_p:N #[token] } + { \token_if_group_end_p:N #[token] } + { + \msg_error:nnx { namedef } { group-delim } + { \cs_to_str:N #[token] } + \@@_skip_to_scan_mark:w + } +% \end{macrocode} +% It can't be a parameter token: +% \TODO{Maybe it can, but maybe it will be ambiguous. Must check.} +% \begin{macrocode} + \token_if_parameter:NT #[token] + { + \msg_error:nnx { namedef } { param-delim } + { \cs_to_str:N #[token] } + \@@_skip_to_scan_mark:w + } +% \end{macrocode} +% It can't be a control sequence: +% \TODO{It probably can, but I'm not sure I want to allow this.} +% \begin{macrocode} + \token_if_cs:NT #[token] + { + \msg_error:nnx { namedef } { macro-delim } + { \c_backslash_str \cs_to_str:N #[token] } + \@@_skip_to_scan_mark:w + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Messages} +% +% Now we define the messages used throughout the package. +% +% \begin{macrocode} +\msg_new:nnn { namedef } { repeated-parm } + { + Parameter~\iow_char:N\#[#1]~duplicated~in~ + definition~of~\l_@@_macro_tl. + } +\msg_new:nnn { namedef } { unknown-parm } + { + Unknown~parameter~\iow_char:N\#[#1]~in~ + definition~of~\l_@@_macro_tl. + } +\msg_new:nnn { namedef } { multi-token-delim } + { + Invalid~\iow_char:N\\named~parameter~delimiter~`#1'.~ + Delimiters~for~named~parameters~must~be~single~tokens. + } +\msg_new:nnn { namedef } { macro-delim } + { + Invalid~\iow_char:N\\named~parameter~delimiter~`#1'.~ + Delimiters~for~named~parameters~can't~be~control~sequence~nor~ + active~characters. + } +\msg_new:nnn { namedef } { group-delim } + { + Invalid~\iow_char:N\\named~parameter~delimiter~`\iow_char:N\\#1'.~ + Delimiters~for~named~parameters~can't~be~ + begin-/end-group~character~tokens. + } +\msg_new:nnn { namedef } { blank-delim } + { + Invalid~\iow_char:N\\named~parameter~delimiter.~ + Delimiters~for~named~parameters~can't~be~empty~nor~space~tokens. + } +\msg_new:nnn { namedef } { param-delim } + { + Invalid~\iow_char:N\\named~parameter~delimiter.~ + Delimiters~for~named~parameters~can't~be~parameter~tokens. + } +\msg_new:nnn { namedef } { missing-end } + { + Missing~\@@_end_name_token:\iow_char:N\ inserted~in~ + definition~of~\l_@@_macro_tl. + } +% \end{macrocode} +% +% Now execute the end package hook (in \LaTeX{} it is +% \cs{prg_do_nothing:}, but in plain \TeX{} it does \cs{ExplSyntaxOff}). +% +% \begin{macrocode} +\@@_end_package_hook: +% \end{macrocode} +% +% \iffalse +% +% \fi +% +% \end{implementation} +% +%^^A \par\CodedocExplainEXP +%^^A \par\CodedocExplainREXP +%^^A \par\CodedocExplainTF +% +% \PrintIndex +% +\endinput diff --git a/macros/generic/namedef/namedef.ins b/macros/generic/namedef/namedef.ins new file mode 100644 index 0000000000..50806470e1 --- /dev/null +++ b/macros/generic/namedef/namedef.ins @@ -0,0 +1,90 @@ +%% +%% Copyright (C) 2019--2020 +%% by Phelype Oleinik +%% +%% This work may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.3c 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.3c or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work is "maintained" (as per the LPPL maintenance status) +%% by Phelype Oleinik. +%% +\def\projectname{namedef}% +\def\nameofplainTeX{plain}% +\def\mainext{sty} +\ifx\fmtname\nameofplainTeX +\else + \expandafter\begingroup +\fi +\input l3docstrip.tex +\keepsilent +\askforoverwritefalse + +\preamble + +This is a generated file. + +Copyright 2019--2020 Phelype Oleinik /phelype.oleinik@latex-project.org/ + +This work may be distributed and/or modified under the conditions of the +LaTeX Project Public License, either version 1.3c 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.3c or later is part of all distributions of LaTeX version +2005/12/01 or later. + +\endpreamble + +\postamble + +This work is "maintained" (as per the LPPL maintenance status) +by Phelype Oleinik. + +This work consists of the files \projectname.dtx, and + \projectname.ins, +and the derived files \projectname.\mainext, + \projectname.pdf, + README.md, and + README.txt.% + +\endpostamble + +\generate + { + \file{\projectname.\mainext} + { + \from{\projectname.dtx}{package} + } + } + +\Msg{*********************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the} +\Msg{* following file into a directory searched by TeX:} +\Msg{*} +\Msg{* \space\space \projectname.\mainext} +\Msg{*} +\ifx\fmtname\nameofplainTeX + \Msg{* To produce the documentation run the file \projectname.dtx} + \Msg{* through LaTeX.} + \Msg{*} +\fi +\Msg{* Happy TeXing!} +\Msg{*} +\Msg{*********************************************************} + +\ifx\fmtname\nameofplainTeX + \expandafter\endbatchfile +\else + \expandafter\endgroup +\fi + +\input{\projectname.dtx} diff --git a/macros/generic/namedef/namedef.pdf b/macros/generic/namedef/namedef.pdf new file mode 100644 index 0000000000..ae32bff6ac Binary files /dev/null and b/macros/generic/namedef/namedef.pdf differ diff --git a/macros/latex/contrib/apa7/apa7.dtx b/macros/latex/contrib/apa7/apa7.dtx index fcaeda30fb..2f816a3f8a 100644 --- a/macros/latex/contrib/apa7/apa7.dtx +++ b/macros/latex/contrib/apa7/apa7.dtx @@ -4,11 +4,11 @@ % % % CHANGE THESE VALUES WITH EACH NEW RELEASE: % % % -%\ProvidesClass{apa7}[2020/05/27 v1.08 APA formatting (7th edition)] +%\ProvidesClass{apa7}[2020/06/19 v1.09 APA formatting (7th edition)] % % %<*internal> % -\def\apaSevenVersionDate{2020/05/27} -\def\apaSevenVersionNumber{1.08} +\def\apaSevenVersionDate{2020/06/19} +\def\apaSevenVersionNumber{1.09} % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -245,6 +245,8 @@ and the derived files apa7.ins, % % \changes{v1.08}{2020/05/27}{Added support for optional running head (shorttitle) in stu mode.} % +% \changes{v1.09}{2020/06/19}{Fixed note command (will no longer print "Author Note" header).} +% % \begin{abstract} % The \textit{Publication Manual} of the American Psychological % Association is widely used in the social sciences. The most @@ -441,7 +443,7 @@ and the derived files apa7.ins, % \begin{itemize} % \item \DescribeMacro{\note}|\note|\marg{note-text}: Notation of % manuscript date or other information desired beneath the -% affiliation line +% affiliation line (not part of the APA 7th edition specification for title page) % \item \DescribeMacro{\journal}|\journal|\marg{journal-name}: Journal % name or other note; typeset in the top left header of page 1 % (|jou| and |doc| modes only); to change the starting page to a @@ -2511,12 +2513,9 @@ and the derived files apa7.ins, \@affilSix \vspace{0.25in} \\ }}}}} %% --- thp 2006/01/05 end of six-author display - \@ifundefined{@note}{}{ - \vfill - \section{\normalfont\normalsize\textbf\acksname} - \raggedright - \setlength{\parindent}{0.5in} - \indent\@note\par} + \@ifundefined{@note} + {\vspace*{\baselineskip} } + {\@note} }{% mask author identity -- show nothing in the author or author note space } @@ -2542,12 +2541,9 @@ and the derived files apa7.ins, \@professor \\ \@duedate \\ - \@ifundefined{@note}{}{ - \vfill - \section{\normalfont\normalsize\textbf\acksname} - \raggedright - \setlength{\parindent}{0.5in} - \indent\@note\par} + \@ifundefined{@note} + {\vspace*{\baselineskip} } + {\@note} \end{center} @@ -2555,12 +2551,10 @@ and the derived files apa7.ins, {} {% \vfill% - \begin{center}% - \acksname% - \end{center}% - \protect\raggedright + \section{\normalfont\normalsize\textbf\acksname} + \raggedright \setlength{\parindent}{0.5in} - \indent\par\@acks% + \indent\@acks\par% } } diff --git a/macros/latex/contrib/apa7/apa7.pdf b/macros/latex/contrib/apa7/apa7.pdf index 50bbb1c9c6..68b928107e 100644 Binary files a/macros/latex/contrib/apa7/apa7.pdf and b/macros/latex/contrib/apa7/apa7.pdf differ diff --git a/macros/latex/contrib/apa7/samples/longsample.pdf b/macros/latex/contrib/apa7/samples/longsample.pdf index 204fa117cf..61af7536c3 100644 Binary files a/macros/latex/contrib/apa7/samples/longsample.pdf and b/macros/latex/contrib/apa7/samples/longsample.pdf differ diff --git a/macros/latex/contrib/apa7/samples/shortsample.pdf b/macros/latex/contrib/apa7/samples/shortsample.pdf index 8ceb61d7fb..aafd245226 100644 Binary files a/macros/latex/contrib/apa7/samples/shortsample.pdf and b/macros/latex/contrib/apa7/samples/shortsample.pdf differ diff --git a/macros/latex/contrib/hyperxmp/hyperxmp.dtx b/macros/latex/contrib/hyperxmp/hyperxmp.dtx index e4e4f52837..9861784479 100644 --- a/macros/latex/contrib/hyperxmp/hyperxmp.dtx +++ b/macros/latex/contrib/hyperxmp/hyperxmp.dtx @@ -22,7 +22,7 @@ %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{hyperxmp} %<*package> - [2020/06/13 v5.3 Store hyperref metadata in XMP format] + [2020/06/19 v5.4 Store hyperref metadata in XMP format] % % %<*driver> @@ -112,7 +112,7 @@ % % \fi % -% \CheckSum{2610} +% \CheckSum{2671} % % \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 @@ -190,8 +190,16 @@ % % ^^A Define a few logical styles. % \DeclareRobustCommand{\term}[1]{#1\SortIndex{#1}{#1}} -% \DeclareRobustCommand{\pkgname}[1]{\mbox{\textsf{#1}}\SortIndex{#1}{\textsf{#1}}} -% \DeclareRobustCommand{\clsname}[1]{\mbox{\textsf{#1}}\SortIndex{#1}{\textsf{#1}}} +% \DeclareRobustCommand{\pkgname}[1]{^^A +% \mbox{\textsf{#1}}^^A +% \SortIndex{#1}{\textsf{#1} (package)}^^A +% \index{packages=\textsf{#1}}^^A +% } +% \DeclareRobustCommand{\clsname}[1]{^^A +% \mbox{\textsf{#1}}^^A +% \SortIndex{#1}{\textsf{#1} (class)}^^A +% \index{classes=\textsf{#1}}^^A +% } % \makeatletter % \DeclareRobustCommand{\xmpprop}[2][]{^^A XMP property % \def\xmppropopt{#1}^^A @@ -210,7 +218,11 @@ % } % \makeatother % \index{XMP=\acrostyle {XMP}&properties|see{properties, \acrostyle{XMP}}} -% \DeclareRobustCommand{\pdfterm}[1]{\mbox{\textsf{#1}}\SortIndex{#1}{\textsf{#1}}} +% \DeclareRobustCommand{\pdfterm}[1]{^^A +% \mbox{\textsf{#1}}^^A +% \SortIndex{#1}{\textsf{#1}}^^A +% \index{PDF=\acrostyle{PDF}=\textsf{#1}}^^A +% } % \DeclareRobustCommand{\cmdname}[1]{\mbox{\texttt{#1}}\SortIndex{#1}{\texttt{#1}}} % \DeclareRobustCommand{\optname}[1]{^^A % \mbox{\textsf{#1}}^^A @@ -272,6 +284,15 @@ % \DeclareRobustCommand{\Lua}{^^A % Lua\index{Lua}^^A % } +% \DeclareRobustCommand{\Koma}{^^A +% Koma^^A +% \SortIndex{Koma}{Koma (class)}^^A +% \index{classes&Koma}^^A +% } +% \DeclareRobustCommand{\ACMclass}{^^A +% \acro{ACM}^^A +% \index{classes&ACM=\acrostyle{ACM}}^^A +% } % % ^^A Define an environment just like macro but for Lua functions. % \makeatletter @@ -1143,15 +1164,16 @@ % \optname{pdfmetalang} defaults to the same value as \optname{pdflang} % if non-empty, ``|x-default|'' otherwise. \pkgname{hyperxmp} % recognizes some class-specific metadata as well, such as that provided -% via the Koma letter classes (e.g.,~\clsname{scrlttr2}) and the -% \acro{ACM} article class (\clsname{acmart}). +% via the \Koma\ letter classes (e.g.,~\clsname{scrlttr2}) and the +% \ACMclass\ article class (\clsname{acmart}). % -% If a document uses the \pkgname{polyglossia} package, it is -% recommended that it \emph{not} explicitly set \optname{pdflang}. -% \optname{pdflang} accepts only a single language name while -% \pkgname{hyperxmp} can automatically query \pkgname{polyglossia} for a -% list of all languages used in the document and include this list in an -% \acro{XMP} \xmpterm{dc:language} element. +% If a document uses either or \pkgname{babel} or \pkgname{polyglossia} +% package, it is recommended that it \emph{not} explicitly set +% \optname{pdflang}. \optname{pdflang} accepts only a single language +% name while \pkgname{hyperxmp} can automatically query \pkgname{babel} +% and \pkgname{polyglossia} for a list of all languages used in the +% document and include this list in an \acro{XMP} \xmpprop{dc:language} +% element. % % \usagenote{Multilingual metadata} % \label{note:multilingual} @@ -2212,6 +2234,7 @@ }{}% }% % \end{macrocode} +% \Needspace{6\baselineskip} % \begin{macro}{\KV@Hyp@pdfauthor} % \begin{macro}{\xmpcomma} % \begin{macro}{\xmpquote} @@ -2337,6 +2360,26 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\hyxmp@concated@metadata} +% Assume that if the document loaded either \pkgname{babel} or +% \pkgname{polyglossia} it will eventually define one or more languages +% that \pkgname{hyperxmp} can list within a \xmpprop{dc:language} +% element. +% \begin{macrocode} +\edef\hyxmp@concated@metadata{} +\AtEndPreamble{% + \@ifpackageloaded{babel}{% + \edef\hyxmp@concated@metadata{babel}% + }{% + \@ifpackageloaded{polyglossia}{% + \edef\hyxmp@concated@metadata{polyglossia}% + }{% + }% + }% +} +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\hyxmp@find@metadata} % \begin{macro}{\hyxmp@concated@metadata} % Issue a warning message if the author failed to specify any metadata @@ -2348,6 +2391,7 @@ % \begin{macrocode} \newcommand*{\hyxmp@find@metadata}{% \edef\hyxmp@concated@metadata{% + \hyxmp@concated@metadata \@baseurl \@pdfauthor \@pdfauthortitle @@ -2452,11 +2496,151 @@ % \end{macro} % \end{macro} % +% Rather than load \pkgname{hyperref} ourself we let the author do it +% then verify he actually did. This approach gives the author the +% flexibility to load \pkgname{hyperxmp} and \pkgname{hyperref} in +% either order and to call |\hypersetup| anywhere in the document's +% preamble, not just before \pkgname{hyperxmp} is loaded. +% \begin{macrocode} +\AtEndPreamble{% + \@ifpackageloaded{hyperref}{% +% \end{macrocode} +% If \cs{@pdflang} is not set, see if we can detect the document +% language via either the \pkgname{babel} or \pkgname{polyglossia} +% packages. +% \begin{macrocode} + \@if@def@and@nonempty{@pdflang}{% + }{% + \hyxmp@detect@langs + }% +% \end{macrocode} +% Fill in any missing metadata we can using values provided by the author +% via mechanisms other than the \cs{hypersetup} command. +% \begin{macrocode} + \hyxmp@auto@assign@data +% \end{macrocode} +% Most \acro{PDF} standards dictate that if the same metadata appear in +% both the \acro{XMP} packet and the \acro{PDF} \pdfterm{Info} +% dictionary, the metadata must match. This requirement poses a problem +% for a user-unspecified \optname{pdfcreationdate} in the context of +% \XeLaTeX\@. In this case we explicitly define |\@pdfcreationdate| as +% |\hyxmp@today@pdf| to prevent the \cmdname{xdvipdfmx} back-end +% processor from detecting a missing \pdfterm{CreationDate} in the +% \pdfterm{Info} dictionary and adding its own---typically a few seconds +% after \pkgname{hyperxmp} has constructed an \xmpprop{xmp:CreateDate} +% for the \acro{XMP} metadata and leading to a metadata mismatch. +% \begin{macrocode} + \@ifundefined{XeTeXversion}{}{% + \@ifmtargexp{\@pdfcreationdate}{% + \let\@pdfcreationdate=\hyxmp@today@pdf + }% + {}% + }% +% \end{macrocode} +% If the document claims to comply with one or more \acro{PDF} +% standards, check that all of the requisite metadata are present. +% \begin{macrocode} + \hyxmp@check@standards +% \end{macrocode} +% Older versions of \pkgname{hyperref} write the \pdfterm{Info} +% dictionary to the \acro{PDF} file at the end of the document. New +% versions of \pkgname{hyperref} write the \pdfterm{Info} dictionary to +% the \acro{PDF} file at the \emph{beginning} of the document. For +% compatibility with both old and new \pkgname{hyperref} implementations +% we suppress writing the \pdfterm{Info} dictionary here, at the +% beginning of the document. +% \changes{v4.1}{2019/04/02}{Invoke +% \protect\cs{hyxmp@no@info@lists} at the beginning of the +% document, for compatibility with both newer and older versions of +% \protect\pkgname{hyperref}} +% \begin{macrocode} + \hyxmp@no@info@lists +% \end{macrocode} +% We wait until the end of the document to construct the \acro{XMP} +% packet and write it to the \acro{PDF} document catalog. This gives +% the author ample opportunity to provide metadata to \pkgname{hyperref} +% and thereby \pkgname{hyperxmp}. +% \begin{macrocode} + \hyxmp@at@end{% + \hyxmp@find@metadata + \hyxmp@embed@packet + }% + }{% + \PackageWarningNoLine{hyperxmp}{% + \jobname.tex failed to include a\MessageBreak + \string\usepackage\string{hyperref\string} + in the preamble.\MessageBreak + Consequently, all hyperxmp functionality will be\MessageBreak + disabled}% + }% +} +% \end{macrocode} +% +% A number of classes either require or recommend that authors declare +% various class-specific metadata \emph{after} the |\begin{document}|. +% So where do we invoke \cs{hyxmp@auto@assign@data}? On one hand, we +% want to invoke it before the |\begin{document}| because this may +% obviate \pkgname{hyperxmp}'s ``\meta{job name} did not specify any +% metadata'' warning message. On the other hand, we want to invoke it +% after the |\begin{document}| so it picks up metadata not specified in +% the preamble. Our solution is to invoke \cs{hyxmp@auto@assign@data} +% twice: both before the |\begin{document}| and at the |\end{document}|. +% We additionally identify here the natural language(s) in use because +% these aren't known until the end of the document when provided by +% \pkgname{babel} or \pkgname{polyglossia}. Also, \pkgname{hyperref} +% forbids changes to \optname{pdflang} past the |\begin{document}|. +% \changes{v1.3}{2011/04/25}{Introduced the \protect\optname{pdfmetalang} +% package option, which enables an author to specify the language in which he +% wrote the document's metadata} +% \changes{v2.0}{2012/08/02}{New \cs{AtBeginDocument} code from Heiko +% Oberdiek to properly encode \cs{@pdfmetalang}} +% \changes{v3.3}{2017/07/21}{Don't overwrite an existing +% \protect\optname{pdfmetalang} with \protect\optname{pdflang} or +% \protect\texttt{x-default}. This addresses a bug report by Niklas +% Beisert} +% \changes{v5.4}{2020/06/18}{Moved the automatic assignment of +% \protect\cs{@pdflang} and \protect\cs{@pdfmetalang} from +% \protect\cs{hyxmp@auto@assign@data} to within a call to +% \protect\cs{hyxmp@at@end}} +% \begin{macrocode} +\hyxmp@at@end{% + \hyxmp@set@dc@lang + \ifx\@pdfmetalang\@empty + \ifx\@pdflang\@empty + \let\@pdfmetalang=\hyxmp@x@default + \else + \edef\@pdfmetalang{\@pdflang}% + \fi + \fi + \hyxmp@xmlify\@pdfmetalang + \hyxmp@auto@assign@data +} +% \end{macrocode} +% +% +% \subsection{Advanced metadata detection} +% +% \pkgname{hyperxmp} strives to be as convenient and user-friendly as +% possible. To that end, we try to automatically detect as much +% metadata as possible. The author can of course augment or override +% autodetected metadata by explicitly providing values to +% \cs{hypersetup}, but the hope is that we can save the author some +% effort in many cases. +% +% In this section, we identify additional metadata we can use. Most of +% the functionality is class- or package-specific. For example, we +% check for phone numbers provided to the \Koma\ letter classes via +% |\setkomavar{fromphone}{|\dots|}| and/or +% |\setkomavar{frommobilephone}{|\dots|}|, street addresses provided to +% the \ACMclass\ article class via \cs{affiliation}, and languages +% the \pkgname{polyglossia} package is instructed to load via +% \cs{setdefaultlanguage} and \cs{setotherlanguage}. +% % \begin{macro}{\hyxmp@set@koma@phones} % \changes{v5.3}{2020/06/07}{Added this macro} % \begin{macro}{\hyxmp@koma@phones} % Define \cs{hyxmp@koma@phones} as a comma-separated list of the phone -% numbers provided to a Koma letter class (mobile and landline). +% numbers provided to a \Koma\ letter class (mobile and landline). % \begin{macrocode} \newcommand*{\hyxmp@set@koma@phones}{% \@if@def@and@nonempty{scr@frommobilephone@var}{% @@ -2525,30 +2709,6 @@ % \begin{macrocode} \newcommand*{\hyxmp@auto@assign@data}{% % \end{macrocode} -% If the author explicitly specified the language to use for the -% document's metadata, we use that. If not, we use the document -% language, specified to \pkgname{hyperref} with the \protect\optname{pdflang} -% option. If the author did not specify a language, we use |x-default| -% as the metadata language. -% \changes{v1.3}{2011/04/25}{Introduced the \protect\optname{pdfmetalang} -% package option, which enables an author to specify the language in which he -% wrote the document's metadata} -% \changes{v2.0}{2012/08/02}{New \cs{AtBeginDocument} code from Heiko -% Oberdiek to properly encode \cs{@pdfmetalang}} -% \changes{v3.3}{2017/07/21}{Don't overwrite an existing -% \protect\optname{pdfmetalang} with \protect\optname{pdflang} or -% \protect\texttt{x-default}. This addresses a bug report by Niklas -% Beisert} -% \begin{macrocode} - \ifx\@pdfmetalang\@empty - \ifx\@pdflang\@empty - \let\@pdfmetalang=\hyxmp@x@default - \else - \edef\@pdfmetalang{\@pdflang}% - \fi - \fi - \hyxmp@xmlify\@pdfmetalang -% \end{macrocode} % If the author left \optname{pdftitle} blank but specified |\title|, % use the title for \optname{pdftitle}. Do likewise for various other % metadata: identify author-provided information that can be co-opted @@ -2558,7 +2718,7 @@ % unspecified. Thanks to Maciej Radziejewski for the suggestion} % \changes{v5.3}{2020/05/29}{Consider other author-provided sources of % metadata. Thanks to Robin Schwab for proposing that -% \protect\pkgname{hyperxmp} use the Koma letter classes's metadata} +% \protect\pkgname{hyperxmp} use the \Koma\ letter classes's metadata} % \begin{macrocode} \hyxmp@use@first@valid{pdftitle}{\@pdftitle}{% \scr@subject@var,% @@ -2728,6 +2888,8 @@ % ``10.1145/nnnnnnn.nnnnnnn'', or the example \acro{DOI} specified in % the \clsname{acmart} example document, ``10.1145/1122445.1122456''. % We ignore both of those \acro{DOI}s. +% \changes{v5.4}{2020/06/16}{Bug fix: Correct a missing ``else'' argument +% in two invocations of \protect\cs{@if@def@and@nonempty}} % \begin{macrocode} \@if@def@and@nonempty{@acmDOI}{% \IfSubStr{\@acmDOI}{10.1145/1122445.1122456}{}{% @@ -2738,6 +2900,7 @@ }% }% }% + {}% % \end{macrocode} % \begin{macro}{\hyxmp@strip@isbn@date} % \begin{macro}{\hyxmp@acm@isbn} @@ -2761,6 +2924,7 @@ }% }% }% + {}% % \end{macrocode} % \end{macro} % \end{macro} @@ -2819,16 +2983,17 @@ % \begin{macro}{\hyxmp@dc@lang} % \cs{@pdflang} is used in both the \acro{PDF} document catalog (the % \pdfterm{Lang} key, written to the \acro{PDF} file by -% \pkgname{hyperref}) and in the Dublin Core \xmpterm{dc:language} tag +% \pkgname{hyperref}) and in the Dublin Core \xmpprop{dc:language} tag % (Section~\ref{sec:dublin-core}). Normally, these are the same. % However, \pdfterm{Lang} accepts only a single language while -% \xmpterm{dc:language} accepts multiple languages. If the document -% loads \pkgname{polyglossia} and does not specify \optname{pdflang} in -% \cs{hypersetup}, \cs{hyxmp@set@dc@lang} is redefined below to set -% \cs{hyxmp@dc@lang} to \pkgname{polyglossia}'s list of used languages -% (once this is known). Otherwise, \cs{hyxmp@set@dc@lang} assigns the -% language specified by \optname{pdflang} (if any) to -% \cs{hyxmp@dc@lang}. +% \xmpprop{dc:language} accepts multiple languages. If the document +% loads either \pkgname{babel} or \pkgname{polyglossia} and does not +% specify \optname{pdflang} in \cs{hypersetup}, \cs{hyxmp@set@dc@lang} +% is redefined below (in \cs{hyxmp@detect@langs}) to set +% \cs{hyxmp@dc@lang} to \pkgname{babel}\slash\pkgname{polyglossia}'s +% list of used languages (once this is known). Otherwise, +% \cs{hyxmp@set@dc@lang} assigns the language specified by +% \optname{pdflang} (if any) to \cs{hyxmp@dc@lang}. % \begin{macrocode} \newcommand*{\hyxmp@set@dc@lang}{% \let\hyxmp@dc@lang=\@pdflang @@ -2837,119 +3002,139 @@ % \end{macro} % \end{macro} % -% Rather than load \pkgname{hyperref} ourself we let the author do it -% then verify he actually did. This approach gives the author the -% flexibility to load \pkgname{hyperxmp} and \pkgname{hyperref} in -% either order and to call |\hypersetup| anywhere in the document's -% preamble, not just before \pkgname{hyperxmp} is loaded. +% \begin{macro}{\hyxmp@detect@langs} +% If \optname{pdflang} was not specified, try to determine the document +% language(s) using either \pkgname{babel}'s or \pkgname{polyglossia}'s +% definitions. If so, we redefine \cs{hyxmp@set@dc@lang} as a +% comma-separate list of languages used in the document. +% \changes{v5.3}{2020/06/08}{Acquire the default language from the +% \protect\pkgname{polyglossia} package, if loaded. Thanks to +% Robin Schwab for bringing that package to my attention} +% \changes{v5.4}{2020/06/16}{Refactored language detection into a +% separate command} % \begin{macrocode} -\AtEndPreamble{% - \@ifpackageloaded{hyperref}{% +\newcommand*{\hyxmp@detect@langs}{% + \@ifundefined{mainbcp47id}{% + \@ifundefined{LocaleForEach}{% % \end{macrocode} -% In older versions of \pkgname{hyperref}, \cs{@pdflang} is set to +% The document doesn't appear to have loaded either \pkgname{babel} or +% \pkgname{polyglossia}. In this case we have one small task to do. In +% older versions of \pkgname{hyperref}, \cs{@pdflang} is set to % \cs{@empty} if \optname{pdflang} is not specified. In newer versions % of \pkgname{hyperref}, \cs{@pdflang} is set to \cs{relax} if % \optname{pdflang} is not specified. The latter is a bit problematic % for \pkgname{hyperxmp} because it makes \cs{@pdflang} non-expandable, % which causes a literal ``\cs{@pdflang}'' to be written as \acro{XMP} -% metadata. To avoid that situation we redefine \cs{@pdflang} as -% \cs{@empty} if we see it set to \cs{relax}. Actually, we first check -% if the \pkgname{polyglossia} package has specified the document's main -% language in \cs{mainbcp47id}. If so, we use that instead of -% \cs{@empty} and redefine \cs{hyxmp@set@dc@lang} to consider -% \pkgname{polyglossia}'s list of used languages. +% metadata. To avoid that situation we explicitly set \cs{@pdflang} to +% \cs{@empty} to avoid problems with non-expandable symbols. % \changes{v2.3a}{2013/04/16}{Bug fix: Redefine \cs{@pdflang} as % \cs{@empty} when \protect\pkgname{hyperref} has set % it to \cs{relax}} -% \changes{v5.3}{2020/06/08}{Acquire the default language from the -% \protect\pkgname{polyglossia} package, if loaded. Thanks to -% Robin Schwab for bringing that package to my attention} % \begin{macrocode} - \ifx\@pdflang\relax - \@ifundefined{mainbcp47id}{% - \let\@pdflang=\@empty - }{% - \xdef\@pdflang{\csname mainbcp47id\endcsname}% - \renewcommand*{\hyxmp@set@dc@lang}{% - \edef\hyxmp@dc@lang{\xpg@bcp@loaded}% + \let\@pdflang=\@empty + }{% +% \end{macrocode} +% Use \pkgname{babel}'s \cs{LocaleForEach} and \cs{getlocaleproperty} to +% construct a comma-separate list of all document languages. We also +% set \cs{@pdflang} within \cs{hyxmp@set@dc@lang}. +% (\cs{hyxmp@detect@langs} should only be called if \cs{@pdflang} is +% empty.) Unlike \pkgname{polyglossia}, \pkgname{babel} does not +% provide information about the main language until after the +% |\begin{document}| so we have to wait until \cs{hyxmp@set@dc@lang} is +% called to set it. +% \changes{v5.4}{2020/06/17}{Added support for \protect\pkgname{babel}} +% \begin{macrocode} + \BabelEnsureInfo + \renewcommand*{\hyxmp@set@dc@lang}{% + \getlocaleproperty\@pdflang{\bbl@main@language}{identification/tag.bcp47}% + \hyxmp@write@pdflang + \let\hyxmp@dc@lang=\relax + \LocaleForEach{% + \getlocaleproperty\hyxmp@lang@tag{####1}{identification/tag.bcp47}% + \ifx\hyxmp@dc@lang\relax + \edef\hyxmp@dc@lang{\hyxmp@lang@tag}% + \else + \edef\hyxmp@dc@lang{\hyxmp@dc@lang,\hyxmp@lang@tag}% + \fi }% }% - \fi -% \end{macrocode} -% Fill in any missing metadata we can using values provided by the author -% via mechanisms other than the \cs{hypersetup} command. -% \begin{macrocode} - \hyxmp@auto@assign@data + }% + }{% % \end{macrocode} -% Most \acro{PDF} standards dictate that if the same metadata appear in -% both the \acro{XMP} packet and the \acro{PDF} \pdfterm{Info} -% dictionary, the metadata must match. This requirement poses a problem -% for a user-unspecified \optname{pdfcreationdate} in the context of -% \XeLaTeX\@. In this case we explicitly define |\@pdfcreationdate| as -% |\hyxmp@today@pdf| to prevent the \cmdname{xdvipdfmx} back-end -% processor from detecting a missing \pdfterm{CreationDate} in the -% \pdfterm{Info} dictionary and adding its own---typically a few seconds -% after \pkgname{hyperxmp} has constructed an \xmpprop{xmp:CreateDate} -% for the \acro{XMP} metadata and leading to a metadata mismatch. +% Use \pkgname{polyglossia}'s \cs{mainbcp47id} as the document's main +% language and its \cs{xpg@bcp@loaded} as a comma-separated list of all +% document languages. % \begin{macrocode} - \@ifundefined{XeTeXversion}{}{% - \@ifmtargexp{\@pdfcreationdate}{% - \let\@pdfcreationdate=\hyxmp@today@pdf - }% - {}% + \xdef\@pdflang{\csname mainbcp47id\endcsname}% + \renewcommand*{\hyxmp@set@dc@lang}{% + \edef\hyxmp@dc@lang{\xpg@bcp@loaded}% }% + }% +} % \end{macrocode} -% If the document claims to comply with one or more \acro{PDF} -% standards, check that all of the requisite metadata are present. +% \end{macro} +% +% \begin{macro}{\hyxmp@write@pdflang} +% Here's a conundrum: \pkgname{babel} doesn't provide access to +% information on the document's main language until after the +% |\begin{document}|. However, \pkgname{hyperref} allows +% \optname{pdflang} to be set only \emph{before} the |\begin{document}|. +% So what do we do? +% +% Note that the underlying \cs{@pdflang} macro serves two purposes: +% \pkgname{hyperref} uses it to set the \pdfterm{Lang} entry in the +% \acro{PDF} document catalog, and \pkgname{hyperxmp} uses it as the +% default metadata language. The latter is used in \xmpprop{dc:title} +% and other \acro{XMP} properties that can include per-language +% variants. We set \cs{@pdflang} once we have the main-language +% information from \pkgname{babel}. As this is too late for +% \pkgname{hyperref}, we bypass \pkgname{hyperref} and manually write +% the \pdfterm{Lang} key into the document catalog. This is a bit +% kludgy, but we do leverage as much of \pkgname{hyperref}'s +% infrastructure as possible to increase \cs{hyxmp@write@pdflang}'s +% robustness. +% \changes{v5.4}{2020/06/19}{Added this macro} +% \begin{macrocode} +\newcommand*{\hyxmp@write@pdflang}{% + \@ifundefined{pdfmark}{% + \@ifundefined{@pdfm@mark}{% + \@ifundefined{pdfcatalog}{% +% \end{macrocode} +% We don't recognize the \tex\ engine or \acro{PDF} generator. (This is +% unexpected.) We therefore issue a warning message and take no further +% action. +% \begin{macrocode} + \PackageWarning{hyperxmp}{Unknown PDF generator; not setting the language (\@pdflang) in the PDF catalog}% + }{% +% \end{macrocode} +% We're running either \pdfTeX\ or \LuaTeX\@. (\pkgname{hyperref} +% defines \cs{pdfcatalog} in the latter case.) % \begin{macrocode} - \hyxmp@check@standards + \pdfcatalog{/Lang (\@pdflang)}% + }% + }{% % \end{macrocode} -% Older versions of \pkgname{hyperref} write the \pdfterm{Info} -% dictionary to the \acro{PDF} file at the end of the document. New -% versions of \pkgname{hyperref} write the \pdfterm{Info} dictionary to -% the \acro{PDF} file at the \emph{beginning} of the document. For -% compatibility with both old and new \pkgname{hyperref} implementations -% we suppress writing the \pdfterm{Info} dictionary here, at the -% beginning of the document. -% \changes{v4.1}{2019/04/02}{Invoke -% \protect\cs{hyxmp@no@info@lists} at the beginning of the -% document, for compatibility with both newer and older versions of -% \protect\pkgname{hyperref}} +% We're running either \XeTeX\ or \tex~+ +% \texttt{dvipdfm}.\SortIndex{dvipdfm}{\texttt{dvipdfm}}. % \begin{macrocode} - \hyxmp@no@info@lists + \@pdfm@mark{docview << /Lang (\@pdflang) >>}% + }% +}{% % \end{macrocode} -% We wait until the end of the document to construct the \acro{XMP} -% packet and write it to the \acro{PDF} document catalog. This gives -% the author ample opportunity to provide metadata to \pkgname{hyperref} -% and thereby \pkgname{hyperxmp}. +% We're running either \tex~+ \Dvips~+ Adobe Acrobat Distiller (or other +% converter from PostScript to \acro{PDF}). % \begin{macrocode} - \hyxmp@at@end{% - \hyxmp@find@metadata - \hyxmp@embed@packet + \pdfmark{% + pdfmark=/PUT,Raw={% + \string{Catalog\string} << + /Lang (\@pdflang) + >> + }% }% - }{% - \PackageWarningNoLine{hyperxmp}{% - \jobname.tex failed to include a\MessageBreak - \string\usepackage\string{hyperref\string} - in the preamble.\MessageBreak - Consequently, all hyperxmp functionality will be\MessageBreak - disabled}% }% } % \end{macrocode} -% -% A number of classes either require or recommend that authors declare -% various class-specific metadata \emph{after} the |\begin{document}|. -% So where do we invoke \cs{hyxmp@auto@assign@data}? On one hand, we -% want to invoke it before the |\begin{document}| because this may -% obviate \pkgname{hyperxmp}'s ``\meta{job name} did not specify any -% metadata'' warning message. On the other hand, we want to invoke it -% after the |\begin{document}| so it picks up metadata not specified in -% the preamble. Our solution is to invoke \cs{hyxmp@auto@assign@data} -% twice: both before the |\begin{document}| at at the |\end{document}|. -% \begin{macrocode} -\hyxmp@at@end{\hyxmp@auto@assign@data} -% \end{macrocode} +% \end{macro} % % % \subsection{Manipulating author-supplied data} @@ -4628,7 +4813,7 @@ _______________________________________________________________^^J% % Assign |\hyxmp@major@minor| to be the \acro{PDF} version targeted by % the running \TeX\ engine. % \changes{v5.2}{2020/05/10}{Added this macro. \string\pkgname{hyperxmp} -% now correctly specifies \string\xmpterm{pdf:PDFVersion} when +% now correctly specifies \string\xmpprop{pdf:PDFVersion} when % generating \string\acro{PDF}~2.0+. Thanks to Ulrike Fischer for % alerting me to \string\acro{PDF}~2.0's availability in the % \string\TeX\ ecosystem and informing me how to activate it} @@ -4852,11 +5037,11 @@ ______^^J% % \end{macro} % % \begin{macro}{\hyxmp@cond@dc@identifier} -% Conditionally add a \xmpterm{dc:identifier} tag. Given a prefix +% Conditionally add a \xmpprop{dc:identifier} tag. Given a prefix % string~(|#1|) and a main string~(|#2|), wrap these in a -% \xmpterm{dc:identifier} if the main string is nonempty and +% \xmpprop{dc:identifier} if the main string is nonempty and % |\hyxmp@xmlified| \emph{is} empty (implying the -% \xmpterm{dc:identifier} has not yet been written). +% \xmpprop{dc:identifier} has not yet been written). % \changes{v5.2}{2020/04/29}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@cond@dc@identifier}[2]{% @@ -4883,14 +5068,19 @@ ______^^J% % the author specified \optname{pdftype}, and the % \xmpprop{dc:identifier} if the author specified % \optname{pdfidentifier} or if we can derive it from other options. We -% also specify the \xmpprop{dc:date} property using the date the -% document was run through \LaTeX\ and the \xmpprop{dc:source} property -% using the base name of the source file with |.tex| appended. +% also specify the \xmpprop{dc:source} property using the base name of +% the source file with |.tex| appended and the \xmpprop{dc:date} +% property using the date the document was run through \LaTeX---unless +% the author specified \optname{pdfdate}, in which case we use that. % \changes{v2.0}{2012/08/26}{Added support for \xmpprop{dc:language} % and \xmpprop{dc:source}} % \changes{v2.4}{2013/12/21}{Made \xmpprop{dc:language} a \xmpterm{Bag} % instead of an individual item so as to conform to the latest % \acro{XMP} specifications, a detail identified by Florian Breitwieser} +% \changes{v5.3}{2020/06/13}{Include all languages used in the document +% in \protect\xmpprop{dc:language}} +% \changes{v5.4}{2020/06/18}{Bug fix: Use \protect\cs{hyxmp@today@xmp} +% as the date only if \protect\cs{@pdfdatetime} is undefined} % \begin{macrocode} \newcommand*{\hyxmp@dc@schema}{% \hyxmp@add@simple{dc:format}{application/pdf}% @@ -4898,7 +5088,11 @@ ______^^J% \hyxmp@rdf@dc[\ifHy@pdfa]{description}{\@pdfsubject}% \hyxmp@rdf@dc{rights}{\@pdfcopyright}% \hyxmp@singleton@dc{publisher}{\@pdfpublisher}% - \hyxmp@singleton@dc[Seq]{date}{\hyxmp@today@xmp}% + \@ifmtargexp{\@pdfdatetime}{% + \hyxmp@singleton@dc[Seq]{date}{\hyxmp@today@xmp}% + }{% + \hyxmp@singleton@dc[Seq]{date}{\@pdfdatetime}% + }% \hyxmp@singleton@dc{type}{\@pdftype}% \hyxmp@list@to@xml[\ifHy@pdfa]{creator}{Seq}{\hyxmp@pdfauthor}% \hyxmp@list@to@xml{subject}{Bag}{\hyxmp@pdfkeywords}% @@ -4906,18 +5100,7 @@ ______^^J% \else \hyxmp@add@simple{dc:source}{\@pdfsource}% \fi -% \end{macrocode} -% Set \cs{hyxmp@dc@lang} to either the single language \cs{@pdflang} -% (which may be unspecified) or to a list of languages used in the -% document via \pkgname{polyglossia}. See -% Section~\ref{sec:hyperref-int} for the definition of -% \cs{hyxmp@set@dc@lang}. -% \changes{v5.3}{2020/06/13}{Include all languages used in the document -% in \protect\xmpterm{dc:language}} -% \begin{macrocode} - \hyxmp@set@dc@lang \hyxmp@list@to@xml{language}{Bag}{\hyxmp@dc@lang}% -% \end{macrocode} % If |\@pdfidentifier| is empty, try setting it to each of |\@pdfdoi|, % |\@pdfeissn|, |\@pdfissn|, and |\@pdfisbn|, in turn, with proper % syntactic adjustments. @@ -6254,6 +6437,7 @@ __^^J% % file, which offers the benefit of live hyperlinks in almost all % \acro{PDF} readers. % +% % \subsection{Ensuring proper support} % % \begin{macro}{\next} @@ -6298,6 +6482,7 @@ __^^J% \typeout{Generating PDF/A-1b compliant hyperxmp documentation.} % \end{macrocode} % +% % \subsection{Complying with the PDF/A-1b standard} % % We can't specify \PDFstd{A}{1}{b}{} compliance until after both diff --git a/macros/latex/contrib/hyperxmp/hyperxmp.pdf b/macros/latex/contrib/hyperxmp/hyperxmp.pdf index 28b08b0787..998059c14e 100644 Binary files a/macros/latex/contrib/hyperxmp/hyperxmp.pdf and b/macros/latex/contrib/hyperxmp/hyperxmp.pdf differ diff --git a/macros/latex/contrib/pict2e/README.md b/macros/latex/contrib/pict2e/README.md index cda901f5a1..0e38783414 100644 --- a/macros/latex/contrib/pict2e/README.md +++ b/macros/latex/contrib/pict2e/README.md @@ -36,8 +36,5 @@ Recommended TDS locations: pict2e.cfg: tex/latex/[TEXDIST]/graphics.cfg ``` -For general installation advice, see -http://www.tex.ac.uk/cgi-bin/texfaq2html?label=instpackages - For bug reports use the GitHub repository: https://github.com/rolfn/pict2e/issues diff --git a/macros/latex/contrib/pict2e/p2e-drivers.pdf b/macros/latex/contrib/pict2e/p2e-drivers.pdf index fe1a1c89af..12c0741fba 100644 Binary files a/macros/latex/contrib/pict2e/p2e-drivers.pdf and b/macros/latex/contrib/pict2e/p2e-drivers.pdf differ diff --git a/macros/latex/contrib/pict2e/pict2e.dtx b/macros/latex/contrib/pict2e/pict2e.dtx index 9c2b986cc2..cccd714da7 100644 --- a/macros/latex/contrib/pict2e/pict2e.dtx +++ b/macros/latex/contrib/pict2e/pict2e.dtx @@ -23,7 +23,7 @@ % %<*package> \NeedsTeXFormat{LaTeX2e}[1999/12/01] -\ProvidesPackage{pict2e}[2020/06/13 v0.3d Improved picture commands (HjG,RN,JT)] +\ProvidesPackage{pict2e}[2020/06/20 v0.3e Improved picture commands (HjG,RN,JT)] % % %<*driver> @@ -63,9 +63,9 @@ % \fi % % \GetFileInfo{pict2e.sty} -% \def\docdate{2020/06/13} +% \def\docdate{2020/06/20} % -% \CheckSum{2157} +% \CheckSum{2206} % % ^^A ======== % @@ -188,6 +188,8 @@ % \changes{v0.2z}{2014/01/12}{Conflict wit epic, eepic solved. (JT)} % \changes{v0.3a}{2016/01/09}{Local line types, documentation fixes. (JT)} % \changes{v0.3d}{2020/06/13}{\cmd{\@sline} renamed \cmd{\pIIe@sline} (RN)} +% \changes{v0.3e}{2020/06/20}{Added \cmd{\Vector}, \cmd{\polyvector} +% suggested by FMi (RN)} % \fi % % \changes{v0.1a}{2003/07/18}{First version. (RN)} @@ -1284,26 +1286,32 @@ % An equivalent \cmd{\pIIearc} to \cmd{\arc} is defined to solve possible % conflicts with other packages. % -% \subsubsection{Lines, polygons} +% \subsubsection{Line, Vector, polyline, polyvector, and polygon} % \label{sec:usage:lines+polygons} % % \DescribeMacro\Line % \DescribeMacro\polyline +% \DescribeMacro\Vector +% \DescribeMacro\polyvector % \DescribeMacro\polygon % \DescribeMacro{\polygon*} % |\Line|\parg{X1,Y1}\parg{X2,Y2}\\ % |\polyline|\parg{X1,Y1}\parg{X2,Y2}\dots\parg{Xn,Yn}\\ +% |\Vector|\parg{X1,Y1}\parg{X2,Y2}\\ +% |\polyvector|\parg{X1,Y1}\parg{X2,Y2}\dots\parg{Xn,Yn}\\ % |\polygon|\parg{X1,Y1}\parg{X2,Y2}\dots\parg{Xn,Yn}\\ % |\polygon*|\parg{X1,Y1}\parg{X2,Y2}\dots\parg{Xn,Yn}\\ % A natural way how to describe a line segment is to give the coordinates of -% the endpoints. The syntax of the \cmd{\line} is different because +% the endpoints. The syntax of the \cmd{\line}/\cmd{\vector} is different +% because % the lines in the standard \texttt{picture} environment are made from small % line segments of a limited number of slopes given in a font. However, this % package changes the \cmd{\line} command computing the coordinates of the % endpoints and using an internal macro for drawing a line segment with given % endpoints. Hence it would be crazy do not use this possibility directly. -% This is done by the command \cmd{\Line}. The command \cmd{\polyline} draws a -% stroken line connecting points with given coordinates. The command +% This is done by the commands \cmd{\Line} and \cmd{\Vector}. The commands +% \cmd{\polyline} and \cmd{\polyvector} draws a +% stroken line/vector connecting points with given coordinates. The command % \cmd{\polygon} draws a polygon with given vertices, the star variant gives % filled polygon. At least two points should be given. % @@ -2203,7 +2211,7 @@ % \] % and $t = x/s$ and $\tau = 2(t-1/2)$. % \end{quote} -% \changes{v0.2r}{2005/07/15}{Two wrong global assignment changed. (RN)} +% \changes{v0.2r}{2005/07/15}{Two wrong global assignments changed. (RN)} % \begin{macrocode} \newcommand*\pIIe@pyth[3]{% \begingroup @@ -2499,11 +2507,13 @@ \pIIe@divide{\@tempdimb}\dimen@\@ydim \pIIe@divide{\@tempdima}\dimen@\@xdim % \end{macrocode} -% Rotate the following vector\slash arrow outlines by angle $\theta$. +% Rotate the following vector\slash arrow outlines by angle $\theta$:\par +% \BigIndent +% $\cos{\theta}$\quad$\sin{\theta}$\quad$-\sin{\theta}$\quad$\cos{\theta}$\quad $0\quad 0$ % \begin{macrocode} \pIIe@concat\@xdim\@ydim{-\@ydim}\@xdim\z@\z@ % \end{macrocode} -% Internal command to draw the outline of the vector\slash arrow. +% Internal command to draw the outline of the vector\slash arrow. % \begin{macrocode} \pIIe@vector \pIIe@fillGraph @@ -3196,15 +3206,14 @@ % We abuse \cmd{\@setfpsbit} from the float processing modules of the % kernel. % ^^A (Should this go to section low-level?) -% \begin{macrocode} +% \begin{macrocode} \newcommand*\pIIe@get@quadrants[1]{% \@ovttrue \@ovbtrue \@ovltrue \@ovrtrue \@tempcnta\z@ \@tfor\reserved@a:=#1\do{\csname @ov\reserved@a false\endcsname}% \if@ovr \if@ovb\@setfpsbit2\fi \if@ovt\@setfpsbit4\fi \fi \if@ovl \if@ovb\@setfpsbit1\fi \if@ovt\@setfpsbit8\fi \fi} -% \end{macrocode} +% \end{macrocode} % \end{macro} -% % \subsubsection{Quadratic Bezier Curve} % \label{sec:implementation:bezier-curves} % @@ -3259,7 +3268,6 @@ \fi} % \end{macrocode} % \end{macro} -% % \begin{macro}{\pIIe@bezier@QtoC} % \changes{v0.1u}{2003/11/21}{New ancillary macro (HjG)} % Ancillary macro; saves us some tokens above. @@ -3271,10 +3279,10 @@ % \noindent % (Missing: Reference for mathematical formula. Or is this trivial?) % \begin{macrocode} - \newcommand*\pIIe@bezier@QtoC[3]{% - \@tempdimc#1\relax \advance\@tempdimc-#2\relax - \divide\@tempdimc\thr@@ \advance\@tempdimc #2\relax - #3\@tempdimc} + \newcommand*\pIIe@bezier@QtoC[3]{% + \@tempdimc#1\relax \advance\@tempdimc-#2\relax + \divide\@tempdimc\thr@@ \advance\@tempdimc #2\relax + #3\@tempdimc} % \end{macrocode} % \end{macro} % @@ -3404,13 +3412,17 @@ % \end{macrocode} % \end{macro} % -% \subsubsection{Lines and polygons} -% \label{sec:implementation:lines-polygons} +% \subsubsection{Line, Vector, polyline, polyvector, and polygon} +% \label{sec:implementation:polyline-polyvector} % +% \changes{v0.3e}{2020/06/20}{Added \cmd{\Vector} and \cmd{\polyvector} +% suggested by FMi. (RN)} % \begin{macro}{\Line} % \begin{macro}{\polyline} +% \begin{macro}{\Vector} +% \begin{macro}{\polyvector} % \begin{macro}{\polygon} -% We use recursive macros for \cmd{\polyline} and \cmd{\polygon}. +% We use recursive macros for \cmd{\polyline}, \cmd{\polyvector}, and \cmd{\polygon}. % \begin{macrocode} \let\lp@r( \let\rp@r) \def\Line(#1,#2)(#3,#4){\polyline(#1,#2)(#3,#4)} @@ -3423,6 +3435,33 @@ \def\@polyline(#1,#2){% \pIIe@lineto{#1\unitlength}{#2\unitlength}% \@ifnextchar\lp@r{\@polyline}{\pIIe@strokeGraph\ignorespaces}} + \def\Vector(#1,#2)(#3,#4){\polyvector(#1,#2)(#3,#4)} + \def\polyvector(#1,#2){% + \@killglue + \@ifnextchar\lp@r{\begingroup\@polyvector(#1,#2)}{% + \PackageWarning{pict2e}% + {Polygonal vectors require at least two vertices!}\ignorespaces}} + \def\@polyvector(#1,#2)(#3,#4){% +% \end{macrocode} +% See the similar definition for \cmd{\vector} (\ref{sec:implementation:vector}) +% \begin{macrocode} + \@xdim#1\unitlength \@tempdima=#3\unitlength + \@ydim#2\unitlength \@tempdimb=#4\unitlength + \advance\@tempdima-\@xdim \advance\@tempdimb-\@ydim + \ifdim\@tempdima=\z@ \@linelen\@tempdimb \else + \ifdim\@tempdimb=\z@ \@linelen\@tempdima \else + \pIIe@pyth\@tempdima\@tempdimb\@linelen + \fi + \fi + \ifdim\@linelen<\z@ \@linelen-\@linelen\fi + \pIIe@divide{\@tempdima}\@linelen\@ovxx + \pIIe@divide{\@tempdimb}\@linelen\@ovyy +% \end{macrocode} +% Note the shift to the previous point in addition to the rotation. +% \begin{macrocode} + \pIIe@concat\@ovxx\@ovyy{-\@ovyy}\@ovxx\@xdim\@ydim + \pIIe@vector \pIIe@fillGraph + \@ifnextchar\lp@r{\@polyvector(#3,#4)}{\endgroup\ignorespaces}} \def\polygon{% \@killglue \@ifstar{\begingroup\@tempswatrue\@polygon}% @@ -3441,6 +3480,8 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} % % \subsubsection{Path commands} % \label{sec:implementation:path-commands} diff --git a/macros/latex/contrib/pict2e/pict2e.pdf b/macros/latex/contrib/pict2e/pict2e.pdf index bcc86e4850..bb634560b3 100644 Binary files a/macros/latex/contrib/pict2e/pict2e.pdf and b/macros/latex/contrib/pict2e/pict2e.pdf differ -- cgit v1.2.3