<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not 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.
 *
 */

#include <libmemcached/common.h>

static memcached_return_t text_incr_decr(memcached_st *ptr,
                                         const char *verb,
                                         const char *group_key, size_t group_key_length,
                                         const char *key, size_t key_length,
                                         uint64_t offset,
                                         uint64_t *value)
{
  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  uint32_t server_key;
  memcached_server_write_instance_st instance;
  bool no_reply= ptr->flags.no_reply;

  if (memcached_failed(memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
  {
    return memcached_set_error(*ptr, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT);
  }

  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
  instance= memcached_server_instance_fetch(ptr, server_key);

  int send_length;
  send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
                        "%s %.*s%.*s %" PRIu64 "%s\r\n", verb,
                        memcached_print_array(ptr->_namespace),
                        (int)key_length, key,
                        offset, no_reply ? " noreply" : "");
  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
  {
    return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
                               memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
  }

  memcached_return_t rc= memcached_do(instance, buffer, (size_t)send_length, true);
  if (no_reply or memcached_failed(rc))
  {
    return rc;
  }

  rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);

  if (rc != MEMCACHED_SUCCESS)
  {
    return memcached_set_error(*instance, rc, MEMCACHED_AT);
  }

  /*
    So why recheck responce? Because the protocol is brain dead :)
    The number returned might end up equaling one of the string
    values. Less chance of a mistake with strncmp() so we will
    use it. We still called memcached_response() though since it
    worked its magic for non-blocking IO.
  */
  if (not strncmp(buffer, memcached_literal_param("ERROR\r\n")))
  {
    *value= 0;
    rc= MEMCACHED_PROTOCOL_ERROR;
  }
  else if (not strncmp(buffer, memcached_literal_param("CLIENT_ERROR\r\n")))
  {
    *value= 0;
    rc= MEMCACHED_PROTOCOL_ERROR;
  }
  else if (not strncmp(buffer, memcached_literal_param("NOT_FOUND\r\n")))
  {
    *value= 0;
    rc= MEMCACHED_NOTFOUND;
  }
  else
  {
    *value= strtoull(buffer, (char **)NULL, 10);
    rc= MEMCACHED_SUCCESS;
  }

  return memcached_set_error(*instance, rc, MEMCACHED_AT);
}

static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
                                           const char *group_key, size_t group_key_length,
                                           const char *key, size_t key_length,
                                           uint64_t offset, uint64_t initial,
                                           uint32_t expiration,
                                           uint64_t *value)
{
  bool no_reply= ptr->flags.no_reply;

  uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
  memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key);

  if (no_reply)
  {
    if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
      cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;

    if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
      cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
  }
  protocol_binary_request_incr request= {}; // = {.bytes= {0}};

  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= cmd;
  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
  request.message.header.request.extlen= 20;
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace) +request.message.header.request.extlen));
  request.message.body.delta= memcached_htonll(offset);
  request.message.body.initial= memcached_htonll(initial);
  request.message.body.expiration= htonl((uint32_t) expiration);

  struct libmemcached_io_vector_st vector[]=
  {
    { request.bytes, sizeof(request.bytes) },
    { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
    { key, key_length }
  };

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true)))
  {
    memcached_io_reset(instance);
    return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
  }

  if (no_reply)
  {
    return MEMCACHED_SUCCESS;
  }

  return memcached_response(instance, (char*)value, sizeof(*value), NULL);
}

memcached_return_t memcached_increment(memcached_st *ptr,
                                       const char *key, size_t key_length,
                                       uint32_t offset,
                                       uint64_t *value)
{
  return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
}

memcached_return_t memcached_decrement(memcached_st *ptr,
                                       const char *key, size_t key_length,
                                       uint32_t offset,
                                       uint64_t *value)
{
  return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
}

memcached_return_t memcached_increment_by_key(memcached_st *ptr,
                                              const char *group_key, size_t group_key_length,
                                              const char *key, size_t key_length,
                                              uint64_t offset,
                                              uint64_t *value)
{
  memcached_return_t rc;
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
                         group_key, group_key_length, key, key_length,
                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
                         value);
  }
  else
  {
     rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value);
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_END();

  return rc;
}

memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
                                              const char *group_key, size_t group_key_length,
                                              const char *key, size_t key_length,
                                              uint64_t offset,
                                              uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_DECREMENT_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
                         group_key, group_key_length, key, key_length,
                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
                         value);
  }
  else
  {
    rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value);
  }

  LIBMEMCACHED_MEMCACHED_DECREMENT_END();

  return rc;
}

memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
                                                    const char *key,
                                                    size_t key_length,
                                                    uint64_t offset,
                                                    uint64_t initial,
                                                    time_t expiration,
                                                    uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  return memcached_increment_with_initial_by_key(ptr, key, key_length,
                                                 key, key_length,
                                                 offset, initial, expiration, value);
}

memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
                                                         const char *group_key,
                                                         size_t group_key_length,
                                                         const char *key,
                                                         size_t key_length,
                                                         uint64_t offset,
                                                         uint64_t initial,
                                                         time_t expiration,
                                                         uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
                         group_key, group_key_length, key, key_length,
                         offset, initial, (uint32_t)expiration,
                         value);
  }
  else
  {
    rc= MEMCACHED_PROTOCOL_ERROR;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();

  return rc;
}

memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
                                                    const char *key,
                                                    size_t key_length,
                                                    uint64_t offset,
                                                    uint64_t initial,
                                                    time_t expiration,
                                                    uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  return memcached_decrement_with_initial_by_key(ptr, key, key_length,
                                                 key, key_length,
                                                 offset, initial, expiration, value);
}

memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
                                                           const char *group_key,
                                                           size_t group_key_length,
                                                           const char *key,
                                                           size_t key_length,
                                                           uint64_t offset,
                                                           uint64_t initial,
                                                           time_t expiration,
                                                           uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
                         group_key, group_key_length, key, key_length,
                         offset, initial, (uint32_t)expiration,
                         value);
  }
  else
  {
    rc= MEMCACHED_PROTOCOL_ERROR;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();

  return rc;
}

<commit_msg>Update auto to use vector<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not 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.
 *
 */

#include <libmemcached/common.h>

static memcached_return_t text_incr_decr(memcached_st *ptr,
                                         const bool is_incr,
                                         const char *group_key, size_t group_key_length,
                                         const char *key, size_t key_length,
                                         uint64_t offset,
                                         uint64_t *value)
{
  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  uint32_t server_key;
  memcached_server_write_instance_st instance;

  // Invert the logic to make it simpler to read the code
  bool reply= (ptr->flags.no_reply) ? false : true;

  if (memcached_failed(memcached_key_test(*ptr, (const char **)&key, &key_length, 1)))
  {
    return memcached_set_error(*ptr, MEMCACHED_BAD_KEY_PROVIDED, MEMCACHED_AT);
  }

  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
  instance= memcached_server_instance_fetch(ptr, server_key);

  int send_length;
  send_length= snprintf(buffer, sizeof(buffer), " %" PRIu64, offset);
  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
  {
    return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
                               memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
  }

  struct libmemcached_io_vector_st vector[]=
  {
    { memcached_literal_param("incr ") },
    { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
    { key, key_length },
    { buffer, send_length },
    { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
    { memcached_literal_param("\r\n") }
  };

  if (is_incr == false)
  {
    vector[0].buffer= "decr ";
  }

  memcached_return_t rc= memcached_vdo(instance, vector, 6, true);
  if (reply == false or memcached_failed(rc))
  {
    return rc;
  }

  rc= memcached_response(instance, buffer, sizeof(buffer), NULL);

  if (rc != MEMCACHED_SUCCESS)
  {
    return memcached_set_error(*instance, rc, MEMCACHED_AT);
  }

  /*
    So why recheck responce? Because the protocol is brain dead :)
    The number returned might end up equaling one of the string
    values. Less chance of a mistake with strncmp() so we will
    use it. We still called memcached_response() though since it
    worked its magic for non-blocking IO.
  */
  if (not strncmp(buffer, memcached_literal_param("ERROR\r\n")))
  {
    *value= 0;
    rc= MEMCACHED_PROTOCOL_ERROR;
  }
  else if (not strncmp(buffer, memcached_literal_param("CLIENT_ERROR\r\n")))
  {
    *value= 0;
    rc= MEMCACHED_PROTOCOL_ERROR;
  }
  else if (not strncmp(buffer, memcached_literal_param("NOT_FOUND\r\n")))
  {
    *value= 0;
    rc= MEMCACHED_NOTFOUND;
  }
  else
  {
    *value= strtoull(buffer, (char **)NULL, 10);
    rc= MEMCACHED_SUCCESS;
  }

  return memcached_set_error(*instance, rc, MEMCACHED_AT);
}

static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
                                           const char *group_key, size_t group_key_length,
                                           const char *key, size_t key_length,
                                           uint64_t offset, uint64_t initial,
                                           uint32_t expiration,
                                           uint64_t *value)
{
  bool no_reply= ptr->flags.no_reply;

  uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
  memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key);

  if (no_reply)
  {
    if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
      cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;

    if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
      cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
  }
  protocol_binary_request_incr request= {}; // = {.bytes= {0}};

  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= cmd;
  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->_namespace)));
  request.message.header.request.extlen= 20;
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->_namespace) +request.message.header.request.extlen));
  request.message.body.delta= memcached_htonll(offset);
  request.message.body.initial= memcached_htonll(initial);
  request.message.body.expiration= htonl((uint32_t) expiration);

  struct libmemcached_io_vector_st vector[]=
  {
    { request.bytes, sizeof(request.bytes) },
    { memcached_array_string(ptr->_namespace), memcached_array_size(ptr->_namespace) },
    { key, key_length }
  };

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true)))
  {
    memcached_io_reset(instance);
    return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
  }

  if (no_reply)
  {
    return MEMCACHED_SUCCESS;
  }

  return memcached_response(instance, (char*)value, sizeof(*value), NULL);
}

