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 #include <errno.h> 11 #include <assert.h> 12 13 #define ARRAY_NOT_FOUND ((size_t)(-1)) 14 15 array *array_init(void) { 16 array *a; 17 18 a = calloc(1, sizeof(*a)); 19 force_assert(a); 20 21 return a; 22 } 23 24 array *array_init_array(array *src) { 25 size_t i; 26 array *a = array_init(); 27 28 if (0 == src->size) return a; 29 30 a->used = src->used; 31 a->size = src->size; 32 a->unique_ndx = src->unique_ndx; 33 34 a->data = malloc(sizeof(*src->data) * src->size); 35 force_assert(NULL != a->data); 36 for (i = 0; i < src->size; i++) { 37 if (src->data[i]) a->data[i] = src->data[i]->fn->copy(src->data[i]); 38 else a->data[i] = NULL; 39 } 40 41 a->sorted = malloc(sizeof(*src->sorted) * src->size); 42 force_assert(NULL != a->sorted); 43 memcpy(a->sorted, src->sorted, sizeof(*src->sorted) * src->size); 44 return a; 45 } 46 47 void array_free(array *a) { 48 size_t i; 49 if (!a) return; 50 51 for (i = 0; i < a->size; i++) { 52 if (a->data[i]) a->data[i]->fn->free(a->data[i]); 53 } 54 55 if (a->data) free(a->data); 56 if (a->sorted) free(a->sorted); 57 58 free(a); 59 } 60 61 void array_reset(array *a) { 62 size_t i; 63 if (!a) return; 64 65 for (i = 0; i < a->used; i++) { 66 a->data[i]->fn->reset(a->data[i]); 67 } 68 69 a->used = 0; 70 a->unique_ndx = 0; 71 } 72 73 void array_reset_data_strings(array *a) { 74 if (!a) return; 75 76 for (size_t i = 0; i < a->used; ++i) { 77 data_string * const ds = (data_string *)a->data[i]; 78 /*force_assert(ds->type == TYPE_STRING);*/ 79 buffer_reset(ds->key); 80 buffer_reset(ds->value); 81 } 82 83 a->used = 0; 84 a->unique_ndx = 0; 85 } 86 87 data_unset *array_pop(array *a) { 88 data_unset *du; 89 90 force_assert(a->used != 0); 91 92 a->used --; 93 du = a->data[a->used]; 94 force_assert(a->sorted[a->used] == a->used); /* only works on "simple" lists */ 95 a->data[a->used] = NULL; 96 97 return du; 98 } 99 100 static int array_keycmp(const char *a, size_t alen, const char *b, size_t blen) { 101 return alen < blen ? -1 : alen > blen ? 1 : buffer_caseless_compare(a, alen, b, blen); 102 } 103 104 /* returns index of element or ARRAY_NOT_FOUND 105 * if rndx != NULL it stores the position in a->sorted[] where the key needs 106 * to be inserted 107 */ 108 static size_t array_get_index(const array *a, const char *key, size_t keylen, size_t *rndx) { 109 /* invariant: [lower-1] < key < [upper] 110 * "virtual elements": [-1] = -INFTY, [a->used] = +INFTY 111 * also an invariant: 0 <= lower <= upper <= a->used 112 */ 113 size_t lower = 0, upper = a->used; 114 force_assert(upper <= SSIZE_MAX); /* (lower + upper) can't overflow */ 115 116 while (lower != upper) { 117 size_t probe = (lower + upper) / 2; 118 const buffer *b = a->data[a->sorted[probe]]->key; 119 int cmp = array_keycmp(key, keylen, CONST_BUF_LEN(b)); 120 121 if (cmp == 0) { 122 /* found */ 123 if (rndx) *rndx = probe; 124 return a->sorted[probe]; 125 } else if (cmp < 0) { 126 /* key < [probe] */ 127 upper = probe; /* still: lower <= upper */ 128 } else { 129 /* key > [probe] */ 130 lower = probe + 1; /* still: lower <= upper */ 131 } 132 } 133 134 /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 135 if (rndx) *rndx = lower; 136 return ARRAY_NOT_FOUND; 137 } 138 139 data_unset *array_get_element_klen(const array *a, const char *key, size_t klen) { 140 size_t ndx; 141 force_assert(NULL != key); 142 143 if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, NULL))) { 144 /* found, return it */ 145 return a->data[ndx]; 146 } 147 148 return NULL; 149 } 150 151 data_unset *array_extract_element_klen(array *a, const char *key, size_t klen) { 152 size_t ndx, pos; 153 force_assert(NULL != key); 154 155 if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, &pos))) { 156 /* found */ 157 const size_t last_ndx = a->used - 1; 158 data_unset *entry = a->data[ndx]; 159 160 /* now we need to swap it with the last element (if it isn't already the last element) */ 161 if (ndx != last_ndx) { 162 /* to swap we also need to modify the index in a->sorted - find pos of last_elem there */ 163 size_t last_elem_pos; 164 /* last element must be present at the expected position */ 165 force_assert(last_ndx == array_get_index(a, CONST_BUF_LEN(a->data[last_ndx]->key), &last_elem_pos)); 166 167 /* move entry from last_ndx to ndx */ 168 a->data[ndx] = a->data[last_ndx]; 169 a->data[last_ndx] = NULL; 170 171 /* fix index entry for moved entry */ 172 a->sorted[last_elem_pos] = ndx; 173 } else { 174 a->data[ndx] = NULL; 175 } 176 177 /* remove entry in a->sorted: move everything after pos one step to the left */ 178 if (pos != last_ndx) { 179 memmove(a->sorted + pos, a->sorted + pos + 1, (last_ndx - pos) * sizeof(*a->sorted)); 180 } 181 a->sorted[last_ndx] = ARRAY_NOT_FOUND; 182 --a->used; 183 184 return entry; 185 } 186 187 return NULL; 188 } 189 190 static data_unset *array_get_unused_element(array *a, data_type_t t) { 191 data_unset *ds = NULL; 192 unsigned int i; 193 194 for (i = a->used; i < a->size; i++) { 195 if (a->data[i] && a->data[i]->type == t) { 196 ds = a->data[i]; 197 198 /* make empty slot at a->used for next insert */ 199 a->data[i] = a->data[a->used]; 200 a->data[a->used] = NULL; 201 202 return ds; 203 } 204 } 205 206 return NULL; 207 } 208 209 void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) { 210 data_string *ds; 211 212 if (NULL != (ds = (data_string *)array_get_element_klen(hdrs, key, key_len))) { 213 buffer_copy_string_len(ds->value, value, val_len); 214 return; 215 } 216 217 array_insert_key_value(hdrs, key, key_len, value, val_len); 218 } 219 220 void array_insert_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) { 221 data_string *ds; 222 223 if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) { 224 ds = data_string_init(); 225 } 226 227 buffer_copy_string_len(ds->key, key, key_len); 228 buffer_copy_string_len(ds->value, value, val_len); 229 array_insert_unique(hdrs, (data_unset *)ds); 230 } 231 232 void array_insert_value(array *hdrs, const char *value, size_t val_len) { 233 data_string *ds; 234 235 if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) { 236 ds = data_string_init(); 237 } 238 239 buffer_copy_string_len(ds->value, value, val_len); 240 array_insert_unique(hdrs, (data_unset *)ds); 241 } 242 243 int * array_get_int_ptr(array *a, const char *k, size_t klen) { 244 data_integer *di = (data_integer *)array_get_element_klen(a, k, klen); 245 246 if (NULL == di) { 247 di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER); 248 if (NULL == di) di = data_integer_init(); 249 buffer_copy_string_len(di->key, k, klen); 250 array_insert_unique(a, (data_unset *)di); 251 } 252 253 return &di->value; 254 } 255 256 /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */ 257 static data_unset **array_find_or_insert(array *a, data_unset *entry) { 258 size_t ndx, pos, j; 259 260 /* generate unique index if neccesary */ 261 if (buffer_is_empty(entry->key) || entry->is_index_key) { 262 buffer_copy_int(entry->key, a->unique_ndx++); 263 entry->is_index_key = 1; 264 force_assert(0 != a->unique_ndx); /* must not wrap or we'll get problems */ 265 } 266 267 /* try to find the entry */ 268 if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, CONST_BUF_LEN(entry->key), &pos))) { 269 /* found collision, return it */ 270 return &a->data[ndx]; 271 } 272 273 /* insert */ 274 275 /* there couldn't possibly be enough memory to store so many entries */ 276 force_assert(a->used + 1 <= SSIZE_MAX); 277 278 if (a->size == 0) { 279 a->size = 16; 280 a->data = malloc(sizeof(*a->data) * a->size); 281 a->sorted = malloc(sizeof(*a->sorted) * a->size); 282 force_assert(a->data); 283 force_assert(a->sorted); 284 for (j = a->used; j < a->size; j++) a->data[j] = NULL; 285 } else if (a->size == a->used) { 286 a->size += 16; 287 a->data = realloc(a->data, sizeof(*a->data) * a->size); 288 a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size); 289 force_assert(a->data); 290 force_assert(a->sorted); 291 for (j = a->used; j < a->size; j++) a->data[j] = NULL; 292 } 293 294 ndx = a->used; 295 296 /* make sure there is nothing here */ 297 if (a->data[ndx]) a->data[ndx]->fn->free(a->data[ndx]); 298 299 a->data[a->used++] = entry; 300 301 /* move everything one step to the right */ 302 if (pos != ndx) { 303 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted)); 304 } 305 306 /* insert */ 307 a->sorted[pos] = ndx; 308 309 return NULL; 310 } 311 312 /* replace or insert data (free existing entry) */ 313 void array_replace(array *a, data_unset *entry) { 314 data_unset **old; 315 316 force_assert(NULL != entry); 317 if (NULL != (old = array_find_or_insert(a, entry))) { 318 force_assert(*old != entry); 319 (*old)->fn->free(*old); 320 *old = entry; 321 } 322 } 323 324 void array_insert_unique(array *a, data_unset *entry) { 325 data_unset **old; 326 327 force_assert(NULL != entry); 328 if (NULL != (old = array_find_or_insert(a, entry))) { 329 force_assert((*old)->type == entry->type); 330 entry->fn->insert_dup(*old, entry); 331 } 332 } 333 334 int array_is_vlist(array *a) { 335 for (size_t i = 0; i < a->used; ++i) { 336 data_unset *du = a->data[i]; 337 if (!du->is_index_key || du->type != TYPE_STRING) return 0; 338 } 339 return 1; 340 } 341 342 int array_is_kvany(array *a) { 343 for (size_t i = 0; i < a->used; ++i) { 344 data_unset *du = a->data[i]; 345 if (du->is_index_key) return 0; 346 } 347 return 1; 348 } 349 350 int array_is_kvarray(array *a) { 351 for (size_t i = 0; i < a->used; ++i) { 352 data_unset *du = a->data[i]; 353 if (du->is_index_key || du->type != TYPE_ARRAY) return 0; 354 } 355 return 1; 356 } 357 358 int array_is_kvstring(array *a) { 359 for (size_t i = 0; i < a->used; ++i) { 360 data_unset *du = a->data[i]; 361 if (du->is_index_key || du->type != TYPE_STRING) return 0; 362 } 363 return 1; 364 } 365 366 /* array_match_*() routines follow very similar pattern, but operate on slightly 367 * different data: array key/value, prefix/suffix match, case-insensitive or not 368 * While these could be combined into fewer routines with flags to modify the 369 * behavior, the interface distinctions are useful to add clarity to the code, 370 * and the specialized routines run slightly faster */ 371 372 data_unset * 373 array_match_key_prefix_klen (const array * const a, const char * const s, const size_t slen) 374 { 375 for (size_t i = 0; i < a->used; ++i) { 376 const buffer * const key = a->data[i]->key; 377 const size_t klen = buffer_string_length(key); 378 if (klen <= slen && 0 == memcmp(s, key->ptr, klen)) 379 return a->data[i]; 380 } 381 return NULL; 382 } 383 384 data_unset * 385 array_match_key_prefix_nc_klen (const array * const a, const char * const s, const size_t slen) 386 { 387 for (size_t i = 0; i < a->used; ++i) { 388 const buffer * const key = a->data[i]->key; 389 const size_t klen = buffer_string_length(key); 390 if (klen <= slen && 0 == strncasecmp(s, key->ptr, klen)) 391 return a->data[i]; 392 } 393 return NULL; 394 } 395 396 data_unset * 397 array_match_key_prefix (const array * const a, const buffer * const b) 398 { 399 return array_match_key_prefix_klen(a, CONST_BUF_LEN(b)); 400 } 401 402 data_unset * 403 array_match_key_prefix_nc (const array * const a, const buffer * const b) 404 { 405 return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b)); 406 } 407 408 const buffer * 409 array_match_value_prefix (const array * const a, const buffer * const b) 410 { 411 const size_t blen = buffer_string_length(b); 412 413 for (size_t i = 0; i < a->used; ++i) { 414 const buffer * const value = ((data_string *)a->data[i])->value; 415 const size_t vlen = buffer_string_length(value); 416 if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen)) 417 return value; 418 } 419 return NULL; 420 } 421 422 const buffer * 423 array_match_value_prefix_nc (const array * const a, const buffer * const b) 424 { 425 const size_t blen = buffer_string_length(b); 426 427 for (size_t i = 0; i < a->used; ++i) { 428 const buffer * const value = ((data_string *)a->data[i])->value; 429 const size_t vlen = buffer_string_length(value); 430 if (vlen <= blen && 0 == strncasecmp(b->ptr, value->ptr, vlen)) 431 return value; 432 } 433 return NULL; 434 } 435 436 data_unset * 437 array_match_key_suffix (const array * const a, const buffer * const b) 438 { 439 const size_t blen = buffer_string_length(b); 440 const char * const end = b->ptr + blen; 441 442 for (size_t i = 0; i < a->used; ++i) { 443 const buffer * const key = a->data[i]->key; 444 const size_t klen = buffer_string_length(key); 445 if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen)) 446 return a->data[i]; 447 } 448 return NULL; 449 } 450 451 data_unset * 452 array_match_key_suffix_nc (const array * const a, const buffer * const b) 453 { 454 const size_t blen = buffer_string_length(b); 455 const char * const end = b->ptr + blen; 456 457 for (size_t i = 0; i < a->used; ++i) { 458 const buffer * const key = a->data[i]->key; 459 const size_t klen = buffer_string_length(key); 460 if (klen <= blen && 0 == strncasecmp(end - klen, key->ptr, klen)) 461 return a->data[i]; 462 } 463 return NULL; 464 } 465 466 const buffer * 467 array_match_value_suffix (const array * const a, const buffer * const b) 468 { 469 const size_t blen = buffer_string_length(b); 470 const char * const end = b->ptr + blen; 471 472 for (size_t i = 0; i < a->used; ++i) { 473 const buffer * const value = ((data_string *)a->data[i])->value; 474 const size_t vlen = buffer_string_length(value); 475 if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen)) 476 return value; 477 } 478 return NULL; 479 } 480 481 const buffer * 482 array_match_value_suffix_nc (const array * const a, const buffer * const b) 483 { 484 const size_t blen = buffer_string_length(b); 485 const char * const end = b->ptr + blen; 486 487 for (size_t i = 0; i < a->used; ++i) { 488 const buffer * const value = ((data_string *)a->data[i])->value; 489 const size_t vlen = buffer_string_length(value); 490 if (vlen <= blen && 0 == strncasecmp(end - vlen, value->ptr, vlen)) 491 return value; 492 } 493 return NULL; 494 } 495 496 data_unset * 497 array_match_path_or_ext (const array * const a, const buffer * const b) 498 { 499 const size_t blen = buffer_string_length(b); 500 501 for (size_t i = 0; i < a->used; ++i) { 502 /* check extension in the form "^/path" or ".ext$" */ 503 const buffer * const key = a->data[i]->key; 504 const size_t klen = buffer_string_length(key); 505 if (klen <= blen 506 && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen), 507 key->ptr, klen)) 508 return a->data[i]; 509 } 510 return NULL; 511 } 512 513 514 515 516 517 #include <stdio.h> 518 519 void array_print_indent(int depth) { 520 int i; 521 for (i = 0; i < depth; i ++) { 522 fprintf(stdout, " "); 523 } 524 } 525 526 size_t array_get_max_key_length(array *a) { 527 size_t maxlen, i; 528 529 maxlen = 0; 530 for (i = 0; i < a->used; i ++) { 531 data_unset *du = a->data[i]; 532 size_t len = buffer_string_length(du->key); 533 534 if (len > maxlen) { 535 maxlen = len; 536 } 537 } 538 return maxlen; 539 } 540 541 int array_print(array *a, int depth) { 542 size_t i; 543 size_t maxlen; 544 int oneline = 1; 545 546 if (a->used > 5) { 547 oneline = 0; 548 } 549 for (i = 0; i < a->used && oneline; i++) { 550 data_unset *du = a->data[i]; 551 if (!du->is_index_key) { 552 oneline = 0; 553 break; 554 } 555 switch (du->type) { 556 case TYPE_INTEGER: 557 case TYPE_STRING: 558 break; 559 default: 560 oneline = 0; 561 break; 562 } 563 } 564 if (oneline) { 565 fprintf(stdout, "("); 566 for (i = 0; i < a->used; i++) { 567 data_unset *du = a->data[i]; 568 if (i != 0) { 569 fprintf(stdout, ", "); 570 } 571 du->fn->print(du, depth + 1); 572 } 573 fprintf(stdout, ")"); 574 return 0; 575 } 576 577 maxlen = array_get_max_key_length(a); 578 fprintf(stdout, "(\n"); 579 for (i = 0; i < a->used; i++) { 580 data_unset *du = a->data[i]; 581 array_print_indent(depth + 1); 582 if (!du->is_index_key) { 583 int j; 584 585 if (i && (i % 5) == 0) { 586 fprintf(stdout, "# %zu\n", i); 587 array_print_indent(depth + 1); 588 } 589 fprintf(stdout, "\"%s\"", du->key->ptr); 590 for (j = maxlen - buffer_string_length(du->key); j > 0; j--) { 591 fprintf(stdout, " "); 592 } 593 fprintf(stdout, " => "); 594 } 595 du->fn->print(du, depth + 1); 596 fprintf(stdout, ",\n"); 597 } 598 if (!(i && (i - 1 % 5) == 0)) { 599 array_print_indent(depth + 1); 600 fprintf(stdout, "# %zu\n", i); 601 } 602 array_print_indent(depth); 603 fprintf(stdout, ")"); 604 605 return 0; 606 } 607