/*****************************************
*  INTERPRETEUR D'ALGEBRE RELATIONNELLE  *
*    Olivier Christiaen - 11 Sep 2004	 *
*             UMH-LIG1			 *
*   Evolutions: www.christiaen.org/sqf	 *
******************************************/
%{
#include <stdio.h>
#include <string.h>
#include "sqf.h"

%}
/* Les terminaux sont de types pointeur sur chaine de caracteres
   Les non-terminaux sont representes par une structure (voir sqf.h)*/
%union {
	char * val_char;
	struct arg_operation * arg_ops;
};
/* association d'un type a chaque terminal ou resultat d'une production */
%token <val_char> Mot Liste_mots Comparaison
%type <arg_ops> relational_expression relational_operation r_select r_project r_join r_rename r_union r_difference
%type <val_char> tuple
/* determination des tokens attendus depuis l'analyseur lexical (Flex) */
%token SQF_RELATION SQF_DATA SQF_LET SQF_PRINT
%token OP_WHERE OP_PROJECT OP_JOIN OP_UNION OP_MINUS OP_RENAME OP_AS
/* determination de l'associativite de gauche a droite */
%left SQF_RELATION SQF_DATA SQF_LET SQF_PRINT
%left OP_WHERE OP_PROJECT OP_JOIN OP_UNION OP_MINUS OP_RENAME OP_AS
%%
sequence_sqf		: commande_sqf
			| sequence_sqf commande_sqf
;
commande_sqf		: sqf_relation
			| sqf_data
			| sqf_let
			| sqf_print
;
sqf_relation		: SQF_RELATION Mot ':' tuple	{creer_relation($2,$4);}
;
sqf_data		: SQF_DATA Mot ':' tuple	{ajouter_tuple($2,$4);}
;
sqf_let 		: SQF_LET Mot ':' relational_operation	{executer_operation($2,$4);free($4);}
;
sqf_print		: SQF_PRINT Mot ':' {afficher_relation($2);}
;
relational_expression	: Mot	{$$ = garnir_struct(0,$1,"","","");}
			| relational_operation	{executer_operation($1->nom_resultante,$1);}
			| '('relational_expression')' {$$=$2;strcpy($$->nom_resultante,$2->nom_resultante);
			/* debug :fprintf(stderr,"\n>> %s / %s / %s / %d",$2->nom_resultante,$2->arg1,$2->arg2,$2->no_op); */}
;
relational_operation	: r_select
			| r_project
			| r_join
			| r_rename
			| r_union
			| r_difference
;
r_select		: relational_expression OP_WHERE Mot Comparaison Mot {$$ = garnir_struct(7,$1->nom_resultante,$3,$4,$5);}
				| relational_expression OP_WHERE Mot Comparaison '"'Mot'"' {$$ = garnir_struct(1,$1->nom_resultante,$3,$4,$6);}
;
r_project		: relational_expression OP_PROJECT tuple	{$$ = garnir_struct(2,$1->nom_resultante,$3,"","");}
;
r_join			: relational_expression OP_JOIN relational_expression	{$$ = garnir_struct(3,$1->nom_resultante,$3->nom_resultante,"","");}
;
r_rename		: relational_expression OP_RENAME Mot OP_AS Mot {$$ = garnir_struct(4,$1->nom_resultante,$3,$5,"");}
;
r_union 		: relational_expression OP_UNION relational_expression	{$$ = garnir_struct(5,$1->nom_resultante,$3->nom_resultante,"","");}
;

r_difference		: relational_expression OP_MINUS relational_expression	{$$ = garnir_struct(6,$1->nom_resultante,$3->nom_resultante,"","");}
;
tuple			: Mot	{$$=$1;}
			| Liste_mots	{$$=$1;}
;
%%


/*
----------------------------------------------------------------------------
garnir la structure d'informations communes (pour Bison)
----------------------------------------------------------------------------
cette structure permet de transferer des valeurs d'une production a une autre
*/
struct arg_operation * garnir_struct(int no_op, char * arg1, char * arg2, char * arg3, char * arg4){
struct arg_operation * struct_courante;
char * ctr_rel_temp;

struct_courante = (struct arg_operation *) malloc(sizeof(struct arg_operation));
if (struct_courante == NULL) {erreur(400);}

/* attribuer un nom different a chaque relation temporaire (debute tjs par #) : ameliorable */
ctr_rel_temp=(char *) malloc(sizeof(char)*TAILLE_MAX_COL);
ctr_rel_temp[0]='#';
ctr_rel_temp[1]='@'+ dico->nbr_relation;
ctr_rel_temp[2]='\0';

strcpy(struct_courante->nom_resultante,ctr_rel_temp);

struct_courante->no_op=no_op;
if (no_op == 0) strcpy(struct_courante->nom_resultante,arg1);
strcpy(struct_courante->arg1,arg1);
strcpy(struct_courante->arg2,arg2);
strcpy(struct_courante->arg3,arg3);
strcpy(struct_courante->arg4,arg4);
/* debug:
fprintf(stderr,"\n%d %s %s %s %s [%s]",no_op,arg1,arg2,arg3,arg4,struct_courante->nom_resultante); */
return struct_courante;
}

/*
----------------------------------------------------------------------------
execute une operation SPJRUD (pour Bison) : @let ...
----------------------------------------------------------------------------
*/
void executer_operation(char * relation_resultante, struct arg_operation * operandes){
int code;
code = operandes->no_op;
switch (code)
	   {
	case 1 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s WHERE %s %s %s",relation_resultante,operandes->arg1,operandes->arg2, operandes->arg3, operandes->arg4);*/
	selection(operandes->arg1, relation_resultante, operandes->arg2, operandes->arg3[0], operandes->arg4);
				break;
	case 2 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s PROJECT %s",relation_resultante, operandes->arg1,operandes->arg2);*/
	projection(operandes->arg1, relation_resultante, operandes->arg2);
				break;
	case 3 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s JOIN %s",relation_resultante, operandes->arg1,operandes->arg2);*/
	jointure(operandes->arg1, operandes->arg2, relation_resultante);
				break;
	case 4 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s RENAME %s AS %s [%s]",relation_resultante, operandes->arg1,operandes->arg2,operandes->arg3,operandes->nom_resultante);*/
	renommer( operandes->arg1, relation_resultante , operandes->arg2, operandes->arg3);
				break;
	case 5 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s UNION %s [%s]",relation_resultante, operandes->arg1,operandes->arg2,operandes->nom_resultante);*/
	union_rel(operandes->arg1, operandes->arg2, relation_resultante);
		break;
	case 6 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s MINUS %s",relation_resultante, operandes->arg1, operandes->arg2);*/
	difference(operandes->arg1, operandes->arg2, relation_resultante);
		break;
	case 7 :
	/* debug:
	fprintf(stderr,"\n#let %s:%s MINUS %s",relation_resultante, operandes->arg1, operandes->arg2);*/
	selection_attribut(operandes->arg1, relation_resultante, operandes->arg2, operandes->arg3[0], operandes->arg4);
		break;
	   }

}

