/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: * * Libhashkit library * * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/ * * 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 #include #include #define HASHKIT_BLOCK_SIZE 1024 struct hashkit_string_st { char *end; size_t current_size; char *string; }; inline static bool _string_check(hashkit_string_st *string, size_t need) { if (need and need > (size_t)(string->current_size - (size_t)(string->end - string->string))) { size_t current_offset= (size_t) (string->end - string->string); /* This is the block multiplier. To keep it larger and surive division errors we must round it up */ size_t adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / HASHKIT_BLOCK_SIZE; adjust++; size_t new_size= sizeof(char) * (size_t)((adjust * HASHKIT_BLOCK_SIZE) + string->current_size); /* Test for overflow */ if (new_size < need) { return false; } char *new_value= (char*)realloc(string->string, new_size); if (new_value == NULL) { return false; } string->string= new_value; string->end= string->string + current_offset; string->current_size+= (HASHKIT_BLOCK_SIZE * adjust); } return true; } static inline void _init_string(hashkit_string_st *self) { self->current_size= 0; self->end= self->string= NULL; } hashkit_string_st *hashkit_string_create(size_t initial_size) { hashkit_string_st* self= (hashkit_string_st*)calloc(1, sizeof(hashkit_string_st)); if (self) { if (_string_check(self, initial_size) == false) { free(self); return NULL; } } return self; } #if 0 static bool hashkit_string_append_null(hashkit_string_st *string) { if (_string_check(string, 1) == false) { return false; } *string->end= 0; return true; } #endif bool hashkit_string_append_character(hashkit_string_st *string, char character) { if (_string_check(string, 1) == false) { return false; } *string->end= character; string->end++; return true; } bool hashkit_string_append(hashkit_string_st *string, const char *value, size_t length) { if (_string_check(string, length) == false) { return false; } assert(length <= string->current_size); assert(string->string); assert(string->end >= string->string); memcpy(string->end, value, length); string->end+= length; return true; } char *hashkit_string_c_copy(hashkit_string_st *string) { if (hashkit_string_length(string) == 0) { return NULL; } char *c_ptr= static_cast(malloc((hashkit_string_length(string)+1) * sizeof(char))); if (c_ptr == NULL) { return NULL; } memcpy(c_ptr, hashkit_string_c_str(string), hashkit_string_length(string)); c_ptr[hashkit_string_length(string)]= 0; return c_ptr; } void hashkit_string_reset(hashkit_string_st *string) { string->end= string->string; } void hashkit_string_free(hashkit_string_st *ptr) { if (ptr == NULL) { return; } if (ptr->string) { free(ptr->string); } free(ptr); } bool hashkit_string_resize(hashkit_string_st& string, const size_t need) { return _string_check(&string, need); } size_t hashkit_string_length(const hashkit_string_st *self) { return size_t(self->end -self->string); } size_t hashkit_string_max_size(const hashkit_string_st *self) { return self->current_size; } char *hashkit_string_take(hashkit_string_st *self) { assert(self); if (self == NULL) { return NULL; } char *value= self->string; _init_string(self); return value; } char *hashkit_string_c_str_mutable(hashkit_string_st *self) { assert(self); if (self == NULL) { return NULL; } return self->string; } const char *hashkit_string_c_str(const hashkit_string_st* self) { assert(self); if (self == NULL) { return NULL; } return self->string; } void hashkit_string_set_length(hashkit_string_st *self, size_t length) { assert(self); if (self and _string_check(self, length)) { self->end= self->string +length; } }