Inout
Des fonctions simples de lecture au clavier en C.
inout.c
Aller à la documentation de ce fichier.
1/**
2 * \file inout.c
3 * \brief Des fonctions simples de lecture au clavier en C.
4 * \author Pierre Courtieu
5 * \version 0.1
6 * \date 17 août 2017
7 *
8 * À utiliser dans le cours d'initiation à la programmation. DUT FIP CNAM.
9 *
10 */
11
12/* Wrapper class for students for IO in C.
13 Copyright (C) 2017 Pierre Courtieu.
14
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of the GNU Lesser General Public License
17 as published by the Free Software Foundation; either
18 version 2.1 of the License, or (at your option) any later version.
19
20 This library is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 Lesser General Public License for more details (see
24 <http://www.gnu.org/licenses/>).
25*/
26#include<stdio.h>
27#include<stdlib.h>
28#include <string.h>
29#include <assert.h>
30#include <time.h>
31
32/** alias BOOL pour int */
33#define BOOL int
34
35/** alias FALSE pour 0 */
36#define FALSE 0
37
38/** alias TRUE pour 1. */
39#define TRUE 1
40
41///@private
42/* \brief Vide le buffer stdin jusqu'a prochain retour à la ligne.
43
44 Attention, si rien n'est dans le buffer le programme attend. On
45 purge les caractère pas paquet de 10 caractères.
46*/
47void purge_line (){
48 char trash[10];
49 int nbread=0;
50 do{
51 fgets (trash , 10 , stdin);
52 nbread = strlen(trash);
53 } while(trash[nbread-1]!='\n');
54}
55
56
57///@private pour cause de: pas pratique à utiliser
58/* @brief Lecture d'une chaîne au clavier sans allocation.
59
60 Écrit dans le tableau de caractères `s` la chaine de caractères
61 tapée au clavier jusqu'à un saut de ligne (touche entrée). Ignore
62 et consomme les caractères tapés au delà de la taille autorisée
63 (`size`) jusqu'au saut de ligne. Les caractères suivant le saut de
64 ligne ne sont ni lus ni consommés.
65
66 ATTENTION `size` doit être strictement inférieur à la taile du
67 tableau (la dernière case est utilisée pour mettre le caractère
68 spécial `\0` qui signale la fin de la chaîne).
69
70 Exemple d'utilsation:
71 \code{c}
72 char s [21];
73 lireString(s,20);
74 \endcode
75
76 \param s a string (`char *` ou `char[]`).
77 \param size the size of `s - 1`
78
79 */
80void lireCharArray(char s[],int size);
81/* NB. On n'utilise pas `scanf` ou `gets` qui sont obsolètes.
82
83 NB 2. `s` est déclaré comme un tableau dans les arguments mais dans
84 ce cas il est implictement considéré comme un pointeur. L'usage
85 veut qu'on mette plutôt un pointeur mais je préfère ne pas utiliser
86 cette notation pour des débutant. Nous verrons le passage par
87 référence en fin de semestre. */
88void lireCharArray(char s[],int size){
89 /* Lecture au clavier, `fgets` garde le dernier caractère pour le `\0` */
90 fgets (s , size+1 , stdin); /* s==NULL? */
91 int nbread = strlen(s);
92 /* `fgets` garde le `\n` dans la chaine si il est dans les bornes.
93 Si il est là on le remplace par `\0`. */
94 if (nbread < size || (nbread == size && s[nbread-1]=='\n')) {
95 s[nbread-1]='\0';
96 }
97 else { /* Sinon c'est qu'il reste des caractères sur la ligne. On
98 les purge en oubliant tout jusqu'au prochain saut de
99 ligne. */
100 purge_line();
101 }
102}
103
104void debugChar(char c){
105 switch(c) {
106 case '\n': printf("\\n"); break;
107 case '\r': printf("\\r"); break;
108 case '\0': printf("\\0"); break;
109 default: printf("%c",c);
110 }
111}
112
113void debugString(char * s){
114 int max = strlen(s);
115 int i=0;
116 for(i = 0; i <= max; i = i +1){
117 debugChar(s[i]);
118 }
119
120}
121
122
123char * lireStringFile(FILE * input) {
124 char d;
125 char c=' ';
126 int i=0;
127 int size = 32; /* Taille initial du tableau de char, on agrandira si nécessaire. */
128 char * res = malloc (sizeof(char)*size);
129 res[0]='\0'; // In case nos character is read at all
130 int eofbeforeanything = TRUE;
131 while((c=fgetc(input))!=EOF) {
132 eofbeforeanything = FALSE;
133 if (i>size - 2) { // Faut-il agrandir?
134 size = size*2;
135 void * res_realloc = realloc(res,(sizeof(char)*size));
136 if(res_realloc == NULL){
137 printf("Memory allocation failed!\n");
138 exit(1);
139 } else {
140 res = res_realloc;
141 }
142 }
143 switch(c) {
144 case '\n': // On a fini
145 res[i]='\0';
146 return res;
147 break;
148 case '\r': // On a presque fini: on consomme le \n juste après si il existe
149 d = getc(input);
150 if(d!='\n') {// il ne fallait pas consommer ce caractère
151 ungetc(d,input);
152 res[i]='\0';
153 return res;
154 }
155 else { // On a consommé le \n suivant le \r on a fini
156 res[i]='\0';
157 return res;
158 }
159 break;
160 default: // On n'a pas fini
161 res[i]=c;
162 i=i+1;
163 }
164 }
165 if (eofbeforeanything) {
166 free(res);
167 return NULL; // If end of file was reached before any char (not even a CR).
168 } else {
169 return res;
170 }
171}
172
173/** Lecture d'une ligne au clavier. Le retour à la ligne n'est pas
174 inclu dans la chaine retournée mais il est consommé. */
175char * lireString() {
176 return lireStringFile(stdin);
177}
178
179
180///@private
181/* Ajoute les mot de lignecourante dans t à partir de l'indice aPartirDe.*/
182int ajouteMots(char * lignecourante,char *t[],int aPartirDe){
183 int i = aPartirDe;
184 char * motsuivant=strtok(lignecourante," ");
185 do {
186 if (motsuivant!=NULL) {
187 t[i] = motsuivant;
188 i = i + 1;
189 motsuivant = strtok(NULL," ");
190 }
191 } while (motsuivant!=NULL);
192 return i;
193}
194
195///@private
196int max (int i, int j) {
197 return i>j?i:j;
198}
199
200
201/** \brief Lecture des mots d'un fichiers + modifie le deuxième
202 arguments (nb de mots lus).
203
204 Retourne un tableau de chaines de charactères contenant tous les
205 mots du fichier nomFicher.
206
207 La fonction modifie également la valeur du deuxième argument afin
208 qu'il contienne le nombre de mots dans le tableau retourné.
209 **/
210char ** lireFichierParMots(char * nomFicher, int* nombreMots) {
211 int size = 32; /* Taille initial du tableau de char, on agrandira si nécessaire. */
212 char ** t = (char**)malloc(sizeof(char *)*size);
213 int i=0;
214 FILE *FICHIER1 =fopen(nomFicher,"r");
215 char * lignecourante;
216 BOOL fini = FALSE;
217 while(! fini){
218 lignecourante = lireStringFile(FICHIER1);
219 if (lignecourante == NULL) {
220 fini = TRUE;
221 } else {
222 int nb_spaces = strlen (lignecourante);
223 if (i>=size - nb_spaces) { // Faut-il agrandir?
224 void * t_realloc = realloc(t,max(sizeof(char *)*size*2,size+nb_spaces));
225 if(t_realloc == NULL){
226 printf("Memory allocation failed!\n");
227 exit(1);
228 } else {
229 t = t_realloc;
230 }
231 size = size*2;
232 }
233 if (i>size - nb_spaces) { // Faut-il agrandir encore plus?
234 void * t_realloc = realloc(t,sizeof(char *)*size+2*nb_spaces*sizeof(char *));
235 if(t_realloc == NULL){
236 printf("Memory allocation failed!\n");
237 exit(1);
238 }
239 size = size+2*nb_spaces;
240 }
241 i = ajouteMots(lignecourante,t,i); // Ajoute les mot de lignecourante dans t.
242 }
243 }
244 *nombreMots = i; // On modifie le paramètre
245 return t;
246}
247
248///@private
249/** \brief Fonction auxiliaire de gestion d'erreur de sscanf. */
250void dispatchError(int nbmatch, char * msg) {
251 if (nbmatch == EOF) {
252 printf("Erreur de lecture\n");
253 exit(1);
254 }
255 else if (nbmatch == 0) {
256 printf("Erreur, ceci n'est pas un(e) %s\n",msg);
257 exit(1);
258 }
259}
260
261/* Lecture d'un entier suivi d'un saut de ligne. */
263 char * s=lireString();
264 int res;
265 int nbmatch = sscanf(s,"%d",&res);
266 if (nbmatch == 1) {
267 free(s);
268 return res;
269 }
270 else {
271 dispatchError(nbmatch,"entier");
272 assert(FALSE);
273 }
274}
275
276/* Lecture d'un entier suivi d'un saut de ligne avec valeur par défaut
277 en cas d'échec. Le seul cas où la fonction plante est quand il n'y
278 a pas du tout de texte tapé (même pas une ligne vide), c'est-à-dire
279 lorsque quelquechose met fin à la lecture (end of file
280 principalement: la fin d'un fichier ou ctrl-d). */
281int lireIntDefaut(int defaut){
282 char * s=lireString();
283 if (s==NULL) { printf("\nPlus d'entrée, fin du programme.\n"); exit (1); }
284 int res;
285 int nbmatch = sscanf(s,"%d",&res);
286 if (nbmatch == 1) {
287 free(s);
288 return res;
289 }
290 else {
291 return defaut;
292 }
293}
294
295/* Lecture d'un caractère suivi d'un saut de ligne. */
296char lireChar(){
297 char * s = lireString();
298 char res;
299 int nbmatch = sscanf(s,"%c",&res);
300 if (nbmatch == 1) {
301 free(s);
302 return res;
303 }
304 else {
305 dispatchError(nbmatch,"caractère");
306 assert(FALSE);
307 }
308}
309
310/* Lecture d'un caractère suivi d'un saut de ligne. */
311char lireCharDefaut(char defaut){
312 char * s = lireString();
313 if (s==NULL) { printf("\nPlus d'entrée, fin du programme.\n"); exit (1); }
314 char res;
315 int nbmatch = sscanf(s,"%c",&res);
316 if (nbmatch == 1) {
317 free(s);
318 return res;
319 }
320 else {
321 return defaut;
322 }
323}
324
325/* Lecture d'un double suivi d'un saut de ligne. */
326double lireDouble(){
327 char * s = lireString();
328 double res;
329 int nbmatch = sscanf(s,"%lf",&res);
330 free(s);
331 if (nbmatch == 1) {
332 return res;
333 }
334 else {
335 dispatchError(nbmatch,"double");
336 assert(FALSE);
337 }
338}
339
340
342
343 time_t timestamp;
344 struct tm * t;
345
346 timestamp = time(NULL);
347 t = localtime(&timestamp);
348 /* t contient maintenant la date et l'heure courante */
349 printf("%d/%d/%d %d:%d:%d",t->tm_mday,t->tm_mon+1,t->tm_year+1900,
350 t->tm_hour,t->tm_min,t->tm_sec);
351}
352
354 time_t timestamp;
355 struct tm * t;
356
357 timestamp = time(NULL);
358 t = localtime(&timestamp);
359 return t -> tm_hour;
360}
361
363 time_t timestamp;
364 struct tm * t;
365
366 timestamp = time(NULL);
367 t = localtime(&timestamp);
368 return t -> tm_min;
369}
370
372 time_t timestamp;
373 struct tm * t;
374
375 timestamp = time(NULL);
376 t = localtime(&timestamp);
377 return t -> tm_sec;
378}
379
381 time_t timestamp;
382 struct tm * t;
383
384 timestamp = time(NULL);
385 t = localtime(&timestamp);
386 return t -> tm_mday;
387}
388
390 time_t timestamp;
391 struct tm * t;
392
393 timestamp = time(NULL);
394 t = localtime(&timestamp);
395 return t -> tm_mon + 1;
396}
397
399 time_t timestamp;
400 struct tm * t;
401
402 timestamp = time(NULL);
403 t = localtime(&timestamp);
404 return 1900 + t -> tm_year;
405}
406
407
408
409void ecrireInt(int n){
410 printf("%d",n);
411}
412
413void ecrireDouble(double n){
414 printf("%lf",n);
415}
416
417void ecrireChar(char c){
418 printf("%c",c);
419}
420
421void ecrireLong(long n){
422 printf("%ld",n);
423}
424
425void ecrireString(char s[]){
426 printf("%s",s);
427}
428
430 printf("\n");
431}
432
433void pause(){
434 purge_line();
435}
void ecrireLong(long n)
Écrit dans le terminal le long n.
Definition: inout.c:421
int lireInt()
Lecture d'un entier suivi d'un saut de ligne.
Definition: inout.c:262
void ecrireDate()
Écrit dans le terminal la date actuelle.
Definition: inout.c:341
void ecrireString(char s[])
Écrit dans le terminal la chaîne de caractères s.
Definition: inout.c:425
void ecrireInt(int n)
Écrit dans le terminal l'entier n.
Definition: inout.c:409
char * lireString()
Lecture d'une chaîne au clavier avec allocation.
Definition: inout.c:175
double lireDouble()
Lecture d'un double suivi d'un saut de ligne.
Definition: inout.c:326
int heureActuelle()
Retourne le numéro de l'heure actuelle (entre 0 et 23).
Definition: inout.c:353
void debugChar(char c)
Fonction de debugage: affiche un caractère. Les caractères \n \r et \0 sont affichés tel quels.
Definition: inout.c:104
int lireIntDefaut(int defaut)
comme liseInt() mais avec une valeur à retourner en cas d'échec de lecture.
Definition: inout.c:281
void ecrireDouble(double n)
Écrit dans le terminal le double n.
Definition: inout.c:413
char lireCharDefaut(char defaut)
comme lireChar() mais avec une valeur à retourner en cas d'échec de lecture.
Definition: inout.c:311
void pause()
Pause jusqu'à ce que l'utilisateur appuie sur entrée.
Definition: inout.c:433
char * lireStringFile(FILE *input)
Lecture d'une chaîne dans un fichier avec allocation.
Definition: inout.c:123
int minuteActuelle()
Retourne le numéro de la minute actuelle (entre 0 et 59).
Definition: inout.c:362
char lireChar()
Lecture d'un caractère suivi d'un saut de ligne.
Definition: inout.c:296
int secondeActuelle()
Retourne le numéro de la seconde actuelle (entre 0 et 59).
Definition: inout.c:371
#define TRUE
Definition: inout.c:39
#define FALSE
Definition: inout.c:36
int moisActuel()
Retourne le numéro du mois actuel (entre 1 et 12).
Definition: inout.c:389
int anneeActuelle()
Retourne le numéro de l'année actuelle (entre 0 et 23).
Definition: inout.c:398
void ecrireSautDeLigne()
Écrit un saut deligne dans le terminal.
Definition: inout.c:429
void ecrireChar(char c)
Écrit dans le terminal le caractère `c.
Definition: inout.c:417
int jourActuel()
Retourne le numéro du jour actuel (entre 1 et 31).
Definition: inout.c:380
#define BOOL
Definition: inout.c:33
void debugString(char *s)
Fonction de debugage: affiche une chaine de cractère en montrant les \n \r et \0.
Definition: inout.c:113
char ** lireFichierParMots(char *nomFicher, int *nombreMots)
Lecture des mots d'un fichiers + modifie le deuxième arguments (nb de mots lus).
Definition: inout.c:210