/*--------------------------------------------------------------------
 * FICHERO:  UneH.c
 * OBJETIVO: Definir la funcin UneH()
 * AUTOR:    Pedro Reina
 * FECHA:    J.20.4.1995
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * Ficheros de cabecera
 *------------------------------------------------------------------*/

#include "Zeus.h"

/*--------------------------------------------------------------------
 * Definicin de macros constantes
 *------------------------------------------------------------------*/

#define MAXCAB  35

#define DENTRO  0
#define FUERA   1

#define ORD_PC  0
#define ORD_QL  1

/*--------------------------------------------------------------------
 * Variables globales
 *------------------------------------------------------------------*/

char   Car;                /* Carcter que se lee y escribe   */
char   Lin[MAXLIN];        /* Lnea que se lee y escribe      */

char   Cab[MAXCAB][15];    /* Nombres de cabecera con < >     */

FILE * Entrada;            /* Fichero de entrada de datos     */
FILE * Salida;             /* Fichero de salida de datos      */

/*--------------------------------------------------------------------
 * Declaracin de funciones
 *------------------------------------------------------------------*/

void Concatena();
void Expurga();
void EscribeCar();
void EstudiaLin();
char NoVacia();
void Extrae();
char CabeceraRepetida();

/*--------------------------------------------------------------------
 * Definicin de macros funciones
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * MACRO:    LeeCar()
 * OBJETIVO: Leer un carcter del fichero Entrada
 * ENTRADAS: Ninguna
 * SALIDAS:  La variable global Car
 *------------------------------------------------------------------*/
#define LeeCar()  (Car=fgetc(Entrada))

/*--------------------------------------------------------------------
 * Definicin de funciones
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * FUNCION:  UneH()
 * OBJETIVO: Reunir todos los ficheros de cabecera .h, quitar ciertos
 *           estamentos y dejar el resultado en Olimpo.h
 * ENTRADAS: Variables globales
 * SALIDAS:  Ninguna. El programa puede abortar
 *------------------------------------------------------------------*/
