/*
Fichier cylincr.c
Auteur Bernard Chardonneau
Logiciel libre, droits d'utilisation précisés en français
dans le fichier : licence-fr.txt
Traductions des droits d'utilisation dans les fichiers :
licence-en.txt , licence-es.txt , licence-pt.txt ,
licence-eo.txt , licence-eo-utf.txt
Droits d'utilisation également sur la page web :
http://cyloop.tuxfamily.org/voir.php?page=droits
Programme permettant d'incrémenter la variable d'un fichier
cyloop si elle est de type compteur.
*/
#include <stdio.h>
#include <time.h>
#include "types.h"
#include "limites.h"
#include "messages.h"
#include "majcycle.h"
// prototypes
void pondere (int coef_pond);
void incrval (uint16 num_instant, int majcmoy);
// variables globales (pour éviter des tas de passages de paramètre)
FILE *descfic; // descripteur du fichier cyloop
desc_cyloop entetefic; // entête du fichier cyloop
desc_var entetevar; // entête de la variable du fichier cyloop
// programme principal
main (int narg, char *varg[])
{
char *nomfic; // nom du fichier cyloop
struct tm stm; // structure contenant la date et l'heure courante
uint32 timep; // date et heure dans un uint32
int maj_entetefic; // indicateur pour mise à jour fichier
uint16 num_instant; // numéro de la donnée à incrémenter
uint32 duree_cycle; // durée du cycle
// mémorisation du nom de la commande
memcom (*varg);
// récupération du nom de fichier et rajout éventuel du suffixe
if (--narg)
nomfic = recup_nomfic (varg [1]);
else
{
// "Nom de fichier manquant"
// "Syntaxe : %s nom_fichier_cyloop"
affiche_err ("MANQUE_NOMFICH");
psyntaxe ("SYNT_CYLINCR");
}
// ouverture en lecture / écriture du fichier cyloop
descfic = fopen (nomfic, "r+");
if (! descfic)
// "Fichier_cyloop %s inexistant ou protégé en lecture ou écriture"
err_fatale_arg ("ACCES_CYLOOP_RW",
nomfic);
// lecture de l'entête du fichier cyloop
fread (&entetefic, 16, 1, descfic);
// vérification de la signature
if (entetefic.signature [0] != 'c' || entetefic.signature [1] != 'y'
|| entetefic.signature [2] != 'l')
{
// "Le fichier %s n'est pas un fichier_cyloop"
aff_err_arg ("FICH_NON_CYLOOP", nomfic);
fclose (descfic);
return;
}
// vérification de la valeur nb_var
if (entetefic.nb_var)
{
// "Ce fichier cyloop utilise une liste de variables"
// "utiliser la version complète de cyloop"
affiche_err ("CYLOOP_LISTEVAR");
affiche_err ("UTIL_VCOMPLETE");
fclose (descfic);
return;
}
// lecture de la partie fixe de l'entête de la variable du fichier cyloop
fread (&entetevar, 6, 1, descfic);
// vérification de la nature de la variable
if (! (entetevar.typedon & compteur))
{
// "La variable du fichier cyloop n'est pas un compteur : utiliser cyladdval"
affiche_err ("VAR_NON_COMPTEUR");
fclose (descfic);
return;
}
// fin de lecture de l'entête de la variable si nécessaire
if (! (entetevar.typedon & cmoy_sep))
fread (&entetevar.coef_moy, 2, 1, descfic);
// récupérer la date et l'heure courante
time (&timep);
// si le début du cycle est ultérieur à l'instant présent
if (timep < entetefic.deb_cycle)
{
fclose (descfic);
// "Régression dans le temps : une intervention manuelle "
// "sur le fichier cyloop ou l'horloge est nécessaire"
affiche_err ("REGRES_TEMPS");
err_fatale ("REGRES_TEMPS2");
}
// initialisation indicateurs de mise à jour du fichier
maj_entetefic = NON;
// si on utilise l'heure locale
if (! (entetefic.caract_gen & temps_utc))
{
// récupérer le détail de la date et de l'heure locale
localtime_r (&timep, &stm);
// si changement d'heure été/hiver
if ((entetefic.etat_cyloop & heure_ete) != stm.tm_isdst)
// prendre en compte ce changement
maj_entetefic = maj_type_heure (stm.tm_isdst, timep);
}
// si changement de cycle
if (entetefic.deb_cycle + entetefic.duree_cycle <= timep)
{
// prise en compte de ce changement de cycle
changement_cycle (timep);
// une manière de mémoriser un début de cycle
entetevar.der_enreg = 0;
// on reportera la mise à jour dans le fichier cyloop
maj_entetefic = OUI;
}
// si mise à jour de l'entête du fichier cyloop nécessaire
if (maj_entetefic)
{
// recopier la nouvelle entête
rewind (descfic);
fwrite (&entetefic, 16, 1, descfic);
}
// récupération de la durée du cycle actuel
duree_cycle = duree_cycle_actuel (&timep);
// calcul de l'instant du cycle à mettre à jour
num_instant = calcul_instant (timep, duree_cycle);
// si on a changé de cycle et une seule valeur coef_moy pour la variable
if (! entetevar.der_enreg && !(entetevar.typedon & cmoy_sep))
{
// mettre à jour cette valeur
if (entetevar.ponderation)
entetevar.coef_moy += 256;
else
entetevar.coef_moy ++;
// y compris dans le fichier cyloop
fseek (descfic, 22, SEEK_SET);
fwrite (&entetevar.coef_moy, 2, 1, descfic);
}
// si c'est la première mise à jour effectuée durant ce cycle
// ou si on passe à un autre instant du même cycle
if (entetevar.der_enreg < num_instant)
{
// mettre à jour le numéro de l'instant du cycle traité
entetevar.der_enreg = num_instant;
// y compris dans le fichier cyloop
fseek (descfic, 16, SEEK_SET);
fwrite (&entetevar.der_enreg, 2, 1, descfic);
// incrémenter le compteur et si nécessaire le
// champ coef_moy pour l'instant du cycle concerné
incrval (num_instant, OUI);
}
// sinon, si on a déjà mis à jour le compteur pour cet instant du cycle
else if (entetevar.der_enreg == num_instant)
{
// si on est autorisé à le mettre à jour plusieur
// fois pour chacun des instants du cycle
if (entetevar.typedon & cumul_donnees)
// incrémenter le compteur et si nécessaire le
// champ coef_moy pour l'instant du cycle concerné
incrval (num_instant, entetevar.typedon & cpt_toute_don);
}
// sinon, il y a régression dans le temps
else
{
// vérifier si elle est supérieure à 2 heures
if (calcul_instant (timep + 7200, duree_cycle) < entetevar.der_enreg)
{
// vérifier si elle est supérieure à 1 journée
// et afficher le message d'erreur approprié
if (calcul_instant (timep + secjour, duree_cycle) <
entetevar.der_enreg)
{
// "Forte régression dans le temps : une intervention manuelle "
// "sur le fichier cyloop ou l'horloge est nécessaire"
affiche_err ("FORTE_REGR_TEMPS");
affiche_err ("REGRES_TEMPS2");
}
else
// "Régression dans le temps : vérifier l'horloge de l'ordinateur"
affiche_err ("REGR_VERIF_HORL");
}
}
// le fichier cyloop a été mis à jour
fclose (descfic);
}
// calcul de pondération sur les cycles antérieurs
void pondere (int coef_pond)
{
uint16 coef_moy; // coef_moy si distinct pour chaque instant du cycle
uint16 valeur16b; // valeur à pondérer si elle est sur 16 bits
uint32 valeur32b; // valeur à pondérer si elle est sur 32 bits
uint32 valmaj; // valeur sur 32 bits pour calcul de pondération
int i; // compteur
// si coefficient coef_moy global au compteur
if (! (entetevar.typedon & cmoy_sep))
{
// mettre à jour ce coefficient
// le calcul de multiplication et division est fait sur 32 bits
valmaj = entetevar.coef_moy;
entetevar.coef_moy = (valmaj * coef_pond) >> 8;
// ce coefficient sera mis à jour plus tard dans le fichier
// se positionner sur la première valeur du compteur
fseek (descfic, 24, SEEK_SET);
// si compteur sur 32 bits
if (entetevar.typedon & donnees_32bits)
{
// mise à jour des valeurs du compteur 32 bits
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// resynchronisation position dans le fichier
// fseek (descfic, 0, SEEK_CUR); (vérifier utilité)
// récupération de la valeur du compteur sur 32 bits
fread (&valeur32b, 4, 1, descfic);
// si risque de débordement lors du calcul
if (valeur32b & 0xFF000000)
// faire la division d'abord
valeur32b = (valeur32b >> 8) * coef_pond;
// sinon faire la multiplication d'abord
else
valeur32b = (valeur32b * coef_pond) >> 8;
// mettre à jour la valeur du compteur dans le fichier
fseek (descfic, -4, SEEK_CUR);
fwrite (&valeur32b, 4, 1, descfic);
}
}
// sinon (compteur sur 16 bits)
else
{
// mise à jour des valeurs du compteur 16 bits
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// resynchronisation position dans le fichier
// fseek (descfic, 0, SEEK_CUR); (vérifier utilité)
// récupération de la valeur du compteur sur 16 bits
fread (&valeur16b, 2, 1, descfic);
// on fait le calcul de pondération sur 32 bits
valmaj = valeur16b;
valeur16b = (valmaj * coef_pond) >> 8;
// mettre à jour la valeur du compteur dans le fichier
fseek (descfic, -2, SEEK_CUR);
fwrite (&valeur16b, 2, 1, descfic);
}
}
}
// sinon
else
{
// se positionner sur le premier coefficient coef_moy de la variable
fseek (descfic, 22, SEEK_SET);
// si compteur sur 32 bits
if (entetevar.typedon & donnees_32bits)
{
// mise à jour des valeurs de coef_moy et du compteur 32 bits
for (i = entetefic.nb_don_cycle; i > 0; i--)
{
// resynchronisation position dans le fichier
// fseek (descfic, 0, SEEK_CUR); (vérifier utilité)
// récupération de la valeur du coef_moy
fread (&coef_moy, 2, 1, descfic);
// récupération de la valeur du compteur sur 32 bits
fread (&valeur32b, 4, 1, descfic);
// calcul de pondération pour coef_moy
// le calcul de multiplication et division est fait sur 32 bits
valmaj = coef_moy;
coef_moy = (valmaj * coef_pond) >> 8;
// calcul de pondération pour la valeur du compteur
// si risque de débordement lors du calcul
if (valeur32b & 0xFF000000)
// faire la division d'abord
valeur32b = (valeur32b >> 8) * coef_pond;
// sinon faire la multiplication d'abord
else
valeur32b = (valeur32b * coef_pond) >> 8;
// mettre à jour les valeurs dans le fichier
fseek (descfic, -6, SEEK_CUR);
fwrite (&coef_moy, 2, 1, descfic);
fwrite (&valeur32b, 4, 1, descfic);
}
}
// sinon (compteur sur 16 bits)
else
{
// mise à jour des valeurs de coef_moy et du compteur 16 bits
// la même boucle sert aux 2 valeurs, moins optimisé pour les
// accès au fichier, mais plus simple
for (i = entetefic.nb_don_cycle * 2; i > 0; i--)
{
// resynchronisation position dans le fichier
// fseek (descfic, 0, SEEK_CUR); (vérifier utilité)
// récupération de la valeur du compteur sur 16 bits
fread (&valeur16b, 2, 1, descfic);
// on fait le calcul de pondération sur 32 bits
valmaj = valeur16b;
valeur16b = (valmaj * coef_pond) >> 8;
// mettre à jour la valeur du compteur dans le fichier
fseek (descfic, -2, SEEK_CUR);
fwrite (&valeur16b, 2, 1, descfic);
}
}
}
}
// incrémente le compteur pour l'instant num_instant du cycle
void incrval (uint16 num_instant, int majcmoy)
{
int ajout; // valeur à rajouter au compteur
long posval; // position de la valeur à incrémenter dans le fichier
uint16 coef_moy; // coefficient coef_moy pour la valeur à incrémenter
uint16 valeur16b; // valeur à incrémenter si elle est sur 16 bits
uint32 valeur32b; // valeur à incrémenter si elle est sur 32 bits
int majfich; // indique si on devra mettre à jour le fichier
// initialisation
majfich = OUI;
// calcul de la valeur à rajouter au compteur
if (entetevar.ponderation)
ajout = 256;
else
ajout = 1;
// pour le calcul de position, le premier instant
// du cycle n'entrainera pas de décalage
num_instant --;
// calcul de la position dans le fichier de la valeur à incrémenter
posval = 24;
if (entetevar.typedon & cmoy_sep)
posval += num_instant * 2;
if (entetevar.typedon & donnees_32bits)
posval += num_instant * 4;
else
posval += num_instant * 2;
// si coefficient coef_moy à mettre à jour
if (majcmoy && (entetevar.typedon & cmoy_sep))
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval - 2, SEEK_SET);
// récupérer et incrémenter le coefficient coef_moy
fread (&coef_moy, 2, 1, descfic);
coef_moy += ajout;
}
// sinon, juste valeur du compteur à modifier
else
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval, SEEK_SET);
// si le compteur est sur 32 bits
if (entetevar.typedon & donnees_32bits)
{
// récupération de la valeur du compteur sur 32 bits
fread (&valeur32b, 4, 1, descfic);
// incrementation de la valeur du compteur
valeur32b += ajout;
}
// sinon (compteur sur 16 bits)
else
{
// récupération de la valeur du compteur sur 16 bits
fread (&valeur16b, 2, 1, descfic);
// s'il n'y a pas encore eu de débordement numérique
if (valeur16b != max_uint16)
{
// incrémenter la valeur (calcul sur 32 bits)
valeur32b = (uint32) valeur16b + ajout;
// si débordement numérique
if (valeur32b & 0xFFFF0000)
{
// message d'erreur
// "Débordement numérique pour la variable"
// "Il faudrait la convertir en 32 bits"
affiche_err ("DEBORD_NUMERIQUE");
affiche_err ("BESOIN_CONV32B");
// le compteur prendra la valeur maximale
valeur16b = max_uint16;
}
// sinon, mémorisation de la nouvelle valeur du compteur
else
valeur16b = valeur32b;
}
// sinon, message de rappel débordement numérique
else
{
// "Rappel : Débordement numérique pour la variable"
// "Il faudrait la convertir en 32 bits"
affiche_err ("PAR_DEBORD_NUM");
affiche_err ("BESOIN_CONV32B");
// pas la peine de mettre à jour le fichier pour la variable
majfich = NON;
}
}
// si coefficient coef_moy à mettre à jour
if (majcmoy && (entetevar.typedon & cmoy_sep))
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval - 2, SEEK_SET);
// mettre à jour le coefficient coef_moy
fwrite (&coef_moy, 2, 1, descfic);
}
// sinon si juste mise à jour de la variable
else if (majfich)
{
// se positionner dans le fichier sur la zone à modifier
fseek (descfic, posval, SEEK_SET);
}
// mettre à jour la valeur de la variable (en fonction de sa taille)
if (majfich)
{
if (entetevar.typedon & donnees_32bits)
fwrite (&valeur32b, 4, 1, descfic);
else
fwrite (&valeur16b, 2, 1, descfic);
}
}