memcached_return_t memcached_increment(memcached_st *ptr,
                                       const char *key, size_t key_length,
                                       uint32_t offset,
                                       uint64_t *value)
{
  return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
}

memcached_return_t memcached_decrement(memcached_st *ptr,
                                       const char *key, size_t key_length,
                                       uint32_t offset,
                                       uint64_t *value)
{
  return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
}

memcached_return_t memcached_increment_by_key(memcached_st *ptr,
                                              const char *group_key, size_t group_key_length,
                                              const char *key, size_t key_length,
                                              uint64_t offset,
                                              uint64_t *value)
{
  memcached_return_t rc;
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
                         group_key, group_key_length, key, key_length,
                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
                         value);
  }
  else
  {
     rc= text_incr_decr(ptr, true, group_key, group_key_length, key, key_length, offset, value);
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_END();

  return rc;
}

memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
                                              const char *group_key, size_t group_key_length,
                                              const char *key, size_t key_length,
                                              uint64_t offset,
                                              uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_DECREMENT_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
                         group_key, group_key_length, key, key_length,
                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
                         value);
  }
  else
  {
    rc= text_incr_decr(ptr, false, group_key, group_key_length, key, key_length, offset, value);
  }

  LIBMEMCACHED_MEMCACHED_DECREMENT_END();

  return rc;
}

memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
                                                    const char *key,
                                                    size_t key_length,
                                                    uint64_t offset,
                                                    uint64_t initial,
                                                    time_t expiration,
                                                    uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  return memcached_increment_with_initial_by_key(ptr, key, key_length,
                                                 key, key_length,
                                                 offset, initial, expiration, value);
}

memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
                                                         const char *group_key,
                                                         size_t group_key_length,
                                                         const char *key,
                                                         size_t key_length,
                                                         uint64_t offset,
                                                         uint64_t initial,
                                                         time_t expiration,
                                                         uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
                         group_key, group_key_length, key, key_length,
                         offset, initial, (uint32_t)expiration,
                         value);
  }
  else
  {
    rc= MEMCACHED_PROTOCOL_ERROR;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();

  return rc;
}

memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
                                                    const char *key,
                                                    size_t key_length,
                                                    uint64_t offset,
                                                    uint64_t initial,
                                                    time_t expiration,
                                                    uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  return memcached_decrement_with_initial_by_key(ptr, key, key_length,
                                                 key, key_length,
                                                 offset, initial, expiration, value);
}

memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
                                                           const char *group_key,
                                                           size_t group_key_length,
                                                           const char *key,
                                                           size_t key_length,
                                                           uint64_t offset,
                                                           uint64_t initial,
                                                           time_t expiration,
                                                           uint64_t *value)
{
  uint64_t local_value;
  if (value == NULL)
  {
    value= &local_value;
  }

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return rc;
  }

  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
  if (ptr->flags.binary_protocol)
  {
    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
                         group_key, group_key_length, key, key_length,
                         offset, initial, (uint32_t)expiration,
                         value);
  }
  else
  {
    rc= MEMCACHED_PROTOCOL_ERROR;
  }

  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();

  return rc;
}

<|endoftext|>


<commit_before>// Copyright 2011 the V8 project authors. 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.

// CPU specific code for arm independent of OS goes here.

#include <sys/syscall.h>
#include <unistd.h>

#ifdef __mips
#include <asm/cachectl.h>
#endif  // #ifdef __mips

#include "v8.h"

#if defined(V8_TARGET_ARCH_MIPS)

#include "cpu.h"
#include "macro-assembler.h"

#include "simulator.h"  // For cache flushing.

namespace v8 {
namespace internal {

void CPU::SetUp() {
  CpuFeatures::Probe();
}

bool CPU::SupportsCrankshaft() {
  return CpuFeatures::IsSupported(FPU);
}

void CPU::FlushICache(void* start, size_t size) {
  // Nothing to do, flushing no instructions.
  if (size == 0) {
    return;
  }

#if !defined (USE_SIMULATOR)
  int res;

  // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
  res = syscall(__NR_cacheflush, start, size, ICACHE);

  if (res) {
    V8_Fatal(__FILE__, __LINE__, "Failed to flush the instruction cache");
  }

#else  // USE_SIMULATOR.
  // Not generating mips instructions for C-code. This means that we are
  // building a mips emulator based target.  We should notify the simulator
  // that the Icache was flushed.
  // None of this code ends up in the snapshot so there are no issues
  // around whether or not to generate the code when building snapshots.
  Simulator::FlushICache(Isolate::Current()->simulator_i_cache(), start, size);
#endif  // USE_SIMULATOR.
}

void CPU::DebugBreak() {
#ifdef __mips
  asm volatile("break");
#endif  // #ifdef __mips
}

} }  // namespace v8::internal

#endif  // V8_TARGET_ARCH_MIPS
<commit_msg>MIPS: Added Android-specific version of cacheflush call.<commit_after>// Copyright 2012 the V8 project authors. 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.

// CPU specific code for arm independent of OS goes here.

#include <sys/syscall.h>
#include <unistd.h>

#ifdef __mips
#include <asm/cachectl.h>
#endif  // #ifdef __mips

#include "v8.h"

#if defined(V8_TARGET_ARCH_MIPS)

#include "cpu.h"
#include "macro-assembler.h"

#include "simulator.h"  // For cache flushing.

namespace v8 {
namespace internal {

void CPU::SetUp() {
  CpuFeatures::Probe();
}

bool CPU::SupportsCrankshaft() {
  return CpuFeatures::IsSupported(FPU);
}

void CPU::FlushICache(void* start, size_t size) {
  // Nothing to do, flushing no instructions.
  if (size == 0) {
    return;
  }

#if !defined (USE_SIMULATOR)
#if defined(ANDROID)
  // Bionic cacheflush can typically run in userland, avoiding kernel call.
  char *end = reinterpret_cast<char *>(start) + size;
  cacheflush(
    reinterpret_cast<intptr_t>(start), reinterpret_cast<intptr_t>(end), 0);
#else  // ANDROID
  int res;
  // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
  res = syscall(__NR_cacheflush, start, size, ICACHE);
  if (res) {
    V8_Fatal(__FILE__, __LINE__, "Failed to flush the instruction cache");
  }
#endif  // ANDROID
#else  // USE_SIMULATOR.
  // Not generating mips instructions for C-code. This means that we are
  // building a mips emulator based target.  We should notify the simulator
  // that the Icache was flushed.
  // None of this code ends up in the snapshot so there are no issues
  // around whether or not to generate the code when building snapshots.
  Simulator::FlushICache(Isolate::Current()->simulator_i_cache(), start, size);
#endif  // USE_SIMULATOR.
}

void CPU::DebugBreak() {
#ifdef __mips
  asm volatile("break");
#endif  // #ifdef __mips
}

} }  // namespace v8::internal

#endif  // V8_TARGET_ARCH_MIPS
<|endoftext|>


<commit_before>#include "window.h"
#include "../controller/controller.h"
#include <stdio.h>

Window::Window() {
	// TODO Auto-generated constructor stub
	init(1280, 720, (char *) "Tytuł okna");

	textures = new unsigned int[3];
	textures[0] = loadGLTexture((char *) "../data/mainmenu/background.png");
	textures[1] = loadGLTexture((char *) "../data/mainmenu/backgroundText.png");

	TTF_Font *fontArial = loadFont((char *) "arial.ttf", 50);
	textures[2] = renderText((char *) "hello world", fontArial);

	cursor1 = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
	cursor2 = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);

	SDL_GetCurrentDisplayMode(0, &this->current);
	printf("Screen size: %ix%i.\n", this->current.w, this->current.h);
}

