%% This is part of OpTeX project, see http://petr.olsak.net/optex \_codedecl \eoldef {OpTeX useful macos <2020-03-15>} % preloaded in format \_doc ----------------------------- We define \`\opinput` `{}` macro which does `\input {}` but catocodes are set to normal catcodes (like \OpTeX/ initializes them) and the catodes setting is return back to the current values when the file is read. You can use `\optinput` in any situation inside the document and you will be sure that the file is read correctly with correct catcode settings. In order to achieve this, we declare \`\optexcatcodes` catcode table and \`\plaintexcatocdes`. They save the commonly used catcode tables. Note that `\catcodetable` is a part of \LuaTeX/ extension. The catcodetable stack is implemented by \OpTeX/ macros. The \`\setctable` `` pushes current catcode table to the stack and activates catcodes from the ``. The \`\restorectable` returns to the saved catocdes from the catcode table stack. So, the `\opinput` macro can be implemented simply: \_cod ----------------------------- \_def\_opinput #1{\_setctable\_optexcatcodes \_input "#1" \_restorectable} \_newcatcodetable \_optexcatcodes \_newcatcodetable \_plaintexcatcodes \_public \optexcatcodes \plaintexcatcodes \opinput ; \_savecatcodetable\_optexcatcodes {\_catcode`_=8 \savecatcodetable\plaintexcatcodes} \_doc ----------------------------- The implementation of the catcodetable stack follows. The current catodes are managed in the `\catcodetable0`. If the `\setctable` is used first (or at the outer level of the stack), then the `\catcodetable0` is pushed to the stack and the current table is re-set to the given ``. The numbers of these tables are stacked to the \`\_ctablelist` macro. The `\restorectable` reads the last saved catcode table number from the `\_ctablelist` and uses it. \_cod ----------------------------- \_newcount\_currctable \_currctable=0 \_catcodetable0 \_def\_setctable#1{\_edef\_ctablelist{{\_the\_currctable}\_ctablelist}% \_catcodetable#1\_relax \_currctable=#1\_relax } \_def\_restorectable{\_ea\_restorectableA\_ctablelist\_relax} \_def\_restorectableA#1#2\_relax{% \_ifx^#2^\_opwarning {You can't use \_noindent\restorectable without previous \_string\setctable}% \_else \_def\_ctablelist{#2}\_catcodetable#1\_relax \_currctable=#1\_relax \_fi } \_def\_ctablelist{.} \_public \setctable \restorectable ; \_doc ----------------------------- When a special macro is defined with different catcodes then \`\normalcatcodes` can be used at the end of such definition. The normal catcodes are restored. The macro reads catcodes from `\optecatodes` table and sets it to the main catcode table 0. \_cod ----------------------------- \_def\_normalcatcodes {\_catcodetable\_optexcatcodes \_savecatcodetable0 \_catcodetable0 } \_public \normalcatodes ; \_doc ----------------------------- The declarator \`\optdef``\macro [] {}` defines the `\macro` with the optional parameter followed by normal parameters declared in ``. The optional parameter must be used as the first first parameter in brackets `[...]`. If it isn't used then is taken into account. The `` can use `\the\opt` because optional parameter is saved to the \`\opt` tokens register. Note the difference from \LaTeX/ concept where the optional parameter is in `#1`. \OpTeX/ uses `#1` as the first normal parameter (if declared). The \`\_nospaceafter` ignores the following optional space at expand processor level using the negative `\romannumeral` trick. \_cod ----------------------------- \_def\_optdef#1[#2]{% \_def#1{\_opt={#2}\_isnextchar[{\_cs{_oA:\_string#1}}{\_cs{_oB:\_string#1}}}% \_sdef{_oA:\_string#1}[##1]{\_opt={##1}\_cs{_oB:\string#1\_nospaceafter}}% \_sdef{_oB:\_string#1\_nospaceafter}% } \_def\_nospaceafter#1{\_ea#1\_romannumeral-`\.} \_newtoks\_opt \_public \opt \optdef ; \_doc ----------------------------- The declarator \`\eoldef``\macro #1{}` defines a `\macro` which scans its parameter to the end of the current line. This is the parameter `#1` which can be used in the ``. The catcode of the `\endlinechar` is reset temporarily when the parameter is scanned. The macro defined by `\eoldef` cannot be used with its parameter inside other macros because the catcode dancing is not possible here. But the \`\bracedparam``\macro{}` can be used here. The `\bracedparam` is a prefix which re-sets temporarily the `\macro` to a `\macro` with normal one parameter. The \`\skiptoeol` macro reads the text to the end of the current line and ignores it. \_cod ----------------------------- \_def\_eoldef #1{\_def #1{\_begingroup \_catcode`\^^M=12 \_eoldefA #1}% \_ea\_def\_csname _\_csstring #1:M\_endcsname} \_catcode`\^^M=12 % \_def\_eoldefA #1#2^^M{\_endgroup\_csname _\_csstring #1:M\_endcsname{#2}}% \_normalcatcodes % \_eoldef\_skiptoeol#1{} \_def\_bracedparam#1{\_ifcsname _\_csstring #1:M\_endcsname \_csname _\_csstring #1:M\_ea \_endcsname \_else \_csname __in\_csstring #1:M\_ea \_endcsname \_fi } \_public \eoldef \skiptoeol \bracedparam ; \_doc ----------------------------- The \`\replstring``\macro{}{}` replaces all occurrences of `` by `` in the `\macro` body. The `\macro` must be defined without parameters. The occurrences of `` are not replaced if they are \"hidden" in braces, for example `...{......}...`. The category codes in the `` must exactly match. \_cod ----------------------------- \_catcode`!=3 \_catcode`?=3 \_def\_replstring #1#2#3{% \replstring #1{stringA}{stringB} \_long\_def\_replacestringsA##1#2{\_def #1{##1}\_replacestringsB}% \_long\_def\_replacestringsB##1#2{\_ifx!##1\_relax \_else \_addto #1{#3##1}% \_ea\_replacestringsB\_fi}% \_ea\_replacestringsA #1?#2!#2% \_long\_def\_replacestringsA##1?{\_def #1{##1}}\_ea\_replacestringsA #1} \_normalcatcodes \_public \replstring ; \_doc ----------------------------- The \`\catcode` primitive is redefined here. Why? There is very common cases like \code{\\catcode`}`` or `\catcode"` but these characters \code{\`} or \code{"} can be set as active (typically by `\activettchar` macro). Nothing problematic happens if re-defined `\catcode` is used in this case. If you really need primitive `\catcode` then you can use `\_catcode`. \_cod ----------------------------- \def\catcode{\_catcode\_string} % more robust in cases \catcode` or \catcode" \_doc ----------------------------- The \`\removespaces` `{}` expands to . \nl The `\_ea`\`\ignorept``\the` expands to a decimal number `\the` but without `pt` unit. \nl The \`\ignoreit``` just ignores the ``. \_cod ----------------------------- \_def\_removespaces #1 {\_isempty{#1}\_iffalse #1\_ea\_removespaces\_fi} \_ea\_def \_ea\_ignorept \_ea#\_ea1\detokenize{pt}{#1} \_def\_ignoreit#1{} \public \removespaces \ignorept \ignoreit ; \_doc ----------------------------- You can use expandable \`\bp``{}` convertor from \TeX/ `` (or from an expression accepted by `\dimexpr` primitive) to a decimal value in big points (used as natural unit in the PDF format). So, you can write, for example: \begtt \pdfliteral{q \_bp{.3\hsize-2mm} \_bp{2mm} m 0 \_bp{-4mm} l S Q} \endtt You can use expandable \`\expr``{}` for analogical purposes. It expands to the value of the `` at expand processor level with \`\_decdigits` digits after decimal point. The `` can include `+-*/()` and decimal numbers in common syntax. The usage of prefixed versions \`\_expr` or \`\_bp` is more recommended because user can re-define the control sequences `\expr` or `\bp`. \_cod ----------------------------- \_def\_decdigits{3} % digits after decimal point in \_bp and \_expr outputs. \_def\_pttopb{% \_directlua{tex.print(string.format('\_pcent.\_decdigits f', token.scan_dimen()/65781.76))}% pt to bp conversion } \def\_bp#1{\_ea\_pttopb\_dimexpr#1\_relax} \def\_expr#1{\_directlua{tex.print(string.format('\_pcent.\_decdigits f',#1))}} \_public \expr \bp ; \_doc ------------------ The pair {\`\_doc` ... \`\_cod`} is used for documenting macros and to printing the technical documentation of the \OpTeX/. The syntax is: {\begtt \_doc \_cod \endtt } The `` (and `` too) must be ``. It means that you cannot document only the `{` but you must document the `}` too. \_cod ------------------ \_long\_def\_doc #1\_cod {\_skiptoeol} \_endcode % -------------------------------------