701 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			701 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| 
 | |
| #include "ccommon.h"
 | |
| #include "genconst.h"
 | |
| #include "ccustio.h"
 | |
| #include "cbpltree.h"
 | |
| #include "bplpriv.h"
 | |
| #include "btrread.h"
 | |
| #include "btrbase.h"
 | |
| #include "checks.h"
 | |
| #ifdef __WATCOMC__
 | |
| #include <malloc.h>
 | |
| #else
 | |
| #include        <memory.h>
 | |
| #endif
 | |
| 
 | |
| 
 | |
|  void Move(byte ,int ,int ,int ,char *,char *);
 | |
| 
 | |
| /*
 | |
| @(SHF) Funzioni di base per il B+Tree
 | |
| @($) ZPage  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Azzera una pagina del B+TREE.
 | |
| @(FD)
 | |
| */
 | |
| 
 | |
|   void                            ZPage(ActPage)
 | |
|   Page                            *ActPage; /* pagina attuale */
 | |
| 
 | |
|     { 
 | |
| 
 | |
|       ActPage->PA.PageHeader.TPage = EmptyPage;
 | |
|       ActPage->PA.PageHeader.PathNumber = 0;
 | |
|       ActPage->PA.PageHeader.Flags = 0;
 | |
|       ActPage->PA.PageHeader.Father = NoLink;
 | |
|       ActPage->PA.PageHeader.Prev = NoLink;
 | |
|       ActPage->PA.PageHeader.Next = NoLink;
 | |
|       ActPage->PA.PageHeader.NKey = 0;
 | |
|       memset(ActPage->PA.AreaForKey, ' ', AreaLen);
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) GetHeader  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Legge l'header di un indice.
 | |
| Restituisce il codice di errore.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| junk = variabile spazzatura per la chiamata della funzione "sleep".
 | |
| 
 | |
| w    = descrittore della finestra.
 | |
| 
 | |
| @(FSV)
 | |
| 
 | |
| */
 | |
| 
 | |
|   int                                     GetHeader(FilCheck, HPage, LockMode, Err)
 | |
|   FilCtrl                 *FilCheck; /* identificatore indice             */
 | |
|   Page                            *HPage;    /* pagina dell' indice  */
 | |
|   int                                     LockMode;  /* lock sull'header                  */
 | |
|   int                                     *Err;      /* codice di errore                  */
 | |
| 
 | |
|   {
 | |
|     do
 | |
|     {
 | |
|       CRead(&FilCheck->Fil, (char *) HPage, 1L, LockMode);
 | |
|       if (TESTLOCK(FilCheck->Fil.IOR))
 | |
|         message_box("Sono in attesa dell' indice");
 | |
|     } while TESTLOCK(FilCheck->Fil.IOR);
 | |
|     return((*Err = FilCheck->Fil.IOR));
 | |
|   }
 | |
| 
 | |
| /*
 | |
| @($) PutHeader  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Scrive l'header di un indice.
 | |
| Restituisce il codice di errore.
 | |
| @(FD)
 | |
| */
 | |
| 
 | |
|   int                                     PutHeader(FilCheck, HPage, LockMode, Err)
 | |
|   FilCtrl                 *FilCheck; /* identificatore indice    */
 | |
|   Page                            *HPage;    /* pagina in cui scrivere l'header */
 | |
|   int                                     LockMode;  /* lock sull'header                */
 | |
|   int                                     *Err;      /* errore                          */
 | |
| 
 | |
|       {
 | |
|         CWrite(&FilCheck->Fil, (char *) HPage, 1L, LockMode);
 | |
|         return((*Err = FilCheck->Fil.IOR));
 | |
|       }
 | |
| 
 | |
| /*
 | |
| @($) GetAPage  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Legge una pagina generica dell'indice.
 | |
| Restituisce il codice di errore.
 | |
| @(FD)
 | |
| */
 | |
| 
 | |
|   int                                     GetAPage(FilCheck, ActPage, Pg, Err)
 | |
|   FilCtrl                 *FilCheck; /* identificatore indice */
 | |
|   Page                            *ActPage;  /* pagina letta          */
 | |
