/****************************************************************************
PROGRAMA:	Words
AUTOR:		Kiko
FECHA:		19.09.94
FINALIDAD:	Imprime en orden alfab‚tico las palabras contenidas en un fichero
				de texto.
HISTORIA:
BIBLIOGRAFIA:	Practical C Programming
					Steve Oualline
					O'Reilly & Associates, Inc
					Cap. 16 Advanced Pointers
					pg. 271 y sigs.
MODO DE UTILIZACION: words <fichero>
****************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

struct node {
		struct node	*right;			/* sub rbol derecho */
		struct node	*left;			/* sub rbol izquierdo */
		char			*word;			/* palabra de este nodo */
};

static struct node *root = NULL;			/* La ra¡z del  rbol */

		/* PROTOTIPOS DE FUNCIONES */
	void scan(char *name);								/* Recorre el fichero buscando palabras */
	void print_tree(struct node *top);				/* Imprime las palabras del fichero */
	void enter(struct node **root, char *word);	/* Coloca una palabra en el  rbol */
	char *save_string(char *string);					/* Almacena una string en el heap */
	void memory_error(void);							/* Indica al usuario que no hay memoria */

main(int argc, char *argv[])
{
	if (argc != 2) {
		(void) fprintf(stderr, "Error: N£mero de par metros err¢neo\n");
		(void) fprintf(stderr, "		 en la l¡nea de comandos\n");
		(void) fprintf(stderr, "El modo de uso es:\n");
		(void) fprintf(stderr, "	words 'fichero'\n");
		exit(8);
	}
	scan(argv[1]);
	print_tree(root);
	return(0);
}

/****************************************************************************
* Scan -- recorre el fichero localizando palabras
*
* Par metros:
*		name -- nombre del fichero a recorrer
****************************************************************************/
void scan(char *name)
{
	char word[100];		/* Palabra en curso */
	int index;				/*	Indice dentro de la palabra */
	int ch;					/*	Caracter actual */
	FILE *in_file;			/*	Fichero de entrada */

	in_file = fopen(name, "r");
	if (in_file == NULL) {
		(void) fprintf(stderr, "Error: Imposible abrir %s\n", name);
		exit(8);
	}
	
	while (1) {
		while (1) {
			/* Leer ignorando los espacios en blanco */
			ch = fgetc(in_file);
			if (isalpha(ch) || (ch == EOF))
				break;
		}
		if (ch == EOF)
			break;

		word[0] = (char)ch;
		for (index = 1; (unsigned)index < sizeof(word); index++) {
			ch = fgetc(in_file);
			if (!isalpha(ch))
				break;
			word[index] = (char)ch;
		}
		word[index] = '\0';		/* Terminar la palabra */
		enter(&root, word);
	}
	(void)fclose(in_file);
}
/****************************************************************************
* Enter -- Coloca una palabra en el  rbol
*
* Par metros:
*		node -- puntero a la ra¡z del  rbol
*		word -- palabra a introducir
****************************************************************************/
void enter(struct node **node, char *word)
{
	int result;		/* Resultado de strcmp */

	/* Mirar si se ha llegado al final */
	if ((*node) == NULL) {
		(*node) = (struct node *)malloc(sizeof(struct node));
		if ((*node) == NULL)
			memory_error();
		(*node)->left = NULL;
		(*node)->right = NULL;
		(*node)->word = save_string(word);
	}
	result = strcmp((*node)->word, word);
	if (result == 0)
		return;
	if (result < 0)
		enter(&(*node)->right, word);
	else
		enter(&(*node)->left, word);
}
/****************************************************************************
* Save_string -- Almacenar una string en el heap
*
* Par metros:
*		string -- string a almacenar
*
* Devuelve:
*		puntero a la memoria alojada en el heap con la string copiada en ella.
****************************************************************************/
char *save_string(char *string)
{
	char *new_string;		/* Espacio para la string */

	new_string = malloc((unsigned)(strlen(string) + 1));
	if (new_string == NULL)
		memory_error();
	(void)strcpy(new_string, string);
	return(new_string);
}
/****************************************************************************
* memory_error -- Indica al usuario que no hay memoria 
****************************************************************************/
void memory_error(void)
{
	(void)fprintf(stderr, "Error: No hay memoria suficiente.\n");
	exit(8);
}
/****************************************************************************
* print_tree -- Imprime las palabras contenidas en el  rbol
*
* Par metros:
*		top -- La ra¡z del  rbol a procesar
****************************************************************************/
void print_tree(struct node *top)
{
	if (top == NULL)
		return;					/* Arbol vac¡o */
	print_tree(top->left);
	(void)printf("%s\n", top->word);
	print_tree(top->right);
}

