[latex3-commits] [git/LaTeX3-latex3-pdfresources] splitting: split dict in local and global part (9db7e4f)

Ulrike Fischer fischer at troubleshooting-tex.de
Tue Jul 7 19:15:30 CEST 2020


Repository : https://github.com/latex3/pdfresources
On branch  : splitting
Link       : https://github.com/latex3/pdfresources/commit/9db7e4f9e4c1813f0491cb00a12d62a7b85b0deb

>---------------------------------------------------------------

commit 9db7e4f9e4c1813f0491cb00a12d62a7b85b0deb
Author: Ulrike Fischer <fischer at troubleshooting-tex.de>
Date:   Wed Jun 10 00:29:36 2020 +0200

    split dict in local and global part


>---------------------------------------------------------------

9db7e4f9e4c1813f0491cb00a12d62a7b85b0deb
 info/sort-commands.txt          |  91 ++++++++
 l3pdfdict.dtx                   | 429 +++++++++++--------------------------
 l3pdfgdict.dtx                  | 459 ++++++++++++++++++++++++++++++++++++++++
 l3pdfmeta.ins => l3pdfgdict.ins |   6 +-
 pdfresources.dtx                |  51 +----
 5 files changed, 674 insertions(+), 362 deletions(-)

diff --git a/info/sort-commands.txt b/info/sort-commands.txt
new file mode 100644
index 0000000..ce00a90
--- /dev/null
+++ b/info/sort-commands.txt
@@ -0,0 +1,91 @@
+\pdf_version_compare
+\pdf_uncompress:
+\pdf_version_gset
+\pdf_pageobject_ref:n
+\pdf_object_new:nn
+\pdf_object_write:nn
+\pdf_object_ref:nn
+\pdf_object_last:nn
+
+\pdf_bdc
+\pdf_bmc
+\pdf_emc
+
+======================
+pdfprint /output / text / value /content fill store type
+======================
+
+\pdftool_name:n
+\pdftool_name_print:n
+\pdftool_textstringlit
+\pdftool_textstringhex_print:nN
+
+commands using/replacing
+ text_purify /pdfstringdef etc
+
+\pdftext_flag_set % if any should be internal
+
+
+=====================
+pdfcoredict
+=====================
+
+\pdfcoredict_gremove     \pdfdict_gremove:nn,
+\pdfcoredict_gput:nnn    \pdfdict_gput:nnn,
+
+\@@coredict_gnew:n
+
+==================
+pdfq (graphics)
+================
+
+\pdf_xform_new:nnn
+\pdf_xform_use:n
+\pdf_xform_ref:n
+\pdf_xform_wd:n, \pdf_xform_ht:n, \pdf_xform_dp:n
+\pdf_xform_if_exist:n
+
+======
+pdfannot: annotations, links, destinations
+======
+
+\pdfannot:nnn
+\pdfannot_box:nnnn
+\pdfannot_box_last:
+\pdfannot_link:nnn
+\pdfannot_link_begin:nnw
+\pdfannot_link_goto_begin:nw
+\pdfannot_link_last:
+\pdfannot_dest:nn (local) <- pdf_destination:nn
+\pdfannot_dest_box:nn
+
+
+%flags ...
+
+\pdfdict_map:n
+\pdfdict_reset:n (local)
+\pdfdict_show:n (local,global)
+\pdfdict_if_exist:n
+\pdfdict_if_empty:n (global?)
+\pdfdict_get:nn
+\pdfdict_remove:nn,
+
+=======
+pdfmeta
+=======
+
+\pdfmeta_if_named_action_allowed:n
+
+====
+pdfoutline ????
+=====
+outline
+
+\pdffile_embed_file:nnn (embed + filespec)
+\pdffile_embed_stream:nnn
+
+
+==============
+pdffield
+=============
+fields appearances ocr
diff --git a/l3pdfdict.dtx b/l3pdfdict.dtx
index 2a217fe..e04fff0 100644
--- a/l3pdfdict.dtx
+++ b/l3pdfdict.dtx
@@ -32,7 +32,7 @@
 % \fi
 %
 % \title{^^A
-%   The \pkg{l3pdfdict} package\\ Managing global and local dictionaries ^^A
+%   The \pkg{l3pdfdict} package\\ Managing local dictionaries ^^A
 % }
 %
 % \author{^^A
@@ -51,55 +51,25 @@
 %
 % \section{\pkg{l3pdfdict} documentation}
 % Many features of a PDF are set by adding a (pdf-)Name and a value
-% to specific PDF dictionaries. The commands in this module offer an interface to
-% these dictionaries. They unify a number of primitives like the pdftex
-% registers \cs{pdfcatalog}, \cs{pdfpagesattr}, \cs{pdfinfo} and similar commands
-% of the other backends  in a backend independant way.
+% to specific PDF dictionaries. Examples are attributes of links,
+% filespec dictionaries, xform dictionaries.
+% The commands in this module offer an number of
+% tools to handle such dictionaries. The main purpose of the code
+% here is to give packages and users a better interface to add or
+% change values of such objects.
 %
-% There are two distinct types of dictionaries
-% \begin{description}
-%    \item[Global dictionaries] These are dictionaries which are inserted only
-%    once in a PDF or only once per page. Examples are the Catalog dictionary,
-%    the Info dictionary, the page resources. For these dictionaries it is necessary
-%    that all package which want to write to them uses the interface provided
-%    by this module to avoid clashes and incompatibilities. Values to these
-%    dictionaries are always added globally and written by the code
-%    at a suitable time to the PDF.
-%    Global dictionaries are set and manipulated with the global commands, e.g.
-%    \cs{pdf_dict_gput:nnn}. Global dictionaries have names starting with an
-%    uppercase letter.
+% The dictionaries are implemented with local property lists.
+% All assignments are local.
 %
-%    \item[Local dictionaries ] These are dictionaries which are used in varying
-%    numberswith varying content. Examples are attributes of links,
-%    filespec dictionaries, xform dictionaries. The main purpose of the code
-%    here is to give packages and users a better interface to add or
-%    change values of such objects.
-%
-%    Local dictionaries are set and manipulated with the local commands, e.g.
-%    \cs{pdf_dict_put:nnn}. By convention their name start with a lowercase.
-%  \end{description}
-%
-% The following tabular summarize the dictionaries and which pdftex primitive they
-% replace:
+% The following tabular summarize the dictionaries
 % \begin{tabular}{lll}
-%  Info                                  & \cs{pdfinfo}    &global\\
-%  Catalog \&  various subdictionaries   & \cs{pdfcatalog} &global\\
-%  Pages                                 & \cs{pdfpagesattr}&global\\
-%  Page, ThisPage                        & \cs{pdfpageattr}&global\\
-%  Page/Resources/ExtGState              & \cs{pdfpageresources}&global\\
-%  Page/Resources/Shading                & \cs{pdfpageresources}&global\\
-%  Page/Resources/Pattern                & \cs{pdfpageresources}&global\\
-%  Page/Resources/ColorSpace             & \cs{pdfpageresources}&global\\%
 %  xform\ldots                           & argument of \cs{pdfxform} &local\\
 %  annot\ldots                           & argument of \cs{pdfannot},
 %                                          \cs{pdfstartlink} &local\\
 %  \end{tabular}
-%
-%  The /Properties dictionary of the page resources is not handled by this module. It is
-%  filled and managed through side effects when setting BDC-marks.
+
 %  \subsection{User Commands}
 % \begin{NOTE}{UF}
-% global: upper case: Catalog, Pages.
 % local:  lower case: annot/link/URI.
 % \end{NOTE}
 % \begin{function}[added = 2020-04-21]
@@ -112,10 +82,9 @@
 % \begin{function}[added = 2020-04-06]
 %   {\pdfdict_put:nnn, \pdfdict_gput:nnn}
 %   \begin{syntax}
-%     \cs{pdfdict_gput:nnn} \Arg{global dictionary} \Arg{name} \Arg{value}\\
 %     \cs{pdfdict_put:nnn} \Arg{local dictionary} \Arg{name} \Arg{value}
 %   \end{syntax}
-% This function puts \Arg{name} \Arg{value} either globally or locally in internal
+% This function puts \Arg{name} \Arg{value} locally in an internal
 % property lists.
 %
 % \Arg{dictionary} is a symbolic name for a concrete PDF dictionary to which the
@@ -127,40 +96,52 @@
 % \Arg{value} should be a valid PDF value for this Name in the
 % target dictionary.
 %
-% The PDF resource management code predefines a large number of
-% symbolic names for important dictionaries and will write the stored values
-% at the right time to the PDF. The predefined symbolic names are described below.
-% By convention, dictionaries starting with an uppercase letter are always stored
-% globally (e.g. \texttt{Catalog} or \texttt{Info}, lowercase letters indicates
-% dictionaries that respect \TeX-groups -- this is e.g. used for dictionaries used in
-% local objects like links.
-%
-% The code works with all major engines but not necessarily
-% in the same way. Most importantly
+% When adding a value keep in mind that
 % \begin{itemize}
-% \item The expansion behaviour of the backends can differ. Some backends expand a
+% \item the expansion behaviour of the backends can differ. Some backends expand a
 % value always fully when writing to the PDF, with other backends command names
 % could end as strings in the PDF. So one should neither rely on \Arg{name}
 % \Arg{value} to be expanded nor not expanded by the backend commands.
-% \item The number of compilations needed can differ between the engines and backends.
-% Some engines has to use labels and the aux-file to setup the dictionaries and so need
-% at least two compilations to put everything in place.
 % \end{itemize}
 % \end{function}
-
+% \begin{function}[EXP,added = 2020-04-21]
+%   {\pdfdict_map:n }
+%   \begin{syntax}
+%     \cs{pdfdict_map:n}  \Arg{dictionary}
+%   \end{syntax}
+%   This outputs the property list of the dictionary as a list of
+%   \texttt{/key value} pairs.
+%   This can be used e.g. when writing a dictionary object with
+%   \cs{pdf_object_write:nx}
+% \end{function}
+% \begin{function}[added = 2020-04-25]
+%   {\pdfdict_reset:n }
+%   \begin{syntax}
+%     \cs{pdfdict_reset:n}  \Arg{(local) dictionary}
+%   \end{syntax}
+% This resets a dictionary: it clears the entries and then adds eventually
+% default values (normally at least the Type entry).
+%  \end{function}
+%  \begin{function}[added = 2020-04-08]
+%   {\pdfdict_show:n }
+%   \begin{syntax}
+%     \cs{pdfdict_show:n}  \Arg{dictionary}
+%   \end{syntax}
+%   This shows the content of \Arg{dictionary} in the log and on the terminal.
+%\end{function}
 % \end{documentation}
 %
 % \begin{implementation}
-%<@@=pdf>
+%<@@=pdfdict>
 %<*package>
 \ProvidesExplPackage {l3pdfdict} {2020-04-08} {0.5}
-  {Managing global and local dictionaries}
+  {Managing local dictionaries}
 % \section{\pkg{l3pdfdict} implementation}
 % \begin{macro}{\pdfdict_new:n}
 %    \begin{macrocode}
 \cs_new_protected:Npn \pdfdict_new:n #1
   {
-    \@@_dict_new:n {#1}
+    \@@_new:n {#1}
   }
 %    \end{macrocode}
 % \end{macro}
@@ -169,28 +150,16 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \pdfdict_put:nnn #1 #2 #3
   {
-    \@@_dict_if_local:nTF { #1 }
+    \@@_if_exist:nTF { #1 }
       {
-        \@@_dict_handler_put:nnn { #1 }{ #2 }{ #3 }
+        \@@_handler_put:nnn { #1 }{ #2 }{ #3 }
       }
       {
         \msg_error:nnnn{pdfdict}{wrong-or-unknown-dict}{#1}{local}
       }
   }
 
-\cs_new_protected:Npn \pdfdict_gput:nnn #1 #2 #3
-  {
-    \@@_dict_if_global:nTF { #1 }
-      {
-        \@@_dict_handler_put:nnn { #1 }{ #2 }{ #3 }
-      }
-      {
-        \msg_error:nnnn{pdfdict}{wrong-or-unknown-dict}{#1}{global}
-      }
-  }
-
 \cs_generate_variant:Nn \pdfdict_put:nnn {nnx,nno}
-\cs_generate_variant:Nn \pdfdict_gput:nnn {nnx}
 %    \end{macrocode}
 % \subsection{Internal dictionary Code}
 %  Many code parts are quite similar: property lists for
@@ -198,31 +167,8 @@
 %  So we define some generic commands to ensure systematic
 %  internal names. The names are based on paths separated by slashed.
 %  The first slash is not used in the names.
-%
-%  Currently the following names are used: ^^A!!!!! check, compare with g_@@_dict_gnames_seq
-%  \begin{verbatim}
-%  /Info                      %    (\pdfinfo)
-%  /Catalog                   %    (\pdfcatalog)
-%  /Catalog/AA                %
-%  /Catalog/AcroForm
-%  /Catalog/OCProperties
-%  /Catalog/OutputIntents
-%  /Catalog/AcroForm/DR
-%  /Catalog/AcroForm/DR/Font
-%  /Catalog/MarkInfo
-%  /Catalog/ViewerPreferences
-%  /Pages                     %    (\pagesattr)
-%  /Page                      %    (\pageattr)
-%  /ThisPage                  %    (\pageattr)
-%  /backend_PageN/Resources/Properties %
-%  /Page/Resources/ExtGState
-%  /Page/Resources/ColorSpace
-%  /Page/Resources/Pattern
-%  /Page/Resources/Shading
-%  /Page/Resources/Properties
-%  /xform/Resources/Properties
-%  \end{verbatim}
-% \begin{macro}{\@@_dict_item:nn,\@@_dict_objref_item:nn}
+
+% \begin{macro}{\@@_item:nn,\@@_objref_item:nn}
 % Commands to output dict entries: The arguments are \meta{name}\meta{value} and
 % \meta{name}\meta{object name}, \meta{name} should be a valid pdf name without
 % the slash.
@@ -230,87 +176,38 @@
 % in the pdf layer at the input.
 % \begin{NOTE}{UF}
 %TODO: check expansion behaviour of \cs{@@_dict_objref_item:nn} in the various uses
+%TODO: this should perhaps be move to the module for "content output"
 % \end{NOTE}
 %    \begin{macrocode}
-\cs_new:Npn \@@_dict_item:nn #1 #2 { /#1~#2~ } %name, value
-\cs_generate_variant:Nn \@@_dict_item:nn {ne}
+\cs_new:Npn \@@_item:nn #1 #2 { /#1~#2~ } %name, value
+\cs_generate_variant:Nn \@@_item:nn {ne}
 
-\cs_new:Npn \@@_dict_objref_item:nn #1 #2      %name, object name
+\cs_new:Npn \@@_objref_item:nn #1 #2      %name, object name
   {
-    /#1~\@@_backend_object_ref:n { #2 }
+    /#1~\pdf_object_ref:n { #2 }
   }
 %    \end{macrocode}
 % \end{macro}
 % \begin{macro}
 %   {
-%    \@@_dict_get_g:n,
-%    \@@_dict_gname:n,
 %    \@@_dict_name:n,
-%    \@@_dict_gnew:n,
 %    \@@_dict_new:n,
-%    \g_@@_dict_gnames_seq,
-%    \g_@@_dict_names_seq
+%    \g_@@_names_seq
 %   }
-%   \cs{@@_dict_get_g:n} gives back a \enquote{g} if the dictionary is global.
 %    \begin{macrocode}
-\seq_new:N \g_@@_dict_gnames_seq
-\seq_new:N \g_@@_dict_names_seq
-
-\tl_const:Nn \c_@@_dict_globalprefix_tl {g}
-\tl_const:Nn \c_@@_dict_localprefix_tl  {}
-
-% to retried global status from pathes
-\cs_new:Npn \@@_dict_get_g:n #1 % path name without the leading /
-  {
-   \tl_if_exist:cT {c_@@_dict_/#1_g_tl}
-     {
-      \tl_use:c {c_@@_dict_/#1_g_tl}
-     }
-  }
-
-%global
-\cs_new:Npn \@@_dict_gname:n #1 % path name without the leading /
-  {
-    g_@@_dict_/#1_prop
-  }
+\seq_new:N \g_@@_names_seq
 
 %local
 \cs_new:Npn \@@_dict_name:n #1 % path name without the leading /
   {
-    l_@@_dict_/#1_prop
-  }
-
-
-%  hm, a bit unclear, can this work? How is expansion?
-%  it falls back to prop_name if the path doesn't exist.
-%  Can this lead to confusion?
-%
-\cs_new:Npn \@@_dict_Xname:n #1 % path name without the leading /
-  {
-    \use:c { @@_dict_\@@_dict_get_g:n{#1}name:n } { #1 }
+    l_@@_/#1_prop
   }
 
-%global
-\cs_new_protected:Npn \@@_dict_gnew:n #1
-  {
-    \@@_dict_if_exist:nTF { #1 }
-      {
-        \msg_error:nnx
-          { pdfdict }
-          { dict-already-defined }
-          { #1}
-       }
-      {
-        \tl_const:cn { c_@@_dict_/#1_g_tl } { g }
-        \prop_new:c  { \@@_dict_gname:n { #1 } }
-        \seq_gput_right:Nn \g_@@_dict_gnames_seq { #1 }
-      }
-  }
 
 %local
-\cs_new_protected:Npn \@@_dict_new:n #1
+\cs_new_protected:Npn \@@_new:n #1
   {
-    \@@_dict_if_exist:nTF { #1 }
+    \@@_if_exist:nTF { #1 }
       {
         \msg_error:nnx
           { pdfdict }
@@ -318,126 +215,67 @@
           { #1}
        }
       {
-        \tl_const:cn { c_@@_dict_/#1_g_tl } {  }
-        \prop_new:c  { \@@_dict_name:n { #1 } }
-        \seq_gput_right:Nn \g_@@_dict_names_seq { #1 }
+        \prop_new:c  { \@@_name:n { #1 } }
+        \seq_gput_right:Nn \g_@@_names_seq { #1 }
       }
   }
 
 % test existence
-\prg_new_conditional:Npnn \@@_dict_if_exist:n #1 { p , T , F , TF }
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
   {
-    \tl_if_exist:cTF
-      { c_@@_dict_/#1_g_tl }
+    \prop_if_exist:cTF
+      { \@@_name:n { #1 } }
       { \prg_return_true: }
       { \prg_return_false: }
   }
-% test if global, non existing dicts return false
-\prg_new_conditional:Npnn \@@_dict_if_global:n #1 { p , T , F , TF }
-   {
-     \tl_if_eq:NcTF
-        \c_@@_dict_globalprefix_tl
-        { c_@@_dict_/#1_g_tl }
-        { \prg_return_true: }
-        { \prg_return_false: }
-   }
-% test if local, non existing dicts return false
-\prg_new_conditional:Npnn \@@_dict_if_local:n #1 { p , T , F , TF }
-   {
-     \tl_if_eq:NcTF
-        \c_@@_dict_localprefix_tl
-        { c_@@_dict_/#1_g_tl }
-        { \prg_return_true: }
-        { \prg_return_false: }
-   }
 
-\prg_new_conditional:Npnn \@@_dict_if_empty:n #1 { p , T , F , TF }
+\prg_new_conditional:Npnn \@@_if_empty:n #1 { p , T , F , TF }
   {
     \prop_if_empty:cTF
-      { \@@_dict_Xname:n { #1 } }
+      { \@@_name:n { #1 }}
       { \prg_return_true: }
       { \prg_return_false: }
   }
 %    \end{macrocode}
 %  \end{macro}
 %  \begin{macro}{
-%                \@@_dict_clear,
-%                \@@_dict_reset,
-%                \@@_dict_handler_put:nnn,
-%                \@@_dict_get:nnN,
-%                \@@_dict_remove:nn,
-%                \@@_dict_show:n
+%                \@@_clear:n,
+%                \@@_reset:n,
+%                \@@_put:nnn,
+%                \@@_get:nnN,
+%                \@@_remove:nn,
+%                \@@_show:n
 %                }
-%  \cs{@@_dict_handler_put:nnn} is the main command to fill the dictionaries.
-%  In simple cases it directly fill the property list, but if a handler exists
-%  this is called. It is important to use it only in places where this make sense.
-%  \cs{@@_dict_put:nnn} is a simpler variant which only fills the property list.
 %
 %    \begin{macrocode}
-
-%we allow only for local dictionaries a clear command
-\cs_new_protected:Npn \@@_dict_clear:n #1
+\cs_new_protected:Npn \@@_clear:n #1
   {
-    \@@_dict_if_local:nT { #1 }
+    \@@_if_exist:nT { #1 }
       {
-        \prop_clear:c  { \@@_dict_name:n { #1 } }
+        \prop_clear:c  { \@@_name:n { #1 } }
       }
   }
 
-%reset clears and then fills with the default
-\cs_new_protected:Npn \@@_dict_reset:n #1
+\cs_new_protected:Npn \@@_reset:n #1
   {
-    \@@_dict_if_local:nT { #1 }
+    \@@_if_exist:nT { #1 }
       {
-        \prop_clear:c  { \@@_dict_name:n { #1 } }
-        \use:c { @@_dict_#1_reset: }
+        \prop_clear:c  { \@@_name:n { #1 } }
+        \use:c {  @@_#1_reset: }
       }
   }
 
-
-%local + global
-\cs_new_protected:Npn \@@_dict_handler_put:nnn #1 #2 #3  %#1 path, #2 name, #3 value
-  {
-    \tl_if_empty:nTF { #3 }
-      {
-        \msg_none:nnn { pdfdict }{ empty-value }{ /#1/#2 }
-      }
-      {
-        \@@_dict_if_exist:nTF { #1 }
-          {
-            \cs_if_exist:cTF
-              { @@_dict_handler/#1/?_\@@_dict_get_g:n{#1}put:nn } %general, name independant handler
-              { \use:c {@@_dict_handler/#1/?_\@@_dict_get_g:n{#1}put:nn} {#2} {#3} }
-              {
-                \cs_if_exist:cTF
-                  { @@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}put:n }
-                  { \use:c {@@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}put:n} {#3} } %special handler
-                  {
-                    \use:c { prop_\@@_dict_get_g:n{#1}put:cnn }
-                      { \@@_dict_Xname:n { #1 } }{ #2 } { #3 }
-                  }
-              }
-          }
-          {
-            \msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
-          }
-      }
-  }
-
-
-\cs_generate_variant:Nn \@@_dict_handler_put:nnn {nxx}
-
-\cs_new_protected:Npn \@@_dict_put:nnn #1 #2 #3  %#1 path, #2 name, #3 value
+\cs_new_protected:Npn \@@_put:nnn #1 #2 #3  %#1 path, #2 name, #3 value
   {
     \tl_if_empty:nTF { #3 }
       {
         \msg_none:nnn { pdfdict }{ empty-value }{ /#1/#2 }
       }
       {
-       \@@_dict_if_exist:nTF { #1 }
+       \@@_if_exist:nTF { #1 }
          {
-           \use:c { prop_\@@_dict_get_g:n{#1}put:cnn }
-             { \@@_dict_Xname:n { #1 } }{ #2 } { #3 }
+           \prop_put:cnn
+             { \@@_name:n { #1 } }{ #2 } { #3 }
          }
          {
            \msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
@@ -445,44 +283,20 @@
       }
   }
 
-%local + global
-
-\cs_new_protected:Npn \@@_dict_get:nnN  #1 #2 #3 %path,key,macro
+\cs_new_protected:Npn \@@_get:nnN  #1 #2 #3 %path,key,macro
   {
     \prop_get:cnN
-      { \use:c{ @@_dict_\tl_use:c{c_@@_dict_/#1_g_tl}name:n } { #1 } }
+      { \@@_name:n } { #1 } }
       { #2 } #3
   }
 
-% local / global
-\cs_new_protected:Npn \@@_dict_handler_remove:nn #1 #2 %path,key
-  {
-    \@@_dict_if_exist:nTF { #1 }
-          {
-            \cs_if_exist:cTF
-              { @@_dict_handler/#1/?_\@@_dict_get_g:n{#1}remove:n } %general, name independant handler
-              { \use:c {@@_dict_handler/#1/?_\@@_dict_get_g:n{#1}remove:n} {#2} }
-              {
-                \cs_if_exist:cTF
-                  { @@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}remove: }
-                  { \use:c {@@_dict_handler/#1/#2_\@@_dict_get_g:n{#1}remove:} } %special handler
-                  {
-                    \use:c { prop_\@@_dict_get_g:n{#1}remove:cn }
-                      { \@@_dict_Xname:n { #1 } }{ #2 }
-                  }
-              }
-          }
-          {
-            \msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
-          }
-  }
 
-\cs_new_protected:Npn \@@_dict_remove:nn #1 #2 %path,key
+\cs_new_protected:Npn \@@_remove:nn #1 #2 %path,key
   {
-    \@@_dict_if_exist:nTF { #1 }
+    \@@_if_exist:nTF { #1 }
           {
-            \use:c { prop_\@@_dict_get_g:n{#1}remove:cn }
-              { \@@_dict_Xname:n { #1 } }{ #2 }
+            \prop_remove:cn
+              { \@@_name:n { #1 } }{ #2 }
           }
           {
             \msg_error:nnn { pdfdict } { unknown-dict } { /#1 }
@@ -490,66 +304,59 @@
   }
 
 
-\cs_new_protected:Npn \@@_dict_show:Nn #1#2
+\cs_new_protected:Npn \@@_show:Nn #1#2
   {
-    \cs_if_exist:cTF
-      { @@_dict_handler/#2/?_show: } %general, name independant handler
-      { \use:c {@@_dict_handler/#2/?_show:} }
-      {
-        \prop_if_exist:cTF { \@@_dict_Xname:n { #2 } }
-          {
-             #1
-               { pdfdict } { show-dict }
-               { \tl_to_str:n {#2} }
-               { \prop_map_function:cN {\@@_dict_Xname:n { #2 }} \msg_show_item:nn }
-               { } { }
-          }
-          {
-            #1 { pdfdict } { unknown-dict } {#2}{}{}{}
-          }
+    \prop_if_exist:cTF { \@@_name:n { #2 } }
+       {
+         #1
+            { pdfdict } { show-dict }
+            { \tl_to_str:n {#2} }
+            { \prop_map_function:cN {\@@_name:n { #2 }} \msg_show_item:nn }
+            { } { }
+       }
+       {
+         #1 { pdfdict } { unknown-dict } {#2}{}{}{}
        }
   }
-\cs_new_protected:Npn \@@_dict_show:n #1  %path
+\cs_new_protected:Npn \@@_show:n #1  %path
   {
-    \prop_show:c { \use:c{ @@_dict_\@@_dict_get_g:n{#1}name:n } { #1 } }
+    \prop_show:c { \@@_name:n } { #1 } }
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{ \@@_dict_map:n }
-% \cs{@@_dict_map:n} outputs a prop as needed in a dictionary:
+% \begin{macro}{ \@@_map:n }
+% \cs{@@_map:n} outputs a prop as needed in a dictionary:
 %  as a list of /\meta{key} \meta{value} pairs.
 %    \begin{macrocode}
-%local + global
-%!! Xname must be replaced later!
-% !! is xexpansion the right thing?
-\cs_new:Npn \@@_dict_map:n #1 %path
+% !! is e-expansion the right thing?
+\cs_new:Npn \@@_map:n #1 %path
   {
-    \prop_map_function:cN { \@@_dict_Xname:n { #1 } } \@@_dict_item:ne
+    \prop_map_function:cN { \@@_name:n { #1 } } \@@_item:ne
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{ \@@_dict_gmerge:nnN }
-% \cs{@@_dict_gmerge:nnN} merges at first the property \meta{name_1}
-%  then optionally \meta{name_2} into property |#3|.
 %    \begin{macrocode}
-% only used globally imho so leaving the global version only for now
-\cs_new_protected:Npn \@@_dict_gmerge:nnN #1 #2 #3
+\cs_new:Npn \pdfdict_map:n #1
   {
-    \prop_gset_eq:Nc #3 { \@@_dict_gname:n  { #1 } }
-    \prop_if_exist:cT  { \@@_dict_gname:n  { #2 } }
-      {
-        \prop_map_inline:cn { \@@_dict_gname:n  { #2 } }
-          {
-            \prop_gput:Nnn #3 { ##1 }{ ##2 }
-          }
-      }
+    \@@_map:n { #1 }
   }
 %    \end{macrocode}
-% \end{macro}
 %
 %    \begin{macrocode}
+\cs_new_protected:Npn \pdfdict_reset:n #1
+  {
+    \@@_reset:n { #1 }
+  }
+%    \end{macrocode}
+%    \begin{macrocode}
+\cs_new_protected:Npn \pdfdict_show:n
+  {
+    \@@_show:Nn \msg_show:nnxxxx {#1}
+  }
+%    \end{macrocode}
+%    \begin{macrocode}
 %</package>
 %    \end{macrocode}
 %
diff --git a/l3pdfgdict.dtx b/l3pdfgdict.dtx
new file mode 100644
index 0000000..696d449
--- /dev/null
+++ b/l3pdfgdict.dtx
@@ -0,0 +1,459 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfgdict.dtx
+%
+% Copyright (C) 2018-2020 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version.  The latest version
+% of this license is in the file
+%
+%    http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "(experimental) pdfresources bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+%    https://github.com/latex3/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \pkg{l3pdfgdict} package\\ Managing core pdf dictionaries ^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX3 Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team at latex-project.org}
+%          {latex-team at latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released XXXX-XX-XX}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfgdict} documentation}
+% The commands in this module offer interfaces to a number of core dictionaries
+% of a PDF. They unify a number of primitives like the pdftex
+% registers \cs{pdfcatalog}, \cs{pdfpagesattr}, \cs{pdfinfo} and similar commands
+% of the other backends  in a backend independant way.
+%
+% The dictionaries handled by these module are inserted only
+% once in a PDF or only once per page. Examples are the Catalog dictionary,
+% the Info dictionary, the page resources. For these dictionaries management by the
+% \LaTeX{} kernel is necessary to avoid that packages overwrite settings from
+% other packages which would lead to clashes and incompatibilities.
+% It is therefor necessary that all packages which want to add content to this
+% dictionaries uses the interface provided by this module.
+%
+% As this dictionaries are so central for the PDF format values to these
+% dictionaries are always added globally. Through the interface values
+% can be added (and in many cases also removed), but the actually writing of the
+% dictionary objects to the PDF are then handled by
+% the kernel code at a suitable time.
+%
+% The names of this core dictionaries follow the names in the PDF reference.
+% They all have names starting with an uppercase letter.
+
+%  \end{description}
+%
+% The following tabular summarize the core dictionaries and which pdftex primitive they
+% replace:
+% \begin{tabular}{ll}
+%  Info                                  & \cs{pdfinfo}           \\
+%  Catalog \&  various subdictionaries   & \cs{pdfcatalog}        \\
+%  Pages                                 & \cs{pdfpagesattr}      \\
+%  Page, ThisPage                        & \cs{pdfpageattr}       \\
+%  Page/Resources/ExtGState              & \cs{pdfpageresources}  \\
+%  Page/Resources/Shading                & \cs{pdfpageresources}  \\
+%  Page/Resources/Pattern                & \cs{pdfpageresources}  \\
+%  Page/Resources/ColorSpace             & \cs{pdfpageresources}  \\%
+%  \end{tabular}
+%
+%  There is no \texttt{Page/Resources/Properties} dictionary in the list
+%  as this is dictionary is not filled directly but
+%  filled and managed through side effects when setting BDC-marks.
+%  \subsection{User Commands}
+%
+% \begin{function}[added = 2020-04-06]
+%   {\pdfgdict_gput:nnn}
+%   \begin{syntax}
+%     \cs{pdfgdict_gput:nnn} \Arg{core dictionary} \Arg{name} \Arg{value}\\
+%   \end{syntax}
+% This function puts \Arg{name} \Arg{value}  globally in an internal
+% property lists.
+%
+% \Arg{core dictionary} is a symbolic name for a concrete PDF dictionary to
+% which the content of these property lists will be written by the PDF
+% resource management code.
+%
+% \Arg{name} should be a valid PDF Name without
+% the starting slash.
+%
+% \Arg{value} should be a valid PDF value for this Name in the
+% target dictionary.
+%
+% The PDF resource management code predefines a large number of
+% symbolic names for important core dictionaries and will write the stored values
+% at the right time to the PDF. The predefined symbolic names are described below.
+%
+% The code works with all major engines but not necessarily
+% in the same way. Most importantly
+% \begin{itemize}
+% \item The expansion behaviour of the backends can differ. Some backends expand a
+% value always fully when writing to the PDF, with other backends command names
+% could end as strings in the PDF. So one should neither rely on \Arg{name}
+% \Arg{value} to be expanded nor not expanded by the backend commands.
+% \item The number of compilations needed can differ between the engines and
+% backends. Some engines have to use labels and the aux-file to setup
+% the dictionaries and so need at least two compilations to put everything
+% in place.
+% \end{itemize}
+% \end{function}
+% \begin{function}[added = 2020-04-08]
+%   {\pdfgdict_show:n }
+%   \begin{syntax}
+%     \cs{pdfgdict_show:n}  \Arg{dictionary}
+%   \end{syntax}
+%   This shows the content of \Arg{dictionary} in the log and on the terminal.
+%   It doesn't show the special catalog dictionaries with arrays as values
+%   as these are filled only at the end of the document. It is not reliable for
+%   page resources as these are filled a shipout.
+%\end{function}
+% \end{documentation}
+%
+% \begin{implementation}
+%    \begin{macrocode}
+%<@@=pdfgdict>
+%<*package>
+%    \end{macrocode}
+\ProvidesExplPackage {l3pdfgdict} {2020-04-08} {0.5}
+  {Managing global and local dictionaries}
+% \section{\pkg{l3pdfgdict} implementation}
+% \subsection{Messages}
+%    \begin{macrocode}
+\msg_new:nnn  { pdfgdict } { unknown-dict }
+  {
+    The~dictionary~'#1'~is~not~declared.
+  }
+\msg_new:nnn  { pdfgdict } { wrong-or-unknown-dict }
+  {
+    The~dictionary~'#1'~is~either~not~a~#2~dictionary\\
+    or~is~not~declared.
+  }
+
+\msg_new:nnn  { pdfgdict } { empty-value }
+              { The~value~for~#1~is~empty~and~will~be~ignored }
+
+\msg_new:nnn  { pdfgdict } { no-removal }
+              { It~is~not~possible~to~remove~values~from~dictionary~'#1'.}
+
+\msg_new:nnn  { pdfgdict } { no-show }
+              { It~is~not~possible~to~show~the~dictionary~'#1'.}
+%    \end{macrocode}
+%    \begin{macrocode}
+\cs_new_protected:Npn \pdfgdict_gput:nnn #1 #2 #3
+  {
+    \@@_if_global:nTF { #1 }
+      {
+        \@@_handler_put:nnn { #1 }{ #2 }{ #3 }
+      }
+      {
+        \msg_error:nnnn{pdfgdict}{wrong-or-unknown-dict}{#1}{core}
+      }
+  }
+
+\cs_generate_variant:Nn \pdfgdict_gput:nnn {nnx}
+%    \end{macrocode}
+% \subsection{Internal dictionary Code}
+%  Many code parts are quite similar: property lists for
+%  dictionaries are filled and output.
+%  So we define some generic commands to ensure systematic
+%  internal names. The names are based on paths separated by slashed.
+%  The first slash is not used in the names.
+%
+%  Currently the following names are used: ^^A!!!!! check, compare with g_@@_gnames_seq
+%  \begin{verbatim}
+%  /Info                      %    (\pdfinfo)
+%  /Catalog                   %    (\pdfcatalog)
+%  /Catalog/AA                %
+%  /Catalog/AcroForm
+%  /Catalog/OCProperties
+%  /Catalog/OutputIntents
+%  /Catalog/AcroForm/DR
+%  /Catalog/AcroForm/DR/Font
+%  /Catalog/MarkInfo
+%  /Catalog/ViewerPreferences
+%  /Pages                     %    (\pagesattr)
+%  /Page                      %    (\pageattr)
+%  /ThisPage                  %    (\pageattr)
+%  /backend_PageN/Resources/Properties %
+%  /Page/Resources/ExtGState
+%  /Page/Resources/ColorSpace
+%  /Page/Resources/Pattern
+%  /Page/Resources/Shading
+%  /Page/Resources/Properties
+%  /xform/Resources/Properties
+%  \end{verbatim}
+% \begin{macro}{\@@_item:nn,\@@_objref_item:nn}
+% Commands to output dict entries: The arguments are \meta{name}\meta{value} and
+% \meta{name}\meta{object name}, \meta{name} should be a valid pdf name without
+% the slash.
+% The commands don't check if the arguments are empty or valid. This should be done
+% in the pdf layer at the input.
+% \begin{NOTE}{UF}
+%TODO: check expansion behaviour of \cs{@@_objref_item:nn} in the various uses
+%This command could be shared with pdfdict, but is it worth the trouble?
+% \end{NOTE}
+%    \begin{macrocode}
+\cs_new:Npn \@@_item:nn #1 #2 { /#1~#2~ } %name, value
+\cs_generate_variant:Nn \@@_item:nn {ne}
+
+\cs_new:Npn \@@_objref_item:nn #1 #2      %name, object name
+  {
+    /#1~\pdf_object_ref:n { #2 }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}
+%   {
+%    \@@_name:n,
+%    \@@_new:n,
+%    \g_@@_names_seq,
+%   }
+%    \begin{macrocode}
+\seq_new:N \g_@@_names_seq
+
+\cs_new:Npn \@@_name:n #1 % path name without the leading /
+  {
+    g_@@_/#1_prop
+  }
+
+\cs_new_protected:Npn \@@_new:n #1
+  {
+    \@@_if_exist:nTF { #1 }
+      {
+        \msg_error:nnx
+          { pdfgdict }
+          { dict-already-defined }
+          { #1}
+       }
+      {
+        \prop_new:c  { \@@_name:n { #1 } }
+        \seq_gput_right:Nn \g_@@_names_seq { #1 }
+      }
+  }
+
+% test existence
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
+  {
+    \prop_if_exist:cTF
+      { \@@_name:n { #1 } }
+      { \prg_return_true: }
+      { \prg_return_false: }
+  }
+
+\prg_new_conditional:Npnn \@@_if_empty:n #1 { p , T , F , TF }
+  {
+    \prop_if_empty:cTF
+      { \@@_name:n { #1 } }
+      { \prg_return_true: }
+      { \prg_return_false: }
+  }
+%    \end{macrocode}
+%  \end{macro}
+%  \begin{macro}{
+%                \@@_handler_gput:nnn,
+%                \@@_gput:nnn,
+%                \@@_get:nnN,
+%                \@@_gremove:nn,
+%                \@@_show:n
+%                }
+%  \cs{@@_handler_gput:nnn} is the main command to fill the dictionaries.
+%  In simple cases it directly fill the property list, but if a handler exists
+%  this is called. It is important to use it only in places where this make sense.
+%  \cs{@@_put:nnn} is a simpler variant which only fills the property list.
+%
+%    \begin{macrocode}
+
+%global
+\cs_new_protected:Npn \@@_handler_gput:nnn #1 #2 #3  %#1 path, #2 name, #3 value
+  {
+    \tl_if_empty:nTF { #3 }
+      {
+        \msg_none:nnn { pdfgdict }{ empty-value }{ /#1/#2 }
+      }
+      {
+        \@@_if_exist:nTF { #1 }
+          {
+            \cs_if_exist:cTF
+              { @@_handler/#1/?_gput:nn } %general, name independant handler
+              { \use:c {@@_handler/#1/?_gput:nn} {#2} {#3} }
+              {
+                \cs_if_exist:cTF
+                  { @@_handler/#1/#2_gput:n }
+                  { \use:c {@@_handler/#1/#2_gput:n} {#3} } %special handler
+                  {
+                    \use:c { prop_gput:cnn }
+                      { \@@_name:n { #1 } }{ #2 } { #3 }
+                  }
+              }
+          }
+          {
+            \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+          }
+      }
+  }
+
+
+\cs_generate_variant:Nn \@@_handler_gput:nnn {nxx}
+
+\cs_new_protected:Npn \@@_gput:nnn #1 #2 #3  %#1 path, #2 name, #3 value
+  {
+    \tl_if_empty:nTF { #3 }
+      {
+        \msg_none:nnn { pdfgdict }{ empty-value }{ /#1/#2 }
+      }
+      {
+       \@@_if_exist:nTF { #1 }
+         {
+           \use:c { prop_gput:cnn }
+             { \@@_name:n { #1 } }{ #2 } { #3 }
+         }
+         {
+           \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+         }
+      }
+  }
+
+\cs_new_protected:Npn \@@_get:nnN  #1 #2 #3 %path,key,macro
+  {
+    \prop_get:cnN
+      { \@@_name:n { #1 } }
+      { #2 } #3
+  }
+
+
+\cs_new_protected:Npn \@@_handler_gremove:nn #1 #2 %path,key
+  {
+    \@@_if_exist:nTF { #1 }
+          {
+            \cs_if_exist:cTF
+              { @@_handler/#1/?_gremove:n } %general, name independant handler
+              { \use:c {@@_handler/#1/?_gremove:n} {#2} }
+              {
+                \cs_if_exist:cTF
+                  { @@_handler/#1/#2_gremove: }
+                  { \use:c {@@_handler/#1/#2_gremove:} } %special handler
+                  {
+                    \prop_gremove:cn
+                      { \@@_name:n { #1 } }{ #2 }
+                  }
+              }
+          }
+          {
+            \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+          }
+  }
+
+\cs_new_protected:Npn \@@_gremove:nn #1 #2 %path,key
+  {
+    \@@_if_exist:nTF { #1 }
+          {
+            \prop_gremove:cn
+              { \@@_name:n { #1 } }{ #2 }
+          }
+          {
+            \msg_error:nnn { pdfgdict } { unknown-dict } { /#1 }
+          }
+  }
+
+
+\cs_new_protected:Npn \@@_show:Nn #1#2
+  {
+    \cs_if_exist:cTF
+      { @@_handler/#2/?_show: } %general, name independant handler
+      { \use:c {@@_handler/#2/?_show:} }
+      {
+        \prop_if_exist:cTF { \@@_name:n { #2 } }
+          {
+             #1
+               { pdfgdict } { show-dict }
+               { \tl_to_str:n {#2} }
+               { \prop_map_function:cN {\@@_name:n { #2 }} \msg_show_item:nn }
+               { } { }
+          }
+          {
+            #1 { pdfgdict } { unknown-dict } {#2}{}{}{}
+          }
+       }
+  }
+
+\cs_new_protected:Npn \@@_show:n #1  %path
+  {
+    \prop_show:c { \@@_name:n { #1 } }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ \@@_map:n }
+% \cs{@@_map:n} outputs a prop as needed in a dictionary:
+%  as a list of /\meta{key} \meta{value} pairs.
+%    \begin{macrocode}
+% !! is e-expansion the right thing?
+\cs_new:Npn \@@_map:n #1 %path
+  {
+    \prop_map_function:cN { \@@_name:n { #1 } } \@@_item:ne
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ \@@_gmerge:nnN }
+% \cs{@@_gmerge:nnN} merges at first the property \meta{name_1}
+%  then optionally \meta{name_2} into property |#3|.
+%    \begin{macrocode}
+
+\cs_new_protected:Npn \@@_gmerge:nnN #1 #2 #3
+  {
+    \prop_gset_eq:Nc #3 { \@@_name:n  { #1 } }
+    \prop_if_exist:cT  { \@@_name:n  { #2 } }
+      {
+        \prop_map_inline:cn { \@@_name:n  { #2 } }
+          {
+            \prop_gput:Nnn #3 { ##1 }{ ##2 }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%    \begin{macrocode}
+\cs_new_protected:Npn \pdfgdict_show:n
+  {
+    \@@_show:Nn \msg_show:nnxxxx {#1}
+  }
+%    \end{macrocode}
+
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/l3pdfmeta.ins b/l3pdfgdict.ins
similarity index 93%
copy from l3pdfmeta.ins
copy to l3pdfgdict.ins
index d2e63a0..0454aa8 100644
--- a/l3pdfmeta.ins
+++ b/l3pdfgdict.ins
@@ -1,6 +1,6 @@
 \iffalse meta-comment
 
-File: l3pdffile.ins
+File: l3pdfgdict.ins
 
 Copyright (C) 2018-2020 The LaTeX3 Project
 
@@ -53,9 +53,9 @@ and all files in that bundle must be distributed together.
 
 \keepsilent
 
-\generate{\file{l3pdfmeta.sty}
+\generate{\file{l3pdfgdict.sty}
   {
-    \from{l3pdfmeta.dtx}            {package}
+    \from{l3pdfgdict.dtx}            {package}
   }
 }
 
diff --git a/pdfresources.dtx b/pdfresources.dtx
index 9c46036..b384baa 100644
--- a/pdfresources.dtx
+++ b/pdfresources.dtx
@@ -366,56 +366,11 @@
 %</package>
 %<*package>
 %    \begin{macrocode}
+\RequirePackage{l3pdfgdict}
 \RequirePackage{l3pdfdict}
+
 %    \end{macrocode}
-% \begin{function}[EXP,added = 2020-04-21]
-%   {\pdfdict_map:n }
-%   \begin{syntax}
-%     \cs{pdfdict_map:n}  \Arg{dictionary}
-%   \end{syntax}
-%   This outputs the property list of the dictionary as a list of
-%   \texttt{/key value} pairs.
-%   This is suitable for simple, local dictionaries which can be written directly
-%   to the PDF.
-% \end{function}
-%    \begin{macrocode}
-\cs_new:Npn \pdfdict_map:n #1
-  {
-    \@@_dict_map:n { #1 }
-  }
-%    \end{macrocode}
-%
-% \begin{function}[added = 2020-04-25]
-%   {\pdfdict_reset:n }
-%   \begin{syntax}
-%     \cs{pdfdict_reset:n}  \Arg{(local) dictionary}
-%   \end{syntax}
-% This resets a dictionary: it clears the entries and then adds eventually
-% default values (normally at least the Type entry).
-%  \end{function}
-%    \begin{macrocode}
-\cs_new_protected:Npn \pdfdict_reset:n #1
-  {
-    \@@_dict_reset:n { #1 }
-  }
-%    \end{macrocode}
-% \begin{function}[added = 2020-04-08]
-%   {\pdfdict_show:n }
-%   \begin{syntax}
-%     \cs{pdfdict_show:n}  \Arg{dictionary}
-%   \end{syntax}
-%   This shows the content of \Arg{dictionary} in the log and on the terminal.
-%   It also shows if  \Arg{dictionary} is a local or a global dictionary.
-%   It doesn't show the special catalog dictionaries with arrays as values
-%   as these are filled only at
-%   the end of the document.
-%\end{function}
-%    \begin{macrocode}
-\cs_new_protected:Npn \pdfdict_show:n
-  {
-    \@@_dict_show:Nn \msg_show:nnxxxx
-  }
-%    \end{macrocode}
+
 % \begin{function}[EXP, pTF,added = 2020-04-08]
 %   {\pdfdict_if_exist:n }
 %   \begin{syntax}





More information about the latex3-commits mailing list.