% \iffalse
% vim: set expandtab:
% vim: set shiftwidth=2:
% vim: set tabstop=2:
% \fi
% \iffalse meta-comment
%
% Copyright (C) 2026 by Lukas Heindl <oss.heindl+latex@protonmail.com>
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008/05/04 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Lukas Heindl.
%
% This work consists of all files listed in manifest.txt.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{hexdumptikz-common.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[2022-06-01]
%
%<*driver>
\begin{document}
  \DocInput{\jobname.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%
% \changes{v0.0.0}{2026-05-13}{First draft}
%
%</driver>
% \fi
%
% \iffalse
%<*package>
%<@@=hexdumptikz_common>
% \fi
%
% \maketitle
%
% \begin{abstract}
%   Defines helpers and variables which are use throughout the whole project.
% \end{abstract}
%
% Identify the package and give the over all version information.
%    \begin{macrocode}
\ProvidesExplPackage {hexdumptikz-common} {2026-06-20} {1.0.1}
  {Common functionality for working with hexdumps and (large) addresses}
%    \end{macrocode}
% \subsection{Conventions of this (sub-)package}
% None of the function defined in this (sub-)package makes use of the expl3 scratch-variables.
%
% The idea behind this is that this (sub-)package only defines small helper functions.
% If they would clobber expl3 scratch-variables functions calling the helpers would not be able to use the normal expl3 scratch-variables anymore.
% Thus, this (sub-)package defines its own scratch-variables if functions need them.
%
% \subsection{Implemenation}
% \subsubsection{pgfkeys}
% Set up common pgf-keys / the space where all pgfkeys will live in
%    \begin{macrocode}
\RequirePackage { pgfkeys }
\pgfkeys {
%    \end{macrocode}
% Make it a real \enquote{directory}.
% \texttt{/tikz} should also be searched to allow easily setting tikz-options.
%    \begin{macrocode}
  /hexdumptikz/.is~family,
  /hexdumptikz/.search~also = { /tikz },
%    \end{macrocode}
% Not all tikz-options work natively.
% Thus, this option allows setting options on the next \texttt{scope}.
%
% Note: All tikz drawings are wrapped in a \texttt{scope}.
% \begin{pgfkey}{/hexdumptikz/tikz}
%    \begin{macrocode}
  /hexdumptikz/next~scope/.style = { },
  /hexdumptikz/tikz/.style = { /hexdumptikz/next~scope/.append~style = { #1 } },
%    \end{macrocode}
% \end{pgfkey}
%    \begin{macrocode}
}
%    \end{macrocode}
% \subsection{Regexes}
% Set up regexes commonly used throught the whole package
%
% \begin{var}{\c_hexdumptikz_common_hex_regex}
% Matches an hexadecimal number
%    \begin{macrocode}
\regex_const:Nn
  \c_hexdumptikz_common_hex_regex
  { \A 0x[0-9a-fA-F]+ \Z }
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\c_hexdumptikz_common_hex_x_regex}
% Matches a hexadecimal number which is (optionally) accompanied by a specification of the x-index.
%    \begin{macrocode}
\regex_const:Nn
  \c_hexdumptikz_common_hex_x_regex
  { \A 0x[0-9a-fA-F]+ (?: / [0-9]+ )? \Z }
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\c_hexdumptikz_common_idx_regex}
% Matches an index specification.
% Can (optionally) be accompanied by a specification of the x-index.
%    \begin{macrocode}
\regex_const:Nn
  \c_hexdumptikz_common_idx_regex
  { \A [0-9]+ (?: / [0-9]+ )? \Z }
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\c_hexdumptikz_common_leading_hex_base_regex}
% Matches a \emph{leading} hexadecimal-base specifier.
%    \begin{macrocode}
\regex_const:Nn
  \c_hexdumptikz_common_leading_hex_base_regex
  { \A 0x }
%    \end{macrocode}
% \end{var}
%
% Generate variants of expl functions which are used often (having this in
% hexdumptikz\_common means this only runs once)
%    \begin{macrocode}
\cs_generate_variant:Nn \int_from_hex:n { f }
\cs_generate_variant:Nn \msg_critical:nnn { nnV }
\cs_generate_variant:Nn \msg_critical:nnnn { nnVV , nneV }
\cs_generate_variant:Nn \msg_critical:nnnnn { nnVeV }
\cs_generate_variant:Nn \msg_warning:nnn { nnV }
%    \end{macrocode}
%
% \subsection{Variables used by multiple other (sub-)packages}
% Define the variables only once here.
% Note that this does not mean the variables are global.
%
% \begin{var}{\l_hexdumptikz_common_nodename_prefix_tl}
% Prefix for nodenames generated
%    \begin{macrocode}
\tl_new:N \l_hexdumptikz_common_nodename_prefix_tl
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\l_hexdumptikz_common_input_file_str}
% Path to the input file from which to read the hexdump from
%    \begin{macrocode}
\str_new:N \l_hexdumptikz_common_input_file_str
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\l_hexdumptikz_common_bytes_per_row_int}
% Number of bytes shown in one row.
% (optionally) enforced by the parser and used at some other locations too.
%    \begin{macrocode}
\int_new:N \l_hexdumptikz_common_bytes_per_row_int
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\l_hexdumptikz_common_addr_len_int}
% padd addresses to this length (only refers to the hex-digits without the leading 0x)
%    \begin{macrocode}
\int_new:N \l_hexdumptikz_common_addr_len_int
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\g_hexdumptikz_common_cur_offsets_prop}
% Stores a mapping \emph{addr/offset} to \emph{out-index}.
% Required to draw from one row to the row above/below since this package avoids calculating on the addresses.