Window::~Window() {
	// TODO Auto-generated destructor stub
	SDL_GL_DeleteContext(mainGLContext);
	SDL_DestroyWindow(mainWindow);
	SDL_Quit();
}

void Window::init(int width, int height, char *title) {
	done = false;
	w = width;
	h = height;
	// Create window.
	initSDL(width, height, title, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
	createOrthoProj(width, height);
}

void Window::initSDL(Uint32 width, Uint32 height, char *title, Uint32 flags) {
	int error;
	error = SDL_Init(SDL_INIT_EVERYTHING);
	TTF_Init(); // TODO

	if (error) {
		printf("ERROR SDL INIT: %i\n", error);
	}

	// Turn on double buffering.
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	// Create the window
	mainWindow = SDL_CreateWindow(title,
	SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
	mainGLContext = SDL_GL_CreateContext(mainWindow);

}

void Window::createOrthoProj(int width, int height) {
	// I use a near plane value of -1, and a far plane value of 1, which is what works best for 2D games.
	w = width;
	h = height;
	glLoadIdentity();
	glOrtho(0.0, (GLdouble) width, 0.0, (GLdouble) height, -1.0, 1.0);
}

void Window::eventLoop() {
	SDL_Event event;

	while (SDL_PollEvent(&event)) {
		int x, y, w, h;
		switch (event.type) {
		case SDL_KEYDOWN:
			// Quit when user presses a key.
			//Controller::setDone();
			break;

		case SDL_QUIT:
			Controller::setDone();
			break;

		case SDL_MOUSEBUTTONDOWN:
			SDL_GetCurrentDisplayMode(0, &this->current);

			SDL_GetMouseState(&x, &y);
			w = 616;
			h = 409;
			if (x > (640 - w / 2) && x < (640 + w / 2) && y > (360 - h / 2)
					&& y < (360 + h / 2)) {
				if (SDL_GetWindowFlags(mainWindow)
						& SDL_WINDOW_FULLSCREEN_DESKTOP) {
					glViewport(0, 0, 1280, 720);
					createOrthoProj(1280.0, 720.0);
					SDL_SetWindowFullscreen(mainWindow, 0);
				} else {
					glViewport(0, 0, this->current.w, this->current.h);
					createOrthoProj(1280.0, 720.0);
					SDL_SetWindowFullscreen(mainWindow,
							SDL_WINDOW_FULLSCREEN_DESKTOP);
				}
			}
			break;

		case SDL_MOUSEMOTION:
			SDL_GetMouseState(&x, &y);
			//fprintf(stdout, "MOUSE x:%i y:%i\n", x, y);
			w = 616;
			h = 409;
			if (x > (640 - w / 2) && x < (640 + w / 2) && y > (360 - h / 2)
					&& y < (360 + h / 2))
				SDL_SetCursor(cursor2);
			else
				SDL_SetCursor(cursor1);
			break;

		default:
			break;
		}   // End switch

	}   // End while
}

int Window::loadGLTexture(char *fileName) {
	unsigned int textureId;
	SDL_Surface *textureImage;
	textureImage = IMG_Load(fileName);
	if (!textureImage) {
		fprintf(stderr, "Couldn't load %s.\n", fileName);
		return 0;
	} else {

		//Create the texture.
		glGenTextures(1, &textureId);
		int error = glGetError();
		if (error) {
			fprintf(stderr, "ERROR CODE %i.\n", error);
		}

		//Typical texture generation using data from the bitmap.
		glBindTexture(GL_TEXTURE_2D, textureId);

		//Generate the texture.
		if (textureImage->format->BytesPerPixel == 4) {
			glTexImage2D(GL_TEXTURE_2D, 0, 4, textureImage->w, textureImage->h,
					0, GL_RGBA, GL_UNSIGNED_BYTE, textureImage->pixels);
		} else {
			glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage->w, textureImage->h,
					0, GL_RGB, GL_UNSIGNED_BYTE, textureImage->pixels);
		}

		//Linear filtering.
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		//Free up the memory.
		if (textureImage)
			SDL_FreeSurface(textureImage);

		return textureId;
	}
}

TTF_Font *Window::loadFont(char *fileName, int fontSize) {
	TTF_Font *text_font = TTF_OpenFont("arial.ttf", 50);
	if (text_font == NULL) {
		printf("Failed to load lazy font! SDL_ttf Error: %s\n", TTF_GetError());
		return 0;
	}
	return text_font;
}

int Window::renderText(char *text, TTF_Font *text_font) {
	SDL_Color textColor = { 128, 0, 0 };

	SDL_Surface *sdl_surface = TTF_RenderText_Blended(text_font, text,
			textColor);
	if (sdl_surface == NULL) {
		printf("Unable to render text surface! SDL_ttf Error: %s\n",
				TTF_GetError());
		return 0;
	}

	GLuint texture_id;

	glGenTextures(1, &texture_id);
	glBindTexture(GL_TEXTURE_2D, texture_id);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sdl_surface->w, sdl_surface->h, 0,
			GL_BGRA, GL_UNSIGNED_BYTE, sdl_surface->pixels);

	return texture_id;
}

void Window::drawImage(int x, int y, int textureId, int width, int height) {
	y = h - y - height;
	glBindTexture(GL_TEXTURE_2D, textureId);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 1);
	glVertex3f(x, y, 0);
	glTexCoord2f(1, 1);
	glVertex3f(x + width, y, 0);
	glTexCoord2f(1, 0);
	glVertex3f(x + width, y + height, 0);
	glTexCoord2f(0, 0);
	glVertex3f(x, y + height, 0);
	glEnd();
}

void Window::renderFrame() {
	glClear(GL_COLOR_BUFFER_BIT);
	//glColor3f(0.7, 0.5, 0.8);

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// For Ortho mode, of course
	int Width = 616;
	int Height = 409;
	int X = (1280 - Width) / 2;
	int Y = (720 - Height) / 2;

	drawImage(0, 0, textures[0], 1280, 720);
	drawImage(100, 100, textures[1], 394, 198);
	drawImage(X, Y, textures[2], 242, 57);

	//glRecti(50, 100, 200, 300);
	SDL_GL_SwapWindow(mainWindow);
}

<commit_msg>Fixed problem with non 16x9 displays.<commit_after>#include "window.h"
#include "../controller/controller.h"
#include <stdio.h>

Window::Window() {
	// TODO Auto-generated constructor stub
	init(1280, 720, (char *) "Tytuł okna");

	textures = new unsigned int[3];
	textures[0] = loadGLTexture((char *) "../data/mainmenu/background.png");
	textures[1] = loadGLTexture((char *) "../data/mainmenu/backgroundText.png");

	TTF_Font *fontArial = loadFont((char *) "arial.ttf", 50);
	textures[2] = renderText((char *) "hello world", fontArial);

	cursor1 = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
	cursor2 = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);

	SDL_GetCurrentDisplayMode(0, &this->current);
	printf("Screen size: %ix%i.\n", this->current.w, this->current.h);
}

Window::~Window() {
	// TODO Auto-generated destructor stub
	SDL_GL_DeleteContext(mainGLContext);
	SDL_DestroyWindow(mainWindow);
	SDL_Quit();
}