|   RecNoType               Pg;        /* numero di pagina      */
 | |
|   int                                     *Err;      /* codice di errore      */
 | |
| 
 | |
|     {
 | |
|       CRead(&FilCheck->Fil, (char *) ActPage, Pg + FilCheck->FHead.CABlock + 1,
 | |
|             NoLock);
 | |
|       return((*Err = FilCheck->Fil.IOR)); 
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) PutAPage  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Scrive una pagina generica dell'indice.
 | |
| Restituisce il codice di errore.
 | |
| @(FD)
 | |
| */
 | |
| 
 | |
|   int                                     PutAPage(FilCheck, ActPage, Pg, Err)
 | |
|   FilCtrl                 *FilCheck; /* identificatore indice */
 | |
|   Page                            *ActPage;  /* pagina attiva         */
 | |
|   RecNoType               Pg;        /* numero della pagina   */
 | |
|   int                                     *Err;      /* codice errore         */
 | |
| 
 | |
|     {
 | |
|       CWrite(&FilCheck->Fil, (char *) ActPage, Pg + FilCheck->FHead.CABlock + 1,
 | |
|               NoLock);
 | |
|       return((*Err = FilCheck->Fil.IOR)); 
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) GetAKey  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Estrae una chiave da una pagina.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| BgnItem = numero di byte precedenti alla chiave dall'inizio della pagina.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            GetAKey(ActPage, KeyLen, Pstion, KKey, Index)
 | |
|   Page                            ActPage; /* pagina attiva                    */
 | |
|   int                                     KeyLen;  /* lunghezza della chiave           */
 | |
|   int                                     Pstion;  /* numero chiave nella pagina       */
 | |
|   TKey                            KKey;    /* Valore chiave (in output)        */
 | |
|   RecNoType               *Index;  /* indice associato a questa chiave */
 | |
| 
 | |
|     {
 | |
|       int                                BgnItem;
 | |
| 
 | |
|       BgnItem = (Pstion - 1) * (KeyLen + IndLen);
 | |
|       strcpy(KKey, (char *)(ActPage.PA.AreaForKey + BgnItem));
 | |
|       *Index = *((RecNoType *)(ActPage.PA.AreaForKey + BgnItem + KeyLen));
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) PutAKey  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Mette una chiave in una pagina.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| BgnItem = numero di byte precedenti alla chiave dall'inizio della pagina.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            PutAKey(KKey, Index, Pstion, KeyLen, ActPage)
 | |
|   TKey                            KKey;    /* valore della chiave             */
 | |
|   RecNoType               Index;   /* indice                          */
 | |
|   int                                     Pstion;  /* posizione nella quale scrivere la chiave */
 | |
|   int                                     KeyLen;  /* lunghezza della chiave          */
 | |
|   Page                            *ActPage;/* pagina attiva                   */
 | |
| 
 | |
|     {
 | |
|       register int                                    BgnItem;
 | |
| 
 | |
|       BgnItem = (Pstion - 1) * (KeyLen + IndLen);
 | |
|       strcpy((char *)(ActPage->PA.AreaForKey + BgnItem), KKey);
 | |
|       *((RecNoType *)(ActPage->PA.AreaForKey + BgnItem + KeyLen)) = Index;
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) Repos  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Riposizione all'ultima chiave letta dall'ultima operazione.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| WKey, WKey1 = variabili di lavoro contenenti chiavi.
 | |
| 
 | |
| WPos        = variabile di lavoro contenente il numero di chiave nella pagina.
 | |
| 
 | |
| WPag        = variabile di lavoro contenente il numero di pagina attuale.
 | |
| 
 | |
| WInd,WInd1  = variabili di lavoro contenenti indici associati alle chavi Wkey.
 | |
| @(FSV)
 | |
| 
 | |
| @(IN)
 | |
| Serve solo in multiutenza (XENIX).
 | |
| @(FN)
 | |
| */
 | |
| 
 | |
|   void                            Repos(FilCheck, BError)
 | |
|   FilCtrl                 *FilCheck;  /* identificatore indice     */
 | |
|   int                                     *BError;    /* codice errore (in output) */
 | |
| 
 | |