% needs to be global since the assignment happens inside a tikz-scope so
% otherwise the assignment is gone when the prop is needed
%    \begin{macrocode}
\prop_new:N \g_hexdumptikz_common_cur_offsets_prop
%    \end{macrocode}
% \end{var}
%
% \subsection{Functions}
% \begin{fn}{\hexdumptikz_common_pad_left:Nnn}
% \begin{sideeffects}
%   \sclobber & \sdir & \texttt{l\_tmpb\_int} \\
% \end{sideeffects}
% \begin{args}
%   1 & \ain/\aout & tl variable to work on \\
%   2 & \ain & target length (int expression) \\
%   3 & \ain & padding token (should have length 1) \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_common_pad_left:Nnn #1 #2 #3
{
%    \end{macrocode}
% calculate the needed padding (target - current length)
%    \begin{macrocode}
  \int_set:Nn \l_tmpb_int { #2 - \tl_count:N #1 }
%    \end{macrocode}
% perform the padding
%    \begin{macrocode}
  \int_compare:nNnT { \l_tmpb_int } > { 0 }
  {
    \tl_put_left:Ne
      #1
      { \prg_replicate:nn { \l_tmpb_int } { #3 } }
  }
}
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\hexdumptikz_common_pad_address:N}
% \begin{sideeffects}
%   \sclobber & \sindir & \texttt{l\_tmpa\_int} \\
%   \sclobber & \sindir & \texttt{l\_tmpb\_int} \\
% \end{sideeffects}
% \begin{args}
%   1 & \ain/\aout & address (tl) \\
%   - & \ain & \texttt{l\_hexdumptikz\_common\_addr\_len\_int} \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_common_pad_address:N #1
{
%    \end{macrocode}
% Remove leading \texttt{0x} (hex base indicator)
%    \begin{macrocode}
  \regex_replace_once:NnNTF
    \c_hexdumptikz_common_leading_hex_base_regex
    { }
    #1
  {
%    \end{macrocode}
% Pad the address and place back the hex base indicator
%    \begin{macrocode}
    \hexdumptikz_common_pad_left:Nnn
      #1
      { \l_hexdumptikz_common_addr_len_int }
      { 0 }
    \tl_put_left:Nn #1 { 0x }
  }
  {
%    \end{macrocode}
% Pad the address (no base-indicator present before -> none present after)
%    \begin{macrocode}
    \hexdumptikz_common_pad_left:Nnn
      #1
      { \l_hexdumptikz_common_addr_len_int }
      { 0 }
  }
}
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\hexdumptikz_common_parse_bool:Nn}
% \begin{sideeffects}
% \end{sideeffects}
% \begin{args}
%   1 & \aout & bool var (bool) \\
%   2 & \ain & user input \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_common_parse_bool:Nn #1 #2
{
  \str_case:enF { \tl_trim_spaces:n { #2 } }
  {
    { true }  { \bool_set_true:N  #1 }
    { false } { \bool_set_false:N #1 }
  }
  {
    \msg_critical:nne { hexdumptikz } { invalid-boolean } { #2 }
  }
}
%    \end{macrocode}
% \end{fn}
% \iffalse
%</package>
% \fi
%
% \Finale
