/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////// /////////////////////////// GESTION DU BACKUP //////////////////////////// ////////////////////////////////////////////////////////////////////////// #include #include #include #include "global.h" #include "pages.h" #include "errors.h" #include "misc.h" #include "windows.h" /// /// GESTION DES PAGES /// void Init_page(T_Page * page) { // Important: appeler cette fonction sur toute nouvelle structure T_Page! if (page!=NULL) { page->Image=NULL; page->Width=0; page->Height=0; memset(page->Palette,0,sizeof(T_Palette)); page->Comment[0]='\0'; page->File_directory[0]='\0'; page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; } } void Download_infos_page_main(T_Page * page) // Affiche la page à l'écran { //int factor_index; int size_is_modified; if (page!=NULL) { size_is_modified=(Main_image_width!=page->Width) || (Main_image_height!=page->Height); Main_screen=page->Image; Main_image_width=page->Width; Main_image_height=page->Height; memcpy(Main_palette,page->Palette,sizeof(T_Palette)); strcpy(Main_comment,page->Comment); strcpy(Main_file_directory,page->File_directory); strcpy(Main_filename,page->Filename); Main_fileformat=page->File_format; if (size_is_modified) { Main_magnifier_mode=0; Main_offset_X=0; Main_offset_Y=0; Pixel_preview=Pixel_preview_normal; Compute_limits(); Compute_paintbrush_coordinates(); } } } void Upload_infos_page_main(T_Page * page) // Sauve l'écran courant dans la page { if (page!=NULL) { page->Image=Main_screen; page->Width=Main_image_width; page->Height=Main_image_height; memcpy(page->Palette,Main_palette,sizeof(T_Palette)); strcpy(page->Comment,Main_comment); strcpy(page->File_directory,Main_file_directory); strcpy(page->Filename,Main_filename); page->File_format=Main_fileformat; } } void Download_infos_page_spare(T_Page * page) { if (page!=NULL) { Spare_screen=page->Image; Spare_image_width=page->Width; Spare_image_height=page->Height; memcpy(Spare_palette,page->Palette,sizeof(T_Palette)); strcpy(Spare_comment,page->Comment); strcpy(Spare_file_directory,page->File_directory); strcpy(Spare_filename,page->Filename); Spare_fileformat=page->File_format; } } void Upload_infos_page_spare(T_Page * page) { if (page!=NULL) { page->Image=Spare_screen; page->Width=Spare_image_width; page->Height=Spare_image_height; memcpy(page->Palette,Spare_palette,sizeof(T_Palette)); strcpy(page->Comment,Spare_comment); strcpy(page->File_directory,Spare_file_directory); strcpy(page->Filename,Spare_filename); page->File_format=Spare_fileformat; } } void Download_infos_backup(T_List_of_pages * list) { Screen_backup=list->Pages[1].Image; if (Config.FX_Feedback) FX_feedback_screen=list->Pages[0].Image; else FX_feedback_screen=list->Pages[1].Image; } void Free_a_page(T_Page * page) { // On peut appeler cette fonction sur une page non allouée. if (page->Image!=NULL) free(page->Image); page->Image=NULL; page->Width=0; page->Height=0; // On ne se préoccupe pas de ce que deviens le reste des infos de l'image. } void Copy_S_page(T_Page * dest,T_Page * source) { *dest=*source; } int Size_of_a_page(T_Page * page) { return sizeof(T_Page)+(page->Width*page->Height)+8; // 8 = 4 + 4 // (Toute zone allouée en mémoire est précédée d'un mot double indiquant sa // taille, or la taille d'un mot double est de 4 octets, et on utilise deux // allocations de mémoires: une pour la T_Page et une pour l'image) } /// /// GESTION DES LISTES DE PAGES /// void Init_list_of_pages(T_List_of_pages * list) { // Important: appeler cette fonction sur toute nouvelle structure // T_List_of_pages! list->List_size=0; list->Nb_pages_allocated=0; list->Pages=NULL; } int Allocate_list_of_pages(T_List_of_pages * list,int size) { // Important: la T_List_of_pages ne doit pas déjà désigner une liste de // pages allouée auquel cas celle-ci serait perdue. int index; /* Debug : if (list->Pages!=NULL) exit(666); */ // On alloue la mémoire pour la liste list->Pages=(T_Page *)malloc(size*sizeof(T_Page)); // On vérifie que l'allocation se soit bien passée if (list->Pages==NULL) return 0; // Echec else { // On initialise chacune des nouvelles pages for (index=0;indexPages+index); list->List_size=size; list->Nb_pages_allocated=0; return 1; // Succès } } void Free_a_list_of_pages(T_List_of_pages * list) { // On peut appeler cette fonction sur une liste de pages non allouée. // Important: cette fonction ne libère pas les pages de la liste. Il faut // donc le faire préalablement si nécessaire. if (list->Pages!=NULL) free(list->Pages); list->Pages=NULL; list->List_size=0; list->Nb_pages_allocated=0; } int Size_of_a_list_of_pages(T_List_of_pages * list) { int result=0; int index; for (index=0;indexNb_pages_allocated;index++) result+=Size_of_a_page(list->Pages+index); return result+sizeof(T_List_of_pages)+4; // C.F. la remarque à propos de Size_of_a_page pour la valeur 4. } void Backward_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'équivalent d'un "Undo" dans la liste de pages. // Elle effectue une sorte de ROL (Rotation Left) sur la liste: // +---+-+-+-+-+-+-+-+-+-+ | // ¦0¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦ | // +---+-+-+-+-+-+-+-+-+-+ | 0=page courante // ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ |_ A=page la plus ancienne // v v v v v v v v v v v | 1=DerniÞre page (1er backup) // +---+-+-+-+-+-+-+-+-+-+ | // ¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦0¦ | // +---+-+-+-+-+-+-+-+-+-+ | // Pour simuler un véritable Undo, l'appelant doit mettre la structure // de page courante à jour avant l'appel, puis en réextraire les infos en // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère // page de la liste). int index; T_Page * temp_page; if (list->Nb_pages_allocated>1) { // On crée la page tempo temp_page=(T_Page *)malloc(sizeof(T_Page)); Init_page(temp_page); // On copie la 1ère page (page 0) dans la page temporaire Copy_S_page(temp_page,list->Pages); // On copie toutes les pages 1-A à leur gauche for (index=1;indexNb_pages_allocated;index++) Copy_S_page(list->Pages+index-1,list->Pages+index); // On copie la page 0 (dont la sauvegarde a été effectuée dans la page // temporaire) en dernière position Copy_S_page(list->Pages+list->Nb_pages_allocated-1,temp_page); // On détruit la page tempo free(temp_page); } } void Advance_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'équivalent d'un "Redo" dans la liste de pages. // Elle effectue une sorte de ROR (Rotation Right) sur la liste: // +-+-+-+-+-+-+-+-+-+-+-+ | // |0|1|2|3|4|5|6|7|8|9|A| | // +-+-+-+-+-+-+-+-+-+-+-+ | 0=page courante // | | | | | | | | | | | |_ A=page la plus ancienne // v v v v v v v v v v v | 1=Dernière page (1er backup) // +-+-+-+-+-+-+-+-+-+-+-+ | // |A|0|1|2|3|4|5|6|7|8|9| | // +-+-+-+-+-+-+-+-+-+-+-+ | // Pour simuler un véritable Redo, l'appelant doit mettre la structure // de page courante à jour avant l'appel, puis en réextraire les infos en // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère // page de la liste). int index; T_Page * temp_page; if (list->Nb_pages_allocated>1) { // On crée la page tempo temp_page=(T_Page *)malloc(sizeof(T_Page)); Init_page(temp_page); // On copie la dernière page dans la page temporaire Copy_S_page(temp_page,list->Pages+list->Nb_pages_allocated-1); // On copie toutes les pages 0-9 à leur droite for (index=list->Nb_pages_allocated-1;index>0;index--) Copy_S_page(list->Pages+index,list->Pages+index-1); // On copie la page plus ancienne page (la "A", dont la sauvegarde a été // effectuée dans la page temporaire) en 1ère position Copy_S_page(list->Pages,temp_page); // On détruit la page tempo free(temp_page); } } int New_page_is_possible( T_Page * new_page, T_List_of_pages * current_list, T_List_of_pages * secondary_list ) { long long mem_available_now; unsigned long current_list_size; unsigned long spare_list_size; unsigned long current_page_size; unsigned long spare_page_size; unsigned long new_page_size; mem_available_now = Memory_free() - MINIMAL_MEMORY_TO_RESERVE; current_list_size =Size_of_a_list_of_pages(current_list); spare_list_size=Size_of_a_list_of_pages(secondary_list); current_page_size =Size_of_a_page(current_list->Pages); spare_page_size =Size_of_a_page(secondary_list->Pages); new_page_size =Size_of_a_page(new_page); // Il faut pouvoir loger la nouvelle page et son backup dans la page // courante, en conservant au pire la 1ère page de brouillon. if ( (mem_available_now + current_list_size + spare_list_size - spare_page_size) < (2*new_page_size) ) return 0; // Il faut pouvoir loger le brouillon et son backup dans la page de // brouillon, en conservant au pire un exemplaire de la nouvelle page dans // la page courante. (pour permettre à l'utilisateur de travailler sur son // brouillon) if ((mem_available_now+current_list_size+ spare_list_size-new_page_size)<(2*spare_page_size)) return 0; return 1; } void Free_last_page_of_list(T_List_of_pages * list) { if (list!=NULL) { if (list->Nb_pages_allocated>0) { list->Nb_pages_allocated--; Free_a_page(list->Pages+list->Nb_pages_allocated); } } } void Create_new_page(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list) { // Cette fonction crée une nouvelle page dont les attributs correspondent à // ceux de new_page (width,height,...) (le champ Image est invalide // à l'appel, c'est la fonction qui le met à jour), et l'enfile dans // current_list. // Il est impératif que la création de cette page soit possible, // éventuellement au détriment des backups de la page de brouillon // (secondary_list). Afin de s'en assurer, il faut vérifier cette // possibilité à l'aide de // New_page_is_possible(new_page,current_list,secondary_list) avant // l'appel à cette fonction. // De plus, il faut qu'il y ait au moins une page dans chacune des listes. int need_to_free; T_List_of_pages * list_to_reduce=NULL; T_Page * page_to_delete; int index; // On regarde s'il faut libérer des pages: need_to_free= // C'est le cas si la current_list est pleine ( (current_list->List_size==current_list->Nb_pages_allocated) // ou qu'il ne reste plus assez de place pour allouer la new_page || ( (Memory_free()-MINIMAL_MEMORY_TO_RESERVE)< (unsigned long)(new_page->Height*new_page->Width) ) ); if (!need_to_free) { // On a assez de place pour allouer une page, et de plus la current_list // n'est pas pleine. On n'a donc aucune page à supprimer. On peut en // allouer une directement. new_page->Image=(byte *)malloc(new_page->Height*new_page->Width); } else { // On manque de mémoire ou la current_list est pleine. Dans tous les // cas, il faut libérer une page... qui peut-être pourra re-servir. // Tant qu'il faut libérer while (need_to_free) { // On cherche sur quelle liste on va virer une page // S'il reste des pages à libérer dans la current_list if (current_list->Nb_pages_allocated>1) // Alors on va détruire la dernière page allouée de la current_list list_to_reduce=current_list; else { if (secondary_list->Nb_pages_allocated>1) { // Sinon on va détruire la dernière page allouée de la // secondary_list list_to_reduce=secondary_list; } else { // Bon, alors là, on vient de vider toutes les pages et on a toujours pas asez de mémoire... C'est donc qu'un vilain programmeur a oublié de vérifier avec Noiuvelle_page_possible avant de venir ici. // On sort méchament du programme sans sauvegarde ni rien. De toutes façons, ça ne devrait jamais se produire... Error(ERROR_SORRY_SORRY_SORRY); } } // Puis on détermine la page que l'on va supprimer (c'est la dernière de // la liste) page_to_delete=list_to_reduce->Pages+(list_to_reduce->Nb_pages_allocated)-1; // On regarde si on peut recycler directement la page (cas où elle // aurait la même surface que la new_page) if ((page_to_delete->Height*page_to_delete->Width)== (new_page->Height*new_page->Width)) { // Alors // On récupère le bitmap de la page à supprimer (évite de faire des // allocations/désallocations fastidieuses et inutiles) new_page->Image=page_to_delete->Image; // On fait semblant que la dernière page allouée ne l'est pas list_to_reduce->Nb_pages_allocated--; // On n'a plus besoin de libérer de la mémoire puisqu'on a refilé à // new_page un bitmap valide need_to_free=0; } else { // Sinon // Détruire la dernière page allouée dans la Liste_à_raboter Free_last_page_of_list(list_to_reduce); // On regarde s'il faut continuer à libérer de la place need_to_free=(Memory_free()-MINIMAL_MEMORY_TO_RESERVE) <(unsigned long)(new_page->Height*new_page->Width); // S'il ne faut pas, c'est qu'on peut allouer un bitmap // pour la new_page if (!need_to_free) new_page->Image=(byte *)malloc(new_page->Height*new_page->Width); } } } // D'après l'hypothèse de départ, la boucle ci-dessus doit s'arrêter car // on a assez de mémoire pour allouer la nouvelle page. // Désormais new_page contient un pointeur sur une zone bitmap valide. // Décaler la current_list d'un cran vers le passé. for (index=current_list->List_size-1;index>0;index--) Copy_S_page(current_list->Pages+index,current_list->Pages+index-1); // Recopier la new_page en 1ère position de la current_list Copy_S_page(current_list->Pages,new_page); current_list->Nb_pages_allocated++; } void Change_page_number_of_list(T_List_of_pages * list,int number) { int index; T_Page * new_pages; // Si la liste a déjà la taille demandée if (list->List_size==number) // Alors il n'y a rien à faire return; // Si la liste contient plus de pages que souhaité if (list->List_size>number) // Alors pour chaque page en excés for (index=number;indexList_size;index++) // On libère la page Free_a_page(list->Pages+index); // On fait une nouvelle liste de pages: new_pages=(T_Page *)malloc(number*sizeof(T_Page)); for (index=0;indexList_size);index++) Copy_S_page(new_pages+index,list->Pages+index); // On libère l'ancienne liste free(list->Pages); // On met à jour les champs de la nouvelle liste list->Pages=new_pages; list->List_size=number; if (list->Nb_pages_allocated>number) list->Nb_pages_allocated=number; } void Free_page_of_a_list(T_List_of_pages * list) { // On ne peut pas détruire la page courante de la liste si après // destruction il ne reste pas encore au moins une page. if (list->Nb_pages_allocated>1) { // On fait faire un undo à la liste, comme ça, la nouvelle page courante // est la page précédente Backward_in_list_of_pages(Main_backups); // Puis on détruit la dernière page, qui est l'ancienne page courante Free_last_page_of_list(list); } } /// /// GESTION DES BACKUPS /// int Init_all_backup_lists(int size,int width,int height) { // size correspond au nombre de pages que l'on souhaite dans chaque liste // (1 pour la page courante, puis 1 pour chaque backup, soit 2 au minimum). // width et height correspondent à la dimension des images de départ. T_Page * page; int return_code=0; if (Allocate_list_of_pages(Main_backups,size) && Allocate_list_of_pages(Spare_backups,size)) { // On a réussi à allouer deux listes de pages dont la taille correspond à // celle demandée par l'utilisateur. // On crée un descripteur de page correspondant à la page principale page=(T_Page *)malloc(sizeof(T_Page)); Init_page(page); Upload_infos_page_main(page); // On y met les infos sur la dimension de démarrage page->Width=width; page->Height=height; // On regarde si on peut ajouter cette page if (New_page_is_possible(page,Main_backups,Spare_backups)) { // On peut, donc on va la créer Create_new_page(page,Main_backups,Spare_backups); Download_infos_page_main(page); Download_infos_backup(Main_backups); // Maintenant, on regarde si on a le droit de créer la même page dans // la page de brouillon. if (New_page_is_possible(page,Spare_backups,Main_backups)) { // On peut donc on le fait Create_new_page(page,Spare_backups,Main_backups); Download_infos_page_spare(page); // Et on efface les 2 images en les remplacant de "0" memset(Main_screen,0,Main_image_width*Main_image_height); memset(Spare_screen,0,Spare_image_width*Spare_image_height); return_code=1; } else { // Il n'est pas possible de démarrer le programme avec la page // principale et la page de brouillon aux dimensions demandée par // l'utilisateur. ==> On l'envoie ballader return_code=0; } } else { // On ne peut pas démarrer le programme avec ne serait-ce qu'une // page de la dimension souhaitée, donc on laisse tout tomber et on // le renvoie chier. free(page); return_code=0; } } else { // On n'a même pas réussi à créer les listes. Donc c'est même pas la // peine de continuer : l'utilisateur ne pourra jamais rien faire, // autant avorter le chargement du programme. return_code=0; } return return_code; } void Set_number_of_backups(int nb_backups) { Change_page_number_of_list(Main_backups,nb_backups+1); Change_page_number_of_list(Spare_backups,nb_backups+1); // Le +1 vient du fait que dans chaque liste, en 1ère position on retrouve // les infos de la page courante sur le brouillon et la page principale. // (nb_backups = Nombre de backups, sans compter les pages courantes) } int Backup_with_new_dimensions(int upload,int width,int height) { // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et // 0 sinon. T_Page * new_page; int return_code=0; if (upload) // On remet à jour l'état des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); // On crée un descripteur pour la nouvelle page courante new_page=(T_Page *)malloc(sizeof(T_Page)); Init_page(new_page); Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; if (New_page_is_possible(new_page,Main_backups,Spare_backups)) { Create_new_page(new_page,Main_backups,Spare_backups); Download_infos_page_main(new_page); Download_infos_backup(Main_backups); // On nettoie la nouvelle image: memset(Main_screen,0,Main_image_width*Main_image_height); return_code=1; } // On détruit le descripteur de la page courante free(new_page); return return_code; } int Backup_and_resize_the_spare(int width,int height) { // Retourne 1 si la page de dimension souhaitee est disponible en brouillon // et 0 sinon. T_Page * new_page; int return_code=0; // On remet à jour l'état des infos de la page de brouillon (pour pouvoir // les retrouver plus tard) Upload_infos_page_spare(Spare_backups->Pages); // On crée un descripteur pour la nouvelle page de brouillon new_page=(T_Page *)malloc(sizeof(T_Page)); Init_page(new_page); Upload_infos_page_spare(new_page); new_page->Width=width; new_page->Height=height; if (New_page_is_possible(new_page,Spare_backups,Main_backups)) { Create_new_page(new_page,Spare_backups,Main_backups); Download_infos_page_spare(new_page); return_code=1; } // On détruit le descripteur de la page courante free(new_page); return return_code; } void Backup(void) // Sauve la page courante comme première page de backup et crée une nouvelle page // pur continuer à dessiner. Utilisé par exemple pour le fill { #if defined(__macosx__) || defined(__FreeBSD__) T_Page new_page; #else T_Page *new_page; #endif // On remet à jour l'état des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); // On crée un descripteur pour la nouvelle page courante #if defined(__macosx__) || defined(__FreeBSD__) Init_page(&new_page); // Enrichissement de l'historique Copy_S_page(&new_page,Main_backups->Pages); Create_new_page(&new_page,Main_backups,Spare_backups); Download_infos_page_main(&new_page); #else new_page=(T_Page *)malloc(sizeof(T_Page)); Init_page(new_page); // Enrichissement de l'historique Copy_S_page(new_page,Main_backups->Pages); Create_new_page(new_page,Main_backups,Spare_backups); Download_infos_page_main(new_page); #endif Download_infos_backup(Main_backups); // On copie l'image du backup vers la page courante: memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); // On détruit le descripteur de la page courante #if !(defined(__macosx__) || defined(__FreeBSD__)) free(new_page); #endif // On allume l'indicateur de modification de l'image Main_image_is_modified=1; } void Undo(void) { // On remet à jour l'état des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); // On fait faire un undo à la liste des backups de la page principale Backward_in_list_of_pages(Main_backups); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Et celles du backup Download_infos_backup(Main_backups); // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même // palette que la page courante. Mais en temps normal, le backup // n'est pas utilisé à la suite d'un Undo. Donc ça ne devrait pas // poser de problèmes. } void Redo(void) { // On remet à jour l'état des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); // On fait faire un redo à la liste des backups de la page principale Advance_in_list_of_pages(Main_backups); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Et celles du backup Download_infos_backup(Main_backups); // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même // palette que la page courante. Mais en temps normal, le backup // n'est pas utilisé à la suite d'un Redo. Donc ça ne devrait pas // poser de problèmes. } void Free_current_page(void) { // On détruit la page courante de la liste principale Free_page_of_a_list(Main_backups); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Et celles du backup Download_infos_backup(Main_backups); // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même // palette que la page courante. Mais en temps normal, le backup // n'est pas utilisé à la suite d'une destruction de page. Donc ça ne // devrait pas poser de problèmes. } void Exchange_main_and_spare(void) { T_List_of_pages * temp_list; // On commence par mettre à jour dans les descripteurs les infos sur les // pages qu'on s'apprête à échanger, pour qu'on se retrouve pas avec de // vieilles valeurs qui datent de mathuzalem. Upload_infos_page_main(Main_backups->Pages); Upload_infos_page_spare(Spare_backups->Pages); // On inverse les listes de pages temp_list=Main_backups; Main_backups=Spare_backups; Spare_backups=temp_list; // On extrait ensuite les infos sur les nouvelles pages courante, brouillon // et backup. /* SECTION GROS CACA PROUT PROUT */ // Auparavant on ruse en mettant déjà à jour les dimensions de la // nouvelle page courante. Si on ne le fait pas, le "Download" va détecter // un changement de dimensions et va bêtement sortir du mode loupe, alors // que lors d'un changement de page, on veut bien conserver l'état du mode // loupe du brouillon. Main_image_width=Main_backups->Pages->Width; Main_image_height=Main_backups->Pages->Height; Download_infos_page_main(Main_backups->Pages); Download_infos_page_spare(Spare_backups->Pages); Download_infos_backup(Main_backups); } int Can_borrow_memory_from_page(int size) { int mem_available_now; int current_list_size; int spare_list_size; int current_page_size; int spare_page_size; mem_available_now=Memory_free()-MINIMAL_MEMORY_TO_RESERVE; current_list_size =Size_of_a_list_of_pages(Main_backups); spare_list_size=Size_of_a_list_of_pages(Spare_backups); current_page_size =Size_of_a_page(Main_backups->Pages); spare_page_size =Size_of_a_page(Spare_backups->Pages); // Il faut pouvoir loger la zone mémoire ainsi qu'un exemplaire de la page // courante, en conservant au pire la 1ère page de brouillon. if ((mem_available_now +current_list_size +spare_list_size -current_page_size -spare_page_size)Nb_pages_allocated>1) // Alors on va détruire la dernière page allouée de la liste des // brouillons list_to_reduce=Spare_backups; else { if (Main_backups->Nb_pages_allocated>1) { // Sinon on va détruire la dernière page allouée de la // liste principale list_to_reduce=Main_backups; } else { // Dans cette branche, il était prévu qu'on obtienne la mémoire // nécessaire mais on n'arrive pas à la trouver. On indique donc // qu'elle n'est pas disponible, et on aura perdu des backups // pour rien return 0; } } // Puis on détermine la page que l'on va supprimer (c'est la dernière // de la liste) page_to_delete=list_to_reduce->Pages+(list_to_reduce->Nb_pages_allocated)-1; // Détruire la dernière page allouée dans la Liste_à_raboter Free_last_page_of_list(list_to_reduce); // On regarde s'il faut continuer à libérer de la place need_to_free= (Memory_free()-MINIMAL_MEMORY_TO_RESERVE)<(unsigned long)size; // S'il ne faut pas, c'est qu'on peut allouer un bitmap // pour la new_page if (!need_to_free) return malloc(size); } } } else { // Il n'y a pas assez de place pour allouer la mémoire temporaire dans // la mémoire réservée aux pages. return 0; } // Pour que le compilateur ne dise pas qu'il manque une valeur de sortie: return 0; } void End_of_modification(void) { }