<commit_before>/********************************************************************
* Description: interp_execute.cc
*
*   Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <boost/python.hpp>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"

#define RESULT_OK(x) ((x) == INTERP_OK || (x) == INTERP_EXECUTE_FINISH)

/****************************************************************************/

/*! execute binary

Returned value: int
   If execute_binary1 or execute_binary2 returns an error code, this
   returns that code.
   Otherwise, it returns INTERP_OK.

Side effects: The value of left is set to the result of applying
  the operation to left and right.

Called by: read_real_expression

This just calls either execute_binary1 or execute_binary2.

*/

int Interp::execute_binary(double *left, int operation, double *right)
{
  if (operation < AND2)
    CHP(execute_binary1(left, operation, right));
  else
    CHP(execute_binary2(left, operation, right));
  return INTERP_OK;
}

/****************************************************************************/

/*! execute_binary1

Returned Value: int
   If any of the following errors occur, this returns the error shown.
   Otherwise, it returns INTERP_OK.
   1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION
   2. An attempt is made to divide by zero: NCE_ATTEMPT_TO_DIVIDE_BY_ZERO
   3. An attempt is made to raise a negative number to a non-integer power:
      NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER

Side effects:
   The result from performing the operation is put into what left points at.

Called by: read_real_expression.

This executes the operations: DIVIDED_BY, MODULO, POWER, TIMES.

*/

int Interp::execute_binary1(double *left,        //!< pointer to the left operand
                           int operation,       //!< integer code for the operation
                           double *right)       //!< pointer to the right operand
{
  switch (operation) {
  case DIVIDED_BY:
    CHKS((*right == 0.0), NCE_ATTEMPT_TO_DIVIDE_BY_ZERO);
    *left = (*left / *right);
    break;
  case MODULO:                 /* always calculates a positive answer */
    *left = fmod(*left, *right);
    if (*left < 0.0) {
      *left = (*left + fabs(*right));
    }
    break;
  case POWER:
    CHKS(((*left < 0.0) && (floor(*right) != *right)),
        NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER);
    *left = pow(*left, *right);
    break;
  case TIMES:
    *left = (*left * *right);
    break;
  default:
    ERS(NCE_BUG_UNKNOWN_OPERATION);
  }
  return INTERP_OK;
}

/****************************************************************************/

/*! execute_binary2

Returned Value: int
   If any of the following errors occur, this returns the error code shown.
   Otherwise, it returns INTERP_OK.
   1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION

Side effects:
   The result from performing the operation is put into what left points at.

Called by: read_real_expression.

This executes the operations: AND2, EXCLUSIVE_OR, MINUS,
NON_EXCLUSIVE_OR, PLUS. The RS274/NGC manual [NCMS] does not say what
the calculated value of the three logical operations should be. This
function calculates either 1.0 (meaning true) or 0.0 (meaning false).
Any non-zero input value is taken as meaning true, and only 0.0 means
false.

*/

int Interp::execute_binary2(double *left,        //!< pointer to the left operand
                           int operation,       //!< integer code for the operation
                           double *right)       //!< pointer to the right operand
{
  double diff;
  switch (operation) {
  case AND2:
    *left = ((*left == 0.0) || (*right == 0.0)) ? 0.0 : 1.0;
    break;
  case EXCLUSIVE_OR:
    *left = (((*left == 0.0) && (*right != 0.0))
             || ((*left != 0.0) && (*right == 0.0))) ? 1.0 : 0.0;
    break;
  case MINUS:
    *left = (*left - *right);
    break;
  case NON_EXCLUSIVE_OR:
    *left = ((*left != 0.0) || (*right != 0.0)) ? 1.0 : 0.0;
    break;
  case PLUS:
    *left = (*left + *right);
    break;

  case LT:
      *left = (*left < *right) ? 1.0 : 0.0;
      break;
  case EQ:
      diff = *left - *right;
      diff = (diff < 0) ? -diff : diff;
      *left = (diff < TOLERANCE_EQUAL) ? 1.0 : 0.0;
      break;
  case NE:
      diff = *left - *right;
      diff = (diff < 0) ? -diff : diff;
      *left = (diff >= TOLERANCE_EQUAL) ? 1.0 : 0.0;
      break;
  case LE:
      *left = (*left <= *right) ? 1.0 : 0.0;
      break;
  case GE:
      *left = (*left >= *right) ? 1.0 : 0.0;
      break;
  case GT:
      *left = (*left > *right) ? 1.0 : 0.0;
      break;

  default:
    ERS(NCE_BUG_UNKNOWN_OPERATION);
  }
  return INTERP_OK;
}

/****************************************************************************/

/*! execute_block

Returned Value: int
   If convert_stop returns INTERP_EXIT, this returns INTERP_EXIT.
   If any of the following functions is called and returns an error code,
   this returns that code.
     convert_comment
     convert_feed_mode
     convert_feed_rate
     convert_g
     convert_m
     convert_speed
     convert_stop
     convert_tool_select
   Otherwise, if the probe_flag in the settings is true,
   or the input_flag is set to true this returns
      INTERP_EXECUTE_FINISH.
   Otherwise, it returns INTERP_OK.

Side effects:
   One block of RS274/NGC instructions is executed.

Called by:
   Interp::execute

This converts a block to zero to many actions. The order of execution
of items in a block is critical to safe and effective machine operation,
but is not specified clearly in the RS274/NGC documentation.

Actions are executed in the following order:
1. any comment.
2. a feed mode setting (g93, g94, g95)
3. a feed rate (f) setting if in units_per_minute feed mode.
4. a spindle speed (s) setting.
5. a tool selection (t).
6. "m" commands as described in convert_m (includes tool change).
7. any g_codes (except g93, g94) as described in convert_g.
8. stopping commands (m0, m1, m2, m30, or m60).

In inverse time feed mode, the explicit and implicit g code executions
include feed rate setting with g1, g2, and g3. Also in inverse time
feed mode, attempting a canned cycle cycle (g81 to g89) or setting a
feed rate with g0 is illegal and will be detected and result in an
error message.

*/

int Interp::execute_block(block_pointer block,   //!< pointer to a block of RS274/NGC instructions
			  setup_pointer settings) //!< pointer to machine settings
{
  int status;

  if (settings->remap_level == 0)
  {
      block->line_number = settings->sequence_number;
  } else
  {   // use saved_line_number of toplevel for motion-id
      block->line_number = settings->blocks[settings->remap_level].saved_line_number;
  }

  if ((block->comment[0] != 0) && ONCE(STEP_COMMENT)) {
    status = convert_comment(block->comment);
    CHP(status);
  }
  if ((block->g_modes[GM_SPINDLE_MODE] != -1) && ONCE(STEP_SPINDLE_MODE)) {
      status = convert_spindle_mode(block, settings);
      CHP(status);
  }
  if ((block->g_modes[GM_FEED_MODE] != -1) && ONCE(STEP_FEED_MODE)) {
      status = convert_feed_mode(block->g_modes[GM_FEED_MODE], settings);
      CHP(status);

  }
  if (block->f_flag){
      if ((settings->feed_mode != INVERSE_TIME) && ONCE(STEP_SET_FEED_RATE))  {
	  if (STEP_REMAPPED_IN_BLOCK(block, STEP_SET_FEED_RATE)) {
	      return (convert_remapped_code(block, settings, STEP_SET_FEED_RATE, 'F'));
	  } else {
	      status = convert_feed_rate(block, settings);
	      CHP(status);
	  }
      }
      /* INVERSE_TIME is handled elsewhere */
  }
  if ((block->s_flag) && ONCE(STEP_SET_SPINDLE_SPEED)){
      if (STEP_REMAPPED_IN_BLOCK(block, STEP_SET_SPINDLE_SPEED)) {
	  return (convert_remapped_code(block,settings,STEP_SET_SPINDLE_SPEED,'S'));
      } else {
	  status = convert_speed(block, settings);
	  CHP(status);
      }
  }
  if ((block->t_flag) && ONCE(STEP_PREPARE)) {
      if (STEP_REMAPPED_IN_BLOCK(block, STEP_PREPARE)) {
	  return (convert_remapped_code(block,settings,STEP_PREPARE,'T'));
      } else {
	  CHP(convert_tool_select(block, settings));
      }
  }
  CHP(convert_m(block, settings));
  CHP(convert_g(block, settings));
  if ((block->m_modes[4] != -1) && ONCE(STEP_MGROUP4)) {        /* converts m0, m1, m2, m30, or m60 */
      if (STEP_REMAPPED_IN_BLOCK(block, STEP_MGROUP4)) {
	  status = convert_remapped_code(block,settings,STEP_MGROUP4,'M',block->m_modes[4]);
      } else {
	  status = convert_stop(block, settings);
      }
    if (status == INTERP_EXIT) {
	return(INTERP_EXIT);
    }
    else if (status != INTERP_OK) {
	ERP(status);
    }
  }
  if (settings->probe_flag)
      return (INTERP_EXECUTE_FINISH);

  if (settings->input_flag)
      return (INTERP_EXECUTE_FINISH);

  if (settings->toolchange_flag)
      return (INTERP_EXECUTE_FINISH);

  return INTERP_OK;
}

