/*
file:   piglatin.c
author: muppet
date:   16 october 1999
description:
	ever have a bunch of text you needed to translate into pig latin?
	yeah, happens all the time.  well, this program will take care
	of that for you.  *cough*
	this is rather more heavily commented than it probably needs to
	be, mostly because i wrote it for a bub who doesn't know C or C++
	very well (i won't name any names here, but he has a goatee and
	answers to the epithet ``buttmunch'').
	there's really nothing very C++-specific about this program, 
	except for the use of iostreams.  it would probably make a smaller
	binary if it were written in C...  but i don't think it really
	matters.
change log:
    16 oct 99 - muppet
	created the program...
    18 oct 99 - muppet
	Y is no longer a vowel, so that "you" can become "ouyay".
	now changes all occurrences of "a" to "an," to make the output a
	little easer to speak.
    18 oct 99 - muppet
	ported to plain C.  deleted a lot of comments rather than 
	changing them.  other than changing to use stdio, no "porting"
	necessary... woohoo!
*/

/***********************************************************************
	#includes...
***********************************************************************/

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

/***********************************************************************
	global variables and macros
***********************************************************************/

#define BUFFERED


/*
 * in several places we will need a buffer in which to place a contructed
 * string.  let's avoid complications and declare a nice, large buffer
 * globally for general use.
 */
#define BUFLEN  1024    /* set this to be sufficiently large */
char buf[BUFLEN];

/***********************************************************************
	function prototypes
***********************************************************************/
int isvowel(char c);
char* piglatinify ( char * dest, const char * src );
void go(FILE *in, FILE *out);

/***********************************************************************
	the code...
***********************************************************************/

/*
 * we need to be able to test for whether a character is a vowel.
 * this is not built into ctype.h, so we have to roll our own.
 * 
 * argument:
 *      c       any single character.
 * 
 * return value:
 *      a boolean value, true if the given character c is a vowel,
 *      false otherwise.
 */
/*
int isvowel(char c)
{
	switch (c) {
		case 'A':
		case 'a':
		case 'E':
		case 'e':
		case 'I':
		case 'i':
		case 'O':
		case 'o':
		case 'U':
		case 'u':
			return 1;
		default:
			return 0;
	}
}
*/

#define isvowel(c)	\
	(  (c=='A')||(c=='a')	\
	 ||(c=='E')||(c=='e')	\
	 ||(c=='I')||(c=='i')	\
	 ||(c=='O')||(c=='o')	\
	 ||(c=='U')||(c=='u'))




/*
 * assume that we've been passed one word, with no surrounding whitespace 
 * or punctuation.  the rules of pig latin say that if a word starts with
 * a vowel, it is left alone, otherwise, the leading consonant group is
 * moved to the end and followed with ``ay.''
 * 
 * arguments:
 *      dest    pointer to a buffer in which we will write the output.
 *              it is up to the caller to ensure that sufficient space
 *              exists.
 * 
 *      src     pointer to the source string which will be translated
 *              into pig latin.  src will NOT be altered in any way.
 * 
 * return value:
 *      returns the pointer given in dest, so that this function can
 *      be placed easily in output stream statements.
 */
char* piglatinify ( char * dest, const char * src )
{
	const char *s = src;
	while (*s && !isvowel(*s))
		s++;
	
	strcpy(dest,s);
	
	if (s-src) {
		strncat(dest,src,s-src);
		strcat(dest,"ay");
	}
	
	return dest;
}





/*
 * the piglatinify() function is quite simplistic, and requires a fairly
 * rigid input format.  this makes the algorithm for turning words into
 * pig latin much easier than if had to make it smart enough to handle 
 * punctuation, et cetera.  so, we need a smart front-end to that function.
 * 
 * this function reads raw text from one stream and writes the pig latin
 * version of that text to the output stream.  we read the input one
 * line at a time, and send one word at a time to the translator.
 * 
 * arguments:
 *      in      stream from which we read input.
 *      out     stream to which we write output.
 * return value:
 *      none.
 */
