/*
 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * mslpd_stack.c : Handles stack operations for the mslpd_query routines.
 *
 * Version: 1.4
 * Date:    03/07/99
 *
 * Licensee will, at its expense,  defend and indemnify Sun Microsystems,
 * Inc.  ("Sun")  and  its  licensors  from  and  against any third party
 * claims, including costs and reasonable attorneys' fees,  and be wholly
 * responsible for  any liabilities  arising  out  of  or  related to the
 * Licensee's use of the Software or Modifications.   The Software is not
 * designed  or intended for use in  on-line  control  of  aircraft,  air
 * traffic,  aircraft navigation,  or aircraft communications;  or in the
 * design, construction, operation or maintenance of any nuclear facility
 * and Sun disclaims any express or implied warranty of fitness  for such
 * uses.  THE SOFTWARE IS PROVIDED TO LICENSEE "AS IS" AND ALL EXPRESS OR
 * IMPLIED CONDITION AND WARRANTIES, INCLUDING  ANY  IMPLIED  WARRANTY OF
 * MERCHANTABILITY,   FITNESS  FOR  WARRANTIES,   INCLUDING  ANY  IMPLIED
 * WARRANTY  OF  MERCHANTABILITY,  FITNESS FOR PARTICULAR PURPOSE OR NON-
 * INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT WILL SUN BE LIABLE HEREUNDER
 * FOR ANY DIRECT DAMAGES OR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL
 * OR CONSEQUENTIAL DAMAGES OF ANY KIND.
 *
 * (c) Sun Microsystems, 1998, All Rights Reserved.
 * Author: Erik Guttman
 */
 /*
	Portions Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
 */

#include <stdio.h>
#include <assert.h>
#include <string.h>

#include "mslp_sd.h"
#include "slp.h"
#include "mslp.h"         /* for LOG */
#include "mslpd_mask.h"
#include "mslpd_stack.h"

#define MSLPQ_INCR 50

/*
 * stack_init
 *
 *   Creates the stack and puts the initial frame (INIT_STATE) on it.
 *   Optimisticly assume that everything in the use mask will be true
 *   initially.
 *
 *     pmUseMask  The mask generated by comparisons of srvtype, scope
 *                list and lang (if the search filter is not null).
 *
 * Returns:
 *   An initialized stack.
 */
MSLPQStack * stack_init(Mask *pmUseMask) {
  
  MSLPQStack *pstack      = (MSLPQStack*)
    safe_malloc(sizeof(MSLPQStack)*MSLPQ_INCR,0,0);
  
  pstack->iSize = 1;
  pstack->iMax  = MSLPQ_INCR;
  
  pstack->pframe          =
    (MSLPQframe*) safe_malloc(sizeof(MSLPQframe)*MSLPQ_INCR,0,0);
  pstack->pframe[0].pmask = pmUseMask;
  pstack->pframe[0].state = INIT_STATE;
  
  return pstack;
}

/*
 * stack_push
 *
 *   This guarantees that the stack does not overflow and pushes
 *   state onto the top available frame.
 *
 *     pstack   The stack to operate on
 *     pmask    The mask to push onto the stack (note the stack OWNS this)
 *     state    The state of the parsing at the time of the stack_push
 *
 * Returns: none
 *
 * Side effect: The stack might be resized as a result of this operation.
 *   It will remain at this increased size (there is no shrink to fit
 *   optimization, etc.)
 */ 
void stack_push(MSLPQStack *pstack, Mask *pmask, MSLPQState state) {
  if ((pstack->iSize +1) == pstack->iMax) {
    MSLPQframe *pframe = (MSLPQframe *)
      safe_malloc((pstack->iMax+MSLPQ_INCR)*sizeof(MSLPQframe),
      (char*)pstack->pframe, pstack->iSize*sizeof(MSLPQframe));
    pstack->iMax += MSLPQ_INCR;
    SLPFree(pstack->pframe);
    pstack->pframe = pframe;
  }
  pstack->pframe[pstack->iSize].state   = state;
  pstack->pframe[pstack->iSize].pmask   = pmask;
  pstack->iSize++;
}

/*
 * stack_pop
 *
 *   The stack is popped - this will simply return the current frame,
 *   and decrement the count.  Do not free the frame itself!  That must
 *   be done by the popper!
 */
MSLPQframe * stack_pop(MSLPQStack *pstack) {
  if (pstack->iSize == 0) {
    LOG(SLP_LOG_ERR,"pop: query handling stack empty");
    return NULL;
  }

#ifdef TRACE_MASK
  printf("at pop:\n");
  mask_show(pstack->pframe->pmask);
#endif
  
  return &(pstack->pframe[pstack->iSize--]);
}

MSLPQframe * stack_curr(MSLPQStack *pstack) {
  assert(pstack->iSize > 0);
  return &(pstack->pframe[pstack->iSize - 1]); /* -1 due to 0 based array */
}

MSLPQframe * stack_prev(MSLPQStack *pstack) {
  assert(pstack->iSize > 0);
  if (pstack->iSize == 1) return NULL;
  return &(pstack->pframe[pstack->iSize-2]);   /* -2 is one less than curr */
}

/*
 * stack_delete
 * 
 *   This operation is performed at the end of a query to release the memory
 *   allocated to perform it.
 *
 *     pstack      The stack to be freed.
 *
 * Returns: none
 *
 * Side effect:
 *   All masks, etc. are freed by this operation.
 */
void stack_delete(MSLPQStack *pstack) {
  int i;
  for (i = 0; i < pstack->iSize; i++) {
    if (pstack->pframe[i].pmask)
      mask_delete(pstack->pframe[i].pmask);
  }
  SLPFree((void*)pstack->pframe);
  SLPFree((void*)pstack);
}
