
// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.


# include <iostream>
using namespace std;  //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include "UtilLecture.h"
#include "Sortie.h"

#include <fstream> 
#include <cstdlib>
#include <iomanip>
#include <algorithm>
#include "ParaGlob.h"
#include "CharUtil.h"
#include "TypeQuelconque.h"
#include <limits>


// méthodes de classe internes 
// surcharge de l'operateur d'ecriture
ostream &  operator << (ostream & sort,const  UtilLecture::Position_BI & a)
  { // écriture du type
    sort << "incre_posi_(nb_et_posi): ";
    // les données
    sort << a.num_incr << " " ;
    // pour la position c'est plus délicat et peut-être pas portable ??
    // normalement on a la position et un paramètre state ?
    // que l'on sauvegarde manuellement because pas de surcharge actuellement
    // () donne normalement l'ofset, et la fonction state() donne le state (?)
    streamoff errt = (streamoff) a.position; // utilisation de la conversion de type forcée
    #ifndef ENLINUX_STREAM
       sort << errt  << " " << a.position.state() << " ";
    #else
       sort << errt;
    #endif      
    return sort;      
  };
  // surcharge de l'operator de lecture
istream & operator >> (istream & entree, UtilLecture::Position_BI& a)
  { // vérification du type
    string type;
    entree >> type;
    if (type != "incre_posi_(nb_et_posi):")
      {Sortie (1);
       return entree;
      };
    // entrée des données  
    entree >> a.num_incr;
    // en fait pour la position du stream il y a deux grandeurs (sur mac)
    // et on est obligé d'utiliser la surcharge standard de copie (?)
    // pour remplir a !! car 
    // streampos contiend deux éléments sur mac !! qui sont en private !!
    // sur unix !!!!! a priori un seul élément
   
    #ifndef ENLINUX_STREAM
      {long long  titi1;
       long long int titi2;
       entree >> titi1 >> titi2; 
       streampos ee(titi1); ee.state(titi2);
       a.position = ee;
      }
    #else
      {long long  titi1;
       entree >> titi1 ;
       streampos ee(titi1); 
       a.position = ee;
      };
    #endif         
    
    return entree;      
  };
 
 // CONSTRUCTEURS :
 // il y a passage éventuelle d'argument : argc=le nombre d'argument
 // argv : donne un tableau correspondant de mots clés
 // ---> lecture de la racine du nom du fichier princial
 UtilLecture::UtilLecture (int argc, const char * argv[]) :
        longueur(2500)  // longueur maxi du tableau de travail
        ,nomCourant(),nomRacine(),ptrfich(NULL),tablcar(NULL),tableau(NULL),lec_ent_info(-10)
        ,ent_BI(NULL),sort_BI(NULL),ent_PI(NULL),sort_PI(NULL),liste_posi_BI()
        ,dernier_increment_lu(0),ptrcommandefich(NULL),ptrschemaXMLfich(NULL) 
        ,sort_princ_vrml(NULL),sort_legende_vrml(NULL),sort_princ_maple(NULL)
        ,sort__temps_cpu(NULL)
        ,sort_princ_geomview(NULL),sort_legende_geomview(NULL)
        ,sort_initial_Gid(NULL), sort_resultat_Gid(NULL)
        ,ent_CommandeVisu(NULL),sort_CommandeVisu(NULL)
        ,tablcarCVisu(NULL),tableauCVisu(NULL),maille1(NULL)
        ,ptnomCVisu(NULL),pteurnom(NULL),nomRacineCVisu()
        ,sort_initial_Gmsh(NULL),sort_resultat_Gmsh(),noms_base_fichiers_gmsh()
		      ,tabMultiLignes(NULL)
        #ifdef UTILISATION_MPI
          // cas d'un  calcul //, num du cpu en cours dans les opérations
          ,num_cpu_en_cours_BI(0) // d'i/o sur .BI et .PI
        #endif

  {  bool fr = ParaGlob::Francais(); // pour simplifier
     // information concernant l'entrée des données
     if (fr){cout << "\n -- initialisation de l'entree des donnees  ";}
			  else   {cout << "\n -- initialisation of the data input   ";}; 
     // tout d'abord on regarde qu'elle etait le nom utilise lors de la derniere
     // execution du programme
     ifstream auxi("ancienNom");
     string ancien; bool ouverture_ancien=false;
     // on regarde l'utilisation de la sauvegarde de l'ancienne racine
     if (!auxi)
         //cas d'une erreur a l'ouverture  parce que pas de fichier          
         // lecture de la racine du nom du fichier princial
       { ouverture_ancien=false;}
     else
       { auxi >> ancien; // lecture de l'ancien nom                
         // lecture de la racine du nom du fichier princial
         if (ancien.length() == 0)
           {ouverture_ancien=false;}
         else
           {ouverture_ancien=true;};
       };
     // on regarde maintenant s'il y a passage  du nom dans les arguments
     lec_ent_info=-10; // init
     bool entree_par_argument= EntreeParArgument(argc,argv);
     // on regarde s'il y a eu pb et que  rien n'est initialisé, il faut arrêter
     if (entree_par_argument)
        if (lec_ent_info==-100) return; 

     // s'il n'y a pas eu d'entrée par argument on effectue une entrée interactive
     if (!entree_par_argument)
         EntreeInteractive(ancien,ouverture_ancien);
     // on regarde s'il y a eu pb et que  rien n'est initialisé, il faut arrêter
     if (lec_ent_info==-100) return; 
     
     
     // traitement en fonction de lec_ent_info
     switch (lec_ent_info)
	    { case -12 : // --------- cas de la construction shema XML d'entrée de données .info ----
         { if (fr) {cout << " racine du nom  de fichier principal = " << nomRacine << endl;}
				       else    {cout << " first part of the name for the principal file  = " << nomRacine << endl;};
           // stockage du nom de fichier courant ouvert      
           nomCourant = nomRacine;      
           break;
         }
	      case -11 : // --------- cas de la construction d'un fichier de commande .info ----
         { if (fr) {cout << " racine du nom  de fichier principal = " << nomRacine << endl;}
				       else    {cout << " first part of the name for the principal file  = " << nomRacine << endl;};
           // stockage du nom de fichier courant ouvert      
           nomCourant = nomRacine;      
           break;
         }
       case 0 : case 3: // ------------ cas d'une entrée via un fichier .info ----------
         { if (fr) {cout << " racine du nom  de fichier principal = " << nomRacine << endl;}
				       else    {cout << " first part of the name for the principal file  = " << nomRacine << endl;};
           // stockage du nom de fichier courant ouvert      
           nomCourant = nomRacine;           		    
           break;
         }
       case  1 : // --------------cas d'une entrée via un fichier .base-info------------
         {  if (fr) {cout << "\n entrer le nom du fichier .base-info : (" << ancien <<").base-info \n"
                          << " ou repondre o ou 0 si l'on veut l'ancien nom (le dernier utilise)\n";}
						      else   	{cout << "\n enter the name of the file  .base-info : (" << ancien <<").base-info \n"
                            << " or answer y or Y if you want the old name (last used)  \n";};		 
            nomRacine= lect_chaine();
            if ((nomRacine == "0")||(nomRacine == "o")||(nomRacine == "y")||(nomRacine == "Y"))
               {  nomRacine = ancien;
                  // stockage du nom de fichier courant ouvert      
                  nomCourant = nomRacine;      
               };
            break;
         }
       case  2 : // --------------cas d'une entrée via un serveur .base-info------------
         {  if (fr) {cout << " cas actuellement non traite = entree de donnees via un serveur base-info \n";}
				        else    {cout << " at this time, not possible = input data with a server for <base-info> file\n";};
            cout << " UtilLecture::UtilLecture () " << endl;
			         Sortie(1);
            break;
         }
       default :
		    	  if (fr) {cout << "\nErreur : valeur incorrecte de lec_ent_info =" << lec_ent_info << "   !\n";}
				     else    {cout << "\nError : incorrect value for  lec_ent_info =" << lec_ent_info << "   !\n";};
			      cout << "UtilLecture::UtilLecture () " << endl;
			      Sortie(1);
     };
           
     // sauvegarde de la racine dans le cas où on ne veut pas un schéma
     auxi.close();
     if (lec_ent_info != -12)
       {ofstream auxo("ancienNom");
        if (auxo)
           {auxo << nomRacine;} // sauvegarde de la racine
        else 
           {if (fr) {cout << "pb en ouverture en ecriture du fichier <ancienNom> , on continu quand meme ";}
					       else    {cout << "problem in the opening of the file <ancienNom> but  we continue as we can !!  ";};
						     };  
       };                  
                        
     tablcar = new char [longueur] ; // def du tableau de travail
     tableau = new char [longueur] ; // def du tableau intermediaire
			  tabMultiLignes = new char [longueur]; // def du tableau pour le stockage de plusieurs lignes           
     // def du flot d'entree filtree en memoire
     // utilise pour les conversions de type en lecture
     #ifndef ENLINUX_STREAM
          entree = new istringstream(tablcar,longueur) ; 
     #else 
          entree = new istrstream(tablcar,longueur) ; 
     #endif                
     // adressage du pointeur de nomRacine
     pteurnom = (char*)nomRacine.c_str();
     nomRacineCVisu = nomRacine; // par défaut le nom de la racine de .CVisu est identique
     ptnomCVisu = (char*)nomRacineCVisu.c_str(); 
      
     // lecture des commandes de visualisation (même technique en simplifié que pour .info)
     tablcarCVisu = new char [longueur] ; // def du tableau de travail
     tableauCVisu = new char [longueur] ; // def du tableau intermediaire           
     // def du flot d'entree filtree en memoire
     // utilise pour les conversions de type en lecture
     #ifndef ENLINUX_STREAM
          entCVisu = new istringstream(tablcarCVisu,longueur) ; 
     #else 
          entCVisu = new istrstream(tablcarCVisu,longueur) ; 
     #endif                            

  };

 // DESTRUCTEUR :
 UtilLecture::~UtilLecture ()
        {  if (ptrfich!= NULL) {delete ptrfich;ptrfich=NULL;}
           if (ptrcommandefich!= NULL) {delete ptrcommandefich;ptrcommandefich=NULL;}
           if (ptrschemaXMLfich!= NULL) {delete ptrschemaXMLfich;ptrschemaXMLfich=NULL;}
           // ****** pour l'instant la suite ne marche pas ?? mais ce n'est pas normal 
           // ****** erreur bizarre
// c'est sans doute qu'il y a une confusion entre des vrais tableaux c de charactères = chaine de caractère
// et le tableau du type caractère et je me demande s'il faut des destructeurs pour ce type de tableau
//// = modif nov 2009 avec le passage sur linux .... il faudra regarder cela du plus près ***************



      //     if (tablcar != NULL) {delete [] tablcar;tablcar=NULL;}
////           if (tableau != NULL) {delete [] tableau;tableau=NULL;};
      //     if (tablcarCVisu != NULL) {delete [] tablcarCVisu;tablcarCVisu=NULL;}
////           if (tableauCVisu != NULL) {delete [] tableauCVisu;tableauCVisu=NULL;};
////			  if (tabMultiLignes != NULL) {delete [] tabMultiLignes; tabMultiLignes=NULL;};
           Fermeture_base_info();
           Fermeture_fichier_principal_vrml();
           Fermeture_fichier_principal_vrml();
           Fermeture_fichier_principal_maple();
           Fermeture_fichier_principal_geomview();
           Fermeture_fichier_principal_geomview();
           Fermeture_fichier_initial_Gid();
           Fermeture_fichier_resultat_Gid();
           Fermeture_fichier_initial_Gmsh();
           Fermeture_TousLesFichiersResultats_Gmsh();
           Fermeture_fichier_temps_cpu();
        } ;
  