void go(FILE *in, FILE *out)
{
	char linebuf[BUFLEN],	/* buffer for text read from the file */
	     c,			/* temporary character storage        */
	     *word,		/* points to the beginning of a word  */
	     *s;		/* our string-iterating pointer...    */
#ifdef BUFFERED
	char outbuf[BUFLEN*2];	/* buffer for output text             */
	char *o;
#endif
	
	/* read until we reach the end of file... */
	while (!feof(in)) {
		fgets(linebuf,BUFLEN,in);
		
		/*
		 * now scan the line for words...  we will use the word
		 * pointer as a kind of state variable.  when we find the
		 * beginning of a word, we will point word to that
		 * beginning, and then look for the end of the word.  once
		 * we find the end of the word, we process it and then set
		 * word back to NULL so that we know that we are now
		 * looking for the beginning of a word.  (a /very/
		 * simplistic state machine.)
		 */
		word=NULL;	/* not initially tracking a word      */
		s=linebuf;	/* start at the beginning of the line */
#ifdef BUFFERED
		o=outbuf;	/* start at the beginning of the line */
#endif
		
		/*
		 * read the entire line, until we reach the NULL
		 * terminator ('\0') at the end of the string...
		 */
		while (*s) {
			if (!word) {
				/* not currently tracking a word... */
				if (isalpha(*s)) {
					word=s;
				} else {
#ifdef BUFFERED
					*o++ = *s;
#else
					fputc(*s,out);
#endif
				}
			} else {
				/* we are currently tracking a word. */
				if (!isalpha(*s)) {
					c=*s;
					*s='\0';
					/*if (strcmp("a",word)==0) {*/
					if (((*word=='A')||(*word=='a')) 
					    && (*(word+1)=='\0')) {
#ifdef BUFFERED
						*o++='a';
						*o++='n';
#else
						buf[0]='a';
						buf[1]='n';
						buf[2]='\0';
#endif
					} else {
#ifdef BUFFERED
						piglatinify(o,word);
						while (*o) o++;
#else
						piglatinify(buf,word);
#endif
					}
#ifdef BUFFERED
					*o++ = c;
#else
					fputs(buf,out);
					fputc(c,out);
#endif
					word=NULL;
				}
			}
			/* advance to the next letter... */
			s++;
		}
	
		
		/*	
		 * we might have found the end of the string while still
		 * tracking a word --- if so, we need to write that as
		 * output!
		 */
		if (word) {
#ifdef BUFFERED
			piglatinify(o,word);
#else
			piglatinify(buf,word);
			fputs(buf,out);
#endif
		}
#ifdef BUFFERED
		*o = '\0';
		fputs(outbuf,out);
#endif
	}
}


/*
 * start point for the program.  we don't do any real work here, only
 * dispatching data to the real worker functions.
 * 
 * arguments:
 *      since main() is a special function, it's input arguments are well-
 *      defined by C/C++ tradition:
 *      argc    number of command line arguments.
 *      argv    array of pointers to the argument strings.
 * return value:
 *	zero for success, non-zero for failure.
 */
int main(int argc, char*argv[])
{
	FILE *infile;
	FILE *outfile;

	/* open output file */
	if (argc > 2) {
		/* second arg exists. -- write to that file. */
		if (!(outfile = fopen(argv[2],"wt"))) {
			perror(argv[2]);
			exit(2);
		}
	} else {
		outfile = stdout;
	}
	
	/* open input file */
	if (argc > 1) {
		/* first arg exists -- read from that file. */
		if (!(infile = fopen(argv[1],"rt"))) {
			perror(argv[1]);
			exit(1);
		}
	} else {
		infile = stdin;
	}
	
	/* process input. */
	go(infile,outfile);
	
	/* clean up */
	fclose(infile);
	fclose(outfile);
	return 0;
}

