%% This is part of the OpTeX project, see http://petr.olsak.net/optex

\_codedecl \eoldef {OpTeX useful macros <2024-10-31>} % preloaded in format

   \_doc -----------------------------
   We define \`\opinput` `{<file name>}` macro which
   does `\input {<file name>}` but the catcodes are set to normal catcodes
   (like \OpTeX/ initializes them) and the catcodes setting is returned back to
   the current values when the file is read. You can use `\opinput`
   in any situation inside the document and you will be sure that the file
   is read correctly with correct catcode settings.

   To achieve this, we declare \`\optexcatcodes` catcode table
   and \`\plaintexcatcodes`. 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` `<catcode table>` pushes 
   current catcode table to the stack and activates catcodes from
   the `<catcode table>`. The \`\restorectable` returns to the saved catcodes
   from the catcode table stack.

   The `\opinput` works inside the catcode table stack. It reads `\optexcatcodes`
   table and stores it to \`\_tmpcatcodes`  table.
   This table is actually used during `\input` (maybe catcodes are
   changed here). Finally, `\_restoretable` pops the stacks and returns
   to the catcodes used before `\opinput` is run.
   \_cod -----------------------------

\_def\_opinput #1{\_setctable\_optexcatcodes
   \_savecatcodetable\_tmpcatcodes \_catcodetable\_tmpcatcodes
   \_input {#1}\_relax\_restorectable}

\_newcatcodetable \_optexcatcodes
\_newcatcodetable \_plaintexcatcodes
\_newcatcodetable \_tmpcatcodes

\_public \optexcatcodes \plaintexcatcodes \opinput ;

\_savecatcodetable\_optexcatcodes
{\_catcode`_=8 \savecatcodetable\plaintexcatcodes}

   \_doc -----------------------------
   The implementation of the catcodetable stack follows. 

   The current catcodes 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 `<catcode table>`.
   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 -----------------------------

\_catcodetable0

\_def\_setctable#1{\_edef\_ctablelist{{\_the\_catcodetable}\_ctablelist}%
   \_catcodetable#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 \_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 \normalcatcodes ;

   \_doc -----------------------------
   The \`\load` `[<filename-list>]` loads files specified in
   comma separated `<filename-list>`. The first space (after comma)
   is ignored using the trick `#1#2,`: first parameter is unseparated.
   The `\load` macro saves information about loaded files by setting
   `\_load:<filename>` as a defined macro.

   If the \`\_afterload` macro is defined then it is run after `\_opinput`.
   The catcode setting should be here. Note that catcode setting done in the
   loaded file is forgotten after the `\opinput`.
   \_cod -----------------------------

\_def \_load [#1]{\_savemathsb \_loadA #1,,,\_end \_restoremathsb}
\_def \_loadA #1#2,{\_ifx,#1 \_ea \_loadE \_else \_loadB{#1#2}\_ea\_loadA\_fi}
\_def \_loadB #1{%
   \_ifcsname _load:#1\_endcsname \_else
      \_isfile {#1.opm}\_iftrue \_opinput {#1.opm}\_else \_opinput {#1}\_fi
      \_sxdef{_load:#1}{}%
      \_trycs{_afterload}{}\_let\_afterload=\_undefined
   \_fi
}
\_def \_loadE #1\_end{}
\_public \load ;

   \_doc -----------------------------
   The declarator \`\optdef``\macro [<opt default>] <params>{<replacement text>}` 
   defines the `\macro` with the optional parameter followed by normal parameters
   declared in `<params>`. The optional parameter must be used as the first
   parameter in brackets `[...]`. If it isn't used then <opt default>
   is taken into account. The `<replacement text>` 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.
   The \`\nospacefuturelet` bahaves like `\futurelet` primitive, but it
   ignores the following optional space and works at expand processor level.
   \_cod -----------------------------

\_newtoks\_opt
\_def\_optdef#1[#2]{%
   \_def#1{\_isnextchar[{\_cs{_oA:\_csstring#1}}{\_cs{_oA:\_csstring#1}[#2]}}%
   \_sdef{_oA:\_csstring#1}[##1]{%
      \_immediateassignment\_opt={##1}\_cs{_oB:\_csstring#1\_nospaceafter}}%
   \_sdef{_oB:\_csstring#1\_nospaceafter}%
}
\_def\_nospaceafter#1{\_ea#1\_romannumeral-`\.\_noexpand}
\_def\_nospacefuturelet#1#2{\_ea\_immediateassignment
   \_ea\_futurelet\_ea#1\_ea#2\_romannumeral-`\.\_noexpand}

\_public \opt \optdef \nospaceafter \nospacefuturelet ;

   \_doc -----------------------------
   \`\_noprefix` `<cs>` works like `\csstring` `<cs>`, but ignores not only
   the first backlash but the second~\"`_`" ignores too (if it follows the
   backslash).
   \_cod -----------------------------

\_def\_noprefix#1{\_ea\_noprefixA \_csstring#1\_empty\_fin}
\_def\_noprefixA #1#2\_fin{\_if _#1\_else #1\_fi #2}

   \_doc -----------------------------
   The declarator \`\eoldef``\macro #1{<replacement text>}` 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 `<replacement text>`.
   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{<parameter>}` can be used here. The `\bracedparam`
   is a prefix that 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 _eol:\_noprefix #1\_endcsname}
\_catcode`\^^M=12 %
\_def\_eoldefA #1#2^^M{\_endgroup\_csname _eol:\_noprefix #1\_endcsname{#2}}%
\_normalcatcodes %

\_eoldef\_skiptoeol#1{}

\_def\_bracedparam#1{%
   \_trycs{_eol:\_noprefix#1}%
      {\_errmessage{\_string\bracedparam: \_string#1 isn't defined by \_string\eoldef}}%
}
\_public \eoldef \skiptoeol \bracedparam ;

   \_doc -----------------------------
   \`\scantoeol``\macro <text to end of line>` scans the
   `<text to end of line>` in verbatim mode and runs the
   `\macro{<text to end of line>}`. The `\macro`
   can be defined `\def\macro#1{...\scantextokens{#1}...}`.
   The new tokenization of the parameter is processed when the parameter is used,
   no when the parameter is scanned. This principle is used in definition
   of \^`\chap`, \^`\sec`, \^`\secc` and \^`\_Xtoc` macros.
   It means that user can write \code{\\sec text `&` text} for example.
   Inline verbatim works in title sections.

   The verbatim scanner of `\scantoeol` keeps category 7 for `^` in
   order to be able to use `^^J` as comment character which means that
   the next line continues.
   \_cod -----------------------------

\_def\_scantoeol#1{\_begingroup \_setscancatcodes \_scantoeolA #1}
\_def\_setscancatcodes{\_setverb \_catcode`\^^M=12\_catcode`\^=7\_catcode`\ =10\_catcode`\^^J=14 }
\_catcode`\^^M=12 %
\_def\_scantoeolA#1#2^^M{\_endgroup #1{#2}}%
\_normalcatcodes %

\_public \scantoeol ;

   \_doc -----------------------------
   The \`\replstring``\macro{<textA>}{<textB>}`
   replaces all occurrences of `<textA>` by `<textB>` in the `\macro` body.
   The `\macro` must be defined without parameters. The occurrences of
   `<textA>` are not replaced if they are \"hidden" in braces, for example
   `...{...<textA>...}...`. The category codes in the `<textA>` must exactly
   match.

   How it works: `\replstring\foo{<textA>}{<textB>}` prepares
   `\_replacestringsA#1<textA>{...}` and runs
   `\_replacestringsA<foo-body>?<textA>!<textA>`.
   So, `#1` includes the first part of <foo-body> before first <textA>.
   It is saved to \`\_repltoks` and `\_replacestringsB` is run with `\_replacestingsC` in a loop.
   It finishes processing (if final `!` is scanned) or appends the next part to `\_repltoks` separated by
   <textB> and continues loop. The final part of the \^`\replstring` macro removes the last `?`
   from resulting `\_repltoks` and defines a new version of the `\foo`.
   \_cod -----------------------------

\_newtoks\_repltoks
\_catcode`!=3 \_catcode`?=3
\_long\_def\_replstring #1#2#3{%  \replstring #1{stringA}{stringB}
   \_long\_def\_replacestringsA##1#2{\_repltoks\_ea{##1}\_replacestringsB\_empty}%
   \_long\_def\_replacestringsB##1#2{\_ea\_replacestringsC\_ea{##1}}%
   \_long\_def\_replacestringsC##1{\_ifx!##1\_empty\_else
       \_toksapp\_repltoks{#3##1}\_ea\_replacestringsB\_ea\_empty\_fi}%
   \_ea\_replacestringsA \_ea\_empty#1?#2!#2%
   \_ea\_replacestringsD \_ea\_empty\_the\_repltoks#1}
\_long\_def\_replacestringsD #1?#2{\_repltoks\_ea{#1}\_edef#2{\_the\_repltoks}}%
\_normalcatcodes

\_public \replstring ;

   \_doc -----------------------------
   You can find three special tricks in the \^`\replstring` code:
   \begitems
   * Adding and removing `?` character: without this the
     `\def\b{xxxA}\replstring\b{AA}{BB}` will cause an error.
   * Using `\_toksapp` instead `\addto`: without this you cannot have $`#`_6$
     in the string. Moreover, it significantly
     reduces the calculation time. Unfortunately, it does \^`\replstring` unexpandable.
   * Using `\_empty` before scanning separated parameters and removing it
     after scanning by \^`\ea`: without this \TeX/
     removes braces from `<textA>{xxx}<textA>`.
   \enditems
   The \^`\replstring` macro isn't expandable. But you can see
   \ulink[http://petr.olsak.net/optex/optex-tricks.html\#xreplstring]{\OpTeX/ trick 0136}
   and \ulink[http://petr.olsak.net/optex/optex-tricks.html\#replmacro]{\OpTeX/ trick 0137}.
   These triks implement expandable alternatives and enable more general modifications
   of macros by regular expressions.
   \_cod -----------------------------

   \_doc -----------------------------
   The \`\catcode` primitive is redefined here. Why?
   There is very common cases like \code{\\catcode`}`<something>`
   or `\catcode"<number>` but these characters
   \code{\`} or \code{"} can be set as active (typically by `\verbchar` 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#1{\_catcode \_if`\_noexpand#1\_ea`\_else\_if"\_noexpand#1"\_else
   \_if'\_noexpand#1'\_else \_ea\_ea\_ea\_ea\_ea\_ea\_ea#1\_fi\_fi\_fi}

   \_doc -----------------------------
   The \`\removespaces` `<text with spaces >{}` expands to <textwithoutspaces>.
   \nl
   The 	`\_ea`\`\ignorept``\the<dimen>` expands to a decimal
   number `\the<dimen>` but without `pt` unit.
   \_cod -----------------------------

\_def\_removespaces #1 {\_isempty{#1}\_iffalse #1\_ea\_removespaces\_fi}
\_ea\_def \_ea\_ignorept \_ea#\_ea1\_detokenize{pt}{#1}

\_public \removespaces \ignorept ;

   \_doc -----------------------------
   If you do `\let\foo=a` then it is not simple to return from `\foo` to the original
   character code of `a`. You can write \code{`a} but you cannot write \code{`\\foo}.
   The macro \`\cstochar``<sequence>` solves this problem. If the sequence
   is equal to a character then it expands to this character (always with
   catcode 12). If it isn't equal to a character then it expands to nothing.
   You can say \code{\\expanded{`\\cstochar\\foo}} if you want to extract
   the character code.
   \_cod -----------------------------

\_def\_cstochar#1{\_ea\_cstocharA\_meaning#1 {} {} \_fin}
\_def\_cstocharA#1 #2 #3 #4\_fin{\_isinlist{#1#2}-\_iffalse #3\_fi}

\_public \cstochar ;

   \_doc -----------------------------
   You can use expandable \`\bp``{<dimen>}` converter from
   \TeX/ `<dimen>` (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``{<expression>}` for analogical purposes.
   It expands to the value of the `<expression>` at expand processor level.
   The `<expression>` can include `+-*/^()` and decimal numbers in common syntax.
   Moreover, `a//b` means integer division and `a\%b` is remainder.
   The math functions (and pi constant) have to be prefixed by `math.`,
   because it is processed by Lua interpreter. For
   example `\expr{math.pi*math.sqrt(2)}`.
   The list of available functions is in
   \ulink[https://www.lua.org/manual/5.3/manual.html\#6.7]{Lua manual}.

   You can set the number of decimal digits after decimal point of the
   results of `\bp` and `\expr`
   by optional syntax `\bp[<digits>]{<dimen>}` and
   `\expr[<digits>]{<expression>}`. Default is \`\_decdigits`.

   The usage of prefixed versions `\_expr` or `\_bp` is more recommended
   for macro programmers because a 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#1{%
   \_directlua{tex.print(string.format('\_pcent.#1f',
               token.scan_dimen()/65781.76))}%  pt to bp conversion
}
\_def\_bp{\_isnextchar[{\_bpA}{\_bpA[\_decdigits]}}
\_def\_bpA[#1]#2{\_pttopb{#1}\_dimexpr#2\_relax}
\_def\_expr{\_isnextchar[{\_exprA}{\_exprA[\_decdigits]}}
\_def\_exprA[#1]#2{\_directlua{tex.print(string.format('\_pcent.#1f',#2))}}

\_public \expr \bp ;

   \_doc -----------------------------
   The \^`\expr` and \^`\bp` macros return their results with given number of decimal
   digits even if there are trailing zeros. There is the \^`\nnum` macro to
   \"normalize" such decimal numbers. \`\nnum``{<number>}` expands its parameter
   and removes trailing zeros after decimal point and removes the decimal point
   if nothing follows. For example, use `\nnum{\expr[10]{<expression>}}`.
   The `\nnum` macro is fully expandable.
   \_cod -----------------------------

\_def\_nnum #1{\_ea\_nnumA\_expanded{#1}.\_fin}
\_def\_nnumA #1.#2\_fin{#1\_ifx~#2~\_else \_nnumB #20.\_fin \_fi}
\_def\_nnumB #10.#2\_fin{\_ifx~#2~\_nnumC#1\_else \_nnumB #1.0.\_fin \_fi}
\_def\_nnumC #1.{\_ifx~#1~\_else .#1\_fi}
\_public \nnum ;

   \_doc ------------------
   You can write \^`\setpos``[<label>]` somewhere and the position of such
   \^`\setpos``[<label>]` can be referenced by \^`\posx``[<label>]`,
   \^`\posy``[<label>]` and \^`\pospg``[<label>]`. The first two macros
   expand to $x$ and $y$ position measured from left-bottom corner of the page
   (dimen values) and \^`\pospg[<label>]` expands to the <gpageno>, i.e.\ to
   the page number counted from one at beginning of the document.
   These values are available in the second (and more) \TeX/ run, because the
   information is saved to `.ref` file and restored from it at the beginning of
   the \TeX/ job. If these values are not known then mentioned macros expand to
   0sp, 0sp and 0. The following example implements `\linefrom[<label>]` and
   `\lineto[<label>]` macros. The line connecting these two points is drawn
   (after second \TeX/ run):
   \begtt
   \def\linefrom[#1]{\setpos[#1:f]\drawlinefromto[#1]}
   \def\lineto  [#1]{\setpos[#1:t]}
   \def\drawlinefromto[#1]{\ifnum\pospg[#1:f]>0 \ifnum\pospg[#1:f]=\pospg[#1:t]
      \pdfliteral{q 0 0 m   1 0 0 RG % << red color
         \expr{\bp{\posx[#1:t]}-\bp{\posx[#1:f]}}
         \expr{\bp{\posy[#1:t]}-\bp{\posy[#1:f]}} l S Q}\fi\fi
   }
   This is a text.\linefrom[A]\par
   This is second paragraph with a text.\lineto[A]
   Try to reverse from-to and watch the changes.
   \endtt
   The coordinates are saved to the `.ref` file in the format
   \`\_Xpos``{<label>}{<x-pos>}{<y-pos>}`. The \^`\_Xpos` macro defines
   `\_pos:<label>` as `{<x-pos>}{<y-pos>}{<total-pg>}{<rel-pg>}`.
   We need to read only given parameter by `\_posi`, `\_posii` or `\_posiii`
   auxiliary macros. The implementation of
   \`\setpos`, \`\posx` and \`\posy` macros are based on `\padsavepos`
   `\pdflastxpos` and `\pdflastypos` pdf\TeX/ primitives. The \`\pospg`
   simply reads the data from the \~`\_currpage` macro.
   \_cod ------------------

\_def\_Xpos#1#2#3{\_sxdef{_pos:#1}{{#2}{#3}\_currpage}}
\_def\_setpos[#1]{\_openref\_pdfsavepos
   \_ewref\_Xpos{{#1}\_unexpanded{{\_the\_pdflastxpos}{\_the\_pdflastypos}}}}

\_def\_posx [#1]{\_ea \_posi   \_expanded {\_trycs{_pos:#1}{{0}{}{}{}}sp}}
\_def\_posy [#1]{\_ea \_posii  \_expanded {\_trycs{_pos:#1}{{}{0}{}{}}sp}}
\_def\_pospg[#1]{\_ea \_posiii \_expanded {\_trycs{_pos:#1}{{}{}{0}{}}}}

\_def\_posi #1#2#3#4{#1}  \_def\_posii #1#2#3#4{#2}  \_def\_posiii #1#2#3#4{#3}

\_public \setpos \posx \posy \pospg ;

   \_doc ------------------
   The pair {\`\_doc` ... \`\_cod`} is used for documenting macros and to
   printing the technical documentation of the \OpTeX/. The syntax is:
   {\begtt \catcode`\<=13
   \_doc <ignored text>
   <documentation>
   \_cod <ignored text>
   \endtt
   }
   The `<documentation>` (and `<ignored text>` too) must be `<balanced text>`. 
   It means that you cannot document only the `{` but you must document the `}` too.
   \_cod ------------------

\_long\_def\_doc #1\_cod {\_skiptoeol}

   \_doc ------------------
   \`\docgen` processes lines before `\_codedecl` because the version text
   in the macro `\_<pkg>_version` can be defined here. The package
   documentation can print it. \^`\docgen` prints banner to log because TeX doesn't do it
   when command line doesn't begin with the main file name after parameters.
   \_cod ------------------

\_def\_docgen #1 {\_ea \_docgenA \_input{#1.opm}}
\_long \_def\_docgenA #1\_codedecl#2\_endcode #3\_doc {#1\_wlog{\_banner}\_skiptoeol}

\_public \docgen ;

\_endcode % -------------------------------------

2024-10-31 \_tmptoks replaced by \_repltoks in \replstring
2024-09-09 \replstring: uses \toksapp (better speed) and \empty (keeps braces)
2024-02-10 \optdef reimplemented, it can create expandable macros now.
2024-01-18 \bracedparam reimplemented.
2023-12-04 \nnum introduced
2023-01-18 \bp, \expr have optional syntax for setting dec-digits
2022-11-24 \setpos, \posx, \posy moved from OpTeX trick here
2022-11-22 \docgen writes banner to log
2022-11-20 \docgen reads lines before \_codedecl in order to define pkg. version
2022-11-18 \cstochar introduced
2022-11-13 \docgen introduced, \bracedparam corrected, \scantoeol modified
2022-11-05 \replstring can be expandable using \immediateassigned: \toksapp replaced
2022-11-03 \nospacefuturelet added.
2022-10-27 \_savemathsb ...\_restoremathsb added to \load (eg. \load[xstring])
2022-05-24 \optdef: used \csstring instead \string, bug fixed.
2021-04-25 \normalcatcodes: typo fixed
2021-04-22 \the\_currctable replaced by \the\_catcodetable, bug fixed.
2020-05-22 robust \catcode newly defined in order \catcode\string.... be possible
2020-05-03 \load macro introduced
2020-03-15 released