/****************************************************************************/

/*! execute_unary

Returned Value: int
   If any of the following errors occur, this returns the error code shown.
   Otherwise, it returns INTERP_OK.
   1. the operation is unknown: NCE_BUG_UNKNOWN_OPERATION
   2. the argument to acos is not between minus and plus one:
      NCE_ARGUMENT_TO_ACOS_OUT_RANGE
   3. the argument to asin is not between minus and plus one:
      NCE_ARGUMENT_TO_ASIN_OUT_RANGE
   4. the argument to the natural logarithm is not positive:
      NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN
   5. the argument to square root is negative:
      NCE_NEGATIVE_ARGUMENT_TO_SQRT

Side effects:
   The result from performing the operation on the value in double_ptr
   is put into what double_ptr points at.

Called by: read_unary.

This executes the operations: ABS, ACOS, ASIN, COS, EXP, FIX, FUP, LN
ROUND, SIN, SQRT, TAN

All angle measures in the input or output are in degrees.

*/

int Interp::execute_unary(double *double_ptr,    //!< pointer to the operand
                         int operation) //!< integer code for the operation
{
  switch (operation) {
  case ABS:
    if (*double_ptr < 0.0)
      *double_ptr = (-1.0 * *double_ptr);
    break;
  case ACOS:
    CHKS(((*double_ptr < -1.0) || (*double_ptr > 1.0)),
        NCE_ARGUMENT_TO_ACOS_OUT_OF_RANGE);
    *double_ptr = acos(*double_ptr);
    *double_ptr = ((*double_ptr * 180.0) / M_PIl);
    break;
  case ASIN:
    CHKS(((*double_ptr < -1.0) || (*double_ptr > 1.0)),
        NCE_ARGUMENT_TO_ASIN_OUT_OF_RANGE);
    *double_ptr = asin(*double_ptr);
    *double_ptr = ((*double_ptr * 180.0) / M_PIl);
    break;
  case COS:
    *double_ptr = cos((*double_ptr * M_PIl) / 180.0);
    break;
  case EXISTS:
    // do nothing here
    // result for the EXISTS function is set by Interp:read_unary()
    break;
  case EXP:
    *double_ptr = exp(*double_ptr);
    break;
  case FIX:
    *double_ptr = floor(*double_ptr);
    break;
  case FUP:
    *double_ptr = ceil(*double_ptr);
    break;
  case LN:
    CHKS((*double_ptr <= 0.0), NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN);
    *double_ptr = log(*double_ptr);
    break;
  case ROUND:
    *double_ptr = (double)
      ((int) (*double_ptr + ((*double_ptr < 0.0) ? -0.5 : 0.5)));
    break;
  case SIN:
    *double_ptr = sin((*double_ptr * M_PIl) / 180.0);
    break;
  case SQRT:
    CHKS((*double_ptr < 0.0), NCE_NEGATIVE_ARGUMENT_TO_SQRT);
    *double_ptr = sqrt(*double_ptr);
    break;
  case TAN:
    *double_ptr = tan((*double_ptr * M_PIl) / 180.0);
    break;
  default:
    ERS(NCE_BUG_UNKNOWN_OPERATION);
  }
  return INTERP_OK;
}

<commit_msg>Interp::execute_block(): remove INTERP_EXECUTE_FINISH<commit_after>/********************************************************************
* Description: interp_execute.cc
*
*   Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <boost/python.hpp>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"

/****************************************************************************/

/*! execute binary

Returned value: int
   If execute_binary1 or execute_binary2 returns an error code, this
   returns that code.
   Otherwise, it returns INTERP_OK.

Side effects: The value of left is set to the result of applying
  the operation to left and right.

Called by: read_real_expression

This just calls either execute_binary1 or execute_binary2.

*/

int Interp::execute_binary(double *left, int operation, double *right)
{
  if (operation < AND2)
    CHP(execute_binary1(left, operation, right));
  else
    CHP(execute_binary2(left, operation, right));
  return INTERP_OK;
}

/****************************************************************************/

/*! execute_binary1

Returned Value: int
   If any of the following errors occur, this returns the error shown.
   Otherwise, it returns INTERP_OK.
   1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION
   2. An attempt is made to divide by zero: NCE_ATTEMPT_TO_DIVIDE_BY_ZERO
   3. An attempt is made to raise a negative number to a non-integer power:
      NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER

Side effects:
   The result from performing the operation is put into what left points at.

Called by: read_real_expression.

This executes the operations: DIVIDED_BY, MODULO, POWER, TIMES.

*/

int Interp::execute_binary1(double *left,        //!< pointer to the left operand
                           int operation,       //!< integer code for the operation
                           double *right)       //!< pointer to the right operand
{
  switch (operation) {
  case DIVIDED_BY:
    CHKS((*right == 0.0), NCE_ATTEMPT_TO_DIVIDE_BY_ZERO);
    *left = (*left / *right);
    break;
  case MODULO:                 /* always calculates a positive answer */
    *left = fmod(*left, *right);
    if (*left < 0.0) {
      *left = (*left + fabs(*right));
    }
    break;
  case POWER:
    CHKS(((*left < 0.0) && (floor(*right) != *right)),
        NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER);
    *left = pow(*left, *right);
    break;
  case TIMES:
    *left = (*left * *right);
    break;
  default:
    ERS(NCE_BUG_UNKNOWN_OPERATION);
  }
  return INTERP_OK;
}

/****************************************************************************/

/*! execute_binary2

Returned Value: int
   If any of the following errors occur, this returns the error code shown.
   Otherwise, it returns INTERP_OK.
   1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION

Side effects:
   The result from performing the operation is put into what left points at.

Called by: read_real_expression.

This executes the operations: AND2, EXCLUSIVE_OR, MINUS,
NON_EXCLUSIVE_OR, PLUS. The RS274/NGC manual [NCMS] does not say what
the calculated value of the three logical operations should be. This
function calculates either 1.0 (meaning true) or 0.0 (meaning false).
Any non-zero input value is taken as meaning true, and only 0.0 means
false.

*/

int Interp::execute_binary2(double *left,        //!< pointer to the left operand
                           int operation,       //!< integer code for the operation
                           double *right)       //!< pointer to the right operand
{
  double diff;
  switch (operation) {
  case AND2:
    *left = ((*left == 0.0) || (*right == 0.0)) ? 0.0 : 1.0;
    break;
  case EXCLUSIVE_OR:
    *left = (((*left == 0.0) && (*right != 0.0))
             || ((*left != 0.0) && (*right == 0.0))) ? 1.0 : 0.0;
    break;
  case MINUS:
    *left = (*left - *right);
    break;
  case NON_EXCLUSIVE_OR:
    *left = ((*left != 0.0) || (*right != 0.0)) ? 1.0 : 0.0;
    break;
  case PLUS:
    *left = (*left + *right);
    break;

  case LT:
      *left = (*left < *right) ? 1.0 : 0.0;
      break;
  case EQ:
      diff = *left - *right;
      diff = (diff < 0) ? -diff : diff;
      *left = (diff < TOLERANCE_EQUAL) ? 1.0 : 0.0;
      break;
  case NE:
      diff = *left - *right;
      diff = (diff < 0) ? -diff : diff;
      *left = (diff >= TOLERANCE_EQUAL) ? 1.0 : 0.0;
      break;
  case LE:
      *left = (*left <= *right) ? 1.0 : 0.0;
      break;
  case GE:
      *left = (*left >= *right) ? 1.0 : 0.0;
      break;
  case GT:
      *left = (*left > *right) ? 1.0 : 0.0;
      break;

  default:
    ERS(NCE_BUG_UNKNOWN_OPERATION);
  }
  return INTERP_OK;
}

/****************************************************************************/