// ouverture  du fichier principal principal de lecture
int  UtilLecture::OuvrirFichier ()
  { char nomm[132];
    char*fileName  = nomm;
    bool fr = ParaGlob::Francais(); // pour simplifier
    strcpy(fileName, pteurnom);
    // traitement en fonction de lec_ent_info
    switch (lec_ent_info)
	    { case -12 : // --------- cas de la construction shema XML d'entrée de données .info ----
        { ptrschemaXMLfich = new ofstream(strcat(fileName,".xsd"));
          if(!(ptrschemaXMLfich->is_open())) 
            { if (fr){cout << "\n erreur en ouverture du fichier " << fileName << endl;}
							       else   {cout << "\n error in opening of the file   " << fileName << endl;};
              Sortie(1);
            }; 
          break;    
        }
	      case -11 : // ------------ cas d'une sortie via un fichier .info ----------
        {// on va essayer d'éviter d'écraser un fichier déjà existant.
         // a) on essaie d'ouvrir le fichier en lecture
         ifstream * essai = new ifstream(strcat(fileName,".info"));
         string rep(" ");
         if (essai->is_open())
          {// l'ouverture est ok ==> il existe déjà
           cout << "\n ****** attention, le fichier "<<fileName
                << " existe deja !!\n voulez-vous vraiment l'ecraser ? (o / n) "<<flush;
           rep = lect_o_n(false);
           Minuscules(rep);
           if (rep != "o")
             { cout << "\n pas d'ecrasement ==> donc on termine l'execution ";
               Sortie(1);
             }
           else // sinon on veut vraiment l'écraser
            {essai->close();
            }; // on ferme le fichier en lecture et on continue
          };
         // cas où le fichier n'existe pas ou qu'on veut écraser un fichier existant
//         ptrcommandefich = new ofstream(strcat(fileName,".info"));
         ptrcommandefich = new ofstream(fileName); // fileName contient déjà le suffixe .info
          if(!(ptrcommandefich->is_open()))
            { if (fr){cout << "\n erreur en ouverture du fichier " << fileName << endl;}
              else {cout << "\n error in opening of the file   " << fileName << endl;};
              Sortie(1);
            }; 
          break;    
        }
       case 0 : // ------------ cas d'une entrée via un fichier .info ----------
        { ptrfich = new ifstream(strcat(fileName,".info"));
          if(!(ptrfich->is_open())) 
            { if (fr){cout << "\n erreur en ouverture du fichier " << fileName << endl;}
							       else   {cout << "\n error in opening of the file   " << fileName << endl;};
              Sortie(1);
            };  
          // initialisation de la liste chainee d'ouverture de fichier
          string no(fileName);
          maille1 = new PointFich (NULL,ptrfich,no);
          break;
        }
       case  1 : // --------------cas d'une entrée via un fichier .base-info------------
        { Ouverture_base_info("lecture"); 
          break;
        }
       case  2 : // --------------cas d'une entrée via un serveur .base-info------------
        { if (fr){cout << " cas actuellement non traite = entree de données via un serveur base-info \n";}
				      else   {cout << " case not possible for the moment = input data with a server for  <base-info> file \n";};
          cout << " UtilLecture::OuvrirFichier () " << endl;
			       Sortie(1);
          break;
        }
       default :
		    	  if (fr){cout << "\nErreur : valeur incorrecte de lec_ent_info =" << lec_ent_info << "   !\n";}
				     else   {cout << "\nerror : incorrect value of  lec_ent_info =" << lec_ent_info << "   !\n";};
				     cout << "UtilLecture::OuvrirFichier () " << endl;
				     Sortie(1);
     };
    return lec_ent_info;                    
  };
 
