/*******************************************************************************
   This is a modified version of the source code file rolofile.c which
   accompanies assignment # 3
   The difference is only in the function ReadRoloEntry() and in the code in
   the UNIT_TEST that tests this function. The version of ReadRoloEntry()
   in this file expects the caller to provide space for the name, address,
   and phone strings instead of making the caller's pointers point to memory
   space that the function has provided as is done in the original version.
*******************************************************************************/

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

#define MAX_LEN	320	/* maximum # of characters in a field */

/***************************************************************************
NAME:		skip_white_space( const char *ptr )
INPUT:		ptr			: points to the current character
OUTPUT:		---
RETURN:		const char *		: points to the next
					  non-white-space character
DESCRIPTION:	Skips over white space in the string given as 'ptr'.

---------------------------------------------------------------------------*/
static	const char	*skip_white_space( const char *ptr )
{
	while ( isspace( *ptr ) )
		++ptr;

	return ( ptr );
}

/***************************************************************************
NAME:		read_field( FILE *fp, const char *field_name,
				char *field_value )
INPUT:		fp			: file to read from
		field_name		: name of the field to be read
OUTPUT:		field_value		: value of the field
RETURN:		int			: 1 if successfull
					  0 otherwise
DESCRIPTION:	Attempts to read the given field from the file.
		Note that the field value may have leading white-space.

---------------------------------------------------------------------------*/
static	int	read_field( FILE *fp, const char *field_name,
				char *field_value )
{
	int	num_matched;
	char	format[80];

	/* The following sprintf command creates a format string for the scanf.
	   Eg: If 'field_name' is "FOO", the format string would
	   be " FOO:%[^\n]". This would be used to check for a line
	   starting with "FOO:" and would read all the characters
	   following the ':' until the end of line.  */

	sprintf( format, " %s:%%[^\n]", field_name );
	/* The space before the %s is important ! */

	num_matched = fscanf( fp, format, field_value );

	return ( num_matched == 1 );
}


/***************************************************************************
NAME:		ReadRoloEntry( FILE *fp, char *the_name,
				char *the_addr, char *the_phone )
INPUT:		fp			: file to read from
OUTPUT:		the_name		: the NAME field of the entry
			the_addr		: the ADDR field of the entry
			the_phone		: the PHONE field of the entry
RETURN:		int			: 0 if successfully read an entry
					 -1 on error or end of file
DESCRIPTION:	Reads one entry (consisting of a name, address, and phone)
		from the file.
		The NAME field must appear in the file and must be the first
		of the three lines defining the entry.
		The ADDR and PHONE fields are optional but the ADDR field
		must precede the PHONE field if both exist.

		Note that the caller must ensure that the output parameters point to
		memory locations where there is sufficient space for the strings.
		The strings will never be longer than MAX_LEN characters.

---------------------------------------------------------------------------*/
int	ReadRoloEntry( FILE *fp, char *the_name, char *the_addr, char *the_phone )
{
	int		status;
	char	name[MAX_LEN+1],
			addr[MAX_LEN+1],
			phone[MAX_LEN+1];

	/* Set all buffers to the empty string */

	name[0] = '\0';
	addr[0] = '\0';
	phone[0] = '\0';
	status = -1;

	if ( read_field( fp, "NAME", name ) )
	{
		read_field( fp, "ADDR", addr );
		read_field( fp, "PHONE", phone );
		status = 0;
	}

	strcpy( the_name, skip_white_space( name ) );
	strcpy( the_addr, skip_white_space( addr ) );
	strcpy( the_phone, skip_white_space( phone ) );

	return ( status );
}

/***************************************************************************
NAME:		WriteRoloEntry( FILE *fp, const char *name, const char *addr,
				const char *phone )
INPUT:		fp			: file to write to
		name			: the NAME field of the entry
		addr			: the ADDR field of the entry
		phone			: the PHONE field of the entry
OUTPUT:		---
RETURN:		int			: 0 if successfully wrote the entry
					 -1 on error
DESCRIPTION:	Writes one entry (consisting of name, address, and phone)
		to the file.
		Only non-empty fields are written to the file.

---------------------------------------------------------------------------*/
int	WriteRoloEntry( FILE *fp, const char *name, const char *addr,
				const char *phone )
{
	int	status = -1;

	if ( name != NULL && name[0] != '\0' )
	{
		fprintf( fp, "NAME: %.*s\n", MAX_LEN, name );

		if ( addr != NULL && addr[0] != '\0' )
			fprintf( fp, "ADDR: %.*s\n", MAX_LEN, addr );

		if ( phone != NULL && phone[0] != '\0' )
			fprintf( fp, "PHONE: %.*s\n", MAX_LEN, phone );

		fprintf( fp, "\n" );

		status = 0;
	}

	return ( status );
}

#ifdef UNIT_TEST
/***************************************************************************
This 'main' function is for use in doing a unit-test of the above functions.
The basic idea of a unit-test is that each module should be tested in isolation
from the others.  When this module is used as part of a larger program,
this main is not used - hence it is ifdef'd out.
---------------------------------------------------------------------------*/
int	main( int argc, char *argv[] )
{
	FILE		*fp;
	char		name[MAX_LEN+1],
				addr[MAX_LEN+1],
				phone[MAX_LEN+1];
	const char	*rolofile = "rolo.txt";

	if ( argc > 1 )
		rolofile = argv[1];

	fp = fopen( rolofile, "r" );
	if ( fp == NULL )
	{
		fprintf( stderr, "Couldn't open %s\n", rolofile );
		exit( 1 );
	}

	while ( ReadRoloEntry( fp, name, addr, phone ) != -1 )
	{
		WriteRoloEntry( stdout, name, addr, phone );
	}

	if ( fclose( fp ) != 0 )
		fprintf( stderr, "Couldn't close %s\n", rolofile );

	return ( 0 );
}
#endif /* UNIT_TEST */

