//Jeff Letendre

#include <stdlib.h> 	                   	//malloc()
#include <stdio.h>     				//for printf(), scanf()
#include <string.h> 			  	//for strlen()
#include <io.h>	    			   	//for fflush()

#define MAX_CITY 30       			//set max for letters in city name
#define MAX_STATE 30     			//set max for letters in state name
#define MAX_ZIP 5

void main (void);                      		//main prototype
int is_empty (struct node *);      		//is_empty prototype
int push (struct node **);          		//push prototype
int pop (struct node **);             		//pop prototype
void search (struct node **);
void free_nodes (struct node **pstack);

struct node     				//structure template
   {
   char zip_code[MAX_ZIP+1];    		//allow 1 extra subset in array for NULL chracter
   char city[MAX_CITY];              		//structure element
   char state[MAX_STATE];          		//structure element
   struct node *link;                   	//pointer to next node in the list
   };
////////////END OF HEADER SECTION////////////////

void main (void)
   {
   struct node *pstack = NULL;     		//pointer to node for stacking
   int ok_so_far = 1, no_of_nodes = 0; 		//looping /counter variables
   clrscr();     //sweep screen
      while (ok_so_far == 1)   			//input loop
      {
      ok_so_far = push(&pstack);   		//call push func to get new info
      if (ok_so_far == 1)
	 no_of_nodes ++;
      else if(ok_so_far == 0)			//if push() could not allocate memory
	 {
	 puts("\nAn unexpected error has occurred - terminating program");
	 exit(1);      				//Abort program
	 }
      }
   search (&pstack);       			//search linked list
   free_nodes(&pstack);                  	//release memory back to OS when done
   }
   /////////// end main() ////////////////

int push(struct node **pstack)
    {
    struct node *new_ptr;                  	//pointer for new struct
    new_ptr = (struct node *) malloc(sizeof(struct node));	//allocate memory for new node
    if(new_ptr == (struct node *) NULL)    	//if malloc returns NULL
       {
       printf("ERROR!  Unable to allocate memory - Abort\n");
       free(new_ptr);
       return (0);     				//return 0 so calling function knows an error occurred
       }
    else
       {
       printf("\n\nEnter %d digit zip code or 'q' to quit>>", MAX_ZIP);
       gets(new_ptr->zip_code); 		//input zip code
       new_ptr->zip_code[MAX_ZIP] = '\0';	//assign NULL to 6th char in zip_code array
       if (strcmp(new_ptr->zip_code, "q") != 0)	//if q is not entered-user must want to proceede
	  {                                	//if user wants to continue
	  printf("\nEnter a less than %d character state name>>\n", MAX_STATE);
	  gets(new_ptr->state);             	//input state
	  printf("\nEnter a less than %d character city name>>\n", MAX_CITY);
	  gets(new_ptr->city);             	//input city
	  new_ptr->link = *pstack;
	  *pstack = new_ptr;
	  return (1);                     	//return 1 so calling func will continue to loop
	  }
       else return (2);               		//return 2 so calling func to stop looping
       }
    }
///////////////////End push////////////////////

void search (struct node **pstack)
   {
   struct node *ptemp;
   int test = 0;
   char ch, find[6];
   ptemp = *pstack;
   printf("\n\nEnter %d digit zip code to search for \nor 'e' to print entire list>>", MAX_ZIP);
   gets(find); 					//input zip code
   find[MAX_ZIP] = '\0';			//assign NULL to 6th char in find array
   if (find[0] =='E' || find[0] =='e')  	//if user wants to view entire list
      {                         		//show it to them
      test = 1;
      while (test != 0)				//while stack is not empty print
	    test = pop (pstack);   		//info from stack and free nodes
      }
   else     					//otherwise search for zip code
      {
      while (test == 0 || ptemp != NULL)   	//while not found nor at the end of list
	 {
	 if (strcmp(ptemp->zip_code, find) == 0)
	    {
	    test = 1;               		//if found set test to 1
	    printf("Zip Code:  %s\n", ptemp->zip_code);  //print output to screen
	    printf("State: %s\n", ptemp->state);
	    printf("City: %s\n\n", ptemp->city);
	    }
	 else if (ptemp == NULL)    		//if at the end of list
	    {
	    printf("The zip code %s was not found.\n", find);
	    test = 1;              		//stop looping / not required because (ptemp != NULL) in while
	    }
	 ptemp = ptemp->link;        		//move to next node in list
	 }
      puts ("\nType 'y' if you would you like to see the entire list");
      puts ("or any other key to continue>>");
      ch = getch();
      if (ch == 'y' || ch == 'Y')
	 {
	 test = 1;
	 while (test != 0)         		//while stack is not empty pop nodes
	 test = pop (pstack);   		//print info from stack and free node
	 }
      }
   }
///////////end of search///////////////

int pop (struct node **pstack)
   {
   struct node *temp;      			//temp pointer used for free()ing memory
   if (is_empty(*pstack)== 1) 			//if stack is empty
      {
      printf("\nStack is now empty");
      return(0);
      }
   else
      {
      temp = *pstack;
      printf("Zip Code:  %s\n", temp->zip_code);	//print output to screen
      printf("State: %s\n", temp->state);
      printf("City: %s\n\n", temp->city);
      *pstack = (*pstack)->link;
      free(temp);                		// release popped node's memory back to Operating System
      return(1);                           	//return 1 so calling function knows stack is not empty
      }
   }
////////////end pop/////////////

int is_empty (struct node *stack)  	//test if stack points to NULL
   {
   if (stack == NULL)
      return(1);             		//if stack does point to NULL return 1 or true
   return(0);                		//othrewise stack is not empty
   }
//////////end is_empty//////////

void free_nodes (struct node **pstack)
   {
   struct node *temp;      		//temp pointer used for free()ing memory
   while (*pstack != NULL)
      {
      temp = *pstack;
      *pstack = (*pstack)->link;
      free(temp);               	//release popped node's memory back to Operating System
      }
   }
/////////end free_nodes/////////
/////////////////////////////////// END PROGRAM /////////////////////////////