// raffraichir le dernier fichier de lecture .info en cours
// il y a fermeture puis ouverture au même endroit du fichier  .info
void UtilLecture::Raffraichir_pointInfo()
  { // on commence par récupérer l'adresse actuelle dans le fichier
    streampos position = maille1->sauvePtr->tellg();
    // puis le nom
    string nom_du_pointInfo = maille1->nom;
    // on ferme le fichier
    delete  maille1->sauvePtr;
    // on le reouvre
    maille1->sauvePtr = new ifstream(nom_du_pointInfo.c_str());
    bool fr = ParaGlob::Francais(); // pour simplifier
    if(!(maille1->sauvePtr->is_open())) 
     { if (fr){cout << "\n erreur en re-ouverture du fichier " << nom_du_pointInfo << endl;}
					  else   {cout << "\n error in re-opening of the file   " << nom_du_pointInfo << endl;};
       Sortie(1);
     };  
    // on se repositionne dans le fichier
    maille1->sauvePtr->clear(); // on remet à 0 les bits de contrôle au cas où
    maille1->sauvePtr->seekg(position, ios::beg);
  };

// fermeture du fichier .info
void UtilLecture::fermeture_pointInfo()
  {  if (ptrcommandefich!= NULL) {delete ptrcommandefich;ptrcommandefich=NULL;}
   };
   
