/*******************************************
 * Demonstration Of Memory Management and  *
 * Doubly Linked Lists   by Tom Krotchko   *
 *  inspired by the book "C Made Easy" by  *
 * Herber Schildt published by Osborne     *
 * McGraw-Hill                             *
 *                                         *
 * Note to Manx users: I had trouble       *
 * running this with the 32 bit integer    *
 * compiler switch. I have not tested it   *
 * with the 16 bit integer switch.         *
 *                                         *
 * This was compiled with Lattice 4.0      *
 *******************************************/

#include "stdio.h" 

/* set up the structure with forward and backward pointers */
struct addr {
	char name[30];
	char street[40];
	char city[20];
	char state[3]; 
	char zip[10];
        char phone[11];
	struct addr *next; 
	struct addr *prior; 
} name_card; 

struct addr *start; /* pointer to first entry in list */
struct addr *last;  /* pointer to last entry in list */
main()
{
	int choice; 
 
	start=0; /* initialize the start of the list */ 
	do { 
		choice=print_menu(); 
		switch(choice) { 
			case 1: enter(); /* a new list addition */ 
				break; 
			case 2: delete(); /* delete a list entry */ 
				break; 
			case 3: list(); /* display everything on list */ 
				break; 
			case 4: search(); /* look for an entry in list */ 
				break; 
                        /* remove comments and delete printf's to activate */
			case 5: /*  save();   save list to disk */ 
				printf("\n*** Sorry, this function has  ***\n");
				printf("***   been disabled for now   ***\n");
				break; 
			case 6: load(); /* get the list from disk */ 
				break; 
			case 7: exit(0); 
		} 
	} while(1); 
} /* end of main procedure */ 
 
/*** beginning of subroutines ***/ 
 
print_menu() 
{ 
	char s[80]; 
	int c; 
 
	printf("\n1. Add an entry\n"); 
	printf("2. Delete an entry\n"); 
	printf("3. List all entries\n"); 
	printf("4. Search entries\n"); 
	printf("5. Save entries to disk\n"); 
	printf("6. Load entries from disk\n"); 
	printf("7. Quit to DOS\n"); 
	do { 
		printf("\nEnter your choice: "); 
		gets(s);
		c=atoi(s); /* change the input string to an integer */
	} while (c<0 || c>7); 
	return c; 
} 
 
enter() 
{ 
	struct addr *info; 
	char *malloc(); 
	do {    /* allocate memory for one more addition to list */
		info=malloc((struct addr *) sizeof(name_card)); 
		if(info==0) { 
			printf("\nOut of Memory"); 
			return; 
		} 
 
		inputs("enter name (press enter to quit): ",info->name,30); 
		if(!info->name[0]) break; 
		inputs("enter street: ",info->street,40); 
		inputs("enter city: ",info->city,20); 
		inputs("enter state: ",info->state,3);
		inputs("enter phone #: ",info->phone,11);
		inputs("enter zip: ",info->zip,10); 
 
		if(start!=0) { /* meaning its not the first entry */ 
			last->next=info;  /* update the forward pointer */
			info->prior=last; /* update the backward pointer */
			last=info;        /* set the last pointer */
			last->next=0;     /* mark the end of the list */
		} 
		else {  /* this is the first entry in the list */ 
			start=info;      /* set a new head of list */
			start->next=0;   /* set the end of the list */
			last=start;      /* mark the end of the list */
 
			start->prior=0;  /* mark the beginning of the list */
		} 
	} while(1); /* a forever loop. only a 'break' will exit */ 
} 
 
delete() 
{ 
 	struct addr *info, *find_it(); 
	char s[255]; 
 
	inputs("enter name to delete: ",s,30);
        /* use the function 'find_it()' to determine if the requested name
	   is in the list */ 
	info=find_it(s); 

	if(info) { 
		if(start==info) { /* if we're deleting the first on the 
				     list, handle it differently        */ 
			start=info->next; 
			start->prior=0; 
		} 
                else 
		{ 
			/* whew! multiple reference levels. This is just
			   setting the next pointer so that we no longer
			   point to the name requested for deletion */
			info->prior->next=info->next; 
			if(info!=last) 
				info->next->prior=info->prior; 
			else 
				last=info->prior; 
		} 
		free(info); /* return the memory of the entry just deleted */ 
	} 
} 
 
