stack.c 6.01 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */

/*****************************************************************
 * stack.c
 *
 * Generic stack package
 *****************************************************************/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "tcl_init.h"
#include "stack.h"
#include "sim_error.h"

Stack *
StackInit(void)
{
   Stack *stack;
   int i;
   
   stack = (Stack *)malloc(sizeof(Stack));

   stack->head = -1;
   for (i=0; i<MAX_STACK_SIZE; i++) {
      stack->element[i] = 0;
   }
   return stack;
}


int
StackPush(Stack *stack, StackItem element)
{
   stack->head++;
   if (stack->head >= MAX_STACK_SIZE) {
      CPUWarning("STACK OVERFLOW\n");
      stack->head--;
      return 1;
   }
   stack->element[stack->head] = element;
   return 0;
}


StackItem
StackPop(Stack *stack)
{
   StackItem tmp;

   if (stack->head == -1) {
      CPUWarning("STACK UNDERFLOW popping\n");
      return (StackItem)NULL;
   } else {
      tmp = stack->element[stack->head];
      stack->head--;
   }
   return tmp;
}

StackItem
StackTop(Stack *stack)
{
   if (stack->head == -1) {
      return (StackItem)NULL;
   } else {
      return stack->element[stack->head];
   }
}

int
StackEmpty(Stack *stack)
{
   return (stack->head == -1);
}

StackItem
StackIndex(Stack *stack, int depth)
{
   if ((stack->head - depth) < 0) {
      return (StackItem)NULL;
   } else {
      return stack->element[stack->head - depth];
   }
}

/************************************************************
 * Stack Tcl Interface
 ************************************************************/

static Tcl_HashTable names;

static int cmdCreate(Tcl_Interp *interp, int argc, char *argv[]);
static int cmdPush(Tcl_Interp *interp, int argc, char *argv[]);
static int cmdPop(Tcl_Interp *interp, int argc, char *argv[]);
static int cmdTop(Tcl_Interp *interp, int argc, char *argv[]);
static int cmdList(Tcl_Interp *interp, int argc, char *argv[]);
static int cmdClear(Tcl_Interp *interp, int argc, char *argv[]);

static tclcmd stackCmds[] = {
{   "create",       3, cmdCreate,      " create name"},
{   "push",         4, cmdPush,        " push id entry"},
{   "pop",          3, cmdPop,         " pop id"},
{   "top",          3, cmdTop,         " top id"},
{   "list",         3, cmdList,        " list id"},
{   "clear",        3, cmdClear,       " clear id"},
{   NULL,           0, NULL,           NULL}
};

void StackTclInit(Tcl_Interp *interp)
{
   Tcl_InitHashTable(&names, TCL_STRING_KEYS);
   Tcl_CreateCommand(interp, "stack", DispatchCmd, (ClientData)stackCmds, NULL);
}

int cmdCreate(Tcl_Interp *interp, int argc, char *argv[])
{
   char *name = argv[2];
   int new = 0;
   Tcl_HashEntry *entry;
   Stack *stack;

   entry = Tcl_CreateHashEntry(&names, name, &new);
   
   if (!new) {
      Tcl_AppendResult(interp, "stack name already taken \"",
                       name, "\"", NULL);
      return TCL_ERROR;
   }
   
   stack = StackInit();
   Tcl_SetHashValue(entry, stack);

   return TCL_OK;
}

int cmdPush(Tcl_Interp *interp, int argc, char *argv[])
{
   char *name = argv[2];
   char *val = argv[3];
   char *savedVal;
   Stack *stack = NULL;
   Tcl_HashEntry *entry;
   
   entry = Tcl_FindHashEntry(&names, name);
   
   if (!entry) {
      Tcl_AppendResult(interp, "no stack named \"", name, "\"", NULL);
      return TCL_ERROR;
   }

   stack = Tcl_GetHashValue(entry);
   ASSERT(stack);

   savedVal = (char *) malloc(strlen(val) + 1);
   ASSERT(savedVal);
   strcpy(savedVal, val);
    
   if (StackPush(stack, PTR_TO_UINT64(savedVal)) != 0) {
      Tcl_AppendResult(interp, "STACK OVERFLOW pushing \"", savedVal, "\"", NULL);
      return TCL_ERROR;
   }
   return TCL_OK;
}

int cmdPop(Tcl_Interp *interp, int argc, char *argv[])
{
   char *name = argv[2];
   char *val;
   Stack *stack = NULL;
   Tcl_HashEntry *entry;
   
   entry = Tcl_FindHashEntry(&names, name);
   
   if (!entry) {
      Tcl_AppendResult(interp, "no stack named \"", name, "\"", NULL);
      return TCL_ERROR;
   }

   stack = Tcl_GetHashValue(entry);
   ASSERT(stack);

   val = UINT64_TO_PTR(StackPop(stack));

   if (val) {
      Tcl_AppendResult(interp, val, NULL);
      free(val);
   } else {
      Tcl_AppendResult(interp, "STACK UNDERFLOW", NULL);
      return TCL_ERROR;
   }
   
   return TCL_OK;
}

int cmdTop(Tcl_Interp *interp, int argc, char *argv[])
{
   char *name = argv[2];
   char *val;
   Stack *stack = NULL;
   Tcl_HashEntry *entry;
   
   entry = Tcl_FindHashEntry(&names, name);
   
   if (!entry) {
      Tcl_AppendResult(interp, "no stack named \"", name, "\"", NULL);
      return TCL_ERROR;
   }

   stack = Tcl_GetHashValue(entry);
   ASSERT(stack);

   val = UINT64_TO_PTR(StackTop(stack));
   Tcl_AppendResult(interp, val, NULL);
   
   return TCL_OK;   
}

int cmdList(Tcl_Interp *interp, int argc, char *argv[])
{
   char *name = argv[2];
   char *val;
   Stack *stack = NULL;
   Tcl_HashEntry *entry;
   int i;

   entry = Tcl_FindHashEntry(&names, name);
   
   if (!entry) {
      Tcl_AppendResult(interp, "no stack named \"", name, "\"", NULL);
      return TCL_ERROR;
   }

   stack = Tcl_GetHashValue(entry);
   ASSERT(stack);

   if (stack->head == -1) {
      Tcl_AppendResult(interp, NULL, NULL);
   } else {
      for (i = 0; i <= stack->head; i++) {
         val = UINT64_TO_PTR(stack->element[i]);
         Tcl_AppendElement(interp, val);
      }
   }
   return TCL_OK;   
}

int cmdClear(Tcl_Interp *interp, int argc, char *argv[])
{
   char *name = argv[2];
   Stack *stack = NULL;
   Tcl_HashEntry *entry;
   int i;

   entry = Tcl_FindHashEntry(&names, name);
   
   if (!entry) {
      Tcl_AppendResult(interp, "no stack named \"", name, "\"", NULL);
      return TCL_ERROR;
   }

   stack = Tcl_GetHashValue(entry);
   ASSERT(stack);
   for (i=0; i<MAX_STACK_SIZE; i++) {
      if (i <= stack->head) free(UINT64_TO_PTR(stack->element[i]));
      stack->element[i] = NULL;
   }
   stack->head = -1;
   return TCL_OK;   
}