// fermeture du fichier SchemaXML
void UtilLecture::fermetureSchemaXML()
  {  if (ptrschemaXMLfich!= NULL) {delete ptrschemaXMLfich;ptrschemaXMLfich=NULL;}
   };
          
// ouverture  du fichier de copie des infos lue par le programme
        void  UtilLecture::OuvrirCopie()
          { char noml[132];
            char*fileName  = noml;
            
            strcpy(fileName, pteurnom);
            copie = new ofstream(strcat(fileName,".copie"));
            
            if(!(copie->is_open())) 
              { cout << "\n erreur en ouverture du fichier de copie " << fileName << endl;
                Sortie(1);
              };  
          };          
//fermeture  du fichier de copie des infos lue par le programme
        void  UtilLecture::FermerCopie()
          { delete copie;
          };  
       
// lecture d'une nouvelle ligne de donnee utilisable pour l'entree de donnee
        void UtilLecture::NouvelleDonnee()
         {
           int indicboucle = 0; // indicateur pour sortir de la boucle globale
//           int indicfichier = 0 ; // indicateur pour la fermeture de fichier
           try
             {
               while (indicboucle == 0)
                { 
                  Nouvel_enreg(); // lecture d'un enreg ds le fichier courant
                  char* pentree ; // position du carractere "<"
                  pentree = strchr(tablcar,'<');  // position eventurelle de "<"
                  if ( pentree != NULL)
                     { pentree++;NouveauFichier(pentree); }
                  else
                     { indicboucle = 1; };
                 };
               // on repositionne le flot au debut du tableau de carractere  
               // ouverture du flot a la longueur sans blanc
               delete entree;  
               #ifndef ENLINUX_STREAM
                   entree = new istringstream(tablcar,strlen (tablcar)) ; 
               #else 
                   entree = new istrstream(tablcar,(long)strlen (tablcar)) ;
               #endif    
            }
            // sortie normale du programme  
           catch (ErrNouvelEnreg erreur)
              {  if ( erreur.lecture == 1) // on a atteind une fin de fichier
                   { int indic; FermetureFichier(indic);
                     if (indic == 0) // cas ou il reste encore un fichier ouvert
                     { NouvelleDonnee();  // appel recursif de la lecture
                       // on repositionne le flot au debut du tableau de carractere
                       // ouverture du flot a la longueur sans blanc
                       delete entree;
                       #ifndef ENLINUX_STREAM
                          entree = new istringstream(tablcar,strlen (tablcar)) ;
                       #else 
                          entree = new istrstream(tablcar,(long)strlen (tablcar)) ;
                       #endif    
                      }
                     else
                       throw (ErrNouvelleDonnee(1)); // fin de tous les fichiers atteind
                    }    
                 else
                   throw (ErrNouvelleDonnee(-1)); // erreur en fermeture de fichier
               }    
         }; 