/*! execute_block

Returned Value: int
   If convert_stop returns INTERP_EXIT, this returns INTERP_EXIT.
   If any of the following functions is called and returns an error code,
   this returns that code.
     convert_comment
     convert_feed_mode
     convert_feed_rate
     convert_g
     convert_m
     convert_speed
     convert_stop
     convert_tool_select
   Otherwise, it returns INTERP_OK.

Side effects:
   One block of RS274/NGC instructions is executed.

Called by:
   Interp::execute

This converts a block to zero to many actions. The order of execution
of items in a block is critical to safe and effective machine operation,
but is not specified clearly in the RS274/NGC documentation.

Actions are executed in the following order:
1. any comment.
2. a feed mode setting (g93, g94, g95)
3. a feed rate (f) setting if in units_per_minute feed mode.
4. a spindle speed (s) setting.
5. a tool selection (t).
6. "m" commands as described in convert_m (includes tool change).
7. any g_codes (except g93, g94) as described in convert_g.
8. stopping commands (m0, m1, m2, m30, or m60).

In inverse time feed mode, the explicit and implicit g code executions
include feed rate setting with g1, g2, and g3. Also in inverse time
feed mode, attempting a canned cycle cycle (g81 to g89) or setting a
feed rate with g0 is illegal and will be detected and result in an
error message.

*/

int Interp::execute_block(block_pointer block,   //!< pointer to a block of RS274/NGC instructions
			  setup_pointer settings) //!< pointer to machine settings
{
  int status;

  if (settings->remap_level == 0)
  {
      block->line_number = settings->sequence_number;
  } else
  {   // use saved_line_number of toplevel for motion-id
      block->line_number = settings->blocks[settings->remap_level].saved_line_number;
  }

  if ((block->comment[0] != 0) && ONCE(STEP_COMMENT)) {
    status = convert_comment(block->comment);
    CHP(status);
  }
  if ((block->g_modes[GM_SPINDLE_MODE] != -1) && ONCE(STEP_SPINDLE_MODE)) {
      status = convert_spindle_mode(block, settings);
      CHP(status);
  }
  if ((block->g_modes[GM_FEED_MODE] != -1) && ONCE(STEP_FEED_MODE)) {
      status = convert_feed_mode(block->g_modes[GM_FEED_MODE], settings);
      CHP(status);

  }
  if (block->f_flag){
      if ((settings->feed_mode != INVERSE_TIME) && ONCE(STEP_SET_FEED_RATE))  {
	  if (STEP_REMAPPED_IN_BLOCK(block, STEP_SET_FEED_RATE)) {
	      return (convert_remapped_code(block, settings, STEP_SET_FEED_RATE, 'F'));
	  } else {
	      status = convert_feed_rate(block, settings);
	      CHP(status);
	  }
      }
      /* INVERSE_TIME is handled elsewhere */
  }
  if ((block->s_flag) && ONCE(STEP_SET_SPINDLE_SPEED)){
      if (STEP_REMAPPED_IN_BLOCK(block, STEP_SET_SPINDLE_SPEED)) {
	  return (convert_remapped_code(block,settings,STEP_SET_SPINDLE_SPEED,'S'));
      } else {
	  status = convert_speed(block, settings);
	  CHP(status);
      }
  }
  if ((block->t_flag) && ONCE(STEP_PREPARE)) {
      if (STEP_REMAPPED_IN_BLOCK(block, STEP_PREPARE)) {
	  return (convert_remapped_code(block,settings,STEP_PREPARE,'T'));
      } else {
	  CHP(convert_tool_select(block, settings));
      }
  }
  CHP(convert_m(block, settings));
  CHP(convert_g(block, settings));
  if ((block->m_modes[4] != -1) && ONCE(STEP_MGROUP4)) {        /* converts m0, m1, m2, m30, or m60 */
      if (STEP_REMAPPED_IN_BLOCK(block, STEP_MGROUP4)) {
	  status = convert_remapped_code(block,settings,STEP_MGROUP4,'M',block->m_modes[4]);
      } else {
	  status = convert_stop(block, settings);
      }
    if (status == INTERP_EXIT) {
	return(INTERP_EXIT);
    }
    else if (status != INTERP_OK) {
	ERP(status);
    }
  }

  return INTERP_OK;
}

/****************************************************************************/

/*! execute_unary

Returned Value: int
   If any of the following errors occur, this returns the error code shown.
   Otherwise, it returns INTERP_OK.
   1. the operation is unknown: NCE_BUG_UNKNOWN_OPERATION
   2. the argument to acos is not between minus and plus one:
      NCE_ARGUMENT_TO_ACOS_OUT_RANGE
   3. the argument to asin is not between minus and plus one:
      NCE_ARGUMENT_TO_ASIN_OUT_RANGE
   4. the argument to the natural logarithm is not positive:
      NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN
   5. the argument to square root is negative:
      NCE_NEGATIVE_ARGUMENT_TO_SQRT

Side effects:
   The result from performing the operation on the value in double_ptr
   is put into what double_ptr points at.

Called by: read_unary.

This executes the operations: ABS, ACOS, ASIN, COS, EXP, FIX, FUP, LN
ROUND, SIN, SQRT, TAN

All angle measures in the input or output are in degrees.

*/

int Interp::execute_unary(double *double_ptr,    //!< pointer to the operand
                         int operation) //!< integer code for the operation
{
  switch (operation) {
  case ABS:
    if (*double_ptr < 0.0)
      *double_ptr = (-1.0 * *double_ptr);
    break;
  case ACOS:
    CHKS(((*double_ptr < -1.0) || (*double_ptr > 1.0)),
        NCE_ARGUMENT_TO_ACOS_OUT_OF_RANGE);
    *double_ptr = acos(*double_ptr);
    *double_ptr = ((*double_ptr * 180.0) / M_PIl);
    break;
  case ASIN:
    CHKS(((*double_ptr < -1.0) || (*double_ptr > 1.0)),
        NCE_ARGUMENT_TO_ASIN_OUT_OF_RANGE);
    *double_ptr = asin(*double_ptr);
    *double_ptr = ((*double_ptr * 180.0) / M_PIl);
    break;
  case COS:
    *double_ptr = cos((*double_ptr * M_PIl) / 180.0);
    break;
  case EXISTS:
    // do nothing here
    // result for the EXISTS function is set by Interp:read_unary()
    break;
  case EXP:
    *double_ptr = exp(*double_ptr);
    break;
  case FIX:
    *double_ptr = floor(*double_ptr);
    break;
  case FUP:
    *double_ptr = ceil(*double_ptr);
    break;
  case LN:
    CHKS((*double_ptr <= 0.0), NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN);
    *double_ptr = log(*double_ptr);
    break;
  case ROUND:
    *double_ptr = (double)
      ((int) (*double_ptr + ((*double_ptr < 0.0) ? -0.5 : 0.5)));
    break;
  case SIN:
    *double_ptr = sin((*double_ptr * M_PIl) / 180.0);
    break;
  case SQRT:
    CHKS((*double_ptr < 0.0), NCE_NEGATIVE_ARGUMENT_TO_SQRT);
    *double_ptr = sqrt(*double_ptr);
    break;
  case TAN:
    *double_ptr = tan((*double_ptr * M_PIl) / 180.0);
    break;
  default:
    ERS(NCE_BUG_UNKNOWN_OPERATION);
  }
  return INTERP_OK;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: listenernotification.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2004-11-26 21:08:50 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX
#include <comphelper/listenernotification.hxx>
#endif

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
/** === end UNO includes === **/

//........................................................................
namespace comphelper
{
//........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;

    //====================================================================
    //= OListenerContainer
    //====================================================================
    //--------------------------------------------------------------------
    OListenerContainer::OListenerContainer( ::osl::Mutex& _rMutex )
        :m_aListeners( _rMutex )
    {
    }

    //--------------------------------------------------------------------
    void OListenerContainer::addListener( const Reference< XEventListener >& _rxListener )
    {
        OSL_PRECOND( _rxListener.is(), "OListenerContainer::addListener: a NULL listener?!" );
        if ( _rxListener.is() )
            m_aListeners.addInterface( _rxListener );
    }

    //--------------------------------------------------------------------
    void OListenerContainer::removeListener( const Reference< XEventListener >& _rxListener )
    {
#if OSL_DEBUG_LEVEL > 0
        ::cppu::OInterfaceIteratorHelper aIter( m_aListeners );
        bool bFound = false;
        while ( aIter.hasMoreElements() && !bFound )
        {
            bFound = ( Reference< XInterface >( aIter.next() ) == _rxListener );
        }
        OSL_ENSURE( bFound, "OListenerContainer::removeListener: sure your listener handling is correct? The given listener is not registered!" );
#endif
        m_aListeners.removeInterface( _rxListener );
    }

    //--------------------------------------------------------------------
    void OListenerContainer::disposing( const EventObject& _rEventSource )
    {
        m_aListeners.disposeAndClear( _rEventSource );
    }

    //--------------------------------------------------------------------
    bool OListenerContainer::notify( const EventObject& _rEvent ) SAL_THROW(( Exception ))
    {
        ::cppu::OInterfaceIteratorHelper aIter( m_aListeners );
        bool bCancelled = false;
        while ( aIter.hasMoreElements() && !bCancelled )
        {
            Reference< XEventListener > xListener( static_cast< XEventListener* >( aIter.next() ) );
            if ( !xListener.is() )
                continue;

            try
            {
                bCancelled = !implNotify( xListener, _rEvent );
            }
            catch( const DisposedException& e )
            {
                // DisposedExceptions from the listener might indicate a
                // broken connection to a different environment.

                OSL_ENSURE( e.Context.is(), "OListenerContainer::notify: caught dispose exception with empty Context field" );

                // If the exception stems from the listener then remove it
                // from the list of listeners.  If the Context field of the
                // exception is empty this is interpreted to indicate the
                // listener as well.
                if ( e.Context == xListener || !e.Context.is() )
                    aIter.remove();
            }
        }

        return !bCancelled;
    }

//........................................................................
}   // namespace comphelper
//........................................................................

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.84); FILE MERGED 2005/09/05 15:24:01 rt 1.4.84.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: listenernotification.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 02:50:23 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX
#include <comphelper/listenernotification.hxx>
#endif

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
/** === end UNO includes === **/

