1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2010 Intel Corporation
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
21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <assert.h>
25bf215546Sopenharmony_ci#include <stdarg.h>
26bf215546Sopenharmony_ci#include <stdint.h>
27bf215546Sopenharmony_ci#include <stdio.h>
28bf215546Sopenharmony_ci#include <stdlib.h>
29bf215546Sopenharmony_ci#include <string.h>
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "util/macros.h"
32bf215546Sopenharmony_ci#include "util/u_math.h"
33bf215546Sopenharmony_ci#include "util/u_printf.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "ralloc.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#define CANARY 0x5A1106
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci/* Align the header's size so that ralloc() allocations will return with the
40bf215546Sopenharmony_ci * same alignment as a libc malloc would have (8 on 32-bit GLIBC, 16 on
41bf215546Sopenharmony_ci * 64-bit), avoiding performance penalities on x86 and alignment faults on
42bf215546Sopenharmony_ci * ARM.
43bf215546Sopenharmony_ci */
44bf215546Sopenharmony_cistruct ralloc_header
45bf215546Sopenharmony_ci{
46bf215546Sopenharmony_ci#if defined(__LP64__) || defined(_WIN64)
47bf215546Sopenharmony_ci   alignas(16)
48bf215546Sopenharmony_ci#else
49bf215546Sopenharmony_ci   alignas(8)
50bf215546Sopenharmony_ci#endif
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci#ifndef NDEBUG
53bf215546Sopenharmony_ci   /* A canary value used to determine whether a pointer is ralloc'd. */
54bf215546Sopenharmony_ci   unsigned canary;
55bf215546Sopenharmony_ci#endif
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   struct ralloc_header *parent;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   /* The first child (head of a linked list) */
60bf215546Sopenharmony_ci   struct ralloc_header *child;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   /* Linked list of siblings */
63bf215546Sopenharmony_ci   struct ralloc_header *prev;
64bf215546Sopenharmony_ci   struct ralloc_header *next;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   void (*destructor)(void *);
67bf215546Sopenharmony_ci};
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_citypedef struct ralloc_header ralloc_header;
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_cistatic void unlink_block(ralloc_header *info);
72bf215546Sopenharmony_cistatic void unsafe_free(ralloc_header *info);
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic ralloc_header *
75bf215546Sopenharmony_ciget_header(const void *ptr)
76bf215546Sopenharmony_ci{
77bf215546Sopenharmony_ci   ralloc_header *info = (ralloc_header *) (((char *) ptr) -
78bf215546Sopenharmony_ci					    sizeof(ralloc_header));
79bf215546Sopenharmony_ci   assert(info->canary == CANARY);
80bf215546Sopenharmony_ci   return info;
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci#define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_cistatic void
86bf215546Sopenharmony_ciadd_child(ralloc_header *parent, ralloc_header *info)
87bf215546Sopenharmony_ci{
88bf215546Sopenharmony_ci   if (parent != NULL) {
89bf215546Sopenharmony_ci      info->parent = parent;
90bf215546Sopenharmony_ci      info->next = parent->child;
91bf215546Sopenharmony_ci      parent->child = info;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci      if (info->next != NULL)
94bf215546Sopenharmony_ci	 info->next->prev = info;
95bf215546Sopenharmony_ci   }
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_civoid *
99bf215546Sopenharmony_ciralloc_context(const void *ctx)
100bf215546Sopenharmony_ci{
101bf215546Sopenharmony_ci   return ralloc_size(ctx, 0);
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_civoid *
105bf215546Sopenharmony_ciralloc_size(const void *ctx, size_t size)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci   /* Some malloc allocation doesn't always align to 16 bytes even on 64 bits
108bf215546Sopenharmony_ci    * system, from Android bionic/tests/malloc_test.cpp:
109bf215546Sopenharmony_ci    *  - Allocations of a size that rounds up to a multiple of 16 bytes
110bf215546Sopenharmony_ci    *    must have at least 16 byte alignment.
111bf215546Sopenharmony_ci    *  - Allocations of a size that rounds up to a multiple of 8 bytes and
112bf215546Sopenharmony_ci    *    not 16 bytes, are only required to have at least 8 byte alignment.
113bf215546Sopenharmony_ci    */
114bf215546Sopenharmony_ci   void *block = malloc(align64(size + sizeof(ralloc_header),
115bf215546Sopenharmony_ci                                alignof(ralloc_header)));
116bf215546Sopenharmony_ci   ralloc_header *info;
117bf215546Sopenharmony_ci   ralloc_header *parent;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   if (unlikely(block == NULL))
120bf215546Sopenharmony_ci      return NULL;
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci   info = (ralloc_header *) block;
123bf215546Sopenharmony_ci   /* measurements have shown that calloc is slower (because of
124bf215546Sopenharmony_ci    * the multiplication overflow checking?), so clear things
125bf215546Sopenharmony_ci    * manually
126bf215546Sopenharmony_ci    */
127bf215546Sopenharmony_ci   info->parent = NULL;
128bf215546Sopenharmony_ci   info->child = NULL;
129bf215546Sopenharmony_ci   info->prev = NULL;
130bf215546Sopenharmony_ci   info->next = NULL;
131bf215546Sopenharmony_ci   info->destructor = NULL;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   parent = ctx != NULL ? get_header(ctx) : NULL;
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   add_child(parent, info);
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci#ifndef NDEBUG
138bf215546Sopenharmony_ci   info->canary = CANARY;
139bf215546Sopenharmony_ci#endif
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   return PTR_FROM_HEADER(info);
142bf215546Sopenharmony_ci}
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_civoid *
145bf215546Sopenharmony_cirzalloc_size(const void *ctx, size_t size)
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   void *ptr = ralloc_size(ctx, size);
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   if (likely(ptr))
150bf215546Sopenharmony_ci      memset(ptr, 0, size);
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   return ptr;
153bf215546Sopenharmony_ci}
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci/* helper function - assumes ptr != NULL */
156bf215546Sopenharmony_cistatic void *
157bf215546Sopenharmony_ciresize(void *ptr, size_t size)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci   ralloc_header *child, *old, *info;
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   old = get_header(ptr);
162bf215546Sopenharmony_ci   info = realloc(old, align64(size + sizeof(ralloc_header),
163bf215546Sopenharmony_ci                               alignof(ralloc_header)));
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   if (info == NULL)
166bf215546Sopenharmony_ci      return NULL;
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   /* Update parent and sibling's links to the reallocated node. */
169bf215546Sopenharmony_ci   if (info != old && info->parent != NULL) {
170bf215546Sopenharmony_ci      if (info->parent->child == old)
171bf215546Sopenharmony_ci	 info->parent->child = info;
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci      if (info->prev != NULL)
174bf215546Sopenharmony_ci	 info->prev->next = info;
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci      if (info->next != NULL)
177bf215546Sopenharmony_ci	 info->next->prev = info;
178bf215546Sopenharmony_ci   }
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   /* Update child->parent links for all children */
181bf215546Sopenharmony_ci   for (child = info->child; child != NULL; child = child->next)
182bf215546Sopenharmony_ci      child->parent = info;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   return PTR_FROM_HEADER(info);
185bf215546Sopenharmony_ci}
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_civoid *
188bf215546Sopenharmony_cireralloc_size(const void *ctx, void *ptr, size_t size)
189bf215546Sopenharmony_ci{
190bf215546Sopenharmony_ci   if (unlikely(ptr == NULL))
191bf215546Sopenharmony_ci      return ralloc_size(ctx, size);
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   assert(ralloc_parent(ptr) == ctx);
194bf215546Sopenharmony_ci   return resize(ptr, size);
195bf215546Sopenharmony_ci}
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_civoid *
198bf215546Sopenharmony_cirerzalloc_size(const void *ctx, void *ptr, size_t old_size, size_t new_size)
199bf215546Sopenharmony_ci{
200bf215546Sopenharmony_ci   if (unlikely(ptr == NULL))
201bf215546Sopenharmony_ci      return rzalloc_size(ctx, new_size);
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   assert(ralloc_parent(ptr) == ctx);
204bf215546Sopenharmony_ci   ptr = resize(ptr, new_size);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   if (new_size > old_size)
207bf215546Sopenharmony_ci      memset((char *)ptr + old_size, 0, new_size - old_size);
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci   return ptr;
210bf215546Sopenharmony_ci}
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_civoid *
213bf215546Sopenharmony_ciralloc_array_size(const void *ctx, size_t size, unsigned count)
214bf215546Sopenharmony_ci{
215bf215546Sopenharmony_ci   if (count > SIZE_MAX/size)
216bf215546Sopenharmony_ci      return NULL;
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   return ralloc_size(ctx, size * count);
219bf215546Sopenharmony_ci}
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_civoid *
222bf215546Sopenharmony_cirzalloc_array_size(const void *ctx, size_t size, unsigned count)
223bf215546Sopenharmony_ci{
224bf215546Sopenharmony_ci   if (count > SIZE_MAX/size)
225bf215546Sopenharmony_ci      return NULL;
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci   return rzalloc_size(ctx, size * count);
228bf215546Sopenharmony_ci}
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_civoid *
231bf215546Sopenharmony_cireralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
232bf215546Sopenharmony_ci{
233bf215546Sopenharmony_ci   if (count > SIZE_MAX/size)
234bf215546Sopenharmony_ci      return NULL;
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   return reralloc_size(ctx, ptr, size * count);
237bf215546Sopenharmony_ci}
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_civoid *
240bf215546Sopenharmony_cirerzalloc_array_size(const void *ctx, void *ptr, size_t size,
241bf215546Sopenharmony_ci                     unsigned old_count, unsigned new_count)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci   if (new_count > SIZE_MAX/size)
244bf215546Sopenharmony_ci      return NULL;
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   return rerzalloc_size(ctx, ptr, size * old_count, size * new_count);
247bf215546Sopenharmony_ci}
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_civoid
250bf215546Sopenharmony_ciralloc_free(void *ptr)
251bf215546Sopenharmony_ci{
252bf215546Sopenharmony_ci   ralloc_header *info;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   if (ptr == NULL)
255bf215546Sopenharmony_ci      return;
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   info = get_header(ptr);
258bf215546Sopenharmony_ci   unlink_block(info);
259bf215546Sopenharmony_ci   unsafe_free(info);
260bf215546Sopenharmony_ci}
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_cistatic void
263bf215546Sopenharmony_ciunlink_block(ralloc_header *info)
264bf215546Sopenharmony_ci{
265bf215546Sopenharmony_ci   /* Unlink from parent & siblings */
266bf215546Sopenharmony_ci   if (info->parent != NULL) {
267bf215546Sopenharmony_ci      if (info->parent->child == info)
268bf215546Sopenharmony_ci	 info->parent->child = info->next;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci      if (info->prev != NULL)
271bf215546Sopenharmony_ci	 info->prev->next = info->next;
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci      if (info->next != NULL)
274bf215546Sopenharmony_ci	 info->next->prev = info->prev;
275bf215546Sopenharmony_ci   }
276bf215546Sopenharmony_ci   info->parent = NULL;
277bf215546Sopenharmony_ci   info->prev = NULL;
278bf215546Sopenharmony_ci   info->next = NULL;
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_cistatic void
282bf215546Sopenharmony_ciunsafe_free(ralloc_header *info)
283bf215546Sopenharmony_ci{
284bf215546Sopenharmony_ci   /* Recursively free any children...don't waste time unlinking them. */
285bf215546Sopenharmony_ci   ralloc_header *temp;
286bf215546Sopenharmony_ci   while (info->child != NULL) {
287bf215546Sopenharmony_ci      temp = info->child;
288bf215546Sopenharmony_ci      info->child = temp->next;
289bf215546Sopenharmony_ci      unsafe_free(temp);
290bf215546Sopenharmony_ci   }
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   /* Free the block itself.  Call the destructor first, if any. */
293bf215546Sopenharmony_ci   if (info->destructor != NULL)
294bf215546Sopenharmony_ci      info->destructor(PTR_FROM_HEADER(info));
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   free(info);
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_civoid
300bf215546Sopenharmony_ciralloc_steal(const void *new_ctx, void *ptr)
301bf215546Sopenharmony_ci{
302bf215546Sopenharmony_ci   ralloc_header *info, *parent;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   if (unlikely(ptr == NULL))
305bf215546Sopenharmony_ci      return;
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   info = get_header(ptr);
308bf215546Sopenharmony_ci   parent = new_ctx ? get_header(new_ctx) : NULL;
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   unlink_block(info);
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci   add_child(parent, info);
313bf215546Sopenharmony_ci}
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_civoid
316bf215546Sopenharmony_ciralloc_adopt(const void *new_ctx, void *old_ctx)
317bf215546Sopenharmony_ci{
318bf215546Sopenharmony_ci   ralloc_header *new_info, *old_info, *child;
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci   if (unlikely(old_ctx == NULL))
321bf215546Sopenharmony_ci      return;
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci   old_info = get_header(old_ctx);
324bf215546Sopenharmony_ci   new_info = get_header(new_ctx);
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   /* If there are no children, bail. */
327bf215546Sopenharmony_ci   if (unlikely(old_info->child == NULL))
328bf215546Sopenharmony_ci      return;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   /* Set all the children's parent to new_ctx; get a pointer to the last child. */
331bf215546Sopenharmony_ci   for (child = old_info->child; child->next != NULL; child = child->next) {
332bf215546Sopenharmony_ci      child->parent = new_info;
333bf215546Sopenharmony_ci   }
334bf215546Sopenharmony_ci   child->parent = new_info;
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   /* Connect the two lists together; parent them to new_ctx; make old_ctx empty. */
337bf215546Sopenharmony_ci   child->next = new_info->child;
338bf215546Sopenharmony_ci   if (child->next)
339bf215546Sopenharmony_ci      child->next->prev = child;
340bf215546Sopenharmony_ci   new_info->child = old_info->child;
341bf215546Sopenharmony_ci   old_info->child = NULL;
342bf215546Sopenharmony_ci}
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_civoid *
345bf215546Sopenharmony_ciralloc_parent(const void *ptr)
346bf215546Sopenharmony_ci{
347bf215546Sopenharmony_ci   ralloc_header *info;
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   if (unlikely(ptr == NULL))
350bf215546Sopenharmony_ci      return NULL;
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci   info = get_header(ptr);
353bf215546Sopenharmony_ci   return info->parent ? PTR_FROM_HEADER(info->parent) : NULL;
354bf215546Sopenharmony_ci}
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_civoid
357bf215546Sopenharmony_ciralloc_set_destructor(const void *ptr, void(*destructor)(void *))
358bf215546Sopenharmony_ci{
359bf215546Sopenharmony_ci   ralloc_header *info = get_header(ptr);
360bf215546Sopenharmony_ci   info->destructor = destructor;
361bf215546Sopenharmony_ci}
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_cichar *
364bf215546Sopenharmony_ciralloc_strdup(const void *ctx, const char *str)
365bf215546Sopenharmony_ci{
366bf215546Sopenharmony_ci   size_t n;
367bf215546Sopenharmony_ci   char *ptr;
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   if (unlikely(str == NULL))
370bf215546Sopenharmony_ci      return NULL;
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci   n = strlen(str);
373bf215546Sopenharmony_ci   ptr = ralloc_array(ctx, char, n + 1);
374bf215546Sopenharmony_ci   memcpy(ptr, str, n);
375bf215546Sopenharmony_ci   ptr[n] = '\0';
376bf215546Sopenharmony_ci   return ptr;
377bf215546Sopenharmony_ci}
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_cichar *
380bf215546Sopenharmony_ciralloc_strndup(const void *ctx, const char *str, size_t max)
381bf215546Sopenharmony_ci{
382bf215546Sopenharmony_ci   size_t n;
383bf215546Sopenharmony_ci   char *ptr;
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci   if (unlikely(str == NULL))
386bf215546Sopenharmony_ci      return NULL;
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci   n = strnlen(str, max);
389bf215546Sopenharmony_ci   ptr = ralloc_array(ctx, char, n + 1);
390bf215546Sopenharmony_ci   memcpy(ptr, str, n);
391bf215546Sopenharmony_ci   ptr[n] = '\0';
392bf215546Sopenharmony_ci   return ptr;
393bf215546Sopenharmony_ci}
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci/* helper routine for strcat/strncat - n is the exact amount to copy */
396bf215546Sopenharmony_cistatic bool
397bf215546Sopenharmony_cicat(char **dest, const char *str, size_t n)
398bf215546Sopenharmony_ci{
399bf215546Sopenharmony_ci   char *both;
400bf215546Sopenharmony_ci   size_t existing_length;
401bf215546Sopenharmony_ci   assert(dest != NULL && *dest != NULL);
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci   existing_length = strlen(*dest);
404bf215546Sopenharmony_ci   both = resize(*dest, existing_length + n + 1);
405bf215546Sopenharmony_ci   if (unlikely(both == NULL))
406bf215546Sopenharmony_ci      return false;
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci   memcpy(both + existing_length, str, n);
409bf215546Sopenharmony_ci   both[existing_length + n] = '\0';
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   *dest = both;
412bf215546Sopenharmony_ci   return true;
413bf215546Sopenharmony_ci}
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_cibool
417bf215546Sopenharmony_ciralloc_strcat(char **dest, const char *str)
418bf215546Sopenharmony_ci{
419bf215546Sopenharmony_ci   return cat(dest, str, strlen(str));
420bf215546Sopenharmony_ci}
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_cibool
423bf215546Sopenharmony_ciralloc_strncat(char **dest, const char *str, size_t n)
424bf215546Sopenharmony_ci{
425bf215546Sopenharmony_ci   return cat(dest, str, strnlen(str, n));
426bf215546Sopenharmony_ci}
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_cibool
429bf215546Sopenharmony_ciralloc_str_append(char **dest, const char *str,
430bf215546Sopenharmony_ci                  size_t existing_length, size_t str_size)
431bf215546Sopenharmony_ci{
432bf215546Sopenharmony_ci   char *both;
433bf215546Sopenharmony_ci   assert(dest != NULL && *dest != NULL);
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci   both = resize(*dest, existing_length + str_size + 1);
436bf215546Sopenharmony_ci   if (unlikely(both == NULL))
437bf215546Sopenharmony_ci      return false;
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci   memcpy(both + existing_length, str, str_size);
440bf215546Sopenharmony_ci   both[existing_length + str_size] = '\0';
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   *dest = both;
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   return true;
445bf215546Sopenharmony_ci}
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_cichar *
448bf215546Sopenharmony_ciralloc_asprintf(const void *ctx, const char *fmt, ...)
449bf215546Sopenharmony_ci{
450bf215546Sopenharmony_ci   char *ptr;
451bf215546Sopenharmony_ci   va_list args;
452bf215546Sopenharmony_ci   va_start(args, fmt);
453bf215546Sopenharmony_ci   ptr = ralloc_vasprintf(ctx, fmt, args);
454bf215546Sopenharmony_ci   va_end(args);
455bf215546Sopenharmony_ci   return ptr;
456bf215546Sopenharmony_ci}
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_cichar *
459bf215546Sopenharmony_ciralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
460bf215546Sopenharmony_ci{
461bf215546Sopenharmony_ci   size_t size = u_printf_length(fmt, args) + 1;
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   char *ptr = ralloc_size(ctx, size);
464bf215546Sopenharmony_ci   if (ptr != NULL)
465bf215546Sopenharmony_ci      vsnprintf(ptr, size, fmt, args);
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci   return ptr;
468bf215546Sopenharmony_ci}
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_cibool
471bf215546Sopenharmony_ciralloc_asprintf_append(char **str, const char *fmt, ...)
472bf215546Sopenharmony_ci{
473bf215546Sopenharmony_ci   bool success;
474bf215546Sopenharmony_ci   va_list args;
475bf215546Sopenharmony_ci   va_start(args, fmt);
476bf215546Sopenharmony_ci   success = ralloc_vasprintf_append(str, fmt, args);
477bf215546Sopenharmony_ci   va_end(args);
478bf215546Sopenharmony_ci   return success;
479bf215546Sopenharmony_ci}
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_cibool
482bf215546Sopenharmony_ciralloc_vasprintf_append(char **str, const char *fmt, va_list args)
483bf215546Sopenharmony_ci{
484bf215546Sopenharmony_ci   size_t existing_length;
485bf215546Sopenharmony_ci   assert(str != NULL);
486bf215546Sopenharmony_ci   existing_length = *str ? strlen(*str) : 0;
487bf215546Sopenharmony_ci   return ralloc_vasprintf_rewrite_tail(str, &existing_length, fmt, args);
488bf215546Sopenharmony_ci}
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_cibool
491bf215546Sopenharmony_ciralloc_asprintf_rewrite_tail(char **str, size_t *start, const char *fmt, ...)
492bf215546Sopenharmony_ci{
493bf215546Sopenharmony_ci   bool success;
494bf215546Sopenharmony_ci   va_list args;
495bf215546Sopenharmony_ci   va_start(args, fmt);
496bf215546Sopenharmony_ci   success = ralloc_vasprintf_rewrite_tail(str, start, fmt, args);
497bf215546Sopenharmony_ci   va_end(args);
498bf215546Sopenharmony_ci   return success;
499bf215546Sopenharmony_ci}
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_cibool
502bf215546Sopenharmony_ciralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
503bf215546Sopenharmony_ci			      va_list args)
504bf215546Sopenharmony_ci{
505bf215546Sopenharmony_ci   size_t new_length;
506bf215546Sopenharmony_ci   char *ptr;
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   assert(str != NULL);
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci   if (unlikely(*str == NULL)) {
511bf215546Sopenharmony_ci      // Assuming a NULL context is probably bad, but it's expected behavior.
512bf215546Sopenharmony_ci      *str = ralloc_vasprintf(NULL, fmt, args);
513bf215546Sopenharmony_ci      *start = strlen(*str);
514bf215546Sopenharmony_ci      return true;
515bf215546Sopenharmony_ci   }
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   new_length = u_printf_length(fmt, args);
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   ptr = resize(*str, *start + new_length + 1);
520bf215546Sopenharmony_ci   if (unlikely(ptr == NULL))
521bf215546Sopenharmony_ci      return false;
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   vsnprintf(ptr + *start, new_length + 1, fmt, args);
524bf215546Sopenharmony_ci   *str = ptr;
525bf215546Sopenharmony_ci   *start += new_length;
526bf215546Sopenharmony_ci   return true;
527bf215546Sopenharmony_ci}
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci/***************************************************************************
530bf215546Sopenharmony_ci * Linear allocator for short-lived allocations.
531bf215546Sopenharmony_ci ***************************************************************************
532bf215546Sopenharmony_ci *
533bf215546Sopenharmony_ci * The allocator consists of a parent node (2K buffer), which requires
534bf215546Sopenharmony_ci * a ralloc parent, and child nodes (allocations). Child nodes can't be freed
535bf215546Sopenharmony_ci * directly, because the parent doesn't track them. You have to release
536bf215546Sopenharmony_ci * the parent node in order to release all its children.
537bf215546Sopenharmony_ci *
538bf215546Sopenharmony_ci * The allocator uses a fixed-sized buffer with a monotonically increasing
539bf215546Sopenharmony_ci * offset after each allocation. If the buffer is all used, another buffer
540bf215546Sopenharmony_ci * is allocated, sharing the same ralloc parent, so all buffers are at
541bf215546Sopenharmony_ci * the same level in the ralloc hierarchy.
542bf215546Sopenharmony_ci *
543bf215546Sopenharmony_ci * The linear parent node is always the first buffer and keeps track of all
544bf215546Sopenharmony_ci * other buffers.
545bf215546Sopenharmony_ci */
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci#define MIN_LINEAR_BUFSIZE 2048
548bf215546Sopenharmony_ci#define SUBALLOC_ALIGNMENT 8
549bf215546Sopenharmony_ci#define LMAGIC 0x87b9c7d3
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_cistruct linear_header {
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   /* align first member to align struct */
554bf215546Sopenharmony_ci#if defined(__LP64__) || defined(_WIN64)
555bf215546Sopenharmony_ci   alignas(16)
556bf215546Sopenharmony_ci#else
557bf215546Sopenharmony_ci   alignas(8)
558bf215546Sopenharmony_ci#endif
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci#ifndef NDEBUG
561bf215546Sopenharmony_ci   unsigned magic;   /* for debugging */
562bf215546Sopenharmony_ci#endif
563bf215546Sopenharmony_ci   unsigned offset;  /* points to the first unused byte in the buffer */
564bf215546Sopenharmony_ci   unsigned size;    /* size of the buffer */
565bf215546Sopenharmony_ci   void *ralloc_parent;          /* new buffers will use this */
566bf215546Sopenharmony_ci   struct linear_header *next;   /* next buffer if we have more */
567bf215546Sopenharmony_ci   struct linear_header *latest; /* the only buffer that has free space */
568bf215546Sopenharmony_ci
569bf215546Sopenharmony_ci   /* After this structure, the buffer begins.
570bf215546Sopenharmony_ci    * Each suballocation consists of linear_size_chunk as its header followed
571bf215546Sopenharmony_ci    * by the suballocation, so it goes:
572bf215546Sopenharmony_ci    *
573bf215546Sopenharmony_ci    * - linear_size_chunk
574bf215546Sopenharmony_ci    * - allocated space
575bf215546Sopenharmony_ci    * - linear_size_chunk
576bf215546Sopenharmony_ci    * - allocated space
577bf215546Sopenharmony_ci    * etc.
578bf215546Sopenharmony_ci    *
579bf215546Sopenharmony_ci    * linear_size_chunk is only needed by linear_realloc.
580bf215546Sopenharmony_ci    */
581bf215546Sopenharmony_ci};
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_cistruct linear_size_chunk {
584bf215546Sopenharmony_ci   unsigned size; /* for realloc */
585bf215546Sopenharmony_ci   unsigned _padding;
586bf215546Sopenharmony_ci};
587bf215546Sopenharmony_ci
588bf215546Sopenharmony_citypedef struct linear_header linear_header;
589bf215546Sopenharmony_citypedef struct linear_size_chunk linear_size_chunk;
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci#define LINEAR_PARENT_TO_HEADER(parent) \
592bf215546Sopenharmony_ci   (linear_header*) \
593bf215546Sopenharmony_ci   ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header))
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci/* Allocate the linear buffer with its header. */
596bf215546Sopenharmony_cistatic linear_header *
597bf215546Sopenharmony_cicreate_linear_node(void *ralloc_ctx, unsigned min_size)
598bf215546Sopenharmony_ci{
599bf215546Sopenharmony_ci   linear_header *node;
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ci   min_size += sizeof(linear_size_chunk);
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_ci   if (likely(min_size < MIN_LINEAR_BUFSIZE))
604bf215546Sopenharmony_ci      min_size = MIN_LINEAR_BUFSIZE;
605bf215546Sopenharmony_ci
606bf215546Sopenharmony_ci   node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size);
607bf215546Sopenharmony_ci   if (unlikely(!node))
608bf215546Sopenharmony_ci      return NULL;
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ci#ifndef NDEBUG
611bf215546Sopenharmony_ci   node->magic = LMAGIC;
612bf215546Sopenharmony_ci#endif
613bf215546Sopenharmony_ci   node->offset = 0;
614bf215546Sopenharmony_ci   node->size = min_size;
615bf215546Sopenharmony_ci   node->ralloc_parent = ralloc_ctx;
616bf215546Sopenharmony_ci   node->next = NULL;
617bf215546Sopenharmony_ci   node->latest = node;
618bf215546Sopenharmony_ci   return node;
619bf215546Sopenharmony_ci}
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_civoid *
622bf215546Sopenharmony_cilinear_alloc_child(void *parent, unsigned size)
623bf215546Sopenharmony_ci{
624bf215546Sopenharmony_ci   linear_header *first = LINEAR_PARENT_TO_HEADER(parent);
625bf215546Sopenharmony_ci   linear_header *latest = first->latest;
626bf215546Sopenharmony_ci   linear_header *new_node;
627bf215546Sopenharmony_ci   linear_size_chunk *ptr;
628bf215546Sopenharmony_ci   unsigned full_size;
629bf215546Sopenharmony_ci
630bf215546Sopenharmony_ci   assert(first->magic == LMAGIC);
631bf215546Sopenharmony_ci   assert(!latest->next);
632bf215546Sopenharmony_ci
633bf215546Sopenharmony_ci   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
634bf215546Sopenharmony_ci   full_size = sizeof(linear_size_chunk) + size;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   if (unlikely(latest->offset + full_size > latest->size)) {
637bf215546Sopenharmony_ci      /* allocate a new node */
638bf215546Sopenharmony_ci      new_node = create_linear_node(latest->ralloc_parent, size);
639bf215546Sopenharmony_ci      if (unlikely(!new_node))
640bf215546Sopenharmony_ci         return NULL;
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_ci      first->latest = new_node;
643bf215546Sopenharmony_ci      latest->latest = new_node;
644bf215546Sopenharmony_ci      latest->next = new_node;
645bf215546Sopenharmony_ci      latest = new_node;
646bf215546Sopenharmony_ci   }
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci   ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset);
649bf215546Sopenharmony_ci   ptr->size = size;
650bf215546Sopenharmony_ci   latest->offset += full_size;
651bf215546Sopenharmony_ci
652bf215546Sopenharmony_ci   assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0);
653bf215546Sopenharmony_ci   return &ptr[1];
654bf215546Sopenharmony_ci}
655bf215546Sopenharmony_ci
656bf215546Sopenharmony_civoid *
657bf215546Sopenharmony_cilinear_alloc_parent(void *ralloc_ctx, unsigned size)
658bf215546Sopenharmony_ci{
659bf215546Sopenharmony_ci   linear_header *node;
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci   if (unlikely(!ralloc_ctx))
662bf215546Sopenharmony_ci      return NULL;
663bf215546Sopenharmony_ci
664bf215546Sopenharmony_ci   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
665bf215546Sopenharmony_ci
666bf215546Sopenharmony_ci   node = create_linear_node(ralloc_ctx, size);
667bf215546Sopenharmony_ci   if (unlikely(!node))
668bf215546Sopenharmony_ci      return NULL;
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci   return linear_alloc_child((char*)node +
671bf215546Sopenharmony_ci                             sizeof(linear_header) +
672bf215546Sopenharmony_ci                             sizeof(linear_size_chunk), size);
673bf215546Sopenharmony_ci}
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_civoid *
676bf215546Sopenharmony_cilinear_zalloc_child(void *parent, unsigned size)
677bf215546Sopenharmony_ci{
678bf215546Sopenharmony_ci   void *ptr = linear_alloc_child(parent, size);
679bf215546Sopenharmony_ci
680bf215546Sopenharmony_ci   if (likely(ptr))
681bf215546Sopenharmony_ci      memset(ptr, 0, size);
682bf215546Sopenharmony_ci   return ptr;
683bf215546Sopenharmony_ci}
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_civoid *
686bf215546Sopenharmony_cilinear_zalloc_parent(void *parent, unsigned size)
687bf215546Sopenharmony_ci{
688bf215546Sopenharmony_ci   void *ptr = linear_alloc_parent(parent, size);
689bf215546Sopenharmony_ci
690bf215546Sopenharmony_ci   if (likely(ptr))
691bf215546Sopenharmony_ci      memset(ptr, 0, size);
692bf215546Sopenharmony_ci   return ptr;
693bf215546Sopenharmony_ci}
694bf215546Sopenharmony_ci
695bf215546Sopenharmony_civoid
696bf215546Sopenharmony_cilinear_free_parent(void *ptr)
697bf215546Sopenharmony_ci{
698bf215546Sopenharmony_ci   linear_header *node;
699bf215546Sopenharmony_ci
700bf215546Sopenharmony_ci   if (unlikely(!ptr))
701bf215546Sopenharmony_ci      return;
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci   node = LINEAR_PARENT_TO_HEADER(ptr);
704bf215546Sopenharmony_ci   assert(node->magic == LMAGIC);
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_ci   while (node) {
707bf215546Sopenharmony_ci      void *ptr = node;
708bf215546Sopenharmony_ci
709bf215546Sopenharmony_ci      node = node->next;
710bf215546Sopenharmony_ci      ralloc_free(ptr);
711bf215546Sopenharmony_ci   }
712bf215546Sopenharmony_ci}
713bf215546Sopenharmony_ci
714bf215546Sopenharmony_civoid
715bf215546Sopenharmony_ciralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr)
716bf215546Sopenharmony_ci{
717bf215546Sopenharmony_ci   linear_header *node;
718bf215546Sopenharmony_ci
719bf215546Sopenharmony_ci   if (unlikely(!ptr))
720bf215546Sopenharmony_ci      return;
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci   node = LINEAR_PARENT_TO_HEADER(ptr);
723bf215546Sopenharmony_ci   assert(node->magic == LMAGIC);
724bf215546Sopenharmony_ci
725bf215546Sopenharmony_ci   while (node) {
726bf215546Sopenharmony_ci      ralloc_steal(new_ralloc_ctx, node);
727bf215546Sopenharmony_ci      node->ralloc_parent = new_ralloc_ctx;
728bf215546Sopenharmony_ci      node = node->next;
729bf215546Sopenharmony_ci   }
730bf215546Sopenharmony_ci}
731bf215546Sopenharmony_ci
732bf215546Sopenharmony_civoid *
733bf215546Sopenharmony_ciralloc_parent_of_linear_parent(void *ptr)
734bf215546Sopenharmony_ci{
735bf215546Sopenharmony_ci   linear_header *node = LINEAR_PARENT_TO_HEADER(ptr);
736bf215546Sopenharmony_ci   assert(node->magic == LMAGIC);
737bf215546Sopenharmony_ci   return node->ralloc_parent;
738bf215546Sopenharmony_ci}
739bf215546Sopenharmony_ci
740bf215546Sopenharmony_civoid *
741bf215546Sopenharmony_cilinear_realloc(void *parent, void *old, unsigned new_size)
742bf215546Sopenharmony_ci{
743bf215546Sopenharmony_ci   unsigned old_size = 0;
744bf215546Sopenharmony_ci   ralloc_header *new_ptr;
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_ci   new_ptr = linear_alloc_child(parent, new_size);
747bf215546Sopenharmony_ci
748bf215546Sopenharmony_ci   if (unlikely(!old))
749bf215546Sopenharmony_ci      return new_ptr;
750bf215546Sopenharmony_ci
751bf215546Sopenharmony_ci   old_size = ((linear_size_chunk*)old)[-1].size;
752bf215546Sopenharmony_ci
753bf215546Sopenharmony_ci   if (likely(new_ptr && old_size))
754bf215546Sopenharmony_ci      memcpy(new_ptr, old, MIN2(old_size, new_size));
755bf215546Sopenharmony_ci
756bf215546Sopenharmony_ci   return new_ptr;
757bf215546Sopenharmony_ci}
758bf215546Sopenharmony_ci
759bf215546Sopenharmony_ci/* All code below is pretty much copied from ralloc and only the alloc
760bf215546Sopenharmony_ci * calls are different.
761bf215546Sopenharmony_ci */
762bf215546Sopenharmony_ci
763bf215546Sopenharmony_cichar *
764bf215546Sopenharmony_cilinear_strdup(void *parent, const char *str)
765bf215546Sopenharmony_ci{
766bf215546Sopenharmony_ci   unsigned n;
767bf215546Sopenharmony_ci   char *ptr;
768bf215546Sopenharmony_ci
769bf215546Sopenharmony_ci   if (unlikely(!str))
770bf215546Sopenharmony_ci      return NULL;
771bf215546Sopenharmony_ci
772bf215546Sopenharmony_ci   n = strlen(str);
773bf215546Sopenharmony_ci   ptr = linear_alloc_child(parent, n + 1);
774bf215546Sopenharmony_ci   if (unlikely(!ptr))
775bf215546Sopenharmony_ci      return NULL;
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci   memcpy(ptr, str, n);
778bf215546Sopenharmony_ci   ptr[n] = '\0';
779bf215546Sopenharmony_ci   return ptr;
780bf215546Sopenharmony_ci}
781bf215546Sopenharmony_ci
782bf215546Sopenharmony_cichar *
783bf215546Sopenharmony_cilinear_asprintf(void *parent, const char *fmt, ...)
784bf215546Sopenharmony_ci{
785bf215546Sopenharmony_ci   char *ptr;
786bf215546Sopenharmony_ci   va_list args;
787bf215546Sopenharmony_ci   va_start(args, fmt);
788bf215546Sopenharmony_ci   ptr = linear_vasprintf(parent, fmt, args);
789bf215546Sopenharmony_ci   va_end(args);
790bf215546Sopenharmony_ci   return ptr;
791bf215546Sopenharmony_ci}
792bf215546Sopenharmony_ci
793bf215546Sopenharmony_cichar *
794bf215546Sopenharmony_cilinear_vasprintf(void *parent, const char *fmt, va_list args)
795bf215546Sopenharmony_ci{
796bf215546Sopenharmony_ci   unsigned size = u_printf_length(fmt, args) + 1;
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_ci   char *ptr = linear_alloc_child(parent, size);
799bf215546Sopenharmony_ci   if (ptr != NULL)
800bf215546Sopenharmony_ci      vsnprintf(ptr, size, fmt, args);
801bf215546Sopenharmony_ci
802bf215546Sopenharmony_ci   return ptr;
803bf215546Sopenharmony_ci}
804bf215546Sopenharmony_ci
805bf215546Sopenharmony_cibool
806bf215546Sopenharmony_cilinear_asprintf_append(void *parent, char **str, const char *fmt, ...)
807bf215546Sopenharmony_ci{
808bf215546Sopenharmony_ci   bool success;
809bf215546Sopenharmony_ci   va_list args;
810bf215546Sopenharmony_ci   va_start(args, fmt);
811bf215546Sopenharmony_ci   success = linear_vasprintf_append(parent, str, fmt, args);
812bf215546Sopenharmony_ci   va_end(args);
813bf215546Sopenharmony_ci   return success;
814bf215546Sopenharmony_ci}
815bf215546Sopenharmony_ci
816bf215546Sopenharmony_cibool
817bf215546Sopenharmony_cilinear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args)
818bf215546Sopenharmony_ci{
819bf215546Sopenharmony_ci   size_t existing_length;
820bf215546Sopenharmony_ci   assert(str != NULL);
821bf215546Sopenharmony_ci   existing_length = *str ? strlen(*str) : 0;
822bf215546Sopenharmony_ci   return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args);
823bf215546Sopenharmony_ci}
824bf215546Sopenharmony_ci
825bf215546Sopenharmony_cibool
826bf215546Sopenharmony_cilinear_asprintf_rewrite_tail(void *parent, char **str, size_t *start,
827bf215546Sopenharmony_ci                             const char *fmt, ...)
828bf215546Sopenharmony_ci{
829bf215546Sopenharmony_ci   bool success;
830bf215546Sopenharmony_ci   va_list args;
831bf215546Sopenharmony_ci   va_start(args, fmt);
832bf215546Sopenharmony_ci   success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args);
833bf215546Sopenharmony_ci   va_end(args);
834bf215546Sopenharmony_ci   return success;
835bf215546Sopenharmony_ci}
836bf215546Sopenharmony_ci
837bf215546Sopenharmony_cibool
838bf215546Sopenharmony_cilinear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
839bf215546Sopenharmony_ci                              const char *fmt, va_list args)
840bf215546Sopenharmony_ci{
841bf215546Sopenharmony_ci   size_t new_length;
842bf215546Sopenharmony_ci   char *ptr;
843bf215546Sopenharmony_ci
844bf215546Sopenharmony_ci   assert(str != NULL);
845bf215546Sopenharmony_ci
846bf215546Sopenharmony_ci   if (unlikely(*str == NULL)) {
847bf215546Sopenharmony_ci      *str = linear_vasprintf(parent, fmt, args);
848bf215546Sopenharmony_ci      *start = strlen(*str);
849bf215546Sopenharmony_ci      return true;
850bf215546Sopenharmony_ci   }
851bf215546Sopenharmony_ci
852bf215546Sopenharmony_ci   new_length = u_printf_length(fmt, args);
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci   ptr = linear_realloc(parent, *str, *start + new_length + 1);
855bf215546Sopenharmony_ci   if (unlikely(ptr == NULL))
856bf215546Sopenharmony_ci      return false;
857bf215546Sopenharmony_ci
858bf215546Sopenharmony_ci   vsnprintf(ptr + *start, new_length + 1, fmt, args);
859bf215546Sopenharmony_ci   *str = ptr;
860bf215546Sopenharmony_ci   *start += new_length;
861bf215546Sopenharmony_ci   return true;
862bf215546Sopenharmony_ci}
863bf215546Sopenharmony_ci
864bf215546Sopenharmony_ci/* helper routine for strcat/strncat - n is the exact amount to copy */
865bf215546Sopenharmony_cistatic bool
866bf215546Sopenharmony_cilinear_cat(void *parent, char **dest, const char *str, unsigned n)
867bf215546Sopenharmony_ci{
868bf215546Sopenharmony_ci   char *both;
869bf215546Sopenharmony_ci   unsigned existing_length;
870bf215546Sopenharmony_ci   assert(dest != NULL && *dest != NULL);
871bf215546Sopenharmony_ci
872bf215546Sopenharmony_ci   existing_length = strlen(*dest);
873bf215546Sopenharmony_ci   both = linear_realloc(parent, *dest, existing_length + n + 1);
874bf215546Sopenharmony_ci   if (unlikely(both == NULL))
875bf215546Sopenharmony_ci      return false;
876bf215546Sopenharmony_ci
877bf215546Sopenharmony_ci   memcpy(both + existing_length, str, n);
878bf215546Sopenharmony_ci   both[existing_length + n] = '\0';
879bf215546Sopenharmony_ci
880bf215546Sopenharmony_ci   *dest = both;
881bf215546Sopenharmony_ci   return true;
882bf215546Sopenharmony_ci}
883bf215546Sopenharmony_ci
884bf215546Sopenharmony_cibool
885bf215546Sopenharmony_cilinear_strcat(void *parent, char **dest, const char *str)
886bf215546Sopenharmony_ci{
887bf215546Sopenharmony_ci   return linear_cat(parent, dest, str, strlen(str));
888bf215546Sopenharmony_ci}
889