// idem avec la méthode NouvelleDonnee()
// mais sans ouverture de fichier automatique
// le signe < est conservé dans la ligne
void UtilLecture::NouvelleDonneeSansInf()
  {
    int indicboucle = 0; // indicateur pour sortir de la boucle globale
//    int indicfichier = 0 ; // indicateur pour la fermeture de fichier
    try
      {
        while (indicboucle == 0)
         { 
           Nouvel_enreg(); // lecture d'un enreg ds le fichier courant
           indicboucle = 1;
          };
        // on repositionne le flot au debut du tableau de carractere  
        // ouverture du flot a la longueur sans blanc
        delete entree;  
        #ifndef ENLINUX_STREAM
            entree = new istringstream(tablcar,strlen (tablcar)) ; 
        #else 
            entree = new istrstream(tablcar,(long)strlen (tablcar)) ;
        #endif    
      }
     // sortie normale du programme  
    catch (ErrNouvelEnreg erreur)
       {  if ( erreur.lecture == 1) // on a atteind une fin de fichier
            { int indic; FermetureFichier(indic);
              if (indic == 0) // cas ou il reste encore un fichier ouvert
                { NouvelleDonnee();  // appel recursif de la lecture
                  // on repositionne le flot au debut du tableau de carractere
                  // ouverture du flot a la longueur sans blanc
                  delete entree;
                  #ifndef ENLINUX_STREAM
                     entree = new istringstream(tablcar,strlen (tablcar)) ;
                  #else 
                     entree = new istrstream(tablcar,(long)strlen (tablcar)) ;
                  #endif    
                }
              else
                throw (ErrNouvelleDonnee(1)); // fin de tous les fichiers atteind
            }
          else
            throw (ErrNouvelleDonnee(-1)); // erreur en fermeture de fichier
       };
  };

 // Retour du flot au debut de l'enregistrement
 void UtilLecture::FlotDebutDonnee()
    {// on repositionne le flot au debut du tableau de carractere
          delete entree;
          #ifndef ENLINUX_STREAM
            entree = new istringstream(tablcar,strlen (tablcar)) ;
          #else 
            entree = new istrstream(tablcar,(long) strlen (tablcar)) ;
          #endif    
     };          
            
  // ecriture d'un message d'erreur du a une mauvaise lecture
    void UtilLecture::ErreurLecture
               (UtilLecture::ErrNouvelleDonnee erreur,char* message)
      { cout << "\n***** erreur en lecture *********"<< '\n';
        cout << message << '\n';
        if ( erreur.lecture == 1) 
         { cout << " fin de fichier atteinte" << '\n'; }
        else if ( erreur.lecture == -1 ) 
         { cout << "erreur de lecture \n";}
        else 
         cout << " cas non prevu\n " ; 
       cout << " contenu de la ligne courante filtree lue " << tablcar << '\n'; 
       cout << " contenu de la ligne courante non filtree lue " << tableau << '\n'; 
       cout << "racine du fichier principal =    " << nomRacine << '\n';
       cout << " fichier courant ouvert en lecture =    " << nomCourant  << '\n'; 
       cout << " numero de la ligne  courante =    " << maille1->numLigne  << '\n'; 
       cout << endl; 
      };   
// ecriture d'un message et du contenu des buffers courant
void UtilLecture::MessageBuffer(string message) 
      { 
        cout << "\n****** " << message << "******** " << '\n';
        cout << "\n**  information sur les buffers  **"<< '\n';
        cout << " contenu de la ligne courante filtree lue =  " << tablcar << '\n'; 
        cout << " contenu de la ligne courante non filtree lue =  " << tableau << '\n'; 
        cout << "racine du fichier principal =    " << nomRacine << '\n';
        cout << " fichier courant ouvert en lecture =     " << nomCourant  << '\n'; 
        if (maille1 != NULL)
            cout << " numero de la ligne  courante =    " << maille1->numLigne  << '\n'; 
        cout << endl; 
      };   
        
 // recherche d'une chaine de carractere pointee par nom 
        void UtilLecture::Cherche(const char * nom)
         { do { NouvelleDonnee(); }
           while(strstr(tablcar,nom)==NULL);
         };        
         
 // ouverture d'un nouveau fichier
        void UtilLecture::NouveauFichier(char* ptr)
        {  
            ifstream * sPtr = ptrfich;  // sauve de l'adresse
            
            // passage des carracteres "espace" eventuelle
            int fii = 1;
            while((*ptr == ' ')&&(fii<longueur)) {fii++; ptr++;};
            
            ptrfich = new ifstream(ptr); // ouverture d'un nouveau fichier
            nomCourant = ptr;
            
            // gestion d'erreur d'ouverture non admise pour la suite du programme           
            if(!(ptrfich->is_open())) 
              { if (ParaGlob::Francais())
                 {cout << " cas d'un fichier decrit par la commande < " << '\n'
                                 << " erreur en ouverture du fichier = " << (string(ptr)) << endl;
                  }
                else
                 {cout << " case of an include file, introduced by the command  < " << '\n'
                                 << " error in opening the file  = " << (string(ptr)) << endl;
                  };
                Sortie(1);
              };  

            
            // ajout d'un maillon a la liste chainee d'ouverture de fichier
            PointFich* poi = maille1;
            maille1 = new PointFich (poi,sPtr,nomCourant);
  
        };


  // fermeture d'un fichier
        void UtilLecture::FermetureFichier(int& indic)
        {
            // retour sur le fichier precedent si possible
            if (maille1->t1 != NULL)
              {
               delete ptrfich;  //fermeture du fichier
               ptrfich = maille1->sauvePtr; // recup de l'adresse fichier
               PointFich* poi = maille1->t1; // sauve adresse precedente
               delete maille1; // suppression de la maille courante
               maille1 = poi; // et pointage sur la maille precedente
               nomCourant = maille1->nom;   // mise a jour du nomcourant de fichier ouvert
               
               indic = 0;  // operation reussie
              }
             else
              indic = 1;  // fin des fichiers intermediaires atteinte 
        };
        