//........................................................................
namespace comphelper
{
//........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;

    //====================================================================
    //= OListenerContainer
    //====================================================================
    //--------------------------------------------------------------------
    OListenerContainer::OListenerContainer( ::osl::Mutex& _rMutex )
        :m_aListeners( _rMutex )
    {
    }

    //--------------------------------------------------------------------
    void OListenerContainer::addListener( const Reference< XEventListener >& _rxListener )
    {
        OSL_PRECOND( _rxListener.is(), "OListenerContainer::addListener: a NULL listener?!" );
        if ( _rxListener.is() )
            m_aListeners.addInterface( _rxListener );
    }

    //--------------------------------------------------------------------
    void OListenerContainer::removeListener( const Reference< XEventListener >& _rxListener )
    {
#if OSL_DEBUG_LEVEL > 0
        ::cppu::OInterfaceIteratorHelper aIter( m_aListeners );
        bool bFound = false;
        while ( aIter.hasMoreElements() && !bFound )
        {
            bFound = ( Reference< XInterface >( aIter.next() ) == _rxListener );
        }
        OSL_ENSURE( bFound, "OListenerContainer::removeListener: sure your listener handling is correct? The given listener is not registered!" );
#endif
        m_aListeners.removeInterface( _rxListener );
    }

    //--------------------------------------------------------------------
    void OListenerContainer::disposing( const EventObject& _rEventSource )
    {
        m_aListeners.disposeAndClear( _rEventSource );
    }

    //--------------------------------------------------------------------
    bool OListenerContainer::notify( const EventObject& _rEvent ) SAL_THROW(( Exception ))
    {
        ::cppu::OInterfaceIteratorHelper aIter( m_aListeners );
        bool bCancelled = false;
        while ( aIter.hasMoreElements() && !bCancelled )
        {
            Reference< XEventListener > xListener( static_cast< XEventListener* >( aIter.next() ) );
            if ( !xListener.is() )
                continue;

            try
            {
                bCancelled = !implNotify( xListener, _rEvent );
            }
            catch( const DisposedException& e )
            {
                // DisposedExceptions from the listener might indicate a
                // broken connection to a different environment.

                OSL_ENSURE( e.Context.is(), "OListenerContainer::notify: caught dispose exception with empty Context field" );

                // If the exception stems from the listener then remove it
                // from the list of listeners.  If the Context field of the
                // exception is empty this is interpreted to indicate the
                // listener as well.
                if ( e.Context == xListener || !e.Context.is() )
                    aIter.remove();
            }
        }

        return !bCancelled;
    }

//........................................................................
}   // namespace comphelper
//........................................................................

<|endoftext|>


<commit_before>// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Unit tests for FileID

#include <elf.h>
#include <stdlib.h>

#include "common/linux/file_id.h"
#include "breakpad_googletest_includes.h"

using namespace google_breakpad;

namespace {
typedef testing::Test FileIDTest;
}

TEST(FileIDTest, FileIDStrip) {
  // Calculate the File ID of our binary using
  // FileID::ElfFileIdentifier, then make a copy of our binary,
  // strip it, and ensure that we still get the same result.
  char exe_name[PATH_MAX];
  ssize_t len = readlink("/proc/self/exe", exe_name, PATH_MAX - 1);
  ASSERT_NE(len, -1);
  exe_name[len] = '\0';

  // copy our binary to a temp file, and strip it
  char templ[] = "/tmp/file-id-unittest-XXXXXX";
  mktemp(templ);
  char cmdline[4096];
  sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ);
  ASSERT_EQ(system(cmdline), 0);
  sprintf(cmdline, "strip \"%s\"", templ);
  ASSERT_EQ(system(cmdline), 0);

  uint8_t identifier1[sizeof(MDGUID)];
  uint8_t identifier2[sizeof(MDGUID)];
  FileID fileid1(exe_name);
  EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1));
  FileID fileid2(templ);
  EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2));
  char identifier_string1[37];
  char identifier_string2[37];
  FileID::ConvertIdentifierToString(identifier1, identifier_string1,
                                    37);
  FileID::ConvertIdentifierToString(identifier2, identifier_string2,
                                    37);
  EXPECT_STREQ(identifier_string1, identifier_string2);
  unlink(templ);
}

struct ElfClass32 {
  typedef Elf32_Ehdr Ehdr;
  typedef Elf32_Shdr Shdr;
  static const int kClass = ELFCLASS32;
};

struct ElfClass64 {
  typedef Elf64_Ehdr Ehdr;
  typedef Elf64_Shdr Shdr;
  static const int kClass = ELFCLASS64;
};

template<typename ElfClass>
struct ElfishElf {
  typedef typename ElfClass::Ehdr Ehdr;
  typedef typename ElfClass::Shdr Shdr;

  Ehdr elf_header;
  Shdr text_header;
  Shdr string_header;
  char text_section[128];
  char string_section[8];

  static void Populate(ElfishElf* elf) {
    memset(elf, 0, sizeof(ElfishElf));
    memcpy(elf, ELFMAG, SELFMAG);
    elf->elf_header.e_ident[EI_CLASS] = ElfClass::kClass;
    elf->elf_header.e_shoff = offsetof(ElfishElf, text_header);
    elf->elf_header.e_shnum = 2;
    elf->elf_header.e_shstrndx = 1;
    elf->text_header.sh_name = 0;
    elf->text_header.sh_type = SHT_PROGBITS;
    elf->text_header.sh_offset = offsetof(ElfishElf, text_section);
    elf->text_header.sh_size = sizeof(text_section);
    for (size_t i = 0; i < sizeof(text_section); ++i) {
      elf->text_section[i] = i * 3;
    }
    elf->string_header.sh_offset = offsetof(ElfishElf, string_section);
    strcpy(elf->string_section, ".text");
  }
};

TEST(FileIDTest, ElfClass) {
  uint8_t identifier[sizeof(MDGUID)];
  const char expected_identifier_string[] =
      "80808080-8080-0000-0000-008080808080";
  char identifier_string[sizeof(expected_identifier_string)];

  ElfishElf<ElfClass32> elf32;
  ElfishElf<ElfClass32>::Populate(&elf32);
  EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(&elf32, identifier));
  FileID::ConvertIdentifierToString(identifier, identifier_string,
                                    sizeof(identifier_string));
  EXPECT_STREQ(expected_identifier_string, identifier_string);

  memset(identifier, 0, sizeof(identifier));
  memset(identifier_string, 0, sizeof(identifier_string));

  ElfishElf<ElfClass64> elf64;
  ElfishElf<ElfClass64>::Populate(&elf64);
  EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(&elf64, identifier));
  FileID::ConvertIdentifierToString(identifier, identifier_string,
                                    sizeof(identifier_string));
  EXPECT_STREQ(expected_identifier_string, identifier_string);
}
<commit_msg>Fix compilation of file_id_unittest. Review URL: http://breakpad.appspot.com/198001<commit_after>// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Unit tests for FileID

#include <elf.h>
#include <stdlib.h>

#include "common/linux/file_id.h"
#include "breakpad_googletest_includes.h"

using namespace google_breakpad;

namespace {
typedef testing::Test FileIDTest;
}

