/* Possibile soluzione al compito del 22 febbraio 1999 per coloro che dovevano sostenere 
 * l'esame di FONDAMENTI DI INFORMATICA 2 
 * 
 * ATTENZIONE: dato che questo programma e' stato sviluppato a fini didattici
 * risulta eccessivamente pieno di commenti. NON prendetelo ad esempio dal
 * punto di vista dei commenti!!! */

/* L'esercizio proposto era la lettura di un file del tipo:
 *           turbo C # 0001
 *           delphi # 231A
 *           nedit # 0001
 *           emacs # 0001
 *           kataweb script di connessione # 0001
 *           netscape # 231A
 *           turbo C++ (3.0) # 231A
 *           mozilla (beta) # 0013
 * il programma doveva leggerlo e produrre in uscita un altro file del tipo:
 *        0001: turbo C , nedit , emacs , kataweb script di connessione 
 *        231A: delphi , netscape , turbo C++ (3.0) 
 *        0013: mozilla (beta) 
 *        */

#include<stdio.h>
#include<stdlib.h> /* molti di voi si dimenticano di includere stdlib
                    * che pero' e' necessaria per le funzioni di 
                    * allocazione dinamica della memoria !! */
#include<string.h>

#define LEN_COD 4
#define BUFFER_LEN 1024

/* dichiarazione struttura dati base, e' richiesta una 
 * multilista: utilizzo due tipi di nodi differenti */

struct software {
	char *titolo;
	struct software *next;
};

struct cd {
	char codice[LEN_COD+1];
	struct software *link; 
	struct cd *next;
} *cd_list;

/* prototipi delle funzioni */
void libera_cd(struct cd *);
void libera_sw(struct software *p);
void *Malloc(size_t); 
FILE *Fopen(const char *, const char *);

int main(int argc, char **argv){
   FILE *file_handler; /* contiene i dati in ingresso */
   char *buffer; /* buffer per leggere dal file */
   int riga=0;   /* tiene traccia della riga che
		  * sto leggendo */
   int ii;       /* semplice contatore */
   char codice_tmp[LEN_COD+1];
   char *titolo_tmp; /* variabili temporanee */

   struct cd *pcd; /* mi servono per scorrere la lista di cd */
   struct software *psw;
	

   /* fase di inizializzazione variabili */
   cd_list=NULL;

   /* apro primo file */
   file_handler=Fopen("package.dat","r");
   /* alloco un buffer per leggere riga per riga
    * si noti che non sono state fatte ipotesi sulla lunghezza massima
    * dei titoli del software. Le faccio ora */
   buffer=Malloc(BUFFER_LEN);

   /* ciclo di lettura dei file e loro
    * inserzione in struttura dati */
   while(!feof(file_handler)){
    ++riga;
    fgets(buffer, BUFFER_LEN, file_handler);
    /* controllo che ci siano i dati */
    if(strlen(buffer)<=LEN_COD){
     break;
    }
    /* conto i caratteri necessari per il 
     * titolo del software */
    ii=0;
    while(buffer[ii]!='#') ++ii;
    /* alloco lo spazio necessario */
    titolo_tmp=Malloc(ii+1);
    /* copio i dati e termino la stringa*/
    memcpy(titolo_tmp,buffer,ii);
    titolo_tmp[ii]='\0';
    /* cerco il primo carattere del codice */
    ++ii;
    while(buffer[ii]==' ')++ii;
    /* copio e termino */
    memcpy(codice_tmp,&buffer[ii],LEN_COD);
    codice_tmp[LEN_COD]='\0';
    /* lo inserisco in lista. Non e' previsto alcun
     * tipo di ordinamento */
    /* devo controllare che la lista esista,
     * nel caso creo e inserisco */
    if(cd_list==NULL){
       cd_list=Malloc(sizeof(struct cd));
       memcpy(cd_list->codice,codice_tmp,LEN_COD);
       cd_list->next=NULL;
       cd_list->link=Malloc(sizeof(struct software));
       cd_list->link->titolo=titolo_tmp;
    }
    else{
       pcd=cd_list;
       /* scorro la lista di CD fino a che non trovo lo stesso codice
	* E fino a che ho elementi */
       while((strcmp(codice_tmp,pcd->codice))&&(pcd->next))
	 pcd=pcd->next;

       if(!strcmp(codice_tmp,pcd->codice)){
	/* devo scorrere la lista fino al penultimo elemento */
	psw=pcd->link;
	while(psw->next)psw=psw->next;
	psw->next=Malloc(sizeof(struct software));
	psw=psw->next;
	psw->next=NULL;
	psw->titolo=titolo_tmp;
       }
       else{
	/* alloco un nuovo cd */
	pcd->next=Malloc(sizeof(struct cd));
	pcd=pcd->next;
	memcpy(pcd->codice,codice_tmp,LEN_COD);
	pcd->next=NULL;
	pcd->link=Malloc(sizeof(struct software));
	pcd->link->titolo=titolo_tmp;
       }
    }
   }
   /* libero le variabili temporanee
    * e chiudo il file */
   free(buffer);
   fclose(file_handler);

   /* apro il file in scrittura */
   file_handler=Fopen("cd.dat","w");
   /* stampo i dati come richisto */
   pcd=cd_list;
   while(pcd){
    fprintf(file_handler,"%s:",pcd->codice);
    psw=pcd->link;
    while(psw){
     fprintf(file_handler," %s",psw->titolo);
     psw=psw->next;
     if(psw)
      fprintf(file_handler,",");
    }
    fprintf(file_handler,"\n");
    pcd=pcd->next;
   }
   fclose(file_handler);

   /* libero la memoria sfruttando la ricorsione */
   libera_cd(cd_list);
   return 0;
}

void libera_cd(struct cd *p){
  if(!p)
    return;
  libera_sw(p->link);
  libera_cd(p->next);
  free(p);
}

void libera_sw(struct software *p){
  if(!p)
    return;
  libera_sw(p->next);
  free(p);
}

/*************************************************************************/
/* da qui in poi sono semplici funzioni di utilita' gia' viste a lezione */
void *Malloc(size_t size)
{
 void *genericp;
 if((genericp=malloc(size))==NULL)
  {
   perror("Malloc");
   exit(1);
  }
  return genericp;
}

/*************************************************************************/

FILE *Fopen(const char *nome, const char *modo)
{
FILE *tmp;

 if((tmp=fopen(nome, modo))==NULL)
  {
   fprintf(stderr, "Non riesco ad aprire il file %s in maniera %s\n",nome, modo);
   perror("Fopen");
   exit(1);
  }
return tmp;
}