/* possibile soluzione all'esame del 13.2.2001 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>

/* costante per lunghezza stringhe */
#define ML 255

/* non e'richiesto ordinamento ma solo che si possano gestire
 * un numero di elementi non predeterminato -> lista non ordinata */
struct nodo{
  unsigned int primo;
  unsigned int secondo;
  struct nodo *prossimo;
};

/* prototipi funzioni */
void *Malloc(size_t); 
FILE *Fopen(const char *, const char *);
struct nodo *leggi_riga(FILE *);
struct nodo *inserisci_in_lista(struct nodo *, struct nodo *);
unsigned int lunghezza_lista(struct nodo *);
void ordina_risultati(long *, int);

/* evito l'utilizzo di variabili globali */

int main(int argc, char **argv){

 /* un puntatore per dati temporanei e uno per
  * la testa della lista */
 struct nodo *tmp;
 struct nodo *testa=NULL; /* lista inizialmente vuota */
 /* file handler per lettura */
 FILE *dati;
 /* stringa per gestire lettura da tastiera */
 char input[ML];
 char comando;
 int nn,ii;
 long *ris;

	
 /* PRIMA PARTE: leggo e interpreto il file */
 dati=Fopen("numeri.txt","r");

 while(1){

  /* leggo una singola riga
   * se non riesco la funzione restituisce NULL
   * e lo interpreto come fine file ed esco */
  tmp=leggi_riga(dati);
  if(!tmp)break;

  /* inserisco i dati nella lista */
  testa=inserisci_in_lista(testa, tmp);
 }

 /* SECONDA PARTE: iterativamente chiedo un tasto
  * ed eseguo l'operazione relativa */

 /* ora so quante coppie di numeri ho letto */
 nn=lunghezza_lista(testa);
 /* alloco opportuno array per i risultati*/
 ris=Malloc(nn*sizeof(long));


 printf("Inserisci un comando: ");
 /* leggo il comando */
 fgets(input,ML,stdin);
 /* considero solo il primo carattere*/
 comando=input[0];
 /* guardo se e'un carattere o una cifra,
  * isalpha e isdigit erano probabilmente soluzioni
  * piu'eleganti */
 switch(comando){
   case 'A': 
     for(ii=0,tmp=testa;tmp;ii++,tmp=tmp->prossimo) 
       ris[ii]=tmp->primo-tmp->secondo; 
     break;
   case 'B': 
     for(ii=0,tmp=testa;tmp;ii++,tmp=tmp->prossimo) {
       ris[ii]=tmp->primo-tmp->secondo;
       ris[ii]=ris[ii]*ris[ii];
     }
     break; 
   default:
     fprintf(stderr, "Errore! comando non riconosciuto!\n");
     exit(EXIT_FAILURE);
 }

 /* ordino i risultati */
 ordina_risultati(ris, nn);

 printf("Risultati:\n");
 for(ii=0;ii<nn;++ii)
   printf("%d\n",ris[ii]);

 return EXIT_SUCCESS; /* codice di uscita senza errori */
}

/* questa funzione restituisce il numero di elementi nella lista */
unsigned int lunghezza_lista(struct nodo *a){
  if(!a)return 0;
  return 1+lunghezza_lista(a->prossimo);
}

/* questa funzione legge una riga del file e ritorna cio' che ha letto
 * se non riesce a leggere ritorna NULL */
struct nodo *leggi_riga(FILE *a){
 struct nodo *letto;
 int nb;

 /* alloco struttura per dati */
 letto=Malloc(sizeof(struct nodo));

 /* provo a leggere dal file i tre elementi che compongono la riga*/
 nb=fscanf(a, "%u %u\n", &letto->primo, &letto->secondo);

 /* se e' riuscito a leggere una riga completa nb deve essere
  * pari ad tre (numero dei componenti) */
 if(nb!=2){
  free(letto);
  return NULL;
 }

 letto->prossimo=NULL;

 return letto;
}


/* questa funzione inserisce  i dati in una lista non
 * ordinata e restituisce la testa */

struct nodo *inserisci_in_lista(struct nodo *head, struct nodo *new){

 /* se la lista non esiste il primo nodo e'
  * sicuramente la testa */
 if(!head)return new;

 /* altrimenti ricorsivamente inserisco in una sottolista */
 head->prossimo=inserisci_in_lista(head->prossimo, new);
 return head;
}

/* funzione di confronto per long necessaria per
 * qsort() */

int comparalong(const void *a, const void *b){ 
  if(*((long *)a)==*((long *)b)) return 0; 
  if(*((long *)a)>*((long *)b)) return 1; 
  return -1;

}       
/* ordina i risultati appoggiandosi su qsort() */
void ordina_risultati(long *elenco, int numelem){

  qsort(elenco,numelem,sizeof(long),comparalong); 
}

/* solite procedure utilizzate durante il corso */
/*************************************************************************/

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;
}