struct addr *find_it(name) 
char *name; 
{ 
	struct addr *info; 
 
	info=start;  /* point to the start of the list */ 
	while(info) { /* keep going until we get to the end of the list */ 
		if(!strcmp(name,info->name)) return info; 
		info=info->next; 
	} 
	printf("Sorry, the name is not in the list\n"); 
	return(0); 
} 
 
list() 
{ 
	register int t; 
	struct addr *info; 
 
	info=start; /* set up the head of the list */
	while(info) { 
		display_list(info); /* the function will handle printing */
		info=info->next; /* after printing, point to the next one */
	} 
	printf("\n\n"); 
} 
 
display_list(info) 
struct addr *info; 
{ 
	printf("%s\n",info->name); 
	printf("%s\n",info->street); 
	printf("%s\n",info->city);
	printf("%s\n",info->state);
        printf("%s\n",info->phone);
	printf("%s\n",info->zip);
	printf("\n");
} 
 
search() 
{ 
	char name[30]; 
	struct addr *info,*find_it(); 
 
	inputs("enter name to locate: ",name,30); 
	if(!(info=find_it(name))) 
		printf("not found\n"); 
	else 
		display_list(info); 
} 
 
save() 
{ 
	register int t,size; 
	struct addr *info; 
	char *p; 
	FILE *fp; 
 
	if((fp=fopen("namelist","w"))==0) { 
		printf("cannot open file\n"); 
		exit(0); 
	} 
 
	printf("\nSaving Entries\n"); 
	size=sizeof(name_card); 
	info=start; 
 
	while(info) { 
		p=(char *)info; 
		for(t=0;t<size;++t) 
			putc(*p++,fp); 
		info=info->next; 
	} 
	putc(EOF,fp); /* write an explicit EOF marker */ 
	fclose(fp); 
} 
 
load() 
{ 
	register int t,size; 
	struct addr *info, *temp; 
	char *p, *malloc(); 
	FILE *fp; 
 
	if((fp=fopen("namelist","r"))==0) { 
		printf("cannot open file\n"); 
		exit(0); 
	} 
 
        delall(); /* Get rid of any previously allocated lists */ 
	printf("\nLoading File\n"); 
	size=sizeof(name_card); 
	start=malloc(size); 
        if(!start) { 
		printf("out of memory\n"); 
		return; 
	} 
	info=start; 
	p=(char *)info; /* convert to char pointer */ 
 
	while((*p++=getc(fp))!=EOF) { /* keep reading until EOF */ 
		for(t=0;t<size-1;++t)  /* scan a character at a time */
			*p++=getc(fp); 
		info->next=malloc(size); 
		if(!info->next) { 
			printf("out of memory\n"); 
			return; 
		} 
		info->prior=temp; 
		temp=info; 
		info=info->next; 
		p=(char *)info; 
	} 
	free(temp->next); /* we do a free here since we've allocated 1 too many */
	temp->next=0; 
	last=temp; 
	start->prior=0; 
	fclose(fp); 
} 
 
/* inputs is a nice character input routine to simplify console handling */
inputs(prompt,s,count) 
 
char *prompt; 
char *s; 
int count; 
{ 
	char p[255]; 
	do { 
		printf(prompt); 
		gets(p); 
		if(strlen(p)>count) printf("\ntoo long\n"); 
	} while(strlen(p)>=count); 
	strcpy(s,p); 
 } 

/* note that the delall() function doesn't have to get fancy, it only needs to
   go through the list deleting anything that is pointed to. No need to worry
   about the backwards pointers since we won't be using them to delete       */
delall() 
{ 
	struct addr *info; 
 
	info=start;  /* point to the start of the list                    */ 
	while(info) { /* keep going until we get to the end of the list   */ 
		start=info->next; /* save the pointer to the next entry   */ 
		free(info); /* free the memory of the entry               */ 
		info=start; /* make info point to the same place as start */ 
        } 
	start=0; /* initialize the start of the list */ 
} 
/*** end of program ***/
