/*
Fichier cylcree.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 de créer un fichier cyloop.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "types.h"
#include "limites.h"
#include "messages.h"
#include "dialogue.h"
#define szmax_nomfic 80
// prototypes
char *recup_nomfic (char *nom);
void choix_cycle ();
void recup_info_var ();
void recap_duree ();
void gendon ();
void gendon16bits ();
void gendon32bits ();
void gendonfloat ();
// 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
// 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 (NULL);
else
nomfic = recup_nomfic (varg [1]);
// terminé si aucun nom de fichier saisi (juste l'extention .cyl)
if (strlen (nomfic) < 5)
return;
// on n'écrase pas un fichier cyloop qui existe déjà
if (access (nomfic, 0) == 0)
// "fichier cyloop %s déjà existant"
err_fatale_arg ("CYLOOP_EXISTE", nomfic);
// création du fichier cyloop
descfic = fopen (nomfic, "w");
if (! descfic)
// "Création impossible du fichier cyloop %s"
err_fatale_arg ("PB_CREE_CYLOOP", nomfic);
// initialisation
entetefic.signature [0] = 'c'; // signature du fichier cyloop
entetefic.signature [1] = 'y';
entetefic.signature [2] = 'l';
entetefic.nb_var = 0; // fichier cyloop de niveau 0 : une variable sans nom
// choix du cycle de mesures
choix_cycle ();
// caractéristiques de la variable mémorisant les cycles
recup_info_var ();
// enregistrement de l'entête du fichier cyloop
// on ne recopie pas les éventuels octets redondants de la structure
fwrite (&entetefic, 16, 1, descfic);
// enregistrement de l'entête de la variable du fichier cyloop
if (entetevar.typedon & cmoy_sep)
// une valeur de coef_moy pour chaque instant du cycle
fwrite (&entetevar, 6, 1, descfic);
else
// champ coef_moy global pour la variable
fwrite (&entetevar, 8, 1, descfic);
// génération des données avec leur valeur initiale
gendon ();
// le fichier cyloop est prêt
if (fclose (descfic) < 0)
// "Problème d'écriture dans le fichier cyloop"
affiche_err ("PB_ECR_CYLOOP");
}
// récupération du nom du fichier cyloop et rajout éventuel de son suffixe
char *recup_nomfic (char *nom)
{
char *nomfic;
int lg_nomfic;
// si un nom de fichier a été passé en paramètre
if (nom)
{
// récupérer sa taille
lg_nomfic = strlen (nom);
// si ce nom se termine par le suffixe .cyl
if ((lg_nomfic > 4) && (strcmp (nom + lg_nomfic - 4, ".cyl") == 0))
{
// mémoriser le nom tel quel
nomfic = malloc (lg_nomfic + 1);
strcpy (nomfic, nom);
}
// sinon
else
{
// rajouter au nom le suffixe .cyl et mémoriser le résultat
nomfic = malloc (lg_nomfic + 5);
strcpy (nomfic, nom);
strcpy (nomfic + lg_nomfic, ".cyl");
}
}
// sinon
else
{
// demander le nom du fichier à l'opérateur et mémoriser sa réponse
nomfic = malloc (szmax_nomfic);
// "Nom du fichier ? "
affiche_msg ("DEMANDE_NOMFICH");
fgets (nomfic, szmax_nomfic - 4, stdin);
// supprimer le '\n' éventuel retourné par la fonction fgets
lg_nomfic = strlen (nomfic);
if (nomfic [lg_nomfic - 1] == '\n')
nomfic [--lg_nomfic] = '\0';
// rajouter au nom le suffixe .cyl si nécessaire
if ((lg_nomfic < 4) || (strcmp (nomfic + lg_nomfic - 4, ".cyl") != 0))
strcpy (nomfic + lg_nomfic, ".cyl");
// vider le buffer clavier
fflush (stdin);
}
// retourner le nom du fichier
return nomfic;
}
// choix du cycle de mesures
void choix_cycle ()
{
struct tm stm; // structure contenant la date et l'heure
uint32 timep; // date et heure dans un uint32
int h_ete; // mémorise si heure d'été en ce moment
int choix, utcloc; // choix de l'opérateur
uint32 duree; // duree d'un cycle
// initialisation champs caractéristiques et état
entetefic.caract_gen = 0;
entetefic.etat_cyloop = 0;
// choix du cycle
// "Choisissez un cycle de mesure\n"
affiche_ligne ("CHOIX_CYCLEMES");
// "Cycle annuel débutant le 1er janvier à 0 H"
// "Cycle mensuel débutant le 1er jour du mois à 0 H"
// "Cycle hebdomadaire débutant le lundi à 0 H"
// "Cycle hebdomadaire débutant le dimanche à 0 H"
// "Cycle journalier débutant à 0 H"
// "Autre cycle"
choix = lecchoix ("CHOIX_CYCLEMES1", "CHOIX_CYCLEMES2",
"CHOIX_CYCLEMES3", "CHOIX_CYCLEMES4",
"CHOIX_CYCLEMES5", "CHOIX_CYCLEMES6", NULL);
if (choix < 6)
{
// choisir le type d'heure
// "utilisation de l'heure temps universel"
// "utilisation de l'heure locale"
utcloc = lecchoix ("UTIL_HEURE_TU", "UTIL_HEURE_LOC", NULL);
if (utcloc & 1)
entetefic.caract_gen |= temps_utc;
// récupérer la date et l'heure courante
time (&timep);
// passer à 0 heures + récupérer date et heure dans structure
if (entetefic.caract_gen & temps_utc)
{
// Passage à 0H par calcul si heure UTC
timep = (timep / secjour) * secjour;
// on récupère la structure ensuite
gmtime_r (&timep, &stm);
}
else
{
// si heure locale on récupère d'abord la structure
localtime_r (&timep, &stm);
// mémorise si on est à l'heure d'été
h_ete = stm.tm_isdst;
// et on modifie l'heure qu'elle contient
stm.tm_hour = 0;
stm.tm_min = 0;
stm.tm_sec = 0;
// avant de recalculer l'heure du début de la journée
timep = mktime (&stm);
}
switch (choix)
{
// Cycle annuel débutant le 1er janvier à 0 H
case 1: entetefic.caract_gen |= cycle_ireg | cycle_annuel;
timep -= stm.tm_yday * secjour;
if (stm.tm_year % 4)
entetefic.duree_cycle = 365 * secjour;
else
entetefic.duree_cycle = 366 * secjour;
break;
// Cycle mensuel débutant le 1er jour du mois à 0 H
case 2: entetefic.caract_gen |= cycle_ireg;
timep -= (stm.tm_mday -1) * secjour;
// la durée du mois pourrait aussi être obtenue par calcul
switch (stm.tm_mon + 1)
{
// février
case 2: if (stm.tm_year % 4)
entetefic.duree_cycle = 28 * secjour;
else
entetefic.duree_cycle = 29 * secjour;
break;
case 4: // mois de 30 jours
case 6:
case 9:
case 11: entetefic.duree_cycle = 30 * secjour;
break;
// mois de 31 jours (7 mois par an)
default: entetefic.duree_cycle = 31 * secjour;
}
break;
// Cycle hebdomadaire débutant le lundi à 0 H
case 3: if (stm.tm_wday)
timep -= (stm.tm_wday - 1) * secjour;
else
timep -= 6 * secjour;
entetefic.duree_cycle = 7 * secjour;
break;
// Cycle hebdomadaire débutant le dimanche à 0 H
case 4: timep -= stm.tm_wday * secjour;
entetefic.duree_cycle = 7 * secjour;
break;
// Cycle journalier débutant à 0 H
case 5: entetefic.duree_cycle = secjour;
}
entetefic.deb_cycle = timep;
if (!(entetefic.caract_gen & temps_utc) && h_ete)
entetefic.etat_cyloop |= heure_ete;
}
else
{
// choix de la durée du cycle
// "Cycle de ... jours"
// "Cycle de ... heures"
// "Cycle de ... minutes"
// "Cycle de ... secondes"
choix = lecchoix ("CYCLE_EN_JOURS", "CYCLE_EN_HEURES",
"CYCLE_EN_MIN", "CYCLE_EN_SEC", NULL);
// "Durée du cycle ? "
affiche_msg ("DEM_DUREE_CYCLE");
duree = lirentier ();
switch (choix)
{
case 1: duree = duree * 24;
case 2: duree = duree * 60;
case 3: duree = duree * 60;
case 4: entetefic.duree_cycle = duree;
}
// choix de l'instant de début du cycle
// "Début du cycle\n"
affiche_ligne ("DEM_DEBUT_CYCLE");
// "Il y a ... jours"
// "Aujourd'hui à 0 heures"
// "Il y a ... heures"
// "Au début de l'heure"
// "Il y a ... minutes"
// "Au début de la minute"
// "Maintenant"
choix = lecchoix ("DEM_DEB_CYCLE1", "DEM_DEB_CYCLE2",
"DEM_DEB_CYCLE3", "DEM_DEB_CYCLE4",
"DEM_DEB_CYCLE5", "DEM_DEB_CYCLE6",
"DEM_DEB_CYCLE7", NULL);
if (choix == 1 || choix == 3 || choix == 5)
{
// "Depuis combien "
affiche_msg ("DEPUIS_COMBIEN");
switch (choix)
{
// "de jours ? "
case 1 : affiche_msg ("COMBIEN_JOURS");
break;
// "d'heures ? "
case 3 : affiche_msg ("COMBIEN_HEURES");
break;
// "de minutes ? "
case 5 : affiche_msg ("COMBIEN_MINUTES");
}
duree = lirentier ();
}
else
duree = 0;
// si démarrage calé sur un début de journée
if (choix <= 2)
{
// choisir le type d'heure
// "utilisation de l'heure temps universel"
// "utilisation de l'heure locale"
utcloc = lecchoix ("UTIL_HEURE_TU", "UTIL_HEURE_LOC", NULL);
if (utcloc & 1)
entetefic.caract_gen |= temps_utc;
}
else
utcloc = 1; // pas de distinction entre heure d'été et
// d'hiver pour les cycles de moins d'une journée
// récupérer la date et l'heure courante
time (&timep);
// calculer l'innstant de début du cycle
switch (choix)
{
case 1: // au début de la journée ou il y a duree jours
case 2: if (utcloc)
// simple calcul si heure UTC
entetefic.deb_cycle =
((timep / secjour) - duree) * secjour;
else
{
// sinon, on soustraira l'hure locale
localtime_r (&timep, &stm);
timep = ((timep / 3600) - stm.tm_hour) * 3600;
// avant de remonter de duree jours
entetefic.deb_cycle = timep - (duree * secjour);
// mémorise également si on est à l'heure d'été
if (stm.tm_isdst)
entetefic.etat_cyloop |= heure_ete;
}
break;
// au début de l'heure
case 3: entetefic.deb_cycle = (timep / 3600) * 3600;
break;
// il y a duree heures
case 4: entetefic.deb_cycle = ((timep / 3600) - duree) * 3600;
break;
// au début de la minute
case 5: entetefic.deb_cycle = (timep / 60) * 60;
break;
// il y a duree minutes
case 6: entetefic.deb_cycle = ((timep / 60) - duree) * 60;
break;
// maintenant
case 7: entetefic.deb_cycle = timep;
}
}
// récapitulatif durée d'un cycle
recap_duree ();
// Saisie du nombre de données par cycle de mesure
do
{
// "\nNombre de données par cycle de mesure ? "
affiche_msg ("DEM_NB_DON_CYCLE");
entetefic.nb_don_cycle = lirentier ();
if (!entetefic.nb_don_cycle)
// "Erreur de saisie, recommencez"
affiche_err ("ERREUR_SAISIE");
}
while (!entetefic.nb_don_cycle);
}
// récapitulatif durée d'un cycle
void recap_duree ()
{
int jour, heure, minute; // détail durée d'un cycle
// "\nUn cycle de mesures "
affiche_msg ("UN_CYCLE_MESURE");
if (entetefic.caract_gen & cycle_ireg)
{
// "peut durer jusqu'à "
affiche_msg ("PEUT_DURER");
if (entetefic.caract_gen & cycle_annuel)
// "366 jours"
affiche_msg ("366_JOURS");
else
// "31 jours"
affiche_msg ("31_JOURS");
}
else
{
// "dure"
affiche_msg ("CYCLE_DURE");
jour = entetefic.duree_cycle / secjour;
heure = (entetefic.duree_cycle % secjour) / 3600;
minute = (entetefic.duree_cycle % 3600) / 60;
if (jour)
{
printf (" %d ", jour);
if (jour > 1)
// "jours"
affiche_msg ("JOURS");
else
// "jour"
affiche_msg ("JOUR");
}
if (heure)
{
printf (" %d ", heure);
if (heure > 1)
// "heures"
affiche_msg ("HEURES");
else
// "heure"
affiche_msg ("HEURE");
}
if (minute)
{
printf (" %d ", minute);
if (minute > 1)
// "minutes"
affiche_msg ("MINUTES");
else
// "minute"
affiche_msg ("MINUTE");
}
}
putchar ('\n');
}
// caractéristiques de la variable mémorisant les cycles
void recup_info_var ()
{
int choix;
int valpond;
// initialisations
entetevar.der_enreg = 0;
entetevar.typedon = 0;
entetevar.extention = 0;
// "\nNature des données mémorisées\n"
// "Compteur de passages", "Valeurs"
affiche_ligne ("NATURE_DONNEES");
choix = lecchoix ("COMPTEUR_PASSAGE", "MEMO_VALEURS", NULL);
if (choix == 1)
entetevar.typedon |= compteur;
// "\nVoulez vous faire un calcul de pondération"
// "à chaque changement de cycle ? "
affiche_ligne ("DEM_CALC_PONDER");
affiche_msg ("DEM_CALC_PONDER2");
if (lirep () != 'n')
{
// "\nCoefficient de pondération ? "
affiche_msg ("SAIS_COEF_PONDER");
valpond = liponder ();
while (valpond < 0 || valpond > 256)
{
// "Coefficient de pondération incorrect"
// "Valeurs autorisées de 0,0039 à 0,996"
// "ou de 0,39 % à 99,61 %"
// "ou de 1/256 à 255/256"
affiche_err ("ERREUR_COEF_POND");
affiche_err ("VAL_PONDER_OK1");
affiche_err ("VAL_PONDER_OK2");
affiche_err ("VAL_PONDER_OK3");
valpond = liponder ();
}
// la pondération minimale est de 1/256
if (! valpond)
valpond = 1;
entetevar.ponderation = valpond;
}
else
entetevar.ponderation = 0;
if (entetevar.ponderation)
{
// "\nDoit on faire un calcul de pondération pour les cycles vides ? "
affiche_msg ("PONDER_CYCLE_VIDE");
if (lirep () != 'n')
entetevar.typedon |= cpt_cycle_vide;
}
// "\nPour les calculs de moyenne, voulez-vous\n"
affiche_ligne ("CALCULS_MOYENNE");
if (entetevar.typedon & compteur)
// "un coefficient global (conseillé)"
// "un coefficient distinct pour chaque instant du cycle"
choix = lecchoix ("COEF_GLOBAL_CONS", "COEF_DISTINCT", NULL);
else
// "un coefficient global pour tout le cycle"
// "un coefficient distinct pour chaque instant du cycle"
choix = lecchoix ("COEF_GLOBAL", "COEF_DISTINCT", NULL);
if (choix == 1)
entetevar.coef_moy = 0;
else
entetevar.typedon |= cmoy_sep;
// "\nDurant un cycle, chaque instant peut il être pris en compte\n"
// "une fois", "plusieurs fois"
affiche_ligne ("CPT_INSTANTS");
choix = lecchoix ("UNE_FOIS", "PLUSIEURS_FOIS", NULL);
if (choix == 2)
entetevar.typedon |= cumul_donnees;
if ((entetevar.typedon & cmoy_sep) &&
(entetevar.typedon & cumul_donnees))
{
// "\nLe coefficient de calcul de la moyenne doit il être mis à jour\n"
// "une fois pour chaque instant du cycle"
// "autant de fois que l'est la variable mémorisée"
affiche_ligne ("MAJ_COEF_MOY");
choix = lecchoix ("UNE_FOIS_INSTANT", "AUTANT_FOIS_VAR", NULL);
if (choix == 2)
entetevar.typedon |= cpt_toute_don;
}
// "\nFormat des données mémorisées\n"
affiche_ligne ("DEM_FORM_DONNEES");
// si la variable est un compteur
if (entetevar.typedon & compteur)
{
// choix de la taille des données mémorisées
if (entetevar.typedon & cumul_donnees)
// "entier 16 bits", "entier 32 bits"
choix = lecchoix ("ENTIER_16_BITS", "ENTIER_32_BITS", NULL);
else
// "entier 16 bits (suffisant)", "entier 32 bits"
choix = lecchoix ("ENTIER_16_B_SUF", "ENTIER_32_BITS", NULL);
if (choix == 2)
entetevar.typedon |= donnees_32bits;
}
// sinon la variable mémorise une valeur à chaque instant des cycles
else
{
// choix de la nature des données mémorisées
// "entier 32 bits", "nombre flottant"
choix = lecchoix ("ENTIER_32_BITS", "NOMBRE_FLOTTANT", NULL);
entetevar.typedon |= donnees_32bits;
if (choix == 2)
entetevar.typedon |= val_float;
// mémorisation des valeurs min et max des données ?
// "\nVoulez vous mémoriser les valeurs"
// "min et max de chaque instant du cycle ? "
affiche_ligne ("MEM_MIN_MAX_1");
affiche_msg ("MEM_MIN_MAX_2");
if (lirep () != 'n')
entetevar.typedon |= mem_min_max;
}
}
// génération des données avec leur valeur initiale
void gendon ()
{
// on appele une fonction dépendant du format des données
if (entetevar.typedon & compteur)
{
if (entetevar.typedon & donnees_32bits)
gendon32bits ();
else
gendon16bits ();
}
else
{
if (entetevar.typedon & val_float)
gendonfloat ();
else
gendon32bits ();
}
}
// génération des données d'une variable 16 bits avec leur valeur initiale
void gendon16bits ()
{
// la structure de donnée maximale pour une variable 16 bits
struct
{
uint16 coef_moy;
int16 total;
} donnees;
int nb_octets; // nombre d'octets utilisés dans la structure ci-dessus
void *debdon; // adresse de début des données recopiées dans le fichier
int i; // compteur de boucle
// initialiser les champs de la structure
// et calculer debdon et nb_octets
if (entetevar.typedon & cmoy_sep)
{
donnees.coef_moy = 0;
debdon = &donnees;
nb_octets = 4;
}
else
{
debdon = &donnees.total;
nb_octets = 2;
}
donnees.total = 0;
// recopier les données dans le fichier cyloop
for (i = 0; i < entetefic.nb_don_cycle; i++)
if (! fwrite (debdon, nb_octets, 1, descfic))
// "Problème d'écriture dans le fichier cyloop"
err_fatale ("PB_ECR_CYLOOP");
}
// génération des données d'une variable 32 bits avec leur valeur initiale
void gendon32bits ()
{
// la structure de donnée maximale pour une variable 32 bits
struct
{
uint16 vide; // sinon coef_moy serait au mauvais endroit
uint16 coef_moy;
int32 total;
int32 min;
int32 max;
} donnees;
int nb_octets; // nombre d'octets utilisés dans la structure ci-dessus
void *debdon; // adresse de début des données recopiées dans le fichier
int i; // compteur de boucle
// initialiser les champs de la structure
// et calculer debdon et nb_octets
if (entetevar.typedon & cmoy_sep)
{
donnees.coef_moy = 0;
debdon = &donnees.coef_moy;
nb_octets = 6;
}
else
{
debdon = &donnees.total;
nb_octets = 4;
}
donnees.total = 0;
if (entetevar.typedon & mem_min_max)
{
donnees.min = max_int32;
donnees.max = min_int32;
nb_octets = nb_octets + 8;
}
// recopier les données dans le fichier cyloop
for (i = 0; i < entetefic.nb_don_cycle; i++)
if (! fwrite (debdon, nb_octets, 1, descfic))
// "Problème d'écriture dans le fichier cyloop"
err_fatale ("PB_ECR_CYLOOP");
}
// génération des données d'une variable non entière avec leur valeur initiale
void gendonfloat ()
{
// la structure de donnée maximale pour une variable 32 bits
struct
{
uint16 vide; // sinon coef_moy serait au mauvais endroit
uint16 coef_moy;
float total;
float min;
float max;
} donnees;
int nb_octets; // nombre d'octets utilisés dans la structure ci-dessus
void *debdon; // adresse de début des données recopiées dans le fichier
int i; // compteur de boucle
// initialiser les champs de la structure
// et calculer debdon et nb_octets
if (entetevar.typedon & cmoy_sep)
{
donnees.coef_moy = 0;
debdon = &donnees.coef_moy;
nb_octets = 6;
}
else
{
debdon = &donnees.total;
nb_octets = 4;
}
donnees.total = 0;
if (entetevar.typedon & mem_min_max)
{
donnees.min = max_float;
donnees.max = min_float;
nb_octets = nb_octets + 8;
}
// recopier les données dans le fichier cyloop
for (i = 0; i < entetefic.nb_don_cycle; i++)
if (! fwrite (debdon, nb_octets, 1, descfic))
// "Problème d'écriture dans le fichier cyloop"
err_fatale ("PB_ECR_CYLOOP");
}