/* File: CExamples/OO_pgm_in_C_new/list_stack_without_newstack.c */
#include <stdio.h>
#include <stdlib.h>
#include "stack_with_delete.h"

/* This is the Data Structure used to implement the stack:
   the contents of the first cell in the list contains the top elem
   and next points to the cells below in the stack */

struct cell { int content;
              struct cell *next;
            };

typedef struct cell *cellptr; /* the data struct for stack is simply
                            a (sentinel) pointer to the first cell */

typedef cellptr *cellptrptr; /* a pointer to that pointer is stored
                      in the abstract class.  With this
                      argument, push and pop can update
                      the pointer to the first cell. */

void list_delete_stack( stackptr self )
/* Assumes that sptr is the result of new_stack */
{extern const stack empty_list_stack; /* forward declare */
 cellptrptr lsptr;
 struct cell *curr, *prev;

 if(self != &empty_list_stack) /* prevent delete of prototype */
   {lsptr = (cellptrptr)self->objptr;
    curr = *lsptr;
    while(curr != NULL)
      {prev = curr; curr = curr->next; free(prev); /* (c) */
      }
   }
 free(lsptr); /* (b) */
 free(self); /* (a) */
}/* end list_delete_stack */


/* The following three functions define the list_stack operations */
int list_isempty(stackptr sptr)
{return( (*(cellptrptr)sptr->objptr) == NULL );
}/* end list_is_empty */

void list_push(int i, stackptr sptr)
{cellptrptr lsptr, lsptr2;
 struct cell *cellptr;

 lsptr = (cellptrptr)sptr->objptr; lsptr2 = lsptr;

 cellptr = malloc(sizeof(struct cell));
 /* no check for memory overflow
    see (c) in delete_stack for correponding delete */
 
 cellptr->content = i;
 cellptr->next = *lsptr2; /* note the dereference
             this is where the pointer to the first cell is stored */
 *lsptr2 = cellptr;
}/* end list_push */


int list_pop(stackptr sptr)
{cellptrptr lsptr; cellptr ls2;
 int topvalue;

 lsptr = (cellptrptr)sptr->objptr;
 ls2 = *lsptr;
 *lsptr = ls2->next;
 
 topvalue = ls2->content;
 free(ls2);
 return topvalue;
}/* end list_pop */

stackptr list_clone(const struct stackstruct* sptr_in)
{cellptrptr lsptr; stackptr sptr;
 struct cell *curr; /* iterator for list that is passed as arg */
 struct cell *copy; /* iterator for copy of that list */

 extern const stack empty_list_stack; /* forward declare */

 if(sptr_in == &empty_list_stack) printf("\nCloning the proto-type empty_list_stack\n");

 /* allocate memory for the stack */
 sptr = (stackptr)malloc(sizeof(stack));
 /* see (a) in delete_stack for corresponding free */

 /* set the function pointers to list functions */
 sptr->is_empty = list_isempty;
 sptr->push     = list_push;
 sptr->pop      = list_pop;
 sptr->clone    = list_clone;
 sptr->delete_stack = list_delete_stack; 

 /* allocate memory for the list_stack and initialize */
 sptr->objptr = malloc(sizeof(cellptr));
 /* see (b) in delete_stack for corresponding free */

 lsptr = (cellptrptr)sptr_in->objptr;
 curr = *lsptr;
 if ( curr == NULL)
    /* no cells in argument list */
    *((cellptrptr)sptr->objptr) = NULL;
 else
    {/* must copy cells: first cell
        see (c) in delete_stack for corresponding free */
     copy = (struct cell*)malloc(sizeof(struct cell));
     copy->content = curr->content;
     *((cellptrptr)sptr->objptr) = copy; /* link data struct to it */
     curr = curr->next;
     while(curr != NULL)
        {/* copy 2nd, 3rd, ... cells
            see (c) in delete_stack for corresponding free */
         copy->next = (struct cell*)malloc(sizeof(struct cell));
         copy = copy->next;
         copy->content = curr->content;
         curr = curr->next;
        }
     copy->next = NULL;
    }    
 return sptr;
}/* end list_clone */

/* There is no constructor newstack().
   Instead there his one linkable variable empty_list_stack,
   whose clone() can be used to make new empty array stacks.
   See main2.c for usage.  */

static const void* sentinel = NULL;

const stack empty_list_stack
= {/* initialize */
&sentinel
,list_isempty
,list_push
,list_pop
,list_clone
,list_delete_stack
}; /* end stack empty_list_stack */
