Bienvenue dans le premier TP de la partie III, c'est-à-dire le second TP de ce cours. Comme je vous le disais dans le précédent chapitre, nous allons cette fois créer un logiciel pour gérer votre collection de CD, DVD, VHS, BluRay… Plus précisément, notre programme permettra d'enregistrer un film, un album de musique, un jeu vidéo ou un autre type de donnée, mais aussi de consulter a posteriori la liste des œuvres. Je vous propose d'appeler notre programme Maktaba, ce qui signifie «Bibliothèque» en Swahili (pourquoi pas ? On a bien Ubuntu, Amarok…).
Cela nous permettra de réutiliser les types de données structurés (pour enregistrer un film, il faut indiquer son titre, le type de support, son genre…), les types énumérés (les supports CD, DVD…), les fichiers binaires ou texte (pour enregistrer notre liste d'œuvres ou exporter des informations sur une œuvre), les strings (pour enregistrer les titres des morceaux de musique par exemple) ou encore les packages (notre programme devrait être assez conséquent).
Cette fois encore, je commencerai ce TP en vous fournissant un cahier des charges : que veut-on comme fonctionnalités ? Comme données ? Quelle structure pour nos fichiers et notre code source ? Puis, je vous guiderai dans la conception du programme : nous ne réaliserons pas tout en seule fois, je commencerai par vous demander de réaliser un programme simple avant d'ajouter des fonctionnalités supplémentaires ou de prendre en charge des cas particuliers. Enfin, je vous transmettrai les sources et les spécifications d'une solution possible (bien entendu il n'y a pas qu'une seule solution mais plusieurs, chacune ayant ses avantages et inconvénients). En conclusion, comme pour le premier TP, je vous soumettrai quelques idées d'améliorations possibles de notre programme.
Prêt à démarrer ce nouveau challenge ? Alors au travail !
Cahier des charges
Quelles données pour quels types de données ?
Pour établir les types dont nous pourrions avoir besoin, nous devons lister les données nécessaires à notre programme pour l'enregistrement ou la lecture.
Le contenu d'une œuvre
Nous souhaitons enregistrer des œuvres, mais qu'est-ce qu'une œuvre ? C'est avant tout :
- un titre : «autant en emporte le vent», «Mario bros 3», «Nevermind»…
- une catégorie : FILM, JEU (VIDÉO), ALBUM (DE MUSIQUE), AUTRE…
- un support : CD, DVD, BLURAY, VHS, HDDVD…
- une note : de zéro à trois étoiles.
Ensuite, selon la catégorie de l'œuvre, d'autres informations peuvent être nécessaires. Pour un film, nous aurons besoin :
- du nom du réalisateur ;
- de savoir si le film est en VF.
Pour un jeu vidéo, nous aurons besoin :
- de la console : Nes, PS1, PC, Nintendo64…;
- de savoir si vous avez terminé le jeu.
Pour un album de musique, nous aurons besoin :
- du nom de l'artiste : «Nirvana», «ACDC», «Bob Marley»…
- D'une liste des morceaux dans l'ordre : «Come as you are», «Something in the way»…
Il serait bon également qu'un type d'oeuvre par défaut existe.
Des types en cascade
Suite à cela, vous avez du comprendre que nous aurons besoin d'un type T_oeuvre qui soit structuré et polymorphe (voire même mutable, ce serait encore mieux et je vous le conseille fortement). Ce type structuré devrait comprendre de nombreuses composantes de types aussi divers que du texte (string mais pas d'unbounded_string, je vous expliquerai plus tard pourquoi), des tableaux, des booléens, des types énumérés (pour les supports ou la catégorie)…
Rien que ça ? T'avais pas plus long ?
C'est en effet beaucoup et en même temps bien peu ! Pensez que nous aurions pu enregistrer les durées des films ou des morceaux, si les films sont en VOSTFR, la pochette de l'album par exemple, l'emplacement où est sensé être rangé le CD (sur l'étagère, dans la tour, chez le voisin…) ou encore sa date d'achat ou de parution… Ayez en tête que la plupart des logiciels actuels sont bien plus complexes que cela, notre programme n'est que peu de chose à côté. Toutefois, il vous sera possible de le perfectionner plus tard.
Tout cela laisse supposer que nous devrions créer un package spécifique pour déclarer notre type T_Oeuvre afin de libérer notre code source principal. Enfin, dernière information, nos textes devant être enregistrés dans des fichiers, nous ne pourrons pas utiliser les unbounded_string, mais seulement les string. L'explication technique vous sera révélée à la fin de la partie III, lors du chapitre sur les listes. Mais cela implique donc que vos strings devront être suffisamment longs pour pouvoir accueillir des titres à rallonge comme celui-ci, extrait d'un album de Nirvana: «Frances Farmer will have her revenge on Seattle».
Les types de fichiers
Qui dit enregistrement, dit nécessairement fichiers. Aux vues de notre type structuré T_Oeuvre, cela signifie que nous aurions besoin d'un fichier binaire pour jouer le rôle de base de donnée (séquentiel ou à accès direct, c'est à vous de voir. Pour ma part, j'ai choisi les fichiers séquentiels dont la manipulation sera plus simple pour vous). Il serait même bon de séparer les bases de données (une pour les jeux, une pour la musique… ). Ces fichiers porteront par conséquent les noms de «ListeJeu.bdd», "ListeAlbum.bdd", «ListeFilm.bdd» et «ListeAutre.bdd» (bdd = Base De Données).
Quelle architecture pour les fichiers
Notre programme ayant besoin de divers types de fichiers, il serait judicieux de ne pas tout mélanger.
- Maktaba.exe devra se trouver dans un répertoire Maktaba, libre à vous de placer un raccourci sur le bureau si vous le souhaitez.
- Les bases de données ListeJeu.bdd et autres devront se trouver dans un sous-répertoire «data».
- Un sous-répertoire «Manual» permettra l'enregistrement d'un fichier texte.
Cela nous fait donc un répertoire principal et deux sous-répertoires.
Quelles fonctionnalités pour quelles fonctions et procédures ?
Maktaba.exe devra proposer les fonctionnalités suivantes :
- Saisie d'une nouvelle œuvre par l'utilisateur.
- Enregistrement d'une nouvelle œuvre par l'utilisateur (ajout dans la base de donnée).
- Modification par l'utilisateur d'une œuvre existante.
- Suppression par l'utilisateur d'une œuvre existante.
- Affichage de la base de donnée ou d'une oeuvre dans la console (sous la forme d'un tableau).
- Accès aux fonctionnalités par lignes de commande : l'utilisateur devra taper add, modify, delete, print pour accéder à une fonctionnalité. Le programme gèrera bien-sûr d'éventuelles erreurs de frappe commises par l'utilisateur.
- Possibilité d'accéder à un manuel en console par la commande manual. Ce manuel sera rédigé dans un fichier texte «manual.txt» placé dans le sous-répertoire «manual» évoqué précédemment et décrira les différentes commandes possibles.
Architecture du code source
Argh ! ! ! Mais jamais je ne parviendrai à faire tout ça ! Je savais bien que je n'aurais pas du me lancer dans cette galère !
Gardez espoir ! Ce ne sera pas aussi compliqué que cela peut paraître. En revanche, cela risque d'être long (notamment le codage des procédures de saisie et d'affichage), donc il sera nécessaire d'y aller étape par étape et d'adopter une approche par modules (tiens, ça devrait vous rappeler les packages ça). Nous aurons donc à créer les fichiers Ada suivants :
- Maktaba.adb : la procédure principale qui ne se chargera que de l'interface utilisateur, du cœur du logiciel.
- Maktaba_Types.ads : pour déclarer nos types et nos constantes.
- Maktaba_Functions.adb et Maktaba_Functions.ads : pour les différentes fonctionnalités liées à la base de données (lecture, saisie, enregistrement, affichage).
Conception du programme (suivez le guide)
Cette partie n'est pas obligatoire, elle permettra toutefois à ceux qui hésitent à se lancer ou qui ne voient pas comment faire, de trouver une méthode ou des voies pour programmer. Attention, il ne s'agit pas d'une solution toute faite (celle-ci sera fournie à la fin) mais plutôt d'un guide et je vous invite à essayer de réaliser ce TP par vous même, en recourant le moins possible à cette partie.
Création des types
Nous allons commencer par créer deux fichiers : Maktaba.adb et Maktaba_Types.ads. Notre fichier Maktaba.adb ne contiendra pour l'instant pas grand chose :
1 2 3 4 5 6 7 8 | WITH Maktaba_Types ; USE Maktaba_Types ; WITH Ada.Text_IO ; USE Ada.Text_IO ; PROCEDURE Maktaba IS Oeuvre : T_Oeuvre ; BEGIN END Maktaba ; |
Comme vous pouvez le constater il n'y a quasiment rien. Nous allons nous concentrer sur le fichier Maktaba_Types.ads et les différents types : nous devons créer un type structuré et polymorphe (et même mutable) T_Oeuvre. Ce type devra contenir différentes composantes :
- titre de l’œuvre, realisateur, console et artiste seront des strings (avec les contraintes que cela implique en terme de taille), mais surtout pas des unbounded_string (cela poserait problème pour l'enregistrement). Il serait bon que les strings soient initialisés.
- Categorie et support seront des types énumérés.
- VF et Termine seront des boolean (vrai ou faux).
- Note sera un sous-type natural de 0 à 3 ou Integer (voire modulaire).
- Morceaux sera un tableau de 30 strings (ou plus).
À vous donc de créer ce type T_Oeuvre ainsi que les types énumérés T_Categorie et T_Support et le sous-type T_Note. Pensez toutefois que, pour être polymorphe, T_Oeuvre doit dépendre de la catégorie de l'oeuvre et que pour être mutable, cette catégorie doit être initialisée :
1 2 3 4 5 6 7 8 | type T_Oeuvre(categorie : T_Categorie := #Une_Valeur#)is record ... case categorie is when FILM => ... ... end case ; end record ; |
Affichage d'une œuvre
Il est temps de créer nos fichiers Maktaba_Functions.adb et Maktaba_Functions.ads ! Nous aurons besoin à l'avenir d'afficher l'intégralité de notre base de données, mais avant d'afficher 300 œuvres, nous devrions créer une fonction ou procédure qui en affiche une et une seule. Cela nous permettra d'avoir dors et déjà un programme Maktaba.exe opérationnel qui saisirait une œuvre (arbitrairement pour l'instant) puis l'afficherait.
1 | procedure Affichage(oeuvre : T_Oeuvre) ; |
Pensez à faire un affichage compact et clair : il y aura à terme des dizaines d'oeuvres ! Pensez également à terminer l'affichage par un ou plusieurs new_line pour éviter les soucis d'affichage plus tard.
Saisie d'une oeuvre
La première chose à faire par la suite sera de créer une procédure ou une fonction de saisie d'une œuvre. Le sous-programme de saisie ne sera pas compliqué à mettre en oeuvre mais sera long à rédiger car il devra prévoir toutes les composantes. Mais avant de vous lancer dans la saisie d'une œuvre, je vous conseille d'implémenter une fonction de saisie de string. Il existe bien get_line ou get, mais si vous souhaitez saisir un string de taille 20, il ne faut pas que l'utilisateur saisisse un texte de 35 ou 3 caractères. Or l'utilisateur final n'aura généralement aucune connaissance de ces contraintes, donc je conseille de commencer par là :
1 | function get_text(taille : natural) return string ; |
Autre indication pour simplifier votre code, il serait bon que votre fonction de saisie d’œuvre (appelons-la Saisie_Oeuvre) ne s’occupe pas de la saisie de la catégorie. Ce travail sera effectué par une fonction tierce (Saisie_Categorie) qui fournira à la première la catégorie à saisir. Cela simplifiera grandement votre travail et votre réflexion. De manière générale, une grande partie de vos fonctions et procédures devraient avoir la catégorie de l'œuvre en paramètre.
1 2 | Function Saisie_Categorie return T_Categorie ; Function Saisie_Oeuvre(Cat : T_Categorie) return T_Oeuvre ; |
Les saisies de strings se feront avec notre fonction get_text. En revanche, les saisies d'entiers devront gérer les cas où l'utilisateur entrerait une note supérieure à 3 :
1 2 3 | TANT QUE choix>3 | Saisir(choix) FIN DE BOUCLE |
De même, pour saisir un booléen ou un type structuré, vous pourrez proposer à l'utilisateur un choix similaire à celui-ci :
1 2 3 4 5 | Votre film est enregistré sur : 1. un CD 2. un DVD 3. une VHS Votre film est-il en VF ? (O : oui / N : Non) _ |
Donc prévoyez les cas où l'utilisateur répondrait de travers pour limiter les plantages.
Gestion des fichiers
La plupart des opérations suivantes se feront uniquement sur les fichiers : sauvegarde dans la base de données (bdd), affichage d'une bdd, modification d'un élément d'une bdd, suppression d'un élément d'une bdd… Nous devrons créer un package pour manipuler des fichiers binaires. Comme dit précédemment, je vous invite à utiliser les fichiers séquentiels plutôt qu'à accès direct pour éviter de rajouter de la difficulté à la difficulté (bien sûr vous êtes libres de votre choix, le type de fichier binaire ne fait pas partie du cahier des charges).
Sauvegarde et affichage avec la BDD
L'implémentation de ces deux fonctionnalités ne devrait pas poser de problème. Il vous suffira d'ouvrir un fichier, de le fermer, en pensant entre temps à soit ajouter un élément (Append_File), soit parcourir le fichier pour le lire (In_file).
Mais si vous avez essayé d'implémenter ces fonctionnalités, vous avez du vous rendre compte qu'elles exigent toutes les deux de commencer par traiter une question toute bête : «Quel fichier dois-je ouvrir ? ». Et cette question, vous devrez vous la reposer à chaque fois. Il y a donc plusieurs façons de faire : soit on la joue gros bourrin et alors «Vive le copier-coller !», soit on est un peu plus futé et on rédige une procédure qui se charge d'ouvrir le bon fichier selon la catégorie fournie en paramètre. Ce paramètre peut être lui-même fourni par la fonction Saisie_categorie évoquée précédemment.
1 2 3 | procedure Ouvrir(cat : T_Categorie) ; procedure Affichage_BDD(cat : T_Categorie) ; procedure Sauvegarde(Oeuvre : T_Oeuvre) ; |
Modification et suppression d'un élément de la BDD
Le plus simple pour effectuer cette opération est de ne manipuler que des fichiers : pas la peine de se casser la tête à tenter de supprimer un élément du fichier. Voici une méthode pour supprimer l'élément numéro N d'un fichier F :
1 2 3 4 5 6 7 8 9 | Ouvrir le fichier F (Nom : truc) Ouvrir le fichier G (Nom : truc2) Copier les (N-1) premiers éléments de F dans G sauter le N-ème élément de F Copier le reste des éléments de F dans G Supprimer F Recreer F (Nom : Truc) comme une copie de G Fermer F Fermer G |
Un raisonnement similaire peut être effectué pour la modification de la BDD.
Affichage du manuel
Là, j'espère bien que vous n'avez pas besoin de moi !
Les commandes
Jusque là, notre fichier Maktaba.adb ne contient rien de bien sérieux, il ne nous sert qu'à tester nos procédures et fonctions. Mais puisque nous avons fini, nous allons pouvoir le rédiger correctement. L'idée ici est simple : si l'utilisateur tape un mot particulier, le programme réalise une opération particulière. Nous allons donc réutiliser notre fonction get_text pour la saisie des commandes. Le corps de la procédure principale sera simple : une boucle infinie qui se contente de demander de saisir du texte et qui, si le texte correspond à une commande connue, lance quelques sous-programmes déjà rédigés. L'un de ces strings entraînera bien entendu la sortie de la boucle (commande : quit ou exit par exemple). En cas d'erreur de l'utilisateur, le programme affichera toutefois une phrase du genre «Si vous ne comprenez rien, vous n'avez qu'à taper Manual pour lire ce #*§%\$€ de Manuel (RTFM)» (en plus aimable bien sûr ) de façon à ne pas laisser l'utilisateur sans indications.
Solutions possibles
Comme promis, voici une solution possible à comparer avec votre travail.
Maktaba.adb :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | ------------------------------------------------------------------------------ -- -- -- PROJET MAKTABA -- -- -- -- MAKTABA.ADS -- -- -- -- -- -- AUTEUR : KAJI9 -- -- DATE : 13/11/2011 -- -- -- -- Contient la procédure principale du logiciel MAKTBA ainsi que les -- -- procédures d'affichage et de saisie. -- -- -- ------------------------------------------------------------------------------ --Retrouvez le tuto à l'adresse suivante http://www.siteduzero.com/tutoriel-3-558031-1-second-tp-un-logiciel-de-gestion-de-bibliotheque.html with Maktaba_Types ; use Maktaba_Types ; with Maktaba_Functions ; use Maktaba_Functions ; with Ada.Characters.Handling ; use Ada.Characters.Handling ; with Ada.Text_IO ; use Ada.Text_IO ; procedure Maktaba is oeuvre : T_Oeuvre ; reponse : string(1..6) ; begin loop Put("> ") ; reponse := Get_Text(6) ; reponse := To_Upper(Reponse) ; if reponse = "QUIT " or reponse = "EXIT " then exit ; elsif reponse = "NEW " then oeuvre := saisie(get_categorie) ; sauvegarde(oeuvre) ; elsif reponse = "MANUAL" then Affichage_Manuel ; elsif reponse = "INIT " or reponse = "ERASE " then creation(get_categorie) ; elsif reponse = "PRINT " then affichage_bdd(get_categorie) ; elsif reponse = "EDIT " then Edit_bdd(get_categorie) ; else put_line("Commande inconnue. Pour plus d'informations, tapez l'instruction MANUAL. ") ; end if ; end loop ; end Maktaba ; |
Maktaba_Types.ads :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ------------------------------------------------------------------------------ -- -- -- PROJET MAKTABA -- -- -- -- MAKTABA_TYPES.ADS -- -- -- -- -- -- AUTEUR : KAJI9 -- -- DATE : 13/11/2011 -- -- -- -- Contient les différents types nécessaires au fonctionnement du logiciel -- -- MAKTABA. -- -- -- ------------------------------------------------------------------------------ --Retrouvez le tuto à l'adresse suivante http://www.siteduzero.com/tutoriel-3-558031-1-second-tp-un-logiciel-de-gestion-de-bibliotheque.html package Maktaba_Types is type T_Categorie is (FILM,JEU,ALBUM,AUTRE) ; type T_Support is (CD, DVD, BLURAY, VHS, HDDVD) ; type T_Morceaux is array(1..30) of string(1..50) ; type T_Oeuvre(categorie : T_Categorie := AUTRE) is record titre : string(1..50) := (others => ' ') ; support : T_Support := CD ; note : natural range 0..3 ; case categorie is when FILM => realisateur : string(1..20) := (others => ' ') ; VF : boolean := false ; when JEU => console : string(1..20) := (others => ' ') ; termine : boolean := false ; when ALBUM => artiste : string(1..20) := (others => ' ') ; morceaux : T_Morceaux := (others =>(others => ' ')) ; when AUTRE => null ; end case ; end record ; type T_Film is new T_Oeuvre(FILM) ; type T_Jeu is new T_Oeuvre(JEU) ; type T_Album is new T_Oeuvre(ALBUM) ; type T_Autre is new T_Oeuvre(AUTRE) ; end ; |
Maktaba_Functions.ads :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | ------------------------------------------------------------------------------ -- -- -- PROJET MAKTABA -- -- -- -- MAKTABA_FUNCTIONS.ADS -- -- -- -- -- -- AUTEUR : KAJI9 -- -- DATE : 13/11/2011 -- -- -- -- Contient les fonctions de saisie, d'affichage, de sauvegarde… du -- -- logiciel MAKTABA. -- -- -- ------------------------------------------------------------------------------ --Retrouvez le tuto à l'adresse suivante http://www.siteduzero.com/tutoriel-3-558031-1-second-tp-un-logiciel-de-gestion-de-bibliotheque.html with Maktaba_Types ; use Maktaba_Types ; WITH Ada.Sequential_IO ; package Maktaba_Functions is Package P_Fichier is new Ada.Sequential_IO(T_Oeuvre) ; use P_Fichier ; subtype T_Fichier is P_Fichier.File_type ; procedure sauvegarde(Oeuvre : in T_Oeuvre) ; procedure sauvegarde(oeuvre : in T_Oeuvre ; rang : natural) ; procedure creation(cat : T_categorie) ; procedure Ouvrir(F: in out T_Fichier ; mode : P_Fichier.File_Mode := P_Fichier.In_file ; cat : T_Categorie); procedure supprimer(cat : T_Categorie ; rang : natural) ; -- SAISIES function get_text(size : integer) return string ; function get_categorie return T_Categorie ; function saisie(cat : T_Categorie) return T_Oeuvre ; -- MANIPULATION DE LA BDD procedure affichage_oeuvre(Oeuvre : in T_Oeuvre) ; procedure affichage_bdd(cat : T_categorie) ; procedure Edit_bdd(cat : T_Categorie) ; -- Manuel procedure affichage_manuel ; end Maktaba_Functions ; |
Maktaba_Functions.adb :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | ------------------------------------------------------------------------------ -- -- -- PROJET MAKTABA -- -- -- -- MAKTABA_FUNCTIONS.ADB -- -- -- -- -- -- AUTEUR : KAJI9 -- -- DATE : 13/11/2011 -- -- -- -- Contient les fonctions de saisie, d'affichage, de sauvegarde ... du -- -- logiciel MAKTABA. -- -- -- ------------------------------------------------------------------------------ --Retrouvez le tuto à l'adresse suivante http://www.siteduzero.com/tutoriel-3-558031-1-second-tp-un-logiciel-de-gestion-de-bibliotheque.html with Ada.Text_IO ; use Ada.Text_IO ; with Ada.Integer_Text_IO ; use Ada.Integer_Text_IO ; with Ada.Characters.Handling ; use Ada.Characters.Handling ; with ada.Strings.Unbounded; Use ada.Strings.Unbounded ; package body Maktaba_Functions is ----------------------------------------------- -- GESTION DES FICHIERS -- ----------------------------------------------- procedure sauvegarde(Oeuvre : in T_Oeuvre) is F : T_Fichier ; begin ouvrir(F,Append_File,oeuvre.categorie) ; write(F,Oeuvre) ; close(F) ; end sauvegarde ; procedure sauvegarde(oeuvre : in T_Oeuvre ; rang : natural) is F,G : T_Fichier ; tmp : T_Oeuvre ; begin -- Ouverture de F en In et de G en Append ouvrir(F,In_File,oeuvre.categorie) ; create(G,Append_File,Name(F) & "2") ; -- copie de F+oeuvre dans G for i in 1..rang-1 loop read(F,tmp) ; write(G,tmp) ; end loop ; write(G,oeuvre) ; read(F,tmp) ; --lecture de l'élément à supprimer while not end_of_file(F) loop read(F,tmp) ; write(G,tmp) ; end loop ; -- Suppression de F / recréation de F -- fermeture de G / réouverture de G delete(F) ; creation(oeuvre.categorie) ; ouvrir(F,Append_File,oeuvre.categorie) ; close(G) ; open(G,In_File,Name(F) & "2") ; -- copie de G dans F while not end_of_file(G) loop read(G,tmp) ; write(F,tmp) ; end loop ; --Fermeture de F / Suppression de G close(F) ; delete(G) ; end sauvegarde ; procedure Creation(cat : T_categorie) is F : T_Fichier ; begin case cat is when FILM => create(F,out_file,"./data/ListeFilm.bdd") ; close(F) ; when JEU => create(F,out_file,"./data/ListeJeu.bdd") ; close(F) ; when ALBUM => create(F,out_file,"./data/ListeAlbum.bdd") ; close(F) ; when AUTRE => create(F,out_file,"./data/ListeAutre.bdd") ; close(F) ; end case ; end creation ; procedure Ouvrir(F: in out T_Fichier ; mode : P_Fichier.File_Mode := P_Fichier.In_file ; cat : T_Categorie) is begin case cat is when FILM => open(F,mode,"./data/ListeFilm.bdd") ; when JEU => open(F,mode,"./data/ListeJeu.bdd") ; when ALBUM => open(F,mode,"./data/ListeAlbum.bdd") ; when AUTRE => open(F,mode,"./data/ListeAutre.bdd") ; end case ; end Ouvrir; procedure supprimer(cat : T_Categorie ; rang : natural) is F,G : T_Fichier ; tmp : T_Oeuvre ; begin -- Ouverture de F en In et de G en Append ouvrir(F,In_File,cat) ; create(G,Append_File,Name(F) & "2") ; -- copie de F-1 oeuvre dans G for i in 1..rang-1 loop read(F,tmp) ; write(G,tmp) ; end loop ; read(F,tmp) ; while not end_of_file(F) loop read(F,tmp) ; write(G,tmp) ; end loop ; -- Suppression de F / recréation de F -- fermeture de G / réouverture de G delete(F) ; creation(cat) ; ouvrir(F,Append_File,cat) ; close(G) ; open(G,In_File,Name(F) & "2") ; -- copie de G dans F while not end_of_file(G) loop read(G,tmp) ; write(F,tmp) ; end loop ; --Fermeture de F / Suppression de G close(F) ; delete(G) ; end supprimer ; ---------------------------------- -- SAISIE -- ---------------------------------- function get_text(size : integer) return string is U : Unbounded_String := Null_Unbounded_String ; T : string(1..size) := (others => ' ') ; begin U := to_unbounded_string(get_line) ; if length(U) > size then T := to_string(U)(1..size) ; else T(1..length(U)) := to_string(U) ; for i in length(U)+1..size loop T(i) := ' ' ; end loop ; end if ; return T ; end get_text ; function get_categorie return T_Categorie is choix_cat : character ; begin Put_line("Choisissez la categorie desiree : ") ; Put_line("F-Film M-Album de Musique") ; Put_line("J-Jeu Video Autre ?") ; Get_Immediate(choix_cat) ; choix_cat := to_upper(choix_cat) ; case choix_cat is when 'F' => return FILM ; when 'M' => return ALBUM ; when 'J' => return JEU; when others => return AUTRE ; end case ; end get_categorie ; function saisie(cat : T_Categorie) return T_Oeuvre is oeuvre : T_Oeuvre(cat) ; choix : character ; note : integer ; begin -- SAISIE DES PARAMETRES COMMUNS Put_line("Quel est le titre de l'oeuvre ? ") ; oeuvre.titre := get_text(50) ; Put_line("Quelle note donneriez-vous ? (Entre 0 et 3) ") ; loop get(note) ; skip_line ; if note in 0..3 then oeuvre.note := note ; exit ; else Put_line("ERREUR ! La note doit être comprise entre 0 et 3 !") ; end if ; end loop ; Put_line("Sur quel type de support l'oeuvre est-elle enregistree ?") ; Put_line("1-VHS 2-CD 3-DVD") ; Put_Line("4-HDDVD 5-BLURAY") ; loop get_immediate(choix) ; choix := to_upper(choix) ; case choix is when '1' => oeuvre.support := VHS ; exit ; when '2' => oeuvre.support := CD ; exit ; when '3' => oeuvre.support := DVD ; exit ; when '4' => oeuvre.support := HDDVD ; exit ; when '5' => oeuvre.support := BLURAY ; exit ; when others => Put_line("Veuillez reconfirmer votre choix.") ; end case ; end loop ; -- SAISIE DES PARAMETRES SPECIFIQUES case cat is when FILM => Put_line("Quel est le realisateur ? ") ; oeuvre.realisateur:= get_text(20) ; Put_line("Le film est-il en VF ? (O : Oui / N : Non)") ; loop get_immediate(choix) ; choix := to_upper(choix) ; if choix = 'O' then oeuvre.vf := true ; exit ; elsif choix = 'N' then oeuvre.vf := false ; exit ; else Put_line("Veuillez appuyer sur O pour Oui ou sur N pour Non") ; end if ; end loop ; return oeuvre ; when ALBUM => Put_line("Quel est l'artiste ? ") ; oeuvre.artiste := get_text(20) ; for i in oeuvre.morceaux'range loop Put_line("Voulez-vous ajouter un morceau ? (O : Oui / N : Non)") ; get_immediate(choix) ; choix := to_upper(choix) ; if choix = 'O' then Put_line("Quel est le titre du morceau ? ") ; oeuvre.morceaux(i) := get_text(50) ; else exit ; end if ; end loop ; return oeuvre ; when JEU => Put_line("Quelle est la console ? ") ; oeuvre.console := get_text(20) ; Put_line("Avez-vous fini le jeu ? (O : Oui / N : Non)") ; loop get_immediate(choix) ; choix := to_upper(choix) ; if choix = 'O' then oeuvre.termine := true ; exit ; elsif choix = 'N' then oeuvre.termine := false ; exit ; else Put_line("Veuillez appuyer sur O pour Oui ou sur N pour Non") ; end if ; end loop ; return oeuvre ; when AUTRE => return oeuvre ; end case ; end Saisie ; ----------------------------------------------- -- AFFICHAGE D'UNE BDD -- ----------------------------------------------- procedure affichage_oeuvre(oeuvre : T_oeuvre) is --Affiche une seule oeuvre null_string : constant string(1..50) := (others => ' ') ; begin put(" >>>Titre : ") ; put(Oeuvre.titre) ; new_line ; put(" >>>Support : ") ; put(T_Support'image(Oeuvre.support)) ; new_line ; put(" >>>Note : ") ; put(Oeuvre.note,1) ; new_line ; case oeuvre.categorie is when FILM => put(" >>>Realisateur : ") ; put(Oeuvre.realisateur) ; new_line ; put(" >>>VF : ") ; if Oeuvre.vf then put("oui") ; else put("non") ; end if ; new_line(2) ; when JEU => put(" >>>Console : ") ; put(Oeuvre.console) ; new_line ; put(" >>>Termine : ") ; if Oeuvre.termine then put("oui") ; else put("non") ; end if ; new_line(2) ; when ALBUM => put(" >>>Artiste : ") ; put(Oeuvre.artiste) ; new_line ; put_line(" >>>Morceaux : ") ; for i in Oeuvre.morceaux'range loop exit when Oeuvre.morceaux(i) = null_string ; put(" ") ; put(i,2) ; put(" : ") ; Put(oeuvre.morceaux(I)); New_Line; end loop ; new_line(2) ; when AUTRE => new_line ; end case ; end affichage_oeuvre ; procedure affichage_bdd(cat : T_categorie) is --Affiche toute une base de données selon la catégorie demandée n : natural := 1 ; suite : character ; Oeuvre : T_Oeuvre(cat) ; F : T_Fichier ; begin ouvrir(F,In_File,cat) ; while not end_of_file(F) loop if n = 0 then put("Cliquez pour continuer") ; get_immediate(suite) ; new_line ; end if ; read(F,Oeuvre) ; Affichage_oeuvre(oeuvre) ; n := (n + 1) mod 5 ; end loop ; close(F) ; end Affichage_bdd ; ------------------------------------------------------ -- EDITION DE LA BASE DE DONNEES -- ------------------------------------------------------ procedure Edit_bdd(cat : T_Categorie) is --Edite une base de données pour modification ou suppression choix : character ; n : natural := 1 ; Oeuvre : T_Oeuvre(cat) ; F : T_Fichier ; begin ouvrir(F,In_File,cat) ; while not end_of_file(F) loop read(F,Oeuvre) ; Affichage_oeuvre(oeuvre) ; put_line("Que voulez-vous faire : Supprimer(S), Modifier(M), Quitter(Q) ou Continuer ?") ; Get_Immediate(choix) ; choix := to_upper(choix) ; if choix = 'M' then close(F) ; oeuvre := saisie(cat) ; sauvegarde(oeuvre,n) ; exit ; elsif choix = 'S' then close(F) ; Supprimer(cat,n) ; exit ; elsif choix = 'Q' then close(F) ; exit ; end if ; n := n + 1 ; end loop ; if Is_Open(F) then close(F) ; end if ; end Edit_bdd ; ------------------------------------------------------ -- EDITION DE LA BASE DE DONNEES -- ------------------------------------------------------ procedure affichage_manuel is F : Ada.text_IO.File_Type ; begin open(F,In_File,"./manual/manual.txt") ; while not end_of_file(F) loop put_line(get_line(F)) ; end loop ; close(F) ; end affichage_manuel ; end Maktaba_Functions ; |
Manual.txt :
1 2 3 4 5 6 7 | Commandes : Quitter : Quit / Exit Nouveau : New Manuel : Manual Réinitialiser une base : Init / Erase Afficher une base : Print Modifier une base : Edit |
Pistes d'amélioration :
- Fournir une interface graphique plutôt que cette vilaine console. Pour l'instant, vous ne pouvez pas encore le faire, mais cela viendra.
- Proposer de gérer d'autres types de supports : disque durs, clés USB…
- Proposer l'enregistrement de nouvelles informations : le genre de l’œuvre (film d'horreur ou d'aventure, album rock ou rap…), une description, les acteurs du film, les membres du groupe de musique, l'éditeur du jeu vidéo, la durée des morceaux…
- Proposer l'exportation de vos bases de données sous formes de fichiers textes consultables plus aisément ou l'importation d'une œuvre à partir d'un fichier texte.
- Permettre de compléter les instructions en ligne de commande par des options : modify -f modifierait un film par exemple.
- Implémenter un service de recherche d’œuvre par titre, par auteur ou même par mots-clés !
Encore une fois, ce ne sont pas les idées qui manquent pour développer un tel logiciel. J'espère toutefois que ce TP vous aura permis de faire un point sur les notions abordées depuis le début de la partie III car nous allons maintenant nous atteler à un type de données plus complexe : les pointeurs. Et, de la même manière que nous avons parlé, reparlé et rereparlé des tableaux, nous allons parler, reparler et rereparler des pointeurs dans les prochains chapitres.