// affichage sur la sortie standard de l'enregistrement courant    
        void UtilLecture::AfficheEnreg () const 
          { cout << tablcar << '\n';
           };

// entrée par argument au niveau de la construction de l'objet UtilLecture
// dans le cas où il y a eu un pb lec_ent_info=-100, et rien n'est initialisé
bool UtilLecture::EntreeParArgument(int argc, const char * argv[])
	{ // on regarde maintenant s'il y a passage  par arguments
	  // le premier argument est le nom du programme qui est lancé (semblerait-il)
	  // donc se qui nous intéresse c'est les arguments suivants
      bool entree_par_argument=false;
      // par défaut on signale que l'on est en mode de demande de renseignement d'UtilLecture
      // mais rien n'est initialisé, il faut arrêter
      if (argc > 1)
         lec_ent_info=-100; // initialisation par défaut
      // === cas où il y a qu'un seul argument ===
      if (argc==2)
       {int i=1;entree_par_argument=true;
        if (argv[i][1]=='f') // -- cas d'une entrée par fichier, il faudrait un second argument 
          { cout << "\n usage: -f <nom_fichier_entree>" << endl; } 
        else if (argv[i][1]=='n') // -- cas de la construction d'un fichier, il faudrait un second argument
          { cout << "\n usage: -n <nom_fichier_sortie(sans le .info)>" << endl; } 
        else if (argv[i][1]=='x') // -- cas de la construction du shema xml d'entree de donnees
          { entree_par_argument=true;
            lec_ent_info = -12;
            nomRacine="Herezhpp";  // nom prédéterminé
           }
        else if (argv[i][1]=='u') // -- cas de l'utilisation d'herezh sous forme d'une procédure umat abaqus
                                  //    il faudrait un autre argument
          { cout << "\n usage: -uf <nom_fichier_entree>" << endl; } 
        else if (argv[i][1]=='h') // -- cas du rappel de l'usage
          { cout << "\n usage: HZpp -[fnxh] <fichier>"
                 << "\n    -h rappel de l'usage"
                 << "\n    -f execution avec le fichier de commande qui suit"
                 << "\n    -x creation du schema XML pour fichier de commande: Herezhpp.xsd"
                 << "\n    -n creation interactive d'un fichier de commande";
           }
       }
      else // === cas où il y a plusieurs arguments ===
       {for (int i=1;i< argc;i++)
          {if (argv[i][1]=='f') // -- cas d'une entrée par fichier 
             {if(i<argc-1)  
               { i++;
                 entree_par_argument=true;
                 lec_ent_info = 0;
                 string motinter(argv[i]); // on récupère en string
                 nomRacine=motinter; // copie
                 // dans le cas où ".info" figure dans la racine, on supprime cette chaine
                 int posi = nomRacine.find(".info");
                 if (posi != string::npos)
                    { string nom_inter = nomRacine.substr(0,posi);
                      nomRacine = nom_inter;
                    };
               }
               else 
                { cout << "\n usage: -f <nom_fichier_entree>" << endl; } 
               break; // pour l'instant une seule passe 
             }
           else if (argv[i][1]=='n') // -- cas de la construction d'un fichier
             {if(i<argc-1)  
              { i++;
                entree_par_argument=true;
                lec_ent_info = -11;
                string motinter(argv[i]); // on récupère en string
                nomRacine=motinter; // copie
                // dans le cas où ".info" figure dans la racine, on supprime cette chaine
                int posi = nomRacine.find(".info");
                if (posi != string::npos)
                  { string nom_inter = nomRacine.substr(0,posi);
                    nomRacine = nom_inter;
						            };
               }
              else 
               { cout << "\n usage: -n <nom_fichier_sortie(sans le .info)>" << endl; } 
               break; // pour l'instant une seule passe 
             }
           else if (argv[i][1]=='x') // -- cas de la construction d'un shema xml d'entree de donnees
            { cout << "\n usage: -x " << endl; 
              break;  
            }
           else if (argv[i][1]=='h') // -- cas du rappel de l'usage
              { cout << "\n usage: HZpp -[fnxh] <fichier>"
                     << "\n    -h rappel de l'usage"
                     << "\n    -f execution avec le fichier de commande qui suit"
                     << "\n    -x creation d'un schema XML pour fichier de commande: Herezhpp.xsd"
                     << "\n    -n creation interactive d'un fichier de commande";
               break; // pour l'instant une seule passe 
              }
          };
       };
     // retour
     return entree_par_argument;		
	};
	