void Window::init(int width, int height, char *title) {
	done = false;
	w = width;
	h = height;
	// Create window.
	initSDL(width, height, title, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
	createOrthoProj(width, height);
}

void Window::initSDL(Uint32 width, Uint32 height, char *title, Uint32 flags) {
	int error;
	error = SDL_Init(SDL_INIT_EVERYTHING);
	TTF_Init(); // TODO

	if (error) {
		printf("ERROR SDL INIT: %i\n", error);
	}

	// Turn on double buffering.
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	// Create the window
	mainWindow = SDL_CreateWindow(title,
	SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
	mainGLContext = SDL_GL_CreateContext(mainWindow);

}

void Window::createOrthoProj(int width, int height) {
	// I use a near plane value of -1, and a far plane value of 1, which is what works best for 2D games.
	w = width;
	h = height;
	glLoadIdentity();
	glOrtho(0.0, (GLdouble) width, 0.0, (GLdouble) height, -1.0, 1.0);
}

void Window::eventLoop() {
	SDL_Event event;

	while (SDL_PollEvent(&event)) {
		int x, y, w, h;
		switch (event.type) {
		case SDL_KEYDOWN:
			// Quit when user presses a key.
			//Controller::setDone();
			break;

		case SDL_QUIT:
			Controller::setDone();
			break;

		case SDL_MOUSEBUTTONDOWN:
			SDL_GetCurrentDisplayMode(0, &this->current);

			SDL_GetMouseState(&x, &y);
			w = 616;
			h = 409;
			if (x > (640 - w / 2) && x < (640 + w / 2) && y > (360 - h / 2)
					&& y < (360 + h / 2)) {
				if (SDL_GetWindowFlags(mainWindow)
						& SDL_WINDOW_FULLSCREEN_DESKTOP) {
					glViewport(0, 0, 1280, 720);
					createOrthoProj(1280.0, 720.0);
					SDL_SetWindowFullscreen(mainWindow, 0);
				} else {
					glViewport(0, (this->current.h-this->current.w/16.0*9.0)/2.0, this->current.w, this->current.w/16.0*9.0);
					createOrthoProj(1280.0, 720.0);
					SDL_SetWindowFullscreen(mainWindow,
							SDL_WINDOW_FULLSCREEN_DESKTOP);
				}
			}
			break;

		case SDL_MOUSEMOTION:
			SDL_GetMouseState(&x, &y);
			//fprintf(stdout, "MOUSE x:%i y:%i\n", x, y);
			w = 616;
			h = 409;
			if (x > (640 - w / 2) && x < (640 + w / 2) && y > (360 - h / 2)
					&& y < (360 + h / 2))
				SDL_SetCursor(cursor2);
			else
				SDL_SetCursor(cursor1);
			break;

		default:
			break;
		}   // End switch

	}   // End while
}

int Window::loadGLTexture(char *fileName) {
	unsigned int textureId;
	SDL_Surface *textureImage;
	textureImage = IMG_Load(fileName);
	if (!textureImage) {
		fprintf(stderr, "Couldn't load %s.\n", fileName);
		return 0;
	} else {

		//Create the texture.
		glGenTextures(1, &textureId);
		int error = glGetError();
		if (error) {
			fprintf(stderr, "ERROR CODE %i.\n", error);
		}

		//Typical texture generation using data from the bitmap.
		glBindTexture(GL_TEXTURE_2D, textureId);

		//Generate the texture.
		if (textureImage->format->BytesPerPixel == 4) {
			glTexImage2D(GL_TEXTURE_2D, 0, 4, textureImage->w, textureImage->h,
					0, GL_RGBA, GL_UNSIGNED_BYTE, textureImage->pixels);
		} else {
			glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage->w, textureImage->h,
					0, GL_RGB, GL_UNSIGNED_BYTE, textureImage->pixels);
		}

		//Linear filtering.
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		//Free up the memory.
		if (textureImage)
			SDL_FreeSurface(textureImage);

		return textureId;
	}
}

TTF_Font *Window::loadFont(char *fileName, int fontSize) {
	TTF_Font *text_font = TTF_OpenFont("arial.ttf", 50);
	if (text_font == NULL) {
		printf("Failed to load lazy font! SDL_ttf Error: %s\n", TTF_GetError());
		return 0;
	}
	return text_font;
}

int Window::renderText(char *text, TTF_Font *text_font) {
	SDL_Color textColor = { 128, 0, 0 };

	SDL_Surface *sdl_surface = TTF_RenderText_Blended(text_font, text,
			textColor);
	if (sdl_surface == NULL) {
		printf("Unable to render text surface! SDL_ttf Error: %s\n",
				TTF_GetError());
		return 0;
	}

	GLuint texture_id;

	glGenTextures(1, &texture_id);
	glBindTexture(GL_TEXTURE_2D, texture_id);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sdl_surface->w, sdl_surface->h, 0,
			GL_BGRA, GL_UNSIGNED_BYTE, sdl_surface->pixels);

	return texture_id;
}

void Window::drawImage(int x, int y, int textureId, int width, int height) {
	y = h - y - height;
	glBindTexture(GL_TEXTURE_2D, textureId);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 1);
	glVertex3f(x, y, 0);
	glTexCoord2f(1, 1);
	glVertex3f(x + width, y, 0);
	glTexCoord2f(1, 0);
	glVertex3f(x + width, y + height, 0);
	glTexCoord2f(0, 0);
	glVertex3f(x, y + height, 0);
	glEnd();
}

void Window::renderFrame() {
	glClear(GL_COLOR_BUFFER_BIT);
	//glColor3f(0.7, 0.5, 0.8);

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// For Ortho mode, of course
	int Width = 616;
	int Height = 409;
	int X = (1280 - Width) / 2;
	int Y = (720 - Height) / 2;

	drawImage(0, 0, textures[0], 1280, 720);
	drawImage(100, 100, textures[1], 394, 198);
	drawImage(X, Y, textures[2], 242, 57);

	//glRecti(50, 100, 200, 300);
	SDL_GL_SwapWindow(mainWindow);
}

<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 "filehandle.h"
#include "common/continuation/continuation.h"
#include "connection/datanodeconnection.h"
#include "reader/block_reader.h"

#include <future>
#include <tuple>

