% Ce fichier contient le code TeX de l'extension "autoaligne"
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                    %
\def\aanom                   {autoaligne}                            %
\def\aaversion                   {1.3}                               %
%                                                                    %
\def\aadate                  {2017/02/11}                            %
%                                                                    %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% --------------------------------------------------------------------
% 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@openmailbox.org
%        Commentaires, suggestions et signalement de bugs bienvenus !
% --------------------------------------------------------------------
% L'extension autoaligne est compos\'ee des 5 fichiers suivants :
%   - code               : listofitems            (.tex et .sty)
%   - manuel en francais : listofitems-fr         (.tex et .pdf)
%   - fichier lisezmoi   : README
% --------------------------------------------------------------------

\expandafter\edef\csname aa_restaure_catcode\endcsname{\catcode\number`\_=\number\catcode`\_\relax}
\catcode`\_11
\def\aa_listofitems_version_mini{1.1}

\ifdefined\PackageError
	\def\aa_erreur#1{\PackageError\aanom{#1}{Read the manual}}% pour LaTeX
\else
	\def\aa_erreur#1{\errmessage{Package \aanom\space Error: #1^^J}}% pour TeX
\fi

\begingroup
	\edef\__tempa{\meaning\eTeXversion}\edef\__tempb{\string\eTeXversion}%
	\ifx\__tempa\__tempb\endgroup
	\else\endgroup
		\aa_erreur{Vous n'utilisez pas un moteur eTeX, \aanom\space ne peut donc pas fonctionner}%
		\expandafter\aa_restaure_catcode\expandafter\endinput
	\fi

\unless\ifdefined\loiname
	\input listofitems.tex
\fi
\ifdim\loiver pt<\aa_listofitems_version_mini pt
	\aa_erreur{\loiname\space est en version v\loiver\space et \aanom\space requiert la v\aa_listofitems_version_mini\space ou plus}%
	\expandafter\aa_restaure_catcode\expandafter\endinput
\fi

\let\aa_sep_terme_vide\relax
\let\aa_sep_membre_vide\relax
\def\aa_compose_en_mode_math#1{$\relax#1$}
\def\aa_devdev_arg#1{\loi_exparg{\loi_exparg{#1}}}
\def\aavcoeff#{\def\aa_v_coeff}
\newtoks\aa_liste_tokens
\def\aa_ajoute_au_toks#1{\aa_liste_tokens\expandafter{\the\aa_liste_tokens#1}}
\def\aa_developpe_et_ajoute_au_toks#1{\loi_exparg\aa_ajoute_au_toks{#1}}
\def\egaldevantmembrevide{\chardef\aa_egal_devant_membre_vide}
\egaldevantmembrevide=0% pas de signe = devant un membre vide
\def\aa_def_tok#1#2{\let#1= #2\empty}\aa_def_tok\aa_tok_espace{ }
\def\aa_si_prochain_tok_est#1#2#3{%
	\aa_def_tok\aa_test_tok{#1}\def\aa_code_vrai{#2}\def\aa_code_faux{#3}%
	\aa_si_prochain_tok_est_i
}
\def\aa_si_prochain_tok_est_i{\futurelet\aa_prochain_token\aa_si_prochain_tok_est_ii}
\def\aa_si_prochain_tok_est_ii{%
	\loi_ifx{\aa_prochain_token\aa_tok_espace}
		{\afterassignment\aa_si_prochain_tok_est_i\let\aa_prochain_token= }
		{\loi_ifx{\aa_prochain_token\aa_test_tok}\aa_code_vrai\aa_code_faux}%
}
\def\aa_si_commence_par#1#2{%
	\def\aa_si_commence_par_i##1#2##2\_nil{\loi_exparg\loi_ifempty{\loi_gobarg##1}}%
	\aa_si_commence_par_i\relax#1#2\_nil
}
\def\definirseparateurs#1#2#3{%
	\loi_ifempty{#1}
		{\aa_erreur{Separateur <vide> entre lignes non permis, "\string\\" retenu}%
		\definirseparateurs{\\}{#2}{#3}%
		}
		{\loi_ifempty{#2#3}
			{\aa_erreur{Separateurs de membre <vide> et de terme <vide> : "=" et "+||-" retenus}%
			\definirseparateurs{#1}{=}{+||-}%
			}
			{\loi_ifempty{#2}
				{\definirseparateurs{#1}{\aa_sep_membre_vide}{#3}%
				}
				{\loi_ifempty{#3}
					{\def\aa_liste_separateurs{#1_#2_\aa_sep_terme_vide}}
					{\def\aa_liste_separateurs{#1_#2_#3}}%
				}%
			}%
		}%
}
\definirseparateurs{\\}{=}{+||-}% s\'eparateurs par d\'efaut
\def\definirespacements{\aa_si_prochain_tok_est[\definirespacements_i{\definirespacements_i[,]}}
\def\definirespacements_i[#1,#2]#3#4{% #3=espace avant & apr\`es s\'eparateurs 2   #4=espace avant & apr\`es s\'eparateurs 3
	\edef\aa_insere_espacement_avant{\aa_devdev_arg\loi_ifempty{\loi_removeextremespaces{#1}}{}{\hskip\glueexpr#1\relax}}%
	\edef\aa_insere_espacement_apres{\aa_devdev_arg\loi_ifempty{\loi_removeextremespaces{#2}}{}{\hskip\glueexpr#2\relax}}%
	\edef\aa_espacement_signe{\dimexpr\loi_ifempty{#3}{0pt}{#3}\relax}%
	\edef\aa_espacement_terme{\dimexpr\loi_ifempty{#4}{0pt}{#4}\relax}%
}
\definirespacements[,]{0pt}{0pt}% espacements par d\'efaut
\def\aa_si_contient_moins#1{\aa_si_contient_moins_i||#1||||-||\_nil}% "||-||" est-il dans #1 ?
\def\aa_si_contient_moins_i#1||-||#2\_nil{\loi_ifempty{#2}\loi_second\loi_first}
\def\aa_trouver_moins_dans_separateur_de_termes{\expandafter\aa_trouver_moins_dans_separateur_de_termes_i\aa_liste_separateurs\_nil}
\def\aa_trouver_moins_dans_separateur_de_termes_i#1_#2_#3\_nil{%
	\aa_si_contient_moins{#2}
		{2}
		{\aa_si_contient_moins{#3}{3}{-1}}%
}
\def\aa_ajoute_si_existe#1{\ifcsname#1\endcsname\loi_argcsname\aa_developpe_et_ajoute_au_toks{#1}\fi}
\def\aa_alignement_signe{\hfil\kern\aa_espacement_signe${}##{}$\kern\aa_espacement_signe\hfil}% pour "=", "+" ou "-"
\def\aa_alignement_terme_c{\hfil\kern\aa_espacement_terme$##$\kern\aa_espacement_terme\hfil}
\def\aa_alignement_terme_d{\hfil\kern\aa_espacement_terme$##$\kern\aa_espacement_terme}
\def\aa_alignement_terme_g{\kern\aa_espacement_terme$##$\kern\aa_espacement_terme\hfil}
\def\autoaligne{%
	\relax\iffalse{\fi\ifnum0=`}\fi
	\begingroup
	\aa_si_prochain_tok_est[
		{\autoaligne_crochet}
		{\aa_si_prochain_tok_est({\autoaligne_paren}{\autoaligne_i[*d](c)}}%
}
\def\autoaligne_crochet[#1]{\aa_si_prochain_tok_est({\autoaligne_i[#1]}{\autoaligne_i[#1](c)}}
\def\autoaligne_paren(#1){\aa_si_prochain_tok_est[{\autoaligne_permute_argopt(#1)}{\autoaligne_i[*d](#1)}}
\def\autoaligne_permute_argopt(#1)[#2]{\autoaligne_i[#2](#1)}
\def\autoaligne_i[#1]{%
	\loi_ifempty{#1}
		{\aa_erreur{Consigne d'alignement vide, "*d" est retenue}%
		\autoaligne_i[*d]%
		}
		{\def\aa_consigne_alignement_general{}%
		\aa_si_commence_par{#1}*
			{\aa_trouve_consigne_alignement_general#1d\_nil}
			{\aa_trouve_consigne_alignement_par_membre{#1}}%
		\autoaligne_ii
		}%
}
\def\autoaligne_ii(#1){%
	\loi_ifempty{#1}
		{\aa_erreur{Consigne de position vide, "c" est retenue}
		\autoaligne_ii(c)%
		}
		{\edef\aa_consigne_alignement_vertical{\aa_verifie_consigne_alignement chb{#1}}%
		\loi_ifnum{\aa_consigne_alignement_vertical=0 }
			{\aa_erreur{Consigne d'alignement vertical "\detokenize{#1}" non reconnue, "c" est retenue}%
			\def\aa_consigne_alignement_general{1}%
			}%
			{}%
		\autoaligne_iii
		}%
}
\def\aa_trouve_consigne_alignement_general*#1#2\_nil{%
	\loi_ifnum{\aa_verifie_consigne_alignement cdg{#1}=0 }
		{\aa_erreur{Consigne d'alignement "\detokenize{#1}" non reconnue, "d" est retenue}%
		\def\aa_consigne_alignement_general{d}%
		}
		{\def\aa_consigne_alignement_general{#1}}%
}
\def\aa_trouve_consigne_alignement_par_membre#1{\aa_trouve_consigne_alignement_par_membre_i1#1\loi_quark}
\def\aa_trouve_consigne_alignement_par_membre_i#1#2{%
	\loi_ifx{#2\loi_quark}
		{}
		{\loi_ifnum{\aa_verifie_consigne_alignement cdg{#2}=0 }
			{\aa_erreur{Consigne d'alignement "\detokenize{#2}" non reconnue, "d" est retenue}%
			\loi_argcsname\def{aa_alignement_membre[#1]}{d}%
			}
			{\loi_argcsname\def{aa_alignement_membre[#1]}{#2}}%
		\loi_exparg\aa_trouve_consigne_alignement_par_membre_i{\number\numexpr#1+1}%
		}%
}
\def\aa_verifie_consigne_alignement#1#2#3#4{% #1,#2,#3=lettres admises  #4=consigne c, d ou g --> renvoie un nombre (1,2 ou 3=ok, 0=erreur)
	0\if\string #1\expandafter\loi_firsttonil\detokenize{#4x}\_nil1\else
	\if\string #2\expandafter\loi_firsttonil\detokenize{#4x}\_nil2\else
	\if\string #3\expandafter\loi_firsttonil\detokenize{#4x}\_nil3\fi\fi\fi
}
\def\autoaligne_iii#1{% #1=tableau
	\def\-{-}\def\+{+}%
	\loi_exparg{\setsepchar[_]}{\aa_liste_separateurs}%
	\edef\aa_numero_separateur_contenant_signe_moins{\aa_trouver_moins_dans_separateur_de_termes}%
	\def\readlist_iii##1||##2\_nil##3{% red\'efinir \readlist_iii pour que
		\loi_ifnum{\loi_nestcnt=\aa_numero_separateur_contenant_signe_moins\relax}% si la profondeur est celle o\`u il a y a un "-"
			{\aa_si_commence_par{##30}{-}% et que la liste restant \`a examiner commence par "-" alors
				{\loi_exparg{\readlist_iv1}{\expandafter\-\loi_gobarg##3##1}}% remplacer ce "-" par \-
				{\readlist_iv1{##3##1}}%
			}
			{\readlist_iv1{##3##1}}%
	}%
	\reademptyitems
	\readlist\aa_termes{#1}%
	\let\aa_nombre_de_lignes\aa_termeslen% nombre de lignes
	\def\aa_nombre_de_membres{0}%
	\loi_fornum\aa_ligne_index=1to\aa_termeslen\do{% pour chaque ligne
		\ifnum\csname aa_termeslen[\aa_ligne_index,0]\endcsname>\aa_nombre_de_membres
			\loi_argcsname\let\aa_nombre_de_membres{aa_termeslen[\aa_ligne_index,0]}% mettre \`a jour le nombre max de membres
		\fi
		\loi_fornum\aa_membre_index=1to\csname aa_termeslen[\aa_ligne_index,0]\endcsname\do{% pour chaque membre
			\loi_argcsname\let\aa_nombre_de_termes_courant{aa_termeslen[\aa_ligne_index,\aa_membre_index,0]}%
			\ifcsname aa_nbtermes_\aa_membre_index\endcsname% mettre \`a jour le nombre max de termes dans ce membre
				\ifnum\aa_nombre_de_termes_courant>\csname aa_nbtermes_\aa_membre_index\endcsname\relax
					\loi_argcsname\let{aa_nbtermes_\aa_membre_index}\aa_nombre_de_termes_courant
				\fi
			\else
				\loi_argcsname\let{aa_nbtermes_\aa_membre_index}\aa_nombre_de_termes_courant
			\fi
		}%
	}%
	\aa_liste_tokens{}%
	% construction du pr\'eambule de l'alignement
	\loi_fornum\aa_membre_index=1to\aa_nombre_de_membres\do{%
		\loi_fornum\aa_terme_index=1to\csname aa_nbtermes_\aa_membre_index\endcsname\do{%
			\ifx\aa_consigne_alignement_general\empty
				\ifcsname aa_alignement_membre[\aa_membre_index]\endcsname
					\loi_argcsname\aa_developpe_et_ajoute_au_toks{aa_alignement_terme_\csname aa_alignement_membre[\aa_membre_index]\endcsname}% terme
				\else
					\aa_erreur{Pas assez de consignes d'alignement, "d" est retenue}%
					\aa_developpe_et_ajoute_au_toks{\aa_alignement_terme_d}%
				\fi
			\else
				\loi_argcsname\aa_developpe_et_ajoute_au_toks{aa_alignement_terme_\aa_consigne_alignement_general}%
			\fi
			\ifnum\aa_terme_index<\csname aa_nbtermes_\aa_membre_index\endcsname\relax
				\aa_developpe_et_ajoute_au_toks{\expandafter&\aa_alignement_signe&}% signe
			\fi
		}%
		\ifnum\aa_membre_index<\aa_nombre_de_membres\relax
			\aa_developpe_et_ajoute_au_toks{\expandafter&\aa_alignement_signe&}% \'egalit\'e
		\fi
	}%
	\aa_ajoute_au_toks\cr
	% fin du pr\'eambule, construction du corps de l'alignement
	\loi_fornum\aa_ligne_index=1to\aa_termeslen\do{% pour chaque ligne,
		\loi_fornum\aa_membre_index=1to\aa_nombre_de_membres\do{% chaque membre
			\def\aa_terme_non_vide_vu{0}%
			\loi_fornum\aa_terme_index=1to\csname aa_nbtermes_\aa_membre_index\endcsname\do{% et chaque terme
				\aa_ajoute_si_existe{aa_termes[\aa_ligne_index,\aa_membre_index,\aa_terme_index]}% ajouter le terme
				\ifcsname aa_termes[\aa_ligne_index,\aa_membre_index,\aa_terme_index]\endcsname% si le terme existe
					\loi_argcsname\loi_exparg\loi_ifempty{aa_termes[\aa_ligne_index,\aa_membre_index,\aa_terme_index]}
						{}
						{\def\aa_terme_non_vide_vu{1}}% et qu'il est non vide, s'en souvenir
				\fi
				\ifnum\aa_terme_index<\csname aa_nbtermes_\aa_membre_index\endcsname\relax% passer \`a l'ajout \'eventuel du signe + ou -
					\aa_ajoute_au_toks&%
					\loi_ifnum{% ins\'erer signe si index correct ET terme suivant non vide ET (un terme non vide a \'et\'e rencontr\'e OU signe="-"
						\numexpr1\loi_ifnum{\aa_terme_index<\csname aa_termeslen[\aa_ligne_index,\aa_membre_index,0]\endcsname\space}10%
						\loi_exparg{\loi_exparg\loi_ifempty}{\csname aa_termes[\aa_ligne_index,\aa_membre_index,\number\numexpr\aa_terme_index+1]\endcsname}01%
						+\aa_terme_non_vide_vu
						+\if\string-\expandafter\loi_firsttonil\detokenize\expandafter\expandafter\expandafter{\csname aa_termessep[\aa_ligne_index,\aa_membre_index,\aa_terme_index]\endcsname}\_nil1\else0\fi>111 }
						{\aa_ajoute_si_existe{aa_termessep[\aa_ligne_index,\aa_membre_index,\aa_terme_index]}}%
						{\aa_ajoute_au_toks{\hphantom{\hbox{${}+{}$}}}}% sinon, encombrement horizontal
					\aa_ajoute_au_toks&%
				\fi
			}%
		\ifnum\aa_membre_index<\aa_nombre_de_membres\relax
			\aa_ajoute_au_toks&% puis, ajouter le signe "=" si...
			\ifcsname aa_termes[\aa_ligne_index,\number\numexpr\aa_membre_index+1]\endcsname% le terme suivant existe
				\ifnum\aa_egal_devant_membre_vide=0 % et si on ne tient compte des = devant les membres vides
						\loi_argcsname\loi_exparg\loi_ifempty{aa_termes[\aa_ligne_index,\number\numexpr\aa_membre_index+1]}
						{}% et si'il n'est pas vide
						{\aa_ajoute_si_existe{aa_termessep[\aa_ligne_index,\aa_membre_index]}}%
				\else
					\aa_ajoute_si_existe{aa_termessep[\aa_ligne_index,\aa_membre_index]}%
				\fi
			\fi
			\aa_ajoute_au_toks&%
		\fi
		}%
		\aa_ajoute_au_toks\cr
	}%
	\aa_ajoute_au_toks\crcr
	\aa_insere_espacement_avant
	\ifcase\aa_consigne_alignement_vertical\relax
	\or
		\let\aa_boite_externe\vcenter
		\csname\ifmmode loi_identity\else aa_compose_en_mode_math\fi\expandafter\endcsname
	\or
		\let\aa_boite_externe\vtop
		\expandafter\loi_identity
	\or
		\let\aa_boite_externe\vbox
		\expandafter\loi_identity
	\fi
		{\aa_boite_externe{%
				\lineskiplimit0pt
				\lineskip0pt
				\baselineskip\aa_v_coeff\baselineskip
				\halign\expandafter{\the\aa_liste_tokens}%
				}%
		}%
	\aa_insere_espacement_apres
	\endgroup
	\ifnum`{=0\fi\iffalse}\fi% cette ligne manquait, voir http://tex.stackexchange.com/questions/353258/gather-and-autoaligne-errors
}
\aavcoeff{1}% par d\'efaut
\aa_restaure_catcode
\endinput

v1.0  01/09/2016
  - premi\`ere version publique
v1.1  06/10/2016
  - correction d'un bug dans \autoaligne_iii qui mangeait le
    \endgroup final
v1.2  22/10/2016
  - possibilit\'e de d\'efinir les s\'eparateurs
  - possibilit\'e de d\'efinir les espaces additionnelles
    autour des s\'eparateurs
  - possibilit\'e de d\'efinir les espaces ins\'er\'ees avant et
    apr\`es l'alignement
v1.3  11/02/2017
    le \iffalse{\fi\ifnum0=`}\fi n'\'est pas \'equilibr\'e par
    \ifnum`{=0\fi\iffalse}\fi ce qui provoque un bug lorsque
    \autoaligne est appel\'e dans un alignement