llist.c (15271B)
1 /* 2 * Copy me if you can. 3 * by 20h 4 */ 5 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <strings.h> 11 #include <sys/types.h> 12 #include <regex.h> 13 14 #include "ind.h" 15 #include "llist.h" 16 17 enum { 18 FREE_NORMAL = 0x0, 19 FREE_EXTENDED = 0x1, 20 FREE_BARE = 0x2 21 }; 22 23 void 24 llistelemvalue_internfree(llistelem_t *elem, int mode) 25 { 26 if (elem->key == NULL && elem->data != NULL 27 && (mode & FREE_EXTENDED)) { 28 if (mode & FREE_BARE) 29 llist_ebfree((llist_t *)elem->data); 30 else 31 llist_efree((llist_t *)elem->data); 32 } else { 33 if (elem->data != NULL && !(mode & FREE_BARE)) { 34 free(elem->data); 35 elem->data = NULL; 36 } 37 } 38 if (elem->key != NULL && !(mode & FREE_BARE)) { 39 free(elem->key); 40 elem->key = NULL; 41 } 42 } 43 44 void 45 llistelemvalue_free(llistelem_t *elem) 46 { 47 llistelemvalue_internfree(elem, FREE_NORMAL); 48 } 49 50 void 51 llistelem_free(llistelem_t *elem) 52 { 53 llistelemvalue_internfree(elem, FREE_NORMAL); 54 free(elem); 55 } 56 57 void 58 llistelemvalue_efree(llistelem_t *elem) 59 { 60 llistelemvalue_internfree(elem, FREE_EXTENDED); 61 } 62 63 void 64 llistelem_efree(llistelem_t *elem) 65 { 66 llistelemvalue_internfree(elem, FREE_EXTENDED); 67 free(elem); 68 } 69 70 llistelem_t * 71 llistelem_set(llistelem_t *elem, char *key, void *data, int datalen) 72 { 73 int keylen; 74 75 llistelemvalue_free(elem); 76 77 if (key != NULL) { 78 keylen = strlen(key); 79 elem->key = mallocz(keylen+1, 2); 80 memmove(elem->key, key, keylen); 81 } 82 if (data != NULL) { 83 elem->data = mallocz(datalen+1, 2); 84 elem->datalen = datalen; 85 memmove(elem->data, data, datalen); 86 } 87 88 return elem; 89 } 90 91 llistelem_t * 92 llistelem_rawset(llistelem_t *elem, char *key, void *data, int datalen) 93 { 94 llistelemvalue_free(elem); 95 96 elem->key = key; 97 elem->data = data; 98 elem->datalen = datalen; 99 100 return elem; 101 } 102 103 llistelem_t * 104 llistelem_new(char *key, void *data, int datalen) 105 { 106 return llistelem_set(mallocz(sizeof(llistelem_t), 2), key, data, 107 datalen); 108 } 109 110 llistelem_t * 111 llistelem_rawnew(char *key, void *data, int datalen) 112 { 113 return llistelem_rawset(mallocz(sizeof(llistelem_t), 2), key, data, 114 datalen); 115 } 116 117 void 118 llistelem_print(llistelem_t *elem) 119 { 120 //printf("(%p)%s = %s\n", elem, elem->key, (char *)elem->data); 121 printf("%s = %s\n", elem->key, (char *)elem->data); 122 } 123 124 void 125 llistelem_printkey(llistelem_t *elem) 126 { 127 printf("%s\n", elem->key); 128 } 129 130 void 131 llistelem_printdata(llistelem_t *elem) 132 { 133 printf("%s\n", (char *)elem->data); 134 } 135 136 int 137 llistelem_cmp(llistelem_t *elem1, llistelem_t *elem2) 138 { 139 int ret, len1, len2; 140 141 if (elem1 == elem2) 142 return 0; 143 144 len1 = strlen(elem1->key); 145 len2 = strlen(elem2->key); 146 147 if (len1 != len2) 148 return (len1 - len2); 149 if (elem1->datalen != elem2->datalen) 150 return (elem1->datalen - elem2->datalen); 151 if ((ret = memcmp(elem1->key, elem2->key, len1))) 152 return ret; 153 if ((ret = memcmp(elem1->data, elem2->data, elem1->datalen))) 154 return ret; 155 156 return 0; 157 } 158 159 llist_t * 160 llist_new(void) 161 { 162 return (llist_t *)mallocz(sizeof(llist_t), 2); 163 } 164 165 /* for mode argument see beginning of this file */ 166 void 167 llist_internfree(llist_t *llist, int mode) 168 { 169 llistelem_t *elem; 170 171 //printf("internfree: %p\n", llist); 172 if (llist->first != NULL) { 173 for (elem = llist->first;;) { 174 //printf("list free %d %d\n", elem->datalen, sizeof(llist_t)); 175 llistelemvalue_internfree(elem, mode); 176 177 if (elem->next != NULL) { 178 elem = elem->next; 179 free(elem->prev); 180 } else { 181 free(elem); 182 break; 183 } 184 } 185 } 186 free(llist); 187 } 188 189 void 190 llist_free(llist_t *llist) 191 { 192 llist_internfree(llist, FREE_NORMAL); 193 } 194 195 void 196 llist_bfree(llist_t *llist) 197 { 198 llist_internfree(llist, FREE_BARE); 199 } 200 201 void 202 llist_efree(llist_t *llist) 203 { 204 llist_internfree(llist, FREE_EXTENDED); 205 } 206 207 void 208 llist_ebfree(llist_t *llist) 209 { 210 llist_internfree(llist, FREE_EXTENDED|FREE_BARE); 211 } 212 213 llistelem_t * 214 llist_addelem(llist_t *llist, llistelem_t *elem) 215 { 216 if (llist->first == NULL) 217 llist->first = elem; 218 if (llist->last == NULL) 219 llist->last = elem; 220 else { 221 llist->last->next = elem; 222 elem->prev = llist->last; 223 llist->last = elem; 224 } 225 llist->len++; 226 227 return elem; 228 } 229 230 llistelem_t * 231 llist_addraw(llist_t *llist, char *key, void *data, int datalen) 232 { 233 llistelem_t *elem; 234 235 elem = llistelem_new(NULL, NULL, 0); 236 elem->key = key; 237 elem->data = data; 238 elem->datalen = datalen; 239 240 llist_addelem(llist, elem); 241 242 return elem; 243 } 244 245 llistelem_t * 246 llist_add(llist_t *llist, char *key, void *data, int datalen) 247 { 248 return llist_addelem(llist, llistelem_new(key, data, datalen)); 249 } 250 251 llistelem_t * 252 llist_push(llist_t *llist, char *key, void *data, int datalen) 253 { 254 llistelem_t *elem; 255 256 elem = llistelem_new(key, data, datalen); 257 258 if (llist->first == NULL) 259 llist->first = elem; 260 else { 261 llist->first->prev = elem; 262 elem->next = llist->first; 263 llist->first = elem; 264 } 265 if (llist->last == NULL) 266 llist->last = elem; 267 llist->len++; 268 269 return elem; 270 } 271 272 llistelem_t * 273 llist_pop(llist_t *llist) 274 { 275 llistelem_t *elem; 276 277 if (llist->len < 1) 278 return NULL; 279 280 elem = llist->first; 281 if (elem->next != NULL) 282 elem->next->prev = NULL; 283 llist->first = elem->next; 284 elem->prev = NULL; 285 elem->next = NULL; 286 llist->len--; 287 288 return elem; 289 } 290 291 enum { 292 FIND_NORMAL = 0x0, 293 FIND_EXTENDED = 0x1, 294 FIND_CI = 0x2 295 }; 296 297 llist_t * 298 llist_internfind(llist_t *llist, char *regex, int mode) 299 { 300 llist_t *results, *sresults; 301 llistelem_t *elem; 302 regex_t preg; 303 304 if (regcomp(&preg, regex, REG_EXTENDED|REG_NOSUB \ 305 |((mode & FIND_CI)? REG_ICASE : 0))) { 306 return NULL; 307 } 308 309 results = llist_new(); 310 forllist(llist, elem) { 311 if (mode & FIND_EXTENDED && elem->key != NULL 312 && elem->data != NULL 313 && elem->datalen == sizeof(llist_t)) { 314 sresults = llist_internfind((llist_t *)elem->data, 315 regex, mode); 316 if (sresults != NULL) { 317 llist_rawlistadd(results, sresults); 318 llist_bfree(sresults); 319 } 320 continue; 321 } 322 323 if (!regexec(&preg, elem->key, 0, NULL, 0)) { 324 llist_add(results, elem->key, elem->data, 325 elem->datalen); 326 } 327 } 328 329 regfree(&preg); 330 331 if (results->first == NULL) { 332 llist_free(results); 333 results = NULL; 334 } 335 336 return results; 337 } 338 339 llist_t * 340 llist_find(llist_t *llist, char *regex) 341 { 342 return llist_internfind(llist, regex, FIND_NORMAL); 343 } 344 345 llist_t * 346 llist_efind(llist_t *llist, char *regex) 347 { 348 return llist_internfind(llist, regex, FIND_EXTENDED); 349 } 350 351 llist_t * 352 llist_cifind(llist_t *llist, char *regex) 353 { 354 return llist_internfind(llist, regex, FIND_NORMAL|FIND_CI); 355 } 356 357 llist_t * 358 llist_ecifind(llist_t *llist, char *regex) 359 { 360 return llist_internfind(llist, regex, FIND_EXTENDED|FIND_CI); 361 } 362 363 enum { 364 GET_NORMAL = 0x01, 365 GET_EXTENDED = 0x02, 366 GET_CASEINSENSITIVE = 0x04 367 }; 368 369 llistelem_t * 370 llist_internget(llist_t *llist, char *key, int mode) 371 { 372 llistelem_t *elem, *selem; 373 374 forllist(llist, elem) { 375 if (mode & GET_EXTENDED && elem->key == NULL 376 && elem->data != NULL 377 && elem->datalen == sizeof(llist_t)) { 378 selem = llist_internget((llist_t *)elem->data, key, 379 mode); 380 if (selem != NULL) 381 return selem; 382 } 383 384 if (mode & GET_CASEINSENSITIVE) { 385 if (elem->key != NULL && !strcasecmp(elem->key, key)) 386 break; 387 } else { 388 if (elem->key != NULL && !strcmp(elem->key, key)) 389 break; 390 } 391 } 392 393 return elem; 394 } 395 396 llistelem_t * 397 llist_get(llist_t *llist, char *key) 398 { 399 return llist_internget(llist, key, GET_NORMAL); 400 } 401 402 llistelem_t * 403 llist_ciget(llist_t *llist, char *key) 404 { 405 return llist_internget(llist, key, GET_NORMAL|GET_CASEINSENSITIVE); 406 } 407 408 llistelem_t * 409 llist_eget(llist_t *llist, char *key) 410 { 411 return llist_internget(llist, key, GET_EXTENDED); 412 } 413 414 llistelem_t * 415 llist_eciget(llist_t *llist, char *key) 416 { 417 return llist_internget(llist, key, GET_EXTENDED|GET_CASEINSENSITIVE); 418 } 419 420 llistelem_t * 421 llist_getn(llist_t *llist, int idx) 422 { 423 llistelem_t *elem; 424 int i; 425 426 i = 0; 427 forllist(llist, elem) { 428 if (i == idx) 429 return elem; 430 i++; 431 } 432 return NULL; 433 } 434 435 void 436 llist_delelemlinks(llist_t *llist, llistelem_t *elem) 437 { 438 llistelem_t *prev, *next; 439 440 prev = elem->prev; 441 next = elem->next; 442 443 if (prev != NULL) 444 prev->next = next; 445 if (next != NULL) 446 next->prev = prev; 447 if (llist->first == elem) 448 llist->first = next; 449 if (llist->last == elem) 450 llist->last = prev; 451 } 452 453 void 454 llist_delelem(llist_t *llist, llistelem_t *elem) 455 { 456 llist_delelemlinks(llist, elem); 457 llistelem_free(elem); 458 llist->len--; 459 } 460 461 llistelem_t * 462 llist_del(llist_t *llist, char *key) 463 { 464 llistelem_t *elem; 465 466 elem = llist_get(llist, key); 467 if (elem != NULL) 468 llist_delelem(llist, elem); 469 470 return elem; 471 } 472 473 llistelem_t * 474 llist_insert(llist_t *llist, llistelem_t *elem, int idx) 475 { 476 int i; 477 llistelem_t *next; 478 479 i = 0; 480 481 if (idx > llist->len-1) 482 return NULL; 483 if (idx == llist->len-1) 484 return llist_addelem(llist, elem); 485 486 forllist(llist, next) 487 if (i == idx) 488 break; 489 490 if (next->prev != NULL) 491 next->prev->next = elem; 492 elem->prev = next->prev; 493 next->prev = elem; 494 elem->next = next; 495 496 return elem; 497 } 498 499 llistelem_t * 500 llist_move(llist_t *llist, llistelem_t *elem, int idx) 501 { 502 llist_delelemlinks(llist, elem); 503 return llist_insert(llist, elem, idx); 504 } 505 506 void 507 llist_print(llist_t *llist) 508 { 509 llistelem_t *elem; 510 511 forllist(llist, elem) 512 printf("%s = \"%s\"\n", (char *)elem->key, (char *)elem->data); 513 fflush(stdout); 514 } 515 516 void 517 llistelem_eprintelem(llistelem_t *elem, int depth) 518 { 519 for (; depth; depth--) 520 printf("\t"); 521 llistelem_print(elem); 522 } 523 524 void 525 llist_eprintintern(llist_t *stru, int depth) 526 { 527 llistelem_t *elem; 528 int i; 529 530 for (i = 0; i < depth; i++) 531 printf("\t"); 532 //printf("list %p\n", stru); 533 printf("list\n"); 534 forllist(stru, elem) { 535 if (elem->key == NULL) 536 llist_eprintintern((llist_t *)elem->data, depth+1); 537 else 538 llistelem_eprintelem(elem, depth); 539 } 540 for (i = 0; i < depth; i++) 541 printf("\t"); 542 printf("list ended\n"); 543 } 544 545 void 546 llist_eprint(llist_t *llist) 547 { 548 llist_eprintintern(llist, 0); 549 } 550 551 void 552 llistelem_eprint(llistelem_t *elem) 553 { 554 if (elem->key == NULL) 555 llist_eprintintern((llist_t *)elem->data, 0); 556 else 557 llistelem_print(elem); 558 } 559 560 llist_t * 561 llist_getdiff(llist_t *llist1, llist_t *llist2) 562 { 563 llist_t *diff; 564 llistelem_t *elem1, *elem2; 565 566 diff = llist_new(); 567 568 forllist(llist1, elem1) { 569 forllist(llist2, elem2) { 570 if (llistelem_cmp(elem1, elem2)) { 571 llist_add(diff, elem1->key, elem1->data, 572 elem1->datalen); 573 llist_add(diff, elem2->key, elem2->data, 574 elem2->datalen); 575 } 576 } 577 } 578 579 return diff; 580 } 581 582 llist_t * 583 llist_getsame(llist_t *llist1, llist_t *llist2) 584 { 585 llist_t *same; 586 llistelem_t *elem1, *elem2; 587 588 same = llist_new(); 589 590 forllist(llist1, elem1) { 591 forllist(llist2, elem2) { 592 if (!llistelem_cmp(elem1, elem2)) { 593 llist_add(same, elem1->key, elem1->data, 594 elem1->datalen); 595 } 596 } 597 } 598 599 return same; 600 } 601 602 llist_t * 603 llist_copy(llist_t *llist) 604 { 605 llist_t *rllist; 606 llistelem_t *elem; 607 608 rllist = llist_new(); 609 forllist(llist, elem) 610 llist_add(rllist, elem->key, elem->data, elem->datalen); 611 612 return rllist; 613 } 614 615 llist_t * 616 llist_listdel(llist_t *llist, llist_t *elems) 617 { 618 llistelem_t *elem; 619 620 forllist(elems, elem) 621 llist_del(llist, elem->key); 622 623 return llist; 624 } 625 626 llist_t * 627 llist_rawlistadd(llist_t *llist, llist_t *elems) 628 { 629 llistelem_t *elem; 630 631 forllist(elems, elem) 632 llist_addraw(llist, elem->key, elem->data, elem->datalen); 633 634 return llist; 635 } 636 637 llist_t * 638 llist_listadd(llist_t *llist, llist_t *elems) 639 { 640 llistelem_t *elem; 641 642 forllist(elems, elem) 643 llist_add(llist, elem->key, elem->data, elem->datalen); 644 645 return llist; 646 } 647 648 llist_t * 649 llist_splitstr(char *str, char *sep) 650 { 651 char *tok, *strc, *saveptr; 652 llist_t *llist; 653 654 saveptr = NULL; 655 656 strc = memdups(str); 657 658 tok = strtok_r(strc, sep, &saveptr); 659 if (tok == NULL) { 660 free(strc); 661 return NULL; 662 } 663 664 llist = llist_new(); 665 do { 666 llist_add(llist, tok, NULL, 0); 667 } while((tok = strtok_r(NULL, sep, &saveptr))); 668 free(strc); 669 670 return llist; 671 } 672 673 llist_t * 674 llist_splitargv(int argc, char *argv[]) 675 { 676 llist_t *llist; 677 int i; 678 679 if (argc < 1) 680 return NULL; 681 682 llist = llist_new(); 683 for(i = 0; argc; i++, argc--) 684 llist_add(llist, argv[i], NULL, 0); 685 686 return llist; 687 } 688 689 char * 690 llist_joinstr(llist_t *llist, char *sep) 691 { 692 char *str, *tstr, *sstr; 693 llistelem_t *elem; 694 int keylen, seplen, size; 695 696 str = NULL; 697 seplen = strlen(sep); 698 size = 0; 699 700 forllist(llist, elem) { 701 keylen = strlen(elem->key); 702 if (str == NULL) { 703 str = memdup(elem->key, keylen+1); 704 size += keylen; 705 } else { 706 /* 707 * Premature optimisation. 708 */ 709 sstr = mallocz(keylen + seplen + 1, 1); 710 memmove(sstr, sep, seplen); 711 memmove(&sstr[seplen], elem->key, keylen); 712 713 keylen += seplen; 714 tstr = memdupcat(str, size, sstr, keylen+1); 715 free(sstr); 716 str = tstr; 717 718 size += keylen; 719 } 720 } 721 722 return str; 723 } 724 725 llist_t * 726 llist_genrange(int begin, int end, int step) 727 { 728 llist_t *llist; 729 int i, min, max; 730 731 if (begin == end) 732 return NULL; 733 734 max = (begin > end)? begin : end; 735 min = (begin > end)? end : begin; 736 737 llist = llist_new(); 738 for (i = min; i < max; i += step) 739 llist_addraw(llist, smprintf("%d", i), NULL, 0); 740 741 return llist; 742 } 743 744 int 745 llist_strcmp(llistelem_t *elem1, llistelem_t *elem2) 746 { 747 return strcmp(elem1->key, elem2->key); 748 } 749 750 int 751 llist_intcmp(llistelem_t *elem1, llistelem_t *elem2) 752 { 753 return atoi(elem1->key) - atoi(elem2->key); 754 } 755 756 /* Taken from: 757 * http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html 758 * 759 * 760 * This following algorithm is copyright 2001 Simon Tatham. 761 * 762 * Permission is hereby granted, free of charge, to any person 763 * obtaining a copy of this software and associated documentation 764 * files (the "Software"), to deal in the Software without 765 * restriction, including without limitation the rights to use, 766 * copy, modify, merge, publish, distribute, sublicense, and/or 767 * sell copies of the Software, and to permit persons to whom the 768 * Software is furnished to do so, subject to the following 769 * conditions: 770 * 771 * The above copyright notice and this permission notice shall be 772 * included in all copies or substantial portions of the Software. 773 * 774 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 775 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 776 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 777 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR 778 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 779 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 780 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 781 * SOFTWARE. 782 */ 783 784 llist_t * 785 llist_internsort(llist_t *llist, int (*cmp)(llistelem_t *, llistelem_t *)) 786 { 787 llistelem_t *p, *q, *e, *tail; 788 int insize, nmerges, psize, qsize, i; 789 790 insize = 1; 791 for (;;) { 792 p = llist->first; 793 llist->first = NULL; 794 tail = NULL; 795 796 nmerges = 0; 797 798 while(p) { 799 nmerges++; 800 801 q = p; 802 psize = 0; 803 for (i = 0; i < insize; i++) { 804 psize++; 805 q = q->next; 806 if (!q) 807 break; 808 } 809 810 qsize = insize; 811 while (psize > 0 || (qsize > 0 && q)) { 812 if (psize == 0) { 813 e = q; 814 q = q->next; 815 qsize--; 816 } else if (qsize == 0 || !q) { 817 e = p; 818 p = p->next; 819 psize--; 820 } else if (cmp(p, q) <= 0) { 821 e = p; 822 p = p->next; 823 psize--; 824 } else { 825 e = q; 826 q = q->next; 827 qsize--; 828 } 829 830 if (tail) 831 tail->next = e; 832 else 833 llist->first = e; 834 e->prev = tail; 835 tail = e; 836 } 837 p = q; 838 } 839 tail->next = NULL; 840 841 if (nmerges <= 1) 842 return llist; 843 844 insize *= 2; 845 } 846 } 847 848 llist_t * 849 llist_sort(llist_t *llist) 850 { 851 return llist_internsort(llist, llist_strcmp); 852 } 853 854 llist_t * 855 llist_intsort(llist_t *llist) 856 { 857 return llist_internsort(llist, llist_intcmp); 858 } 859