namespace hdfs {

using ::hadoop::hdfs::LocatedBlocksProto;

FileHandle::~FileHandle() {}

FileHandleImpl::FileHandleImpl(::asio::io_service *io_service, const std::string &client_name,
                                 const std::shared_ptr<const struct FileInfo> file_info,
                                 std::shared_ptr<BadDataNodeTracker> bad_data_nodes)
    : io_service_(io_service), client_name_(client_name), file_info_(file_info),
      bad_node_tracker_(bad_data_nodes), offset_(0), cancel_state_(CancelTracker::New()) {
}

void FileHandleImpl::PositionRead(
    void *buf, size_t nbyte, uint64_t offset,
    const std::function<void(const Status &, size_t)> &handler) {
  /* prevent usage after cancelation */
  if(cancel_state_->is_canceled()) {
    handler(Status::Canceled(), 0);
    return;
  }

  auto callback = [this, handler](const Status &status,
                                  const std::string &contacted_datanode,
                                  size_t bytes_read) {
    /* determine if DN gets marked bad */
    if (ShouldExclude(status)) {
      bad_node_tracker_->AddBadNode(contacted_datanode);
    }

    handler(status, bytes_read);
  };

  AsyncPreadSome(offset, asio::buffer(buf, nbyte), bad_node_tracker_, callback);
}

Status FileHandleImpl::PositionRead(void *buf, size_t *nbyte, off_t offset) {
  auto callstate = std::make_shared<std::promise<std::tuple<Status, size_t>>>();
  std::future<std::tuple<Status, size_t>> future(callstate->get_future());

  /* wrap async call with promise/future to make it blocking */
  auto callback = [callstate](const Status &s, size_t bytes) {
    callstate->set_value(std::make_tuple(s,bytes));
  };

  PositionRead(buf, *nbyte, offset, callback);

  /* wait for async to finish */
  auto returnstate = future.get();
  auto stat = std::get<0>(returnstate);

  if (!stat.ok()) {
    return stat;
  }

  *nbyte = std::get<1>(returnstate);
  return stat;
}

Status FileHandleImpl::Read(void *buf, size_t *nbyte) {
  Status stat = PositionRead(buf, nbyte, offset_);
  if(!stat.ok()) {
    return stat;
  }

  offset_ += *nbyte;
  return Status::OK();
}

Status FileHandleImpl::Seek(off_t *offset, std::ios_base::seekdir whence) {
  if(cancel_state_->is_canceled()) {
    return Status::Canceled();
  }

  off_t new_offset = -1;

  switch (whence) {
    case std::ios_base::beg:
      new_offset = *offset;
      break;
    case std::ios_base::cur:
      new_offset = offset_ + *offset;
      break;
    case std::ios_base::end:
      new_offset = file_info_->file_length_ + *offset;
      break;
    default:
      /* unsupported */
      return Status::InvalidArgument("Invalid Seek whence argument");
  }

  if(!CheckSeekBounds(new_offset)) {
    return Status::InvalidArgument("Seek offset out of bounds");
  }
  offset_ = new_offset;

  *offset = offset_;
  return Status::OK();
}

/* return false if seek will be out of bounds */
bool FileHandleImpl::CheckSeekBounds(ssize_t desired_position) {
  ssize_t file_length = file_info_->file_length_;

  if (desired_position < 0 || desired_position > file_length) {
    return false;
  }

  return true;
}

/*
 * Note that this method must be thread-safe w.r.t. the unsafe operations occurring
 * on the FileHandle
 */
void FileHandleImpl::AsyncPreadSome(
    size_t offset, const MutableBuffers &buffers,
    std::shared_ptr<NodeExclusionRule> excluded_nodes,
    const std::function<void(const Status &, const std::string &, size_t)> handler) {
  using ::hadoop::hdfs::DatanodeInfoProto;
  using ::hadoop::hdfs::LocatedBlockProto;

  if(cancel_state_->is_canceled()) {
    handler(Status::Canceled(), "", 0);
    return;
  }

  /**
   *  Note: block and chosen_dn will end up pointing to things inside
   *  the blocks_ vector.  They shouldn't be directly deleted.
   **/
  auto block = std::find_if(
      file_info_->blocks_.begin(), file_info_->blocks_.end(), [offset](const LocatedBlockProto &p) {
        return p.offset() <= offset && offset < p.offset() + p.b().numbytes();
      });

  if (block == file_info_->blocks_.end()) {
    handler(Status::InvalidArgument("Cannot find corresponding blocks"), "", 0);
    return;
  }

  /**
   * If user supplies a rule use it, otherwise use the tracker.
   * User is responsible for making sure one of them isn't null.
   **/
  std::shared_ptr<NodeExclusionRule> rule =
      excluded_nodes != nullptr ? excluded_nodes : bad_node_tracker_;

  auto datanodes = block->locs();
  auto it = std::find_if(datanodes.begin(), datanodes.end(),
                         [rule](const DatanodeInfoProto &dn) {
                           return !rule->IsBadNode(dn.id().datanodeuuid());
                         });

  if (it == datanodes.end()) {
    handler(Status::ResourceUnavailable("No datanodes available"), "", 0);
    return;
  }

  DatanodeInfoProto &chosen_dn = *it;

  uint64_t offset_within_block = offset - block->offset();
  uint64_t size_within_block = std::min<uint64_t>(
      block->b().numbytes() - offset_within_block, asio::buffer_size(buffers));

  // This is where we will put the logic for re-using a DN connection; we can
  //    steal the FileHandle's dn and put it back when we're done
  std::shared_ptr<DataNodeConnection> dn = CreateDataNodeConnection(io_service_, chosen_dn, nullptr /*token*/);
  std::string dn_id = dn->uuid_;
  std::string client_name = client_name_;

  // Wrap the DN in a block reader to handle the state and logic of the
  //    block request protocol
  std::shared_ptr<BlockReader> reader;
  reader = CreateBlockReader(BlockReaderOptions(), dn);

  auto read_handler = [reader, dn_id, handler](const Status & status, size_t transferred) {
    handler(status, dn_id, transferred);
  };

  dn->Connect([handler,read_handler,block,offset_within_block,size_within_block, buffers, reader, dn_id, client_name]
          (Status status, std::shared_ptr<DataNodeConnection> dn) {
    (void)dn;
    if (status.ok()) {
      reader->AsyncReadBlock(
          client_name, *block, offset_within_block,
          asio::buffer(buffers, size_within_block), read_handler);
    } else {
      handler(status, dn_id, 0);
    }
  });

  return;
}

std::shared_ptr<BlockReader> FileHandleImpl::CreateBlockReader(const BlockReaderOptions &options,
                                               std::shared_ptr<DataNodeConnection> dn)
{
  std::shared_ptr<BlockReader> reader = std::make_shared<BlockReaderImpl>(options, dn, cancel_state_);
  readers_.AddReader(reader);
  return reader;
}

std::shared_ptr<DataNodeConnection> FileHandleImpl::CreateDataNodeConnection(
    ::asio::io_service * io_service,
    const ::hadoop::hdfs::DatanodeInfoProto & dn,
    const hadoop::common::TokenProto * token) {
  return std::make_shared<DataNodeConnectionImpl>(io_service, dn, token);
}

void FileHandleImpl::CancelOperations() {
  cancel_state_->set_canceled();

  /* Push update to BlockReaders that may be hung in an asio call */
  std::vector<std::shared_ptr<BlockReader>> live_readers = readers_.GetLiveReaders();
  for(auto reader : live_readers) {
    reader->CancelOperation();
  }
}

bool FileHandle::ShouldExclude(const Status &s) {
  if (s.ok()) {
    return false;
  }

  switch (s.code()) {
    /* client side resource exhaustion */
    case Status::kResourceUnavailable:
    case Status::kOperationCanceled:
      return false;
    case Status::kInvalidArgument:
    case Status::kUnimplemented:
    case Status::kException:
    default:
      return true;
  }
}

}
<commit_msg>HDFS-9753. libhdfs++: Client fails to pass TokenProto from LocatedBlockProto to server when reading a block.  Contributed by James Clampffer.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 "filehandle.h"
#include "common/continuation/continuation.h"
#include "connection/datanodeconnection.h"
#include "reader/block_reader.h"

#include <future>
#include <tuple>

