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