// entrée interactive au niveau de la construction de l'objet UtilLecture
// dans le cas où il y a eu un pb lec_ent_info=-100, et rien n'est initialisé
void UtilLecture::EntreeInteractive(string& ancien,bool& ouverture_ancien)
	{ // entrée interactive
      if (!ouverture_ancien)
             // pas de possibilité d'utilisation de racine déjà existante
             { nomRacine = "";
               while (!((nomRacine.length () != 0) ||
                       (nomRacine == "1") || (nomRacine == "2")))
                 { cout << "\n pb en ouverture en lecture du fichier : ancien"
                        << " , on continu quand meme ";
                   cout << "\n entrer la racine du nom du fichier .info :\n"
                        << " ou repondre 1 pour une entree via le fichier base-info\n"
                        << " ou repondre 2 pour une entree via un serveur base-info\n"
                        << " ou repondre x pour la creation d'un schema XML pour creer\n" 
                        << "               un  fichier de commade: Herezhpp.xsd\n"
                        << " ou repondre n pour la construction d'un nouveau fichier de commande\n";
                   nomRacine= lect_chaine();
                   if (nomRacine == "1") 
                      lec_ent_info = 1;
                   else if (nomRacine == "2")
                      lec_ent_info = 2;
                   else if (nomRacine == "n")
                      {lec_ent_info = -11;
                       cout << "\n entrer la racine du nom du fichier de commande a cree : \n";
                       nomRacine= lect_chaine();
                       }
                   else if (nomRacine == "x")
                      {lec_ent_info = -12;
                       cout << "\n ====================================== \n";
                       cout << "\n $$$$$ construction du schema XML  $$$$ \n";
                       cout << "\n $$$$$  fichier:  Herezhpp.xsd     $$$$ \n";
                       cout << "\n ====================================== \n";
                       nomRacine="Herezhpp";
                       }
                   else
                      lec_ent_info = 0;   
                   }
             }
      else
              // utilisation de la racine existante                              
              { nomRacine = "";
               while (!((nomRacine.length () != 0) || (nomRacine == "0") || (nomRacine == "o")
                       || (nomRacine == "1") || (nomRacine == "2")))
                {  cout << "\n entrer la racine du nom du fichier .info : (" << ancien <<").info \n"
                        << " ou repondre o ou 0 si l'on veut l'ancien nom \n"
                        << " ou repondre 1 pour une entree via le fichier base-info\n"
                        << " ou repondre 2 pour une entree via un serveur base-info\n"
                        << " ou repondre x pour la creation d'un schema XML pour creer\n" 
                        << "               un  fichier de commade: Herezhpp.xsd\n"
                        << " ou repondre n pour la construction d'un nouveau fichier de commande\n";
                   nomRacine= lect_chaine();
                   if (nomRacine == "1")
                      lec_ent_info = 1;
                   else if (nomRacine == "2")
                      lec_ent_info = 2;
                   else if ((nomRacine == "0")||(nomRacine == "o"))
                      { lec_ent_info = 0;
                        nomRacine = ancien;
                       } 
                   else if (nomRacine == "n")
                      {lec_ent_info = -11;
                       cout << "\n entrer la racine du nom du fichier de commande a cree : \n";
                       nomRacine= lect_chaine();
                       }
                   else if (nomRacine == "x")
                      {lec_ent_info = -12;
                       cout << "\n ====================================== \n";
                       cout << "\n $$$$$ construction du schema XML  $$$$ \n";
                       cout << "\n $$$$$  fichier:  Herezhpp.xsd     $$$$ \n";
                       cout << "\n ====================================== \n";
                       nomRacine="Herezhpp";
                       }
                   else if  (nomRacine.length () != 0)
                      lec_ent_info = 0;
                   }
              };
      // dans le cas où ".info" figure dans la racine, on supprime cette chaine
      int posi = nomRacine.find(".info");
      if (posi != string::npos)
                { string nom_inter = nomRacine.substr(0,posi);
                  nomRacine = nom_inter;
                 };
		
	};       
	
//------------- utilitaires de lecture d'une grandeurs qui peut-être une constante utilisateur ---


double UtilLecture::lect_avec_const_double_utilisateur(string nom_erreur) const
  {string nom;
   double val; // le retour
   *entree >>  nom ;
   // on regarde si les 3 premières lettres sont C__
   if ((nom[0]== 'C')&&(nom[1]== '_')&&(nom[2]== '_'))
    // il s'agit d'une constante utilisateur, on récupère sa valeur
    {
     // on récupère le pointeur correspondant à la grandeur
     const void* pointe =  (ParaGlob::param->GrandeurGlobal(nom));
     if (pointe != NULL)
      {TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
       if ((gr_quelc->Grandeur_pointee()->Type_structure_grandeurAssocie()==TYPE_SIMPLE)
           && (gr_quelc->Grandeur_pointee()->Type_enumGrandeurParticuliere()==PARTICULIER_SCALAIRE_DOUBLE)
          )
            {val =  gr_quelc->Grandeur_pointee()->GrandeurNumOrdre(1);
            }
       else // sinon pb
            { cout << "\n *** pb dans dans l'utilisation de la constante globale "<< nom
                     << " le conteneur lu " << nom << " n'est pas d'un type correct !! "
                     << "\n >>> lecture : " << nom_erreur;
              if (ParaGlob::NiveauImpression() > 3)
                 cout << "\n UtilLecture::Lect_avec_const_double_utilisateur(...";
              Sortie(1);
            };
       }
     else // sinon pb
        { cout << "\n *** erreur dans l'utilisation de la constante globale "<< nom
                 << " la variable n'existe pas !! "
                 << "\n >>> lecture : " << nom_erreur
                     << "\n >>> lecture : " << nom_erreur;
          if (ParaGlob::NiveauImpression() > 3)
             cout << "\n UtilLecture::Lect_avec_const_double_utilisateur(...";
          Sortie(1);
        };

    }
   else // c'est directement une valeur, on traduit
    {val = ChangeReel(nom);};
   // retour de la valeur
   return val;
  };