namespace hdfs {

using ::hadoop::hdfs::LocatedBlocksProto;

FileHandle::~FileHandle() {}

FileHandleImpl::FileHandleImpl(::asio::io_service *io_service, const std::string &client_name,
                                 const std::shared_ptr<const struct FileInfo> file_info,
                                 std::shared_ptr<BadDataNodeTracker> bad_data_nodes)
    : io_service_(io_service), client_name_(client_name), file_info_(file_info),
      bad_node_tracker_(bad_data_nodes), offset_(0), cancel_state_(CancelTracker::New()) {
}

void FileHandleImpl::PositionRead(
    void *buf, size_t nbyte, uint64_t offset,
    const std::function<void(const Status &, size_t)> &handler) {
  /* prevent usage after cancelation */
  if(cancel_state_->is_canceled()) {
    handler(Status::Canceled(), 0);
    return;
  }

  auto callback = [this, handler](const Status &status,
                                  const std::string &contacted_datanode,
                                  size_t bytes_read) {
    /* determine if DN gets marked bad */
    if (ShouldExclude(status)) {
      bad_node_tracker_->AddBadNode(contacted_datanode);
    }

    handler(status, bytes_read);
  };

  AsyncPreadSome(offset, asio::buffer(buf, nbyte), bad_node_tracker_, callback);
}

Status FileHandleImpl::PositionRead(void *buf, size_t *nbyte, off_t offset) {
  auto callstate = std::make_shared<std::promise<std::tuple<Status, size_t>>>();
  std::future<std::tuple<Status, size_t>> future(callstate->get_future());

  /* wrap async call with promise/future to make it blocking */
  auto callback = [callstate](const Status &s, size_t bytes) {
    callstate->set_value(std::make_tuple(s,bytes));
  };

  PositionRead(buf, *nbyte, offset, callback);

  /* wait for async to finish */
  auto returnstate = future.get();
  auto stat = std::get<0>(returnstate);

  if (!stat.ok()) {
    return stat;
  }

  *nbyte = std::get<1>(returnstate);
  return stat;
}

Status FileHandleImpl::Read(void *buf, size_t *nbyte) {
  Status stat = PositionRead(buf, nbyte, offset_);
  if(!stat.ok()) {
    return stat;
  }

  offset_ += *nbyte;
  return Status::OK();
}

Status FileHandleImpl::Seek(off_t *offset, std::ios_base::seekdir whence) {
  if(cancel_state_->is_canceled()) {
    return Status::Canceled();
  }

  off_t new_offset = -1;

  switch (whence) {
    case std::ios_base::beg:
      new_offset = *offset;
      break;
    case std::ios_base::cur:
      new_offset = offset_ + *offset;
      break;
    case std::ios_base::end:
      new_offset = file_info_->file_length_ + *offset;
      break;
    default:
      /* unsupported */
      return Status::InvalidArgument("Invalid Seek whence argument");
  }

  if(!CheckSeekBounds(new_offset)) {
    return Status::InvalidArgument("Seek offset out of bounds");
  }
  offset_ = new_offset;

  *offset = offset_;
  return Status::OK();
}

/* return false if seek will be out of bounds */
bool FileHandleImpl::CheckSeekBounds(ssize_t desired_position) {
  ssize_t file_length = file_info_->file_length_;

  if (desired_position < 0 || desired_position > file_length) {
    return false;
  }

  return true;
}

/*
 * Note that this method must be thread-safe w.r.t. the unsafe operations occurring
 * on the FileHandle
 */
void FileHandleImpl::AsyncPreadSome(
    size_t offset, const MutableBuffers &buffers,
    std::shared_ptr<NodeExclusionRule> excluded_nodes,
    const std::function<void(const Status &, const std::string &, size_t)> handler) {
  using ::hadoop::hdfs::DatanodeInfoProto;
  using ::hadoop::hdfs::LocatedBlockProto;

  if(cancel_state_->is_canceled()) {
    handler(Status::Canceled(), "", 0);
    return;
  }

  /**
   *  Note: block and chosen_dn will end up pointing to things inside
   *  the blocks_ vector.  They shouldn't be directly deleted.
   **/
  auto block = std::find_if(
      file_info_->blocks_.begin(), file_info_->blocks_.end(), [offset](const LocatedBlockProto &p) {
        return p.offset() <= offset && offset < p.offset() + p.b().numbytes();
      });

  if (block == file_info_->blocks_.end()) {
    handler(Status::InvalidArgument("Cannot find corresponding blocks"), "", 0);
    return;
  }

  /**
   * If user supplies a rule use it, otherwise use the tracker.
   * User is responsible for making sure one of them isn't null.
   **/
  std::shared_ptr<NodeExclusionRule> rule =
      excluded_nodes != nullptr ? excluded_nodes : bad_node_tracker_;

  auto datanodes = block->locs();
  auto it = std::find_if(datanodes.begin(), datanodes.end(),
                         [rule](const DatanodeInfoProto &dn) {
                           return !rule->IsBadNode(dn.id().datanodeuuid());
                         });

  if (it == datanodes.end()) {
    handler(Status::ResourceUnavailable("No datanodes available"), "", 0);
    return;
  }

  DatanodeInfoProto &chosen_dn = *it;

  uint64_t offset_within_block = offset - block->offset();
  uint64_t size_within_block = std::min<uint64_t>(
      block->b().numbytes() - offset_within_block, asio::buffer_size(buffers));

  // This is where we will put the logic for re-using a DN connection; we can
  //    steal the FileHandle's dn and put it back when we're done
  std::shared_ptr<DataNodeConnection> dn = CreateDataNodeConnection(io_service_, chosen_dn, &block->blocktoken());
  std::string dn_id = dn->uuid_;
  std::string client_name = client_name_;

  // Wrap the DN in a block reader to handle the state and logic of the
  //    block request protocol
  std::shared_ptr<BlockReader> reader;
  reader = CreateBlockReader(BlockReaderOptions(), dn);

  auto read_handler = [reader, dn_id, handler](const Status & status, size_t transferred) {
    handler(status, dn_id, transferred);
  };

  dn->Connect([handler,read_handler,block,offset_within_block,size_within_block, buffers, reader, dn_id, client_name]
          (Status status, std::shared_ptr<DataNodeConnection> dn) {
    (void)dn;
    if (status.ok()) {
      reader->AsyncReadBlock(
          client_name, *block, offset_within_block,
          asio::buffer(buffers, size_within_block), read_handler);
    } else {
      handler(status, dn_id, 0);
    }
  });

  return;
}

std::shared_ptr<BlockReader> FileHandleImpl::CreateBlockReader(const BlockReaderOptions &options,
                                               std::shared_ptr<DataNodeConnection> dn)
{
  std::shared_ptr<BlockReader> reader = std::make_shared<BlockReaderImpl>(options, dn, cancel_state_);
  readers_.AddReader(reader);
  return reader;
}

std::shared_ptr<DataNodeConnection> FileHandleImpl::CreateDataNodeConnection(
    ::asio::io_service * io_service,
    const ::hadoop::hdfs::DatanodeInfoProto & dn,
    const hadoop::common::TokenProto * token) {
  return std::make_shared<DataNodeConnectionImpl>(io_service, dn, token);
}

void FileHandleImpl::CancelOperations() {
  cancel_state_->set_canceled();

  /* Push update to BlockReaders that may be hung in an asio call */
  std::vector<std::shared_ptr<BlockReader>> live_readers = readers_.GetLiveReaders();
  for(auto reader : live_readers) {
    reader->CancelOperation();
  }
}

bool FileHandle::ShouldExclude(const Status &s) {
  if (s.ok()) {
    return false;
  }

  switch (s.code()) {
    /* client side resource exhaustion */
    case Status::kResourceUnavailable:
    case Status::kOperationCanceled:
      return false;
    case Status::kInvalidArgument:
    case Status::kUnimplemented:
    case Status::kException:
    default:
      return true;
  }
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: component_context.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: dbo $ $Date: 2001-06-07 12:55:20 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef _DEBUG
#include <stdio.h>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _CPPUHELPER_IMPLBASE1_HXX
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _CPPUHELPER_COMPBASE1_HXX
#include <cppuhelper/compbase1.hxx>
#endif
#ifndef _CPPUHELPER_COMPONENT_CONTEXT_HXX
#include <cppuhelper/component_context.hxx>
#endif

#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>

#include <hash_map>

#define SMGR_NAME "com.sun.star.lang.ServiceManager"
#define TDMGR_NAME "com.sun.star.reflection.TypeDescriptionManager"

using namespace ::osl;
using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;

namespace cppu
{

//==================================================================================================
class Disposer_Impl
    : public WeakImplHelper1< lang::XEventListener >
{
    Reference< lang::XComponent > m_xTarget;

public:
    inline Disposer_Impl( Reference< lang::XComponent > const & xTarget )
        SAL_THROW( () )
        : m_xTarget( xTarget )
        { OSL_ASSERT( m_xTarget.is() ); }

    virtual void SAL_CALL disposing( lang::EventObject const & rSource )
        throw (RuntimeException);
};
//__________________________________________________________________________________________________
void Disposer_Impl::disposing( lang::EventObject const & rSource )
    throw (RuntimeException)
{
    m_xTarget->dispose();
    m_xTarget.clear();
}

//==================================================================================================
struct MutexHolder
{
    Mutex m_mutex;
};
//==================================================================================================
class ComponentContext
    : public MutexHolder
    , public WeakComponentImplHelper1< XComponentContext >
{
    Reference< XComponentContext > m_xDelegate;

    struct ContextEntry
    {
        Any value;
        bool bLateInitService;

        inline ContextEntry( bool bLateInitService_, Any const & value_ )
            : value( value_ )
            , bLateInitService( bLateInitService_ )
            {}
    };
    typedef ::std::hash_map< OUString, ContextEntry *, OUStringHash > t_map;
    t_map m_map;

    Reference< lang::XMultiComponentFactory > m_xSMgr;
    // denotes if service manager has to be disposed by this context,
    // else it was retieved from a delegate which itself has to dispose it
    bool m_bDisposeSMgr;

protected:
    virtual void SAL_CALL disposing();

public:
    ComponentContext(
        ContextEntry_Init const * pEntries, sal_Int32 nEntries,
        Reference< XComponentContext > const & xDelegate )
        SAL_THROW( () );
    ComponentContext(
        ContextEntry_Init const * pEntries, sal_Int32 nEntries,
        Reference< registry::XSimpleRegistry > const & xRegistry )
        SAL_THROW( () );
    virtual ~ComponentContext();

    // XComponentContext
    virtual Any SAL_CALL getValueByName( OUString const & rName )
        throw (RuntimeException);
    virtual Reference< lang::XMultiComponentFactory > SAL_CALL getServiceManager()
        throw (RuntimeException);
};
//__________________________________________________________________________________________________
Any ComponentContext::getValueByName( OUString const & rName )
    throw (RuntimeException)
{
    /** map is anytime untouched, if an uninit value will be inited, synch is done on mutex.
     */

    t_map::const_iterator const iFind( m_map.find( rName ) );
    if (iFind != m_map.end())
    {
        ContextEntry * pEntry = iFind->second;

        if (pEntry->bLateInitService)
        {
            try
            {
                Reference< XInterface > xInstance;

                Reference< lang::XSingleComponentFactory > xFac;
                if (pEntry->value >>= xFac) // try via factory
                {
                    xInstance = xFac->createInstanceWithContext( this );
                }
                else // optionally service name
                {
                    OUString aServiceName;
                    if ((pEntry->value >>= aServiceName) && aServiceName.getLength())
                    {
                        if (m_xSMgr.is())
                        {
                            xInstance = m_xSMgr->createInstanceWithContext( aServiceName, this );
                        }
#ifdef _DEBUG
                        else
                        {
                            ::fprintf( stderr, "### no service manager given for instanciating singletons!\n" );
                        }
#endif
                    }
                }

                if (xInstance.is())
                {
                    ClearableMutexGuard aGuard( m_mutex );
                    if (pEntry->bLateInitService)
                    {
                        pEntry->value.setValue( &xInstance, ::getCppuType( &xInstance ) );
                        pEntry->bLateInitService = false;
                    }
                    else // inited in the meantime
                    {
                        aGuard.clear();
                        // service has entered the context in the meantime
                        // => try to dispose this object
                        Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
                        if (xComp.is())
                        {
                            xComp->dispose();
                        }
                    }

                    return pEntry->value;
                }
                else
                {
                    OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_ASCII_US ) );
                    OSL_TRACE( "### cannot raise singleton: $s\n", aStr.getStr() );
                }
            }
            catch (Exception & rExc)
            {
#ifdef _DEBUG
                OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_ASCII_US ) );
                OString aStr2( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
                ::fprintf( stderr, "### exception occured raising singleton %s: %s\n", aStr.getStr(), aStr2.getStr() );
#endif
            }
        }
        else
        {
            return pEntry->value;
        }

        return Any(); // error occured
    }
    else if (m_xDelegate.is())
    {
        return m_xDelegate->getValueByName( rName );
    }

