\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{malagasy-numberwords}[2026/09/05 v0.1.0 Nombres cardinaux malgaches]
%%
%% 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: https://www.latex-project.org/lppl.txt
%% This work has the LPPL maintenance status 'maintained'.
%% The Current Maintainer of this work is the malagasy-numberwords
%% contributors (RALAHADY Bruno Bakys, TOTOHASINA André).
%% This work consists of the files malagasy-numberwords.sty and
%% fc-malagasy-numberwords.def.
%%

% Port LaTeX (e-TeX/\numexpr, macros classiques) de la grammaire cardinale validee
% dans le paquet Python malagasy-numberwords (formal-grammar.md, regles R1-R8, R7').
% Portee : 0 <= n <= 2147483647 environ (limite des compteurs TeX 32 bits -- NOTE :
% plus restrictif que cardinal.py, qui n'a pas cette limite ; voir README de ce
% dossier). Separation donnees/moteur : tables lexicales en tete de fichier.

% ---------------------------------------------------------------------------
% Donnees linguistiques (cf. rules/mutation.py)
% ---------------------------------------------------------------------------
\newcommand{\mnw@setword}[3]{\expandafter\def\csname mnw@#1@#2\endcsname{#3}}

\mnw@setword{unit}{1}{iray}
\mnw@setword{unit}{2}{roa}
\mnw@setword{unit}{3}{telo}
\mnw@setword{unit}{4}{efatra}
\mnw@setword{unit}{5}{dimy}
\mnw@setword{unit}{6}{enina}
\mnw@setword{unit}{7}{fito}
\mnw@setword{unit}{8}{valo}
\mnw@setword{unit}{9}{sivy}

\mnw@setword{tens}{1}{folo}
\mnw@setword{tens}{2}{roapolo}
\mnw@setword{tens}{3}{telopolo}
\mnw@setword{tens}{4}{efapolo}
\mnw@setword{tens}{5}{dimampolo}
\mnw@setword{tens}{6}{enimpolo}
\mnw@setword{tens}{7}{fitopolo}
\mnw@setword{tens}{8}{valopolo}
\mnw@setword{tens}{9}{sivifolo}

\mnw@setword{hundreds}{1}{zato}
\mnw@setword{hundreds}{2}{roanjato}
\mnw@setword{hundreds}{3}{telonjato}
\mnw@setword{hundreds}{4}{efajato}
\mnw@setword{hundreds}{5}{dimanjato}
\mnw@setword{hundreds}{6}{eninjato}
\mnw@setword{hundreds}{7}{fitonjato}
\mnw@setword{hundreds}{8}{valonjato}
\mnw@setword{hundreds}{9}{sivinjato}

\newcommand{\mnw@unit}[1]{\csname mnw@unit@#1\endcsname}
\newcommand{\mnw@unitcompound}[1]{\ifnum#1=1 iraika\else\mnw@unit{#1}\fi}
\newcommand{\mnw@tens}[1]{\csname mnw@tens@#1\endcsname}
\newcommand{\mnw@hundreds}[1]{\csname mnw@hundreds@#1\endcsname}

% ---------------------------------------------------------------------------
% Registres de travail
% ---------------------------------------------------------------------------
\newcount\mnw@du   % chiffre des unites
\newcount\mnw@dt   % chiffre des dizaines
\newcount\mnw@dh   % chiffre des centaines
\newcount\mnw@dm   % chiffre des milliers
\newcount\mnw@dy   % chiffre des myriades (dizaines de mille)
\newcount\mnw@dl   % chiffre des centaines de mille (lakh)

\newcount\mnw@divA
\newcount\mnw@divB
\newcount\mnw@divC
\newcount\mnw@divD
\newcount\mnw@divE
\newcount\mnw@divF

\newcommand{\mnw@setdigits}[1]{%
  % ATTENTION : \numexpr arrondit la division au plus proche (pas de troncature) --
  % on utilise donc \divide sur des \count, qui tronque, comme le veut une
  % division entiere classique.
  \mnw@divA=#1\relax \divide\mnw@divA by 10\relax
  \mnw@divB=#1\relax \divide\mnw@divB by 100\relax
  \mnw@divC=#1\relax \divide\mnw@divC by 1000\relax
  \mnw@divD=#1\relax \divide\mnw@divD by 10000\relax
  \mnw@divE=#1\relax \divide\mnw@divE by 100000\relax
  \mnw@divF=#1\relax \divide\mnw@divF by 1000000\relax
  \mnw@du=\numexpr (#1)-\mnw@divA*10 \relax
  \mnw@dt=\numexpr \mnw@divA-\mnw@divB*10 \relax
  \mnw@dh=\numexpr \mnw@divB-\mnw@divC*10 \relax
  \mnw@dm=\numexpr \mnw@divC-\mnw@divD*10 \relax
  \mnw@dy=\numexpr \mnw@divD-\mnw@divE*10 \relax
  \mnw@dl=\numexpr \mnw@divE-\mnw@divF*10 \relax
}

% ---------------------------------------------------------------------------
% R5 : bloc bas (unites, dizaines, centaines) -- construit dans \mnw@blocklow
% ---------------------------------------------------------------------------
\newcommand{\mnw@blocklow}{}
\newcommand{\mnw@computeblocklow}{%
  \def\mnw@prefix{}% p0 (+eventuellement p1), avant jonction avec p2
  \ifnum\mnw@du>0
    \ifnum\mnw@dt>0
      \ifnum\mnw@dt=1
        \edef\mnw@prefix{\mnw@unitcompound{\the\mnw@du}\space ambin'ny\space\mnw@tens{\the\mnw@dt}}%
      \else
        \edef\mnw@prefix{\mnw@unitcompound{\the\mnw@du}\space amby\space\mnw@tens{\the\mnw@dt}}%
      \fi
    \else
      \edef\mnw@prefix{\mnw@unitcompound{\the\mnw@du}}%
    \fi
  \else
    \ifnum\mnw@dt>0
      \edef\mnw@prefix{\mnw@tens{\the\mnw@dt}}%
    \fi
  \fi
  \ifnum\mnw@dh>0
    \ifx\mnw@prefix\@empty
      \edef\mnw@blocklow{\mnw@hundreds{\the\mnw@dh}}%
    \else
      \ifnum\mnw@dh=1
        \edef\mnw@blocklow{\mnw@prefix\space amby\space\mnw@hundreds{\the\mnw@dh}}%
      \else
        \edef\mnw@blocklow{\mnw@prefix\space sy\space\mnw@hundreds{\the\mnw@dh}}%
      \fi
    \fi
  \else
    \let\mnw@blocklow\mnw@prefix
  \fi
}

% ---------------------------------------------------------------------------
% R6/R8 : terme d'echelle (arivo/alina/hetsy). #1=chiffre #2=mot #3=1 si forme
% nue pour d=1 (arivo/zato), 0 sinon (alina/hetsy exigent "iray"). Resultat
% dans \mnw@scaleterm (vide si #1=0).
% ---------------------------------------------------------------------------
\newcommand{\mnw@scaleterm}[3]{%
  \ifnum#1=0
    \let\mnw@scaleterm@out\@empty
  \else
    \ifnum#1=1
      \if1#3
        \edef\mnw@scaleterm@out{#2}%
      \else
        \edef\mnw@scaleterm@out{iray\space#2}%
      \fi
    \else
      \edef\mnw@scaleterm@out{\mnw@unit{#1}\space#2}%
    \fi
  \fi
}

% Concatene jusqu'a 4 parties (deja calculees, eventuellement vides) avec "sy"
\newcommand{\mnw@joinsy}[4]{%
  \def\mnw@acc{}%
  \renewcommand{\mnw@joinone}[1]{%
    \ifx##1\@empty\else
      \ifx\mnw@acc\@empty \edef\mnw@acc{##1}\else\edef\mnw@acc{\mnw@acc\space sy\space##1}\fi
    \fi
  }%
  \mnw@joinone{#1}\mnw@joinone{#2}\mnw@joinone{#3}\mnw@joinone{#4}%
}
\newcommand{\mnw@joinone}[1]{}

% ---------------------------------------------------------------------------
% below_tapitrisa : 0 <= n <= 999999, sans terme "tapitrisa". Resultat dans
% \mnw@belowtap.
% ---------------------------------------------------------------------------
\newcommand{\mnw@belowtapitrisa}[1]{%
  \ifnum#1=0
    \let\mnw@belowtap\@empty
  \else
    \mnw@setdigits{#1}%
    \mnw@computeblocklow
    \mnw@scaleterm{\the\mnw@dm}{arivo}{1}%
    \let\mnw@scaleA\mnw@scaleterm@out
    \mnw@scaleterm{\the\mnw@dy}{alina}{0}%
    \let\mnw@scaleB\mnw@scaleterm@out
    \mnw@scaleterm{\the\mnw@dl}{hetsy}{0}%
    \let\mnw@scaleC\mnw@scaleterm@out
    \mnw@joinsy{\mnw@blocklow}{\mnw@scaleA}{\mnw@scaleB}{\mnw@scaleC}%
    \let\mnw@belowtap\mnw@acc
  \fi
}

% ---------------------------------------------------------------------------
% R7' : nombre complet, cycle recursif au-dela de tapitrisa. Resultat dans
% \mnw@fullresult. NOTE : #1 doit tenir dans un compteur TeX (< 2^31 environ) --
% c'est une limite d'IMPLEMENTATION (pas linguistique), plus restrictive que
% cardinal.py (entiers Python illimites). Voir README de ce dossier.
% ---------------------------------------------------------------------------
\newcount\mnw@topn
\newcount\mnw@topm
\newcount\mnw@topr
\newcommand{\mnw@fullnumber}[1]{%
  \mnw@topn=#1\relax
  \ifnum\mnw@topn=0
    \def\mnw@fullresult{aotra}%
  \else
    \mnw@topm=\mnw@topn\relax \divide\mnw@topm by 1000000\relax
    \mnw@topr=\numexpr\mnw@topn-\mnw@topm*1000000\relax
    \mnw@belowtapitrisa{\the\mnw@topm}%
    \let\mnw@mresult\mnw@belowtap
    \mnw@belowtapitrisa{\the\mnw@topr}%
    \let\mnw@rresult\mnw@belowtap
    \ifx\mnw@mresult\@empty
      \let\mnw@fullresult\mnw@rresult
    \else
      \ifnum\mnw@topm=1
        \def\mnw@tapterm{iray\space tapitrisa}%
      \else
        \edef\mnw@tapterm{\mnw@mresult\space tapitrisa}%
      \fi
      \ifx\mnw@rresult\@empty
        \let\mnw@fullresult\mnw@tapterm
      \else
        \edef\mnw@fullresult{\mnw@rresult\space sy\space\mnw@tapterm}%
      \fi
    \fi
  \fi
}

% ---------------------------------------------------------------------------
% Garde-fou : les compteurs TeX sont limites a environ +-2^31 (~2 147 483 647).
% Plutot que de laisser TeX echouer avec un message cryptique ("Number too big")
% pour un nombre plus grand, on detecte les cas manifestement hors de portee via
% un comptage de caracteres (fiable sans avoir a parser le nombre comme entier)
% et on emet une erreur de paquet explicite.
% ---------------------------------------------------------------------------
\newcount\mnw@strlen
\newcommand{\mnw@strlenloop}[1]{%
  \ifx#1\@nil\else
    \advance\mnw@strlen by 1
    \expandafter\mnw@strlenloop
  \fi
}
\newcommand{\mnw@checkrange}[1]{%
  \mnw@strlen=0
  \expandafter\mnw@strlenloop#1\@nil
  \ifnum\mnw@strlen>10
    \PackageError{malagasy-numberwords}
      {Nombre trop grand (#1) pour les compteurs TeX natifs (limite ~2^31)}
      {Ce port LaTeX ne peut pas depasser environ 2 147 483 647 : c'est une
       limite d'implementation des compteurs TeX, pas une limite linguistique
       (voir cardinal.py, qui n'a pas cette contrainte). Utilisez le paquet
       Python malagasy-numberwords pour ce nombre.}%
  \fi
}

% ---------------------------------------------------------------------------
% Interface publique
% ---------------------------------------------------------------------------
\newcommand{\MalagasyNumberToWords}[1]{\mnw@checkrange{#1}\mnw@fullnumber{#1}\mnw@fullresult}

% ---------------------------------------------------------------------------
% Pourcentage (R-CUR-like : [cardinal] isan-jato, cf. percentage.py)
% ---------------------------------------------------------------------------
\newcommand{\MalagasyPercentageToWords}[1]{%
  \mnw@checkrange{#1}%
  \mnw@fullnumber{#1}%
  \edef\mnw@percentageresult{\mnw@fullresult\space isan-jato}%
  \mnw@percentageresult
}

% ---------------------------------------------------------------------------
% Monnaie (seul MGA/ariary est sourcé, cf. currency.py et currency-model.md)
% ---------------------------------------------------------------------------
\newcommand{\MalagasyCurrencyToWords}[1]{%
  \mnw@checkrange{#1}%
  \mnw@fullnumber{#1}%
  \edef\mnw@currencyresult{\mnw@fullresult\space ariary}%
  \mnw@currencyresult
}

% ---------------------------------------------------------------------------
% Decimal ([entier] faingo [decimale], cf. decimal.py et decimal-model.md).
% #1 = partie entiere, #2 = partie decimale (sans le zero non significatif
% -- limite connue, identique a decimal.py).
% ---------------------------------------------------------------------------
\newcommand{\MalagasyDecimalToWords}[2]{%
  \mnw@checkrange{#1}%
  \mnw@fullnumber{#1}%
  \edef\mnw@decimal@int{\mnw@fullresult}%
  \mnw@checkrange{#2}%
  \mnw@fullnumber{#2}%
  \edef\mnw@decimalresult{\mnw@decimal@int\space faingo\space\mnw@fullresult}%
  \mnw@decimalresult
}

% ---------------------------------------------------------------------------
% Ordinal (voalohany=1er ; faha- + cardinal sinon, avec fusion+elision R-ORD3
% SEULEMENT si le cardinal est un seul mot, sinon faha reste separe -- R-ORD5,
% cf. ordinal.py et ordinal-model.md).
% ---------------------------------------------------------------------------
\def\mnw@dosplit#1 #2\mnw@splitend{%
  \def\mnw@firstword@out{#1}%
  \def\mnw@restword@out{#2}%
}
\newcommand{\mnw@splitfirstword}[1]{\expandafter\mnw@dosplit#1 \mnw@splitend}

\def\mnw@extractfirstchar#1#2\mnw@nilend{\def\mnw@firstchar@out{#1}}
\def\mnw@lettere{e}

\newcommand{\mnw@ordinal}[1]{%
  \ifnum#1=1
    \def\mnw@ordinalresult{voalohany}%
  \else
    \mnw@checkrange{#1}%
    \mnw@fullnumber{#1}%
    \edef\mnw@ord@cardinal{\mnw@fullresult}%
    \mnw@splitfirstword{\mnw@ord@cardinal}%
    \ifx\mnw@restword@out\@empty
      \expandafter\mnw@extractfirstchar\mnw@firstword@out e\mnw@nilend
      \ifx\mnw@firstchar@out\mnw@lettere
        \edef\mnw@ordinalresult{fah\mnw@firstword@out}%
      \else
        \edef\mnw@ordinalresult{faha\mnw@firstword@out}%
      \fi
    \else
      \edef\mnw@ordinalresult{faha\space\mnw@ord@cardinal}%
    \fi
  \fi
}
\newcommand{\MalagasyOrdinalToWords}[1]{\mnw@ordinal{#1}\mnw@ordinalresult}

% ---------------------------------------------------------------------------
% Date ([jour ordinal] ny volana [mois] [annee], cf. date.py et date-model.md).
% Meme mise en garde : seule la structure est confirmee, jour/annee epeles
% restent des extrapolations.
% ---------------------------------------------------------------------------
\mnw@setword{month}{1}{Janoary}
\mnw@setword{month}{2}{Febroary}
\mnw@setword{month}{3}{Martsa}
\mnw@setword{month}{4}{Aprily}
\mnw@setword{month}{5}{Mey}
\mnw@setword{month}{6}{Jona}
\mnw@setword{month}{7}{Jolay}
\mnw@setword{month}{8}{Aogositra}
\mnw@setword{month}{9}{Septambra}
\mnw@setword{month}{10}{Oktobra}
\mnw@setword{month}{11}{Novambra}
\mnw@setword{month}{12}{Desambra}
\newcommand{\mnw@month}[1]{\csname mnw@month@#1\endcsname}

\newcommand{\MalagasyDateToWords}[3]{%
  % #1 = jour, #2 = mois (1-12), #3 = annee
  \ifcase#2\relax
    \PackageError{malagasy-numberwords}{Mois invalide (0)}{Le mois doit etre entre 1 et 12.}%
  \or\edef\mnw@date@month{\mnw@month{1}}%
  \or\edef\mnw@date@month{\mnw@month{2}}%
  \or\edef\mnw@date@month{\mnw@month{3}}%
  \or\edef\mnw@date@month{\mnw@month{4}}%
  \or\edef\mnw@date@month{\mnw@month{5}}%
  \or\edef\mnw@date@month{\mnw@month{6}}%
  \or\edef\mnw@date@month{\mnw@month{7}}%
  \or\edef\mnw@date@month{\mnw@month{8}}%
  \or\edef\mnw@date@month{\mnw@month{9}}%
  \or\edef\mnw@date@month{\mnw@month{10}}%
  \or\edef\mnw@date@month{\mnw@month{11}}%
  \or\edef\mnw@date@month{\mnw@month{12}}%
  \else
    \PackageError{malagasy-numberwords}{Mois invalide (#2)}{Le mois doit etre entre 1 et 12.}%
  \fi
  \mnw@ordinal{#1}%
  \let\mnw@date@day\mnw@ordinalresult
  \mnw@checkrange{#3}%
  \mnw@fullnumber{#3}%
  \edef\mnw@dateresult{\mnw@date@day\space ny\space volana\space\mnw@date@month\space\mnw@fullresult}%
  \mnw@dateresult
}

% ---------------------------------------------------------------------------
% Chargement de la couche fmtcount. Le fichier d'interoperabilite est nomme
% "fc-malagasy-numberwords.def" (et non "fc-malagasy.def") pour rester
% facilement identifiable comme appartenant a ce paquet dans l'ensemble de
% l'archive CTAN/TeX Live -- mais cela signifie que la commande standard de
% fmtcount, "\FCloadlang{malagasy}", qui cherche exclusivement un fichier
% nomme "fc-<langue>.def", NE TROUVE PAS ce fichier. Cette macro reproduit
% l'essentiel du mecanisme interne de \FCloadlang (fmtcount.sty) en ciblant
% le nom de fichier reellement utilise par ce paquet.
\newcommand{\MalagasyLoadFmtcountSupport}{%
  \makeatletter
  \@ifpackageloaded{fmtcount}{%
    \@set@mulitling@fmtcount
    \def\languagename{malagasy}%
    \InputIfFileExists{fc-malagasy-numberwords.def}%
      {%
        \ifdefempty{\fc@languages}%
          {\gdef\fc@languages{malagasy}}%
          {\gappto\fc@languages{,malagasy}}%
        \gdef\fc@mainlang{malagasy}%
      }%
      {\PackageError{malagasy-numberwords}{fc-malagasy-numberwords.def not found}%
        {Make sure fc-malagasy-numberwords.def is on TeX's search path.}}%
  }{%
    \PackageError{malagasy-numberwords}{fmtcount is not loaded}%
      {Load \string\usepackage{fmtcount} before \string\MalagasyLoadFmtcountSupport.}%
  }%
  \makeatother
}
