/*************************************************************************************************************************************/ /* */ /* O P E R A T I O N S A R I T H M E T I Q U E S S U R D E S F I C H I E R S : */ /* */ /* */ /* Author of '$xrv/ARITHMET.1g$I' : */ /* */ /* Jean-Francois COLONNA (LACTAMME, 20060215103111). */ /* */ /*************************************************************************************************************************************/ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* R E C U P E R A T I O N D ' U N F I C H I E R " L I S T E " : */ /* */ /*************************************************************************************************************************************/ #define PREMIER_ELEMENT_D_UNE_LISTE_VERSION_PREMIER_ELEMENT_D_UN_FICHIER_0 \ /* Afin de faire la difference entre les programmes dont les premiers elements sont */ \ /* numerotes 'PREMIER_POINT_DES_LISTES' ('v $xrv/particule.10$K') et ceux dont les premiers */ \ /* elements sont numerotes 'PREMIER_ELEMENT_D_UN_FICHIER' ('v $xrv/distance.02$K'). */ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* V A L E U R S I M P L I C I T E S D E S P A R A M E T R E S : */ /* */ /*************************************************************************************************************************************/ #nodefine NOMBRE_D_ELEMENTS \ TRI_DIMENSIONNEL #define NOMBRE_D_ELEMENTS \ ZERO /* Nombre d'elements attendus a priori dans les fichiers. Le passage de 'TRI_DIMENSIONNEL' */ /* a 'ZERO' a eu lieu le 19991217121738 afin de permettre la determination automatique de */ /* 'nombre_d_elements'... */ #define UTILISER_LE_FORMAT_EXPONENTIEL \ VRAI \ /* Faut-il sortir en format "%g" ('VRAI') ou en format "%f" ('FAUX'). Ceci a ete introduit */ \ /* afin de permettre d'extraire la partie entiere d'un nombre en supprimant simplement tout */ \ /* ce qui suit le point decimal avec '$SE'... */ /*===================================================================================================================================*/ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N D E S F I C H I E R S : */ /* */ /*************************************************************************************************************************************/ #define EN_TETE_DANS_LE_FICHIER \ ZERO #define SAUT_DANS_LE_FICHIER \ ZERO DEFV(Local,DEFV(Positive,INIT(en_tete_dans_le_fichier_des_valeurs,EN_TETE_DANS_LE_FICHIER))); DEFV(Local,DEFV(Positive,INIT(saut_dans_le_fichier_des_valeurs,SAUT_DANS_LE_FICHIER))); /* Definition du nombre de valeurs a sauter entre deux valeurs recuperees du fichier de */ /* coordonnees et de valeurs. L'amplitude du saut sur le debut du fichier ("en_tete") a */ /* ete introduite le 20021104171432 par symetrie avec '$xrv/particule.11$I 20021104161517'. */ #define PROCESS_ARGUMENTS_DE_DEFINITION_DES_FICHIERS_01 \ /* La partie "_01" du nom 'PROCESS_ARGUMENTS_DE_DEFINITION_DES_FICHIERS_01' est choisie */ \ /* en harmonie avec le nom de la procedure 'lTRANSFORMAT_01(...)' qui lui est associee... */ \ Bblock \ \ DEBUT_D_IMBRICATION_DES_____gPROCESS_PARAMETRE_____SECONDAIRES; \ /* Introduit le 20060208111712 ('v $xig/fonct$vv$DEF _IMBRICATION_DES__gPROCESS_PARAMETRE'). */ \ \ PROCESS_ARGUMENT_I("en_tete=",en_tete_dans_le_fichier_des_valeurs \ ,BLOC(VIDE;) \ ,BLOC(PRINT_AVERTISSEMENT("'saut=' doit etre defini avant toute entree de fichiers");) \ ); \ /* ATTENTION : la recuperation de 'en_tete_dans_le_fichier_des_valeurs' doit */ \ /* preceder les 'PROCESS_ARGUMENT_C(...)' qui suivent car ils l'utilisent. */ \ PROCESS_ARGUMENT_I("saut=",saut_dans_le_fichier_des_valeurs \ ,BLOC(VIDE;) \ ,BLOC(PRINT_AVERTISSEMENT("'saut=' doit etre defini avant toute entree de fichiers");) \ ); \ /* ATTENTION : la recuperation de 'saut_dans_le_fichier_des_valeurs' doit preceder */ \ /* les 'PROCESS_ARGUMENT_C(...)' qui suivent car ils l'utilisent. */ \ \ FIN___D_IMBRICATION_DES_____gPROCESS_PARAMETRE_____SECONDAIRES; \ /* Introduit le 20060208111712 ('v $xig/fonct$vv$DEF _IMBRICATION_DES__gPROCESS_PARAMETRE'). */ \ \ Eblock \ /* Introduit le 20021104173637 pour faciliter la mise a jour de differents '$K' suite */ \ /* a l'introduction du nouveau parametre 'en_tete_dans_le_fichier_des_valeurs'... */ #TestADef NOMBRE_MAXIMAL_D_ELEMENTS_DANS_LE_FICHIER \ GRO2(MILLION) \ /* Nombre maximal d'elements dans les fichiers (valeur tres arbitraire...). */ \ /* */ \ /* Le 20060210172552, ce nombre est passe de 'MILLION' a 'GRO2(MILLION)' a cause de */ \ /* 'v $xiird/.PEA3.3.11.$U'... */ DEFV(Local,DEFV(Positive,INIT(nombre_maximal_d_elements_dans_le_fichier,NOMBRE_MAXIMAL_D_ELEMENTS_DANS_LE_FICHIER))); #define gGENERATION_D_UN_FICHIER_nom(fichier_des_valeurs) \ DEFV(Local,DEFV(CHAR,INIT(POINTERc(fichier_des_valeurs),NOM_PIPE_Local))); #define gGENERATION_D_UN_FICHIER_liste(liste_des_valeurs) \ DEFV(Local,DEFV(Positive,INIT(liste_des_valeurs`____nombre_d_elements,NOMBRE_D_ELEMENTS))); \ /* Il est plus logique de definir 'nombre_d_elements' a partir de 'liste_des_valeurs' qu'a */ \ /* l'aide de 'fichier_des_valeurs' car, en effet, ainsi cette variable specifique a chaque */ \ /* fichier pourra etre utilisee dans 'gELEMENT_DU_FICHIER(...)' si besoin est... */ \ DEFV(Local,DEFV(Float,DdTb1(POINTERf \ ,liste_des_valeurs \ ,nombre_maximal_d_elements_dans_le_fichier \ ,ADRESSE_NON_ENCORE_DEFINIE \ ) \ ) \ ); #define gGENERATION_D_UN_FICHIER(fichier_des_valeurs,liste_des_valeurs) \ gGENERATION_D_UN_FICHIER_nom(fichier_des_valeurs); \ gGENERATION_D_UN_FICHIER_liste(liste_des_valeurs); /* Generation en memoire d'un fichier sous la forme {nom,liste}. */ /* */ /* L'allocation dynamique de 'liste_des_valeurs' a ete introduite le 20060213182327... */ /* */ /* Le nombre specifique d'elements de chauqe fichier a ete introduit le 20240930155301... */ #define gELEMENT_DU_FICHIER(liste_des_valeurs,index) \ IdTb1(liste_des_valeurs \ ,INDX(index,PREMIER_ELEMENT_D_UN_FICHIER) \ ,nombre_maximal_d_elements_dans_le_fichier \ ) \ /* Acces a un element courant des fichiers. */ \ /* */ \ /* ATTENTION a ne pas confondre : */ \ /* */ \ /* 1-'ACCES_LISTE(...)', pour lequel le premier element vaut : */ \ /* */ \ /* PREMIER_POINT_DES_LISTES=PREMIER_POINT=PREMIERE_ITERATION_D_UN_Komp=UN */ \ /* */ \ /* qui est donc adapte a une gestion de type 'Komp(...)' ou le premier element est defini */ \ /* implicitement (et vaut donc 'UN'), et */ \ /* */ \ /* 2-'gELEMENT_DU_FICHIER(...)', pour lequel le premier element vaut : */ \ /* */ \ /* PREMIER_ELEMENT_D_UN_FICHIER=INDEX0=ZERO */ \ /* */ \ /* qui ne peut utiliser 'Komp(...)' et demande donc une gestion de type 'DoIn(...)' en */ \ /* precisant le premier element en tant qu'argument du 'DoIn(...)' (et valant donc 'ZERO'). */ #define glTRANSFORMAT_01__nombre_d_elements(nombre_effectif_d_elements,editer_les_messages_d_erreur_des_fichiers) \ Bblock \ DEFV(Int,INIT(taille_du_fichier_des_valeurs_effectif,UNDEF)); \ EGAL(Fsize_fichier_____compter_les_lignes,COMPTER_LES_LIGNES_DANS_Fsize_fichier); \ CALS(Fsize_fichier(fichier_des_valeurs_effectif \ ,ADRESSE(taille_du_fichier_des_valeurs_effectif) \ ,editer_les_messages_d_erreur_des_fichiers \ ) \ ); \ EGAL(nombre_effectif_d_elements \ ,DIVI(SOUS(Fsize_fichier_____nombre_de_lignes,en_tete_dans_le_fichier_des_valeurs) \ ,TRPU(saut_dans_le_fichier_des_valeurs) \ ) \ ); \ Eblock \ /* Introduit le 20240930155301... */ #define glTRANSFORMAT_01(fichier_des_valeurs,liste_des_valeurs,valeur_par_defaut,sequence_allocation_eventuelle) \ Bblock \ DEFV(CHAR,INIC(POINTERc(fichier_des_valeurs_effectif),NOM_UNDEF)); \ /* Nom du fichier a lire (soit un "vrai" fichier, soit un "pipe"). */ \ \ Test(I3OU(IFEQ_chaine(fichier_des_valeurs,C_VIDE) \ ,IFEQ_chaine(fichier_des_valeurs,NOM_PIPE) \ ,IFEQ_chaine(fichier_des_valeurs,NOM_PIPE_Local) \ ) \ ) \ /* ATTENTION, j'ai decouvert le 20000207110651 qu'il n'etait pas equivalent de laisser */ \ /* a un argument 'fichier_des_valeurs' sa valeur implicite ('NOM_PIPE_Local'), et de lui */ \ /* donner cette valeur, par exemple a l'aide de : */ \ /* */ \ /* fichier="=" */ \ /* */ \ /* (en supposant que l'argument s'appelle "fichier="). En effet, dans le premier cas */ \ /* (valeur implicite conservee), la procedure 'lTRANSFORMAT_01(...)' n'est pas appelee */ \ /* par 'PROCESF_ARGUMENT_C(...)' puisque l'argument courant n'est pas rencontre. Alors, */ \ /* dans ce cas, la gestion du "pipe" qui suit n'est pas effectuee. Donc, moralite, pour */ \ /* acceder proprement au "pipe", il faut que cela soit demande explicitement... */ \ /* */ \ /* Cela est vrai aussi, malheureusement, de l'evaluation automatique de 'nombre_d_elements'. */ \ /* */ \ /* Cela a donc conduit a l'introduction de 'v $xig/fonct$vv$DEF gPROCESS_PARAMETRE' et de */ \ /* 'v $xig/fonct$vv$DEF PROCESF_ARGUMENT_C'. Malheureusement, le 20000207173145 j'ai */ \ /* decouvert que cela etait insuffisant ('v $xig/fonct$vv$DEF 20000207173145'). Donc, pour */ \ /* "connecter" un fichier au "pipe", il faudra malheureusement ecrire quelque chose du */ \ /* type : */ \ /* */ \ /* fichier="=" */ \ /* */ \ /* si l'on veut que les arguments du meme type et qui sont absents, correspondent a leur */ \ /* valeur par defaut. On etait donc en presence de deux desirs contradictoires : */ \ /* */ \ /* 1-initialiser un fichier avec la valeur par defaut lorsqu'il est */ \ /* absent en tant qu'argument, */ \ /* */ \ /* 1-"connecter" un fichier au "pipe" (valeur par defaut de son nom) */ \ /* lorsqu'il est absent en tant qu'argument. */ \ /* */ \ /* Ainsi, malgre les initialisations (dans 'gGENERATION_D_UN_FICHIER(...)'), l'absence d'un */ \ /* fichier (en tant qu'argument) impliquera l'initialisation de tous ses elements avec sa */ \ /* valeur par defaut, meme si donc son nom vaut 'NOM_PIPE_Local'... */ \ Bblock \ EGAL(fichier_des_valeurs_effectif,generation_d_un_nom_absolu_dans_xT_temporaire(C_VIDE)); \ /* Generation du nom du fichier temporaire correspondant au "pipe". */ \ \ EXECUTION_D_UNE_SUITE_DE_COMMANDES_SOUS_SH(chain_Aconcaten3(Gvar("CA") \ ,C_SH__REDIRECTION_FICHIER \ ,fichier_des_valeurs_effectif \ ) \ ); \ /* Transfert du "pipe" dans le fichier temporaire... */ \ /* */ \ /* Passage de 'C_REDIRECTION_FICHIER' a 'C_SH__REDIRECTION_FICHIER' le 20111117082138... */ \ Eblock \ ATes \ Bblock \ EGAL(fichier_des_valeurs_effectif,chain_Acopie(fichier_des_valeurs)); \ /* Le fichier utilise est le fichier argument... */ \ Eblock \ ETes \ \ Test(IZEQ(nombre_d_elements)) \ /* Dispositif introduit le 19991217121738 pour permettre la determination automatique */ \ /* de 'nombre_d_elements' lorsque la valeur qui lui est donnee est nulle... */ \ Bblock \ glTRANSFORMAT_01__nombre_d_elements(nombre_d_elements \ ,EDITER_LES_MESSAGES_D_ERREUR_DES_FICHIERS \ ); \ /* Determination automatique de 'nombre_d_elements' que le fichier soit un "vrai" fichier */ \ /* ou bien un "pipe"... */ \ /* */ \ /* ATTENTION, cela ne fonctionne pas evidemment dans le cas ou le nom du fichier est en fait */ \ /* une valeur numerique ('LE_NOM_DU_FICHIER_EST_CONVERTISSABLE_EN_UNE_VALEUR_NUMERIQUE'). */ \ /* Dans ce cas et lorsque le programme correspondant recoit comme Arguments plusieurs noms */ \ /* de fichier, la solution consiste a mettre en premier les "vrais" fichiers, puis derriere */ \ /* les "faux" fichiers (dont les noms sont des valeurs numeriques). Ainsi : */ \ /* */ \ /* COMMANDE ne=0 fichier1=1234 fichier2=NOM */ \ /* */ \ /* ne fonctionnera pas car 'Fsize_fichier(...)' va vouloir ouvrir le fichier dont le nom */ \ /* est '1234', alors que : */ \ /* */ \ /* COMMANDE ne=0 fichier1=NOM fichier2=1234 */ \ /* */ \ /* ou encore : */ \ /* */ \ /* COMMANDE ne=0 fichier1="=" fichier2=1234 */ \ /* */ \ /* fonctionneront car la determination de 'nombre_d_elements' aura lieu sur 'fichier1' et */ \ /* donc sur un vrai fichier (de nom 'NOM' ou le "pipe"). */ \ /* */ \ /* Le 20110324100311 (c'est-a-dire un peu tardivement !) ont ete pris en compte dans le */ \ /* calcul de 'nombre_d_elements' des variables 'en_tete_dans_le_fichier_des_valeurs' et */ \ /* 'saut_dans_le_fichier_des_valeurs'... */ \ Eblock \ ATes \ Bblock \ Eblock \ ETes \ \ glTRANSFORMAT_01__nombre_d_elements(liste_des_valeurs`____nombre_d_elements \ ,NE_PAS_EDITER_LES_MESSAGES_D_ERREUR_DES_FICHIERS \ ); \ /* Mise a jour specifique et systematique introduite le 20240930155301... */ \ /* */ \ /* Je note le 20241005203934 que cette instruction rend impossible la conversion d'un */ \ /* nom de fichier en valeur numerique. On a alors : */ \ /* */ \ /* liste_des_valeurs`____nombre_d_elements == 0 */ \ /* */ \ /* En fait, il apparait que tout se passe bien, sauf le message d'erreur, d'ou sa */ \ /* suppression... */ \ \ BLOC(sequence_allocation_eventuelle); \ /* Allocation memoire ou validation de la taille... */ \ \ CALS(Fload_fichier_formatte_Float(fichier_des_valeurs_effectif \ ,liste_des_valeurs \ ,nombre_d_elements \ ,en_tete_dans_le_fichier_des_valeurs \ ,saut_dans_le_fichier_des_valeurs \ ,VRAI \ ,valeur_par_defaut \ ,LE_NOM_DU_FICHIER_EST_CONVERTISSABLE_EN_UNE_VALEUR_NUMERIQUE \ ) \ ); \ /* Et enfin, lecture du fichier... */ \ \ &define __ParaVal liste_des_valeurs&&& \ &define __ParaInd PREMIER_ELEMENT_D_UN_FICHIER&&& \ &define __ParaLon nombre_d_elements&&& \ &define __ParaTyp TYPE_FORMAT_FLOT&&& \ &define __ParaFor FORMAT_FLOT_EDITION&&& \ \ Test(IFEQ_chaine(fichier_des_valeurs_effectif,fichier_des_valeurs)) \ Bblock \ /* Cas ou il s'agissait d'un "vrai" fichier... */ \ Eblock \ ATes \ Bblock \ /* Cas ou il s'agissait d'un "pipe"... */ \ CALS(Idelete_fichier(fichier_des_valeurs_effectif)); \ /* Destruction du fichier temporaire. */ \ Eblock \ ETes \ \ CALZ_FreCC(fichier_des_valeurs_effectif); \ /* Liberation de l'espace contenant le nom du fichier effectif. */ \ Eblock \ /* Recuperation d'un fichier contenant une liste. ATTENTION, le 19980317091800, le */ \ /* parametre : */ \ /* */ \ /* LE_NOM_DU_FICHIER_N_EST_PAS_CONVERTISSABLE_EN_UNE_VALEUR_NUMERIQUE */ \ /* */ \ /* est devenu : */ \ /* */ \ /* LE_NOM_DU_FICHIER_EST_CONVERTISSABLE_EN_UNE_VALEUR_NUMERIQUE */ \ /* */ \ /* car cela permet, par exemple, d'incrementer tous les elements d'un fichier d'une valeur */ \ /* constante... */ \ /* */ \ /* Je rappelle le 20170111102646 que si le nom du fichier est une "bonne" valeur numerique, */ \ /* c'est elle qui l'emporte, meme si il existe un fichier portant ce nom. Cela ne peut */ \ /* evidemment se produire que si ce dernier fichier est designe de facon relative (et donc */ \ /* dans '$CWD'). Pour forcer l'acces a ce fichier (et donc ne pas utiliser la valeur */ \ /* numerique correspondant a son nom), il suffit d'absolutiser ce nom, qui alors ne */ \ /* ressemblera plus a une "bonne" valeur numerique... */