void UneH()
  {
  short i;
  char  Cabecera[LONG_FICH_LARGO];
  char  Final   [LONG_FICH_LARGO];

  PresentaOpcion ("Creacin de Olimpo.h");

  if ( Salida = AbreFicheroGrabar ("Inutil") )
    {
    printf ("\nLeyendo ficheros de cabecera...");
    for ( i=0 ; i<TotalOlimpo ; i++ ) 
      { 
      strcpy (Cabecera,Olimpo[i]);
      strcat (Cabecera,".h");
      ArreglaSeparador (Cabecera);
      Concatena ( Cabecera ); 
      }
    fclose (Salida);

    strcpy (Final,"Olimpo");
    strcat (Final,".h");
    ArreglaSeparador (Final);
    Expurga ("Inutil",Final);
    remove ("Inutil");
    printf ("\nTerminado.\n");
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  Concatena()
 * OBJETIVO: Leer caracteres de un fichero y volcarlos en Salida, quitando
 *           todos los comentarios y las lneas en blanco.
 * AVISO:    Se considera comentario todo lo que formalmente lo sea, aunque
 *           est entre comillas.
 * ENTRADAS: El nombre del fichero de entrada
 * SALIDAS:  El fichero Salida se modifica
 *------------------------------------------------------------------*/
void Concatena (Nombre)
char * Nombre;
  {
  char Estado = FUERA;

  if ( Entrada = AbreFicheroLeer (Nombre) )
    {
    while ( !feof(Entrada) )
      {
      LeeCar();

      if ( Estado == FUERA )
        {
        if ( Car == '/' )
          {
          LeeCar();
          if ( Car == '*' ) { Estado = DENTRO; }
          else
            {
            EscribeCar ('/');
            EscribeCar (Car);
            }
          }
        else { EscribeCar (Car); }
        }

      if ( Estado == DENTRO )
        {
        if ( Car == '*' )
          {
          LeeCar();
          if ( Car == '/' )
            { Estado = FUERA; }
          }
        }
      }
    fclose (Entrada);
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  EscribeCar()
 * OBJETIVO: Escribir un carcter en el fichero Salida, evitando que se
 *           escriban dos '\n' seguidos
 * ENTRADAS: El caracter
 * SALIDAS:  El fichero Salida se modifica
 *------------------------------------------------------------------*/
void EscribeCar(c)
char c;
  {
  static char Ant = '\n';

  if ( ( (c!='\n') || (c=='\n' && Ant!='\n') ) && c!=EOF )
    {
    Ant = c;
    fputc(c,Salida);
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  Expurga()
 * OBJETIVO: Volcar un fichero en otro quitando las lneas inutiles
 * ENTRADAS: Los nombres de dos ficheros
 * SALIDAS:  El fichero Salida queda modificado
 *------------------------------------------------------------------*/
void Expurga (Origen,Destino)
char *Origen, *Destino;
  {
  if ( Entrada = AbreFicheroLeer (Origen) )
    {
    if ( Salida = AbreFicheroGrabar (Destino) )
      {
      fprintf (Salida, "/* Olimpo.h %s  -  Pedro Reina, %s */\n", 
               VERSION, FECHA);
      fputs ("#ifndef _OLIMPO_\n",Salida);
      fputs ("#define _OLIMPO_\n",Salida);
      printf ( "\nEstudiando datos..." );
      while ( !feof(Entrada) )
        {
        fgets (Lin,MAXLIN,Entrada);
        EstudiaLin();
        }
      fputs ("#endif /* _OLIMPO_ */\n",Salida);
      fclose (Salida);
      }
    fclose (Entrada);
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  EstudiaLin()
 * OBJETIVO: Estudiar una lnea y escribirla en Salida si es necesaria
 * ENTRADAS: La variable global Lin
 * SALIDAS:  El fichero Salida puede quedar modificado
 *------------------------------------------------------------------*/
void EstudiaLin()
  {
  static char Estado = FUERA;
  static char Ord = NULL;

  if ( strstr (Lin,"#define OLIMPO_") )
    {
    if ( strstr (Lin,"OLIMPO_PC") ) { Ord = ORD_PC; }
    if ( strstr (Lin,"OLIMPO_QL") ) { Ord = ORD_QL; }
    }

  if ( Estado == DENTRO )
    {
    if ( strstr (Lin,"#endif") ) { Estado = FUERA; }
    }

  if ( Estado == FUERA )
    {
    if ( strstr (Lin,"#ifdef OLIMPO_PC") && Ord != ORD_PC   ||
         strstr (Lin,"#ifdef OLIMPO_QL") && Ord != ORD_QL )
      { Estado = DENTRO; }

    else if ( strstr (Lin,"#ifdef OLIMPO_")   ||
              strstr (Lin,"#ifndef _")        ||
              strstr (Lin,"#define _")        ||
              strstr (Lin,"#endif")           ||
              strstr (Lin,"#include \"")      ||
              strstr (Lin,"#include <") && CabeceraRepetida() )
       ;
    else 
      {
      if ( NoVacia (Lin) )  { fputs (Lin,Salida); }
      }
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  NoVacia()
 * OBJETIVO: Decir si una lnea es no vaca
 * ENTRADAS: Una cadena
 * SALIDAS:  1 si la lnea slo contiene blancos, 0 en otro caso
 *------------------------------------------------------------------*/
char NoVacia (Linea)
char *Linea;
  {
  char  Vacia = 1;
  short i;
  
  for ( i=0 ; Linea[i] && Vacia ; i++ )
    { Vacia = isspace (Linea[i]); }
    
  return ( !Vacia );
  }

/*--------------------------------------------------------------------
 * FUNCION:  CabeceraRepetida()
 * OBJETIVO: Decir si un fichero de cabecera ya ha sido incluido
 * ENTRADAS: La variable global Lin
 * SALIDAS:  La variable global Cab puede quedar modificada
 *------------------------------------------------------------------*/
char CabeceraRepetida()
  {
  static short Total = 0;
  char Visto = 0;
  char Nombre[15];
  short i;

  Extrae (Nombre);

  for ( i=0 ; i<=Total && !Visto ; i++ )
    {
    if ( ! strcmp (Nombre,Cab[i]) ) { Visto = 1; }
    }

  if ( !Visto )
    {
    Total++;
    if ( Total == MAXCAB )
      {
      printf ("\n\nError: Demasiados ficheros de cabecera\n");
      exit (1);
      }
    else
      { strcpy (Cab[Total],Nombre); }
    }

  return ( Visto );
  }

/*--------------------------------------------------------------------
 * FUNCION:  Extrae
 * OBJETIVO: Sacar el nombre del fichero de cabecera de una lnea
 * ENTRADAS: La cadena donde dejar el nombre
 * SALIDAS:  La cadena queda modificada
 *------------------------------------------------------------------*/
void Extrae (Nombre)
char * Nombre;
  {
  char *Inicio,*Fin;

  Inicio = strchr (Lin,'<'), Inicio++;
  Fin    = strchr (Lin,'>'), Fin--;

  while ( Inicio<=Fin ) { *Nombre++ = *Inicio++; }
  *Nombre = NULL;
  }