|   {
 | |
|     TKey                    WKey, WKey1;
 | |
|     int                             WPos = FilCheck->Pos, WError;
 | |
|     RecNoType       WPag = FilCheck->CurPag, WInd, WInd1;
 | |
| 
 | |
|     if (GetAPage(FilCheck, &PathPage, WPag, BError) != NoErr) return;
 | |
|     if (PathPage.PA.PageHeader.NKey < WPos) WPos = PathPage.PA.PageHeader.NKey ;
 | |
|     GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, WPos, WKey, &WInd);
 | |
|     if ((strcmp(WKey, FilCheck->Key) == 0) && (WInd == FilCheck->Ind)) return ;
 | |
|     strcpy(WKey1, FilCheck->Key) ;
 | |
|     WInd = FilCheck->Ind ;
 | |
|     BTrRead(FilCheck, FilCheck->Key, WKey, &WInd1, BError) ;
 | |
|     WPag =  FilCheck->CurPag ;
 | |
|     WPos =  FilCheck->Pos ;
 | |
|     if (*BError == BTrEmptyTree) return ;
 | |
|     if (FilCheck->Base[FilCheck->PN].DupKeys == TRUE)
 | |
|     {
 | |
|       while ((strcmp(WKey, WKey1) == 0) && (WInd1 < WInd))
 | |
|       {
 | |
|         if (WPos < PathPage.PA.PageHeader.NKey) WPos++;
 | |
|         else
 | |
|           if (PathPage.PA.PageHeader.Next == NoLink) break;
 | |
|           else
 | |
|           {
 | |
|             WPag = PathPage.PA.PageHeader.Next;
 | |
|             if (GetAPage(FilCheck, &PathPage, WPag, BError) != NoErr) return;
 | |
|             WPos = 1;
 | |
|           }
 | |
|         GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, WPos, WKey, &WInd1);
 | |
|       }
 | |
|     }
 | |
|     if (GetAPage(FilCheck, &PathPage, WPag, &WError) != NoErr) return;
 | |
|     if ((strcmp(WKey, WKey1) == 0) && (WInd == WInd1))
 | |
|     {
 | |
|       FilCheck->CurPag = WPag;
 | |
|       FilCheck->Pos = WPos;
 | |
|     }
 | |
|     else 
 | |
