/*
test5.c
L'objectif est d'avoir une soubroutine en C
qui peut être accédé depuis le langage Python.

Pour compiler depuis un Terminal :
gcc -shared -o test5.so -fPIC test5.c

Depuis Python, exécuter le script test5.py qui est donné dans un autre fichier.

Pour les types que Python reconnait et peut convertir en C :
https://www.tutorialspoint.com/python/python_further_extensions.htm
***********************************************************************/

#include "Python.h"

static PyObject *test5_sommeInv9(PyObject *self, PyObject *args) {
//===============================================================
// Définit la fonction en C qui sera appelée depuis Python
// PyObject *x_obj;  // autre possibilité.
// Somme des inverses des nombres entiers de lNbMin à lNbMax-1
// lNbMin et lNbMax sont les deux arguments.
// test5_sommeInv9(1,10) = 2.8178571428571426;  // La somme de 1 à 8
// test5_sommeInv9(10,100) = 2.063991622224917;  // La somme de 10 à 88
// test5_sommeInv9(100,1000) = 1.818871425200977;  // La somme de 1 à 8888
// test5_sommeInv9(1000,10000) = 1.633464212583175;  // La somme de 1 à 88888
long lNbMax;
long lNbMin;
long lNbr;
long lDixPow;
double vRep;

if (!PyArg_ParseTuple(args, "ll", &lNbMin, &lNbMax)) return NULL; 
//if (!PyArg_ParseTuple(args, "O", &x_obj)) return NULL;
//lNbMax = PyLong_AsLong(x_obj); // c.f. https://docs.python.org/3.3/c-api/long.html

vRep = 0.0;
lNbr=lNbMin;
while (lNbr<lNbMax) {
  if (lNbr % 10 == 9) { lNbr ++;
    if (lNbr/10 % 10 == 9) { lNbr += 10;
      if (lNbr/100 % 10 == 9) { lNbr += 100;
        // J'ai laissé quelques "if" pour comprendre la structures des tests.
        lDixPow = 1000;
        while (lNbr/lDixPow % 10 == 9) {
          lNbr += lDixPow;
          lDixPow *=10;
          }
        }      
      }
    }
  vRep = vRep + 1.0 / lNbr;
  lNbr++;
  } // while

return PyFloat_FromDouble(vRep);
// https://docs.python.org/3.3/c-api/float.html
} // test5_sommeInv9

static PyObject *test5_sommeInv(PyObject *self, PyObject *args) {
//===============================================================
// Définit la fonction en C qui sera appelée depuis Python
// PyObject *x_obj;  // autre possibilité.
// Somme des inverses des nombres entiers de lNbMin à lNbMax-1
// lNbMin et lNbMax sont les deux arguments.
long lNbMax;
long lNbMin;
long lNbr;
double vRep;

if (!PyArg_ParseTuple(args, "ll", &lNbMin, &lNbMax)) return NULL; 
//if (!PyArg_ParseTuple(args, "O", &x_obj)) return NULL;
//lNbMax = PyLong_AsLong(x_obj); // c.f. https://docs.python.org/3.3/c-api/long.html

vRep = 0.0;
for (lNbr=lNbMax-1; lNbr>=lNbMin; lNbr--) vRep = vRep + 1.0 / lNbr;

return PyFloat_FromDouble(vRep);
// https://docs.python.org/3.3/c-api/float.html
} // test5_sommeInv

// Définit l'aide associée à la fonction.
#define AIDE "sommeInv prend deux nombres entiers Nmin et Nmax en entrée\n\
et retourne la somme des inverses des entiers de 1/Nmin à 1/(Nmax-1)."

// Définit l'aide associée à la fonction.
#define AIDE9 "sommeInv9 prend deux nombres entiers Nmin et Nmax en entrée\n\
et retourne la somme des inverses des entiers de 1/Nmin à 1/(Nmax-1)\n\
dans laquelle tous les nombres contenant le chiffre 9\n\
ont été éliminés. Voici des nombres éliminés :\n\
9 ; 19 ; 29 ; 9xxx ; 19xxx ; 29xxx ; 999999.\n\
Nmin ne doit pas contenir de chiffre 9."

static PyMethodDef test5Methods[] = {
//===================================
{"sommeInv9",  test5_sommeInv9, METH_VARARGS, AIDE9}, // Est un texte d'aide. Obtenu avec : print(test5.sommeInv9.__doc__)
{"sommeInv",  test5_sommeInv, METH_VARARGS, AIDE}, // Est un texte d'aide. Obtenu avec : print(test5.sommeInv.__doc__)
{NULL, NULL, 0, NULL}  // Sentinel 
};

static struct PyModuleDef test5module = {
//=======================================
// Est une structure nécessaire pour Python ???
  PyModuleDef_HEAD_INIT,
  "test5",   /* name of module */
  NULL,  //test5_doc, /* module documentation, may be NULL */
  -1,       /* size of per-interpreter state of the module,
             or -1 if the module keeps state in global variables. */
  test5Methods
};

PyMODINIT_FUNC PyInit_test5(void) {
//=================================
// Fonction de création du module
return PyModule_Create(&test5module);
} // PyInit_test5

int main(int argc, char *argv[]) {
//================================
// Fonction principale, qui sera exécutée au chargement du module
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
  fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
  exit(1);
  }

/* Add a built-in module, before Py_Initialize */
PyImport_AppendInittab("test5", PyInit_test5);

/* Pass argv[0] to the Python interpreter */
Py_SetProgramName(program);

/* Initialize the Python interpreter.  Required. */
Py_Initialize();

/* Optionally import the module; alternatively,
   import can be deferred until the embedded script
   imports it. */
PyImport_ImportModule("test5");

PyMem_RawFree(program);
return 0;
} // main
