101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2017 Thomas Helland 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg * 2301e04c3fSmrg */ 2401e04c3fSmrg 2501e04c3fSmrg#include "string_buffer.h" 2601e04c3fSmrg 2701e04c3fSmrgstatic bool 2801e04c3fSmrgensure_capacity(struct _mesa_string_buffer *str, uint32_t needed_capacity) 2901e04c3fSmrg{ 3001e04c3fSmrg if (needed_capacity <= str->capacity) 3101e04c3fSmrg return true; 3201e04c3fSmrg 3301e04c3fSmrg /* Too small, double until we can fit the new string */ 3401e04c3fSmrg uint32_t new_capacity = str->capacity * 2; 3501e04c3fSmrg while (needed_capacity > new_capacity) 3601e04c3fSmrg new_capacity *= 2; 3701e04c3fSmrg 3801e04c3fSmrg str->buf = reralloc_array_size(str, str->buf, sizeof(char), new_capacity); 3901e04c3fSmrg if (str->buf == NULL) 4001e04c3fSmrg return false; 4101e04c3fSmrg 4201e04c3fSmrg str->capacity = new_capacity; 4301e04c3fSmrg return true; 4401e04c3fSmrg} 4501e04c3fSmrg 4601e04c3fSmrgstruct _mesa_string_buffer * 4701e04c3fSmrg_mesa_string_buffer_create(void *mem_ctx, uint32_t initial_capacity) 4801e04c3fSmrg{ 4901e04c3fSmrg struct _mesa_string_buffer *str; 5001e04c3fSmrg str = ralloc(mem_ctx, struct _mesa_string_buffer); 5101e04c3fSmrg 5201e04c3fSmrg if (str == NULL) 5301e04c3fSmrg return NULL; 5401e04c3fSmrg 5501e04c3fSmrg /* If no initial capacity is set then set it to something */ 5601e04c3fSmrg str->capacity = initial_capacity ? initial_capacity : 32; 5701e04c3fSmrg str->buf = ralloc_array(str, char, str->capacity); 5801e04c3fSmrg 5901e04c3fSmrg if (!str->buf) { 6001e04c3fSmrg ralloc_free(str); 6101e04c3fSmrg return NULL; 6201e04c3fSmrg } 6301e04c3fSmrg 6401e04c3fSmrg str->length = 0; 6501e04c3fSmrg str->buf[str->length] = '\0'; 6601e04c3fSmrg return str; 6701e04c3fSmrg} 6801e04c3fSmrg 6901e04c3fSmrgbool 7001e04c3fSmrg_mesa_string_buffer_append_all(struct _mesa_string_buffer *str, 7101e04c3fSmrg uint32_t num_args, ...) 7201e04c3fSmrg{ 7301e04c3fSmrg int i; 7401e04c3fSmrg char* s; 7501e04c3fSmrg va_list args; 7601e04c3fSmrg va_start(args, num_args); 7701e04c3fSmrg for (i = 0; i < num_args; i++) { 7801e04c3fSmrg s = va_arg(args, char*); 7901e04c3fSmrg if (!_mesa_string_buffer_append_len(str, s, strlen(s))) { 8001e04c3fSmrg va_end(args); 8101e04c3fSmrg return false; 8201e04c3fSmrg } 8301e04c3fSmrg } 8401e04c3fSmrg va_end(args); 8501e04c3fSmrg return true; 8601e04c3fSmrg} 8701e04c3fSmrg 8801e04c3fSmrgbool 8901e04c3fSmrg_mesa_string_buffer_append_len(struct _mesa_string_buffer *str, 9001e04c3fSmrg const char *c, uint32_t len) 9101e04c3fSmrg{ 9201e04c3fSmrg uint32_t needed_length = str->length + len + 1; 9301e04c3fSmrg 9401e04c3fSmrg /* Check if we're overflowing uint32_t */ 9501e04c3fSmrg if (needed_length < str->length) 9601e04c3fSmrg return false; 9701e04c3fSmrg 9801e04c3fSmrg if (!ensure_capacity(str, needed_length)) 9901e04c3fSmrg return false; 10001e04c3fSmrg 10101e04c3fSmrg memcpy(str->buf + str->length, c, len); 10201e04c3fSmrg str->length += len; 10301e04c3fSmrg str->buf[str->length] = '\0'; 10401e04c3fSmrg return true; 10501e04c3fSmrg} 10601e04c3fSmrg 10701e04c3fSmrgbool 10801e04c3fSmrg_mesa_string_buffer_vprintf(struct _mesa_string_buffer *str, 10901e04c3fSmrg const char *format, va_list args) 11001e04c3fSmrg{ 11101e04c3fSmrg /* We're looping two times to avoid duplicating code */ 11201e04c3fSmrg for (uint32_t i = 0; i < 2; i++) { 11301e04c3fSmrg va_list arg_copy; 11401e04c3fSmrg va_copy(arg_copy, args); 11501e04c3fSmrg uint32_t space_left = str->capacity - str->length; 11601e04c3fSmrg 1177ec681f3Smrg int32_t len = vsnprintf(str->buf + str->length, 11801e04c3fSmrg space_left, format, arg_copy); 11901e04c3fSmrg va_end(arg_copy); 12001e04c3fSmrg 12101e04c3fSmrg /* Error in vsnprintf() or measured len overflows size_t */ 12201e04c3fSmrg if (unlikely(len < 0 || str->length + len + 1 < str->length)) 12301e04c3fSmrg return false; 12401e04c3fSmrg 12501e04c3fSmrg /* There was enough space for the string; we're done */ 12601e04c3fSmrg if (len < space_left) { 12701e04c3fSmrg str->length += len; 12801e04c3fSmrg return true; 12901e04c3fSmrg } 13001e04c3fSmrg 13101e04c3fSmrg /* Not enough space, resize and retry */ 13201e04c3fSmrg ensure_capacity(str, str->length + len + 1); 13301e04c3fSmrg } 13401e04c3fSmrg 13501e04c3fSmrg return false; 13601e04c3fSmrg} 13701e04c3fSmrg 13801e04c3fSmrgbool 13901e04c3fSmrg_mesa_string_buffer_printf(struct _mesa_string_buffer *str, 14001e04c3fSmrg const char *format, ...) 14101e04c3fSmrg{ 14201e04c3fSmrg bool res; 14301e04c3fSmrg va_list args; 14401e04c3fSmrg va_start(args, format); 14501e04c3fSmrg res = _mesa_string_buffer_vprintf(str, format, args); 14601e04c3fSmrg va_end(args); 14701e04c3fSmrg return res; 14801e04c3fSmrg} 149