|     {
 | |
|       if (*BError != BTrEOF)
 | |
|       {
 | |
|         FilCheck->CurPag = WPag;
 | |
|         FilCheck->Pos = WPos;
 | |
|         strcpy(FilCheck->Key, WKey) ;
 | |
|         FilCheck->Ind = WInd1;
 | |
|         *BError = BTrKeyNotFound;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| /*
 | |
| @($) BTrNext  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Restituisce la chiave successiva all'ultima letta.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| WKey = variabile di lavoro contenente la chiave.
 | |
| 
 | |
| - Versione DOS e XENIX
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            BTrNext(FilCheck, KKey, IndSr, BError)
 | |
|   FilCtrl                 *FilCheck; /* identificatore indice   */
 | |
|   TKey                            KKey;      /* valore della chiave     */
 | |
|   RecNoType               *IndSr;    /* indice associato        */
 | |
|   int                                     *BError;   /* codice errore           */
 | |
| 
 | |
|     {
 | |
|       TKey                    WKey;
 | |
| 
 | |
|       if (FilCheck->CurPag == NoLink)
 | |
|       {
 | |
|         MaxKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);
 | |
|         BTrRead(FilCheck, FilCheck->Key, WKey, IndSr, BError) ;
 | |
|         *BError = BTrEOF;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         Repos(FilCheck, BError) ;
 | |
|         if (*BError != NoErr)
 | |
|         {
 | |
|           if (*BError == BTrKeyNotFound)
 | |
|           {
 | |
|             strcpy(KKey,FilCheck->Key);
 | |
|             *IndSr = FilCheck->Ind ;
 | |
|             *BError = NoErr ;
 | |
|           }
 | |
|           return;
 | |
|         }
 | |
|         if (FilCheck->Pos < PathPage.PA.PageHeader.NKey)
 | |
|         {
 | |
|           FilCheck->Pos++;
 | |
|           GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|           if (PathPage.PA.PageHeader.Next == NoLink)
 | |
|           {
 | |
|             GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
 | |
|             /*MaxKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);*/
 | |
|             *BError = BTrEOF;
 | |
|           }
 | |
|           else
 | |
|           {
 | |
|             FilCheck->CurPag = PathPage.PA.PageHeader.Next;
 | |
|             if (GetAPage(FilCheck, &PathPage, FilCheck->CurPag, BError) != NoErr) return;
 | |
|             FilCheck->Pos = 1;
 | |
|             GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
 | |
|           }
 | |
|         }
 | |
|         strcpy(KKey,FilCheck->Key);
 | |
|         FilCheck->Ind = *IndSr ;
 | |
|       }
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) BTrPrev  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Restituisce la chiave successiva all'ultima.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| WKey = variabile di lavoro contenente una chiave.
 | |
| 
 | |
| - Versione DOS e XENIX
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            BTrPrev(FilCheck, KKey, IndSr, BError)
 | |
|   FilCtrl                 *FilCheck; /* identificatore indice  */
 | |
|   TKey                            KKey;      /* valore della chiave (in output) */
 | |
|   RecNoType               *IndSr;    /* indice associato       */
 | |
|   int                                     *BError;   /* codice di errore       */
 | |
| 
 | |
|     {
 | |
|       TKey                    WKey;
 | |
| 
 | |
|       if (FilCheck->CurPag == NoLink)
 | |
|       {
 | |
|         MinKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);
 | |
|         BTrRead(FilCheck, FilCheck->Key, WKey, IndSr, BError) ;
 | |
|         *BError = BTrBOF;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         Repos(FilCheck, BError) ;
 | |
|         if ((*BError != NoErr) && (*BError != BTrKeyNotFound))
 | |
|         {
 | |
|           if (*BError == BTrEOF)
 | |
|           {
 | |
|             strcpy(KKey,FilCheck->Key);
 | |
|             *IndSr = FilCheck->Ind ;
 | |
|             *BError = NoErr ;
 | |
|           }
 | |
|           return;
 | |
|         }
 | |
|         *BError = NoErr;
 | |
|         if (FilCheck->Pos > 1)
 | |
|         {
 | |
|           FilCheck->Pos--;
 | |
|           GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|           if (PathPage.PA.PageHeader.Prev == NoLink)
 | |
|           {
 | |
|             GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
 | |
|             /*MinKey(FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Key);*/
 | |
|             *BError = BTrBOF;
 | |
|           }
 | |
|           else
 | |
|           {
 | |
|             FilCheck->CurPag = PathPage.PA.PageHeader.Prev;
 | |
|             if (GetAPage(FilCheck, &PathPage, FilCheck->CurPag, BError) != NoErr) return;
 | |
|             FilCheck->Pos = PathPage.PA.PageHeader.NKey;
 | |
|             GetAKey(PathPage, FilCheck->Base[FilCheck->PN].KeyLen, FilCheck->Pos, FilCheck->Key, IndSr);
 | |
|           }
 | |
|         }
 | |
|         strcpy(KKey, FilCheck->Key);
 | |
|         FilCheck->Ind = *IndSr ;
 | |
|       }
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) Move  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Sposta a destra od a sinistra un numero di byte "NByt" da una sorgente "Buff1"
 | |
| ad una destinazione "Buff2".
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| w = area di transito.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            Move(RghOrLft, NByt, BytBeg, BytDest, Buff1, Buff2)
 | |
|   byte                            RghOrLft; /* destra o sinistra */
 | |
|   int                                     NByt;     /* numero di byte da spostare */
 | |
|   int                                     BytBeg;   /* num. byte inizio sorgente  */
 | |
|   int                                     BytDest;  /* num. byte inizio destinazione */
 | |
|   AreaKey                 Buff1;    /* sorgente                      */
 | |
|   AreaKey                 Buff2;    /* destinazione                  */
 | |
| 
 | |