    return Any();
}
//__________________________________________________________________________________________________
Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
    throw (RuntimeException)
{
    return m_xSMgr;
}
//__________________________________________________________________________________________________
ComponentContext::~ComponentContext()
{
#ifdef DEBUG
    ::fprintf( stderr, "> destructed context %p\n", this );
#endif
}
//__________________________________________________________________________________________________
void ComponentContext::disposing()
{
#ifdef DEBUG
    ::fprintf( stderr, "> disposing context %p\n", this );
#endif

    Reference< lang::XComponent > xTDMgr; // to be disposed separately

    // first dispose all context objects
    t_map::const_iterator iPos( m_map.begin() );
    for ( ; iPos != m_map.end(); ++iPos )
    {
        ContextEntry * pEntry = iPos->second;

        // service manager disposed separately
        if (!m_xSMgr.is() || !iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_NAME) ))
        {
            Reference< lang::XComponent > xComp;

            if (pEntry->bLateInitService)
            {
                // may be in late init
                MutexGuard aGuard( m_mutex );
                pEntry->value >>= xComp;
            }
            else
            {
                pEntry->value >>= xComp;
            }

            if (xComp.is())
            {
                if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(TDMGR_NAME) ))
                {
                    // disposed separately
                    xTDMgr = xComp;
                }
                else
                {
                    xComp->dispose();
                }
            }
        }
    }

    // second dispose service manager
    if (m_bDisposeSMgr)
    {
        Reference< lang::XComponent > xComp( m_xSMgr, UNO_QUERY );
        if (xComp.is())
        {
            xComp->dispose();
        }
    }

    // last dispose of tdmgr: revoke callback from cppu runtime
    if (xTDMgr.is())
    {
        xTDMgr->dispose();
    }

    // everything is disposed, hopefully nobody accesses the context anymore...
    for ( iPos = m_map.begin(); iPos != m_map.end(); ++iPos )
    {
        delete iPos->second;
    }

    m_map.clear();
}
//__________________________________________________________________________________________________
ComponentContext::ComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< XComponentContext > const & xDelegate )
    SAL_THROW( () )
    : WeakComponentImplHelper1< XComponentContext >( m_mutex )
    , m_xDelegate( xDelegate )
{
    while (nEntries--)
    {
        ContextEntry_Init const & rEntry = pEntries[ nEntries ];

        if (rEntry.name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_NAME) ))
        {
            rEntry.value >>= m_xSMgr;
        }
        m_map[ rEntry.name ] = new ContextEntry( rEntry.bLateInitService, rEntry.value );
    }

    m_bDisposeSMgr = (m_xSMgr.is() != sal_False);

    if (m_xDelegate.is())
    {
        Reference< lang::XComponent > xComp( m_xDelegate, UNO_QUERY );
        OSL_ENSURE( xComp.is(), "### component context should export lang::XComponent!" );
        if (xComp.is())
        {
            xComp->addEventListener( new Disposer_Impl( this ) );
        }
        if (! m_xSMgr.is())
        {
            m_xSMgr = m_xDelegate->getServiceManager();
            m_bDisposeSMgr = false;
        }
    }
}
//__________________________________________________________________________________________________
ComponentContext::ComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< registry::XSimpleRegistry > const & xRegistry )
    SAL_THROW( () )
    : WeakComponentImplHelper1< XComponentContext >( m_mutex )
{
    // inited values
    while (nEntries--)
    {
        ContextEntry_Init const & rEntry = pEntries[ nEntries ];

        if (rEntry.name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_NAME) ))
        {
            rEntry.value >>= m_xSMgr;
        }
        m_map[ rEntry.name ] = new ContextEntry( rEntry.bLateInitService, rEntry.value );
    }

    m_bDisposeSMgr = (m_xSMgr.is() != sal_False);

    // late init singleton services
    if (xRegistry.is())
    {
        Reference< registry::XRegistryKey > xKey( xRegistry->getRootKey() );
        if (xKey.is())
        {
            xKey = xKey->openKey( OUString( RTL_CONSTASCII_USTRINGPARAM("/SINGLETONS") ) );
            if (xKey.is())
            {
                Sequence< Reference< registry::XRegistryKey > > keys( xKey->openKeys() );
                Reference< registry::XRegistryKey > const * pKeys = keys.getConstArray();
                for ( sal_Int32 nPos = keys.getLength(); nPos--; )
                {
                    try
                    {
                        Reference< registry::XRegistryKey > const & xKey = pKeys[ nPos ];
                        m_map[ xKey->getKeyName().copy( sizeof("/SINGLETONS") /* -\0 +'/' */ ) ] =
                            new ContextEntry( true, makeAny( xKey->getStringValue() ) );
                    }
                    catch (Exception & rExc)
                    {
#ifdef _DEBUG
                        OString aStr( OUStringToOString( xKey->getKeyName().copy( 11 ), RTL_TEXTENCODING_ASCII_US ) );
                        OString aStr2( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
                        ::fprintf( stderr, "### failed reading singleton [%s] service name from registry: %s\n", aStr.getStr(), aStr2.getStr() );
#endif
                    }
                }
            }
        }
    }
}

//==================================================================================================
Reference< XComponentContext > SAL_CALL createInitialComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< registry::XSimpleRegistry > const & xRegistry )
    SAL_THROW( () )
{
    return new ComponentContext( pEntries, nEntries, xRegistry );
}

//##################################################################################################
Reference< XComponentContext > SAL_CALL createComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< XComponentContext > const & xDelegate )
    SAL_THROW( () )
{
    if (nEntries > 0)
    {
        return new ComponentContext( pEntries, nEntries, xDelegate );
    }
    else
    {
        return xDelegate;
    }
}

}
<commit_msg>#87233# singleton init<commit_after>/*************************************************************************
 *
 *  $RCSfile: component_context.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: dbo $ $Date: 2001-06-13 08:39:27 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef _DEBUG
#include <stdio.h>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _CPPUHELPER_IMPLBASE1_HXX
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _CPPUHELPER_COMPBASE1_HXX
#include <cppuhelper/compbase1.hxx>
#endif
#ifndef _CPPUHELPER_COMPONENT_CONTEXT_HXX
#include <cppuhelper/component_context.hxx>
#endif

#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>

#include <hash_map>

#define SMGR_NAME "com.sun.star.lang.ServiceManager"
#define TDMGR_NAME "com.sun.star.reflection.TypeDescriptionManager"

using namespace ::osl;
using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;

