% !TeX encoding = UTF-8
% Ce fichier contient le code commenté de l'extension "simplekv"
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                    %
\def\skvname                  {simplekv}                             %
\def\skvver                     {0.2c}                               %
%                                                                    %
\def\skvdate                 {2023/10/02}                            %
%                                                                    %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% --------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% 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.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
% --------------------------------------------------------------------
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Christian Tellechea
% email: unbonpetit@netc.fr
%        Commentaires, suggestions et signalement de bugs bienvenus !
%        Comments, bug reports and suggestions are welcome.
% Copyright: Christian Tellechea 2017-2023
% --------------------------------------------------------------------
% L'extension simplekv est composée des 5 fichiers suivants :
%   - code               : simplekv            (.tex et .sty)
%   - manuel en français : simplekv-fr         (.tex et .pdf)
%   - fichier lisezmoi   : README
% --------------------------------------------------------------------

%##########################################
%################ Préalable ###############
%##########################################
\csname skvloadonce\endcsname
\let\skvloadonce\endinput
\ifdefined\skvfromSTY\else
	\immediate\write -1 {%
		Package: \skvname\space\skvdate\space v\skvver\space Simple keyval package (CT)%
	}%
\fi
%##########################################
%############ Gestion catcodes ############
%##########################################
\begingroup
	\def\X#1{\catcode\number`#1=\number\catcode`#1\relax}
	\expandafter\xdef\csname skv_restorecatcode\endcsname{\X\,\X\=\X\_}