TEST(FileIDTest, FileIDStrip) {
  // Calculate the File ID of our binary using
  // FileID::ElfFileIdentifier, then make a copy of our binary,
  // strip it, and ensure that we still get the same result.
  char exe_name[PATH_MAX];
  ssize_t len = readlink("/proc/self/exe", exe_name, PATH_MAX - 1);
  ASSERT_NE(len, -1);
  exe_name[len] = '\0';

  // copy our binary to a temp file, and strip it
  char templ[] = "/tmp/file-id-unittest-XXXXXX";
  mktemp(templ);
  char cmdline[4096];
  sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ);
  ASSERT_EQ(system(cmdline), 0);
  sprintf(cmdline, "strip \"%s\"", templ);
  ASSERT_EQ(system(cmdline), 0);

  uint8_t identifier1[sizeof(MDGUID)];
  uint8_t identifier2[sizeof(MDGUID)];
  FileID fileid1(exe_name);
  EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1));
  FileID fileid2(templ);
  EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2));
  char identifier_string1[37];
  char identifier_string2[37];
  FileID::ConvertIdentifierToString(identifier1, identifier_string1,
                                    37);
  FileID::ConvertIdentifierToString(identifier2, identifier_string2,
                                    37);
  EXPECT_STREQ(identifier_string1, identifier_string2);
  unlink(templ);
}

struct ElfClass32 {
  typedef Elf32_Ehdr Ehdr;
  typedef Elf32_Shdr Shdr;
  static const int kClass = ELFCLASS32;
};

struct ElfClass64 {
  typedef Elf64_Ehdr Ehdr;
  typedef Elf64_Shdr Shdr;
  static const int kClass = ELFCLASS64;
};

template<typename ElfClass>
struct ElfishElf {
  static const size_t kTextSectionSize = 128;
  typedef typename ElfClass::Ehdr Ehdr;
  typedef typename ElfClass::Shdr Shdr;

  Ehdr elf_header;
  Shdr text_header;
  Shdr string_header;
  char text_section[kTextSectionSize];
  char string_section[8];

  static void Populate(ElfishElf* elf) {
    memset(elf, 0, sizeof(ElfishElf));
    memcpy(elf, ELFMAG, SELFMAG);
    elf->elf_header.e_ident[EI_CLASS] = ElfClass::kClass;
    elf->elf_header.e_shoff = offsetof(ElfishElf, text_header);
    elf->elf_header.e_shnum = 2;
    elf->elf_header.e_shstrndx = 1;
    elf->text_header.sh_name = 0;
    elf->text_header.sh_type = SHT_PROGBITS;
    elf->text_header.sh_offset = offsetof(ElfishElf, text_section);
    elf->text_header.sh_size = kTextSectionSize;
    for (size_t i = 0; i < kTextSectionSize; ++i) {
      elf->text_section[i] = i * 3;
    }
    elf->string_header.sh_offset = offsetof(ElfishElf, string_section);
    strcpy(elf->string_section, ".text");
  }
};

TEST(FileIDTest, ElfClass) {
  uint8_t identifier[sizeof(MDGUID)];
  const char expected_identifier_string[] =
      "80808080-8080-0000-0000-008080808080";
  char identifier_string[sizeof(expected_identifier_string)];

  ElfishElf<ElfClass32> elf32;
  ElfishElf<ElfClass32>::Populate(&elf32);
  EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(&elf32, identifier));
  FileID::ConvertIdentifierToString(identifier, identifier_string,
                                    sizeof(identifier_string));
  EXPECT_STREQ(expected_identifier_string, identifier_string);

  memset(identifier, 0, sizeof(identifier));
  memset(identifier_string, 0, sizeof(identifier_string));

  ElfishElf<ElfClass64> elf64;
  ElfishElf<ElfClass64>::Populate(&elf64);
  EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(&elf64, identifier));
  FileID::ConvertIdentifierToString(identifier, identifier_string,
                                    sizeof(identifier_string));
  EXPECT_STREQ(expected_identifier_string, identifier_string);
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2015 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <algorithm>

#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"

#include "xenia/ui/vulkan/circular_buffer.h"

namespace xe {
namespace ui {
namespace vulkan {

CircularBuffer::CircularBuffer(VulkanDevice* device, VkBufferUsageFlags usage,
                               VkDeviceSize capacity, VkDeviceSize alignment)
    : device_(device), capacity_(capacity) {
  VkResult status = VK_SUCCESS;

  // Create our internal buffer.
  VkBufferCreateInfo buffer_info;
  buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  buffer_info.pNext = nullptr;
  buffer_info.flags = 0;
  buffer_info.size = capacity;
  buffer_info.usage = usage;
  buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  buffer_info.queueFamilyIndexCount = 0;
  buffer_info.pQueueFamilyIndices = nullptr;
  status = vkCreateBuffer(*device_, &buffer_info, nullptr, &gpu_buffer_);
  CheckResult(status, "vkCreateBuffer");
  if (status != VK_SUCCESS) {
    assert_always();
  }

  VkMemoryRequirements reqs;
  vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);
  alignment_ = reqs.alignment;
}
CircularBuffer::~CircularBuffer() { Shutdown(); }

VkResult CircularBuffer::Initialize(VkDeviceMemory memory,
                                    VkDeviceSize offset) {
  assert_true(offset % alignment_ == 0);
  gpu_memory_ = memory;
  gpu_base_ = offset;

  VkResult status = VK_SUCCESS;

  // Bind the buffer to its backing memory.
  status = vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
  CheckResult(status, "vkBindBufferMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to bind memory!");
    Shutdown();
    return status;
  }

  // Map the memory so we can access it.
  status = vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
                       reinterpret_cast<void**>(&host_base_));
  CheckResult(status, "vkMapMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to map memory!");
    Shutdown();
    return status;
  }

  return VK_SUCCESS;
}

VkResult CircularBuffer::Initialize() {
  VkResult status = VK_SUCCESS;

  VkMemoryRequirements reqs;
  vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);

  // Allocate memory from the device to back the buffer.
  owns_gpu_memory_ = true;
  gpu_memory_ = device_->AllocateMemory(reqs);
  if (!gpu_memory_) {
    XELOGE("CircularBuffer::Initialize - Failed to allocate memory!");
    Shutdown();
    return VK_ERROR_INITIALIZATION_FAILED;
  }

  capacity_ = reqs.size;
  gpu_base_ = 0;

  // Bind the buffer to its backing memory.
  status = vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
  CheckResult(status, "vkBindBufferMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to bind memory!");
    Shutdown();
    return status;
  }

  // Map the memory so we can access it.
  status = vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
                       reinterpret_cast<void**>(&host_base_));
  CheckResult(status, "vkMapMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to map memory!");
    Shutdown();
    return status;
  }

  return VK_SUCCESS;
}

void CircularBuffer::Shutdown() {
  Clear();
  if (host_base_) {
    vkUnmapMemory(*device_, gpu_memory_);
    host_base_ = nullptr;
  }
  if (gpu_buffer_) {
    vkDestroyBuffer(*device_, gpu_buffer_, nullptr);
    gpu_buffer_ = nullptr;
  }
  if (gpu_memory_ && owns_gpu_memory_) {
    vkFreeMemory(*device_, gpu_memory_, nullptr);
    gpu_memory_ = nullptr;
  }
}

void CircularBuffer::GetBufferMemoryRequirements(VkMemoryRequirements* reqs) {
  vkGetBufferMemoryRequirements(*device_, gpu_buffer_, reqs);
}

bool CircularBuffer::CanAcquire(VkDeviceSize length) {
  // Make sure the length is aligned.
  length = xe::round_up(length, alignment_);
  if (allocations_.empty()) {
    // Read head has caught up to write head (entire buffer available for write)
    assert_true(read_head_ == write_head_);
    return capacity_ >= length;
  } else if (write_head_ < read_head_) {
    // Write head wrapped around and is behind read head.
    // |  write  |---- read ----|
    return (read_head_ - write_head_) >= length;
  } else if (write_head_ > read_head_) {
    // Read head behind write head.
    // 1. Check if there's enough room from write -> capacity
    // |  |---- read ----|    write     |
    if ((capacity_ - write_head_) >= length) {
      return true;
    }

    // 2. Check if there's enough room from 0 -> read
    // |    write     |---- read ----|  |
    if ((read_head_ - 0) >= length) {
      return true;
    }
  }

  return false;
}

