1 #include "first.h" 2 3 #include "array.h" 4 #include "buffer.h" 5 6 #include <string.h> 7 #include <stdlib.h> 8 #include <limits.h> 9 10 __attribute_cold__ 11 static void array_extend(array * const a, uint32_t n) { 12 /* This data structure should not be used for nearly so many entries */ 13 force_assert(a->size <= INT32_MAX-n); 14 a->size += n; 15 a->data = realloc(a->data, sizeof(*a->data) * a->size); 16 a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size); 17 force_assert(a->data); 18 force_assert(a->sorted); 19 memset(a->data+a->used, 0, (a->size-a->used)*sizeof(*a->data)); 20 } 21 22 array *array_init(uint32_t n) { 23 array *a; 24 25 a = calloc(1, sizeof(*a)); 26 force_assert(a); 27 if (n) array_extend(a, n); 28 29 return a; 30 } 31 32 void array_free_data(array * const a) { 33 if (a->sorted) free(a->sorted); 34 data_unset ** const data = a->data; 35 const uint32_t sz = a->size; 36 for (uint32_t i = 0; i < sz; ++i) { 37 if (data[i]) data[i]->fn->free(data[i]); 38 } 39 free(data); 40 a->data = NULL; 41 a->sorted = NULL; 42 a->used = 0; 43 a->size = 0; 44 } 45 46 void array_copy_array(array * const dst, const array * const src) { 47 array_free_data(dst); 48 if (0 == src->size) return; 49 50 array_extend(dst, src->size); 51 for (uint32_t i = 0; i < src->used; ++i) { 52 array_insert_unique(dst, src->data[i]->fn->copy(src->data[i])); 53 } 54 } 55 56 void array_free(array * const a) { 57 if (!a) return; 58 array_free_data(a); 59 free(a); 60 } 61 62 void array_reset_data_strings(array * const a) { 63 if (!a) return; 64 65 data_string ** const data = (data_string **)a->data; 66 const uint32_t used = a->used; 67 a->used = 0; 68 for (uint32_t i = 0; i < used; ++i) { 69 data_string * const ds = data[i]; 70 /*force_assert(ds->type == TYPE_STRING);*/ 71 buffer_reset(&ds->key); 72 buffer_reset(&ds->value); 73 } 74 } 75 76 #if 0 /*(unused; see array_extract_element_klen())*/ 77 data_unset *array_pop(array * const a) { 78 data_unset *du; 79 80 force_assert(a->used != 0); 81 82 a->used --; 83 du = a->data[a->used]; 84 force_assert(a->sorted[a->used] == du); /* only works on "simple" lists */ 85 a->data[a->used] = NULL; 86 87 return du; 88 } 89 #endif 90 91 __attribute_pure__ 92 static int array_caseless_compare(const char * const a, const char * const b, const uint32_t len) { 93 for (uint32_t i = 0; i < len; ++i) { 94 unsigned int ca = ((unsigned char *)a)[i]; 95 unsigned int cb = ((unsigned char *)b)[i]; 96 if (ca == cb) continue; 97 98 /* always lowercase for transitive results */ 99 if (light_isupper(ca)) ca |= 0x20; 100 if (light_isupper(cb)) cb |= 0x20; 101 102 if (ca == cb) continue; 103 return (int)(ca - cb); 104 } 105 return 0; 106 } 107 108 __attribute_pure__ 109 static int array_keycmp(const char * const a, const uint32_t alen, const char * const b, const uint32_t blen) { 110 return alen < blen ? -1 : alen > blen ? 1 : array_caseless_compare(a, b, blen); 111 } 112 113 __attribute_cold__ 114 __attribute_pure__ 115 static int array_keycmpb(const char * const k, const uint32_t klen, const buffer * const b) { 116 /* key is non-empty (0==b->used), though possibly blank (1==b->used) 117 * if inserted into key-value array */ 118 /*force_assert(b && b->used);*/ 119 return array_keycmp(k, klen, b->ptr, b->used-1); 120 /*return array_keycmp(k, klen, CONST_BUF_LEN(b));*/ 121 } 122 123 /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[] 124 * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[] 125 * where the key needs to be inserted (-1 to avoid -0) 126 */ 127 __attribute_hot__ 128 __attribute_pure__ 129 static int32_t array_get_index_ext(const array * const a, const int ext, const char * const k, const uint32_t klen) { 130 /* invariant: [lower-1] < probe < [upper] 131 * invariant: 0 <= lower <= upper <= a->used 132 */ 133 uint32_t lower = 0, upper = a->used; 134 while (lower != upper) { 135 const uint32_t probe = (lower + upper) / 2; 136 const int x = ((data_string *)a->sorted[probe])->ext; 137 /* (compare strings only if ext is 0 for both)*/ 138 const int e = (ext|x) 139 ? ext 140 : array_keycmpb(k, klen, &a->sorted[probe]->key); 141 if (e < x) /* e < [probe] */ 142 upper = probe; /* still: lower <= upper */ 143 else if (e > x) /* e > [probe] */ 144 lower = probe + 1; /* still: lower <= upper */ 145 else /*(e == x)*/ /* found */ 146 return (int32_t)probe; 147 } 148 /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 149 return -(int)lower - 1; 150 } 151 152 data_unset *array_get_element_klen_ext(const array * const a, const int ext, const char *key, const uint32_t klen) { 153 const int32_t ipos = array_get_index_ext(a, ext, key, klen); 154 return ipos >= 0 ? a->sorted[ipos] : NULL; 155 } 156 157 /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[] 158 * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[] 159 * where the key needs to be inserted (-1 to avoid -0) 160 */ 161 __attribute_hot__ 162 __attribute_pure__ 163 static int32_t array_get_index(const array * const a, const char * const k, const uint32_t klen) { 164 /* invariant: [lower-1] < probe < [upper] 165 * invariant: 0 <= lower <= upper <= a->used 166 */ 167 uint32_t lower = 0, upper = a->used; 168 while (lower != upper) { 169 uint32_t probe = (lower + upper) / 2; 170 const buffer * const b = &a->sorted[probe]->key; 171 /* key is non-empty (0==b->used), though possibly blank (1==b->used), 172 * if inserted into key-value array */ 173 /*force_assert(b && b->used);*/ 174 int cmp = array_keycmp(k, klen, b->ptr, b->used-1); 175 /*int cmp = array_keycmp(k, klen, CONST_BUF_LEN(b));*/ 176 if (cmp < 0) /* key < [probe] */ 177 upper = probe; /* still: lower <= upper */ 178 else if (cmp > 0) /* key > [probe] */ 179 lower = probe + 1; /* still: lower <= upper */ 180 else /*(cmp == 0)*/ /* found */ 181 return (int32_t)probe; 182 } 183 /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 184 return -(int)lower - 1; 185 } 186 187 __attribute_hot__ 188 const data_unset *array_get_element_klen(const array * const a, const char *key, const uint32_t klen) { 189 const int32_t ipos = array_get_index(a, key, klen); 190 return ipos >= 0 ? a->sorted[ipos] : NULL; 191 } 192 193 /* non-const (data_config *) for configparser.y (not array_get_element_klen())*/ 194 data_unset *array_get_data_unset(const array * const a, const char *key, const uint32_t klen) { 195 const int32_t ipos = array_get_index(a, key, klen); 196 return ipos >= 0 ? a->sorted[ipos] : NULL; 197 } 198 199 data_unset *array_extract_element_klen(array * const a, const char *key, const uint32_t klen) { 200 const int32_t ipos = array_get_index(a, key, klen); 201 if (ipos < 0) return NULL; 202 203 /* remove entry from a->sorted: move everything after pos one step left */ 204 data_unset * const entry = a->sorted[ipos]; 205 const uint32_t last_ndx = --a->used; 206 if (last_ndx != (uint32_t)ipos) { 207 data_unset ** const d = a->sorted + ipos; 208 memmove(d, d+1, (last_ndx - (uint32_t)ipos) * sizeof(*d)); 209 } 210 211 if (entry != a->data[last_ndx]) { 212 /* walk a->data[] to find data ptr */ 213 /* (not checking (ndx <= last_ndx) since entry must be in a->data[]) */ 214 uint32_t ndx = 0; 215 while (entry != a->data[ndx]) ++ndx; 216 a->data[ndx] = a->data[last_ndx]; /* swap with last element */ 217 } 218 a->data[last_ndx] = NULL; 219 return entry; 220 } 221 222 static data_unset *array_get_unused_element(array * const a, const data_type_t t) { 223 /* After initial startup and config, most array usage is of homogeneous types 224 * and arrays are cleared once per request, so check only the first unused 225 * element to see if it can be reused */ 226 #if 1 227 data_unset * const du = (a->used < a->size) ? a->data[a->used] : NULL; 228 if (NULL != du && du->type == t) { 229 a->data[a->used] = NULL;/* make empty slot at a->used for next insert */ 230 return du; 231 } 232 return NULL; 233 #else 234 data_unset ** const data = a->data; 235 for (uint32_t i = a->used, sz = a->size; i < sz; ++i) { 236 if (data[i] && data[i]->type == t) { 237 data_unset * const ds = data[i]; 238 239 /* make empty slot at a->used for next insert */ 240 data[i] = data[a->used]; 241 data[a->used] = NULL; 242 243 return ds; 244 } 245 } 246 247 return NULL; 248 #endif 249 } 250 251 __attribute_hot__ 252 static void array_insert_data_at_pos(array * const a, data_unset * const entry, const uint32_t pos) { 253 if (a->used < a->size) { 254 data_unset * const prev = a->data[a->used]; 255 if (__builtin_expect( (prev != NULL), 0)) 256 prev->fn->free(prev); /* free prior data, if any, from slot */ 257 } 258 else { 259 array_extend(a, 16); 260 } 261 262 const uint32_t ndx = a->used++; 263 a->data[ndx] = entry; 264 265 /* move everything one step to the right */ 266 if (pos != ndx) { 267 data_unset ** const d = a->sorted + pos; 268 memmove(d+1, d, (ndx - pos) * sizeof(*a->sorted)); 269 } 270 a->sorted[pos] = entry; 271 } 272 273 static data_integer * array_insert_integer_at_pos(array * const a, const uint32_t pos) { 274 #if 0 /*(not currently used by lighttpd in way that reuse would occur)*/ 275 data_integer *di = (data_integer *)array_get_unused_element(a,TYPE_INTEGER); 276 if (NULL == di) di = data_integer_init(); 277 #else 278 data_integer * const di = data_integer_init(); 279 #endif 280 array_insert_data_at_pos(a, (data_unset *)di, pos); 281 return di; 282 } 283 284 __attribute_hot__ 285 static data_string * array_insert_string_at_pos(array * const a, const uint32_t pos) { 286 data_string *ds = (data_string *)array_get_unused_element(a, TYPE_STRING); 287 if (NULL == ds) ds = data_string_init(); 288 array_insert_data_at_pos(a, (data_unset *)ds, pos); 289 return ds; 290 } 291 292 __attribute_hot__ 293 buffer * array_get_buf_ptr_ext(array * const a, const int ext, const char * const k, const uint32_t klen) { 294 int32_t ipos = array_get_index_ext(a, ext, k, klen); 295 if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value; 296 297 data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1)); 298 ds->ext = ext; 299 buffer_copy_string_len(&ds->key, k, klen); 300 buffer_clear(&ds->value); 301 return &ds->value; 302 } 303 304 int * array_get_int_ptr(array * const a, const char * const k, const uint32_t klen) { 305 int32_t ipos = array_get_index(a, k, klen); 306 if (ipos >= 0) return &((data_integer *)a->sorted[ipos])->value; 307 308 data_integer * const di =array_insert_integer_at_pos(a,(uint32_t)(-ipos-1)); 309 buffer_copy_string_len(&di->key, k, klen); 310 di->value = 0; 311 return &di->value; 312 } 313 314 buffer * array_get_buf_ptr(array * const a, const char * const k, const uint32_t klen) { 315 int32_t ipos = array_get_index(a, k, klen); 316 if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value; 317 318 data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1)); 319 buffer_copy_string_len(&ds->key, k, klen); 320 buffer_clear(&ds->value); 321 return &ds->value; 322 } 323 324 void array_insert_value(array * const a, const char * const v, const uint32_t vlen) { 325 data_string * const ds = array_insert_string_at_pos(a, a->used); 326 buffer_clear(&ds->key); 327 buffer_copy_string_len(&ds->value, v, vlen); 328 } 329 330 /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */ 331 __attribute_cold__ 332 static data_unset **array_find_or_insert(array * const a, data_unset * const entry) { 333 force_assert(NULL != entry); 334 335 /* push value onto end of array if there is no key */ 336 if (buffer_is_empty(&entry->key)) { 337 array_insert_data_at_pos(a, entry, a->used); 338 return NULL; 339 } 340 341 /* try to find the entry */ 342 const int32_t ipos = array_get_index(a, CONST_BUF_LEN(&entry->key)); 343 if (ipos >= 0) return &a->sorted[ipos]; 344 345 array_insert_data_at_pos(a, entry, (uint32_t)(-ipos - 1)); 346 return NULL; 347 } 348 349 /* replace or insert data (free existing entry) */ 350 void array_replace(array * const a, data_unset * const entry) { 351 if (NULL == array_find_or_insert(a, entry)) return; 352 353 /* find the entry (array_find_or_insert() returned non-NULL) */ 354 const int32_t ipos = array_get_index(a, CONST_BUF_LEN(&entry->key)); 355 force_assert(ipos >= 0); 356 data_unset *old = a->sorted[ipos]; 357 force_assert(old != entry); 358 a->sorted[ipos] = entry; 359 360 uint32_t i = 0; 361 while (i < a->used && a->data[i] != old) ++i; 362 force_assert(i != a->used); 363 a->data[i] = entry; 364 365 old->fn->free(old); 366 } 367 368 void array_insert_unique(array * const a, data_unset * const entry) { 369 data_unset **old; 370 371 if (NULL != (old = array_find_or_insert(a, entry))) { 372 force_assert((*old)->type == entry->type); 373 entry->fn->insert_dup(*old, entry); 374 } 375 } 376 377 int array_is_vlist(const array * const a) { 378 for (uint32_t i = 0; i < a->used; ++i) { 379 data_unset *du = a->data[i]; 380 if (!buffer_is_empty(&du->key) || du->type != TYPE_STRING) return 0; 381 } 382 return 1; 383 } 384 385 int array_is_kvany(const array * const a) { 386 for (uint32_t i = 0; i < a->used; ++i) { 387 data_unset *du = a->data[i]; 388 if (buffer_is_empty(&du->key)) return 0; 389 } 390 return 1; 391 } 392 393 int array_is_kvarray(const array * const a) { 394 for (uint32_t i = 0; i < a->used; ++i) { 395 data_unset *du = a->data[i]; 396 if (buffer_is_empty(&du->key) || du->type != TYPE_ARRAY) return 0; 397 } 398 return 1; 399 } 400 401 int array_is_kvstring(const array * const a) { 402 for (uint32_t i = 0; i < a->used; ++i) { 403 data_unset *du = a->data[i]; 404 if (buffer_is_empty(&du->key) || du->type != TYPE_STRING) return 0; 405 } 406 return 1; 407 } 408 409 /* array_match_*() routines follow very similar pattern, but operate on slightly 410 * different data: array key/value, prefix/suffix match, case-insensitive or not 411 * While these could be combined into fewer routines with flags to modify the 412 * behavior, the interface distinctions are useful to add clarity to the code, 413 * and the specialized routines run slightly faster */ 414 415 data_unset * 416 array_match_key_prefix_klen (const array * const a, const char * const s, const uint32_t slen) 417 { 418 for (uint32_t i = 0; i < a->used; ++i) { 419 const buffer * const key = &a->data[i]->key; 420 const uint32_t klen = buffer_string_length(key); 421 if (klen <= slen && 0 == memcmp(s, key->ptr, klen)) 422 return a->data[i]; 423 } 424 return NULL; 425 } 426 427 data_unset * 428 array_match_key_prefix_nc_klen (const array * const a, const char * const s, const uint32_t slen) 429 { 430 for (uint32_t i = 0; i < a->used; ++i) { 431 const buffer * const key = &a->data[i]->key; 432 const uint32_t klen = buffer_string_length(key); 433 if (klen <= slen && buffer_eq_icase_ssn(s, key->ptr, klen)) 434 return a->data[i]; 435 } 436 return NULL; 437 } 438 439 data_unset * 440 array_match_key_prefix (const array * const a, const buffer * const b) 441 { 442 #ifdef __clang_analyzer__ 443 force_assert(b); 444 #endif 445 return array_match_key_prefix_klen(a, CONST_BUF_LEN(b)); 446 } 447 448 data_unset * 449 array_match_key_prefix_nc (const array * const a, const buffer * const b) 450 { 451 return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b)); 452 } 453 454 const buffer * 455 array_match_value_prefix (const array * const a, const buffer * const b) 456 { 457 const uint32_t blen = buffer_string_length(b); 458 459 for (uint32_t i = 0; i < a->used; ++i) { 460 const buffer * const value = &((data_string *)a->data[i])->value; 461 const uint32_t vlen = buffer_string_length(value); 462 if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen)) 463 return value; 464 } 465 return NULL; 466 } 467 468 const buffer * 469 array_match_value_prefix_nc (const array * const a, const buffer * const b) 470 { 471 const uint32_t blen = buffer_string_length(b); 472 473 for (uint32_t i = 0; i < a->used; ++i) { 474 const buffer * const value = &((data_string *)a->data[i])->value; 475 const uint32_t vlen = buffer_string_length(value); 476 if (vlen <= blen && buffer_eq_icase_ssn(b->ptr, value->ptr, vlen)) 477 return value; 478 } 479 return NULL; 480 } 481 482 data_unset * 483 array_match_key_suffix (const array * const a, const buffer * const b) 484 { 485 const uint32_t blen = buffer_string_length(b); 486 const char * const end = b->ptr + blen; 487 488 for (uint32_t i = 0; i < a->used; ++i) { 489 const buffer * const key = &a->data[i]->key; 490 const uint32_t klen = buffer_string_length(key); 491 if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen)) 492 return a->data[i]; 493 } 494 return NULL; 495 } 496 497 data_unset * 498 array_match_key_suffix_nc (const array * const a, const buffer * const b) 499 { 500 const uint32_t blen = buffer_string_length(b); 501 const char * const end = b->ptr + blen; 502 503 for (uint32_t i = 0; i < a->used; ++i) { 504 const buffer * const key = &a->data[i]->key; 505 const uint32_t klen = buffer_string_length(key); 506 if (klen <= blen && buffer_eq_icase_ssn(end - klen, key->ptr, klen)) 507 return a->data[i]; 508 } 509 return NULL; 510 } 511 512 const buffer * 513 array_match_value_suffix (const array * const a, const buffer * const b) 514 { 515 const uint32_t blen = buffer_string_length(b); 516 const char * const end = b->ptr + blen; 517 518 for (uint32_t i = 0; i < a->used; ++i) { 519 const buffer * const value = &((data_string *)a->data[i])->value; 520 const uint32_t vlen = buffer_string_length(value); 521 if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen)) 522 return value; 523 } 524 return NULL; 525 } 526 527 const buffer * 528 array_match_value_suffix_nc (const array * const a, const buffer * const b) 529 { 530 const uint32_t blen = buffer_string_length(b); 531 const char * const end = b->ptr + blen; 532 533 for (uint32_t i = 0; i < a->used; ++i) { 534 const buffer * const value = &((data_string *)a->data[i])->value; 535 const uint32_t vlen = buffer_string_length(value); 536 if (vlen <= blen && buffer_eq_icase_ssn(end - vlen, value->ptr, vlen)) 537 return value; 538 } 539 return NULL; 540 } 541 542 data_unset * 543 array_match_path_or_ext (const array * const a, const buffer * const b) 544 { 545 const uint32_t blen = buffer_string_length(b); 546 547 for (uint32_t i = 0; i < a->used; ++i) { 548 /* check extension in the form "^/path" or ".ext$" */ 549 const buffer * const key = &a->data[i]->key; 550 const uint32_t klen = buffer_string_length(key); 551 if (klen <= blen 552 && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen), 553 key->ptr, klen)) 554 return a->data[i]; 555 } 556 return NULL; 557 } 558