\endgroup
\catcode`\_ = 11 \catcode`\, = 12 \catcode`\= = 12
%##########################################
%############ Macros auxilaires ###########
%##########################################
\chardef\skv_stop 0
\long\def\skv_first#1#2{#1}
\long\def\skv_second#1#2{#2}
\long\def\skv_antefi#1\fi{\fi#1}
\long\def\skv_gob#1{}
\long\def\skv_exe#1{#1}
\expandafter\def\expandafter\skv_gobspace\space{}% pour garder la compatibilité
\long\def\skv_eearg#1#2{\expandafter\expandafter\expandafter\skv_earg_i\expandafter\expandafter\expandafter{#2}{#1}}
\long\def\skv_earg_i#1#2{#2{#1}}
\def\skv_ifcsname#1{\ifcsname#1\endcsname\expandafter\skv_first\else\expandafter\skv_second\fi}
\long\def\skv_ifempty#1{\skv_ifempty_i#1\_nil\_nil\skv_second\skv_first\__nil}%
\long\def\skv_ifempty_i#1#2\_nil#3#4#5\__nil{#4}
\def\skv_stripsp#1{%
	\long\def\skv_stripsp##1##2{\expanded{\skv_stripsp_i\_marksp##2\__nil\_marksp#1\_marksp\_nil{##1}}}%
	\long\def\skv_stripsp_i##1\_marksp#1##2\_marksp##3\_nil{\skv_stripsp_ii##3##1##2\__nil#1\__nil\_nil}%
	\long\def\skv_stripsp_ii##1#1\__nil##2\_nil{\skv_stripsp_iii##1##2\_nil}%
	\long\def\skv_stripsp_iii##1##2\__nil##3\_nil##4{\unexpanded{##4{##2}}}%
}
\skv_stripsp{ }
\def\skv_error#1{\errmessage{Package \skvname\space Error: #1.}}
%##########################################
%########## Macros de définition ##########
%##########################################
\def\setKVdefault{\let\skv_find_kv_ii\skv_find_kv_nocode\skv_readKV\skv_exe}
\def\setKV       {\let\skv_find_kv_ii\skv_find_kv_nocode\skv_readKV\skv_gob}
\def\defKV       {\let\skv_find_kv_ii\skv_find_kv_code  \skv_readKV\skv_gob}
\long\def\skv_readKV#1[#2]#3{%
	#1{\expandafter\def\csname skv_[#2]\endcsname{#3}}% exécute (si \setKVdefault) ou pas
	\def\skv__currentname{#2}%
	\skv_readKV_i#3,\skv_end,%
}
\long\def\skv_readKV_i#1,{%
	\skv_stripsp\skv_ifempty{#1}% Bugfix 0.2c : on ignore un truc vide entre 2 virgules
		{%
		\skv_readKV_i
		}
		{%
		\skv_readKV_ii\skv_find_kv#1=true=\_nil\skv_find_kv\skv_end\__nil% si #1=\skv_end ne rien faire sinon \skv_find_kv#1=true=\_nil
		}%
}
\long\def\skv_readKV_ii#1\skv_find_kv\skv_end#2\__nil{#1}
\long\def\skv_find_kv#1={%
	\edef\skv__currentkey{_[\skv__currentname]_\skv_stripsp\detokenize{#1}}%
	\skv_find_kv_i{}%
}
\long\def\skv_find_kv_i#1=#2\_nil{%
	\expandafter\skv_stripsp\expandafter\skv_find_kv_ii\expandafter{\skv_gob#1}%
	\skv_readKV_i
}
\long\def\skv_find_kv_nocode#1{%
	\expandafter\def\csname skv\skv__currentkey\endcsname{#1}% stocker la valeur
	\ifcsname skvcode\skv__currentkey\endcsname
		\skv_antefi\csname skvcode\skv__currentkey\endcsname{#1}%
	\fi
}
\long\def\skv_find_kv_code{%
	\expandafter\def\csname skvcode\skv__currentkey\endcsname##1%
}
\def\restoreKV[#1]{%
	\skv_ifcsname{skv_[#1]}
		{%
		\skv_eearg{\setKV[#1]}{\csname skv_[#1]\endcsname}%
		}
		{%
		\skv_error{Undefined or not saved set of keys "#1"}%
		}%
}
\let\useKVdefault\restoreKV
%##########################################
%############## Macro \useKV ##############
%##########################################
\def\useKV[#1]{\romannumeral\skv_stripsp{\useKV_i[#1]}}
\def\useKV_i[#1]#2{%
	\ifcsname skv_[#1]_\detokenize{#2}\endcsname
		\expandafter\expandafter\expandafter\skv_stop\csname skv_[#1]_\detokenize{#2}\expandafter\endcsname
	\else
		\skv_stop
		\skv_error{Key "\detokenize{#2}" not defined in group of keys "#1"}%
	\fi
}
%##########################################
%############# Macros de test #############
%##########################################
\def\ifboolKV[#1]{\romannumeral\skv_stripsp{\ifboolKV_i[#1]}}
\def\ifboolKV_i[#1]#2{%
	\ifcsname skv_[#1]_\detokenize{#2}\endcsname
		\expandafter\expandafter\expandafter\ifboolKV_ii\csname skv_[#1]_\detokenize{#2}\expandafter\endcsname
		\expandafter\ifboolKV_ii
	\else
		\skv_stop
		\skv_error{Key "\detokenize{#2}" not defined in group of keys "#1"}%
		\expandafter\skv_second
	\fi
}
\def\ifboolKV_ii#1\ifboolKV_ii{%% Cette macro teste si #1, qui est une <valeur>, vaut "true" ou "false"
	\skv_ifargtrue{#1}
		{%
		\expandafter\skv_stop
		\skv_first
		}
		{%
		\skv_ifargfalse{#1}
			{%
			\expandafter\skv_stop
			\skv_second
			}
			{%
			\skv_stop
			\skv_error{Value "\detokenize{#1}" is not a valid boolean}%
			\skv_second
			}%
		}%
}
\def\testboolKV{\romannumeral\skv_stripsp\testboolKV_i}% macro publique qui teste si #1 est <true> ou <false>, erreur sinon
\def\testboolKV_i#1{%
	\skv_ifempty{#1}
		{%
		\skv_stop
		\skv_error{Empty argument is not a valid boolean}
		\skv_second
		}
		{%
		\ifboolKV_ii#1\ifboolKV_ii
		}%
}
\def\skv_ifargtrue#1{\skv_ifargtrue_i#1true\_nil}
\def\skv_ifargtrue_i#1true#2\_nil{%
	\skv_ifempty{#1}
		{%
		\skv_ifargtrue_ii#2\_nil
		}
		{%
		\skv_second
		}%
}
\def\skv_ifargtrue_ii#1true#2\_nil{\skv_ifempty{#1#2}}
\def\skv_ifargfalse#1{\skv_ifargfalse_i#1false\_nil}
\def\skv_ifargfalse_i#1false#2\_nil{%
	\skv_ifempty{#1}
		{%
		\skv_ifargfalse_ii#2\_nil
		}
		{%
		\skv_second
		}%
}
\def\skv_ifargfalse_ii#1false#2\_nil{\skv_ifempty{#1#2}}
%##########################################
%############# Macro \showKV ##############
%##########################################
\def\showKV[#1]{\skv_stripsp{\showKV_i[#1]}}
\def\showKV_i[#1]#2{%
	\edef\skv__currentkey{_[#1]_\detokenize{#2}}%
	\immediate\write-1 {%
		^^J%
		Key\space\space\detokenize{[#1]#2 -> }%
		\skv_ifcsname{skv\skv__currentkey}
			{%
			\showKV_ii{skv\skv__currentkey}%
			^^J%
			Code \detokenize{[#1]#2 -> }%
			\skv_ifcsname{skvcode\skv__currentkey}
				{%
				\showKV_ii{skvcode\skv__currentkey}%
				}
				{%
				not defined%
				}%
			}
			{%
			not defined%
			}%
	^^J%
	\relax}%
}
\def\showKV_ii#1{%
		\expandafter\expandafter\expandafter
	\skv_show\expandafter
	\meaning\csname#1\endcsname
}
\def\skv_show#1->{}
\skv_restorecatcode
\endinput

Versions :
 _____________________________________________________________________________
| Version |    Date    | Changements                                          |
|-----------------------------------------------------------------------------|
|   0.1   | 08/08/2017 | Première version                                     |
|-----------------------------------------------------------------------------|
|   0.2   | 27/04/2020 | - Un <code> peut être assigné à une <clé>            |
|         |            | - Correction de bugs                                 |
|         |            | - Optimisations                                      |
|-----------------------------------------------------------------------------|
|   0.2a  | 01/10/2022 | - vieux bug corrigé : \useKV envoie désormais une    |
|         |            |   erreur si une clé n'est pas définie                |
|         |            | - la valeur n'est dépouillée que d'une accolade (et  |
|         |            |   non pas de 2 comme auparavant)                     |
|         |            | - quelques petits nettoyages, code en UTF8           |
|-----------------------------------------------------------------------------|
|   0.2b  | 30/10/2022 | - messages d'erreur mieux formatés                   |
|         |            | - <clé> détokénisée dans \ifboolKV et \showKV pour   |
|         |            |   être cohérent avec \setKV et \useKV                |
|-----------------------------------------------------------------------------|
|   0.2c  | 02/10/2023 | - bug corrigé : si un item <clé=val> est vide, il est|
|         |            |   ignoré                                             |
|         |            | - quelques remaniements du code                      |
|-----------------------------------------------------------------------------|