1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2017 Thomas Helland
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include "string_buffer.h"
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_cistatic bool
28bf215546Sopenharmony_ciensure_capacity(struct _mesa_string_buffer *str, uint32_t needed_capacity)
29bf215546Sopenharmony_ci{
30bf215546Sopenharmony_ci   if (needed_capacity <= str->capacity)
31bf215546Sopenharmony_ci      return true;
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci   /* Too small, double until we can fit the new string */
34bf215546Sopenharmony_ci   uint32_t new_capacity = str->capacity * 2;
35bf215546Sopenharmony_ci   while (needed_capacity > new_capacity)
36bf215546Sopenharmony_ci      new_capacity *= 2;
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci   str->buf = reralloc_array_size(str, str->buf, sizeof(char), new_capacity);
39bf215546Sopenharmony_ci   if (str->buf == NULL)
40bf215546Sopenharmony_ci      return false;
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci   str->capacity = new_capacity;
43bf215546Sopenharmony_ci   return true;
44bf215546Sopenharmony_ci}
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_cistruct _mesa_string_buffer *
47bf215546Sopenharmony_ci_mesa_string_buffer_create(void *mem_ctx, uint32_t initial_capacity)
48bf215546Sopenharmony_ci{
49bf215546Sopenharmony_ci   struct _mesa_string_buffer *str;
50bf215546Sopenharmony_ci   str = ralloc(mem_ctx, struct _mesa_string_buffer);
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   if (str == NULL)
53bf215546Sopenharmony_ci      return NULL;
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci   /* If no initial capacity is set then set it to something */
56bf215546Sopenharmony_ci   str->capacity = initial_capacity ? initial_capacity : 32;
57bf215546Sopenharmony_ci   str->buf = ralloc_array(str, char, str->capacity);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   if (!str->buf) {
60bf215546Sopenharmony_ci      ralloc_free(str);
61bf215546Sopenharmony_ci      return NULL;
62bf215546Sopenharmony_ci   }
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   str->length = 0;
65bf215546Sopenharmony_ci   str->buf[str->length] = '\0';
66bf215546Sopenharmony_ci   return str;
67bf215546Sopenharmony_ci}
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_cibool
70bf215546Sopenharmony_ci_mesa_string_buffer_append_all(struct _mesa_string_buffer *str,
71bf215546Sopenharmony_ci                               uint32_t num_args, ...)
72bf215546Sopenharmony_ci{
73bf215546Sopenharmony_ci   int i;
74bf215546Sopenharmony_ci   char* s;
75bf215546Sopenharmony_ci   va_list args;
76bf215546Sopenharmony_ci   va_start(args, num_args);
77bf215546Sopenharmony_ci   for (i = 0; i < num_args; i++) {
78bf215546Sopenharmony_ci      s = va_arg(args, char*);
79bf215546Sopenharmony_ci      if (!_mesa_string_buffer_append_len(str, s, strlen(s))) {
80bf215546Sopenharmony_ci         va_end(args);
81bf215546Sopenharmony_ci         return false;
82bf215546Sopenharmony_ci      }
83bf215546Sopenharmony_ci   }
84bf215546Sopenharmony_ci   va_end(args);
85bf215546Sopenharmony_ci   return true;
86bf215546Sopenharmony_ci}
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_cibool
89bf215546Sopenharmony_ci_mesa_string_buffer_append_len(struct _mesa_string_buffer *str,
90bf215546Sopenharmony_ci                               const char *c, uint32_t len)
91bf215546Sopenharmony_ci{
92bf215546Sopenharmony_ci   uint32_t needed_length = str->length + len + 1;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   /* Check if we're overflowing uint32_t */
95bf215546Sopenharmony_ci   if (needed_length < str->length)
96bf215546Sopenharmony_ci      return false;
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   if (!ensure_capacity(str, needed_length))
99bf215546Sopenharmony_ci      return false;
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   memcpy(str->buf + str->length, c, len);
102bf215546Sopenharmony_ci   str->length += len;
103bf215546Sopenharmony_ci   str->buf[str->length] = '\0';
104bf215546Sopenharmony_ci   return true;
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cibool
108bf215546Sopenharmony_ci_mesa_string_buffer_vprintf(struct _mesa_string_buffer *str,
109bf215546Sopenharmony_ci                            const char *format, va_list args)
110bf215546Sopenharmony_ci{
111bf215546Sopenharmony_ci   /* We're looping two times to avoid duplicating code */
112bf215546Sopenharmony_ci   for (uint32_t i = 0; i < 2; i++) {
113bf215546Sopenharmony_ci      va_list arg_copy;
114bf215546Sopenharmony_ci      va_copy(arg_copy, args);
115bf215546Sopenharmony_ci      uint32_t space_left = str->capacity - str->length;
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci      int32_t len = vsnprintf(str->buf + str->length,
118bf215546Sopenharmony_ci                                   space_left, format, arg_copy);
119bf215546Sopenharmony_ci      va_end(arg_copy);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci      /* Error in vsnprintf() or measured len overflows size_t */
122bf215546Sopenharmony_ci      if (unlikely(len < 0 || str->length + len + 1 < str->length))
123bf215546Sopenharmony_ci         return false;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci      /* There was enough space for the string; we're done */
126bf215546Sopenharmony_ci      if (len < space_left) {
127bf215546Sopenharmony_ci         str->length += len;
128bf215546Sopenharmony_ci         return true;
129bf215546Sopenharmony_ci      }
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci      /* Not enough space, resize and retry */
132bf215546Sopenharmony_ci      ensure_capacity(str, str->length + len + 1);
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   return false;
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_cibool
139bf215546Sopenharmony_ci_mesa_string_buffer_printf(struct _mesa_string_buffer *str,
140bf215546Sopenharmony_ci                            const char *format, ...)
141bf215546Sopenharmony_ci{
142bf215546Sopenharmony_ci   bool res;
143bf215546Sopenharmony_ci   va_list args;
144bf215546Sopenharmony_ci   va_start(args, format);
145bf215546Sopenharmony_ci   res = _mesa_string_buffer_vprintf(str, format, args);
146bf215546Sopenharmony_ci   va_end(args);
147bf215546Sopenharmony_ci   return res;
148bf215546Sopenharmony_ci}
149