1*4226f635SJason King /* 2*4226f635SJason King * This file and its contents are supplied under the terms of the 3*4226f635SJason King * Common Development and Distribution License ("CDDL"), version 1.0. 4*4226f635SJason King * You may only use this file in accordance with the terms of version 5*4226f635SJason King * 1.0 of the CDDL. 6*4226f635SJason King * 7*4226f635SJason King * A full copy of the text of the CDDL should have accompanied this 8*4226f635SJason King * source. A copy of the CDDL is also available via the Internet at 9*4226f635SJason King * http://www.illumos.org/license/CDDL. 10*4226f635SJason King */ 11*4226f635SJason King 12*4226f635SJason King /* 13*4226f635SJason King * Copyright 2017 Jason King 14*4226f635SJason King */ 15*4226f635SJason King #include <sys/debug.h> 16*4226f635SJason King #include <sys/sysmacros.h> 17*4226f635SJason King #include <string.h> 18*4226f635SJason King #include "str.h" 19*4226f635SJason King #include "demangle_int.h" 20*4226f635SJason King 21*4226f635SJason King #define STR_CHUNK_SZ (64U) 22*4226f635SJason King 23*4226f635SJason King /* are we storing a reference vs. a dynamically allocated copy? */ 24*4226f635SJason King #define IS_REF(s) ((s)->str_s != NULL && (s)->str_size == 0) 25*4226f635SJason King 26*4226f635SJason King /* 27*4226f635SJason King * Dynamically resizeable strings, with lazy allocation when initialized 28*4226f635SJason King * with a constant string value 29*4226f635SJason King * 30*4226f635SJason King * NOTE: these are not necessairly 0-terminated 31*4226f635SJason King * 32*4226f635SJason King * Additionally, these can store references instead of copies of strings 33*4226f635SJason King * (as indicated by the IS_REF() macro. However mutation may cause a 34*4226f635SJason King * string to convert from a refence to a dynamically allocated copy. 35*4226f635SJason King */ 36*4226f635SJason King 37*4226f635SJason King void 38*4226f635SJason King str_init(str_t *restrict s, sysdem_ops_t *restrict ops) 39*4226f635SJason King { 40*4226f635SJason King (void) memset(s, 0, sizeof (*s)); 41*4226f635SJason King s->str_ops = (ops != NULL) ? ops : sysdem_ops_default; 42*4226f635SJason King } 43*4226f635SJason King 44*4226f635SJason King void 45*4226f635SJason King str_fini(str_t *s) 46*4226f635SJason King { 47*4226f635SJason King if (s == NULL) 48*4226f635SJason King return; 49*4226f635SJason King if (!IS_REF(s)) 50*4226f635SJason King xfree(s->str_ops, s->str_s, s->str_size); 51*4226f635SJason King (void) memset(s, 0, sizeof (*s)); 52*4226f635SJason King } 53*4226f635SJason King 54*4226f635SJason King size_t 55*4226f635SJason King str_length(const str_t *s) 56*4226f635SJason King { 57*4226f635SJason King return (s->str_len); 58*4226f635SJason King } 59*4226f635SJason King 60*4226f635SJason King /* 61*4226f635SJason King * store as a reference instead of a copy 62*4226f635SJason King * if len == 0, means store entire copy of 0 terminated string 63*4226f635SJason King */ 64*4226f635SJason King void 65*4226f635SJason King str_set(str_t *s, const char *cstr, size_t len) 66*4226f635SJason King { 67*4226f635SJason King sysdem_ops_t *ops = s->str_ops; 68*4226f635SJason King 69*4226f635SJason King str_fini(s); 70*4226f635SJason King s->str_ops = ops; 71*4226f635SJason King s->str_s = (char *)cstr; 72*4226f635SJason King s->str_len = (len == 0 && cstr != NULL) ? strlen(cstr) : len; 73*4226f635SJason King } 74*4226f635SJason King 75*4226f635SJason King boolean_t 76*4226f635SJason King str_copy(const str_t *src, str_t *dest) 77*4226f635SJason King { 78*4226f635SJason King str_fini(dest); 79*4226f635SJason King str_init(dest, src->str_ops); 80*4226f635SJason King 81*4226f635SJason King if (src->str_len == 0) 82*4226f635SJason King return (B_TRUE); 83*4226f635SJason King 84*4226f635SJason King size_t len = roundup(src->str_len, STR_CHUNK_SZ); 85*4226f635SJason King dest->str_s = zalloc(src->str_ops, len); 86*4226f635SJason King if (dest->str_s == NULL) 87*4226f635SJason King return (B_FALSE); 88*4226f635SJason King 89*4226f635SJason King (void) memcpy(dest->str_s, src->str_s, src->str_len); 90*4226f635SJason King dest->str_len = src->str_len; 91*4226f635SJason King dest->str_size = len; 92*4226f635SJason King 93*4226f635SJason King return (B_TRUE); 94*4226f635SJason King } 95*4226f635SJason King 96*4226f635SJason King /* 97*4226f635SJason King * ensure s has at least amt bytes free, resizing if necessary 98*4226f635SJason King */ 99*4226f635SJason King static boolean_t 100*4226f635SJason King str_reserve(str_t *s, size_t amt) 101*4226f635SJason King { 102*4226f635SJason King size_t newlen = s->str_len + amt; 103*4226f635SJason King 104*4226f635SJason King /* overflow check */ 105*4226f635SJason King if (newlen < s->str_len || newlen < amt) 106*4226f635SJason King return (B_FALSE); 107*4226f635SJason King 108*4226f635SJason King if ((amt > 0) && (s->str_len + amt <= s->str_size)) 109*4226f635SJason King return (B_TRUE); 110*4226f635SJason King 111*4226f635SJason King size_t newsize = roundup(newlen, STR_CHUNK_SZ); 112*4226f635SJason King void *temp; 113*4226f635SJason King 114*4226f635SJason King if (IS_REF(s)) { 115*4226f635SJason King temp = zalloc(s->str_ops, newsize); 116*4226f635SJason King if (temp == NULL) 117*4226f635SJason King return (B_FALSE); 118*4226f635SJason King 119*4226f635SJason King (void) memcpy(temp, s->str_s, s->str_len); 120*4226f635SJason King } else { 121*4226f635SJason King temp = xrealloc(s->str_ops, s->str_s, s->str_size, newsize); 122*4226f635SJason King if (temp == NULL) 123*4226f635SJason King return (B_FALSE); 124*4226f635SJason King } 125*4226f635SJason King 126*4226f635SJason King s->str_s = temp; 127*4226f635SJason King s->str_size = newsize; 128*4226f635SJason King 129*4226f635SJason King return (B_TRUE); 130*4226f635SJason King } 131*4226f635SJason King 132*4226f635SJason King /* append to s, cstrlen == 0 means entire length of string */ 133*4226f635SJason King boolean_t 134*4226f635SJason King str_append(str_t *s, const char *cstr, size_t cstrlen) 135*4226f635SJason King { 136*4226f635SJason King if (cstr != NULL && cstrlen == 0) 137*4226f635SJason King cstrlen = strlen(cstr); 138*4226f635SJason King 139*4226f635SJason King const str_t src = { 140*4226f635SJason King .str_s = (char *)cstr, 141*4226f635SJason King .str_len = cstrlen, 142*4226f635SJason King .str_ops = s->str_ops 143*4226f635SJason King }; 144*4226f635SJason King 145*4226f635SJason King return (str_append_str(s, &src)); 146*4226f635SJason King } 147*4226f635SJason King 148*4226f635SJason King boolean_t 149*4226f635SJason King str_append_str(str_t *dest, const str_t *src) 150*4226f635SJason King { 151*4226f635SJason King /* empty string is a noop */ 152*4226f635SJason King if (src->str_s == NULL || src->str_len == 0) 153*4226f635SJason King return (B_TRUE); 154*4226f635SJason King 155*4226f635SJason King /* if src is a reference, we can just copy that */ 156*4226f635SJason King if (dest->str_s == NULL && IS_REF(src)) { 157*4226f635SJason King *dest = *src; 158*4226f635SJason King return (B_TRUE); 159*4226f635SJason King } 160*4226f635SJason King 161*4226f635SJason King if (!str_reserve(dest, src->str_len)) 162*4226f635SJason King return (B_FALSE); 163*4226f635SJason King 164*4226f635SJason King (void) memcpy(dest->str_s + dest->str_len, src->str_s, src->str_len); 165*4226f635SJason King dest->str_len += src->str_len; 166*4226f635SJason King return (B_TRUE); 167*4226f635SJason King } 168*4226f635SJason King 169*4226f635SJason King boolean_t 170*4226f635SJason King str_append_c(str_t *s, char c) 171*4226f635SJason King { 172*4226f635SJason King if (!str_reserve(s, 1)) 173*4226f635SJason King return (B_FALSE); 174*4226f635SJason King 175*4226f635SJason King s->str_s[s->str_len++] = c; 176*4226f635SJason King return (B_TRUE); 177*4226f635SJason King } 178*4226f635SJason King 179*4226f635SJason King boolean_t 180*4226f635SJason King str_insert(str_t *s, size_t idx, const char *cstr, size_t cstrlen) 181*4226f635SJason King { 182*4226f635SJason King if (cstr == NULL) 183*4226f635SJason King return (B_TRUE); 184*4226f635SJason King 185*4226f635SJason King if (cstrlen == 0) 186*4226f635SJason King cstrlen = strlen(cstr); 187*4226f635SJason King 188*4226f635SJason King str_t src = { 189*4226f635SJason King .str_s = (char *)cstr, 190*4226f635SJason King .str_len = cstrlen, 191*4226f635SJason King .str_ops = s->str_ops, 192*4226f635SJason King .str_size = 0 193*4226f635SJason King }; 194*4226f635SJason King 195*4226f635SJason King return (str_insert_str(s, idx, &src)); 196*4226f635SJason King } 197*4226f635SJason King 198*4226f635SJason King boolean_t 199*4226f635SJason King str_insert_str(str_t *dest, size_t idx, const str_t *src) 200*4226f635SJason King { 201*4226f635SJason King ASSERT3U(idx, <=, dest->str_len); 202*4226f635SJason King 203*4226f635SJason King if (idx == dest->str_len) 204*4226f635SJason King return (str_append_str(dest, src)); 205*4226f635SJason King 206*4226f635SJason King if (idx == 0 && dest->str_s == NULL && IS_REF(src)) { 207*4226f635SJason King sysdem_ops_t *ops = dest->str_ops; 208*4226f635SJason King *dest = *src; 209*4226f635SJason King dest->str_ops = ops; 210*4226f635SJason King return (B_TRUE); 211*4226f635SJason King } 212*4226f635SJason King 213*4226f635SJason King if (!str_reserve(dest, src->str_len)) 214*4226f635SJason King return (B_FALSE); 215*4226f635SJason King 216*4226f635SJason King /* 217*4226f635SJason King * Shift the contents of dest over at the insertion point. Since 218*4226f635SJason King * src and dest ranges will overlap, and unlike some programmers, 219*4226f635SJason King * *I* can read man pages - memmove() is the appropriate function 220*4226f635SJason King * to this. 221*4226f635SJason King */ 222*4226f635SJason King (void) memmove(dest->str_s + idx + src->str_len, dest->str_s + idx, 223*4226f635SJason King dest->str_len - idx); 224*4226f635SJason King 225*4226f635SJason King /* 226*4226f635SJason King * However the content to insert does not overlap with the destination 227*4226f635SJason King * so memcpy() is fine here. 228*4226f635SJason King */ 229*4226f635SJason King (void) memcpy(dest->str_s + idx, src->str_s, src->str_len); 230*4226f635SJason King dest->str_len += src->str_len; 231*4226f635SJason King 232*4226f635SJason King return (B_TRUE); 233*4226f635SJason King } 234*4226f635SJason King 235*4226f635SJason King boolean_t 236*4226f635SJason King str_erase(str_t *s, size_t pos, size_t len) 237*4226f635SJason King { 238*4226f635SJason King ASSERT3U(pos, <, s->str_len); 239*4226f635SJason King ASSERT3U(pos + len, <=, s->str_len); 240*4226f635SJason King 241*4226f635SJason King if (IS_REF(s)) { 242*4226f635SJason King if (!str_reserve(s, 0)) 243*4226f635SJason King return (B_FALSE); 244*4226f635SJason King } 245*4226f635SJason King 246*4226f635SJason King (void) memmove(s->str_s + pos, s->str_s + pos + len, s->str_len - len); 247*4226f635SJason King s->str_len -= len; 248*4226f635SJason King return (B_TRUE); 249*4226f635SJason King } 250*4226f635SJason King 251*4226f635SJason King str_pair_t * 252*4226f635SJason King str_pair_init(str_pair_t *sp, sysdem_ops_t *ops) 253*4226f635SJason King { 254*4226f635SJason King (void) memset(sp, 0, sizeof (*sp)); 255*4226f635SJason King str_init(&sp->strp_l, ops); 256*4226f635SJason King str_init(&sp->strp_r, ops); 257*4226f635SJason King return (sp); 258*4226f635SJason King } 259*4226f635SJason King 260*4226f635SJason King void 261*4226f635SJason King str_pair_fini(str_pair_t *sp) 262*4226f635SJason King { 263*4226f635SJason King str_fini(&sp->strp_l); 264*4226f635SJason King str_fini(&sp->strp_r); 265*4226f635SJason King } 266*4226f635SJason King 267*4226f635SJason King /* combine left and right parts and put result into left part */ 268*4226f635SJason King boolean_t 269*4226f635SJason King str_pair_merge(str_pair_t *sp) 270*4226f635SJason King { 271*4226f635SJason King /* if right side is empty, don't need to do anything */ 272*4226f635SJason King if (str_length(&sp->strp_r) == 0) 273*4226f635SJason King return (B_TRUE); 274*4226f635SJason King 275*4226f635SJason King /* if left side is empty, just move right to left */ 276*4226f635SJason King if (str_length(&sp->strp_l) == 0) { 277*4226f635SJason King str_fini(&sp->strp_l); 278*4226f635SJason King sp->strp_l = sp->strp_r; 279*4226f635SJason King sp->strp_r.str_s = NULL; 280*4226f635SJason King sp->strp_r.str_len = sp->strp_r.str_size = 0; 281*4226f635SJason King return (B_TRUE); 282*4226f635SJason King } 283*4226f635SJason King 284*4226f635SJason King if (!str_append_str(&sp->strp_l, &sp->strp_r)) 285*4226f635SJason King return (B_FALSE); 286*4226f635SJason King 287*4226f635SJason King str_fini(&sp->strp_r); 288*4226f635SJason King str_init(&sp->strp_r, sp->strp_l.str_ops); 289*4226f635SJason King return (B_TRUE); 290*4226f635SJason King } 291*4226f635SJason King 292*4226f635SJason King boolean_t 293*4226f635SJason King str_pair_copy(const str_pair_t *src, str_pair_t *dest) 294*4226f635SJason King { 295*4226f635SJason King boolean_t ok = B_TRUE; 296*4226f635SJason King 297*4226f635SJason King ok &= str_copy(&src->strp_l, &dest->strp_l); 298*4226f635SJason King ok &= str_copy(&src->strp_r, &dest->strp_r); 299*4226f635SJason King 300*4226f635SJason King if (!ok) { 301*4226f635SJason King str_fini(&dest->strp_l); 302*4226f635SJason King str_fini(&dest->strp_r); 303*4226f635SJason King return (B_FALSE); 304*4226f635SJason King } 305*4226f635SJason King 306*4226f635SJason King return (B_TRUE); 307*4226f635SJason King } 308*4226f635SJason King 309*4226f635SJason King size_t 310*4226f635SJason King str_pair_len(const str_pair_t *sp) 311*4226f635SJason King { 312*4226f635SJason King return (str_length(&sp->strp_l) + str_length(&sp->strp_r)); 313*4226f635SJason King } 314