CircularBuffer::Allocation* CircularBuffer::Acquire(VkDeviceSize length,
                                                    VkFence fence) {
  VkDeviceSize aligned_length = xe::round_up(length, alignment_);
  if (!CanAcquire(aligned_length)) {
    return nullptr;
  }

  assert_true(write_head_ % alignment_ == 0);
  if (write_head_ < read_head_) {
    // Write head behind read head.
    assert_true(read_head_ - write_head_ >= aligned_length);

    auto alloc = new Allocation();
    alloc->host_ptr = host_base_ + write_head_;
    alloc->gpu_memory = gpu_memory_;
    alloc->offset = gpu_base_ + write_head_;
    alloc->length = length;
    alloc->aligned_length = aligned_length;
    alloc->fence = fence;
    write_head_ += aligned_length;
    allocations_.push_back(alloc);

    return alloc;
  } else {
    // Write head equal to/after read head
    if (capacity_ - write_head_ >= aligned_length) {
      // Free space from write -> capacity
      auto alloc = new Allocation();
      alloc->host_ptr = host_base_ + write_head_;
      alloc->gpu_memory = gpu_memory_;
      alloc->offset = gpu_base_ + write_head_;
      alloc->length = length;
      alloc->aligned_length = aligned_length;
      alloc->fence = fence;
      write_head_ += aligned_length;
      allocations_.push_back(alloc);

      return alloc;
    } else if ((read_head_ - 0) >= aligned_length) {
      // Not enough space from write -> capacity, but there is enough free space
      // from begin -> read
      auto alloc = new Allocation();
      alloc->host_ptr = host_base_ + 0;
      alloc->gpu_memory = gpu_memory_;
      alloc->offset = gpu_base_ + 0;
      alloc->length = length;
      alloc->aligned_length = aligned_length;
      alloc->fence = fence;
      write_head_ = aligned_length;
      allocations_.push_back(alloc);

      return alloc;
    }
  }

  return nullptr;
}

void CircularBuffer::Flush(Allocation* allocation) {
  VkMappedMemoryRange range;
  range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
  range.pNext = nullptr;
  range.memory = gpu_memory_;
  range.offset = gpu_base_ + allocation->offset;
  range.size = allocation->length;
  vkFlushMappedMemoryRanges(*device_, 1, &range);
}

void CircularBuffer::Flush(VkDeviceSize offset, VkDeviceSize length) {
  VkMappedMemoryRange range;
  range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
  range.pNext = nullptr;
  range.memory = gpu_memory_;
  range.offset = gpu_base_ + offset;
  range.size = length;
  vkFlushMappedMemoryRanges(*device_, 1, &range);
}

void CircularBuffer::Clear() {
  for (auto alloc : allocations_) {
    delete alloc;
  }
  allocations_.clear();

  write_head_ = read_head_ = 0;
}

void CircularBuffer::Scavenge() {
  for (auto it = allocations_.begin(); it != allocations_.end();) {
    if (vkGetFenceStatus(*device_, (*it)->fence) != VK_SUCCESS) {
      // Don't bother freeing following allocations to ensure proper ordering.
      break;
    }

    if (capacity_ - read_head_ < (*it)->aligned_length) {
      // This allocation is stored at the beginning of the buffer.
      read_head_ = (*it)->aligned_length;
    } else {
      read_head_ += (*it)->aligned_length;
    }

    delete *it;
    it = allocations_.erase(it);
  }

  if (allocations_.empty()) {
    // Reset R/W heads to work around fragmentation issues.
    read_head_ = write_head_ = 0;
  }
}

}  // namespace vulkan
}  // namespace ui
}  // namespace xe<commit_msg>[Vulkan UI] CircularBuffer: Actually use provided alignment<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2015 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <algorithm>

#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"

#include "xenia/ui/vulkan/circular_buffer.h"

namespace xe {
namespace ui {
namespace vulkan {

CircularBuffer::CircularBuffer(VulkanDevice* device, VkBufferUsageFlags usage,
                               VkDeviceSize capacity, VkDeviceSize alignment)
    : device_(device), capacity_(capacity) {
  VkResult status = VK_SUCCESS;

  // Create our internal buffer.
  VkBufferCreateInfo buffer_info;
  buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  buffer_info.pNext = nullptr;
  buffer_info.flags = 0;
  buffer_info.size = capacity;
  buffer_info.usage = usage;
  buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  buffer_info.queueFamilyIndexCount = 0;
  buffer_info.pQueueFamilyIndices = nullptr;
  status = vkCreateBuffer(*device_, &buffer_info, nullptr, &gpu_buffer_);
  CheckResult(status, "vkCreateBuffer");
  if (status != VK_SUCCESS) {
    assert_always();
  }

  VkMemoryRequirements reqs;
  vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);
  alignment_ = xe::round_up(alignment, reqs.alignment);
}
CircularBuffer::~CircularBuffer() { Shutdown(); }

VkResult CircularBuffer::Initialize(VkDeviceMemory memory,
                                    VkDeviceSize offset) {
  assert_true(offset % alignment_ == 0);
  gpu_memory_ = memory;
  gpu_base_ = offset;

  VkResult status = VK_SUCCESS;

  // Bind the buffer to its backing memory.
  status = vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
  CheckResult(status, "vkBindBufferMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to bind memory!");
    Shutdown();
    return status;
  }

  // Map the memory so we can access it.
  status = vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
                       reinterpret_cast<void**>(&host_base_));
  CheckResult(status, "vkMapMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to map memory!");
    Shutdown();
    return status;
  }

  return VK_SUCCESS;
}

VkResult CircularBuffer::Initialize() {
  VkResult status = VK_SUCCESS;

  VkMemoryRequirements reqs;
  vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);

  // Allocate memory from the device to back the buffer.
  owns_gpu_memory_ = true;
  gpu_memory_ = device_->AllocateMemory(reqs);
  if (!gpu_memory_) {
    XELOGE("CircularBuffer::Initialize - Failed to allocate memory!");
    Shutdown();
    return VK_ERROR_INITIALIZATION_FAILED;
  }

  capacity_ = reqs.size;
  gpu_base_ = 0;

  // Bind the buffer to its backing memory.
  status = vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
  CheckResult(status, "vkBindBufferMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to bind memory!");
    Shutdown();
    return status;
  }

  // Map the memory so we can access it.
  status = vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
                       reinterpret_cast<void**>(&host_base_));
  CheckResult(status, "vkMapMemory");
  if (status != VK_SUCCESS) {
    XELOGE("CircularBuffer::Initialize - Failed to map memory!");
    Shutdown();
    return status;
  }

  return VK_SUCCESS;
}

void CircularBuffer::Shutdown() {
  Clear();
  if (host_base_) {
    vkUnmapMemory(*device_, gpu_memory_);
    host_base_ = nullptr;
  }
  if (gpu_buffer_) {
    vkDestroyBuffer(*device_, gpu_buffer_, nullptr);
    gpu_buffer_ = nullptr;
  }
  if (gpu_memory_ && owns_gpu_memory_) {
    vkFreeMemory(*device_, gpu_memory_, nullptr);
    gpu_memory_ = nullptr;
  }
}

void CircularBuffer::GetBufferMemoryRequirements(VkMemoryRequirements* reqs) {
  vkGetBufferMemoryRequirements(*device_, gpu_buffer_, reqs);
}

bool CircularBuffer::CanAcquire(VkDeviceSize length) {
  // Make sure the length is aligned.
  length = xe::round_up(length, alignment_);
  if (allocations_.empty()) {
    // Read head has caught up to write head (entire buffer available for write)
    assert_true(read_head_ == write_head_);
    return capacity_ >= length;
  } else if (write_head_ < read_head_) {
    // Write head wrapped around and is behind read head.
    // |  write  |---- read ----|
    return (read_head_ - write_head_) >= length;
  } else if (write_head_ > read_head_) {
    // Read head behind write head.
    // 1. Check if there's enough room from write -> capacity
    // |  |---- read ----|    write     |
    if ((capacity_ - write_head_) >= length) {
      return true;
    }

    // 2. Check if there's enough room from 0 -> read
    // |    write     |---- read ----|  |
    if ((read_head_ - 0) >= length) {
      return true;
    }
  }

  return false;
}

CircularBuffer::Allocation* CircularBuffer::Acquire(VkDeviceSize length,
                                                    VkFence fence) {
  VkDeviceSize aligned_length = xe::round_up(length, alignment_);
  if (!CanAcquire(aligned_length)) {
    return nullptr;
  }

  assert_true(write_head_ % alignment_ == 0);
  if (write_head_ < read_head_) {
    // Write head behind read head.
    assert_true(read_head_ - write_head_ >= aligned_length);

    auto alloc = new Allocation();
    alloc->host_ptr = host_base_ + write_head_;
    alloc->gpu_memory = gpu_memory_;
    alloc->offset = gpu_base_ + write_head_;
    alloc->length = length;
    alloc->aligned_length = aligned_length;
    alloc->fence = fence;
    write_head_ += aligned_length;
    allocations_.push_back(alloc);

    return alloc;
  } else {
    // Write head equal to/after read head
    if (capacity_ - write_head_ >= aligned_length) {
      // Free space from write -> capacity
      auto alloc = new Allocation();
      alloc->host_ptr = host_base_ + write_head_;
      alloc->gpu_memory = gpu_memory_;
      alloc->offset = gpu_base_ + write_head_;
      alloc->length = length;
      alloc->aligned_length = aligned_length;
      alloc->fence = fence;
      write_head_ += aligned_length;
      allocations_.push_back(alloc);

      return alloc;
    } else if ((read_head_ - 0) >= aligned_length) {
      // Not enough space from write -> capacity, but there is enough free space
      // from begin -> read
      auto alloc = new Allocation();
      alloc->host_ptr = host_base_ + 0;
      alloc->gpu_memory = gpu_memory_;
      alloc->offset = gpu_base_ + 0;
      alloc->length = length;
      alloc->aligned_length = aligned_length;
      alloc->fence = fence;
      write_head_ = aligned_length;
      allocations_.push_back(alloc);

      return alloc;
    }
  }

  return nullptr;
}