/*
----------------------------------------------------------------------------
detection des erreurs de syntaxe dans le fichier d'entree
----------------------------------------------------------------------------
*/

int yyerror(char *s){
fprintf(stderr,"\nERREUR ligne %d : erreur de syntaxe (%s)\n",num_ligne,s);
}

/*
----------------------------------------------------------------------------
cree une nouvelle relation
----------------------------------------------------------------------------
*/
relation* creer_relation(char *nom_relation, char * champs_rel){
int ctr,nbr;
relation * relation_courante;
/* le nom de la relation ou la liste des champs ne doit pas depasser la taille allouee */
if (strlen(nom_relation) > TAILLE_MAX_COL ) {erreur(209);}
if (strlen(champs_rel) > TAILLE_MAX_CHAMPS ) {erreur(209);}
/* verifier si la relation n'existe pas deja dans le dico */
if ( ! relation_existe(nom_relation) )
   {
   nbr = compter_champs(champs_rel);
   /* le nombre de col doit etre inferieur au nbre de colonnes par defaut */
   if (nbr > NBR_MAX_COL ) {erreur(202);}
   /* verifie que la relation ne comporte pas deux attributs de meme nom */
   if ( comparer_noms_champs(champs_rel) && flag_prod_cart == 0) {erreur(208);} /* arret : 2 attributs de meme nom*/
   /* la relation n'existe pas encore : creation */
   relation_courante = (relation *) malloc(sizeof(relation));
   if (relation_courante == NULL) {erreur(400);}
   relation_courante->enregistrement = (tuple *) malloc(sizeof(tuple)*NBR_LIGNES_INIT);
   if (relation_courante->enregistrement == NULL) {erreur(400);}
   /* sauvegarde du nom de la relation et initialisations */
   strcpy(relation_courante->nom,nom_relation);
   relation_courante->nbr_tuples=0;
   relation_courante->nbr_tuples_max=NBR_LIGNES_INIT;
   /* ajouter la relation dans le dico */
   ajouter_ds_dico(relation_courante);
   /* creer les intitules de colonnes a l'indice zero */
   relation_courante->nbr_colonnes = nbr;
   ajouter_tuple(relation_courante->nom, champs_rel);
   /* par def : les en-tete de colonne sont inactives */
   relation_courante->enregistrement[0].actif = 0;
   relation_courante->nbr_tuples_actifs=0;
   }
else {erreur(200);} /* la relation existe deja dans le dico */
return relation_courante;
}
/*
----------------------------------------------------------------------------
compte le nombre de champs dans un tuple
----------------------------------------------------------------------------
la syntaxe de la chaine 'champs_rel' a ete verifiee prealablement
par l'analyseur syntaxique (Flex)
*/
int compter_champs(char champs_rel[]){
int ctr=0, nbr=0;
if ( strlen(champs_rel) > 0 ) {nbr = 1;}
   else erreur(205); /* nombre de champs ou de valeurs nul */
while (champs_rel[ctr] != '\0')
	  {
	  if (champs_rel[ctr] == ',') nbr++;
	  ctr++;
	  }
if (nbr > 0) {return nbr;}
   else return 0;
}
/*
----------------------------------------------------------------------------
ajouter un tuple dans une relation
----------------------------------------------------------------------------
*/
int ajouter_tuple(char * nom_relation, char* champs){
int ctr=0,nbr_tuples,nbr_colonnes_rel,nbr_colonnes_tuple,no_tuple=0,longueur=0;
relation * relation_courante;
char* adr;
adr = (char *) malloc(sizeof(char)*TAILLE_MAX_COL);
if (adr == NULL) {erreur(400);}
/* la liste des champs ne doit pas depasser la taille allouee */
if (strlen(champs) > TAILLE_MAX_CHAMPS ) {erreur(209);}
/* vérification de l'existence de la relation (dans le dictionnaire) */
relation_courante = relation_existe(nom_relation);
if ( relation_courante ) { /* si la relation n'existait pas encore */
   nbr_colonnes_rel = relation_courante->nbr_colonnes;
   nbr_colonnes_tuple = compter_champs(champs);
   /*verifie si nbre de donnees du tuple correspond au nbre de champs de la relation*/
   if (nbr_colonnes_rel == nbr_colonnes_tuple){
	  relation_courante->nbr_tuples++;
	  /* Reallocation si dépassement du nbre max de tuples pour la relation */
	  if (relation_courante->nbr_tuples == (relation_courante->nbr_tuples_max)-1){
	  relation_courante->nbr_tuples_max=relation_courante->nbr_tuples_max+NBR_LIGNES_INIT;
	  relation_courante->enregistrement = (tuple *) realloc(relation_courante->enregistrement,sizeof(tuple)*relation_courante->nbr_tuples_max);
	  if (relation_courante->enregistrement == NULL) {erreur(400);}
	  }
	  relation_courante->nbr_tuples_actifs++;
	  no_tuple = relation_courante->nbr_tuples -1 ; /* numero du tuple courant */
	  relation_courante->enregistrement[no_tuple].actif = 1;
	  /* stockage de la valeur de chaque champs dans une cellule de la table */
	  adr = strtok(champs,",");
	  while ( adr ) {
			strcpy(relation_courante->enregistrement[no_tuple].element[ctr],adr);
			longueur = longueur + strlen(adr);
			/*printf("\n%s [%d][%d] : %s : ",relation_courante->nom,no_tuple,ctr,relation_courante->enregistrement[no_tuple].element[ctr]);*/
			adr = strtok(NULL,",");
			ctr++;
			}
	  /* la longueur du tuple est un champ de ctl pour les doublons, on ne
	  compare deux tuples pour savoir s ils sont identiques que s ils ont la meme longueur */
	  relation_courante->enregistrement[no_tuple].longueur=longueur;
	  /*printf("\nlongueur %d",relation_courante->enregistrement[no_tuple].longueur);*/
	  /* verifie si le tuple insere ne l'a pas ete en double */
	  verifier_doublon(relation_courante);
	  }
	  else erreur(201); /* le nombre de valeurs a inserer ne correspond pas au nbr de col de la relation*/
   }
   else erreur(200); /* la relation existe deja */
free(adr);
return 1;
}
/*
----------------------------------------------------------------------------
compare si des intitulés de champs d'une relation sont différents
----------------------------------------------------------------------------
*/
int comparer_noms_champs(char * champs){
int nbr,ctr=0,courant=0;
champ * tuple_temp;
char * copie_champs;
char* valeur_attr;
valeur_attr = (char *) malloc(sizeof(char)*TAILLE_MAX_COL);
copie_champs =(char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (valeur_attr == NULL) {erreur(400);}
if (copie_champs == NULL) {erreur(400);}
/* recopie la liste des attributs car strtok l'altere*/
strcpy(copie_champs,champs);
nbr = compter_champs(champs); /* determine le nbre d'attributs */
/* tableau temporaire pour stocker les valeurs avant comparaison */
tuple_temp = (champ *) malloc (sizeof(champ)*nbr);
if (tuple_temp == NULL) {erreur(400);}
/* place chaque attribut dans une cellule du tableau tuple_temp */
valeur_attr = strtok(copie_champs,",");
while ( valeur_attr ) {
	  strcpy(tuple_temp[ctr],valeur_attr);
	  valeur_attr = strtok(NULL,",");
	  ctr++;
	  }
/* compare chaque une cellule au cellule restant dans le tableau temporaire */
while ( courant < nbr-1 ) {
	  for ( ctr = courant+1 ; ctr < nbr ; ctr++){
		  /* si deux attributs identiques retourne 1 */
		  if (strcmp(tuple_temp[courant],tuple_temp[ctr]) == 0 ) {return 1;}
		  }
	  courant++;
	  }
free(tuple_temp);
free(copie_champs);
return 0; /* si les attributs sont tous differents */
}
/*
----------------------------------------------------------------------------
verifie si le dernier tuple insere est en double si oui => rendu inactif
----------------------------------------------------------------------------
*/
int verifier_doublon(relation * relation_courante){
int tuple_courant,ctr;
/* verifie si contient au moins deux enregistrements actifs */
if ( relation_courante->nbr_tuples_actifs > 1 ) {
   /* compare le dernier tuple de la table avec tous les tuples actifs */
	tuple_courant = relation_courante->nbr_tuples-1;
	/*printf("\nactifs : %d / tuple courant : %d",relation_courante->nbr_tuples_actifs,tuple_courant);*/
	for (ctr = 1; ctr < tuple_courant; ctr++){
	   /* comparaison de la taille du tuple avec chaque tuple actif */
		if ( relation_courante->enregistrement[ctr].actif
			 && (relation_courante->enregistrement[ctr].longueur == relation_courante->enregistrement[tuple_courant].longueur))
			 {
			 /* si taille tuple identique alors comparaison champ à champ */
			 if (comparer_champ_champ(relation_courante,ctr,tuple_courant)) {
				/* si apres comparaison les champs sont identiques le dernier tuple insere est marque inactif */
				relation_courante->enregistrement[tuple_courant].actif = 0;
				relation_courante->nbr_tuples_actifs--;
				/*printf("\ndoublon entre tuple %d et tuple %d / nbr tuples actifs dans %s = %d",ctr,tuple_courant,relation_courante->nom,relation_courante->nbr_tuples_actifs);*/
				}
			 }
		}
   return 1;
   } else return 0;
}
/*
----------------------------------------------------------------------------
comparaison de deux tuples d'une meme relation champs a champs : detection doublon
----------------------------------------------------------------------------
*/
int comparer_champ_champ(relation * relation_courante, int no_tuple, int tuple_courant){
int ctr = 0 , resultat = 0;
/* l'appel de cette fonction n'a lieu qu'apres avoir verifie que les tuples
d'indices ctr et tuple_courant ont la meme longueur */
int identiques = 1; /* affirmation de depart */
while (identiques && (ctr < relation_courante->nbr_colonnes) ) {
	  resultat = strcmp (relation_courante->enregistrement[no_tuple].element[ctr],relation_courante->enregistrement[tuple_courant].element[ctr]);
	  if ( resultat != 0 ) {identiques = 0 ;}
	  ctr++;
	  }
/* si a la sortie du test identique est tjs VRAI alors les tuples sont identiques */
if (identiques) return 1;
else return 0;
}
/*
----------------------------------------------------------------------------
recherche l'existence d'une relation dans le dictionnaire des relations
----------------------------------------------------------------------------
*/
relation * relation_existe(char * nom_relation){
int 	 ctr = 0;
booleen  existe = 0;
if (dico->nbr_relation == 0) return 0;	/* le dico est vide*/
/* tant que n'existe pas et que la fin du dico n'est pas atteinte*/
while ( (existe == 0) && (ctr < (dico->nbr_relation)) ){
	  /* comparer chaque nom present dans le dico au nom de la relation*/
	  if( strcmp(dico->relation_dico[ctr].nom_relation,nom_relation) == 0)
		  existe = 1; /* si trouve : existe et sortie du while */
	  ctr++;	 /* pas trouve : continuer avec valeur suivante */
	  }
if ( existe == 1) {
   /* si existe retour de l'adresse de la relation trouvee */
   return dico->relation_dico[ctr-1].adresse_relation;}
   /* si pas trouvee retour de NULL */
   else return 0;
}
/*
----------------------------------------------------------------------------
initialisation du dictionnaire des relations
----------------------------------------------------------------------------
*/
void initialiser_dico(){
dico = (dictionnaire *) malloc(sizeof(dictionnaire));
if (dico == NULL) {erreur(400);}
dico->nbr_relation = 0;
}
/*
----------------------------------------------------------------------------
ajout d'une relation dans le dico (apres verif de son absence)
----------------------------------------------------------------------------
*/
void ajouter_ds_dico(relation * relation_courante){
(dico->nbr_relation)++; /* augmenter le nbre d'elements du dico */
/* allouer la memoire necessaire dans le dico */
dico->relation_dico = (entree_dictionnaire *) realloc (dico->relation_dico,sizeof(entree_dictionnaire)*(dico->nbr_relation));
if (dico->relation_dico == NULL) {erreur(400);}
/* placer le nom de la relation et son adresse */
strcpy(dico->relation_dico[(dico->nbr_relation)-1].nom_relation,relation_courante->nom);
dico->relation_dico[(dico->nbr_relation)-1].adresse_relation = relation_courante;
}
/*
----------------------------------------------------------------------------
affiche le contenu du dictionnaire (fct usage interne)
----------------------------------------------------------------------------
*/
void afficher_dico(){
int ctr=0;
relation * relation_courante;
printf("\nDictionnaire : %d relation(s)",dico->nbr_relation);
printf("\n	 NOM			  -  ADRESSE - COL - TUPL - T_ACT");
while (ctr < (dico->nbr_relation)){
	  relation_courante = dico->relation_dico[ctr].adresse_relation;
	  /*printf("\n%20s : %15d",dico->relation_dico[ctr].nom_relation,
	  dico->relation_dico[ctr].adresse_relation);*/
	  printf("\n%20s%10d%6d%6d%6d",relation_courante->nom,dico->relation_dico[ctr].adresse_relation,relation_courante->nbr_colonnes,relation_courante->nbr_tuples,relation_courante->nbr_tuples_actifs);
	  ctr++;
	  }
printf("\n");
}
/*
----------------------------------------------------------------------------
affiche la relation dont le nom a ete passe en parametre
----------------------------------------------------------------------------
*/
void afficher_relation(char * nom_relation){
int ctr, ctr2;
relation * relation_courante;
relation_courante = relation_existe(nom_relation);
/* verifie si la relation existe dans dico */
if ( relation_courante )
   /* si la relation existe */
   {
   fprintf(yyout,"\n\n@relation %s:",relation_courante->nom);
   /* intitules de colonnes */
   for(ctr=0;ctr<relation_courante->nbr_colonnes;ctr++)
	  {
	  fprintf(yyout,"%s",relation_courante->enregistrement[0].element[ctr]);
	  if(ctr<relation_courante->nbr_colonnes-1) fprintf(yyout,",");
	  }
   /* donnees de la relation */
   if (relation_courante->nbr_tuples_actifs > 0)
	  {
	  /* si la relation possede des tuples actifs : les afficher*/
	  for (ctr=0;ctr<relation_courante->nbr_tuples;ctr++)
		  {
		  if ( relation_courante->enregistrement[ctr].actif ) {
		 fprintf(yyout,"\n@data %s:",relation_courante->nom);
			 for (ctr2=0;ctr2<relation_courante->nbr_colonnes;ctr2++)
				 {
				 fprintf(yyout,"%s",relation_courante->enregistrement[ctr].element[ctr2]);
				 if (ctr2 < relation_courante->nbr_colonnes-1) fprintf(yyout,",");
				 }
			 }				 
	  }

	  }
   }
   /* si elle n'existe pas */
   else erreur(203);
}
/*
----------------------------------------------------------------------------
realise la projection
----------------------------------------------------------------------------
*/
void projection(char * nom_relation_init ,char * nom_relation_res , char* champs_rel ){
relation * relation_init;
relation * relation_res;
int * indices_champs_init; /* tableau des indices des champs de la relation initiale a conserver*/
int ctr,ctr2,
	indice, 			   /* indice courant du champ existant dans relation initiale*/
	nbr_indices=0;		   /* nbre d'indices concernes par projection */
char * champ_courant;
char * copie_champs_rel;
champ_courant = (char *) malloc (sizeof(char)*TAILLE_MAX_COL);
copie_champs_rel = (char *) malloc (sizeof(char)*TAILLE_MAX_CHAMPS);
if (champ_courant == NULL) {erreur(400);}
if (copie_champs_rel == NULL) {erreur(400);}

/* verifie l'existence de la relation de base dans le dictionnaire */
relation_init = relation_existe(nom_relation_init);
if ( relation_init == 0 ) {erreur(203);} /* la relation initiale n'existe pas */
/* verifie l'inexistence de la relation resultante dans le dictionnaire */
relation_res = relation_existe(nom_relation_res);
if ( relation_res !=0 ) {erreur(200);} /* le nom de la relation resultante existe deja ds dico*/
/* alloue un tableau pour stocker les indices des champs concernes par la projection */
ctr = compter_champs(champs_rel);
indices_champs_init = (int * ) malloc(sizeof(int) * ctr);
if (indices_champs_init == NULL)  {erreur(400);}
ctr=0; /* reutilisation du compteur */
/* verifie si le(s) nom de champ(s) existent dans la table initiale */
strcpy(copie_champs_rel,champs_rel); /* copie de la liste des champs car alteree par strtok()*/
champ_courant = strtok(champs_rel,",");
while ( champ_courant ) {
	  indice = verifier_champ_relation(relation_init,champ_courant);
	  if (indice == -1) {erreur(204);} /* le champ n'existe pas dans relation initiale */
		 else { /* le champ existe : placer son indice dans le tableau des indices */
			  indices_champs_init[nbr_indices] = indice;
			  nbr_indices++;
		 }
	  champ_courant = strtok(NULL,",");
	  ctr++;
	  }
/* creation la relation resultante */
free(champ_courant); /* uniquement utile dans while ci-dessus */
relation_res = creer_relation(nom_relation_res, copie_champs_rel);
free(copie_champs_rel);
/* recopie (insere) les donnees des champs concernes ds relation resultante */
strcpy(champs_rel,"");
for (ctr = 0; ctr < relation_init->nbr_tuples ; ctr++ ){
	/* uniquement pour les tuples actifs */
	if ( relation_init->enregistrement[ctr].actif ) {
	   for ( ctr2 = 0; ctr2 < nbr_indices ; ctr2++ ) { /* parcours des indices concernés*/
		   /* compose la liste des valeurs des champs a inserer dans table resultante */
		   strcat(champs_rel,relation_init->enregistrement[ctr].element[indices_champs_init[ctr2]]);
		   if ( ctr2 < nbr_indices-1 ) strcat(champs_rel,",");
		   }
	   ajouter_tuple(relation_res->nom, champs_rel);
	   strcpy(champs_rel,"");
	   }
	}
free(indices_champs_init);
}
/*
----------------------------------------------------------------------------
verifie si un champ existe dans le schema d'une relation et retourne son indice
----------------------------------------------------------------------------
cette fonction n'est appelee que pour une relation existante
la verification de sa presence dans le dictionnaire n'est pas requise
*/
int verifier_champ_relation(relation * relation_courante, char * champ){
int ctr=0;
int identiques=0;
while (( !identiques ) && (ctr < relation_courante->nbr_colonnes))
	  {
	  if (strcmp(relation_courante->enregistrement[0].element[ctr],champ) == 0) {identiques = 1;}
		 else ctr++;
	  }
if ( identiques ) {return ctr;}
   else return -1;
}

/*
----------------------------------------------------------------------------
renomme un attribut (champ) d'une relation
----------------------------------------------------------------------------
*/
void renommer(char * nom_relation_init ,char * nom_relation_res ,char * attribut_init , char * attribut_res ){
relation * relation_courante;
relation * relation_res;
char * champs_rel;
int indice,ctr;

/* verifie si la relation existe dans le dictionnaire */
relation_courante = relation_existe(nom_relation_init);
if ( relation_courante == 0 ) {erreur(203);} /* la relation n'existe pas */
/* verifie si le nom à donner en renommant n'existe pas deja dans la relation */
indice = verifier_champ_relation(relation_courante, attribut_res);
if ( indice > 0 ) {erreur(206);} /* le futur nom de champ existe deja */
/* verifie si le champ a renommer existe dans la relation */
indice = verifier_champ_relation(relation_courante, attribut_init);
if (indice == -1) {erreur(204);} /* le champ a renommer n'existe pas */
/* obtenir la liste des attributs de la relation initiale pour creer la rel resultante */
champs_rel = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);} /* pas assez de memoire */
champs_rel = transformer_tuple_liste(nom_relation_init, 0);
relation_res = creer_relation(nom_relation_res,champs_rel);
strcpy(champs_rel,"");
/* inserer chaque tuple actif de la relation initiale dans la rel resultante = copie */
for ( ctr = 1; ctr < relation_courante->nbr_tuples ; ctr++ ) {
	if ( relation_courante->enregistrement[ctr].actif ) {
		champs_rel = transformer_tuple_liste(nom_relation_init, ctr);
			/* insere le tuple courant dans la nouvelle relation */
			ajouter_tuple(nom_relation_res, champs_rel);
			strcpy(champs_rel,"");
		}
	}