namespace cppu
{

//==================================================================================================
class Disposer_Impl
    : public WeakImplHelper1< lang::XEventListener >
{
    Reference< lang::XComponent > m_xTarget;

public:
    inline Disposer_Impl( Reference< lang::XComponent > const & xTarget )
        SAL_THROW( () )
        : m_xTarget( xTarget )
        { OSL_ASSERT( m_xTarget.is() ); }

    virtual void SAL_CALL disposing( lang::EventObject const & rSource )
        throw (RuntimeException);
};
//__________________________________________________________________________________________________
void Disposer_Impl::disposing( lang::EventObject const & rSource )
    throw (RuntimeException)
{
    m_xTarget->dispose();
    m_xTarget.clear();
}

//==================================================================================================
struct MutexHolder
{
    Mutex m_mutex;
};
//==================================================================================================
class ComponentContext
    : public MutexHolder
    , public WeakComponentImplHelper1< XComponentContext >
{
    Reference< XComponentContext > m_xDelegate;

    struct ContextEntry
    {
        Any lateInit;
        Any value;

        inline ContextEntry( Any const & lateInit_, Any const & value_ )
            : lateInit( lateInit_ )
            , value( value_ )
            {}
    };
    typedef ::std::hash_map< OUString, ContextEntry *, OUStringHash > t_map;
    t_map m_map;

    Reference< lang::XMultiComponentFactory > m_xSMgr;
    // denotes if service manager has to be disposed by this context,
    // else it was retieved from a delegate which itself has to dispose it
    bool m_bDisposeSMgr;

protected:
    virtual void SAL_CALL disposing();

public:
    ComponentContext(
        ContextEntry_Init const * pEntries, sal_Int32 nEntries,
        Reference< XComponentContext > const & xDelegate )
        SAL_THROW( () );
    ComponentContext(
        ContextEntry_Init const * pEntries, sal_Int32 nEntries,
        Reference< registry::XSimpleRegistry > const & xRegistry )
        SAL_THROW( () );
    virtual ~ComponentContext();

    // XComponentContext
    virtual Any SAL_CALL getValueByName( OUString const & rName )
        throw (RuntimeException);
    virtual Reference< lang::XMultiComponentFactory > SAL_CALL getServiceManager()
        throw (RuntimeException);
};
//__________________________________________________________________________________________________
Any ComponentContext::getValueByName( OUString const & rName )
    throw (RuntimeException)
{
    /** map is anytime untouched, if an uninit value will be inited, synch is done on mutex.
     */

    t_map::const_iterator const iFind( m_map.find( rName ) );
    if (iFind != m_map.end())
    {
        ContextEntry * pEntry = iFind->second;

        if (pEntry->lateInit.hasValue())
        {
            try
            {
                Reference< XInterface > xInstance;

                Reference< lang::XSingleComponentFactory > xFac;
                if (pEntry->lateInit >>= xFac) // try via factory
                {
                    xInstance = xFac->createInstanceWithContext( this );
                }
                else // optionally service name
                {
                    OUString aServiceName;
                    if ((pEntry->lateInit >>= aServiceName) && aServiceName.getLength())
                    {
                        if (m_xSMgr.is())
                        {
                            xInstance = m_xSMgr->createInstanceWithContext( aServiceName, this );
                        }
#ifdef _DEBUG
                        else
                        {
                            ::fprintf( stderr, "### no service manager given for instanciating singletons!\n" );
                        }
#endif
                    }
                }

                if (xInstance.is())
                {
                    ClearableMutexGuard aGuard( m_mutex );
                    if (pEntry->lateInit.hasValue())
                    {
                        pEntry->value.setValue( &xInstance, ::getCppuType( &xInstance ) );
                        pEntry->lateInit.clear();
                    }
                    else // inited in the meantime
                    {
                        aGuard.clear();
                        // service has entered the context in the meantime
                        // => try to dispose this object
                        Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
                        if (xComp.is())
                        {
                            xComp->dispose();
                        }
                    }

                    return pEntry->value;
                }
                else
                {
                    OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_ASCII_US ) );
                    OSL_TRACE( "### cannot raise singleton: $s\n", aStr.getStr() );
                }
            }
            catch (Exception & rExc)
            {
#ifdef _DEBUG
                OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_ASCII_US ) );
                OString aStr2( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
                ::fprintf( stderr, "### exception occured raising singleton %s: %s\n", aStr.getStr(), aStr2.getStr() );
#endif
            }
        }
        else
        {
            return pEntry->value;
        }

        return Any(); // error occured
    }
    else if (m_xDelegate.is())
    {
        return m_xDelegate->getValueByName( rName );
    }

    return Any();
}
//__________________________________________________________________________________________________
Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
    throw (RuntimeException)
{
    return m_xSMgr;
}
//__________________________________________________________________________________________________
ComponentContext::~ComponentContext()
{
#ifdef DEBUG
    ::fprintf( stderr, "> destructed context %p\n", this );
#endif
}
//__________________________________________________________________________________________________
void ComponentContext::disposing()
{
#ifdef DEBUG
    ::fprintf( stderr, "> disposing context %p\n", this );
#endif

    Reference< lang::XComponent > xTDMgr; // to be disposed separately

    // first dispose all context objects
    t_map::const_iterator iPos( m_map.begin() );
    for ( ; iPos != m_map.end(); ++iPos )
    {
        ContextEntry * pEntry = iPos->second;

        // service manager disposed separately
        if (!m_xSMgr.is() || !iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_NAME) ))
        {
            Reference< lang::XComponent > xComp;

            if (pEntry->lateInit.hasValue())
            {
                // may be in late init
                MutexGuard aGuard( m_mutex );
                pEntry->value >>= xComp;
                pEntry->lateInit.clear();
            }
            else
            {
                pEntry->value >>= xComp;
            }

            if (xComp.is())
            {
                if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(TDMGR_NAME) ))
                {
                    // disposed separately
                    xTDMgr = xComp;
                }
                else
                {
                    xComp->dispose();
                }
            }
        }
    }

    // second dispose service manager
    if (m_bDisposeSMgr)
    {
        Reference< lang::XComponent > xComp( m_xSMgr, UNO_QUERY );
        if (xComp.is())
        {
            xComp->dispose();
        }
    }

    // last dispose of tdmgr: revoke callback from cppu runtime
    if (xTDMgr.is())
    {
        xTDMgr->dispose();
    }

    // everything is disposed, hopefully nobody accesses the context anymore...
    for ( iPos = m_map.begin(); iPos != m_map.end(); ++iPos )
    {
        delete iPos->second;
    }

    m_map.clear();
}
//__________________________________________________________________________________________________
ComponentContext::ComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< XComponentContext > const & xDelegate )
    SAL_THROW( () )
    : WeakComponentImplHelper1< XComponentContext >( m_mutex )
    , m_xDelegate( xDelegate )
{
    while (nEntries--)
    {
        ContextEntry_Init const & rEntry = pEntries[ nEntries ];

        if (rEntry.name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_NAME) ))
        {
            rEntry.value >>= m_xSMgr;
        }

        ContextEntry * pEntry;
        if (rEntry.bLateInitService)
        {
            // value is factory or string for late init
            pEntry = new ContextEntry( rEntry.value, Any() );
        }
        else
        {
            // only value, no late init factory nor string
            pEntry = new ContextEntry( Any(), rEntry.value );
        }
        m_map[ rEntry.name ] = pEntry;
    }

    m_bDisposeSMgr = (m_xSMgr.is() != sal_False);

    if (m_xDelegate.is())
    {
        Reference< lang::XComponent > xComp( m_xDelegate, UNO_QUERY );
        OSL_ENSURE( xComp.is(), "### component context should export lang::XComponent!" );
        if (xComp.is())
        {
            xComp->addEventListener( new Disposer_Impl( this ) );
        }
        if (! m_xSMgr.is())
        {
            m_xSMgr = m_xDelegate->getServiceManager();
            m_bDisposeSMgr = false;
        }
    }
}
//__________________________________________________________________________________________________
ComponentContext::ComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< registry::XSimpleRegistry > const & xRegistry )
    SAL_THROW( () )
    : WeakComponentImplHelper1< XComponentContext >( m_mutex )
{
    // inited values
    while (nEntries--)
    {
        ContextEntry_Init const & rEntry = pEntries[ nEntries ];

        if (rEntry.name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_NAME) ))
        {
            rEntry.value >>= m_xSMgr;
        }

        ContextEntry * pEntry;
        if (rEntry.bLateInitService)
        {
            // value is factory or string for late init
            pEntry = new ContextEntry( rEntry.value, Any() );
        }
        else
        {
            // only value, no late init factory nor string
            pEntry = new ContextEntry( Any(), rEntry.value );
        }
        m_map[ rEntry.name ] = pEntry;
    }

    m_bDisposeSMgr = (m_xSMgr.is() != sal_False);

    // late init singleton services
    if (xRegistry.is())
    {
        Reference< registry::XRegistryKey > xKey( xRegistry->getRootKey() );
        if (xKey.is())
        {
            xKey = xKey->openKey( OUString( RTL_CONSTASCII_USTRINGPARAM("/SINGLETONS") ) );
            if (xKey.is())
            {
                Sequence< Reference< registry::XRegistryKey > > keys( xKey->openKeys() );
                Reference< registry::XRegistryKey > const * pKeys = keys.getConstArray();
                for ( sal_Int32 nPos = keys.getLength(); nPos--; )
                {
                    try
                    {
                        Reference< registry::XRegistryKey > const & xKey = pKeys[ nPos ];
                        m_map[ xKey->getKeyName().copy( sizeof("/SINGLETONS") /* -\0 +'/' */ ) ] =
                            new ContextEntry( makeAny( xKey->getStringValue() ), Any() );
                    }
                    catch (Exception & rExc)
                    {
#ifdef _DEBUG
                        OString aStr( OUStringToOString( xKey->getKeyName().copy( 11 ), RTL_TEXTENCODING_ASCII_US ) );
                        OString aStr2( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
                        ::fprintf( stderr, "### failed reading singleton [%s] service name from registry: %s\n", aStr.getStr(), aStr2.getStr() );
#endif
                    }
                }
            }
        }
    }
}

//==================================================================================================
Reference< XComponentContext > SAL_CALL createInitialComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< registry::XSimpleRegistry > const & xRegistry )
    SAL_THROW( () )
{
    return new ComponentContext( pEntries, nEntries, xRegistry );
}

//##################################################################################################
Reference< XComponentContext > SAL_CALL createComponentContext(
    ContextEntry_Init const * pEntries, sal_Int32 nEntries,
    Reference< XComponentContext > const & xDelegate )
    SAL_THROW( () )
{
    if (nEntries > 0)
    {
        return new ComponentContext( pEntries, nEntries, xDelegate );
    }
    else
    {
        return xDelegate;
    }
}

}
<|endoftext|>