void CircularBuffer::Flush(Allocation* allocation) {
  VkMappedMemoryRange range;
  range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
  range.pNext = nullptr;
  range.memory = gpu_memory_;
  range.offset = gpu_base_ + allocation->offset;
  range.size = allocation->length;
  vkFlushMappedMemoryRanges(*device_, 1, &range);
}

void CircularBuffer::Flush(VkDeviceSize offset, VkDeviceSize length) {
  VkMappedMemoryRange range;
  range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
  range.pNext = nullptr;
  range.memory = gpu_memory_;
  range.offset = gpu_base_ + offset;
  range.size = length;
  vkFlushMappedMemoryRanges(*device_, 1, &range);
}

void CircularBuffer::Clear() {
  for (auto alloc : allocations_) {
    delete alloc;
  }
  allocations_.clear();

  write_head_ = read_head_ = 0;
}

void CircularBuffer::Scavenge() {
  for (auto it = allocations_.begin(); it != allocations_.end();) {
    if (vkGetFenceStatus(*device_, (*it)->fence) != VK_SUCCESS) {
      // Don't bother freeing following allocations to ensure proper ordering.
      break;
    }

    if (capacity_ - read_head_ < (*it)->aligned_length) {
      // This allocation is stored at the beginning of the buffer.
      read_head_ = (*it)->aligned_length;
    } else {
      read_head_ += (*it)->aligned_length;
    }

    delete *it;
    it = allocations_.erase(it);
  }

  if (allocations_.empty()) {
    // Reset R/W heads to work around fragmentation issues.
    read_head_ = write_head_ = 0;
  }
}

}  // namespace vulkan
}  // namespace ui
}  // namespace xe<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

#include "zorbatypes/decimal.h"
#include "zorbatypes/float.h"
#include "zorbatypes/integer.h"
#include "zorbatypes/numconversions.h"

#include "compiler/parser/symbol_table.h"

#include "util/ascii_util.h"
#include "util/xml_util.h"
#include "util/uri_util.h"
#include "util/utf8_util.h"

#include "compiler/parser/xquery_driver.h"

#include <cstdlib>
#include <string>

using namespace std;

namespace zorba {

static bool decode_string(const char *yytext, size_t yyleng, string *result) {
  char delim = yytext [0];
  size_t i;
  for (i = 1; i + 1 < yyleng; i++) {
    char ch = yytext [i];
    if (ch == '&') {
      int d = xml::parse_entity(yytext + i + 1, result);
      if (d < 0) return false;
      i += d;
    } else {
      *result += ch;
      if (ch == delim) ++i;
    }
  }
  return true;
}

symbol_table::symbol_table(size_t initial_heapsize)
  :
  heap(initial_heapsize),
  last_qname(-1)
{
}

symbol_table::~symbol_table()
{
}

size_t symbol_table::size() const
{
  return (size_t)heap.size();
}

// bool attribute == true when an attribute value is normalized
static void normalize_eol(const char *text, size_t length, string *out, bool attribute = false) {
  size_t i;
  out->reserve (length + 1);
  char lastCh = '\0';
  for (i = 0; i < length; i++) {
    char ch = text [i];
    if (ch == '\r')
      *out += attribute ? ' ' : '\n';
    else if (ch != '\n' || lastCh != '\r')
      *out += (attribute && (ch == '\t' || ch == '\n'))? ' ' : ch;

    lastCh = ch;
  }
}

off_t symbol_table::put(char const* text)
{
  return put(text, strlen(text));
}

// normalizationType == 2 is used for normalizing attribute values
off_t symbol_table::put(char const* text, size_t length, int normalizationType)
{
  string normStr;
  if (normalizationType == 1 || normalizationType == 2)
  {
    normalize_eol (text, length, &normStr, normalizationType == 2);
    text = normStr.c_str ();
    length = normStr.size ();
  }

  return heap.put(text, 0, length);
}

off_t symbol_table::put_ncname(char const* text, size_t length)
{
  last_qname = heap.put(text, 0, length);
  return last_qname;
}

off_t symbol_table::put_qname(char const* text, size_t length, bool do_trim_start, bool do_trim_end, bool is_eqname)
{
  if (do_trim_start)
  {
    text = ascii::trim_start_space(text, &length);
  }

  if (do_trim_end)
  {
    length = ascii::trim_end_space(text, length);
  }

  if (!is_eqname)
  {
    last_qname = heap.put(text, 0, length);
  }
  else
  {
    // EQName:  Q{prefix}name
    string name;
    string prefix = text;
    string::size_type pos = prefix.rfind('}');
    name = prefix.substr(pos+1);
    prefix = prefix.substr(1, pos);

    off_t uri = put_uri(prefix.c_str(), prefix.size());
    name = get(uri) + ":" + name;

    last_qname = heap.put(name.c_str(), 0, name.size());
  }

  return last_qname;
}

off_t symbol_table::put_uri(char const* text, size_t length)
{
  // trim whitespace
  text = ascii::trim_space(text, &length);

  // normalize whitespace
  string result;
  if (! decode_string (text, length, &result))
    return -1;
  ascii::normalize_space( result );

  return heap.put (result.c_str (), 0, result.length ());
}

off_t symbol_table::put_varname(char const* text, size_t length)
{
  return heap.put(text, 0, length);
}

off_t symbol_table::put_entityref(char const* text, size_t length)
{
  string result;
  if (xml::parse_entity (text + 1, &result) < 0)
    return -1;
  return heap.put(result.c_str(), 0, result.size ());
}

off_t symbol_table::put_charref(char const* text, size_t length)
{
  return heap.put (text + 1, 0, length - 1);
}

off_t symbol_table::put_stringlit(char const* yytext, size_t yyleng)
{
  string eolNorm;
  normalize_eol (yytext, yyleng, &eolNorm);
  yytext = eolNorm.c_str ();
  yyleng = eolNorm.size ();
  string result;
  if (! decode_string (yytext, yyleng, &result))
    return -1;
  return heap.put (result.c_str (), 0, result.length ());
}

off_t symbol_table::put_json_stringliteral(char const* yytext, size_t yyleng, xquery_driver *driver, const location &loc)
{
  string result;
  unsigned int cp;
  size_t len;
  bool found_escape = false;
  bool found_ampersand = false;

  for (const char* chr = yytext+1; (unsigned int)(chr-yytext)<yyleng-1; chr+=1)
  {
    if (*chr == '\\')
    {
      bool is_escape = true;
      chr += 1;
      switch (*chr)
      {
      case '\\': result += '\\'; break;
      case '/': result += '/'; break;
      case '\"': result += '\"'; break;
      case '\'': result += '\''; break;
      case 'b': result += '\b'; break;
      case 'f': result += '\f'; break;
      case 'n': result += '\n'; break;
      case 'r': result += '\r'; break;
      case 't': result += '\t'; break;
      case 'u':
        cp = 0;
        for (unsigned int i=0; i<4; i++, chr+=1)
          cp = (cp << 4) + uri::hex2dec[(unsigned int)*(chr+1)];
        char tmp[10];
        len = utf8::encode(cp, tmp);
        result.append(tmp, len);
        break;
      default:
        result += *(chr-1);
        result += *chr;
        is_escape = false;
        break;
      }

      if (is_escape)
        found_escape = true;
    }
    else
    {
      if (*chr == '&')
        found_ampersand = true;
      result += *chr;
    }
  } // for

  if (found_escape && driver->commonLanguageEnabled())
    driver->addCommonLanguageWarning(loc, ZED(ZWST0009_JSON_ESCAPE));

  if (found_ampersand && driver->commonLanguageEnabled())
    driver->addCommonLanguageWarning(loc, ZED(ZWST0009_CHAR_REF));

  return heap.put (result.c_str (), 0, result.length ());
}

off_t symbol_table::put_commentcontent(char const* yytext, size_t yyleng)
{
  string eolNorm;
  normalize_eol (yytext, yyleng, &eolNorm);
  yytext = eolNorm.c_str (); yyleng = eolNorm.size ();
  return heap.put (yytext, 0, yyleng);
}

xs_decimal* symbol_table::decimalval(char const* text, size_t length)
{
  return new xs_decimal(text);
}

xs_double* symbol_table::doubleval(char const* text, size_t length)
{
  try {
    return new xs_double(text);
  }
  catch ( std::range_error const& ) {
    return NULL;
  }
}

xs_integer* symbol_table::integerval(char const* text, size_t length)
{
  try {
    return new xs_integer(text);
  }
  catch ( std::invalid_argument const& ) {
    return NULL;
  }
}

std::string symbol_table::get(off_t id)
{
  size_t n = heap.get_length0(id);
  char *buf;
  buf = (char*)malloc(n+1);
  heap.get0(id, buf, 0, n+1);
  std::string retstr = string(buf, 0, n);
  free(buf);
  return retstr;
}

std::string symbol_table::get_last_qname()
{
  return get(last_qname);
}

}	/* namespace zorba */
/* vim:set et sw=2 ts=2: */
<commit_msg>Fixed exception catching.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