/* change le nom de l'attribut dans la relation resultante */
strcpy(relation_res->enregistrement[0].element[indice],attribut_res);
}
/*
----------------------------------------------------------------------------
verifie le schema de deux relations
----------------------------------------------------------------------------
retourne 1 si les schémas sont identiques
sinon 0
*/
int verifier_schema(char * nom_relation1, char * nom_relation2){
relation * relation1;
relation * relation2;
int indice1,indice2,ctr;
booleen schema_identique;
/* verifie si les relations existent dans le dictionnaire */
relation1 = relation_existe(nom_relation1);
relation2 = relation_existe(nom_relation2);
if ( !relation1 || !relation2 ) {erreur(203);} /* la(es) relation(s) n'existe(nt) pas */
/* verifie si le nbre de champs est identique dans les deux relations */
if ( compter_champs(nom_relation1) != compter_champs(nom_relation2))
   {erreur(201);} /* schema different*/
/* comparaison de l'attribut de relation1[ctr] et relation2[ctr] : champ a champ */
for (ctr = 0; ctr < relation1->nbr_colonnes ; ctr++) {
	indice1 = verifier_champ_relation(relation1, relation1->enregistrement[0].element[ctr]);
	indice2 = verifier_champ_relation(relation2, relation1->enregistrement[0].element[ctr]);
	/*printf("\n%d:%s / %d:%s",indice1,relation1->enregistrement[0].element[ctr],indice2,relation2->enregistrement[0].element[ctr]);*/
	/*si un des champs n'existe pas (ou les deux) ou s'ils ne sont pas identiques : schema different*/
	if (indice1 != indice2 || indice1 < 0 || indice2 < 0 ) {schema_identique = 0;}
	   else schema_identique = 1;
	}
return schema_identique;
}
/*
----------------------------------------------------------------------------
transforme un tuple en une liste de valeurs (ou attributs) separee par ,
----------------------------------------------------------------------------
*/
char * transformer_tuple_liste(char * nom_relation, int no_tuple){
relation * relation_courante;
char * champs_rel;
int ctr;
champs_rel = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
/* verification de l'existence de la table dans le dictionnaire */
relation_courante = relation_existe(nom_relation);
if ( !relation_courante ) {erreur(203);} /* la relation n'existe pas*/
/* verifie si le numero du tuple est compris dans la relation */
if (no_tuple > relation_courante->nbr_tuples) {erreur(207);}
/* verifie si le tuple est actif sinon renvoi NULL
le tuple qui contient les intitules de champ est toujours inactif
*/
if ( !relation_courante->enregistrement[no_tuple].actif && no_tuple ) {return NULL;}
/* extrait chaque champs et l'insere dans la liste separe par une virgule */
strcpy(champs_rel,"");
for (ctr = 0 ; ctr < relation_courante->nbr_colonnes ; ctr ++){
	strcat(champs_rel,relation_courante->enregistrement[no_tuple].element[ctr]);
	if ( ctr < relation_courante->nbr_colonnes-1 ) strcat(champs_rel,",");
	}
return champs_rel;
}
/*
----------------------------------------------------------------------------
realise l'union de deux relations
----------------------------------------------------------------------------
*/
void union_rel(char * nom_relation1, char * nom_relation2 ,char * nom_relation_res){
relation * relation_res,
		 * relation1,
		 * relation2;
char * champs_rel;
int ctr;
champs_rel = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
/* verifie l'inexistence de la relation resultante dans le dictionnaire */
relation_res = relation_existe(nom_relation_res);
if ( relation_res !=0 ) {erreur(200);} /* le nom de la relation resultante existe deja ds dico*/
/* verifie si le schema de relation1 est identique au schema de relation2*/
if ( verifier_schema(nom_relation1, nom_relation2)){
   relation1 = relation_existe(nom_relation1);
   relation2 = relation_existe(nom_relation2);
   /* cree la relation resultante de meme schema */
   champs_rel = transformer_tuple_liste(nom_relation1, 0);
   relation_res = creer_relation(nom_relation_res, champs_rel);
   strcpy(champs_rel,"");
   /* insere tous les elements de relation1 dans la relation resultante
	  le fonction ajouter_tuple(...) elimine les doublons */
   for ( ctr = 1 ; ctr < relation1->nbr_tuples ; ctr++) { /* debute a 1 : pas les noms d'attributs */
	   /* pour les tuples actifs uniquement */
	   if ( relation1->enregistrement[ctr].actif ) {
		  /* obtient la liste des valeurs de la relation separees par des virgules */
		  champs_rel = transformer_tuple_liste(nom_relation1, ctr);
		  /* insere le tuple courant dans la nouvelle relation */
		  ajouter_tuple(nom_relation_res, champs_rel);
		  strcpy(champs_rel,"");
		  }
	   }
   /* insere tous les elements de relation2 dans la relation resultante
	  le fonction ajouter_tuple(...) elimine les doublons */
   for ( ctr = 1 ; ctr < relation2->nbr_tuples ; ctr++) { /* debute a 1 : pas les noms d'attributs */
	   /* pour les tuples actifs uniquement */
	   if ( relation2->enregistrement[ctr].actif ) {
		  /* obtient la liste des valeurs de la relation separees par des virgules */
		  champs_rel = transformer_tuple_liste(nom_relation2, ctr);
		  /* insere le tuple courant dans la nouvelle relation */
		  ajouter_tuple(nom_relation_res, champs_rel);
		  strcpy(champs_rel,"");
		  }
	   }
   }
free(champs_rel);
}
/*
----------------------------------------------------------------------------
verifie l'existence d'un tuple d'une relation1 dans une relation2
----------------------------------------------------------------------------
si existe retourne le numero du tuple dans la seconde relation
sinon retourne 0
*/
int verifier_presence_tuple(char * nom_relation1,char * nom_relation2, int no_tuple){
relation * relation1,
		 * relation2;
int ctr_col=0,ctr_lign=1,indice1,indice2;
int tuples_identiques=0;
int champs_identiques=0;
/* verifie le schema : relations existent, meme nbre et intitules de champs */
if ( verifier_schema(nom_relation1,nom_relation2) ){
   relation1 = relation_existe(nom_relation1);
   /* verifie si le tuple est present dans la relation1*/
   if (no_tuple > relation1->nbr_tuples) {erreur(207);}
   relation2 = relation_existe(nom_relation2);
   /* pour chaque tuple actif de relation2 */
   while (ctr_lign < relation2->nbr_tuples){
		 if (relation2->enregistrement[ctr_lign].actif) {
			/* si chaque champ du tuple de la relation1 = champ du tuple de la relation2*/
			while ((strcmp(relation1->enregistrement[no_tuple].element[ctr_col],relation2->enregistrement[ctr_lign].element[ctr_col]) == 0) && (ctr_col < relation1->nbr_colonnes)){
				  champs_identiques++;
				  ctr_col++;
				  }
			/* si le nbre de champs identiques dans un tuple correspond au nbre
			d'elements du tuple alors les deux tuples sont bien identiques
			et dans ce cas, il faut retourner la position du tuple dans relation2 */
			if ( champs_identiques == relation1->nbr_colonnes ) {return ctr_lign;}
			}
		 ctr_col = 0;
		 ctr_lign++;
	 champs_identiques=0;
		 }
   /* si aucun tuple identique dans relation2 pour le tuple de relation1 */
   return 0;
   }
}
/*
----------------------------------------------------------------------------
realise la difference entre deux relations
----------------------------------------------------------------------------
*/
void difference(char * nom_relation1, char * nom_relation2 ,char * nom_relation_res){
relation * relation_res,
		 * relation1,
		 * relation2;
char * champs_rel;
int ctr;
champs_rel = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
/* verifie l'inexistence de la relation resultante dans le dictionnaire */
relation_res = relation_existe(nom_relation_res);
if ( relation_res !=0 ) {erreur(200);} /* le nom de la relation resultante existe deja ds dico*/
/* verifie si le schema de relation1 est identique au schema de relation2*/
if ( verifier_schema(nom_relation1, nom_relation2)){
   relation1 = relation_existe(nom_relation1);
   relation2 = relation_existe(nom_relation2);
   /* cree la relation resultante de meme schema */
   champs_rel = transformer_tuple_liste(nom_relation1, 0);
   relation_res = creer_relation(nom_relation_res, champs_rel);
   for ( ctr = 1 ; ctr < relation1->nbr_tuples ; ctr++ ) {
	   if ( relation1->enregistrement[ctr].actif ) { /* uniqt pour les tuples actifs */
		  if ( verifier_presence_tuple(nom_relation1, nom_relation2, ctr) == 0) {
			 /* si le tuple n'est pas present dans la seconde relation */
			 champs_rel = transformer_tuple_liste(nom_relation1, ctr);
			 /* l'inserer dans la table resultante */
			 ajouter_tuple(nom_relation_res, champs_rel);
			 strcpy(champs_rel,"");
			 }
		  }
	   }
   }
free(champs_rel);
}
/*
----------------------------------------------------------------------------
realise la selection sur une relation sur base de la valeur de l'attribut
----------------------------------------------------------------------------
*/
void selection(char * nom_relation_init,char * nom_relation_res,char * attribut,char operateur,char * valeur_attr){
relation * relation_init,
		 * relation_res;
int indice, identiques, ctr;
char * champs_rel;
champs_rel = (char *) malloc (sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
/* verifie l'existence de la relation de base dans le dictionnaire */
relation_init = relation_existe(nom_relation_init);
if ( relation_init == 0 ) {erreur(203);} /* la relation initiale n'existe pas */
/* verifie l'inexistence de la relation resultante dans le dictionnaire */
relation_res = relation_existe(nom_relation_res);
if ( relation_res !=0 ) {erreur(200);} /* le nom de la relation resultante existe deja ds dico*/
/* verifie l'existence de l'attribut concerne dans la relation initiale */
indice = verifier_champ_relation(relation_init, attribut);
if ( indice < 0 ) {erreur(204);} /* l'attribut n'existe pas dans la relation */
/* cree la relation resultante */
champs_rel = transformer_tuple_liste(nom_relation_init,0); /* obtient la liste des attributs de relation_init */
relation_res = creer_relation(nom_relation_res, champs_rel);
strcpy(champs_rel,"");
/* pour chaque tuple actif de relation_init */
for (ctr = 1 ; ctr < relation_init->nbr_tuples ; ctr++){
	if ( relation_init->enregistrement[ctr].actif ) {
	   /* si l'operateur de comparaison est = */
	   if ( operateur == '=' ) {
		  identiques = strcmp(relation_init->enregistrement[ctr].element[indice],valeur_attr);
		  if (identiques == 0) { /* trouve valeur identique => retour du no du tuple */
			 /* transforme les valeurs du tuple trouve en liste de valeurs */
			 champs_rel = transformer_tuple_liste(nom_relation_init,ctr);
			 /* ajout du tuple dans la relation resultante */
			 ajouter_tuple(nom_relation_res, champs_rel);
			 strcpy(champs_rel,"");
			 /* poursuite de l'operation jusque au dernier tuple car plusieurs pourraient correspondre*/
			 }
		  }
	   }
	   if ( operateur == '<' ) { erreur(303);};
	   if ( operateur == '>' ) { erreur(303);};
	}
free(champs_rel);
}
/*
----------------------------------------------------------------------------
realise la selection sur une relation sur base du nom d'attribut
----------------------------------------------------------------------------
*/
void selection_attribut(char * nom_relation_init,char * nom_relation_res,char * attribut1,char operateur,char * attribut2){
relation * relation_init,
		 * relation_res;
int indice1, indice2,identiques, ctr;
char * champs_rel;
champs_rel = (char *) malloc (sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
/* verifie l'existence de la relation de base dans le dictionnaire */
relation_init = relation_existe(nom_relation_init);
if ( relation_init == 0 ) {erreur(203);} /* la relation initiale n'existe pas */
/* verifie l'inexistence de la relation resultante dans le dictionnaire */
relation_res = relation_existe(nom_relation_res);
if ( relation_res !=0 ) {erreur(200);} /* le nom de la relation resultante existe deja ds dico*/
/* verifie l'existence de l'attribut concerne dans la relation initiale */
indice1 = verifier_champ_relation(relation_init, attribut1);
indice2 = verifier_champ_relation(relation_init, attribut2);
if ( indice1 < 0 ) {erreur(204);} /* l'attribut n'existe pas dans la relation */
if ( indice2 < 0 ) {erreur(204);} /* l'attribut n'existe pas dans la relation */
/* cree la relation resultante */
champs_rel = transformer_tuple_liste(nom_relation_init,0); /* obtient la liste des attributs de relation_init */
relation_res = creer_relation(nom_relation_res, champs_rel);
strcpy(champs_rel,"");
/* pour chaque tuple actif de relation_init */
for (ctr = 1 ; ctr < relation_init->nbr_tuples ; ctr++){
	if ( relation_init->enregistrement[ctr].actif ) {
	   /* si l'operateur de comparaison est = */
	   if ( operateur == '=' ) {
		  identiques = strcmp(relation_init->enregistrement[ctr].element[indice1],relation_init->enregistrement[ctr].element[indice2]);
		  if (identiques == 0) { /* trouve valeur identique => retour du no du tuple */
			 /* transforme les valeurs du tuple trouve en liste de valeurs */
			 champs_rel = transformer_tuple_liste(nom_relation_init,ctr);
			 /* ajout du tuple dans la relation resultante */
			 ajouter_tuple(nom_relation_res, champs_rel);
			 strcpy(champs_rel,"");
			 /* poursuite de l'operation jusque au dernier tuple car plusieurs pourraient correspondre*/
			 }
		  }
	   }
	   if ( operateur == '<' ) { erreur(303);};
	   if ( operateur == '>' ) { erreur(303);};
	}
free(champs_rel);
}
/*
----------------------------------------------------------------------------
realise une jointure entre deux relations
----------------------------------------------------------------------------
*/
void jointure(char * nom_relation1, char * nom_relation2, char * nom_relation_res){
relation * relation_res,
		 * relation1,
		 * relation2,
		 * relation_temp;
int ctr,ctr2=0,ind_relation2,nbr_champs_ident=0,identique=0,courant=0;
int * ind_rel1,
	* ind_rel2;
char * champs_rel,
	 * valeur1,
	 * valeur2;
char c;
char nom_rel_temp[12];
booleen a_copier=1; /* affirmation : par defaut les attributs de relation2 sont tous differents de ceux de relation1 */
/* verifie l'inexistence de la relation resultante dans le dictionnaire */
relation_res = relation_existe(nom_relation_res);
if ( relation_res !=0 ) {erreur(200);} /* le nom de la relation resultante existe deja ds dico*/
/* verifie l'existence des relations de base dans le dictionnaire */
relation1 = relation_existe(nom_relation1);
relation2 = relation_existe(nom_relation2);
if ( relation1 == 0 ) {erreur(203);} /* la relation1 n'existe pas */
if ( relation2 == 0 ) {erreur(203);} /* la relation2 n'existe pas */
/* reservation d'espace pour sauver la liste des attributs de la nouvelle relation */
champs_rel = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
valeur1 = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
valeur2 = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
if (valeur1 == NULL) {erreur(400);}
if (valeur2 == NULL) {erreur(400);}
/* un tableau par relation qui reprend les attributs identiques de cahque relation */
ind_rel1 = (int *) malloc (sizeof(int)*NBR_MAX_COL);
ind_rel2 = (int *) malloc (sizeof(int)*NBR_MAX_COL);
if (ind_rel1 == NULL) {erreur(400);}
if (ind_rel2 == NULL) {erreur(400);}
/* verifie si des attributs sont communs aux deux relations */
for ( ctr = 0 ; ctr < relation1->nbr_colonnes ; ctr++ ) {
	ind_relation2 = verifier_champ_relation(relation2, relation1->enregistrement[0].element[ctr]);
	if ( ind_relation2 >= 0 ) {
	   /* constitution d'un tableau des champs identiques en conservant leurs indices */
	   ind_rel1[nbr_champs_ident]=ctr;
	   ind_rel2[nbr_champs_ident]=ind_relation2;
	   nbr_champs_ident++;
	   }
	}
/* cree une relation temporaire comme etant un produit cartesien */
strcpy(nom_rel_temp,"#"); /* attribution d'un nom pour le dictionnaire */
/* evite d'avoir deux noms de relations identiques si +sieurs produits cartesiens */
strcat(nom_rel_temp,nom_relation_res);
produit_cartesien(nom_relation1,nom_relation2,nom_rel_temp); /* la table est cree par l'effet du prod cart */
relation_temp = relation_existe(nom_rel_temp);
strcpy(valeur1,"");
strcpy(valeur2,"");
if (relation_temp->nbr_tuples_actifs > 0){ /* si la relation temp contient des tuples actifs */
   for ( ctr = 1; ctr < relation_temp->nbr_tuples ; ctr++ ){
	   if ( relation_temp->enregistrement[ctr].actif ) { /* pour chaque tuple actif de la rel temporaire */
		  for ( ctr2 = 0 ; ctr2<nbr_champs_ident ; ctr2++) {
			  /* pour chaque liste de valeurs identiques */
			  strcat(valeur1,relation_temp->enregistrement[ctr].element[ind_rel1[ctr2]]);
			  strcat(valeur2,relation_temp->enregistrement[ctr].element[ind_rel2[ctr2]+relation1->nbr_colonnes]);
			  }
		  /* compare les valeurs concatenee des attributs communs
			 surtout utile si plusieurs attributs sont communs */
		  if ( strcmp(valeur1,valeur2) == 0 ) {relation_temp->enregistrement[ctr].actif = 1;}
			 else { relation_temp->enregistrement[ctr].actif = 0; relation_temp->nbr_tuples_actifs--; }
		  strcpy(valeur1,"");
		  strcpy(valeur2,"");
		  }
	   }
   }
/* determination de la liste des attributs pour la table resultante : consiste a eliminer les attributs identiques */
champs_rel = transformer_tuple_liste(nom_relation1,0); /* contient ts les attributs de la relation1 */
/* y ajouter les attributs de la relation2 qui ne sont pas deja presents dans relation1 */
for ( ctr=0 ; ctr < relation2->nbr_colonnes ; ctr++) {
	for ( ctr2=0 ; ctr2<nbr_champs_ident ; ctr2++) {
		if ( ctr == ind_rel2[ctr2] ) { /* l'attribut existe dans relation1 */
		   a_copier = 0;
		   }
		}
	if ( a_copier ) { /* copier dans la liste des attributs ceux qui n'y sont pas deja presents */
	   strcat(champs_rel,",");
	   strcat(champs_rel,relation2->enregistrement[0].element[ctr]);
	   }
	a_copier = 1;
	}
/* cree la table resultante comme une projection sur la table temporaire
en ne eliminant les attributs identiques */
projection(nom_rel_temp,nom_relation_res,champs_rel );

free(ind_rel1);
free(ind_rel2);
free(champs_rel);
free(valeur1);
free(valeur2);
}
/*
----------------------------------------------------------------------------
produit cartesien entre relation1 et relation2
----------------------------------------------------------------------------
*/
void produit_cartesien(char * nom_relation1,char * nom_relation2,char * nom_relation_res){
relation * relation_res,
		 * relation1,
		 * relation2;
int ctr,ctr2;
char * champs_rel;
champs_rel = (char *) malloc(sizeof(char)*TAILLE_MAX_CHAMPS);
if (champs_rel == NULL) {erreur(400);}
/* concatene la liste des attributs de relation1 avec ceux de relation2*/
champs_rel = transformer_tuple_liste(nom_relation1,0);
strcat(champs_rel,",");
strcat(champs_rel,transformer_tuple_liste(nom_relation2,0));
/* le flag permet de desactiver temporairement le controle de l'existence de
deux attributs de meme nom dans une relation*/
flag_prod_cart=1;
relation_res = creer_relation(nom_relation_res, champs_rel);
flag_prod_cart=0; /* reactivation du controle pour les autres creations de relations */
relation1 = relation_existe(nom_relation1);
relation2 = relation_existe(nom_relation2);
if ( (relation1->nbr_tuples_actifs > 0) && (relation2->nbr_tuples_actifs > 0)) {
/* concatene la liste des valeurs de chaque tuple actifs de relation1 avec ceux de relation2 */
for (ctr = 1 ; ctr < relation1->nbr_tuples ; ctr++ ){
	if (relation1->enregistrement[ctr].actif){
	   for (ctr2 = 1 ; ctr2 < relation2->nbr_tuples ; ctr2++ ){
		   if (relation2->enregistrement[ctr2].actif){
			  champs_rel = transformer_tuple_liste(nom_relation1,ctr);
			  strcat(champs_rel,",");
			  strcat(champs_rel,transformer_tuple_liste(nom_relation2,ctr2));
			  ajouter_tuple(nom_relation_res, champs_rel);
			  strcpy(champs_rel,"");
			  }
		   }
	   }
	}
}
free(champs_rel);
}
/*
----------------------------------------------------------------------------
liberation de la memoire utilisee
----------------------------------------------------------------------------
*/
void liberer_memoire(){
int ctr=0;
relation * relation_courante;
while (ctr < (dico->nbr_relation)){
	  relation_courante = dico->relation_dico[ctr].adresse_relation;
	  free (relation_courante);
	  ctr++;
	  }
free(dico);
/* fermeture des fichiers */
fclose(yyin);
fclose(yyout);
}
/*
----------------------------------------------------------------------------
gestion des erreurs
----------------------------------------------------------------------------
*/
void erreur(int code){

fprintf(stderr,"ERREUR ligne %d : ",num_ligne);
switch (code)
	   {
	   case 200 : fprintf(stderr,"[%d] la relation existe deja\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 201 : fprintf(stderr,"[%d] schema non correspondant\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 202 : fprintf(stderr,"[%d] nbre colonnes depasse valeur par defaut\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 203 : fprintf(stderr,"[%d] la relation n'existe pas\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 204 : fprintf(stderr,"[%d] champ inexistant\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 205 : fprintf(stderr,"[%d] nombre de champs ou de valeurs nul\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 206 : fprintf(stderr,"[%d] un attribut de meme nom existe deja\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 207 : fprintf(stderr,"[%d] le tuple recherche n'existe pas\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 208 : fprintf(stderr,"[%d] deux attributs de la relation portent le meme nom\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 209 : fprintf(stderr,"[%d] depassgement de capacite : nom ou liste trop long\n",code);
				  liberer_memoire();
				  exit (0);
				  break;
	   case 300 : fprintf(stderr,"\n[%d] syntaxe spjrud [filename_data.sqf] filename_input.sqf filename_output.sqf\n",code);
				  exit (0);
				  break;
	   case 301 : fprintf(stderr,"\n[%d] impossible d'ouvrir le fichier d'entree\n",code);
				  exit (0);
				  break;
	   case 302 : fprintf(stderr,"\n[%d] impossible d'ouvrir le fichier de sortie\n",code);
				  exit (0);
				  break;
	   case 303 : fprintf(stderr,"\n[%d] seul le controle de l'egalite est implemente dans cette version\n",code);
				  liberer_memoire();
		  exit (0);
		  break;
	   case 400 : fprintf(stderr,"\n[%d] memoire insuffisante\n",code);
				  liberer_memoire();
		  exit (0);
				  break;
	   default	:
				  liberer_memoire();
				  exit (0);
	   }
}



int main(int nbr_arg, char *argv[]){
char * infile;
char * outfile;
printf("\nSQF - Version Sep 2004 - www.christiaen.org/sqf\n");
/* controle du nombre des arguments */
if (nbr_arg < 3 || nbr_arg > 4) {erreur(300);}

initialiser_dico();
infile = argv[1];
yyin = fopen(infile,"r");
if (yyin == NULL ) {erreur(301);};

if (nbr_arg == 3) {outfile = argv[2];}
if (nbr_arg == 4) {outfile = argv[3];}

yyout = fopen(outfile,"w");
if (yyout == NULL ) {erreur(302);}

yyparse(); /* traitement du premier fichier en entree */


if (nbr_arg == 4) {
	fclose(yyin);
	infile = argv[2];
	yyin = fopen(infile,"r");
	if (yyin == NULL ) {erreur(301);}
	yyparse(); /* traitement du second fichier en entree */
	}

fclose(yyin);
fclose(yyout);

afficher_dico();

}