// modification interactive d'une constante utilisateur
// la constante doit déjà exister
void UtilLecture::Modif_interactive_constante_utilisateur()
  {
   try
    {string nom;
     cout << "\n nom de la constante utilisateur a modifier ? ";
     cin >>  nom ;
     cout << " (nom lu: "<< nom << ") ";
     // on regarde si les 3 premières lettres sont C__
     if ((nom[0]== 'C')&&(nom[1]== '_')&&(nom[2]== '_'))
         // il s'agit d'une constante utilisateur, on récupère sa valeur
         {
          // on récupère le pointeur correspondant à la grandeur
          const void* pointe =  (ParaGlob::param->GrandeurGlobal(nom));
          if (pointe != NULL)
           {TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
            // récup du typeQuelconque
            const TypeQuelconque_enum_etendu& enu = gr_quelc->EnuTypeQuelconque();
            if (enu == GENERIQUE_UNE_CONSTANTE_GLOB_DOUBLE_UTILISATEUR)
             {if ((gr_quelc->Grandeur_pointee()->Type_structure_grandeurAssocie()==TYPE_SIMPLE)
                && (gr_quelc->Grandeur_pointee()->Type_enumGrandeurParticuliere()==PARTICULIER_SCALAIRE_DOUBLE)
               )
                {// valeur initiale
                 double val_init =  gr_quelc->Grandeur_pointee()->GrandeurNumOrdre(1);
                 // lecture de la nouvelle valeur
                 double nevezval;
                 cout << "\n valeur actuelle  " << val_init
                      << " nouvelle valeur ? " ;
                 cin >> nevezval;
                 if (ParaGlob::NiveauImpression() > 0)
                  {cout << "\n modification de la constante utilisateur : "<< nom;
                   cout << " ancienne valeur " << val_init;
                   cout << " nouvelle valeur lue "<< nevezval ;
                  };
                 ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(nom,nevezval);
                }
              else // sinon pb
                 { cout << "\n *** pb dans dans la modification de la constante utilisateur "<< nom
                          << " le conteneur lu " << nom << " n'est pas d'un type correct !! ";
                   if (ParaGlob::NiveauImpression() > 3)
                      cout << "\n UtilLecture::Modif_interactive_constante_utilisateur(...";
                   Sortie(1);
                 };
             }
            else // cas ou on a détecter que la grandeur globale n'est pas une constante utilisateur
             { cout << "\n *** erreur dans l'utilisation de la  grandeur globale "<< nom
                   << " ce n'est pas une constante utilisateur !! "
                   << " ***  on ne change rien " ;
               if (ParaGlob::NiveauImpression() > 3)
                  cout << "\n UtilLecture::Modif_interactive_constante_utilisateur(...";
               cout  <<flush;
             };
           }
          else // cas ou la constante n'existe pas
             { cout << "\n *** erreur dans l'utilisation de la  constante utilisateur "<< nom
                      << " la variable n'existe pas !! "
                      << " ***  on ne change rien " ;
               if (ParaGlob::NiveauImpression() > 3)
                  cout << "\n UtilLecture::Modif_interactive_constante_utilisateur(...";
               cout  <<flush;
             };

         }
     else //cas ou ce n'est pas une constante utilisateur
         {cout << "\n *** erreur en lecture d'une constante utilisateur "<< nom
               << " la variable doit commencer par C__ !! "
               << " et on a lue : " << nom
               << " ***  on ne change rien " ;
          if (ParaGlob::NiveauImpression() > 3)
             cout << "\n UtilLecture::Modif_interactive_constante_utilisateur(...";
          cout  <<flush;
         };
    }
   // sortie anormale normale du programme
   catch (ErrSortieFinale)
        // cas d'une direction voulue vers la sortie
        // on relance l'interuption pour le niveau supérieur
      { ErrSortieFinale toto;
        throw (toto);
      }
   catch (...)
      {cout << "\n *** erreur inconnue en modification d'une constante utilisateur "
            << " ***  on ne change rien " ;
       if (ParaGlob::NiveauImpression() > 3)
          cout << "\n UtilLecture::Modif_interactive_constante_utilisateur(...";
       cout  <<flush;
      };

   std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin

 };