#include "zorbatypes/decimal.h"
#include "zorbatypes/float.h"
#include "zorbatypes/integer.h"
#include "zorbatypes/numconversions.h"

#include "compiler/parser/symbol_table.h"

#include "util/ascii_util.h"
#include "util/xml_util.h"
#include "util/uri_util.h"
#include "util/utf8_util.h"

#include "compiler/parser/xquery_driver.h"

#include <cstdlib>
#include <string>

using namespace std;

namespace zorba {

static bool decode_string(const char *yytext, size_t yyleng, string *result) {
  char delim = yytext [0];
  size_t i;
  for (i = 1; i + 1 < yyleng; i++) {
    char ch = yytext [i];
    if (ch == '&') {
      int d = xml::parse_entity(yytext + i + 1, result);
      if (d < 0) return false;
      i += d;
    } else {
      *result += ch;
      if (ch == delim) ++i;
    }
  }
  return true;
}

symbol_table::symbol_table(size_t initial_heapsize)
  :
  heap(initial_heapsize),
  last_qname(-1)
{
}

symbol_table::~symbol_table()
{
}

size_t symbol_table::size() const
{
  return (size_t)heap.size();
}

// bool attribute == true when an attribute value is normalized
static void normalize_eol(const char *text, size_t length, string *out, bool attribute = false) {
  size_t i;
  out->reserve (length + 1);
  char lastCh = '\0';
  for (i = 0; i < length; i++) {
    char ch = text [i];
    if (ch == '\r')
      *out += attribute ? ' ' : '\n';
    else if (ch != '\n' || lastCh != '\r')
      *out += (attribute && (ch == '\t' || ch == '\n'))? ' ' : ch;

    lastCh = ch;
  }
}

off_t symbol_table::put(char const* text)
{
  return put(text, strlen(text));
}

// normalizationType == 2 is used for normalizing attribute values
off_t symbol_table::put(char const* text, size_t length, int normalizationType)
{
  string normStr;
  if (normalizationType == 1 || normalizationType == 2)
  {
    normalize_eol (text, length, &normStr, normalizationType == 2);
    text = normStr.c_str ();
    length = normStr.size ();
  }

  return heap.put(text, 0, length);
}

off_t symbol_table::put_ncname(char const* text, size_t length)
{
  last_qname = heap.put(text, 0, length);
  return last_qname;
}

off_t symbol_table::put_qname(char const* text, size_t length, bool do_trim_start, bool do_trim_end, bool is_eqname)
{
  if (do_trim_start)
  {
    text = ascii::trim_start_space(text, &length);
  }

  if (do_trim_end)
  {
    length = ascii::trim_end_space(text, length);
  }

  if (!is_eqname)
  {
    last_qname = heap.put(text, 0, length);
  }
  else
  {
    // EQName:  Q{prefix}name
    string name;
    string prefix = text;
    string::size_type pos = prefix.rfind('}');
    name = prefix.substr(pos+1);
    prefix = prefix.substr(1, pos);

    off_t uri = put_uri(prefix.c_str(), prefix.size());
    name = get(uri) + ":" + name;

    last_qname = heap.put(name.c_str(), 0, name.size());
  }

  return last_qname;
}

off_t symbol_table::put_uri(char const* text, size_t length)
{
  // trim whitespace
  text = ascii::trim_space(text, &length);

  // normalize whitespace
  string result;
  if (! decode_string (text, length, &result))
    return -1;
  ascii::normalize_space( result );

  return heap.put (result.c_str (), 0, result.length ());
}

off_t symbol_table::put_varname(char const* text, size_t length)
{
  return heap.put(text, 0, length);
}

off_t symbol_table::put_entityref(char const* text, size_t length)
{
  string result;
  if (xml::parse_entity (text + 1, &result) < 0)
    return -1;
  return heap.put(result.c_str(), 0, result.size ());
}

off_t symbol_table::put_charref(char const* text, size_t length)
{
  return heap.put (text + 1, 0, length - 1);
}

off_t symbol_table::put_stringlit(char const* yytext, size_t yyleng)
{
  string eolNorm;
  normalize_eol (yytext, yyleng, &eolNorm);
  yytext = eolNorm.c_str ();
  yyleng = eolNorm.size ();
  string result;
  if (! decode_string (yytext, yyleng, &result))
    return -1;
  return heap.put (result.c_str (), 0, result.length ());
}

off_t symbol_table::put_json_stringliteral(char const* yytext, size_t yyleng, xquery_driver *driver, const location &loc)
{
  string result;
  unsigned int cp;
  size_t len;
  bool found_escape = false;
  bool found_ampersand = false;

  for (const char* chr = yytext+1; (unsigned int)(chr-yytext)<yyleng-1; chr+=1)
  {
    if (*chr == '\\')
    {
      bool is_escape = true;
      chr += 1;
      switch (*chr)
      {
      case '\\': result += '\\'; break;
      case '/': result += '/'; break;
      case '\"': result += '\"'; break;
      case '\'': result += '\''; break;
      case 'b': result += '\b'; break;
      case 'f': result += '\f'; break;
      case 'n': result += '\n'; break;
      case 'r': result += '\r'; break;
      case 't': result += '\t'; break;
      case 'u':
        cp = 0;
        for (unsigned int i=0; i<4; i++, chr+=1)
          cp = (cp << 4) + uri::hex2dec[(unsigned int)*(chr+1)];
        char tmp[10];
        len = utf8::encode(cp, tmp);
        result.append(tmp, len);
        break;
      default:
        result += *(chr-1);
        result += *chr;
        is_escape = false;
        break;
      }

      if (is_escape)
        found_escape = true;
    }
    else
    {
      if (*chr == '&')
        found_ampersand = true;
      result += *chr;
    }
  } // for

  if (found_escape && driver->commonLanguageEnabled())
    driver->addCommonLanguageWarning(loc, ZED(ZWST0009_JSON_ESCAPE));

  if (found_ampersand && driver->commonLanguageEnabled())
    driver->addCommonLanguageWarning(loc, ZED(ZWST0009_CHAR_REF));

  return heap.put (result.c_str (), 0, result.length ());
}

off_t symbol_table::put_commentcontent(char const* yytext, size_t yyleng)
{
  string eolNorm;
  normalize_eol (yytext, yyleng, &eolNorm);
  yytext = eolNorm.c_str (); yyleng = eolNorm.size ();
  return heap.put (yytext, 0, yyleng);
}

xs_decimal* symbol_table::decimalval(char const* text, size_t length)
{
  return new xs_decimal(text);
}

xs_double* symbol_table::doubleval(char const* text, size_t length)
{
  try {
    return new xs_double(text);
  }
  catch ( std::exception const& ) {
    return NULL;
  }
}

xs_integer* symbol_table::integerval(char const* text, size_t length)
{
  try {
    return new xs_integer(text);
  }
  catch ( std::exception const& ) {
    return NULL;
  }
}

std::string symbol_table::get(off_t id)
{
  size_t n = heap.get_length0(id);
  char *buf;
  buf = (char*)malloc(n+1);
  heap.get0(id, buf, 0, n+1);
  std::string retstr = string(buf, 0, n);
  free(buf);
  return retstr;
}

std::string symbol_table::get_last_qname()
{
  return get(last_qname);
}

}	/* namespace zorba */
/* vim:set et sw=2 ts=2: */
<|endoftext|>