|     {
 | |
|       AreaKey         w;
 | |
| 
 | |
|       memcpy(w, &Buff1[BytBeg], NByt);
 | |
|       memcpy(&Buff2[BytDest], w, NByt);
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($) ShiftPage  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Esegue uno spostamento di un certo numero di posizioni (coppie chiave-puntatore)
 | |
| all'interno della pagina.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| Len = lunghezza di una coppia chiave-puntatore.
 | |
| 
 | |
| Beg = numero di byte dall'inizio della pagina alla chiave "StartK" (esclusa).
 | |
| 
 | |
| Dest =  byte al quale si deve postare la coppia chiave-puntatore.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            ShiftPage(RghOrLft, StartK, NPos, MxKey, KeyLen, Page1)
 | |
|   byte                            RghOrLft; /* destra o sinistra  */
 | |
|   int                                     StartK;   /* chiave di partenza */
 | |
|   int                                     NPos;     /* numero di posizioni da saltare  */
 | |
|   int                                     MxKey;    /* numero max chiavi in una pagina */
 | |
|   int                                     KeyLen;   /* lunghezza di una chiave         */
 | |
|   Page                            *Page1;   /* pagina attiva                   */
 | |
| 
 | |
|   {
 | |
|     register int                                    Len = KeyLen + IndLen;
 | |
|     register int                                    Beg = (StartK - 1) * Len;
 | |
|     register int                                    Dest;
 | |
| 
 | |
|     if (RghOrLft == RightDir)
 | |
|     {
 | |
|       Dest = Beg + NPos * Len;
 | |
|       if (Page1->PA.PageHeader.NKey + NPos <= MxKey)
 | |
|       {
 | |
|         Move(RightDir, (Page1->PA.PageHeader.NKey - StartK + 1) * Len, Beg, Dest, Page1->PA.AreaForKey, Page1->PA.AreaForKey);
 | |
|         Page1->PA.PageHeader.NKey += NPos;
 | |
|       }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       Dest = Beg - NPos * Len;
 | |
|       if (StartK - NPos > 0)
 | |
|       {
 | |
|         if (StartK <= Page1->PA.PageHeader.NKey)
 | |
|           Move(LeftDir, (Page1->PA.PageHeader.NKey - StartK + 1) * Len, Beg, Dest, Page1->PA.AreaForKey, Page1->PA.AreaForKey);
 | |
|         Page1->PA.PageHeader.NKey -= NPos;
 | |
|         memset(&Page1->PA.AreaForKey[Page1->PA.PageHeader.NKey * Len], ' ', NPos * Len);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| /*
 | |
| @($) ShiftOut  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Sposta un certo numero di chiavi da una pagina.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| Len = lunghezza coppia chiave-puntatore.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            ShiftOut(FromK, Numk, ToK, KeyLen, Page1, Page2)
 | |
|   int                                     FromK; /* prima chiave da spostare               */
 | |
|   int                                     Numk;  /* numero di chiavi da spostare           */
 | |
|   int                                     ToK;   /* posizione nella pagina destinazione    */
 | |
|   int                                     KeyLen;/* lunghezza della chiave                 */
 | |
|   Page                            *Page1;/* puntatore alla pagina destinazione     */
 | |
|   Page                            *Page2;/* puntatore alla pagina sorgente         */
 | |
| 
 | |
|   {
 | |
|     register int                                    Len = KeyLen + IndLen;
 | |
| 
 | |
|     if (Page1->PA.PageHeader.TPage == Page2->PA.PageHeader.TPage)
 | |
|       Move(LeftDir, Numk * Len, (FromK - 1) * Len, (ToK - 1) * Len, Page2->PA.AreaForKey, Page1->PA.AreaForKey);
 | |
|   }
 | |
| 
 | |
| /*
 | |
| @($) FindPos  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Cerca una chiave all'interno di una pagina.
 | |
| Restituisce la chiave piu' simile.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| low = numero della chiave.
 | |
| 
 | |
| j   = incremento in byte di coppia chiave puntatore.
 | |
| @(FSV)
 | |
| 
 | |
| */
 | |
| 
 | |
|   int                                     FindPos(ActPage, KKey, KeyLen, KeyOut, IndOut)
 | |
|   Page                            *ActPage;  /* pagina attiva          */
 | |
|   TKey                            KKey;      /* valore chiave (input)  */
 | |
|   int                                     KeyLen;    /* lunghezza della chiave */
 | |
|   TKey                            KeyOut;    /* valore chiave (output) */
 | |
|   RecNoType               *IndOut;   /* indice associato       */
 | |
| 
 | |
|   {
 | |
|     register int                            low = 1, j = 0;
 | |
| 
 | |
|     while (strcmp((char *)(ActPage->PA.AreaForKey + j), KKey) < 0)
 | |
|       if (low < ActPage->PA.PageHeader.NKey)
 | |
|       {
 | |
|         low++;
 | |
|         j += (KeyLen + IndLen);
 | |
|       }
 | |
|       else break;
 | |
|     strcpy(KeyOut, (char *)(ActPage->PA.AreaForKey + j));
 | |
|     *IndOut = *((RecNoType *)(ActPage->PA.AreaForKey + j + KeyLen));
 | |
|     return(low);
 | |
|   }
 | |
| 
 | |
| /*
 | |
| @($) PerformOp  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Effettua operazioni di Underflow e Overflow sull'indice.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| Pst    = variabile di lavoro contenente numeri chiave.
 | |
| 
 | |
| W      = contatore.
 | |
| 
 | |
| OldKey = variabile di lavoro contenente il valore di chiavi.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void            PerformOp(RecOp,ActPage,Pg,OvUnFlow,Temp,MxKey,MnKey,KeyLen,BError)
 | |
|   KOp                                             RecOp; /* struttura contenente le operazioni da effettuare */
 | |
|   Page                                    *ActPage; /* pagina attiva           */
 | |
|   RecNoType                       Pg;       /* numero pagina           */
 | |
|   BOOLEAN                         *OvUnFlow;/* underflow opp. overflow */
 | |
|   KeyInd                          *Temp;    /* di lavoro, contiene una coppia chiave-puntatore */
 | |
|   int                                             MxKey;    /* numero max chiave       */
 | |
|   int                                             MnKey;    /* numero min chiave       */
 | |
|   int                                             KeyLen;   /* lunghezza della chiave  */
 | |
|   int                                             *BError;  /* codice errore           */
 | |
| 
 | |
|     {
 | |
|       int                                     Pst, W, i;
 | |
|       TKey                            OldKey;
 | |
| 
 | |
|       for (W = 0; W <= 1; W++)
 | |
|       {
 | |
|         if (RecOp[W].FlagOp)
 | |
|         {
 | |
|           RecOp[W].FlagOp = FALSE;
 | |
|           if (RecOp[W].Which == Inser)
 | |
|           {
 | |
|             Pst = 0;
 | |
|             while (Pst < ActPage->PA.PageHeader.NKey )
 | |
|             {
 | |
|               GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
 | |
|               if (IntIndex == RecOp[W].where) break;
 | |
|             }
 | |
|             if (ActPage->PA.PageHeader.NKey == MxKey)
 | |
|             {
 | |
|               GetAKey(*ActPage, KeyLen, MxKey, IntKey, &IntIndex);
 | |
|               if (strcmp(IntKey, RecOp[W].KeyAndInd.KKey) < 0)
 | |
|               {
 | |
|                 strcpy(Temp->KKey, RecOp[W].KeyAndInd.KKey);
 | |
|                 Temp->Ind = RecOp[W].KeyAndInd.Ind;
 | |
|               }
 | |
|               else
 | |
|               {
 | |
|                 strcpy(Temp->KKey, IntKey);
 | |
|                 Temp->Ind = IntIndex;
 | |
|                 ActPage->PA.PageHeader.NKey--;
 | |
|                 ShiftPage(RightDir, Pst, OnePos, MxKey, KeyLen, ActPage);
 | |
|                 PutAKey(RecOp[W].KeyAndInd.KKey, RecOp[W].KeyAndInd.Ind, Pst, KeyLen, ActPage);
 | |
|               }
 | |
|               *OvUnFlow = TRUE;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|               *OvUnFlow = FALSE;
 | |
|               if (strcmp(IntKey, RecOp[W].KeyAndInd.KKey) < 0)
 | |
|               {
 | |
|                 ActPage->PA.PageHeader.NKey++;
 | |
|                 PutAKey(RecOp[W].KeyAndInd.KKey, RecOp[W].KeyAndInd.Ind, ActPage->PA.PageHeader.NKey, KeyLen, ActPage);
 | |
|                 RecOp[W].FlagOp = TRUE;
 | |
|                 RecOp[W].Which = Change;
 | |
|                 RecOp[W].KeyAndInd.Ind = Pg;
 | |
|               }
 | |
|               else
 | |
|               {
 | |
|                 ShiftPage(RightDir, Pst, OnePos, MxKey, KeyLen, ActPage);
 | |
|                 PutAKey(RecOp[W].KeyAndInd.KKey, RecOp[W].KeyAndInd.Ind, Pst, KeyLen, ActPage);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           else
 | |
|             if (RecOp[W].Which == Change)
 | |
|             {
 | |
|               Pst = 0;
 | |
|               GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
 | |
|               while ((IntIndex != RecOp[W].KeyAndInd.Ind) && (Pst < ActPage->PA.PageHeader.NKey))
 | |
|                 GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
 | |
|               if (IntIndex == RecOp[W].KeyAndInd.Ind)
 | |
|                 PutAKey(RecOp[W].KeyAndInd.KKey, IntIndex, Pst, KeyLen, ActPage);
 | |
|               *OvUnFlow = FALSE;
 | |
|               if ((IntIndex == RecOp[W].KeyAndInd.Ind) && (Pst == ActPage->PA.PageHeader.NKey))
 | |
|               {
 | |
|                 RecOp[W].FlagOp = TRUE;
 | |
|                 RecOp[W].Which = Change;
 | |
|                 RecOp[W].KeyAndInd.Ind = Pg;
 | |
|               }
 | |
|             }
 | |
|             else
 | |
|               if (RecOp[W].Which == Delet)
 | |
|               {
 | |
|                 Pst = 0;
 | |
|                 GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
 | |
|                 while ((IntIndex != RecOp[W].KeyAndInd.Ind) && (Pst < ActPage->PA.PageHeader.NKey))
 | |
|                   GetAKey(*ActPage, KeyLen, ++Pst, IntKey, &IntIndex);
 | |
|                 if (IntIndex == RecOp[W].KeyAndInd.Ind)
 | |
|                 {
 | |
|                   *OvUnFlow = (ActPage->PA.PageHeader.NKey == MnKey);
 | |
|                   ShiftPage(LeftDir, ++Pst, OnePos, MxKey, KeyLen, ActPage);
 | |
|                 }
 | |
|               }
 | |
|           if ((!OvUnFlow) && (Pst >= ActPage->PA.PageHeader.NKey))
 | |
|           {
 | |
|             RecOp[W].FlagOp = TRUE;
 | |
|             RecOp[W].Which = Change;
 | |
|             GetAKey(*ActPage, KeyLen, ActPage->PA.PageHeader.NKey, IntKey, &IntIndex);
 | |
|             strcpy(RecOp[W].KeyAndInd.KKey, IntKey);
 | |
|             RecOp[W].KeyAndInd.Ind = Pg;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
| /*
 | |
| @($)  ZrecOp  B+TREE
 | |
| 
 | |
| @(ID)
 | |
| Azzera la struttura delle operazioni da effettuare.
 | |
| @(FD)
 | |
| 
 | |
| @(ISV)
 | |
| i = contatore.
 | |
| @(FSV)
 | |
| */
 | |
| 
 | |
|   void                            ZRecOp(R)
 | |
|   KOp                                     R; /* struttura operazioni da azzerare */
 | |
| 
 | |
|     {
 | |
|       int                                     i;
 | |
| 
 | |
|       for (i = 0; i <= 1; i++)
 | |
|       {
 | |
|         R[i].FlagOp = FALSE;
 | |
|         R[i].Which = Nothing;
 | |
|         R[i].Posit = NoLink;
 | |
|         R[i].where = -1;
 | |
|         MinKey(MaxArray, R[i].KeyAndInd.KKey);
 | |
|         R[i].KeyAndInd.Ind = NoLink;
 | |
|       }
 | |
|     }
 | |
| 
 |