├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.lua ├── etoolbox.def ├── etoolbox.sty ├── etoolbox.tex ├── support ├── install.sh └── texlive.profile └── testfiles ├── etoolbox-cmdcopy.dev.tlg ├── etoolbox-cmdcopy.lvt ├── etoolbox-cmdcopy.tlg ├── etoolbox-defs.lvt ├── etoolbox-defs.tlg ├── etoolbox-lists.lvt └── etoolbox-lists.tlg /.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.gz 4 | *.log 5 | *.out 6 | *.toc 7 | 8 | ## Intermediate documents: 9 | *.pdf 10 | 11 | ## Structures for building release 12 | *.zip 13 | build/* 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | install: 2 | - source ./support/install.sh 3 | 4 | cache: 5 | directories: 6 | - /tmp/texlive 7 | 8 | script: 9 | - texlua build.lua check -H 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The LaTeX Project Public License 2 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 3 | 4 | LPPL Version 1.3c 2008-05-04 5 | 6 | Copyright 1999 2002-2008 LaTeX3 Project 7 | Everyone is allowed to distribute verbatim copies of this 8 | license document, but modification of it is not allowed. 9 | 10 | 11 | PREAMBLE 12 | ======== 13 | 14 | The LaTeX Project Public License (LPPL) is the primary license under 15 | which the LaTeX kernel and the base LaTeX packages are distributed. 16 | 17 | You may use this license for any work of which you hold the copyright 18 | and which you wish to distribute. This license may be particularly 19 | suitable if your work is TeX-related (such as a LaTeX package), but 20 | it is written in such a way that you can use it even if your work is 21 | unrelated to TeX. 22 | 23 | The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE', 24 | below, gives instructions, examples, and recommendations for authors 25 | who are considering distributing their works under this license. 26 | 27 | This license gives conditions under which a work may be distributed 28 | and modified, as well as conditions under which modified versions of 29 | that work may be distributed. 30 | 31 | We, the LaTeX3 Project, believe that the conditions below give you 32 | the freedom to make and distribute modified versions of your work 33 | that conform with whatever technical specifications you wish while 34 | maintaining the availability, integrity, and reliability of 35 | that work. If you do not see how to achieve your goal while 36 | meeting these conditions, then read the document `cfgguide.tex' 37 | and `modguide.tex' in the base LaTeX distribution for suggestions. 38 | 39 | 40 | DEFINITIONS 41 | =========== 42 | 43 | In this license document the following terms are used: 44 | 45 | `Work' 46 | Any work being distributed under this License. 47 | 48 | `Derived Work' 49 | Any work that under any applicable law is derived from the Work. 50 | 51 | `Modification' 52 | Any procedure that produces a Derived Work under any applicable 53 | law -- for example, the production of a file containing an 54 | original file associated with the Work or a significant portion of 55 | such a file, either verbatim or with modifications and/or 56 | translated into another language. 57 | 58 | `Modify' 59 | To apply any procedure that produces a Derived Work under any 60 | applicable law. 61 | 62 | `Distribution' 63 | Making copies of the Work available from one person to another, in 64 | whole or in part. Distribution includes (but is not limited to) 65 | making any electronic components of the Work accessible by 66 | file transfer protocols such as FTP or HTTP or by shared file 67 | systems such as Sun's Network File System (NFS). 68 | 69 | `Compiled Work' 70 | A version of the Work that has been processed into a form where it 71 | is directly usable on a computer system. This processing may 72 | include using installation facilities provided by the Work, 73 | transformations of the Work, copying of components of the Work, or 74 | other activities. Note that modification of any installation 75 | facilities provided by the Work constitutes modification of the Work. 76 | 77 | `Current Maintainer' 78 | A person or persons nominated as such within the Work. If there is 79 | no such explicit nomination then it is the `Copyright Holder' under 80 | any applicable law. 81 | 82 | `Base Interpreter' 83 | A program or process that is normally needed for running or 84 | interpreting a part or the whole of the Work. 85 | 86 | A Base Interpreter may depend on external components but these 87 | are not considered part of the Base Interpreter provided that each 88 | external component clearly identifies itself whenever it is used 89 | interactively. Unless explicitly specified when applying the 90 | license to the Work, the only applicable Base Interpreter is a 91 | `LaTeX-Format' or in the case of files belonging to the 92 | `LaTeX-format' a program implementing the `TeX language'. 93 | 94 | 95 | 96 | CONDITIONS ON DISTRIBUTION AND MODIFICATION 97 | =========================================== 98 | 99 | 1. Activities other than distribution and/or modification of the Work 100 | are not covered by this license; they are outside its scope. In 101 | particular, the act of running the Work is not restricted and no 102 | requirements are made concerning any offers of support for the Work. 103 | 104 | 2. You may distribute a complete, unmodified copy of the Work as you 105 | received it. Distribution of only part of the Work is considered 106 | modification of the Work, and no right to distribute such a Derived 107 | Work may be assumed under the terms of this clause. 108 | 109 | 3. You may distribute a Compiled Work that has been generated from a 110 | complete, unmodified copy of the Work as distributed under Clause 2 111 | above, as long as that Compiled Work is distributed in such a way that 112 | the recipients may install the Compiled Work on their system exactly 113 | as it would have been installed if they generated a Compiled Work 114 | directly from the Work. 115 | 116 | 4. If you are the Current Maintainer of the Work, you may, without 117 | restriction, modify the Work, thus creating a Derived Work. You may 118 | also distribute the Derived Work without restriction, including 119 | Compiled Works generated from the Derived Work. Derived Works 120 | distributed in this manner by the Current Maintainer are considered to 121 | be updated versions of the Work. 122 | 123 | 5. If you are not the Current Maintainer of the Work, you may modify 124 | your copy of the Work, thus creating a Derived Work based on the Work, 125 | and compile this Derived Work, thus creating a Compiled Work based on 126 | the Derived Work. 127 | 128 | 6. If you are not the Current Maintainer of the Work, you may 129 | distribute a Derived Work provided the following conditions are met 130 | for every component of the Work unless that component clearly states 131 | in the copyright notice that it is exempt from that condition. Only 132 | the Current Maintainer is allowed to add such statements of exemption 133 | to a component of the Work. 134 | 135 | a. If a component of this Derived Work can be a direct replacement 136 | for a component of the Work when that component is used with the 137 | Base Interpreter, then, wherever this component of the Work 138 | identifies itself to the user when used interactively with that 139 | Base Interpreter, the replacement component of this Derived Work 140 | clearly and unambiguously identifies itself as a modified version 141 | of this component to the user when used interactively with that 142 | Base Interpreter. 143 | 144 | b. Every component of the Derived Work contains prominent notices 145 | detailing the nature of the changes to that component, or a 146 | prominent reference to another file that is distributed as part 147 | of the Derived Work and that contains a complete and accurate log 148 | of the changes. 149 | 150 | c. No information in the Derived Work implies that any persons, 151 | including (but not limited to) the authors of the original version 152 | of the Work, provide any support, including (but not limited to) 153 | the reporting and handling of errors, to recipients of the 154 | Derived Work unless those persons have stated explicitly that 155 | they do provide such support for the Derived Work. 156 | 157 | d. You distribute at least one of the following with the Derived Work: 158 | 159 | 1. A complete, unmodified copy of the Work; 160 | if your distribution of a modified component is made by 161 | offering access to copy the modified component from a 162 | designated place, then offering equivalent access to copy 163 | the Work from the same or some similar place meets this 164 | condition, even though third parties are not compelled to 165 | copy the Work along with the modified component; 166 | 167 | 2. Information that is sufficient to obtain a complete, 168 | unmodified copy of the Work. 169 | 170 | 7. If you are not the Current Maintainer of the Work, you may 171 | distribute a Compiled Work generated from a Derived Work, as long as 172 | the Derived Work is distributed to all recipients of the Compiled 173 | Work, and as long as the conditions of Clause 6, above, are met with 174 | regard to the Derived Work. 175 | 176 | 8. The conditions above are not intended to prohibit, and hence do not 177 | apply to, the modification, by any method, of any component so that it 178 | becomes identical to an updated version of that component of the Work as 179 | it is distributed by the Current Maintainer under Clause 4, above. 180 | 181 | 9. Distribution of the Work or any Derived Work in an alternative 182 | format, where the Work or that Derived Work (in whole or in part) is 183 | then produced by applying some process to that format, does not relax or 184 | nullify any sections of this license as they pertain to the results of 185 | applying that process. 186 | 187 | 10. a. A Derived Work may be distributed under a different license 188 | provided that license itself honors the conditions listed in 189 | Clause 6 above, in regard to the Work, though it does not have 190 | to honor the rest of the conditions in this license. 191 | 192 | b. If a Derived Work is distributed under a different license, that 193 | Derived Work must provide sufficient documentation as part of 194 | itself to allow each recipient of that Derived Work to honor the 195 | restrictions in Clause 6 above, concerning changes from the Work. 196 | 197 | 11. This license places no restrictions on works that are unrelated to 198 | the Work, nor does this license place any restrictions on aggregating 199 | such works with the Work by any means. 200 | 201 | 12. Nothing in this license is intended to, or may be used to, prevent 202 | complete compliance by all parties with all applicable laws. 203 | 204 | 205 | NO WARRANTY 206 | =========== 207 | 208 | There is no warranty for the Work. Except when otherwise stated in 209 | writing, the Copyright Holder provides the Work `as is', without 210 | warranty of any kind, either expressed or implied, including, but not 211 | limited to, the implied warranties of merchantability and fitness for a 212 | particular purpose. The entire risk as to the quality and performance 213 | of the Work is with you. Should the Work prove defective, you assume 214 | the cost of all necessary servicing, repair, or correction. 215 | 216 | In no event unless required by applicable law or agreed to in writing 217 | will The Copyright Holder, or any author named in the components of the 218 | Work, or any other party who may distribute and/or modify the Work as 219 | permitted above, be liable to you for damages, including any general, 220 | special, incidental or consequential damages arising out of any use of 221 | the Work or out of inability to use the Work (including, but not limited 222 | to, loss of data, data being rendered inaccurate, or losses sustained by 223 | anyone as a result of any failure of the Work to operate with any other 224 | programs), even if the Copyright Holder or said author or said other 225 | party has been advised of the possibility of such damages. 226 | 227 | 228 | MAINTENANCE OF THE WORK 229 | ======================= 230 | 231 | The Work has the status `author-maintained' if the Copyright Holder 232 | explicitly and prominently states near the primary copyright notice in 233 | the Work that the Work can only be maintained by the Copyright Holder 234 | or simply that it is `author-maintained'. 235 | 236 | The Work has the status `maintained' if there is a Current Maintainer 237 | who has indicated in the Work that they are willing to receive error 238 | reports for the Work (for example, by supplying a valid e-mail 239 | address). It is not required for the Current Maintainer to acknowledge 240 | or act upon these error reports. 241 | 242 | The Work changes from status `maintained' to `unmaintained' if there 243 | is no Current Maintainer, or the person stated to be Current 244 | Maintainer of the work cannot be reached through the indicated means 245 | of communication for a period of six months, and there are no other 246 | significant signs of active maintenance. 247 | 248 | You can become the Current Maintainer of the Work by agreement with 249 | any existing Current Maintainer to take over this role. 250 | 251 | If the Work is unmaintained, you can become the Current Maintainer of 252 | the Work through the following steps: 253 | 254 | 1. Make a reasonable attempt to trace the Current Maintainer (and 255 | the Copyright Holder, if the two differ) through the means of 256 | an Internet or similar search. 257 | 258 | 2. If this search is successful, then enquire whether the Work 259 | is still maintained. 260 | 261 | a. If it is being maintained, then ask the Current Maintainer 262 | to update their communication data within one month. 263 | 264 | b. If the search is unsuccessful or no action to resume active 265 | maintenance is taken by the Current Maintainer, then announce 266 | within the pertinent community your intention to take over 267 | maintenance. (If the Work is a LaTeX work, this could be 268 | done, for example, by posting to comp.text.tex.) 269 | 270 | 3a. If the Current Maintainer is reachable and agrees to pass 271 | maintenance of the Work to you, then this takes effect 272 | immediately upon announcement. 273 | 274 | b. If the Current Maintainer is not reachable and the Copyright 275 | Holder agrees that maintenance of the Work be passed to you, 276 | then this takes effect immediately upon announcement. 277 | 278 | 4. If you make an `intention announcement' as described in 2b. above 279 | and after three months your intention is challenged neither by 280 | the Current Maintainer nor by the Copyright Holder nor by other 281 | people, then you may arrange for the Work to be changed so as 282 | to name you as the (new) Current Maintainer. 283 | 284 | 5. If the previously unreachable Current Maintainer becomes 285 | reachable once more within three months of a change completed 286 | under the terms of 3b) or 4), then that Current Maintainer must 287 | become or remain the Current Maintainer upon request provided 288 | they then update their communication data within one month. 289 | 290 | A change in the Current Maintainer does not, of itself, alter the fact 291 | that the Work is distributed under the LPPL license. 292 | 293 | If you become the Current Maintainer of the Work, you should 294 | immediately provide, within the Work, a prominent and unambiguous 295 | statement of your status as Current Maintainer. You should also 296 | announce your new status to the same pertinent community as 297 | in 2b) above. 298 | 299 | 300 | WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE 301 | ====================================================== 302 | 303 | This section contains important instructions, examples, and 304 | recommendations for authors who are considering distributing their 305 | works under this license. These authors are addressed as `you' in 306 | this section. 307 | 308 | Choosing This License or Another License 309 | ---------------------------------------- 310 | 311 | If for any part of your work you want or need to use *distribution* 312 | conditions that differ significantly from those in this license, then 313 | do not refer to this license anywhere in your work but, instead, 314 | distribute your work under a different license. You may use the text 315 | of this license as a model for your own license, but your license 316 | should not refer to the LPPL or otherwise give the impression that 317 | your work is distributed under the LPPL. 318 | 319 | The document `modguide.tex' in the base LaTeX distribution explains 320 | the motivation behind the conditions of this license. It explains, 321 | for example, why distributing LaTeX under the GNU General Public 322 | License (GPL) was considered inappropriate. Even if your work is 323 | unrelated to LaTeX, the discussion in `modguide.tex' may still be 324 | relevant, and authors intending to distribute their works under any 325 | license are encouraged to read it. 326 | 327 | A Recommendation on Modification Without Distribution 328 | ----------------------------------------------------- 329 | 330 | It is wise never to modify a component of the Work, even for your own 331 | personal use, without also meeting the above conditions for 332 | distributing the modified component. While you might intend that such 333 | modifications will never be distributed, often this will happen by 334 | accident -- you may forget that you have modified that component; or 335 | it may not occur to you when allowing others to access the modified 336 | version that you are thus distributing it and violating the conditions 337 | of this license in ways that could have legal implications and, worse, 338 | cause problems for the community. It is therefore usually in your 339 | best interest to keep your copy of the Work identical with the public 340 | one. Many works provide ways to control the behavior of that work 341 | without altering any of its licensed components. 342 | 343 | How to Use This License 344 | ----------------------- 345 | 346 | To use this license, place in each of the components of your work both 347 | an explicit copyright notice including your name and the year the work 348 | was authored and/or last substantially modified. Include also a 349 | statement that the distribution and/or modification of that 350 | component is constrained by the conditions in this license. 351 | 352 | Here is an example of such a notice and statement: 353 | 354 | %% pig.dtx 355 | %% Copyright 2005 M. Y. Name 356 | % 357 | % This work may be distributed and/or modified under the 358 | % conditions of the LaTeX Project Public License, either version 1.3 359 | % of this license or (at your option) any later version. 360 | % The latest version of this license is in 361 | % http://www.latex-project.org/lppl.txt 362 | % and version 1.3 or later is part of all distributions of LaTeX 363 | % version 2005/12/01 or later. 364 | % 365 | % This work has the LPPL maintenance status `maintained'. 366 | % 367 | % The Current Maintainer of this work is M. Y. Name. 368 | % 369 | % This work consists of the files pig.dtx and pig.ins 370 | % and the derived file pig.sty. 371 | 372 | Given such a notice and statement in a file, the conditions 373 | given in this license document would apply, with the `Work' referring 374 | to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being 375 | generated from `pig.dtx' using `pig.ins'), the `Base Interpreter' 376 | referring to any `LaTeX-Format', and both `Copyright Holder' and 377 | `Current Maintainer' referring to the person `M. Y. Name'. 378 | 379 | If you do not want the Maintenance section of LPPL to apply to your 380 | Work, change `maintained' above into `author-maintained'. 381 | However, we recommend that you use `maintained', as the Maintenance 382 | section was added in order to ensure that your Work remains useful to 383 | the community even when you can no longer maintain and support it 384 | yourself. 385 | 386 | Derived Works That Are Not Replacements 387 | --------------------------------------- 388 | 389 | Several clauses of the LPPL specify means to provide reliability and 390 | stability for the user community. They therefore concern themselves 391 | with the case that a Derived Work is intended to be used as a 392 | (compatible or incompatible) replacement of the original Work. If 393 | this is not the case (e.g., if a few lines of code are reused for a 394 | completely different task), then clauses 6b and 6d shall not apply. 395 | 396 | 397 | Important Recommendations 398 | ------------------------- 399 | 400 | Defining What Constitutes the Work 401 | 402 | The LPPL requires that distributions of the Work contain all the 403 | files of the Work. It is therefore important that you provide a 404 | way for the licensee to determine which files constitute the Work. 405 | This could, for example, be achieved by explicitly listing all the 406 | files of the Work near the copyright notice of each file or by 407 | using a line such as: 408 | 409 | % This work consists of all files listed in manifest.txt. 410 | 411 | in that place. In the absence of an unequivocal list it might be 412 | impossible for the licensee to determine what is considered by you 413 | to comprise the Work and, in such a case, the licensee would be 414 | entitled to make reasonable conjectures as to which files comprise 415 | the Work. 416 | 417 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `etoolbox`: e-TeX tools for LaTeX 2 | 3 | The `etoolbox` package is a toolbox of programming facilities geared 4 | primarily towards LaTeX class and package authors. It provides LaTeX 5 | frontends to some of the primitives provided by e-TeX as well as 6 | some generic tools which are not related to e-TeX but match the 7 | profile of this package. 8 | 9 | -------------------------------------------------------------------------------- /build.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env texlua 2 | 3 | -- Build script for "etoolbox" files 4 | 5 | -- Identify the bundle and module 6 | bundle = "" 7 | module = "etoolbox" 8 | 9 | -- Install .def files as well as .sty 10 | -- These are also the sources 11 | installfiles = {"*.def", "*.sty"} 12 | sourcefiles = installfiles 13 | 14 | -- Documentation is standalone 15 | typesetfiles = {"*.tex"} 16 | 17 | -- No packed source files 18 | unpackfiles = {} 19 | 20 | -- Release a TDS-style zip 21 | packtdszip = true 22 | 23 | -- Only need one test run 24 | checkengines = {"pdftex"} 25 | 26 | -- Detail how to set the version automatically 27 | tagfiles = {"*.def", "*.sty", "*.tex"} 28 | function update_tag(file,content,tagname,tagdate) 29 | local tagdate = string.gsub(tagdate,"%-","/") 30 | if string.match(file,"%.sty") or string.match(file,"%.def") then 31 | return string.gsub(content, 32 | "\n %[%d%d%d%d/%d%d/%d%d v%d%.%d%w?", 33 | "\n [" .. tagdate .. " v" .. tagname) 34 | elseif string.match(file,"%.tex") then 35 | content = string.gsub(content, 36 | "\n date=%{%d%d%d%d/%d%d/%d%d%}", 37 | "\n date={" .. tagdate .. "}") 38 | return string.gsub(content, 39 | "\n revision=%{v%d%.%d%w?%}", 40 | "\n revision={v" .. tagname .. "}") 41 | end 42 | return content 43 | end 44 | 45 | -------------------------------------------------------------------------------- /etoolbox.def: -------------------------------------------------------------------------------- 1 | \ProvidesFile{etoolbox.def} 2 | [2025/02/11 v2.5l etoolbox debug messages (JAW)] 3 | 4 | \begingroup 5 | \makeatletter 6 | \@makeother\+ 7 | \@makeother\- 8 | \@makeother\= 9 | \@makeother\> 10 | 11 | \long\gdef\etb@dbg@trce#1{\typeout{% 12 | [debug] tracing \string#1\on@line}}% 13 | \long\gdef\etb@dbg@init#1{\typeout{% 14 | [debug] analyzing '\detokenize\expandafter{\string#1}'}}% 15 | \gdef\etb@dbg@info#1{\typeout{% 16 | [debug] ++ \csuse{etb@msg@i@#1}}}% 17 | \gdef\etb@dbg@succ#1{\typeout{% 18 | [debug] == \csuse{etb@msg@s@#1}}}% 19 | \gdef\etb@dbg@fail#1{\typeout{% 20 | [debug] -- \csuse{etb@msg@f@#1}}}% 21 | 22 | \gdef\etb@msg@ex{^^J[debug] -> }% 23 | \gdef\etb@msg@br{^^J[debug]\@spaces} 24 | 25 | \gdef\etb@msg@i@def{% 26 | control sequence is defined} 27 | \gdef\etb@msg@i@mac{% 28 | control sequence is a macro} 29 | \gdef\etb@msg@i@prm{% 30 | control sequence is a macro with parameters} 31 | \gdef\etb@msg@i@prl{% 32 | control sequence is a macro without parameters} 33 | \xdef\etb@msg@i@pro{% 34 | control sequence is a \string\protected\space macro} 35 | \gdef\etb@msg@i@tok{% 36 | macro can be retokenized cleanly} 37 | \gdef\etb@msg@i@pat{% 38 | search pattern found in replacement text} 39 | \gdef\etb@msg@i@pos{% 40 | patching possible} 41 | \gdef\etb@msg@s@red{% 42 | redefining macro now} 43 | \gdef\etb@msg@s@ret{% 44 | retokenizing macro now} 45 | \xdef\etb@msg@f@def{% 46 | control sequence is undefined or \string\relax} 47 | \gdef\etb@msg@f@mac{% 48 | control sequence is not a macro} 49 | \xdef\etb@msg@f@tok{% 50 | macro cannot be retokenized cleanly\noexpand\etb@msg@ex 51 | the macro may have been defined under a category\noexpand\etb@msg@br 52 | code regime different from the current one\noexpand\etb@msg@ex 53 | the replacement text may contain special control\noexpand\etb@msg@br 54 | sequence tokens formed with 55 | \string\csname...\string\endcsname;\noexpand\etb@msg@ex 56 | the replacement text may contain carriage return,\noexpand\etb@msg@br 57 | newline, or similar characters} 58 | \xdef\etb@msg@f@hsh{% 59 | nested patching command and parameters in patch\noexpand\etb@msg@ex 60 | the patching command seems to be nested in the\noexpand\etb@msg@br 61 | argument to some other command\noexpand\etb@msg@ex 62 | the patch text seems to contain \string# characters\noexpand\etb@msg@ex 63 | either avoid nesting or use \string# characters with\noexpand\etb@msg@br 64 | category code 12 in the patch text\noexpand\etb@msg@ex 65 | simply doubling the \string# characters will not work} 66 | \gdef\etb@msg@f@pat{% 67 | search pattern not found in replacement text} 68 | 69 | \endgroup 70 | \endinput 71 | -------------------------------------------------------------------------------- /etoolbox.sty: -------------------------------------------------------------------------------- 1 | % Copyright (c) 2007-2011 Philipp Lehman. 2 | % (c) 2015-2020 Joseph Wright 3 | % 4 | % Permission is granted to copy, distribute and/or modify this 5 | % software under the terms of the LaTeX Project Public License 6 | % (LPPL), version 1.3c or any later version. 7 | % 8 | % This software is provided 'as is', without warranty of any kind, 9 | % either expressed or implied, including, but not limited to, the 10 | % implied warranties of merchantability and fitness for a 11 | % particular purpose. 12 | 13 | \NeedsTeXFormat{LaTeX2e} 14 | \ProvidesPackage{etoolbox} 15 | [2025/02/11 v2.5l e-TeX tools for LaTeX (JAW)] 16 | 17 | \begingroup 18 | \@ifundefined{eTeXversion} 19 | {\PackageError{etoolbox} 20 | {Not running under e-TeX} 21 | {This package requires e-TeX. Try compiling the document 22 | with\MessageBreak 'elatex' instead of 'latex'. When using 23 | pdfTeX, try 'pdfelatex'\MessageBreak instead of 'pdflatex'. 24 | This is a fatal error. I'm aborting now.}% 25 | \aftergroup\endinput} 26 | {} 27 | \endgroup 28 | 29 | \ifdefined\extrafloats 30 | \expandafter\@gobble 31 | \else 32 | \expandafter\@firstofone 33 | \fi 34 | {\RequirePackage{etex}} 35 | 36 | \def\etb@catcodes{\do\&\do\|\do\:\do\-\do\=\do\<\do\>} 37 | \def\do#1{\catcode\number`#1=\the\catcode`#1\relax} 38 | \edef\etb@catcodes{\etb@catcodes} 39 | \let\do\noexpand 40 | \AtEndOfPackage{\etb@catcodes\undef\etb@catcodes} 41 | 42 | \catcode`\&=3 43 | \catcode`\|=3 44 | \@makeother\: 45 | \@makeother\- 46 | \@makeother\= 47 | \@makeother\< 48 | \@makeother\> 49 | 50 | \protected\def\etb@error{\PackageError{etoolbox}} 51 | \protected\def\etb@warning{\PackageWarning{etoolbox}} 52 | \protected\def\etb@info{\PackageInfo{etoolbox}} 53 | \newcount\etb@tempcnta 54 | 55 | % {}[][]{} 56 | 57 | \newcommand*{\newrobustcmd}{} 58 | \protected\def\newrobustcmd{\@star@or@long\etb@new@command} 59 | 60 | \def\etb@new@command#1{\@testopt{\etb@newcommand#1}0} 61 | 62 | \def\etb@newcommand#1[#2]{% 63 | \@ifnextchar[%] 64 | {\etb@xargdef#1[#2]} 65 | {\ifx\l@ngrel@x\relax 66 | \let\l@ngrel@x\protected 67 | \else 68 | \protected\def\l@ngrel@x{\protected\long}% 69 | \fi 70 | \@argdef#1[#2]}} 71 | 72 | \long\def\etb@xargdef#1[#2][#3]#4{% 73 | \@ifdefinable#1{% 74 | \expandafter\protected 75 | \expandafter\def 76 | \expandafter#1% 77 | \expandafter{% 78 | \expandafter\@testopt 79 | \csname\string#1\endcsname{#3}}% 80 | \expandafter\@yargdef\csname\string#1\endcsname\tw@{#2}{#4}}} 81 | 82 | % {}[][]{} 83 | 84 | \newrobustcmd*{\renewrobustcmd}{\@star@or@long\etb@renew@command} 85 | 86 | \def\etb@renew@command#1{% 87 | \ifundef{#1} 88 | {\etb@error{\string#1 undefined}\@ehc} 89 | {}% 90 | \let\@ifdefinable\@rc@ifdefinable 91 | \etb@new@command#1} 92 | 93 | % {}[][]{} 94 | 95 | \newrobustcmd*{\providerobustcmd}{\@star@or@long\etb@provide@command} 96 | 97 | \def\etb@provide@command#1{% 98 | \ifundef{#1} 99 | {\def\reserved@a{\etb@new@command#1}} 100 | {\def\reserved@a{\etb@renew@command\reserved@a}}% 101 | \reserved@a} 102 | 103 | % {} 104 | 105 | \newrobustcmd*{\csshow}[1]{% 106 | \begingroup\expandafter\endgroup 107 | \expandafter\show\csname#1\endcsname} 108 | 109 | % {} 110 | 111 | \newcommand*{\csmeaning}[1]{% 112 | \ifcsname #1\endcsname 113 | \expandafter\meaning\csname #1\endcsname 114 | \else 115 | \detokenize{undefined}% 116 | \fi} 117 | 118 | % {}{}{} 119 | 120 | \newcommand{\ifdef}[1]{% 121 | \ifdefined#1% 122 | \expandafter\@firstoftwo 123 | \else 124 | \expandafter\@secondoftwo 125 | \fi} 126 | 127 | % {}{}{} 128 | 129 | \newcommand{\ifundef}[1]{% 130 | \ifdefined#1% 131 | \ifx#1\relax 132 | \expandafter\expandafter 133 | \expandafter\@firstoftwo 134 | \else 135 | \expandafter\expandafter 136 | \expandafter\@secondoftwo 137 | \fi 138 | \else 139 | \expandafter\@firstoftwo 140 | \fi} 141 | 142 | % {}{}{} 143 | 144 | \newcommand*{\ifcsdef}[1]{% 145 | \ifcsname#1\endcsname 146 | \expandafter\@firstoftwo 147 | \else 148 | \expandafter\@secondoftwo 149 | \fi} 150 | 151 | % {}{}{} 152 | 153 | \newcommand*{\ifcsundef}[1]{% 154 | \ifcsname#1\endcsname 155 | \expandafter\ifx\csname#1\endcsname\relax 156 | \expandafter\expandafter 157 | \expandafter\@firstoftwo 158 | \else 159 | \expandafter\expandafter 160 | \expandafter\@secondoftwo 161 | \fi 162 | \else 163 | \expandafter\@firstoftwo 164 | \fi} 165 | 166 | % {}{} 167 | 168 | \newcommand{\ifdefmacro}{} 169 | \long\edef\ifdefmacro#1{% 170 | \noexpand\expandafter\noexpand\etb@ifdefmacro 171 | \noexpand\meaning#1\detokenize{macro}:&} 172 | \edef\etb@ifdefmacro{% 173 | \def\noexpand\etb@ifdefmacro##1\detokenize{macro}:##2&} 174 | \etb@ifdefmacro{\notblank{#2}} 175 | 176 | % {}{}{} 177 | 178 | \newcommand*{\ifcsmacro}[1]{% 179 | \ifcsdef{#1} 180 | {\expandafter\ifdefmacro\csname#1\endcsname} 181 | {\@secondoftwo}} 182 | 183 | % {}{} 184 | 185 | \newcommand{\ifdefprefix}[1]{% 186 | \ifdefmacro{#1} 187 | {\etb@ifdefprefix{#1}} 188 | {\@secondoftwo}} 189 | \long\edef\etb@ifdefprefix#1{% 190 | \noexpand\expandafter\noexpand\etb@ifdefprefix@i 191 | \noexpand\meaning#1\detokenize{macro}:&} 192 | \edef\etb@ifdefprefix@i{% 193 | \def\noexpand\etb@ifdefprefix@i##1\detokenize{macro}:##2&} 194 | \etb@ifdefprefix@i{\notblank{#1}} 195 | 196 | % {}{}{} 197 | 198 | \newcommand*{\ifcsprefix}[1]{% 199 | \ifcsdef{#1} 200 | {\expandafter\ifdefprefix\csname#1\endcsname} 201 | {\@secondoftwo}} 202 | 203 | % {}{} 204 | 205 | \newcommand{\ifdefparam}{} 206 | \long\edef\ifdefparam#1{% 207 | \noexpand\expandafter\noexpand\etb@ifdefparam 208 | \noexpand\meaning#1\detokenize{macro}:->&} 209 | \edef\etb@ifdefparam{% 210 | \def\noexpand\etb@ifdefparam##1\detokenize{macro}:##2->##3&} 211 | \etb@ifdefparam{\notblank{#2}} 212 | 213 | % {}{}{} 214 | 215 | \newcommand*{\ifcsparam}[1]{% 216 | \ifcsdef{#1} 217 | {\expandafter\ifdefparam\csname#1\endcsname} 218 | {\@secondoftwo}} 219 | 220 | % {}{} 221 | 222 | \newcommand{\ifdefprotected}{} 223 | \long\edef\ifdefprotected#1{% 224 | \noexpand\expandafter\noexpand\etb@ifdefprotected 225 | \noexpand\meaning#1\string\protected&} 226 | \edef\etb@ifdefprotected{% 227 | \def\noexpand\etb@ifdefprotected##1\string\protected##2&} 228 | \etb@ifdefprotected{\notblank{#2}} 229 | 230 | % {}{}{} 231 | 232 | \newcommand*{\ifcsprotected}[1]{% 233 | \ifcsdef{#1} 234 | {\expandafter\ifdefprotected\csname#1\endcsname} 235 | {\@secondoftwo}} 236 | 237 | % {}{} 238 | 239 | \newrobustcmd{\ifdefltxprotect}[1]{% 240 | \begingroup 241 | \edef\etb@resrvda{\string#1}% 242 | \def\etb@resrvdb{#1}% 243 | \edef\etb@resrvdb{\expandafter\strip@prefix\meaning\etb@resrvdb}% 244 | \edef\etb@resrvda{% 245 | \ifx\etb@resrvda\etb@resrvdb 246 | \noexpand\x@protect 247 | \noexpand#1% 248 | \fi 249 | \noexpand\protect\expandafter\noexpand 250 | \csname\expandafter\@gobble\string#1 \endcsname}% 251 | \expandafter\endgroup\ifx#1\etb@resrvda 252 | \expandafter\@firstoftwo 253 | \else 254 | \expandafter\@secondoftwo 255 | \fi} 256 | 257 | % {}{}{} 258 | 259 | \newrobustcmd*{\ifcsltxprotect}[1]{% 260 | \ifcsdef{#1} 261 | {\expandafter\ifdefltxprotect\csname#1\endcsname} 262 | {\@secondoftwo}} 263 | 264 | % {}{}{} 265 | 266 | \newcommand{\ifdefempty}[1]{% 267 | \ifundef{#1} 268 | {\@secondoftwo} 269 | {\ifdefmacro{#1} 270 | {\ifdefparam{#1} 271 | {\@secondoftwo} 272 | {\etb@ifdefempty{#1}}} 273 | {\@secondoftwo}}} 274 | 275 | \def\etb@ifdefempty#1{% 276 | \expandafter\expandafter 277 | \expandafter\ifstrempty 278 | \expandafter\expandafter 279 | \expandafter{% 280 | \expandafter\strip@prefix\meaning#1}} 281 | 282 | % {}{}{} 283 | 284 | \newcommand*{\ifcsempty}[1]{% 285 | \ifcsundef{#1} 286 | {\@secondoftwo} 287 | {\expandafter\ifdefparam\csname#1\endcsname 288 | {\@secondoftwo} 289 | {\expandafter\etb@ifdefempty\csname#1\endcsname}}} 290 | 291 | % {}{}{} 292 | 293 | \newcommand{\ifdefvoid}[1]{% 294 | \ifundef{#1} 295 | {\@firstoftwo} 296 | {\ifdefmacro{#1} 297 | {\ifdefparam{#1} 298 | {\@secondoftwo} 299 | {\etb@ifdefempty{#1}}} 300 | {\@secondoftwo}}} 301 | 302 | % {}{}{} 303 | 304 | \newcommand*{\ifcsvoid}[1]{% 305 | \ifcsundef{#1} 306 | {\@firstoftwo} 307 | {\expandafter\ifdefparam\csname#1\endcsname 308 | {\@secondoftwo} 309 | {\expandafter\etb@ifdefempty\csname#1\endcsname}}} 310 | 311 | % {}{}{}{} 312 | 313 | \newcommand{\ifdefequal}[2]{% 314 | \ifundef{#1} 315 | {\@secondoftwo} 316 | {\ifundef{#2} 317 | {\@secondoftwo} 318 | {\ifx#1#2% 319 | \expandafter\@firstoftwo 320 | \else 321 | \expandafter\@secondoftwo 322 | \fi}}} 323 | 324 | % {}{}{}{} 325 | 326 | \newcommand*{\ifcsequal}[2]{% 327 | \ifcsundef{#1} 328 | {\@secondoftwo} 329 | {\ifcsundef{#2} 330 | {\@secondoftwo} 331 | {\expandafter\ifx 332 | \csname#1\expandafter\endcsname 333 | \csname#2\endcsname 334 | \expandafter\@firstoftwo 335 | \else 336 | \expandafter\@secondoftwo 337 | \fi}}} 338 | 339 | % {}{}{}{} 340 | 341 | \newrobustcmd{\ifdefstrequal}[2]{% 342 | \ifdefmacro{#1} 343 | {\ifdefmacro{#2} 344 | {\begingroup 345 | \edef\etb@tempa{\expandafter\strip@prefix\meaning#1}% 346 | \edef\etb@tempb{\expandafter\strip@prefix\meaning#2}% 347 | \ifx\etb@tempa\etb@tempb 348 | \aftergroup\@firstoftwo 349 | \else 350 | \aftergroup\@secondoftwo 351 | \fi 352 | \endgroup} 353 | {\@secondoftwo}} 354 | {\@secondoftwo}} 355 | 356 | % {}{}{}{} 357 | 358 | \newcommand*{\ifcsstrequal}[2]{% 359 | \ifcsundef{#1} 360 | {\@secondoftwo} 361 | {\ifcsundef{#2} 362 | {\@secondoftwo} 363 | {\expandafter\ifdefstrequal 364 | \csname#1\expandafter\endcsname 365 | \csname#2\endcsname}}} 366 | 367 | % {}{}{}{} 368 | 369 | \newrobustcmd{\ifdefstring}[2]{% 370 | \ifdefmacro{#1} 371 | {\begingroup 372 | \edef\etb@tempa{\expandafter\strip@prefix\meaning#1}% 373 | \edef\etb@tempb{\detokenize{#2}}% 374 | \ifx\etb@tempa\etb@tempb 375 | \aftergroup\@firstoftwo 376 | \else 377 | \aftergroup\@secondoftwo 378 | \fi 379 | \endgroup} 380 | {\@secondoftwo}} 381 | 382 | % {}{}{}{} 383 | 384 | \newrobustcmd{\ifcsstring}[2]{% 385 | \ifcsundef{#1} 386 | {\@secondoftwo} 387 | {\expandafter\ifdefstring\csname#1\endcsname{#2}}} 388 | 389 | % {}{} 390 | 391 | \newcommand{\ifdefcounter}[1]{\etb@ifcounter#1&} 392 | \long\def\etb@ifcounter#1#2&{% 393 | \ifx\count#1% 394 | \expandafter\@secondoftwo 395 | \else 396 | \expandafter\etb@ifcounter@i\meaning#1:% 397 | \fi} 398 | \edef\etb@ifcounter@i#1:#2\fi{\noexpand\fi 399 | \noexpand\etb@ifcounter@ii#1\string\count&} 400 | \edef\etb@ifcounter@ii{% 401 | \def\noexpand\etb@ifcounter@ii##1\string\count##2&} 402 | \etb@ifcounter@ii{\ifblank{#1}} 403 | 404 | % {}{}{} 405 | 406 | \newcommand*{\ifcscounter}[1]{% 407 | \ifcsdef{#1} 408 | {\expandafter\ifdefcounter\csname#1\endcsname} 409 | {\@secondoftwo}} 410 | 411 | % {}{}{} 412 | 413 | \newcommand*{\ifltxcounter}[1]{% 414 | \ifcsdef{c@#1} 415 | {\expandafter\ifdefcounter\csname c@#1\endcsname} 416 | {\@secondoftwo}} 417 | 418 | % {}{} 419 | 420 | \newcommand{\ifdeflength}[1]{\etb@iflength#1&} 421 | \long\def\etb@iflength#1#2&{% 422 | \ifx\skip#1% 423 | \expandafter\@secondoftwo 424 | \else 425 | \expandafter\etb@iflength@i\meaning#1:% 426 | \fi} 427 | \edef\etb@iflength@i#1:#2\fi{\noexpand\fi 428 | \noexpand\etb@iflength@ii#1\string\skip&} 429 | \edef\etb@iflength@ii{% 430 | \def\noexpand\etb@iflength@ii##1\string\skip##2&} 431 | \etb@iflength@ii{\ifblank{#1}} 432 | 433 | % {}{}{} 434 | 435 | \newcommand*{\ifcslength}[1]{% 436 | \ifcsdef{#1} 437 | {\expandafter\ifdeflength\csname#1\endcsname} 438 | {\@secondoftwo}} 439 | 440 | % {}{} 441 | 442 | \newcommand{\ifdefdimen}[1]{\etb@ifdimen#1&} 443 | \long\def\etb@ifdimen#1#2&{% 444 | \ifx\dimen#1% 445 | \expandafter\@secondoftwo 446 | \else 447 | \expandafter\etb@ifdimen@i\meaning#1:% 448 | \fi} 449 | \edef\etb@ifdimen@i#1:#2\fi{\noexpand\fi 450 | \noexpand\etb@ifdimen@ii#1\string\dimen&} 451 | \edef\etb@ifdimen@ii{% 452 | \def\noexpand\etb@ifdimen@ii##1\string\dimen##2&} 453 | \etb@ifdimen@ii{\ifblank{#1}} 454 | 455 | % {}{}{} 456 | 457 | \newcommand*{\ifcsdimen}[1]{% 458 | \ifcsdef{#1} 459 | {\expandafter\ifdefdimen\csname#1\endcsname} 460 | {\@secondoftwo}} 461 | 462 | % {}{}{}{} 463 | 464 | \newrobustcmd{\ifstrequal}[2]{% 465 | \begingroup 466 | \edef\etb@tempa{\detokenize{#1}}% 467 | \edef\etb@tempb{\detokenize{#2}}% 468 | \ifx\etb@tempa\etb@tempb 469 | \aftergroup\@firstoftwo 470 | \else 471 | \aftergroup\@secondoftwo 472 | \fi 473 | \endgroup} 474 | 475 | % {}{}{} 476 | 477 | \newcommand{\ifstrempty}[1]{% 478 | \expandafter\ifx\expandafter&\detokenize{#1}&% 479 | \expandafter\@firstoftwo 480 | \else 481 | \expandafter\@secondoftwo 482 | \fi} 483 | 484 | % {}{}{} 485 | 486 | \newcommand{\ifblank}[1]{% from expl3 487 | \expandafter\ifx\expandafter\relax\detokenize\expandafter{\@gobble#1?}\relax 488 | \expandafter\@firstoftwo 489 | \else 490 | \expandafter\@secondoftwo 491 | \fi} 492 | 493 | \newcommand{\notblank}[1]{% 494 | \expandafter\ifx\expandafter\relax\detokenize\expandafter{\@gobble#1?}\relax 495 | \expandafter\@secondoftwo 496 | \else 497 | \expandafter\@firstoftwo 498 | \fi} 499 | 500 | % {}{}{}{}{} 501 | 502 | \newcommand*{\ifnumcomp}[3]{% 503 | \ifnum\numexpr#1\relax#2\numexpr#3\relax 504 | \expandafter\@firstoftwo 505 | \else 506 | \expandafter\@secondoftwo 507 | \fi} 508 | 509 | % {}{}{}{} 510 | 511 | \newcommand*{\ifnumequal}[1]{% 512 | \ifnumcomp{#1}=} 513 | 514 | \newcommand*{\ifnumgreater}[1]{% 515 | \ifnumcomp{#1}>} 516 | 517 | \newcommand*{\ifnumless}[1]{% 518 | \ifnumcomp{#1}<} 519 | 520 | % {}{}{} 521 | 522 | \newcommand*{\ifnumodd}[1]{% 523 | \ifodd\numexpr#1\relax 524 | \expandafter\@firstoftwo 525 | \else 526 | \expandafter\@secondoftwo 527 | \fi} 528 | 529 | % {}{}{}{}{} 530 | 531 | \newcommand*{\ifdimcomp}[3]{% 532 | \ifdim\dimexpr#1\relax#2\dimexpr#3\relax 533 | \expandafter\@firstoftwo 534 | \else 535 | \expandafter\@secondoftwo 536 | \fi} 537 | 538 | % {}{}{}{} 539 | 540 | \newcommand*{\ifdimequal}[1]{% 541 | \ifdimcomp{#1}=} 542 | 543 | \newcommand*{\ifdimgreater}[1]{% 544 | \ifdimcomp{#1}>} 545 | 546 | \newcommand*{\ifdimless}[1]{% 547 | \ifdimcomp{#1}<} 548 | 549 | % {}{}{} 550 | 551 | \newcommand{\ifboolexpe}[1]{% 552 | \etb@be@beg\etb@be@bgroup#1(&\etb@be@end} 553 | 554 | \let\etb@be@true\@empty 555 | \def\etb@be@false{-\@ne} 556 | 557 | \def\etb@be@beg{% 558 | \ifnum\numexpr\z@\ifnum\numexpr\z@} 559 | 560 | \def\etb@be@end{% 561 | <\z@ 562 | \expandafter\etb@be@false 563 | \fi 564 | <\z@ 565 | \expandafter\@secondoftwo 566 | \else 567 | \expandafter\@firstoftwo 568 | \fi} 569 | 570 | \long\def\etb@be@bgroup#1(#2&{% 571 | \etb@be@egroup#1)&% 572 | \ifblank{#2} 573 | {} 574 | {\etb@be@beg 575 | \etb@be@bgroup#2&}} 576 | 577 | \long\def\etb@be@egroup#1)#2&{% 578 | \etb@be@and#1and&% 579 | \ifblank{#2} 580 | {} 581 | {\etb@be@end\etb@be@true\etb@be@false 582 | \etb@be@egroup#2&}} 583 | 584 | \long\def\etb@be@and#1and#2&{% 585 | \etb@be@or#1or&% 586 | \ifblank{#2} 587 | {} 588 | {<\z@ 589 | \expandafter\@firstofone 590 | \else 591 | \expandafter\@gobble 592 | \fi 593 | {=\z@\fi\ifnum\numexpr\m@ne}% 594 | \ifnum\numexpr\z@ 595 | \etb@be@and#2&}} 596 | 597 | \long\def\etb@be@or#1or#2&{% 598 | \etb@be@not#1not&% 599 | \ifblank{#2} 600 | {} 601 | {<\z@ 602 | \expandafter\@secondoftwo 603 | \else 604 | \expandafter\@firstoftwo 605 | \fi 606 | {=\z@\fi\ifnum\numexpr\z@ 607 | \ifnum\numexpr\@ne} 608 | {=\z@\fi\ifnum\numexpr\z@ 609 | \ifnum\numexpr\z@}% 610 | \etb@be@or#2&}} 611 | 612 | \long\def\etb@be@not#1not#2&{% 613 | \etb@be@togl#1togl&% 614 | \ifblank{#2} 615 | {} 616 | {>\z@ 617 | \expandafter\@firstoftwo 618 | \else 619 | \expandafter\@secondoftwo 620 | \fi 621 | {\unless\ifnum\numexpr\m@ne} 622 | {\unless\ifnum\numexpr\z@}% 623 | \etb@be@not#2&}} 624 | 625 | \long\def\etb@be@togl#1togl#2&{% 626 | \etb@be@bool#1bool&% 627 | \ifblank{#2} 628 | {} 629 | {\etb@be@togl@i#2&}} 630 | 631 | \long\def\etb@be@togl@i#1#2&{% 632 | \ifcsdef{etb@tgl@#1} 633 | {\csname etb@tgl@#1\endcsname\etb@be@true\etb@be@false} 634 | {\etb@be@err{Toggle '#1' undefined}{}}% 635 | \etb@be@togl#2&} 636 | 637 | \long\def\etb@be@bool#1bool#2&{% 638 | \etb@be@test#1test&% 639 | \ifblank{#2} 640 | {} 641 | {\etb@be@bool@i#2&}} 642 | 643 | \long\def\etb@be@bool@i#1#2&{% 644 | \ifcsundef{if#1} 645 | {\etb@be@err{Boolean '#1' undefined}{}} 646 | {\csname if#1\endcsname 647 | \else 648 | \etb@be@false 649 | \fi}% 650 | \etb@be@bool#2&} 651 | 652 | \long\def\etb@be@test#1test#2&{% 653 | \ifblank{#1} 654 | {} 655 | {\etb@be@err{The invalid part is: '\detokenize{#1}'}{}}% 656 | \ifblank{#2} 657 | {} 658 | {\etb@be@test@i#2&}} 659 | 660 | \long\def\etb@be@test@i#1#2&{% 661 | #1\etb@be@true\etb@be@false 662 | \etb@be@test#2&} 663 | 664 | \long\def\etb@be@err#1#2{% 665 | \expandafter\ifnum\the\numexpr 666 | \expandafter\ifnum\the\currentiftype=-3 667 | \expandafter\thr@@ 668 | \else 669 | \expandafter\currentiftype 670 | \fi 671 | =\thr@@ 672 | \expandafter\@firstoftwo 673 | \else 674 | \expandafter\@secondoftwo 675 | \fi 676 | {=\z@\fi 677 | \etb@be@err{#1}{#2\ifnum\numexpr\m@ne}} 678 | {\etb@err@expr{#1}#2}} 679 | 680 | % {}{}{} 681 | 682 | \newrobustcmd{\ifboolexpr}[1]{\etb@boolexpr{#1}} 683 | 684 | \long\def\etb@boolexpr#1{% 685 | \begingroup 686 | \let\etb@br@neg\@firstoftwo 687 | \etb@tempcnta\z@ 688 | \etb@br@beg 689 | \etb@br@bgroup#1(&% 690 | \etb@br@end 691 | \etb@br@eval} 692 | 693 | \def\etb@br@beg{% 694 | \begingroup 695 | \let\etb@br@neg\@firstoftwo 696 | \etb@tempcnta\z@} 697 | 698 | \def\etb@br@end{% 699 | \etb@br@eval\etb@br@true\etb@br@false} 700 | 701 | \def\etb@br@eval{% 702 | \ifnum\etb@tempcnta<\z@ 703 | \aftergroup\@secondoftwo 704 | \else 705 | \aftergroup\@firstoftwo 706 | \fi 707 | \endgroup} 708 | 709 | \def\etb@br@true{% 710 | \advance\etb@tempcnta\etb@br@neg\z@\m@ne 711 | \let\etb@br@neg\@firstoftwo} 712 | 713 | \def\etb@br@false{% 714 | \advance\etb@tempcnta\etb@br@neg\m@ne\z@ 715 | \let\etb@br@neg\@firstoftwo} 716 | 717 | \long\def\etb@br@bgroup#1(#2&{% 718 | \etb@br@egroup#1)&% 719 | \ifblank{#2} 720 | {} 721 | {\etb@br@beg 722 | \etb@br@bgroup#2&}} 723 | 724 | \long\def\etb@br@egroup#1)#2&{% 725 | \etb@br@and#1and&% 726 | \ifblank{#2} 727 | {} 728 | {\etb@br@end 729 | \etb@br@egroup#2&}} 730 | 731 | \long\def\etb@br@and#1and#2&{% 732 | \etb@br@or#1or&% 733 | \ifblank{#2} 734 | {} 735 | {\ifnum\etb@tempcnta<\z@ 736 | \etb@tempcnta\m@ne 737 | \else 738 | \etb@tempcnta\z@ 739 | \fi 740 | \etb@br@and#2&}} 741 | 742 | \long\def\etb@br@or#1or#2&{% 743 | \etb@br@not#1not&% 744 | \ifblank{#2} 745 | {} 746 | {\ifnum\etb@tempcnta<\z@ 747 | \etb@tempcnta\z@ 748 | \else 749 | \etb@tempcnta\@ne 750 | \fi 751 | \etb@br@or#2&}} 752 | 753 | \long\def\etb@br@not#1not#2&{% 754 | \etb@br@togl#1togl&% 755 | \ifblank{#2} 756 | {} 757 | {\let\etb@br@neg\@secondoftwo 758 | \etb@br@not#2&}} 759 | 760 | \long\def\etb@br@togl#1togl#2&{% 761 | \etb@br@bool#1bool&% 762 | \ifblank{#2} 763 | {} 764 | {\etb@br@togl@i#2&}} 765 | 766 | \long\def\etb@br@togl@i#1#2&{% 767 | \ifcsdef{etb@tgl@#1} 768 | {\csname etb@tgl@#1\endcsname\etb@br@true\etb@br@false} 769 | {\etb@err@expr{Toggle '#1' undefined}\etb@br@false}% 770 | \etb@br@togl#2&} 771 | 772 | \long\def\etb@br@bool#1bool#2&{% 773 | \etb@br@test#1test&% 774 | \ifblank{#2} 775 | {} 776 | {\etb@br@bool@i#2&}} 777 | 778 | \long\def\etb@br@bool@i#1#2&{% 779 | \ifcsundef{if#1} 780 | {\etb@err@expr{Boolean '#1' undefined}\etb@br@false} 781 | {\csname if#1\endcsname 782 | \etb@br@true 783 | \else 784 | \etb@br@false 785 | \fi}% 786 | \etb@br@bool#2&} 787 | 788 | \long\def\etb@br@test#1test#2&{% 789 | \ifblank{#1} 790 | {} 791 | {\etb@err@expr{The invalid part is: '\detokenize{#1}'}}% 792 | \ifblank{#2} 793 | {} 794 | {\etb@br@test@i#2&}} 795 | 796 | \long\def\etb@br@test@i#1#2&{% 797 | \ignorespaces#1\etb@br@true\etb@br@false 798 | \etb@br@test#2&} 799 | 800 | \long\def\etb@err@expr#1{% 801 | \etb@error 802 | {Invalid boolean expression} 803 | {#1.}} 804 | 805 | % {}{} 806 | 807 | \newrobustcmd{\whileboolexpr}[2]{% 808 | \etb@boolexpr{#1}{#2\whileboolexpr{#1}{#2}}{}} 809 | 810 | % {}{} 811 | 812 | \newrobustcmd{\unlessboolexpr}[2]{% 813 | \etb@boolexpr{#1}{}{#2\unlessboolexpr{#1}{#2}}} 814 | 815 | % {} 816 | 817 | \newcommand{\expandonce}[1]{% 818 | \unexpanded\expandafter{#1}} 819 | 820 | % {} 821 | 822 | \newcommand*{\csexpandonce}[1]{% 823 | \expandafter\expandonce\csname#1\endcsname} 824 | 825 | % {} 826 | 827 | \newcommand*{\protecting}{} 828 | \def\protecting#{% 829 | \ifx\protect\@typeset@protect 830 | \etb@protecting\@firstofone 831 | \fi 832 | \ifx\protect\@unexpandable@protect 833 | \etb@protecting\etb@unexpandable 834 | \fi 835 | \ifx\protect\noexpand 836 | \etb@protecting\unexpanded 837 | \fi 838 | \ifx\protect\string 839 | \etb@protecting\detokenize 840 | \fi 841 | \relax\@firstofone} 842 | 843 | \def\etb@protecting#1#2\relax\@firstofone{\fi#1} 844 | \long\def\etb@unexpandable#1{\unexpanded{\protecting{#1}}} 845 | 846 | % {} 847 | 848 | \newrobustcmd*{\csdef}[1]{\expandafter\def\csname#1\endcsname} 849 | \newrobustcmd*{\csedef}[1]{\expandafter\edef\csname#1\endcsname} 850 | \newrobustcmd*{\csgdef}[1]{\expandafter\gdef\csname#1\endcsname} 851 | \newrobustcmd*{\csxdef}[1]{\expandafter\xdef\csname#1\endcsname} 852 | \newrobustcmd*{\protected@csedef}{\etb@protected\csedef} 853 | \newrobustcmd*{\protected@csxdef}{\etb@protected\csxdef} 854 | 855 | \def\etb@protected{% 856 | \let\@@protect\protect 857 | \let\protect\@unexpandable@protect 858 | \afterassignment\restore@protect} 859 | 860 | % {}{} 861 | 862 | \newrobustcmd{\cslet}[2]{% 863 | \expandafter\let\csname#1\endcsname#2} 864 | 865 | % {}{} 866 | 867 | \newrobustcmd{\letcs}[2]{% 868 | \ifcsdef{#2} 869 | {\expandafter\let\expandafter#1\csname#2\endcsname} 870 | {\undef#1}} 871 | 872 | % {}{} 873 | 874 | \newrobustcmd*{\csletcs}[2]{% 875 | \ifcsdef{#2} 876 | {\expandafter\let 877 | \csname#1\expandafter\endcsname 878 | \csname#2\endcsname} 879 | {\csundef{#1}}} 880 | 881 | \ifdef\NewCommandCopy 882 | {% 883 | \long\def\etb@carsquare#1#2#3\@nil{#1#2} 884 | % 885 | % {}{}{} 886 | % 887 | \newrobustcmd*{\etb@if@robustcmd}[1]{% 888 | \begingroup 889 | \escapechar=`\\ 890 | \edef\etb@tempa{% 891 | \endgroup 892 | \def\noexpand\etb@tempa{\noexpand\@testopt 893 | \expandafter\noexpand\csname\string#1\endcsname}% 894 | \def\noexpand\etb@tempb{\unexpanded\expandafter\expandafter\expandafter 895 | {\expandafter\etb@carsquare#1{}{}\@nil}}% 896 | }\etb@tempa 897 | \ifx\etb@tempa\etb@tempb 898 | \expandafter\@firstoftwo 899 | \else 900 | \expandafter\@secondoftwo 901 | \fi} 902 | % 903 | % {}{} 904 | % 905 | \newrobustcmd*{\etb@copy@robustcmd}[2]{% 906 | \begingroup 907 | \escapechar=`\\ 908 | \edef\etb@tempa{% 909 | \endgroup 910 | \protected\def\noexpand#1{\noexpand\@testopt 911 | \expandafter\noexpand\csname\string#1\endcsname 912 | \unexpanded\expandafter\expandafter\expandafter 913 | {\expandafter\@gobbletwo#2}}% 914 | \let\expandafter\noexpand\csname\string#1\endcsname 915 | \expandafter\noexpand\csname\string#2\endcsname 916 | }\etb@tempa} 917 | \g@addto@macro\@declarecommandcopylisthook 918 | {{\etb@if@robustcmd\etb@copy@robustcmd}} 919 | }{} 920 | % {} 921 | 922 | \newcommand*{\csuse}[1]{% 923 | \ifcsname#1\endcsname 924 | \csname#1\expandafter\endcsname 925 | \fi} 926 | 927 | % {} 928 | 929 | \newrobustcmd{\undef}[1]{\let#1\etb@undefined} 930 | \newrobustcmd{\gundef}[1]{\global\let#1\etb@undefined} 931 | 932 | % {} 933 | 934 | \newrobustcmd*{\csundef}[1]{\cslet{#1}\etb@undefined} 935 | \newrobustcmd*{\csgundef}[1]{\global\cslet{#1}\etb@undefined} 936 | 937 | % {}{} 938 | 939 | \newrobustcmd{\appto}[2]{% 940 | \ifundef{#1} 941 | {\edef#1{\unexpanded{#2}}} 942 | {\edef#1{\expandonce#1\unexpanded{#2}}}} 943 | \newrobustcmd{\eappto}[2]{% 944 | \ifundef{#1} 945 | {\edef#1{#2}} 946 | {\edef#1{\expandonce#1#2}}} 947 | \newrobustcmd{\gappto}[2]{% 948 | \ifundef{#1} 949 | {\xdef#1{\unexpanded{#2}}} 950 | {\xdef#1{\expandonce#1\unexpanded{#2}}}} 951 | \newrobustcmd{\xappto}[2]{% 952 | \ifundef{#1} 953 | {\xdef#1{#2}} 954 | {\xdef#1{\expandonce#1#2}}} 955 | 956 | \newrobustcmd*{\protected@eappto}{\etb@protected\eappto} 957 | \newrobustcmd*{\protected@xappto}{\etb@protected\xappto} 958 | 959 | % {}{} 960 | 961 | \newrobustcmd{\preto}[2]{% 962 | \ifundef{#1} 963 | {\edef#1{\unexpanded{#2}}} 964 | {\edef#1{\unexpanded{#2}\expandonce#1}}} 965 | \newrobustcmd{\epreto}[2]{% 966 | \ifundef{#1} 967 | {\edef#1{#2}} 968 | {\edef#1{#2\expandonce#1}}} 969 | \newrobustcmd{\gpreto}[2]{% 970 | \ifundef{#1} 971 | {\xdef#1{\unexpanded{#2}}} 972 | {\xdef#1{\unexpanded{#2}\expandonce#1}}} 973 | \newrobustcmd{\xpreto}[2]{% 974 | \ifundef{#1} 975 | {\xdef#1{#2}} 976 | {\xdef#1{#2\expandonce#1}}} 977 | 978 | \newrobustcmd*{\protected@epreto}{\etb@protected\epreto} 979 | \newrobustcmd*{\protected@xpreto}{\etb@protected\xpreto} 980 | 981 | % {}{} 982 | 983 | \newrobustcmd*{\csappto}[1]{\expandafter\appto\csname#1\endcsname} 984 | \newrobustcmd*{\cseappto}[1]{\expandafter\eappto\csname#1\endcsname} 985 | \newrobustcmd*{\csgappto}[1]{\expandafter\gappto\csname#1\endcsname} 986 | \newrobustcmd*{\csxappto}[1]{\expandafter\xappto\csname#1\endcsname} 987 | \newrobustcmd*{\protected@cseappto}{\etb@protected\cseappto} 988 | \newrobustcmd*{\protected@csxappto}{\etb@protected\csxappto} 989 | 990 | % {}{} 991 | 992 | \newrobustcmd*{\cspreto}[1]{\expandafter\preto\csname#1\endcsname} 993 | \newrobustcmd*{\csepreto}[1]{\expandafter\epreto\csname#1\endcsname} 994 | \newrobustcmd*{\csgpreto}[1]{\expandafter\gpreto\csname#1\endcsname} 995 | \newrobustcmd*{\csxpreto}[1]{\expandafter\xpreto\csname#1\endcsname} 996 | \newrobustcmd*{\protected@csepreto}{\etb@protected\csepreto} 997 | \newrobustcmd*{\protected@csxpreto}{\etb@protected\csxpreto} 998 | 999 | % {}{} 1000 | 1001 | \newrobustcmd*{\numdef}[2]{% 1002 | \ifundef#1{\let#1\z@}{}% 1003 | \edef#1{\the\numexpr#2}} 1004 | \newrobustcmd*{\numgdef}[2]{% 1005 | \ifundef#1{\let#1\z@}{}% 1006 | \xdef#1{\the\numexpr#2}} 1007 | 1008 | % {}{} 1009 | 1010 | \newrobustcmd*{\csnumdef}[1]{% 1011 | \expandafter\numdef\csname#1\endcsname} 1012 | \newrobustcmd*{\csnumgdef}[1]{% 1013 | \expandafter\numgdef\csname#1\endcsname} 1014 | 1015 | % {}{} 1016 | 1017 | \newrobustcmd*{\dimdef}[2]{% 1018 | \ifundef#1{\let#1\z@}{}% 1019 | \edef#1{\the\dimexpr#2}} 1020 | \newrobustcmd*{\dimgdef}[2]{% 1021 | \ifundef#1{\let#1\z@}{}% 1022 | \xdef#1{\the\dimexpr#2}} 1023 | 1024 | % {}{} 1025 | 1026 | \newrobustcmd*{\csdimdef}[1]{% 1027 | \expandafter\dimdef\csname#1\endcsname} 1028 | \newrobustcmd*{\csdimgdef}[1]{% 1029 | \expandafter\dimgdef\csname#1\endcsname} 1030 | 1031 | % {}{} 1032 | 1033 | \newrobustcmd*{\gluedef}[2]{% 1034 | \ifundef#1{\let#1\z@skip}{}% 1035 | \edef#1{\the\glueexpr#2}} 1036 | \newrobustcmd*{\gluegdef}[2]{% 1037 | \ifundef#1{\let#1\z@skip}{}% 1038 | \xdef#1{\the\glueexpr#2}} 1039 | 1040 | % {}{} 1041 | 1042 | \newrobustcmd*{\csgluedef}[1]{% 1043 | \expandafter\gluedef\csname#1\endcsname} 1044 | \newrobustcmd*{\csgluegdef}[1]{% 1045 | \expandafter\gluegdef\csname#1\endcsname} 1046 | 1047 | % {}{} 1048 | 1049 | \newrobustcmd*{\mudef}[2]{% 1050 | \ifundef#1{\def#1{0mu}}{}% 1051 | \edef#1{\the\muexpr#2}} 1052 | \newrobustcmd*{\mugdef}[2]{% 1053 | \ifundef#1{\let#1\z@}{}% 1054 | \xdef#1{\the\muexpr#2}} 1055 | 1056 | % {}{} 1057 | 1058 | \newrobustcmd*{\csmudef}[1]{% 1059 | \expandafter\mudef\csname#1\endcsname} 1060 | \newrobustcmd*{\csmugdef}[1]{% 1061 | \expandafter\mugdef\csname#1\endcsname} 1062 | 1063 | % {}{} 1064 | 1065 | \newrobustcmd*{\defcounter}[2]{% 1066 | \ifcsundef{c@#1} 1067 | {\etb@noglobal\@nocounterr{#1}}% 1068 | {\csname c@#1\endcsname\numexpr#2\relax}} 1069 | 1070 | % {}{} 1071 | 1072 | \newrobustcmd*{\deflength}[2]{% 1073 | \ifundef{#1} 1074 | {\etb@noglobal\etb@err@nolen{#1}}% 1075 | {#1\glueexpr#2\relax}} 1076 | 1077 | \protected\def\etb@err@nolen#1{% 1078 | \etb@error{Length '\string#1' undefined}\@eha} 1079 | 1080 | % {} 1081 | 1082 | \newrobustcmd*{\newbool}[1]{% 1083 | \expandafter\@ifdefinable\csname if#1\endcsname{% 1084 | \expandafter\newif\csname if#1\endcsname}} 1085 | 1086 | % {} 1087 | 1088 | \newrobustcmd*{\providebool}[1]{% 1089 | \ifcsundef{if#1} 1090 | {\expandafter\newif\csname if#1\endcsname} 1091 | {\begingroup 1092 | \edef\@tempa{\expandafter\meaning\csname if#1\endcsname}% 1093 | \ifx\@tempa\etb@isfalse 1094 | \else 1095 | \ifx\@tempa\etb@istrue 1096 | \else 1097 | \etb@error{\@backslashchar if#1 not a boolean}\@eha 1098 | \fi 1099 | \fi 1100 | \endgroup}} 1101 | 1102 | % {}{|} 1103 | 1104 | \newrobustcmd*{\setbool}[2]{% 1105 | \ifcsundef{if#1} 1106 | {\etb@noglobal\etb@err@nobool{#1}} 1107 | {\ifcsundef{#1#2} 1108 | {\etb@noglobal\etb@err@boolval{#2}} 1109 | {\csname#1#2\endcsname}}} 1110 | 1111 | % {} 1112 | 1113 | \newrobustcmd*{\booltrue}[1]{% 1114 | \ifcsundef{if#1} 1115 | {\etb@noglobal\etb@err@nobool{#1}} 1116 | {\csname#1true\endcsname}} 1117 | 1118 | % {} 1119 | 1120 | \newrobustcmd*{\boolfalse}[1]{% 1121 | \ifcsundef{if#1} 1122 | {\etb@noglobal\etb@err@nobool{#1}} 1123 | {\csname#1false\endcsname}} 1124 | 1125 | \edef\etb@istrue{\meaning\iftrue} 1126 | \edef\etb@isfalse{\meaning\iffalse} 1127 | \protected\def\etb@noglobal{\let\relax\relax} 1128 | 1129 | % {}{} 1130 | 1131 | \newcommand*{\ifbool}[1]{% 1132 | \ifcsundef{if#1} 1133 | {\etb@err@nobool{#1}\@gobbletwo} 1134 | {\csname if#1\endcsname 1135 | \expandafter\@firstoftwo 1136 | \else 1137 | \expandafter\@secondoftwo 1138 | \fi}} 1139 | 1140 | % {}{} 1141 | 1142 | \newcommand*{\notbool}[1]{% 1143 | \ifcsundef{if#1} 1144 | {\etb@err@nobool{#1}\@gobbletwo} 1145 | {\csname if#1\endcsname 1146 | \expandafter\@secondoftwo 1147 | \else 1148 | \expandafter\@firstoftwo 1149 | \fi}} 1150 | 1151 | \protected\def\etb@err@nobool#1{% 1152 | \etb@error{Boolean '\@backslashchar if#1' undefined}\@eha} 1153 | 1154 | \def\etb@err@boolval#1{% 1155 | \etb@error 1156 | {Invalid boolean value '#1'} 1157 | {Valid boolean values are 'true' and 'false'.}} 1158 | 1159 | % {} 1160 | 1161 | \newrobustcmd*{\newtoggle}[1]{% 1162 | \ifcsdef{etb@tgl@#1} 1163 | {\etb@error{Toggle '#1' already defined}\@eha} 1164 | {\cslet{etb@tgl@#1}\@secondoftwo}} 1165 | 1166 | % {} 1167 | 1168 | \newrobustcmd*{\providetoggle}[1]{% 1169 | \ifcsdef{etb@tgl@#1} 1170 | {} 1171 | {\cslet{etb@tgl@#1}\@secondoftwo}} 1172 | 1173 | % {}{|} 1174 | 1175 | \newrobustcmd*{\settoggle}[2]{% 1176 | \ifcsdef{etb@tgl@#1} 1177 | {\ifcsdef{etb@toggle#2} 1178 | {\csletcs{etb@tgl@#1}{etb@toggle#2}} 1179 | {\etb@noglobal\etb@err@boolval{#2}}} 1180 | {\etb@noglobal\etb@err@notoggle{#1}}} 1181 | 1182 | % {} 1183 | 1184 | \newrobustcmd*{\toggletrue}[1]{% 1185 | \ifcsdef{etb@tgl@#1} 1186 | {\cslet{etb@tgl@#1}\etb@toggletrue} 1187 | {\etb@noglobal\etb@err@notoggle{#1}}} 1188 | 1189 | % {} 1190 | 1191 | \newrobustcmd*{\togglefalse}[1]{% 1192 | \ifcsdef{etb@tgl@#1} 1193 | {\cslet{etb@tgl@#1}\etb@togglefalse} 1194 | {\etb@noglobal\etb@err@notoggle{#1}}} 1195 | 1196 | \let\etb@toggletrue\@firstoftwo 1197 | \let\etb@togglefalse\@secondoftwo 1198 | 1199 | % {}{} 1200 | 1201 | \newcommand*{\iftoggle}[1]{% 1202 | \ifcsdef{etb@tgl@#1} 1203 | {\csname etb@tgl@#1\endcsname} 1204 | {\etb@err@notoggle{#1}\@gobbletwo}} 1205 | 1206 | % {}{} 1207 | 1208 | \newcommand*{\nottoggle}[1]{% 1209 | \ifcsdef{etb@tgl@#1} 1210 | {\csname etb@tgl@#1\endcsname\@secondoftwo\@firstoftwo} 1211 | {\etb@err@notoggle{#1}\@gobbletwo}} 1212 | 1213 | \protected\def\etb@err@notoggle#1{% 1214 | \etb@error{Toggle '#1' undefined}\@eha} 1215 | 1216 | % {}{} 1217 | 1218 | \protected\def\etb@ifscanable#1{% 1219 | \begingroup 1220 | \edef\etb@resrvda{% 1221 | \def\noexpand\etb@resrvda####1\detokenize{macro}:####2->####3&{% 1222 | ####1\def\string\etb@resrvda####2{####3}}% 1223 | \edef\noexpand\etb@resrvda{\noexpand\etb@resrvda\meaning#1&}}% 1224 | \etb@resrvda 1225 | \makeatletter 1226 | \endlinechar\m@ne 1227 | \newlinechar\m@ne 1228 | \scantokens\expandafter{\etb@resrvda}% 1229 | \expandafter\endgroup\ifx#1\etb@resrvda 1230 | \expandafter\@firstoftwo 1231 | \else 1232 | \expandafter\@secondoftwo 1233 | \fi} 1234 | 1235 | % {}{}{} 1236 | 1237 | \protected\long\def\etb@ifpattern#1#2{% 1238 | \begingroup 1239 | \edef\etb@resrvda{% 1240 | \def\noexpand\etb@resrvda####1\detokenize{#2}####2&{% 1241 | \endgroup\noexpand\noexpand\noexpand\ifblank{####2}}% 1242 | \edef\noexpand\etb@resrvda{\noexpand\etb@resrvda 1243 | \expandafter\strip@prefix\meaning#1\detokenize{#2}&}% 1244 | \noexpand\etb@resrvda}% 1245 | \etb@resrvda\@secondoftwo\@firstoftwo} 1246 | 1247 | % {}{} 1248 | 1249 | \protected\long\def\etb@ifhashcheck#1{% 1250 | \begingroup 1251 | \edef\etb@resrvda{\detokenize{#1}}% 1252 | \expandafter\endgroup 1253 | \expandafter\etb@ifhashcheck@i\meaning\etb@resrvda&} 1254 | 1255 | \edef\etb@ifhashcheck@i#1&{% 1256 | \noexpand\expandafter 1257 | \noexpand\etb@ifhashcheck@ii 1258 | \noexpand\strip@prefix#1\string#\string#&} 1259 | 1260 | \edef\etb@ifhashcheck@ii{% 1261 | \def\noexpand\etb@ifhashcheck@ii##1\string#\string###2&} 1262 | \etb@ifhashcheck@ii{\ifblank{#2}} 1263 | 1264 | % {} 1265 | 1266 | \newrobustcmd*{\robustify}[1]{% 1267 | \ifundef{#1} 1268 | {\etb@error{\string#1 undefined}\@eha} 1269 | {\ifdefmacro{#1} 1270 | {\ifdefltxprotect{#1} 1271 | {\letcs\etb@resrvda{\expandafter\@gobble\string#1 }% 1272 | \@tempswatrue} 1273 | {\let\etb@resrvda#1% 1274 | \@tempswafalse}% 1275 | \ifdefparam\etb@resrvda 1276 | {\etb@ifscanable\etb@resrvda 1277 | {\etb@robustify\etb@resrvda 1278 | \let#1\etb@resrvda} 1279 | {\etb@error{Failed to robustify \string#1} 1280 | {The command is special and cannot be 1281 | handled by \string\robustify.}% 1282 | \@tempswafalse}} 1283 | {\protected\edef#1{\expandonce\etb@resrvda}}% 1284 | \if@tempswa 1285 | \csundef{\expandafter\@gobble\string#1 }% 1286 | \fi 1287 | \undef\etb@resrvda} 1288 | {\etb@error{\string#1 not a macro}\@eha}}} 1289 | 1290 | \def\etb@robustify#1{% 1291 | \begingroup 1292 | \edef\etb@resrvdb{% 1293 | \def\noexpand\etb@resrvdb####1\detokenize{macro}:####2->####3&{% 1294 | \protected####1\def\string#1\space####2{####3}}% 1295 | \edef\noexpand\etb@resrvdb{% 1296 | \noexpand\etb@resrvdb\meaning#1&}}% 1297 | \etb@resrvdb 1298 | \etb@patchcmd@scantoks\etb@resrvdb} 1299 | 1300 | % {}{}{} 1301 | % *{}{} 1302 | 1303 | \newrobustcmd{\ifpatchable}{% 1304 | \etb@dbg@trce\ifpatchable 1305 | \begingroup 1306 | \@makeother\#% 1307 | \@ifstar\etb@ifpatchable@i\etb@ifpatchable} 1308 | 1309 | \long\def\etb@ifpatchable#1#2{% 1310 | \endgroup 1311 | \etb@dbg@init#1% 1312 | \ifundef{#1} 1313 | {\etb@dbg@fail{def}\@secondoftwo} 1314 | {\etb@dbg@info{def}% 1315 | \ifdefmacro{#1} 1316 | {\etb@dbg@info{mac}% 1317 | \etb@ifscanable{#1} 1318 | {\etb@ifhashcheck{#2} 1319 | {\etb@dbg@info{tok}% 1320 | \etb@ifpattern#1{#2} 1321 | {\etb@dbg@info{pat}% 1322 | \etb@dbg@info{pos}\@firstoftwo} 1323 | {\etb@dbg@fail{pat}\@secondoftwo}} 1324 | {\etb@dbg@fail{hsh}\@secondoftwo}} 1325 | {\etb@dbg@fail{tok}\@secondoftwo}} 1326 | {\etb@dbg@fail{mac}\@secondoftwo}}} 1327 | 1328 | \long\def\etb@ifpatchable@i#1{% 1329 | \endgroup 1330 | \etb@dbg@init#1% 1331 | \ifundef{#1} 1332 | {\etb@dbg@fail{def}\@secondoftwo} 1333 | {\etb@dbg@info{def}% 1334 | \ifdefmacro{#1} 1335 | {\etb@dbg@info{mac}% 1336 | \ifdefparam{#1} 1337 | {\etb@dbg@info{prm}% 1338 | \etb@ifscanable{#1} 1339 | {\etb@dbg@info{tok}% 1340 | \etb@dbg@info{pos}\@firstoftwo} 1341 | {\etb@dbg@fail{tok}\@secondoftwo}} 1342 | {\etb@dbg@info{prl}% 1343 | \ifdefprotected{#1} 1344 | {\etb@dbg@info{pro}} 1345 | {}% 1346 | \etb@dbg@info{pos}\@firstoftwo}} 1347 | {\etb@dbg@fail{mac}\@secondoftwo}}} 1348 | 1349 | % []{}{}{}{}{} 1350 | 1351 | \newrobustcmd*{\patchcmd}{% 1352 | \etb@dbg@trce\patchcmd 1353 | \begingroup 1354 | \@makeother\#% 1355 | \etb@patchcmd} 1356 | 1357 | \newcommand{\etb@patchcmd}[4][########1]{% 1358 | \etb@ifpatchable#2{#3} 1359 | {\etb@dbg@succ{ret}% 1360 | \begingroup 1361 | \edef\etb@resrvda{% 1362 | \def\noexpand\etb@resrvda####1\detokenize{macro:}####2->####3&{% 1363 | #1\def\string\etb@resrvda\space####2{\noexpand\etb@resrvdb####3&}}% 1364 | \def\noexpand\etb@resrvdb####1\detokenize{#3}####2&{% 1365 | ####1\detokenize{#4}####2}% 1366 | \edef\noexpand\etb@resrvda{% 1367 | \noexpand\etb@resrvda\meaning#2&}}% 1368 | \etb@resrvda 1369 | \etb@patchcmd@scantoks\etb@resrvda 1370 | \let#2\etb@resrvda 1371 | \undef\etb@resrvda 1372 | \@firstoftwo}% 1373 | {\@secondoftwo}} 1374 | 1375 | \def\etb@patchcmd@scantoks#1{% 1376 | \edef\etb@resrvda{\endgroup 1377 | \endlinechar\m@ne 1378 | \unexpanded{\makeatletter\scantokens}{#1}% 1379 | \endlinechar\the\endlinechar\relax 1380 | \catcode\number`\@=\the\catcode`\@\relax}% 1381 | \etb@resrvda} 1382 | 1383 | % {}{}{}{} 1384 | 1385 | \newrobustcmd*{\apptocmd}{% 1386 | \etb@dbg@trce\apptocmd 1387 | \begingroup 1388 | \@makeother\#% 1389 | \etb@hooktocmd\etb@append} 1390 | 1391 | \newrobustcmd*{\pretocmd}{% 1392 | \etb@dbg@trce\pretocmd 1393 | \begingroup 1394 | \@makeother\#% 1395 | \etb@hooktocmd\etb@prepend} 1396 | 1397 | \long\def\etb@hooktocmd#1#2#3{% 1398 | \endgroup 1399 | \etb@dbg@init#2% 1400 | \ifundef{#2} 1401 | {\etb@dbg@fail{def}\@secondoftwo} 1402 | {\etb@dbg@info{def}% 1403 | \ifdefmacro{#2} 1404 | {\etb@dbg@info{mac}% 1405 | \ifdefparam{#2} 1406 | {\etb@dbg@info{prm}% 1407 | \etb@ifscanable{#2} 1408 | {\etb@ifhashcheck{#3} 1409 | {\etb@dbg@info{tok}% 1410 | \etb@dbg@succ{ret}% 1411 | \etb@hooktocmd@i#1#2{#3}% 1412 | \@firstoftwo} 1413 | {\etb@dbg@fail{hsh}\@secondoftwo}} 1414 | {\etb@dbg@fail{tok}\@secondoftwo}} 1415 | {\etb@dbg@info{prl}% 1416 | \ifdefprotected{#2} 1417 | {\etb@dbg@info{pro}% 1418 | \etb@dbg@succ{red}% 1419 | \protected} 1420 | {\etb@dbg@succ{red}}% 1421 | \edef#2{#1{\expandonce#2}{\unexpanded{#3}}}% 1422 | \@firstoftwo}} 1423 | {\etb@dbg@fail{mac}\@secondoftwo}}} 1424 | 1425 | \long\def\etb@hooktocmd@i#1#2#3{% 1426 | \begingroup 1427 | \edef\etb@resrvda{% 1428 | \def\noexpand\etb@resrvda####1\detokenize{macro}:####2->####3&{% 1429 | ####1\def\string\etb@resrvda\space####2{#1{####3}{\detokenize{#3}}}}% 1430 | \edef\noexpand\etb@resrvda{% 1431 | \noexpand\etb@resrvda\meaning#2&}}% 1432 | \etb@resrvda 1433 | \etb@patchcmd@scantoks\etb@resrvda 1434 | \let#2\etb@resrvda 1435 | \undef\etb@resrvda} 1436 | 1437 | \long\def\etb@append#1#2{#1#2} 1438 | \long\def\etb@prepend#1#2{#2#1} 1439 | 1440 | \newrobustcmd*{\tracingpatches}{% 1441 | \etb@info{Enabling tracing}% 1442 | \input{etoolbox.def}% 1443 | \global\let\tracingpatches\relax} 1444 | \@onlypreamble\tracingpatches 1445 | 1446 | \let\etb@dbg@trce\@gobble 1447 | \let\etb@dbg@init\@gobble 1448 | \let\etb@dbg@info\@gobble 1449 | \let\etb@dbg@succ\@gobble 1450 | \let\etb@dbg@fail\@gobble 1451 | 1452 | % {} 1453 | 1454 | \newcommand{\rmntonum}[1]{% 1455 | \ifblank{#1} 1456 | {} 1457 | {\expandafter\etb@rti@end\number\numexpr 1458 | \expandafter\etb@rti@prs\detokenize{#1}&\relax}} 1459 | 1460 | \def\etb@rti@prs#1#2{% 1461 | \ifx% 1462 | \expandafter\@firstoftwo 1463 | \else 1464 | \expandafter\@secondoftwo 1465 | \fi 1466 | {#1#2} 1467 | {\ifx% 1468 | \expandafter\@firstoftwo 1469 | \else 1470 | \expandafter\@secondoftwo 1471 | \fi 1472 | {\etb@rti@chk#1+\etb@rti@num#1#2} 1473 | {\etb@rti@chk#1\etb@rti@chk#2% 1474 | \ifnum\etb@rti@num#1<\etb@rti@num#2 % 1475 | \expandafter\@firstoftwo 1476 | \else 1477 | \expandafter\@secondoftwo 1478 | \fi 1479 | {+\etb@rti@num#2-\etb@rti@num#1\etb@rti@prs} 1480 | {+\etb@rti@num#1\etb@rti@prs#2}}}} 1481 | 1482 | \def\etb@rti@chk#1{% 1483 | \ifcsname etb@rmn@#1\endcsname 1484 | \else 1485 | \expandafter\etb@rti@brk 1486 | \fi} 1487 | 1488 | \def\etb@rti@brk#1&{+\z@&-1} 1489 | \def\etb@rti@end#1\relax{\ifblank{#2}{#1}{#2}} 1490 | \def\etb@rti@num#1{\csname etb@rmn@#1\endcsname} 1491 | 1492 | \chardef\etb@rmn@i=1 1493 | \chardef\etb@rmn@I=1 1494 | \chardef\etb@rmn@v=5 1495 | \chardef\etb@rmn@V=5 1496 | \chardef\etb@rmn@x=10 1497 | \chardef\etb@rmn@X=10 1498 | \chardef\etb@rmn@l=50 1499 | \chardef\etb@rmn@L=50 1500 | \chardef\etb@rmn@c=100 1501 | \chardef\etb@rmn@C=100 1502 | \mathchardef\etb@rmn@d=500 1503 | \mathchardef\etb@rmn@D=500 1504 | \mathchardef\etb@rmn@m=1000 1505 | \mathchardef\etb@rmn@M=1000 1506 | 1507 | % {}{}{} 1508 | 1509 | \newcommand{\ifrmnum}[1]{% 1510 | \ifblank{#1} 1511 | {\@secondoftwo} 1512 | {\expandafter\etb@ifr@prs\detokenize{#1}\relax}} 1513 | 1514 | \def\etb@ifr@prs#1{% 1515 | \ifx\relax#1% 1516 | \expandafter\@firstoftwo 1517 | \else 1518 | \ifcsname etb@rmn@#1\endcsname 1519 | \expandafter\expandafter 1520 | \expandafter\etb@ifr@prs 1521 | \else 1522 | \expandafter\expandafter 1523 | \expandafter\etb@ifr@brk 1524 | \fi 1525 | \fi} 1526 | 1527 | \def\etb@ifr@brk#1\relax{\@secondoftwo} 1528 | 1529 | % <*>{}{} 1530 | 1531 | \newrobustcmd*{\DeclareListParser}{% 1532 | \@ifstar 1533 | {\etb@defparser\etb@defparser@arg} 1534 | {\etb@defparser\etb@defparser@do}} 1535 | 1536 | \def\etb@defparser#1#2#3{% 1537 | \@ifdefinable#2{#1{#2}{#3}}} 1538 | 1539 | \def\etb@defparser@do#1#2{% 1540 | \ifblank{#2}{\long\def#1##1{% 1541 | \etb@lst@@notoken@do##1\etb@lst@q@end&}} 1542 | {\etb@defparser@do@aux{#1}{#2}}} 1543 | 1544 | \def\etb@defparser@do@aux#1#2{% 1545 | \begingroup 1546 | \edef\@tempa{\endgroup 1547 | \long\def\noexpand#1####1{% 1548 | \expandafter\noexpand 1549 | \csname etb@lst@\expandafter\@gobble\string#1\endcsname 1550 | \noexpand\@nil####1\noexpand#2\noexpand\etb@lst@q@end\noexpand#2&}% 1551 | \long\csdef{etb@lst@\expandafter\@gobble\string#1}% 1552 | ####1\noexpand#2{% 1553 | \noexpand\expandafter\noexpand\ifx\noexpand\expandafter 1554 | \noexpand\etb@lst@q@end\noexpand\@gobble####1\noexpand\@empty 1555 | \noexpand\expandafter\noexpand\@firstoftwo 1556 | \noexpand\else 1557 | \noexpand\expandafter\noexpand\@secondoftwo 1558 | \noexpand\fi 1559 | {\noexpand\listbreak} 1560 | {\noexpand\etb@listitem\noexpand\do{####1}% 1561 | \expandafter\noexpand 1562 | \csname etb@lst@\expandafter\@gobble\string#1\endcsname 1563 | \noexpand\@nil}}}% 1564 | \@tempa} 1565 | 1566 | \long\def\etb@lst@@notoken@do#1{% 1567 | \ifx\etb@lst@q@end#1\@empty 1568 | \expandafter\@firstoftwo 1569 | \else 1570 | \expandafter\@secondoftwo 1571 | \fi 1572 | {\listbreak} 1573 | {\do{#1}% 1574 | \etb@lst@@notoken@do}} 1575 | 1576 | \def\etb@lst@q@end{\etb@lst@q@end} 1577 | 1578 | \def\etb@defparser@arg#1#2{% 1579 | \ifblank{#2}{\long\def#1##1##2{% 1580 | \etb@lst@@notoken@arg{##1}##2\etb@lst@q@end&}} 1581 | {\etb@defparser@arg@aux{#1}{#2}}} 1582 | 1583 | \def\etb@defparser@arg@aux#1#2{% 1584 | \begingroup 1585 | \edef\@tempa{\endgroup 1586 | \long\def\noexpand#1####1####2{% 1587 | \expandafter\noexpand 1588 | \csname etb@lst@\expandafter\@gobble\string#1\endcsname 1589 | {####1}\noexpand\@nil####2\noexpand#2\noexpand\etb@lst@q@end\noexpand#2&}% 1590 | \long\csdef{etb@lst@\expandafter\@gobble\string#1}####1####2\noexpand#2{% 1591 | \noexpand\expandafter\noexpand\ifx\noexpand\expandafter 1592 | \noexpand\etb@lst@q@end\noexpand\@gobble####2\noexpand\@empty 1593 | \noexpand\expandafter\noexpand\@firstoftwo 1594 | \noexpand\else 1595 | \noexpand\expandafter\noexpand\@secondoftwo 1596 | \noexpand\fi 1597 | {\noexpand\listbreak} 1598 | {\noexpand\etb@listitem{####1}{####2}% 1599 | \expandafter\noexpand 1600 | \csname etb@lst@\expandafter\@gobble\string#1\endcsname 1601 | {####1}\noexpand\@nil}}}% 1602 | \@tempa} 1603 | 1604 | \long\def\etb@lst@@notoken@arg#1#2{% 1605 | \ifx\etb@lst@q@end#2\@empty 1606 | \expandafter\@firstoftwo 1607 | \else 1608 | \expandafter\@secondoftwo 1609 | \fi 1610 | {\listbreak} 1611 | {#1{#2}% 1612 | \etb@lst@@notoken@arg{#1}}} 1613 | 1614 | \long\def\etb@listitem#1#2{% 1615 | \expandafter\ifblank\expandafter{\@gobble#2} 1616 | {} 1617 | {\expandafter\etb@listitem@i 1618 | \expandafter{\@secondoftwo#2}{#1}}} 1619 | \long\def\etb@listitem@i#1#2{#2{#1}} 1620 | 1621 | \newcommand*{\listbreak}{} 1622 | \long\def\listbreak#1&{} 1623 | 1624 | % {,,...} => \do{}\do{}... 1625 | 1626 | \DeclareListParser{\docsvlist}{,} 1627 | 1628 | % {}{,,...} => {}{}... 1629 | 1630 | \DeclareListParser*{\forcsvlist}{,} 1631 | 1632 | % {}{} 1633 | 1634 | \newrobustcmd{\listadd}[2]{% 1635 | \ifblank{#2}{}{\appto#1{#2|}}} 1636 | \newrobustcmd{\listeadd}[2]{% 1637 | \begingroup 1638 | \edef\etb@tempa{\endgroup\noexpand\ifblank{#2}}% 1639 | \etb@tempa{}{\eappto#1{#2|}}} 1640 | \newrobustcmd{\listgadd}[2]{% 1641 | \ifblank{#2}{}{\gappto#1{#2|}}} 1642 | \newrobustcmd{\listxadd}[2]{% 1643 | \begingroup 1644 | \edef\etb@tempa{\endgroup\noexpand\ifblank{#2}}% 1645 | \etb@tempa{}{\xappto#1{#2|}}} 1646 | 1647 | % {}{} 1648 | 1649 | \newrobustcmd{\listcsadd}[1]{% 1650 | \expandafter\listadd\csname#1\endcsname} 1651 | \newrobustcmd{\listcseadd}[1]{% 1652 | \expandafter\listeadd\csname#1\endcsname} 1653 | \newrobustcmd{\listcsgadd}[1]{% 1654 | \expandafter\listgadd\csname#1\endcsname} 1655 | \newrobustcmd{\listcsxadd}[1]{% 1656 | \expandafter\listxadd\csname#1\endcsname} 1657 | 1658 | % {}{} 1659 | 1660 | \newrobustcmd{\listremove}[2]{% 1661 | \etb@listremove{#1}{#2}\def} 1662 | \newrobustcmd{\listgremove}[2]{% 1663 | \etb@listremove{#1}{#2}\gdef} 1664 | 1665 | \protected\long\def\etb@listremove#1#2#3{% 1666 | \ifblank{#2} 1667 | {} 1668 | {\ifinlist{#2}{#1}{% 1669 | \begingroup 1670 | \def\etb@tempa##1|#2|##2&{\endgroup 1671 | \expandafter#3\expandafter#1\expandafter{\@gobble##1|##2}}% 1672 | \expandafter\etb@tempa\expandafter|#1&}{}}% 1673 | } 1674 | 1675 | % {}{} 1676 | 1677 | \newrobustcmd{\listcsremove}[1]{% 1678 | \expandafter\listremove\csname#1\endcsname} 1679 | \newrobustcmd{\listcsgremove}[1]{% 1680 | \expandafter\listgremove\csname#1\endcsname} 1681 | 1682 | % {}{}{}{} 1683 | 1684 | \newrobustcmd{\ifinlist}[2]{% 1685 | \begingroup 1686 | \def\etb@tempa##1|#1|##2&{\endgroup 1687 | \ifblank{##2}\@secondoftwo\@firstoftwo}% 1688 | \expandafter\etb@tempa\expandafter|#2|#1|&} 1689 | 1690 | \newrobustcmd{\xifinlist}[1]{% 1691 | \begingroup 1692 | \edef\etb@tempa{\endgroup\ifinlist{#1}}% 1693 | \etb@tempa} 1694 | 1695 | % {}{}{}{} 1696 | 1697 | \newrobustcmd{\ifinlistcs}[2]{% 1698 | \expandafter\etb@ifinlistcs@i\csname #2\endcsname{#1}} 1699 | \long\def\etb@ifinlistcs@i#1#2{\ifinlist{#2}{#1}} 1700 | 1701 | \newrobustcmd{\xifinlistcs}[1]{% 1702 | \begingroup 1703 | \edef\etb@tempa{\endgroup\ifinlistcs{#1}}% 1704 | \etb@tempa} 1705 | 1706 | % {}{} => {}{}... 1707 | 1708 | \newcommand*{\forlistloop}[2]{% 1709 | \expandafter\etb@forlistloop\expandafter{#2}{#1}} 1710 | 1711 | \long\def\etb@forlistloop#1#2{\etb@forlistloop@i{#2}#1|\etb@lst@q@end|&} 1712 | 1713 | \long\def\etb@forlistloop@i#1#2|{% 1714 | \ifx\etb@lst@q@end#2\@empty 1715 | \expandafter\@firstoftwo 1716 | \else 1717 | \expandafter\@secondoftwo 1718 | \fi 1719 | {\listbreak} 1720 | {\ifblank{#2} 1721 | {} 1722 | {#1{#2}}% 1723 | \etb@forlistloop@i{#1}}} 1724 | 1725 | % {}{} => {}{}... 1726 | 1727 | \newcommand*{\forlistcsloop}[2]{% 1728 | \expandafter\expandafter\expandafter\etb@forlistloop 1729 | \expandafter\expandafter\expandafter{\csname#2\endcsname}{#1}} 1730 | 1731 | % {} => \do{}\do{}... 1732 | 1733 | \newcommand*{\dolistloop}{\forlistloop\do} 1734 | 1735 | % {} => \do{}\do{}... 1736 | 1737 | \newcommand*{\dolistcsloop}{\forlistcsloop\do} 1738 | 1739 | \providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion} 1740 | \IfFormatAtLeastTF{2020-10-01} 1741 | {% 1742 | \newrobustcmd*{\AtEndPreamble}{\AddToHook{begindocument/before}}% 1743 | \let\AfterPreamble\AtBeginDocument 1744 | \newrobustcmd*{\AfterEndPreamble}{\AddToHook{begindocument/end}}% 1745 | \newrobustcmd*{\AfterEndDocument}{\AddToHook{enddocument/end}}% 1746 | \endinput 1747 | } 1748 | {} 1749 | 1750 | % {} 1751 | 1752 | \newrobustcmd*{\AtEndPreamble}{\gappto\@endpreamblehook} 1753 | \newcommand*{\@endpreamblehook}{} 1754 | 1755 | \preto\document{% 1756 | \endgroup 1757 | \let\AtEndPreamble\@firstofone 1758 | \@endpreamblehook 1759 | \protected\def\AtEndPreamble{\@notprerr\@gobble}% 1760 | \undef\@endpreamblehook 1761 | \begingroup} 1762 | 1763 | % {} 1764 | 1765 | \newrobustcmd*{\AfterPreamble}{\AtBeginDocument} 1766 | \AtEndPreamble{\let\AfterPreamble\@firstofone} 1767 | 1768 | % {} 1769 | 1770 | \newrobustcmd*{\AfterEndPreamble}{\gappto\@afterendpreamblehook} 1771 | \newcommand*{\@afterendpreamblehook}{} 1772 | 1773 | \appto\document{% 1774 | \let\AfterEndPreamble\@firstofone 1775 | \@afterendpreamblehook 1776 | \protected\def\AfterEndPreamble{\@notprerr\@gobble}% 1777 | \undef\@afterendpreamblehook 1778 | \ignorespaces} 1779 | 1780 | \AtEndDocument{\let\AfterEndPreamble\@gobble} 1781 | 1782 | % {} 1783 | 1784 | \newrobustcmd*{\AfterEndDocument}{\gappto\@afterenddocumenthook} 1785 | \newcommand*{\@afterenddocumenthook}{} 1786 | 1787 | \patchcmd\enddocument 1788 | {\deadcycles} 1789 | {\let\AfterEndDocument\@firstofone 1790 | \@afterenddocumenthook 1791 | \deadcycles} 1792 | {} 1793 | {\AtEndDocument{% 1794 | \let\etb@@end\@@end 1795 | \def\@@end{% 1796 | \let\AfterEndDocument\@firstofone 1797 | \@afterenddocumenthook 1798 | \etb@@end}}} 1799 | 1800 | % {}{} 1801 | 1802 | \newrobustcmd{\AtBeginEnvironment}[1]{% 1803 | \csgappto{@begin@#1@hook}} 1804 | 1805 | \ifcsname begin \endcsname 1806 | \expandafter\patchcmd\csname begin \endcsname 1807 | {\csname #1\endcsname} 1808 | {\csuse{@begin@#1@hook}% 1809 | \csname #1\endcsname} 1810 | {} 1811 | {\etb@warning{% 1812 | Patching '\string\begin' failed!\MessageBreak 1813 | '\string\AtBeginEnvironment' will not work\@gobble}} 1814 | \else 1815 | \patchcmd\begin 1816 | {\csname #1\endcsname} 1817 | {\csuse{@begin@#1@hook}% 1818 | \csname #1\endcsname} 1819 | {} 1820 | {\etb@warning{% 1821 | Patching '\string\begin' failed!\MessageBreak 1822 | '\string\AtBeginEnvironment' will not work\@gobble}} 1823 | \fi 1824 | 1825 | % {}{} 1826 | 1827 | \newrobustcmd{\AtEndEnvironment}[1]{% 1828 | \csgappto{@end@#1@hook}} 1829 | 1830 | \ifcsname end \endcsname 1831 | \expandafter\patchcmd\csname end \endcsname 1832 | {\csname end#1\endcsname} 1833 | {\csuse{@end@#1@hook}% 1834 | \csname end#1\endcsname} 1835 | {} 1836 | {\etb@warning{% 1837 | Patching '\string\end' failed!\MessageBreak 1838 | '\string\AtEndEnvironment' will not work\@gobble}} 1839 | \else 1840 | \patchcmd\end 1841 | {\csname end#1\endcsname} 1842 | {\csuse{@end@#1@hook}% 1843 | \csname end#1\endcsname} 1844 | {} 1845 | {\etb@warning{% 1846 | Patching '\string\end' failed!\MessageBreak 1847 | '\string\AtEndEnvironment' will not work\@gobble}} 1848 | \fi 1849 | 1850 | % {}{} 1851 | 1852 | \newrobustcmd{\BeforeBeginEnvironment}[1]{% 1853 | \csgappto{@beforebegin@#1@hook}} 1854 | 1855 | \ifcsname begin \endcsname 1856 | \expandafter\pretocmd\csname begin \endcsname 1857 | {\csuse{@beforebegin@#1@hook}} 1858 | {} 1859 | {\etb@warning{% 1860 | Patching '\string\begin' failed!\MessageBreak 1861 | '\string\BeforeBeginEnvironment' will not work\@gobble}} 1862 | \else 1863 | \pretocmd\begin 1864 | {\csuse{@beforebegin@#1@hook}} 1865 | {} 1866 | {\etb@warning{% 1867 | Patching '\string\begin' failed!\MessageBreak 1868 | '\string\BeforeBeginEnvironment' will not work\@gobble}} 1869 | \fi 1870 | 1871 | % {}{} 1872 | 1873 | \newrobustcmd{\AfterEndEnvironment}[1]{% 1874 | \csgappto{@afterend@#1@hook}} 1875 | 1876 | \let\if@ignore\relax 1877 | \ifcsname end \endcsname 1878 | \expandafter\patchcmd\csname end \endcsname 1879 | {\if@ignore} 1880 | {\csuse{@afterend@#1@hook}% 1881 | \if@ignore} 1882 | {} 1883 | {\etb@warning{% 1884 | Patching '\string\end' failed!\MessageBreak 1885 | '\string\AfterEndEnvironment' will not work\@gobble}} 1886 | \else 1887 | \patchcmd\end 1888 | {\if@ignore} 1889 | {\csuse{@afterend@#1@hook}% 1890 | \if@ignore} 1891 | {} 1892 | {\etb@warning{% 1893 | Patching '\string\end' failed!\MessageBreak 1894 | '\string\AfterEndEnvironment' will not work\@gobble}} 1895 | \fi 1896 | \let\if@ignore\iffalse 1897 | 1898 | \endinput 1899 | -------------------------------------------------------------------------------- /etoolbox.tex: -------------------------------------------------------------------------------- 1 | \documentclass{ltxdockit}[2010/09/26] 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[american]{babel} 4 | \usepackage[strict]{csquotes} 5 | \usepackage{shortvrb} 6 | \MakeAutoQuote*{<}{>} 7 | \MakeShortVerb{\|} 8 | 9 | \titlepage{% 10 | title={The \sty{etoolbox} Package}, 11 | subtitle={An \etex Toolbox for Class and Package Authors}, 12 | url={http://www.ctan.org/pkg/etoolbox/}, 13 | author={Philipp Lehman, Joseph Wright}, 14 | email={joseph.wright@morningstar2.co.uk}, 15 | revision={v2.5l}, 16 | date={2025/02/11}} 17 | 18 | \hypersetup{% 19 | pdftitle={The etoolbox Package}, 20 | pdfsubject={An e-TeX Toolbox for Class and Package Authors}, 21 | pdfauthor={Philipp Lehman, Joseph Wright}, 22 | pdfkeywords={tex, e-tex, latex, class, package, programming}} 23 | 24 | \begin{document} 25 | 26 | \printtitlepage 27 | \tableofcontents 28 | 29 | \section{Introduction} 30 | \label{int} 31 | 32 | \subsection[About]{About \sty{etoolbox}} 33 | 34 | The \sty{etoolbox} package is a toolbox of programming tools geared primarily towards \latex class and package authors. It provides \latex frontends to some of the new primitives provided by \etex as well as some generic tools which are not related to \etex but match the profile of this package. 35 | 36 | \subsection{License} 37 | 38 | Copyright \textcopyright\ 2007--2011 Philipp Lehman, 2015--2025 Joseph Wright. Permission is granted to copy, distribute and\slash or modify this software under the terms of the \lppl, version 1.3c or later.\fnurl{http://www.latex-project.org/lppl/} 39 | 40 | \section{User Commands} 41 | \label{use} 42 | 43 | The tools in this section are geared towards regular users as well as class and package authors. 44 | 45 | \subsection{Definitions} 46 | \label{use:def} 47 | 48 | \begin{ltxsyntax} 49 | 50 | \cmditem{newrobustcmd}{command}[arguments][optarg default]{replacement text} 51 | \cmditem*{newrobustcmd*}{command}[arguments][optarg default]{replacement text} 52 | 53 | The syntax and behavior of this command is similar to \cmd{newcommand} except that the newly defined \prm{command} will be robust. The behavior of this command differs from the \cmd{DeclareRobustCommand} command from the \latex kernel in that it issues an error rather than just an informational message if the \prm{command} is already defined. Since it uses \etex's low-level protection mechanism rather than the corresponding higher-level \latex facilities, it does not require an additional macro to implement the . 54 | 55 | \cmditem{renewrobustcmd}{command}[arguments][optarg default]{replacement text} 56 | \cmditem*{renewrobustcmd*}{command}[arguments][optarg default]{replacement text} 57 | 58 | The syntax and behavior of this command is similar to \cmd{renewcommand} except that the redefined \prm{command} will be robust. 59 | 60 | \cmditem{providerobustcmd}{command}[arguments][optarg default]{replacement text} 61 | \cmditem*{providerobustcmd*}{command}[arguments][optarg default]{replacement text} 62 | 63 | The syntax and behavior of this command is similar to \cmd{providecommand} except that the newly defined \prm{command} will be robust. Note that this command will provide a robust definition of the \prm{command} only if it is undefined. It will not make an already defined \prm{command} robust. 64 | 65 | \end{ltxsyntax} 66 | 67 | \subsection{Patching} 68 | \label{use:pat} 69 | 70 | \begin{ltxsyntax} 71 | 72 | \cmditem{robustify}{command} 73 | 74 | Redefines a \prm{command} defined with \cmd{newcommand} such that it is robust, without altering its parameters, its prefixes, or its replacement text. If the \prm{command} has been defined with \cmd{DeclareRobustCommand}, this will be detected automatically and \latex's high-level protection mechanism will be replaced by the corresponding low-level \etex feature. If the command has been copied using \cmd{let} \emph{before} robustifing, it is possible an error will arise if the copy is used: in this case, a fresh copy should be created, ideally using the \latex kernel command \cmd{DeclareCommandCopy}. 75 | 76 | \end{ltxsyntax} 77 | 78 | \subsection{Protection} 79 | \label{use:pro} 80 | 81 | \begin{ltxsyntax} 82 | 83 | \cmditem{protecting}{code} 84 | 85 | This command applies \latex's protection mechanism, which normally requires prefixing each fragile command with \cmd{protect}, to an entire chunk of arbitrary \prm{code}. Its behavior depends on the current state of \cmd{protect}. Note that the braces around the \prm{code} are mandatory even if it is a single token. 86 | 87 | \end{ltxsyntax} 88 | 89 | \subsection[Lengths and Counters]{Length and Counter Assignments} 90 | \label{use:cal} 91 | 92 | The tools in this section are replacements for \cmd{setcounter} and \cmd{setlength} which support arithmetic expressions. 93 | 94 | \begin{ltxsyntax} 95 | 96 | \cmditem{defcounter}{counter}{integer expression} 97 | 98 | Assigns a value to a \latex \prm{counter} previously initialized with \cmd{newcounter}. This command is similar in concept and syntax to \cmd{setcounter} except for two major differences. 1) The second argument may be an \prm{integer expression} which will be processed with \cmd{numexpr}. The \prm{integer expression} may be any arbitrary code which is valid in this context. The value assigned to the \prm{counter} will be the result of that calculation. 2) In contrast to \cmd{setcounter}, the assignment is local by default but \cmd{defcounter} may be prefixed with \cs{global}. The functional equivalent of \cmd{setcounter} would be \cs{global}\cmd{defcounter}. 99 | 100 | \cmditem{deflength}{length}{glue expression} 101 | 102 | Assigns a value to a \prm{length} register previously initialized with \cmd{newlength}. This command is similar in concept and syntax to \cmd{setlength} except that the second argument may be a \prm{glue expression} which will be processed with \cmd{glueexpr}. The \prm{glue expression} may be any arbitrary code which is valid in this context. The value assigned to the \prm{length} register will be the result of that calculation. The assignment is local by default but \cmd{deflength} may be prefixed with \cs{global}. This command may be used as a drop-in replacement for \cmd{setlength}. 103 | 104 | \end{ltxsyntax} 105 | 106 | \subsection[Document Hooks]{Additional Document Hooks} 107 | \label{use:pre} 108 | 109 | \latex provides two hooks which defer the execution of code either to the beginning or to the end of the document body. Any \cmd{AtBeginDocument} code is executed towards the beginning of the document body, after the main \file{aux} file has been read for the first time. Any \cmd{AtEndDocument} code is executed at the end of the document body, before the main \file{aux} file is read for the second time. The hooks introduced here are similar in concept but defer the execution of their \prm{code} argument to slightly different locations. The \prm{code} may be arbitrary \tex code. Parameter characters in the \prm{code} argument are permissible and need not be doubled. 110 | 111 | \begin{ltxsyntax} 112 | 113 | \cmditem{AfterPreamble}{code} 114 | 115 | This hook is a variant of \cmd{AtBeginDocument} which may be used in both the preamble and the document body. When used in the preamble, it behaves exactely like \cmd{AtBeginDocument}. When used in the document body, it immediately executes its \prm{code} argument. \cmd{AtBeginDocument} would issue an error in this case. This hook is useful to defer code which needs to write to the main \file{aux} file. 116 | 117 | \cmditem{AtEndPreamble}{code} 118 | 119 | This hook differs from \cmd{AtBeginDocument} in that the \prm{code} is executed right at the end of the preamble, before the main \file{aux} file (as written on the previous \latex pass) is read and prior to any \cmd{AtBeginDocument} code. Note that it is not possible to write to the \file{aux} file at this point. 120 | 121 | \cmditem{AfterEndPreamble}{code} 122 | 123 | This hook differs from \cmd{AtBeginDocument} in that the \prm{code} is executed at the very end of |\begin{document}|, after any \cmd{AtBeginDocument} code. Note that commands whose scope has been restricted to the preamble with \cmd{@onlypreamble} are no longer available when this hook is executed. 124 | 125 | \cmditem{AfterEndDocument}{code} 126 | 127 | This hook differs from \cmd{AtEndDocument} in that the \prm{code} is executed at the very end of the document, after the main \file{aux} file (as written on the current \latex pass) has been read and after any \cmd{AtEndDocument} code. 128 | 129 | \end{ltxsyntax} 130 | 131 | In a way, \cmd{AtBeginDocument} code is part neither of the preamble nor the document body but located in-between them since it gets executed in the middle of the initialization sequence performed prior to typesetting. It is sometimes desirable to move code to the end of the preamble because all requested packages have been loaded at this point. \cmd{AtBeginDocument} code, however, is executed too late if it is required in the \file{aux} file. In contrast to that, \cmd{AtEndPreamble} code is part of the preamble; \cmd{AfterEndPreamble} code is part of the document body and may contain printable text to be typeset at the very beginning of the document. To sum that up, \latex will perform the following tasks |\begin{document}|: 132 | 133 | \begin{itemize} 134 | \setlength{\itemsep}{0pt} 135 | \item Execute any \cmd{AtEndPreamble} code 136 | \item Start initialization for document body (page layout, default fonts, etc.) 137 | \item Load the main \file{aux} file written on the previous \latex pass 138 | \item Open the main \file{aux} file for writing on the current pass 139 | \item Continue initialization for document body 140 | \item Execute any \cmd{AtBeginDocument} code 141 | \item Complete initialization for document body 142 | \item Disable all \cmd{@onlypreamble} commands 143 | \item Execute any \cmd{AfterEndPreamble} code 144 | \end{itemize} 145 | % 146 | Inside |\end{document}|, \latex will perform the following tasks: 147 | 148 | \begin{itemize} 149 | \setlength{\itemsep}{0pt} 150 | \item Execute any \cmd{AtEndDocument} code 151 | \item Perform a final \cmd{clearpage} operation 152 | \item Close the main \file{aux} file for writing 153 | \item Load the main \file{aux} file written on the current \latex pass 154 | \item Perform final tests and issue warnings, if applicable 155 | \item Execute any \cmd{AfterEndDocument} code 156 | \end{itemize} 157 | % 158 | Any \cmd{AtEndDocument} code may be considered as being part of the document body insofar as it is still possible to perform typesetting tasks and write to the main \file{aux} file when it gets executed. \cmd{AfterEndDocument} code is not part of the document body. This hook is useful to evaluate the data in the \file{aux} file at the very end of a \latex pass. 159 | 160 | \subsection[Environment Hooks]{Environment Hooks} 161 | \label{use:env} 162 | 163 | The tools in this section provide hooks for arbitrary environments. Note that they will not modify the definition of the \prm{environment}. They hook into the \cmd{begin} and \cmd{end} commands instead. Redefining the \prm{environment} will not clear the corresponding hooks. The \prm{code} may be arbitrary \tex code. Parameter characters in the \prm{code} argument are permissible and need not be doubled. 164 | 165 | \begin{ltxsyntax} 166 | 167 | \cmditem{AtBeginEnvironment}{environment}{code} 168 | 169 | Appends arbitrary \prm{code} to a hook executed by the \cmd{begin} command at the beginning of a given \prm{environment}, immediately before \cmd{\prm{environment}}, inside the group opened by \cmd{begin}. 170 | 171 | \cmditem{AtEndEnvironment}{environment}{code} 172 | 173 | Appends arbitrary \prm{code} to a hook executed by the \cmd{end} command at the end of a given \prm{environment}, immediately before \cmd{end\prm{environment}}, inside the group opened by \cmd{begin}. 174 | 175 | \cmditem{BeforeBeginEnvironment}{environment}{code} 176 | 177 | Appends arbitrary \prm{code} to a hook executed at a very early point by the \cmd{begin} command, before the group holding the environment is opened. 178 | 179 | \cmditem{AfterEndEnvironment}{environment}{code} 180 | 181 | Appends arbitrary \prm{code} to a hook executed at a very late point by the \cmd{end} command, after the group holding the environment has been closed. 182 | 183 | \end{ltxsyntax} 184 | 185 | \section{Author Commands} 186 | 187 | The tools in this section are geared towards class and package authors. 188 | 189 | \subsection{Definitions} 190 | 191 | \subsubsection{Macro Definitions} 192 | \label{aut:def:def} 193 | 194 | The tools in this section are simple but frequently required shorthands which extend the scope of the \cmd{@namedef} and \cmd{@nameuse} macros from the \latex kernel. 195 | 196 | \begin{ltxsyntax} 197 | 198 | \cmditem{csdef}{csname}{replacement text} 199 | 200 | Similar to the \tex primitive \cmd{def} except that it takes a control sequence name as its first argument. This command is robust and corresponds to \cmd{@namedef}. 201 | 202 | \cmditem{csgdef}{csname}{replacement text} 203 | 204 | Similar to the \tex primitive \cmd{gdef} except that it takes a control sequence name as its first argument. This command is robust. 205 | 206 | \cmditem{csedef}{csname}{replacement text} 207 | 208 | Similar to the \tex primitive \cmd{edef} except that it takes a control sequence name as its first argument. This command is robust. 209 | 210 | \cmditem{csxdef}{csname}{replacement text} 211 | 212 | Similar to the \tex primitive \cmd{xdef} except that it takes a control sequence name as its first argument. This command is robust. 213 | 214 | \cmditem{protected@csedef}{csname}{replacement text} 215 | 216 | Similar to \cmd{csedef} except that \latex's protection mechanism is temporarily enabled. To put it in other words: this command is similar to the \latex kernel command \cmd{protected@edef} except that it takes a control sequence name as its first argument. This command is robust. 217 | 218 | \cmditem{protected@csxdef}{csname}{replacement text} 219 | 220 | Similar to \cmd{csxdef} except that \latex's protection mechanism is temporarily enabled. To put it in other words: this command is similar to the \latex kernel command \cmd{protected@xdef} except that it takes a control sequence name as its first argument. This command is robust. 221 | 222 | \cmditem{cslet}{csname}{command} 223 | 224 | Similar to the \tex primitive \cmd{let} except that the first argument is a control sequence name. If \prm{command} is undefined, \prm{csname} will be undefined as well after the assignment. This command is robust and may be prefixed with \cs{global}. 225 | 226 | \cmditem{letcs}{command}{csname} 227 | 228 | Similar to the \tex primitive \cmd{let} except that the second argument is a control sequence name. If \prm{csname} is undefined, the \prm{command} will be undefined as well after the assignment. This command is robust and may be prefixed with \cs{global}. 229 | 230 | \cmditem{csletcs}{csname}{csname} 231 | 232 | Similar to the \tex primitive \cmd{let} except that both arguments are control sequence names. If the second \prm{csname} is undefined, the first \prm{csname} will be undefined as well after the assignment. This command is robust and may be prefixed with \cs{global}. 233 | 234 | \cmditem{csuse}{csname} 235 | 236 | Takes a control sequence name as its argument and forms a control sequence token. This command differs from the \cmd{@nameuse} macro in the \latex kernel in that it expands to an empty string if the control sequence is undefined. 237 | 238 | \cmditem{undef} 239 | 240 | Clears a \prm{command} such that \etex's \cmd{ifdefined} and \cmd{ifcsname} tests will consider it as undefined. This command is robust and may be prefixed with \cs{global}. 241 | 242 | \cmditem{gundef} 243 | 244 | Similar to \cmd{undef} but acts globally. 245 | 246 | \cmditem{csundef}{csname} 247 | 248 | Similar to \cmd{undef} except that it takes a control sequence name as its argument. This command is robust and may be prefixed with \cs{global}. 249 | 250 | \cmditem{csgundef}{csname} 251 | 252 | Similar to \cmd{csundef} but acts globally. 253 | 254 | \cmditem{csmeaning}{csname} 255 | 256 | Similar to the \tex primitive \cmd{meaning} but takes a control sequence name as its argument. If the control sequence is undefined, this command will not implicitly assign a meaning of \cmd{relax} to it. 257 | 258 | \cmditem{csshow}{csname} 259 | 260 | Similar to the \tex primitive \cmd{show} but takes a control sequence name as its argument. If the control sequence is undefined, this command will not implicitly assign a meaning of \cmd{relax} to it. This command is robust. 261 | 262 | \end{ltxsyntax} 263 | 264 | \subsubsection{Arithmetic Definitions} 265 | \label{aut:def:cal} 266 | 267 | The tools in this section permit calculations using macros rather than length registers and counters. 268 | 269 | \begin{ltxsyntax} 270 | 271 | \cmditem{numdef}{integer expression} 272 | 273 | Similar to \cmd{edef} except that the \prm{integer expression} is processed with \cmd{numexpr}. The \prm{integer expression} may be any arbitrary code which is valid in this context. The replacement text assigned to the \prm{command} will be the result of that calculation. If the \prm{command} is undefined, it will be initialized to \texttt{0} before the \prm{integer expression} is processed. 274 | 275 | \cmditem{numgdef}{integer expression} 276 | 277 | Similar to \cmd{numdef} except that the assignment is global. 278 | 279 | \cmditem{csnumdef}{csname}{integer expression} 280 | 281 | Similar to \cmd{numdef} except that it takes a control sequence name as its first argument. 282 | 283 | \cmditem{csnumgdef}{csname}{integer expression} 284 | 285 | Similar to \cmd{numgdef} except that it takes a control sequence name as its first argument. 286 | 287 | \cmditem{dimdef}{dimen expression} 288 | 289 | Similar to \cmd{edef} except that the \prm{dimen expression} is processed with \cmd{dimexpr}. The \prm{dimen expression} may be any arbitrary code which is valid in this context. The replacement text assigned to the \prm{command} will be the result of that calculation. If the \prm{command} is undefined, it will be initialized to \texttt{0pt} before the \prm{dimen expression} is processed. 290 | 291 | \cmditem{dimgdef}{dimen expression} 292 | 293 | Similar to \cmd{dimdef} except that the assignment is global. 294 | 295 | \cmditem{csdimdef}{csname}{dimen expression} 296 | 297 | Similar to \cmd{dimdef} except that it takes a control sequence name as its first argument. 298 | 299 | \cmditem{csdimgdef}{csname}{dimen expression} 300 | 301 | Similar to \cmd{dimgdef} except that it takes a control sequence name as its first argument. 302 | 303 | \cmditem{gluedef}{glue expression} 304 | 305 | Similar to \cmd{edef} except that the \prm{glue expression} is processed with \cmd{glueexpr}. The \prm{glue expression} may be any arbitrary code which is valid in this context. The replacement text assigned to the \prm{command} will be the result of that calculation. If the \prm{command} is undefined, it will be initialized to \texttt{0pt plus 0pt minus 0pt} before the \prm{glue expression} is processed. 306 | 307 | \cmditem{gluegdef}{glue expression} 308 | 309 | Similar to \cmd{gluedef} except that the assignment is global. 310 | 311 | \cmditem{csgluedef}{csname}{glue expression} 312 | 313 | Similar to \cmd{gluedef} except that it takes a control sequence name as its first argument. 314 | 315 | \cmditem{csgluegdef}{csname}{glue expression} 316 | 317 | Similar to \cmd{gluegdef} except that it takes a control sequence name as its first argument. 318 | 319 | \cmditem{mudef}{muglue expression} 320 | 321 | Similar to \cmd{edef} except that the \prm{muglue expression} is processed with \cmd{muexpr}. The \prm{muglue expression} may be any arbitrary code which is valid in this context. The replacement text assigned to the \prm{command} will be the result of that calculation. If the \prm{command} is undefined, it will be initialized to \texttt{0mu} before the \prm{muglue expression} is processed. 322 | 323 | \cmditem{mugdef}{muglue expression} 324 | 325 | Similar to \cmd{mudef} except that the assignment is global. 326 | 327 | \cmditem{csmudef}{csname}{muglue expression} 328 | 329 | Similar to \cmd{mudef} except that it takes a control sequence name as its first argument. 330 | 331 | \cmditem{csmugdef}{csname}{muglue expression} 332 | 333 | Similar to \cmd{mugdef} except that it takes a control sequence name as its first argument. 334 | 335 | \end{ltxsyntax} 336 | 337 | \subsection{Expansion Control} 338 | \label{aut:exp} 339 | 340 | The tools in this section are useful to control expansion in an \cmd{edef} or a similar context. 341 | 342 | \begin{ltxsyntax} 343 | 344 | \cmditem{expandonce} 345 | 346 | This command expands a \prm{command} once and prevents further expansion of the replacement text. This command is expandable. 347 | 348 | \cmditem{csexpandonce}{csname} 349 | 350 | Similar to \cmd{expandonce} except that it takes a control sequence name as its argument. 351 | 352 | \end{ltxsyntax} 353 | 354 | \subsection{Hook Management} 355 | \label{aut:hok} 356 | 357 | The tools in this section are intended for hook management. A \prm{hook} in this context is a plain macro without any parameters and prefixes which is used to collect code to be executed later. These tools may also be useful to patch simple macros by appending code to their replacement text. For more complex patching operations, see section \ref{aut:pat}. All commands in this section will initialize the \prm{hook} if it is undefined. 358 | 359 | \subsubsection{Appending to a Hook} 360 | \label{aut:hok:app} 361 | 362 | The tools in this section append arbitrary code to a hook. 363 | 364 | \begin{ltxsyntax} 365 | 366 | \cmditem{appto}{code} 367 | 368 | This command appends arbitrary \prm{code} to a \prm{hook}. If the \prm{code} contains any parameter characters, they need not be doubled. This command is robust. 369 | 370 | \cmditem{gappto}{code} 371 | 372 | Similar to \cmd{appto} except that the assignment is global. This command may be used as a drop-in replacement for the \cmd{g@addto@macro} command in the \latex kernel. 373 | 374 | \cmditem{eappto}{code} 375 | 376 | This command appends arbitrary \prm{code} to a \prm{hook}. The \prm{code} is expanded at definition"=time. Only the new \prm{code} is expanded, the current replacement text of the \prm{hook} is not. This command is robust. 377 | 378 | \cmditem{xappto}{code} 379 | 380 | Similar to \cmd{eappto} except that the assignment is global. 381 | 382 | \cmditem{protected@eappto}{code} 383 | 384 | Similar to \cmd{eappto} except that \latex's protection mechanism is temporarily enabled. 385 | 386 | \cmditem{protected@xappto}{code} 387 | 388 | Similar to \cmd{xappto} except that \latex's protection mechanism is temporarily enabled. 389 | 390 | \cmditem{csappto}{csname}{code} 391 | 392 | Similar to \cmd{appto} except that it takes a control sequence name as its first argument. 393 | 394 | \cmditem{csgappto}{csname}{code} 395 | 396 | Similar to \cmd{gappto} except that it takes a control sequence name as its first argument. 397 | 398 | \cmditem{cseappto}{csname}{code} 399 | 400 | Similar to \cmd{eappto} except that it takes a control sequence name as its first argument. 401 | 402 | \cmditem{csxappto}{csname}{code} 403 | 404 | Similar to \cmd{xappto} except that it takes a control sequence name as its first argument. 405 | 406 | \cmditem{protected@cseappto}{csname}{code} 407 | 408 | Similar to \cmd{protected@eappto} except that it takes a control sequence name as its first argument. 409 | 410 | \cmditem{protected@csxappto}{csname}{code} 411 | 412 | Similar to \cmd{protected@xappto} except that it takes a control sequence name as its first argument. 413 | 414 | \end{ltxsyntax} 415 | 416 | \subsubsection{Prepending to a Hook} 417 | \label{aut:hok:pre} 418 | 419 | The tools in this section arbitrary code to a hook, \ie the code is inserted at the beginning of the hook rather than being added at the end. 420 | 421 | \begin{ltxsyntax} 422 | 423 | \cmditem{preto}{code} 424 | 425 | Similar to \cmd{appto} except that the \prm{code} is prepended. 426 | 427 | \cmditem{gpreto}{code} 428 | 429 | Similar to \cmd{preto} except that the assignment is global. 430 | 431 | \cmditem{epreto}{code} 432 | 433 | Similar to \cmd{eappto} except that the \prm{code} is prepended. 434 | 435 | \cmditem{xpreto}{code} 436 | 437 | Similar to \cmd{epreto} except that the assignment is global. 438 | 439 | \cmditem{protected@epreto}{code} 440 | 441 | Similar to \cmd{epreto} except that \latex's protection mechanism is temporarily enabled. 442 | 443 | \cmditem{protected@xpreto}{code} 444 | 445 | Similar to \cmd{xpreto} except that \latex's protection mechanism is temporarily enabled. 446 | 447 | \cmditem{cspreto}{csname}{code} 448 | 449 | Similar to \cmd{preto} except that it takes a control sequence name as its first argument. 450 | 451 | \cmditem{csgpreto}{csname}{code} 452 | 453 | Similar to \cmd{gpreto} except that it takes a control sequence name as its first argument. 454 | 455 | \cmditem{csepreto}{csname}{code} 456 | 457 | Similar to \cmd{epreto} except that it takes a control sequence name as its first argument. 458 | 459 | \cmditem{csxpreto}{csname}{code} 460 | 461 | Similar to \cmd{xpreto} except that it takes a control sequence name as its first argument. 462 | 463 | \cmditem{protected@csepreto}{csname}{code} 464 | 465 | Similar to \cmd{protected@epreto} except that it takes a control sequence name as its first argument. 466 | 467 | \cmditem{protected@csxpreto}{csname}{code} 468 | 469 | Similar to \cmd{protected@xpreto} except that it takes a control sequence name as its first argument. 470 | 471 | \end{ltxsyntax} 472 | 473 | \subsection{Patching} 474 | \label{aut:pat} 475 | 476 | The tools in this section are useful to hook into or modify existing code. All commands presented here preserve the parameters and the prefixes of the patched \prm{command}. Note that \cs{outer} commands may not be patched. Also note that the commands in this section will not automatically issue any error messages if patching fails. Instead, they take a \prm{failure} argument which should provide suitable fallback code or an error message. Issuing \cmd{tracingpatches} in the preamble will cause the commands to write debugging information to the transcript file. 477 | 478 | \begin{ltxsyntax} 479 | 480 | \cmditem{patchcmd}[prefix]{command}{search}{replace}{success}{failure} 481 | 482 | This command extracts the replacement text of a \prm{command}, replaces \prm{search} with \prm{replace}, and reassembles the \prm{command}. The pattern match is category code agnostic and matches the first occurence of the \prm{search} pattern in the replacement text of the \prm{command} to be patched. Note that the patching process involves detokenizing the replacement text of the \prm{command} and retokenizing it under the current category code regime after patching. The category code of the @ sign is temporarily set to 11. If the replacement text of the \prm{command} includes any tokens with non"=standard category codes, the respective category codes must be adjusted prior to patching. If the code to be replaced or inserted refers to the parameters of the \prm{command} to be patched, the parameter characters need not be doubled. If an optional \prm{prefix} is specified, it replaces the prefixes of the \prm{command}. An empty \prm{prefix} argument strips all prefixes from the \prm{command}. The assignment is local. This command implicitly performs the equivalent of an \cmd{ifpatchable} test prior to patching. If this test succeeds, the command applies the patch and executes \prm{success}. If the test fails, it executes \prm{failure} without modifying the original \prm{command}. This command is robust. 483 | 484 | \cmditem{ifpatchable}{command}{search}{true}{false} 485 | 486 | This command executes \prm{true} if the \prm{command} may be patched with \cmd{patchcmd} and if the \prm{search} pattern is found in its replacement text, and \prm{false} otherwise. This command is robust. 487 | 488 | \cmditem*{ifpatchable*}{command}{true}{false} 489 | 490 | Similar to \cmd{ifpatchable} except that the starred variant does not require a search pattern. Use this version to check if a command may be patched with \cmd{apptocmd} and \cmd{pretocmd}. 491 | 492 | \cmditem{apptocmd}{command}{code}{success}{failure} 493 | 494 | This command appends \prm{code} to the replacement text of a \prm{command}. If the \prm{command} is a parameterless macro, it behaves like \cmd{appto} from section \ref{aut:hok:app}. In contrast to \cmd{appto}, \cmd{apptocmd} may also be used to patch commands with parameters. In this case, it will detokenize the replacement text of the \prm{command}, apply the patch, and retokenize it under the current category code regime. The category code of the @ sign is temporarily set to 11. The \prm{code} may refer to the parameters of the \prm{command}. The assignment is local. If patching succeeds, this command executes \prm{success}. If patching fails, it executes \prm{failure} without modifying the original \prm{command}. This command is robust. 495 | 496 | \cmditem{pretocmd}{command}{code}{success}{failure} 497 | 498 | This command is similar to \cmd{apptocmd} except that the \prm{code} is inserted at the beginning of the replacement text of the \prm{command}. If the \prm{command} is a parameterless macro, it behaves like \cmd{preto} from section \ref{aut:hok:app}. In contrast to \cmd{preto}, \cmd{pretocmd} may also be used to patch commands with parameters. In this case, it will detokenize the replacement text of the \prm{command}, apply the patch, and retokenize it under the current category code regime. The category code of the @ sign is temporarily set to 11. The \prm{code} may refer to the parameters of the \prm{command}. The assignment is local. If patching succeeds, this command executes \prm{success}. If patching fails, it executes \prm{failure} without modifying the original \prm{command}. This command is robust. 499 | 500 | \csitem{tracingpatches} 501 | 502 | Enables tracing for all patching commands, including \cmd{ifpatchable}. The debugging information will be written to the transcript file. This is useful if the reason why a patch is not applied or \cmd{ifpatchable} yields \prm{false} is not obvious. This command must be issued in the preamble. 503 | 504 | \end{ltxsyntax} 505 | 506 | \subsection{Boolean Flags} 507 | \label{aut:bol} 508 | 509 | This package provides two interfaces to boolean flags which are completely independent of each other. The tools in section \ref{aut:bo1:bol} are a \latex frontend to \cmd{newif}. Those in section \ref{aut:bo1:tgl} use a different mechanism. 510 | 511 | \subsubsection{\tex Flags} 512 | \label{aut:bo1:bol} 513 | 514 | Since the tools in this section are based on \cmd{newif} internally, they may be used to test and alter the state of flags previously defined with \cmd{newif}. They are also compatible with the boolean tests of the \sty{ifthen} package and may serve as a \latex interface for querying \tex primitives such as \cmd{ifmmode}. The \cmd{newif} approach requires a total of three macros per flag. 515 | 516 | \begin{ltxsyntax} 517 | 518 | \cmditem{newbool}{name} 519 | 520 | Defines a new boolean flag called \prm{name}. If the flag has already been defined, this command issues an error. The initial state of newly defined flags is \texttt{false}. This command is robust. 521 | 522 | \cmditem{providebool}{name} 523 | 524 | Defines a new boolean flag called \prm{name} unless it has already been defined. This command is robust. 525 | 526 | \cmditem{booltrue}{name} 527 | 528 | Sets the boolean flag \prm{name} to \texttt{true}. This command is robust and may be prefixed with \cs{global}. It will issue an error if the flag is undefined. 529 | 530 | \cmditem{boolfalse}{name} 531 | 532 | Sets the boolean flag \prm{name} to \texttt{false}. This command is robust and may be prefixed with \cs{global}. It will issue an error if the flag is undefined. 533 | 534 | \cmditem{setbool}{name}{value} 535 | 536 | Sets the boolean flag \prm{name} to \prm{value} which may be either \texttt{true} or \texttt{false}. This command is robust and may be prefixed with \cs{global}. It will issue an error if the flag is undefined. 537 | 538 | \cmditem{ifbool}{name}{true}{false} 539 | 540 | Expands to \prm{true} if the state of the boolean flag \prm{name} is \texttt{true}, and to \prm{false} otherwise. If the flag is undefined, this command issues an error. This command may be used to perform any boolean test based on plain \tex syntax, \ie any test normally employed like this: 541 | 542 | \begin{ltxcode} 543 | <<\iftest>> true<<\else>> false<<\fi>> 544 | \end{ltxcode} 545 | 546 | This includes all flags defined with \cmd{newif} as well as \tex primitives such as \cmd{ifmmode}. The \cmd{if} prefix is omitted when using the flag or the primitive in the expression. For example: 547 | 548 | \begin{ltxcode} 549 | <<\ifmytest>> true\else false\fi 550 | <<\ifmmode>> true\else false\fi 551 | \end{ltxcode} 552 | % 553 | becomes 554 | 555 | \begin{ltxcode} 556 | \ifbool{<>}{true}{false} 557 | \ifbool{<>}{true}{false} 558 | \end{ltxcode} 559 | 560 | \cmditem{notbool}{name}{not true}{not false} 561 | 562 | Similar to \cmd{ifbool} but negates the test. 563 | 564 | \end{ltxsyntax} 565 | 566 | \subsubsection{\latex Flags} 567 | \label{aut:bo1:tgl} 568 | 569 | In contrast to the flags from section \ref{aut:bo1:bol}, the tools in this section require only one macro per flag. They also use a separate namespace to avoid name clashes with regular macros. 570 | 571 | \begin{ltxsyntax} 572 | 573 | \cmditem{newtoggle}{name} 574 | 575 | Defines a new boolean flag called \prm{name}. If the flag has already been defined, this command issues an error. The initial state of newly defined flags is \texttt{false}. This command is robust. 576 | 577 | \cmditem{providetoggle}{name} 578 | 579 | Defines a new boolean flag called \prm{name} unless it has already been defined. This command is robust. 580 | 581 | \cmditem{toggletrue}{name} 582 | 583 | Sets the boolean flag \prm{name} to \texttt{true}. This command is robust and may be prefixed with \cs{global}. It will issue an error if the flag is undefined. 584 | 585 | \cmditem{togglefalse}{name} 586 | 587 | Sets the boolean flag \prm{name} to \texttt{false}. This command is robust and may be prefixed with \cs{global}. It will issue an error if the flag is undefined. 588 | 589 | \cmditem{settoggle}{name}{value} 590 | 591 | Sets the boolean flag \prm{name} to \prm{value} which may be either \texttt{true} or \texttt{false}. This command is robust and may be prefixed with \cs{global}. It will issue an error if the flag is undefined. 592 | 593 | \cmditem{iftoggle}{name}{true}{false} 594 | 595 | Expands to \prm{true} if the state of the boolean flag \prm{name} is \texttt{true}, and to \prm{false} otherwise. If the flag is undefined, this command issues an error. 596 | 597 | \cmditem{nottoggle}{name}{not true}{not false} 598 | 599 | Similar to \cmd{iftoggle} but negates the test. 600 | 601 | \end{ltxsyntax} 602 | 603 | \subsection{Generic Tests} 604 | \label{aut:tst} 605 | 606 | \subsubsection{Macro Tests} 607 | \label{aut:tst:def} 608 | 609 | \begin{ltxsyntax} 610 | 611 | \cmditem{ifdef}{control sequence}{true}{false} 612 | 613 | Expands to \prm{true} if the \prm{control sequence} is defined, and to \prm{false} otherwise. Note that control sequences will be considered as defined even if their meaning is \cmd{relax}. This command is a \latex wrapper for the \etex primitive \cmd{ifdefined}. 614 | 615 | \cmditem{ifcsdef}{csname}{true}{false} 616 | 617 | Similar to \cmd{ifdef} except that it takes a control sequence name as its first argument. This command is a \latex wrapper for the \etex primitive \cmd{ifcsname}. 618 | 619 | \cmditem{ifundef}{control sequence}{true}{false} 620 | 621 | Expands to \prm{true} if the \prm{control sequence} is undefined, and to \prm{false} otherwise. Apart from reversing the logic of the test, this command also differs from \cmd{ifdef} in that commands will be considered as undefined if their meaning is \cmd{relax}. 622 | 623 | \cmditem{ifcsundef}{csname}{true}{false} 624 | 625 | Similar to \cmd{ifundef} except that it takes a control sequence name as its first argument. This command may be used as a drop-in replacement for the \cmd{@ifundefined} test in the \latex kernel. 626 | 627 | \cmditem{ifdefmacro}{control sequence}{true}{false} 628 | 629 | Expands to \prm{true} if the \prm{control sequence} is defined and is a macro, and to \prm{false} otherwise. 630 | 631 | \cmditem{ifcsmacro}{csname}{true}{false} 632 | 633 | Similar to \cmd{ifdefmacro} except that it takes a control sequence name as its first argument. 634 | 635 | \cmditem{ifdefparam}{control sequence}{true}{false} 636 | 637 | Expands to \prm{true} if the \prm{control sequence} is defined and is a macro with one or more parameters, and to \prm{false} otherwise. 638 | 639 | \cmditem{ifcsparam}{csname}{true}{false} 640 | 641 | Similar to \cmd{ifdefparam} except that it takes a control sequence name as its first argument. 642 | 643 | \cmditem{ifdefprefix}{control sequence}{true}{false} 644 | 645 | Expands to \prm{true} if the \prm{control sequence} is defined and is a macro prefixed with \cs{long} and\slash or \cs{protected}, and to \prm{false} otherwise. Note that \cs{outer} macros may not be tested. 646 | 647 | \cmditem{ifcsprefix}{csname}{true}{false} 648 | 649 | Similar to \cmd{ifdefprefix} except that it takes a control sequence name as its first argument. 650 | 651 | \cmditem{ifdefprotected}{control sequence}{true}{false} 652 | 653 | Expands to \prm{true} if the \prm{control sequence} is defined and is a macro prefixed with \cs{protected}, and to \prm{false} otherwise. 654 | 655 | \cmditem{ifcsprotected}{csname}{true}{false} 656 | 657 | Similar to \cmd{ifdefprotected} except that it takes a control sequence name as its first argument. 658 | 659 | \cmditem{ifdefltxprotect}{control sequence}{true}{false} 660 | 661 | Executes \prm{true} if the \prm{control sequence} is defined and is a \latex protection shell, and \prm{false} otherwise. This command is robust. It will detect commands which have been defined with \cmd{DeclareRobustCommand} or by way of a similar technique. 662 | 663 | \cmditem{ifcsltxprotect}{csname}{true}{false} 664 | 665 | Similar to \cmd{ifdefltxprotect} except that it takes a control sequence name as its first argument. 666 | 667 | \cmditem{ifdefempty}{control sequence}{true}{false} 668 | 669 | Expands to \prm{true} if the \prm{control sequence} is defined and is a parameterless macro whose replacement text is empty, and to \prm{false} otherwise. In contrast to \cmd{ifx}, this test ignores the prefixes of the \prm{command}. 670 | 671 | \cmditem{ifcsempty}{csname}{true}{false} 672 | 673 | Similar to \cmd{ifdefempty} except that it takes a control sequence name as its first argument. 674 | 675 | \cmditem{ifdefvoid}{control sequence}{true}{false} 676 | 677 | Expands to \prm{true} if the \prm{control sequence} is undefined, or is a control sequence whose meaning is \cmd{relax}, or is a parameterless macro whose replacement text is empty, and to \prm{false} otherwise. 678 | 679 | \cmditem{ifcsvoid}{csname}{true}{false} 680 | 681 | Similar to \cmd{ifdefvoid} except that it takes a control sequence name as its first argument. 682 | 683 | \cmditem{ifdefequal}{control sequence}{control sequence}{true}{false} 684 | 685 | Compares two control sequences and expands to \prm{true} if they are equal in the sense of \cmd{ifx}, and to \prm{false} otherwise. In contrast to \cmd{ifx}, this test will also yield \prm{false} if both control sequences are undefined or have a meaning of \cmd{relax}. 686 | 687 | \cmditem{ifcsequal}{csname}{csname}{true}{false} 688 | 689 | Similar to \cmd{ifdefequal} except that it takes control sequence names as arguments. 690 | 691 | \cmditem{ifdefstring}{command}{string}{true}{false} 692 | 693 | Compares the replacement text of a \prm{command} to a \prm{string} and executes \prm{true} if they are equal, and \prm{false} otherwise. Neither the \prm{command} nor the \prm{string} is expanded in the test and the comparison is category code agnostic. Control sequence tokens in the \prm{string} argument will be detokenized and treated as strings. This command is robust. Note that it will only consider the replacement text of the \prm{command}. For example, this test 694 | 695 | \begin{ltxcode} 696 | \long\edef\mymacro#1#2{\string&} 697 | \ifdefstring{\mymacro}{&}{true}{false} 698 | \end{ltxcode} 699 | % 700 | would yield \prm{true}. The prefix and the parameters of \cmd{mymacro} as well as the category codes in the replacement text are ignored. 701 | 702 | \cmditem{ifcsstring}{csname}{string}{true}{false} 703 | 704 | Similar to \cmd{ifdefstring} except that it takes a control sequence name as its first argument. 705 | 706 | \cmditem{ifdefstrequal}{command}{command}{true}{false} 707 | 708 | Performs a category code agnostic string comparison of the replacement text of two commands. This command is similar to \cmd{ifdefstring} except that both arguments to be compared are macros. This command is robust. 709 | 710 | \cmditem{ifcsstrequal}{csname}{csname}{true}{false} 711 | 712 | Similar to \cmd{ifdefstrequal} except that it takes control sequence names as arguments. 713 | 714 | \end{ltxsyntax} 715 | 716 | \subsubsection{Counter and Length Tests} 717 | \label{aut:tst:cnt} 718 | 719 | \begin{ltxsyntax} 720 | 721 | \cmditem{ifdefcounter}{control sequence}{true}{false} 722 | 723 | Expands to \prm{true} if the \prm{control sequence} is a \tex \cmd{count} register allocated with \cmd{newcount}, and to \prm{false} otherwise. 724 | 725 | \cmditem{ifcscounter}{csname}{true}{false} 726 | 727 | Similar to \cmd{ifdefcounter} except that it takes a control sequence name as its first argument. 728 | 729 | \cmditem{ifltxcounter}{name}{true}{false} 730 | 731 | Expands to \prm{true} if \prm{name} is a \latex counter allocated with \cmd{newcounter}, and to \prm{false} otherwise. 732 | 733 | \cmditem{ifdeflength}{control sequence}{true}{false} 734 | 735 | Expands to \prm{true} if the \prm{control sequence} is a \tex \cmd{skip} register allocated with \cmd{newskip} or \cmd{newlength}, and to \prm{false} otherwise. 736 | 737 | \cmditem{ifcslength}{csname}{true}{false} 738 | 739 | Similar to \cmd{ifdeflength} except that it takes a control sequence name as its first argument. 740 | 741 | \cmditem{ifdefdimen}{control sequence}{true}{false} 742 | 743 | Expands to \prm{true} if the \prm{control sequence} is a \tex \cmd{dimen} register allocated with \cmd{newdimen}, and to \prm{false} otherwise. 744 | 745 | \cmditem{ifcsdimen}{csname}{true}{false} 746 | 747 | Similar to \cmd{ifdefdimen} except that it takes a control sequence name as its first argument. 748 | 749 | \end{ltxsyntax} 750 | 751 | \subsubsection{String Tests} 752 | \label{aut:tst:str} 753 | 754 | \begin{ltxsyntax} 755 | 756 | \cmditem{ifstrequal}{string}{string}{true}{false} 757 | 758 | Compares two strings and executes \prm{true} if they are equal, and \prm{false} otherwise. The strings are not expanded in the test and the comparison is category code agnostic. Control sequence tokens in any of the \prm{string} arguments will be detokenized and treated as strings. This command is robust. 759 | 760 | \cmditem{ifstrempty}{string}{true}{false} 761 | 762 | Expands to \prm{true} if the \prm{string} is empty, and to \prm{false} otherwise. The \prm{string} is not expanded in the test. 763 | 764 | \cmditem{ifblank}{string}{true}{false} 765 | 766 | Expands to \prm{true} if the \prm{string} is blank (empty or spaces), and to \prm{false} otherwise. The \prm{string} is not expanded in the test. 767 | 768 | \cmditem{notblank}{string}{not true}{not false} 769 | 770 | Similar to \cmd{ifblank} but negates the test. 771 | 772 | \end{ltxsyntax} 773 | 774 | \subsubsection{Arithmetic Tests} 775 | \label{aut:tst:num} 776 | 777 | \begin{ltxsyntax} 778 | 779 | \cmditem{ifnumcomp}{integer expression}{relation}{integer expression}{true}{false} 780 | 781 | Compares two integer expressions according to \prm{relation} and expands to \prm{true} or \prm{false} depending on the result. The \prm{relation} may be |<|, |>|, or |=|. Both integer expressions will be processed with \cmd{numexpr}. An \prm{integer expression} may be any arbitrary code which is valid in this context. All arithmetic expressions may contain spaces. Here are some examples: 782 | 783 | \begin{ltxcode} 784 | \ifnumcomp{<<3>>}{<<>>>}{<<6>>}{true}{<>} 785 | \ifnumcomp{<<(7 + 5) / 2>>}{<<=>>}{<<6>>}{<>}{false} 786 | \ifnumcomp{<<(7+5) / 4>>}{<<>>>}{<<3*(12-10)>>}{true}{<>} 787 | \newcounter{countA} 788 | \setcounter{countA}{<<6>>} 789 | \newcounter{countB} 790 | \setcounter{countB}{<<5>>} 791 | \ifnumcomp{<<\value{countA} * \value{countB}/2}>>{<<=>>}{<<15>>}{<>}{false} 792 | \ifnumcomp{<<6/2>>}{<<=>>}{<<5/2>>}{<>}{false} 793 | \end{ltxcode} 794 | % 795 | Technically, this command is a \latex wrapper for the \tex primitive \cmd{ifnum}, incorporating \cmd{numexpr}. Note that \cmd{numexpr} will round the result of all integer expressions, \ie both expressions will be processed and rounded prior to being compared. In the last line of the above examples, the result of the second expression is 2.5, which is rounded to 3, hence \cmd{ifnumcomp} will expand to \prm{true}. 796 | 797 | \cmditem{ifnumequal}{integer expression}{integer expression}{true}{false} 798 | 799 | Alternative syntax for |\ifnumcomp{...}{=}{...}{...}{...}|. 800 | 801 | \cmditem{ifnumgreater}{integer expression}{integer expression}{true}{false} 802 | 803 | Alternative syntax for |\ifnumcomp{...}{>}{...}{...}{...}|. 804 | 805 | \cmditem{ifnumless}{integer expression}{integer expression}{true}{false} 806 | 807 | Alternative syntax for |\ifnumcomp{...}{<}{...}{...}{...}|. 808 | 809 | \cmditem{ifnumodd}{integer expression}{true}{false} 810 | 811 | Evaluates an integer expression and expands to \prm{true} if the result is an odd number, and to \prm{false} otherwise. Technically, this command is a \latex wrapper for the \tex primitive \cmd{ifodd}, incorporating \cmd{numexpr}. 812 | 813 | \cmditem{ifdimcomp}{dimen expression}{relation}{dimen expression}{true}{false} 814 | 815 | Compares two dimen expressions according to \prm{relation} and expands to \prm{true} or \prm{false} depending on the result. The \prm{relation} may be |<|, |>|, or |=|. Both dimen expressions will be processed with \cmd{dimexpr}. A \prm{dimen expression} may be any arbitrary code which is valid in this context. All arithmetic expressions may contain spaces. Here are some examples: 816 | 817 | \begin{ltxcode} 818 | \ifdimcomp{<<1cm>>}{<<=>>}{<<28.45274pt>>}{<>}{false} 819 | \ifdimcomp{<<(7pt + 5pt) / 2>>}{<<<>>}{2pt}{true}{<>} 820 | \ifdimcomp{<<(3.725pt + 0.025pt) * 2>>}{<<<>>}{<<7pt>>}{true}{<>} 821 | \newlength{\lengthA} 822 | \setlength{\lengthA}{<<7.25pt>>} 823 | \newlength{\lengthB} 824 | \setlength{\lengthB}{<<4.75pt>>} 825 | \ifdimcomp{<<(\lengthA + \lengthB) / 2>>}{<<>>>}{<<2.75pt * 2>>}{<>}{false} 826 | \ifdimcomp{<<(\lengthA + \lengthB) / 2>>}{<<>>>}{<<25pt / 6>>}{<>}{false} 827 | \end{ltxcode} 828 | % 829 | Technically, this command is a \latex wrapper for the \tex primitive \cmd{ifdim}, incorporating \cmd{dimexpr}. Since both \cmd{ifdimcomp} and \cmd{ifnumcomp} are expandable, they may also be nested: 830 | 831 | \begin{ltxcode} 832 | <<\ifnumcomp>>{<<\ifdimcomp>>{<<5pt+5pt>>}{<<=>>}{<<10pt>>}{<<1>>}{<<0>>}}{<<>>>}{<<0>>}{<>}{false} 833 | \end{ltxcode} 834 | 835 | \cmditem{ifdimequal}{dimen expression}{dimen expression}{true}{false} 836 | 837 | Alternative syntax for |\ifdimcomp{...}{=}{...}{...}{...}|. 838 | 839 | \cmditem{ifdimgreater}{dimen expression}{dimen expression}{true}{false} 840 | 841 | Alternative syntax for |\ifdimcomp{...}{>}{...}{...}{...}|. 842 | 843 | \cmditem{ifdimless}{dimen expression}{dimen expression}{true}{false} 844 | 845 | Alternative syntax for |\ifdimcomp{...}{<}{...}{...}{...}|. 846 | 847 | \end{ltxsyntax} 848 | 849 | \subsubsection{Boolean Expressions} 850 | \label{aut:tst:bol} 851 | 852 | The commands in this section are replacements for the \cmd{ifthenelse} command provided by the \sty{ifthen} package. They serve the same purpose but differ in syntax, concept, and implementation. In contrast to \cmd{ifthenelse}, they do not provide any tests of their own but serve as a frontend to other tests. Any test which satisfies certain syntactical requirements may be used in a boolean expression. 853 | 854 | \begin{ltxsyntax} 855 | 856 | \cmditem{ifboolexpr}{expression}{true}{false} 857 | 858 | Evaluates the \prm{expression} and executes \prm{true} if it is true, and \prm{false} otherwise. The \prm{expression} is evaluated sequentially from left to right. The following elements, discussed in more detail below, are available in the \prm{expression}: the test operators \texttt{togl}, \texttt{bool}, \texttt{test}; the logical operators \texttt{not}, \texttt{and}, \texttt{or}; and the subexpression delimiter \texttt{(...)}. Spaces, tabs, and line endings may be used freely to arrange the \prm{expression} visually. Blank lines are not permissible in the \prm{expression}. This command is robust. 859 | 860 | \cmditem{ifboolexpe}{expression}{true}{false} 861 | 862 | An expandable version of \cmd{ifboolexpr} which may be processed in an expansion-only context, \eg in an \cmd{edef} or in a \cmd{write} operation. Note that all tests used in the \prm{expression} must be expandable, even if \cmd{ifboolexpe} is not located in an expansion-only context. 863 | 864 | \cmditem{whileboolexpr}{expression}{code} 865 | 866 | Evaluates the \prm{expression} like \cmd{ifboolexpr} and repeatedly executes the \prm{code} while the expression is true. The \prm{code} may be any valid \tex or \latex code. This command is robust. 867 | 868 | \cmditem{unlessboolexpr}{expression}{code} 869 | 870 | Similar to \cmd{whileboolexpr} but negates the \prm{expression}, \ie it keeps executing the \prm{code} repeatedly unless the expression is true. This command is robust. 871 | 872 | \end{ltxsyntax} 873 | % 874 | The following test operators are available in the \prm{expression}: 875 | 876 | \begin{marglist} 877 | \appto\marglistfont{\verbatimfont} 878 | 879 | \item[togl] 880 | 881 | Use the \texttt{togl} operator to test the state of a flag defined with \cmd{newtoggle}. For example: 882 | 883 | \begin{ltxcode} 884 | <<\iftoggle{mytoggle}>>{true}{false} 885 | \end{ltxcode} 886 | % 887 | becomes 888 | 889 | \begin{ltxcode} 890 | \ifboolexpr{ <> {<>} }{true}{false} 891 | \end{ltxcode} 892 | % 893 | The \texttt{togl} operator may be used with both \cmd{ifboolexpr} and \cmd{ifboolexpe}. 894 | 895 | \item[bool] 896 | 897 | Use the \texttt{bool} operator to perform a boolean test based on plain \tex syntax, \ie any test normally employed like this: 898 | 899 | \begin{ltxcode} 900 | <<\iftest>> true<<\else>> false<<\fi>> 901 | \end{ltxcode} 902 | % 903 | This includes all flags defined with \cmd{newif} as well as \tex primitives such as \cmd{ifmmode}. The \cmd{if} prefix is omitted when using the flag or the primitive in the expression. For example: 904 | 905 | \begin{ltxcode} 906 | <<\ifmmode>> true\else false\fi 907 | <<\ifmytest>> true\else false\fi 908 | \end{ltxcode} 909 | % 910 | becomes 911 | 912 | \begin{ltxcode} 913 | \ifboolexpr{ <> {<>} }{true}{false} 914 | \ifboolexpr{ <> {<>} }{true}{false} 915 | \end{ltxcode} 916 | % 917 | This also works with flags defined with \cmd{newbool} (see \secref{aut:bo1:bol}). In this case 918 | 919 | \begin{ltxcode} 920 | <<\ifbool{mybool}>>{true}{false} 921 | \end{ltxcode} 922 | % 923 | becomes 924 | 925 | \begin{ltxcode} 926 | \ifboolexpr{ <> {<>} }{true}{false} 927 | \end{ltxcode} 928 | % 929 | The \texttt{bool} operator may be used with both \cmd{ifboolexpr} and \cmd{ifboolexpe}. 930 | 931 | \item[test] 932 | 933 | Use the \texttt{test} operator to perform a test based on \latex syntax, \ie any test normally employed like this: 934 | 935 | \begin{ltxcode} 936 | <<\iftest>>{<>}{<>} 937 | \end{ltxcode} 938 | % 939 | This applies to all macros based on \latex syntax, \ie the macro must take a \prm{true} and a \prm{false} argument and these must be the final arguments. For example: 940 | 941 | \begin{ltxcode} 942 | <<\ifdef>>{\somemacro}<<{true}{false}>> 943 | <<\ifdimless>>{\textwidth}{365pt}<<{true}{false}>> 944 | <<\ifnumcomp>>{\value{somecounter}}{>}{3}<<{true}{false}>> 945 | \end{ltxcode} 946 | 947 | When using such tests in the \prm{expression}, their \prm{true} and \prm{false} arguments are omitted. For example: 948 | 949 | \begin{ltxcode} 950 | <<\ifcsdef{mymacro}>>{true}{false} 951 | \end{ltxcode} 952 | % 953 | becomes 954 | 955 | \begin{ltxcode} 956 | \ifboolexpr{ <> {<<\ifcsdef{mymacro}>>} }{true}{false} 957 | \end{ltxcode} 958 | % 959 | and 960 | 961 | \begin{ltxcode} 962 | <<\ifnumcomp{\value{mycounter}}{>}{3}>>{true}{false} 963 | \end{ltxcode} 964 | % 965 | becomes 966 | 967 | \begin{ltxcode} 968 | \ifboolexpr{ 969 | <> {<<\ifnumcomp{\value{mycounter}}{>}{3}>>} 970 | } 971 | {true} 972 | {false} 973 | \end{ltxcode} 974 | % 975 | The \texttt{test} operator may be used with \cmd{ifboolexpr} without any restrictions. It may also be used with \cmd{ifboolexpe}, provided that the test is expandable. Some of the generic tests in \secref{aut:tst} are robust and may not be used with \cmd{ifboolexpe}, even if \cmd{ifboolexpe} is not located in an expansion-only context. Use \cmd{ifboolexpr} instead if the test is not expandable. 976 | 977 | \end{marglist} 978 | 979 | Since \cmd{ifboolexpr} and \cmd{ifboolexpe} imply processing overhead, there is generally no benefit in employing them for a single test. The stand-alone tests in \secref{aut:tst} are more efficient than \texttt{test}, \cmd{ifbool} from \secref{aut:bo1:bol} is more efficient than \texttt{bool}, and \cmd{iftoggle} from \secref{aut:bo1:tgl} is more efficient than \texttt{togl}. The point of \cmd{ifboolexpr} and \cmd{ifboolexpe} is that they support logical operators and subexpressions. The following logical operators are available in the \prm{expression}: 980 | 981 | \begin{marglist} 982 | \appto\marglistfont{\verbatimfont} 983 | 984 | \item[not] 985 | 986 | The \texttt{not} operator negates the truth value of the immediately following element. You may prefix \texttt{togl}, \texttt{bool}, \texttt{test}, and subexpressions with \texttt{not}. For example: 987 | 988 | \begin{ltxcode} 989 | \ifboolexpr{ 990 | <> bool {mybool} 991 | } 992 | {true} 993 | {false} 994 | \end{ltxcode} 995 | % 996 | will yield \prm{true} if \texttt{mybool} is false and \prm{false} if \texttt{mybool} is true, and 997 | 998 | \begin{ltxcode} 999 | \ifboolexpr{ 1000 | <> bool {boolA} or bool {boolB} <<)>> 1001 | } 1002 | {true} 1003 | {false} 1004 | \end{ltxcode} 1005 | % 1006 | will yield \prm{true} if both \texttt{boolA} and \texttt{boolB} are false. 1007 | 1008 | \item[and] 1009 | 1010 | The \texttt{and} operator expresses a conjunction (both \emph{a} and \emph{b}). The \prm{expression} is true if all elements joined with \texttt{and} are true. For example: 1011 | 1012 | \begin{ltxcode} 1013 | \ifboolexpr{ 1014 | bool {boolA} <> bool {boolB} 1015 | } 1016 | {true} 1017 | {false} 1018 | \end{ltxcode} 1019 | % 1020 | will yield \prm{true} if both \texttt{bool} tests are true. The \texttt{nand} operator (negated \texttt{and}, \ie not both) is not provided as such but may be expressed by using \texttt{and} in a negated subexpression. For example: 1021 | 1022 | \begin{ltxcode} 1023 | bool {boolA} <> bool {boolB} 1024 | \end{ltxcode} 1025 | % 1026 | may be written as 1027 | 1028 | \begin{ltxcode} 1029 | <> <<(>> bool {boolA} <> bool {boolB} <<)>> 1030 | \end{ltxcode} 1031 | 1032 | \item[or] 1033 | 1034 | The \texttt{or} operator expresses a non-exclusive disjunction (either \emph{a} or \emph{b} or both). The \prm{expression} is true if at least one of the elements joined with \texttt{or} is true. For example: 1035 | 1036 | \begin{ltxcode} 1037 | \ifboolexpr{ 1038 | togl {toglA} <> togl {toglB} 1039 | } 1040 | {true} 1041 | {false} 1042 | \end{ltxcode} 1043 | % 1044 | will yield \prm{true} if either \texttt{togl} test or both tests are true. The \texttt{nor} operator (negated non-exclusive disjunction, \ie neither \emph{a} nor \emph{b} nor both) is not provided as such but may be expressed by using \texttt{or} in a negated subexpression. For example: 1045 | 1046 | \begin{ltxcode} 1047 | bool {boolA} <> bool {boolB} 1048 | \end{ltxcode} 1049 | % 1050 | may be written as 1051 | 1052 | \begin{ltxcode} 1053 | <> <<(>> bool {boolA} <> bool {boolB} <<)>> 1054 | \end{ltxcode} 1055 | 1056 | \item[(...)] 1057 | 1058 | The parentheses delimit a subexpression in the \prm{expression}. The subexpression is evaluated and the result of this evaluation is treated as a single truth value in the enclosing expression. Subexpressions may be nested. For example, the expression: 1059 | 1060 | \begin{ltxcode} 1061 | <<(>> bool {boolA} or bool {boolB} <<)>> 1062 | and 1063 | <<(>> bool {boolC} or bool {boolD} <<)>> 1064 | \end{ltxcode} 1065 | % 1066 | is true if both subexpressions are true, \ie if at least one of \texttt{boolA}/\texttt{boolB} and at least one of \texttt{boolC}/\texttt{boolD} is true. Subexpressions are generally not required if all elements are joined with \texttt{and} or with \texttt{or}. For example, the expressions 1067 | 1068 | \begin{ltxcode} 1069 | bool {boolA} <> bool {boolB} <> {boolC} <> bool {boolD} 1070 | bool {boolA} <> bool {boolB} <> {boolC} <> bool {boolD} 1071 | \end{ltxcode} 1072 | % 1073 | will yield the expected results: the first one is true if all elements are true; the second one is true if at least one element is true. However, when combining \texttt{and} and \texttt{or}, it is advisable to always group the elements in subexpressions in order to avoid potential misconceptions which may arise from differences between the semantics of formal boolean expressions and the semantics of natural languages. For example, the following expression 1074 | 1075 | \begin{ltxcode} 1076 | bool {<>} <> bool {<>} <> bool {<>} 1077 | \end{ltxcode} 1078 | % 1079 | is always true if \texttt{sugar} is true since the \texttt{or} operator will take the result of the \texttt{and} evaluation as input. In contrast to the meaning of this expression when pronounced in English, it is not processed like this 1080 | 1081 | \begin{ltxcode} 1082 | bool {<>} <> <<(>> bool {<>} <> bool {<>} <<)>> 1083 | \end{ltxcode} 1084 | % 1085 | but evaluated strictly from left to right: 1086 | 1087 | \begin{ltxcode} 1088 | <<(>> bool {<>} <> bool {<>} <<)>> <> bool {<>} 1089 | \end{ltxcode} 1090 | % 1091 | which is probably not what you meant to order. 1092 | 1093 | \end{marglist} 1094 | 1095 | \subsection{List Processing} 1096 | \label{aut:lst} 1097 | 1098 | \subsubsection{User Input} 1099 | \label{aut:lst:inp} 1100 | 1101 | The tools in this section are primarily designed to handle user input. When building lists for internal use by a package, using the tools in section \ref{aut:lst:int} may be preferable as they allow testing if an element is in a list. 1102 | 1103 | \begin{ltxsyntax} 1104 | 1105 | \cmditem{DeclareListParser}{command}{separator} 1106 | 1107 | This command defines a list parser similar to the \cmd{docsvlist} command below, which is defined like this: 1108 | 1109 | \begin{ltxcode} 1110 | \DeclareListParser{\docsvlist}{,} 1111 | \end{ltxcode} 1112 | % 1113 | Note that the list parsers are sensitive to the category code of the \prm{separator}. 1114 | 1115 | \cmditem*{DeclareListParser*}{command}{separator} 1116 | 1117 | The starred variant of \cmd{DeclareListParser} defines a list parser similar to the \cmd{forcsvlist} command below, which is defined like this: 1118 | 1119 | \begin{ltxcode} 1120 | \DeclareListParser*{\forcsvlist}{,} 1121 | \end{ltxcode} 1122 | 1123 | \cmditem{docsvlist}{item, item, ...} 1124 | 1125 | This command loops over a comma"=separated list of items and executes the auxiliary command \cmd{do} for every item in the list, passing the item as an argument. In contrast to the \cmd{@for} loop in the \latex kernel, \cmd{docsvlist} is expandable. With a suitable definition of \cmd{do}, lists may be processed in an \cmd{edef} or a comparable context. You may use \cmd{listbreak} at the end of the replacement text of \cmd{do} to stop processing and discard the remaining items in the list. Whitespace after list separators is ignored. If an item contains a comma or starts with a space, it must be wrapped in curly braces. The braces will be removed as the list is processed. Here is a usage example which prints a comma"=separated list as an \env{itemize} environment: 1126 | 1127 | \begin{ltxcode} 1128 | \begin{itemize} 1129 | \renewcommand*{\do}[1]{\item #1} 1130 | \docsvlist{item1, item2, {item3a, item3b}, item4} 1131 | \end{itemize} 1132 | \end{ltxcode} 1133 | % 1134 | Here is another example: 1135 | 1136 | \begin{ltxcode} 1137 | \renewcommand*{\do}[1]{* #1\MessageBreak} 1138 | \PackageInfo{mypackage}{% 1139 | Example list:\MessageBreak 1140 | \docsvlist{item1, item2, {item3a, item3b}, item4}} 1141 | \end{ltxcode} 1142 | % 1143 | In this example, the list is written to the log file as part of an informational message. The list processing takes place during the \cmd{write} operation. 1144 | 1145 | \cmditem{forcsvlist}{handler}{item, item, ...} 1146 | 1147 | This command is similar to \cmd{docsvlist} except that \cmd{do} is replaced by a \prm{handler} specified at invocation time. The \prm{handler} may also be a sequence of commands, provided that the command given last takes the item as trailing argument. For example, the following code will convert a comma"=separated list of items into an internal list called \cmd{mylist}: 1148 | 1149 | \begin{ltxcode} 1150 | \forcsvlist{\listadd\mylist}{item1, item2, item3} 1151 | \end{ltxcode} 1152 | 1153 | \end{ltxsyntax} 1154 | 1155 | \subsubsection{Internal Lists} 1156 | \label{aut:lst:int} 1157 | 1158 | The tools in this section handle internal lists of data. An in this context is a plain macro without any parameters and prefixes which is employed to collect data. These lists use a special character as internal list separator.\footnote{The character \texttt{\string|} with category code 3. Note that you may not typeset a list by saying \cmd{listname}. Use \cmd{show} instead to inspect the list.} When processing user input in list format, see the tools in section \ref{aut:lst:inp}. 1159 | 1160 | \begin{ltxsyntax} 1161 | 1162 | \cmditem{listadd}{listmacro}{item} 1163 | 1164 | This command appends an \prm{item} to a \prm{listmacro}. A blank \prm{item} is not added to the list. 1165 | 1166 | \cmditem{listgadd}{listmacro}{item} 1167 | 1168 | Similar to \cmd{listadd} except that the assignment is global. 1169 | 1170 | \cmditem{listeadd}{listmacro}{item} 1171 | 1172 | Similar to \cmd{listadd} except that the \prm{item} is expanded at definition"=time. Only the new \prm{item} is expanded, the \prm{listmacro} is not. If the expanded \prm{item} is blank, it is not added to the list. 1173 | 1174 | \cmditem{listxadd}{listmacro}{item} 1175 | 1176 | Similar to \cmd{listeadd} except that the assignment is global. 1177 | 1178 | \cmditem{listcsadd}{listcsname}{item} 1179 | 1180 | Similar to \cmd{listadd} except that it takes a control sequence name as its first argument. 1181 | 1182 | \cmditem{listcsgadd}{listcsname}{item} 1183 | 1184 | Similar to \cmd{listcsadd} except that the assignment is global. 1185 | 1186 | \cmditem{listcseadd}{listcsname}{item} 1187 | 1188 | Similar to \cmd{listeadd} except that it takes a control sequence name as its first argument. 1189 | 1190 | \cmditem{listcsxadd}{listcsname}{item} 1191 | 1192 | Similar to \cmd{listcseadd} except that the assignment is global. 1193 | 1194 | \cmditem{listremove}{listmacro}{item} 1195 | 1196 | This command removes an \prm{item} from a \prm{listmacro}. A blank \prm{item} is ignored. 1197 | 1198 | \cmditem{listgremove}{listmacro}{item} 1199 | 1200 | Similar to \cmd{listremove} except that the assignment is global. 1201 | 1202 | \cmditem{listcsremove}{listcsname}{item} 1203 | 1204 | Similar to \cmd{listremove} except that it takes a control sequence name as its first argument. 1205 | 1206 | \cmditem{listcsgremove}{listcsname}{item} 1207 | 1208 | Similar to \cmd{listcsremove} except that the assignment is global. 1209 | 1210 | \cmditem{dolistloop}{listmacro} 1211 | 1212 | This command loops over all items in a \prm{listmacro} and executes the auxiliary command \cmd{do} for every item in the list, passing the item as an argument. The list loop itself is expandable. You may use \cmd{listbreak} at the end of the replacement text of \cmd{do} to stop processing and discard the remaining items in the list. Here is a usage example which prints an internal list called \cmd{mylist} as an \env{itemize} environment: 1213 | 1214 | \begin{ltxcode} 1215 | \begin{itemize} 1216 | \renewcommand*{\do}[1]{\item #1} 1217 | \dolistloop{\mylist} 1218 | \end{itemize} 1219 | \end{ltxcode} 1220 | 1221 | \cmditem{dolistcsloop}{listcsname} 1222 | 1223 | Similar to \cmd{dolistloop} except that it takes a control sequence name as its argument. 1224 | 1225 | \cmditem{forlistloop}{handler}{listmacro} 1226 | 1227 | This command is similar to \cmd{dolistloop} except that \cmd{do} is replaced by a \prm{handler} specified at invocation time. The \prm{handler} may also be a sequence of commands, provided that the command given last takes the item as trailing argument. For example, the following code will prefix all items in the internal list \cmd{mylist} with \cmd{item}, count the items as the list is processed, and append the item count at the end: 1228 | 1229 | \begin{ltxcode} 1230 | \newcounter{itemcount} 1231 | \begin{itemize} 1232 | \forlistloop{\stepcounter{itemcount}\item}{\mylist} 1233 | \item Total: \number\value{itemcount} items 1234 | \end{itemize} 1235 | \end{ltxcode} 1236 | 1237 | \cmditem{forlistcsloop}{handler}{listcsname} 1238 | 1239 | Similar to \cmd{forlistloop} except that it takes a control sequence name as its second argument. 1240 | 1241 | \cmditem{ifinlist}{item}{listmacro}{true}{false} 1242 | 1243 | This command executes \prm{true} if the \prm{item} is included in a \prm{listmacro}, and \prm{false} otherwise. Note that this test uses pattern matching based on \tex's argument scanner to check if the search string is included in the list. This means that it is usually faster than looping over all items in the list, but it also implies that the items must not include curly braces which would effectively hide them from the scanner. In other words, this macro is most useful when dealing with lists of plain strings rather than printable data. When dealing with printable text, it is safer to use \cmd{dolistloop} to check if an item is in the list as follows: 1244 | 1245 | \begin{ltxcode} 1246 | \renewcommand*{\do}[1]{% 1247 | \ifstrequal{#1}{<>} 1248 | {item found!\listbreak} 1249 | {}} 1250 | \dolistloop{\mylist} 1251 | \end{ltxcode} 1252 | 1253 | \cmditem{xifinlist}{item}{listmacro}{true}{false} 1254 | 1255 | Similar to \cmd{ifinlist} except that the \prm{item} is expanded prior to the test. 1256 | 1257 | \cmditem{ifinlistcs}{item}{listcsname}{true}{false} 1258 | 1259 | Similar to \cmd{ifinlist} except that it takes a control sequence name as its second argument. 1260 | 1261 | \cmditem{xifinlistcs}{item}{listcsname}{true}{false} 1262 | 1263 | Similar to \cmd{xifinlist} except that it takes a control sequence name as its second argument. 1264 | 1265 | \end{ltxsyntax} 1266 | 1267 | \subsection{Miscellaneous Tools} 1268 | \label{aut:msc} 1269 | 1270 | \begin{ltxsyntax} 1271 | 1272 | \cmditem{rmntonum}{numeral} 1273 | 1274 | The \tex primitive \cmd{romannumeral} converts an integer to a Roman numeral but \tex or \latex provide no command which goes the opposite way. \cmd{rmntonum} fills this gap. It takes a Roman numeral as its argument and converts it to the corresponding integer. Since it is expandable, it may also be used in counter assignments or arithmetic tests: 1275 | 1276 | \begin{ltxcode} 1277 | <<\rmntonum>>{<>} 1278 | \setcounter{counter}{<<\rmntonum>>{<>}} 1279 | \ifnumless{<<\rmntonum>>{<>}}{2000}{true}{false} 1280 | \end{ltxcode} 1281 | % 1282 | The \prm{numeral} argument must be a literal string. It will be detokenized prior to parsing. The parsing of the numeral is case"=insensitive and whitespace in the argument is ignored. If there is an invalid token in the argument, \cmd{rmntonum} will expand to~\texttt{-1}; an empty argument will yield an empty string. Note that \cmd{rmntonum} will not check the numeral for formal validity. For example, both \texttt{V} and \texttt{VX} would yield \texttt{5}, \texttt{IC} would yield \texttt{99}, etc. 1283 | 1284 | \cmditem{ifrmnum}{string}{true}{false} 1285 | 1286 | Expands to \prm{true} if \prm{string} is a Roman numeral, and to \prm{false} otherwise. The \prm{string} will be detokenized prior to performing the test. The test is case"=insensitive and ignores whitespace in the \prm{string}. Note that \cmd{ifrmnum} will not check the numeral for formal validity. For example, both \texttt{V} and \texttt{VXV} will yield \prm{true}. Strictly speaking, what \cmd{ifrmnum} does is parse the \prm{string} in order to find out if it consists of characters which may form a valid Roman numeral, but it will not check if they really are a valid Roman numeral. 1287 | 1288 | \end{ltxsyntax} 1289 | 1290 | \section{Reporting issues} 1291 | 1292 | The development code for \sty{etoolbox} is hosted on GitHub: \url{https://github.com/josephwright/etoolbox}. This is the best place to log any issues with the package. 1293 | 1294 | \section{Revision History} 1295 | 1296 | This revision history is a list of changes relevant to users of this package. Changes of a more technical nature which do not affect the user interface or the behavior of the package are not included in the list. If an entry in the revision history states that a feature has been \emph{improved} or \emph{extended}, this indicates a syntactically backwards compatible modification, such as the addition of an optional argument to an existing command. Entries stating that a feature has been \emph{modified} demand attention. They indicate a modification which may require changes to existing documents in some, hopefully rare, cases. The numbers on the right indicate the relevant section of this manual. 1297 | 1298 | \begin{changelog} 1299 | 1300 | \begin{release}{2.5l}{2025-02-11} 1301 | \item Fix handling of \cmd{long} macros linked to \cmd{NewCommandCopy} 1302 | \end{release} 1303 | 1304 | \begin{release}{2.5k}{2020-10-05} 1305 | \item Internal updates 1306 | \end{release} 1307 | 1308 | \begin{release}{2.5j}{2020-08-24} 1309 | \item Track \LaTeXe{} kernel changes 1310 | \end{release} 1311 | 1312 | \begin{release}{2.5i}{2020-07-13} 1313 | \item Track \LaTeXe{} kernel changes 1314 | \end{release} 1315 | 1316 | \begin{release}{2.5h}{2019-09-21} 1317 | \item Add missing \cmd{gundef} 1318 | \end{release} 1319 | 1320 | \begin{release}{2.5g}{2019-09-09} 1321 | \item Update patching of \cmd{begin} and \cmd{end} in advance of \LaTeX{} 1322 | kernel changes 1323 | \end{release} 1324 | 1325 | \begin{release}{2.5f}{2018-08-18} 1326 | \item Fix issue with \cmd{ifdefempty}, \cmd{ifcsempty}, \cs{ifdefvoid} 1327 | and \cmd{ifcsvoid} when applied to macros expanding to space tokens 1328 | \end{release} 1329 | 1330 | \begin{release}{2.5e}{2018-02-11} 1331 | \item More work on empty list separator in \cmd{DeclareListParser} 1332 | \end{release} 1333 | 1334 | \begin{release}{2.5d}{2018-02-10} 1335 | \item Allow for empty list separator in \cmd{DeclareListParser} 1336 | \end{release} 1337 | 1338 | \begin{release}{2.5c}{2018-02-06} 1339 | \item Fix issue with \cmd{forcsvlist} introduced by v2.5b 1340 | \end{release} 1341 | 1342 | \begin{release}{2.5b}{2018-02-04} 1343 | \item Preserve braces in some internal steps 1344 | \item Internal performance improvements in list processors 1345 | \end{release} 1346 | 1347 | \begin{release}{2.5a}{2018-02-03} 1348 | \item Internal performance improvements in list processors 1349 | \end{release} 1350 | 1351 | \begin{release}{2.5}{2017-11-22} 1352 | \item Added \cmd{csgundef}\see{aut:def:def} 1353 | \item Added \cmd{gundef}\see{aut:def:def} 1354 | \item Allow scanning of macros containing new line characters 1355 | \end{release} 1356 | 1357 | \begin{release}{2.4}{2017-01-02} 1358 | \item Renamed \cmd{listdel} to \cmd{listremove} (name clash)\see{aut:lst:int} 1359 | \item Renamed \cmd{listgdel} to \cmd{listgremove} (name clash)\see{aut:lst:int} 1360 | \end{release} 1361 | 1362 | \begin{release}{2.3}{2016-12-26} 1363 | \item Added \cmd{listdel}\see{aut:lst:int} 1364 | \item Added \cmd{listgdel}\see{aut:lst:int} 1365 | \end{release} 1366 | 1367 | \begin{release}{2.2b}{2016-12-01} 1368 | \item Fixed \cmd{ifdefltxprotect} for some types of \latex robust commands 1369 | \item Remove redundant macro after \cmd{robustify} processing 1370 | \end{release} 1371 | 1372 | \begin{release}{2.2a}{2015-08-02} 1373 | \item Fixed robustness bug in \cmd{ifblank}/\cmd{notblank} 1374 | \end{release} 1375 | 1376 | \begin{release}{2.2}{2015-05-04} 1377 | \item Added \cmd{csmeaning}\see{aut:def:def} 1378 | \end{release} 1379 | 1380 | \begin{release}{2.1d}{2015-03-19} 1381 | \item Fixed issue with \sty{bm} and some classes 1382 | \end{release} 1383 | 1384 | \begin{release}{2.1c}{2015-03-15} 1385 | \item Fixed space bug in \cmd{ifpatchable} 1386 | \item Fixed space bug in \cmd{patchcmd} 1387 | \item Fixed space bug in \cmd{robustify} 1388 | \end{release} 1389 | 1390 | \begin{release}{2.1b}{2015-03-10} 1391 | \item Minor documentation fixes 1392 | \end{release} 1393 | 1394 | \begin{release}{2.1a}{2015-03-10} 1395 | \item New maintainer: Joseph Wright 1396 | \item Skip loading \sty{etex} package with newer \latex kernel releases 1397 | \end{release} 1398 | 1399 | \begin{release}{2.1}{2011-01-03} 1400 | \item Added \cmd{AtBeginEnvironment}\see{use:env} 1401 | \item Added \cmd{AtEndEnvironment}\see{use:env} 1402 | \item Added \cmd{BeforeBeginEnvironment}\see{use:env} 1403 | \item Added \cmd{AfterEndEnvironment}\see{use:env} 1404 | \item Added \cmd{ifdefstrequal}\see{aut:tst:def} 1405 | \item Added \cmd{ifcsstrequal}\see{aut:tst:def} 1406 | \item Added \cmd{ifdefcounter}\see{aut:tst:cnt} 1407 | \item Added \cmd{ifcscounter}\see{aut:tst:cnt} 1408 | \item Added \cmd{ifltxcounter}\see{aut:tst:cnt} 1409 | \item Added \cmd{ifdeflength}\see{aut:tst:cnt} 1410 | \item Added \cmd{ifcslength}\see{aut:tst:cnt} 1411 | \item Added \cmd{ifdefdimen}\see{aut:tst:cnt} 1412 | \item Added \cmd{ifcsdimen}\see{aut:tst:cnt} 1413 | \end{release} 1414 | 1415 | \begin{release}{2.0a}{2010-09-12} 1416 | \item Fixed bug in \cmd{patchcmd}, \cmd{apptocmd}, \cmd{pretocmd}\see{aut:pat} 1417 | \end{release} 1418 | 1419 | \begin{release}{2.0}{2010-08-21} 1420 | 1421 | \item Added \cmd{csshow}\see{aut:def:def} 1422 | \item Added \cmd{DeclareListParser*}\see{aut:lst:inp} 1423 | \item Added \cmd{forcsvlist}\see{aut:lst:inp} 1424 | \item Added \cmd{forlistloop}\see{aut:lst:int} 1425 | \item Added \cmd{forlistcsloop}\see{aut:lst:int} 1426 | \item Allow testing \cmd{par} in macro tests\see{aut:tst:def} 1427 | \item Fixed some bugs 1428 | 1429 | \end{release} 1430 | 1431 | \begin{release}{1.9}{2010-04-10} 1432 | 1433 | \item Improved \cmd{letcs}\see{aut:def:def} 1434 | \item Improved \cmd{csletcs}\see{aut:def:def} 1435 | \item Improved \cmd{listeadd}\see{aut:lst:int} 1436 | \item Improved \cmd{listxadd}\see{aut:lst:int} 1437 | \item Added \cmd{notblank}\see{aut:tst:str} 1438 | \item Added \cmd{ifnumodd}\see{aut:tst:num} 1439 | \item Added \cmd{ifboolexpr}\see{aut:tst:bol} 1440 | \item Added \cmd{ifboolexpe}\see{aut:tst:bol} 1441 | \item Added \cmd{whileboolexpr}\see{aut:tst:bol} 1442 | \item Added \cmd{unlessboolexpr}\see{aut:tst:bol} 1443 | 1444 | \end{release} 1445 | 1446 | \begin{release}{1.8}{2009-08-06} 1447 | 1448 | \item Improved \cmd{deflength}\see{use:cal} 1449 | \item Added \cmd{ifnumcomp}\see{aut:tst:num} 1450 | \item Added \cmd{ifnumequal}\see{aut:tst:num} 1451 | \item Added \cmd{ifnumgreater}\see{aut:tst:num} 1452 | \item Added \cmd{ifnumless}\see{aut:tst:num} 1453 | \item Added \cmd{ifdimcomp}\see{aut:tst:num} 1454 | \item Added \cmd{ifdimequal}\see{aut:tst:num} 1455 | \item Added \cmd{ifdimgreater}\see{aut:tst:num} 1456 | \item Added \cmd{ifdimless}\see{aut:tst:num} 1457 | 1458 | \end{release} 1459 | 1460 | \begin{release}{1.7}{2008-06-28} 1461 | 1462 | \item Renamed \cmd{AfterBeginDocument} to \cmd{AfterEndPreamble} (name clash)\see{use:pre} 1463 | \item Resolved conflict with \sty{hyperref} 1464 | \item Rearranged manual slightly 1465 | 1466 | \end{release} 1467 | 1468 | \begin{release}{1.6}{2008-06-22} 1469 | 1470 | \item Improved \cmd{robustify}\see{use:pat} 1471 | \item Improved \cmd{patchcmd} and \cmd{ifpatchable}\see{aut:pat} 1472 | \item Modified and improved \cmd{apptocmd}\see{aut:pat} 1473 | \item Modified and improved \cmd{pretocmd}\see{aut:pat} 1474 | \item Added \cmd{ifpatchable*}\see{aut:pat} 1475 | \item Added \cmd{tracingpatches}\see{aut:pat} 1476 | \item Added \cmd{AfterBeginDocument}\see{use:pre} 1477 | \item Added \cmd{ifdefmacro}\see{aut:tst:def} 1478 | \item Added \cmd{ifcsmacro}\see{aut:tst:def} 1479 | \item Added \cmd{ifdefprefix}\see{aut:tst:def} 1480 | \item Added \cmd{ifcsprefix}\see{aut:tst:def} 1481 | \item Added \cmd{ifdefparam}\see{aut:tst:def} 1482 | \item Added \cmd{ifcsparam}\see{aut:tst:def} 1483 | \item Added \cmd{ifdefprotected}\see{aut:tst:def} 1484 | \item Added \cmd{ifcsprotected}\see{aut:tst:def} 1485 | \item Added \cmd{ifdefltxprotect}\see{aut:tst:def} 1486 | \item Added \cmd{ifcsltxprotect}\see{aut:tst:def} 1487 | \item Added \cmd{ifdefempty}\see{aut:tst:def} 1488 | \item Added \cmd{ifcsempty}\see{aut:tst:def} 1489 | \item Improved \cmd{ifdefvoid}\see{aut:tst:def} 1490 | \item Improved \cmd{ifcsvoid}\see{aut:tst:def} 1491 | \item Added \cmd{ifstrempty}\see{aut:tst:str} 1492 | \item Added \cmd{setbool}\see{aut:bo1:bol} 1493 | \item Added \cmd{settoggle}\see{aut:bo1:tgl} 1494 | 1495 | \end{release} 1496 | 1497 | \begin{release}{1.5}{2008-04-26} 1498 | 1499 | \item Added \cmd{defcounter}\see{use:cal} 1500 | \item Added \cmd{deflength}\see{use:cal} 1501 | \item Added \cmd{ifdefstring}\see{aut:tst:def} 1502 | \item Added \cmd{ifcsstring}\see{aut:tst:def} 1503 | \item Improved \cmd{rmntonum}\see{aut:msc} 1504 | \item Added \cmd{ifrmnum}\see{aut:msc} 1505 | \item Added extended \pdf bookmarks to this manual 1506 | \item Rearranged manual slightly 1507 | 1508 | \end{release} 1509 | 1510 | \begin{release}{1.4}{2008-01-24} 1511 | 1512 | \item Resolved conflict with \sty{tex4ht} 1513 | 1514 | \end{release} 1515 | 1516 | \begin{release}{1.3}{2007-10-08} 1517 | 1518 | \item Renamed package from \sty{elatex} to \sty{etoolbox}\see{int} 1519 | \item Renamed \cmd{newswitch} to \cmd{newtoggle} (name clash)\see{aut:bo1:tgl} 1520 | \item Renamed \cmd{provideswitch} to \cmd{providetoggle} (consistency)\see{aut:bo1:tgl} 1521 | \item Renamed \cmd{switchtrue} to \cmd{toggletrue} (consistency)\see{aut:bo1:tgl} 1522 | \item Renamed \cmd{switchfalse} to \cmd{togglefalse} (consistency)\see{aut:bo1:tgl} 1523 | \item Renamed \cmd{ifswitch} to \cmd{iftoggle} (consistency)\see{aut:bo1:tgl} 1524 | \item Renamed \cmd{notswitch} to \cmd{nottoggle} (consistency)\see{aut:bo1:tgl} 1525 | \item Added \cmd{AtEndPreamble}\see{use:pre} 1526 | \item Added \cmd{AfterEndDocument}\see{use:pre} 1527 | \item Added \cmd{AfterPreamble}\see{use:pre} 1528 | \item Added \cmd{undef}\see{aut:def:def} 1529 | \item Added \cmd{csundef}\see{aut:def:def} 1530 | \item Added \cmd{ifdefvoid}\see{aut:tst:def} 1531 | \item Added \cmd{ifcsvoid}\see{aut:tst:def} 1532 | \item Added \cmd{ifdefequal}\see{aut:tst:def} 1533 | \item Added \cmd{ifcsequal}\see{aut:tst:def} 1534 | \item Added \cmd{ifstrequal}\see{aut:tst:str} 1535 | \item Added \cmd{listadd}\see{aut:lst:int} 1536 | \item Added \cmd{listeadd}\see{aut:lst:int} 1537 | \item Added \cmd{listgadd}\see{aut:lst:int} 1538 | \item Added \cmd{listxadd}\see{aut:lst:int} 1539 | \item Added \cmd{listcsadd}\see{aut:lst:int} 1540 | \item Added \cmd{listcseadd}\see{aut:lst:int} 1541 | \item Added \cmd{listcsgadd}\see{aut:lst:int} 1542 | \item Added \cmd{listcsxadd}\see{aut:lst:int} 1543 | \item Added \cmd{ifinlist}\see{aut:lst:int} 1544 | \item Added \cmd{xifinlist}\see{aut:lst:int} 1545 | \item Added \cmd{ifinlistcs}\see{aut:lst:int} 1546 | \item Added \cmd{xifinlistcs}\see{aut:lst:int} 1547 | \item Added \cmd{dolistloop}\see{aut:lst:int} 1548 | \item Added \cmd{dolistcsloop}\see{aut:lst:int} 1549 | 1550 | \end{release} 1551 | 1552 | \begin{release}{1.2}{2007-07-13} 1553 | 1554 | \item Renamed \cmd{patchcommand} to \cmd{patchcmd} (name clash)\see{aut:pat} 1555 | \item Renamed \cmd{apptocommand} to \cmd{apptocmd} (consistency)\see{aut:pat} 1556 | \item Renamed \cmd{pretocommand} to \cmd{pretocmd} (consistency)\see{aut:pat} 1557 | \item Added \cmd{newbool}\see{aut:bo1:bol} 1558 | \item Added \cmd{providebool}\see{aut:bo1:bol} 1559 | \item Added \cmd{booltrue}\see{aut:bo1:bol} 1560 | \item Added \cmd{boolfalse}\see{aut:bo1:bol} 1561 | \item Added \cmd{ifbool}\see{aut:bo1:bol} 1562 | \item Added \cmd{notbool}\see{aut:bo1:bol} 1563 | \item Added \cmd{newswitch}\see{aut:bo1:tgl} 1564 | \item Added \cmd{provideswitch}\see{aut:bo1:tgl} 1565 | \item Added \cmd{switchtrue}\see{aut:bo1:tgl} 1566 | \item Added \cmd{switchfalse}\see{aut:bo1:tgl} 1567 | \item Added \cmd{ifswitch}\see{aut:bo1:tgl} 1568 | \item Added \cmd{notswitch}\see{aut:bo1:tgl} 1569 | \item Added \cmd{DeclareListParser}\see{aut:lst:inp} 1570 | \item Added \cmd{docsvlist}\see{aut:lst:inp} 1571 | \item Added \cmd{rmntonum}\see{aut:msc} 1572 | 1573 | \end{release} 1574 | 1575 | \begin{release}{1.1}{2007-05-28} 1576 | 1577 | \item Added \cmd{protected@csedef}\see{aut:def:def} 1578 | \item Added \cmd{protected@csxdef}\see{aut:def:def} 1579 | \item Added \cmd{gluedef}\see{aut:def:cal} 1580 | \item Added \cmd{gluegdef}\see{aut:def:cal} 1581 | \item Added \cmd{csgluedef}\see{aut:def:cal} 1582 | \item Added \cmd{csgluegdef}\see{aut:def:cal} 1583 | \item Added \cmd{mudef}\see{aut:def:cal} 1584 | \item Added \cmd{mugdef}\see{aut:def:cal} 1585 | \item Added \cmd{csmudef}\see{aut:def:cal} 1586 | \item Added \cmd{csmugdef}\see{aut:def:cal} 1587 | \item Added \cmd{protected@eappto}\see{aut:hok:app} 1588 | \item Added \cmd{protected@xappto}\see{aut:hok:app} 1589 | \item Added \cmd{protected@cseappto}\see{aut:hok:app} 1590 | \item Added \cmd{protected@csxappto}\see{aut:hok:app} 1591 | \item Added \cmd{protected@epreto}\see{aut:hok:pre} 1592 | \item Added \cmd{protected@xpreto}\see{aut:hok:pre} 1593 | \item Added \cmd{protected@csepreto}\see{aut:hok:pre} 1594 | \item Added \cmd{protected@csxpreto}\see{aut:hok:pre} 1595 | \item Fixed bug in \cmd{newrobustcmd}\see{use:def} 1596 | \item Fixed bug in \cmd{renewrobustcmd}\see{use:def} 1597 | \item Fixed bug in \cmd{providerobustcmd}\see{use:def} 1598 | 1599 | \end{release} 1600 | 1601 | \begin{release}{1.0}{2007-05-07} 1602 | 1603 | \item Initial public release 1604 | 1605 | \end{release} 1606 | 1607 | \end{changelog} 1608 | 1609 | \end{document} 1610 | -------------------------------------------------------------------------------- /support/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # See if there is a cached verson of TL available 4 | export PATH=/tmp/texlive/bin/x86_64-linux:$PATH 5 | if ! command -v texlua > /dev/null; then 6 | # Obtain TeX Live 7 | wget http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz 8 | tar -xzf install-tl-unx.tar.gz 9 | cd install-tl-20* 10 | 11 | # Install a minimal system 12 | ./install-tl --profile=../support/texlive.profile 13 | 14 | cd .. 15 | fi 16 | 17 | # l3build itself and LuaTeX: need for texlua 18 | tlmgr install l3build luatex 19 | 20 | # Keep no backups (not required, simply makes cache bigger) 21 | tlmgr option -- autobackup 0 22 | 23 | # Update the TL install but add nothing new 24 | tlmgr update --self --all --no-auto-install 25 | -------------------------------------------------------------------------------- /support/texlive.profile: -------------------------------------------------------------------------------- 1 | selected_scheme scheme-basic 2 | TEXDIR /tmp/texlive 3 | TEXMFCONFIG ~/.texlive/texmf-config 4 | TEXMFHOME ~/texmf 5 | TEXMFLOCAL /tmp/texlive/texmf-local 6 | TEXMFSYSCONFIG /tmp/texlive/texmf-config 7 | TEXMFSYSVAR /tmp/texlive/texmf-var 8 | TEXMFVAR ~/.texlive/texmf-var 9 | option_doc 0 10 | option_src 0 11 | -------------------------------------------------------------------------------- /testfiles/etoolbox-cmdcopy.dev.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | \tmp=\protected macro:->\@testopt \\tmp {zzz}| 4 | \\tmp=\long macro:[#1]->boo| 5 | \+=\protected macro:->\@testopt \\+ {zzz}| 6 | \\+=\long macro:[#1]->boo| 7 | \tmp=\protected macro:->\@testopt \\tmp {zzz}| 8 | \\tmp=\long macro:[#1]->boo| 9 | \+=\protected macro:->\@testopt \\+ {zzz}| 10 | \\+=\long macro:[#1]->boo| 11 | -------------------------------------------------------------------------------- /testfiles/etoolbox-cmdcopy.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test 2 | \RequirePackage{etoolbox} 3 | 4 | \START 5 | 6 | \ifdef\DeclareCommandCopy{}{\END} 7 | 8 | \def\testt#1#2#3#4{% 9 | #4% 10 | \DeclareCommandCopy#1#3% 11 | \testtt#1 12 | \expandafter\testtt\csname\string#1\endcsname 13 | \typeout{}} 14 | \def\testtt#1{% 15 | \typeout{\string#1=\meaning#1|}% 16 | \let#1\undefined} 17 | 18 | \def\cmdd{defined} 19 | 20 | % Here we need control words 21 | \testt\tmp{tmp}\cmdd 22 | {\renewrobustcmd\cmdd[1][zzz]{boo}} 23 | 24 | % And here control symbols 25 | \testt\+{+}\% 26 | {\renewrobustcmd\%[1][zzz]{boo}} 27 | 28 | % Test letting a control symbol to a control word 29 | \testt\tmp{tmp}\% 30 | {\renewrobustcmd\%[1][zzz]{boo}} 31 | 32 | % And a control word to a control symbol 33 | \testt\+{+}\cmdd 34 | {\renewrobustcmd\cmdd[1][zzz]{boo}} 35 | 36 | \END 37 | -------------------------------------------------------------------------------- /testfiles/etoolbox-cmdcopy.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | \tmp=\protected macro:->\@testopt \\tmp {zzz}| 4 | \\tmp=\long macro:[#1]->boo| 5 | \+=\protected macro:->\@testopt \\+ {zzz}| 6 | \\+=\long macro:[#1]->boo| 7 | \tmp=\protected macro:->\@testopt \\tmp {zzz}| 8 | \\tmp=\long macro:[#1]->boo| 9 | \+=\protected macro:->\@testopt \\+ {zzz}| 10 | \\+=\long macro:[#1]->boo| 11 | -------------------------------------------------------------------------------- /testfiles/etoolbox-defs.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test 2 | \RequirePackage{etoolbox} 3 | 4 | \START 5 | 6 | \OMIT 7 | \def\testa{} 8 | \def\testb{ } 9 | \def\testc#1{} 10 | \def\testd#1{ } 11 | \def\teste{a} 12 | \def\testf#1{a} 13 | \let\testg\relax 14 | \TIMO 15 | 16 | \TESTEXP{\ifdefempty} 17 | {% 18 | \ifdefempty{\testa}{\TRUE}{\FALSE}% 19 | \NEWLINE 20 | \ifdefempty{\testb}{\TRUE}{\FALSE}% 21 | \NEWLINE 22 | \ifdefempty{\testc}{\TRUE}{\FALSE}% 23 | \NEWLINE 24 | \ifdefempty{\testd}{\TRUE}{\FALSE}% 25 | \NEWLINE 26 | \ifdefempty{\teste}{\TRUE}{\FALSE}% 27 | \NEWLINE 28 | \ifdefempty{\testf}{\TRUE}{\FALSE}% 29 | \NEWLINE 30 | \ifdefempty{\testg}{\TRUE}{\FALSE}% 31 | \NEWLINE 32 | \ifdefempty{\testh}{\TRUE}{\FALSE}% 33 | } 34 | 35 | \TESTEXP{\ifdefvoid} 36 | {% 37 | \ifdefvoid{\testa}{\TRUE}{\FALSE}% 38 | \NEWLINE 39 | \ifdefvoid{\testb}{\TRUE}{\FALSE}% 40 | \NEWLINE 41 | \ifdefvoid{\testc}{\TRUE}{\FALSE}% 42 | \NEWLINE 43 | \ifdefvoid{\testd}{\TRUE}{\FALSE}% 44 | \NEWLINE 45 | \ifdefvoid{\teste}{\TRUE}{\FALSE}% 46 | \NEWLINE 47 | \ifdefvoid{\testf}{\TRUE}{\FALSE}% 48 | \NEWLINE 49 | \ifdefvoid{\testg}{\TRUE}{\FALSE}% 50 | \NEWLINE 51 | \ifdefvoid{\testh}{\TRUE}{\FALSE}% 52 | } 53 | 54 | \END -------------------------------------------------------------------------------- /testfiles/etoolbox-defs.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | ============================================================ 4 | TEST 1: \ifdefempty 5 | ============================================================ 6 | TRUE 7 | FALSE 8 | FALSE 9 | FALSE 10 | FALSE 11 | FALSE 12 | FALSE 13 | FALSE 14 | ============================================================ 15 | ============================================================ 16 | TEST 2: \ifdefvoid 17 | ============================================================ 18 | TRUE 19 | FALSE 20 | FALSE 21 | FALSE 22 | FALSE 23 | FALSE 24 | TRUE 25 | TRUE 26 | ============================================================ 27 | -------------------------------------------------------------------------------- /testfiles/etoolbox-lists.lvt: -------------------------------------------------------------------------------- 1 | \input regression-test 2 | \RequirePackage{etoolbox} 3 | 4 | \START 5 | 6 | \OMIT 7 | \def\do#1{\detokenize{"#1"}} 8 | \TIMO 9 | \TESTEXP{\docsvlist} 10 | {% 11 | \docsvlist{a,b,c}% 12 | \NEWLINE 13 | \docsvlist{a,{b,c}}% 14 | \NEWLINE 15 | \docsvlist{a, {b,c}}% 16 | \NEWLINE 17 | \docsvlist{a,{b}, {c}}% 18 | \NEWLINE 19 | \docsvlist{a,{b},,{c},}% 20 | } 21 | 22 | \TESTEXP{\forcsvlist} 23 | {% 24 | \forcsvlist{\empty\do}{a,b,c}% 25 | \NEWLINE 26 | \forcsvlist{\empty\do}{a,{b,c}}% 27 | \NEWLINE 28 | \forcsvlist{\empty\do}{a, {b,c}}% 29 | \NEWLINE 30 | \forcsvlist{\empty\do}{a,{b}, {c}}% 31 | \NEWLINE 32 | \forcsvlist{\empty\do}{a,{b},,{c},}% 33 | } 34 | 35 | \OMIT 36 | \listadd{\testlist}{a} 37 | \listadd{\testlist}{{b}} 38 | \listadd{\testlist}{ {c}} 39 | \listadd{\testlist}{{d} } 40 | \listadd{\testlist}{ {e} } 41 | \listadd{\testlist}{} 42 | \listadd{\testlist}{ f } 43 | \TIMO 44 | \TESTEXP{\forlistloop} 45 | {% 46 | \forlistloop{\do}{\testlist}% 47 | } 48 | 49 | \OMIT 50 | \DeclareListParser\foo{} 51 | \TIMO 52 | \TESTEXP{Empty list marker} 53 | {\foo{;.{.} {;} }} 54 | 55 | 56 | \END -------------------------------------------------------------------------------- /testfiles/etoolbox-lists.tlg: -------------------------------------------------------------------------------- 1 | This is a generated file for the l3build validation system. 2 | Don't change this file in any respect. 3 | ============================================================ 4 | TEST 1: \docsvlist 5 | ============================================================ 6 | "a""b""c" 7 | "a""b,c" 8 | "a""b,c" 9 | "a""b""c" 10 | "a""b""c" 11 | ============================================================ 12 | ============================================================ 13 | TEST 2: \forcsvlist 14 | ============================================================ 15 | "a""b""c" 16 | "a""b,c" 17 | "a""b,c" 18 | "a""b""c" 19 | "a""b""c" 20 | ============================================================ 21 | ============================================================ 22 | TEST 3: \forlistloop 23 | ============================================================ 24 | "a""b"" {c}""{d} "" {e} "" f " 25 | ============================================================ 26 | ============================================================ 27 | TEST 4: Empty list marker 28 | ============================================================ 29 | ";"".""."";" 30 | ============================================================ 31 | --------------------------------------------------------------------------------