|
13 | 13 | #include <subcmd/exec-cmd.h>
|
14 | 14 | #include "util/hist.h" /* perf_hist_config */
|
15 | 15 | #include "util/llvm-utils.h" /* perf_llvm_config */
|
| 16 | +#include "config.h" |
16 | 17 |
|
17 | 18 | #define MAXNAME (256)
|
18 | 19 |
|
@@ -524,6 +525,178 @@ int perf_config(config_fn_t fn, void *data)
|
524 | 525 | return ret;
|
525 | 526 | }
|
526 | 527 |
|
| 528 | +static struct perf_config_section *find_section(struct list_head *sections, |
| 529 | + const char *section_name) |
| 530 | +{ |
| 531 | + struct perf_config_section *section; |
| 532 | + |
| 533 | + list_for_each_entry(section, sections, node) |
| 534 | + if (!strcmp(section->name, section_name)) |
| 535 | + return section; |
| 536 | + |
| 537 | + return NULL; |
| 538 | +} |
| 539 | + |
| 540 | +static struct perf_config_item *find_config_item(const char *name, |
| 541 | + struct perf_config_section *section) |
| 542 | +{ |
| 543 | + struct perf_config_item *item; |
| 544 | + |
| 545 | + list_for_each_entry(item, §ion->items, node) |
| 546 | + if (!strcmp(item->name, name)) |
| 547 | + return item; |
| 548 | + |
| 549 | + return NULL; |
| 550 | +} |
| 551 | + |
| 552 | +static struct perf_config_section *add_section(struct list_head *sections, |
| 553 | + const char *section_name) |
| 554 | +{ |
| 555 | + struct perf_config_section *section = zalloc(sizeof(*section)); |
| 556 | + |
| 557 | + if (!section) |
| 558 | + return NULL; |
| 559 | + |
| 560 | + INIT_LIST_HEAD(§ion->items); |
| 561 | + section->name = strdup(section_name); |
| 562 | + if (!section->name) { |
| 563 | + pr_debug("%s: strdup failed\n", __func__); |
| 564 | + free(section); |
| 565 | + return NULL; |
| 566 | + } |
| 567 | + |
| 568 | + list_add_tail(§ion->node, sections); |
| 569 | + return section; |
| 570 | +} |
| 571 | + |
| 572 | +static struct perf_config_item *add_config_item(struct perf_config_section *section, |
| 573 | + const char *name) |
| 574 | +{ |
| 575 | + struct perf_config_item *item = zalloc(sizeof(*item)); |
| 576 | + |
| 577 | + if (!item) |
| 578 | + return NULL; |
| 579 | + |
| 580 | + item->name = strdup(name); |
| 581 | + if (!item->name) { |
| 582 | + pr_debug("%s: strdup failed\n", __func__); |
| 583 | + free(item); |
| 584 | + return NULL; |
| 585 | + } |
| 586 | + |
| 587 | + list_add_tail(&item->node, §ion->items); |
| 588 | + return item; |
| 589 | +} |
| 590 | + |
| 591 | +static int set_value(struct perf_config_item *item, const char *value) |
| 592 | +{ |
| 593 | + char *val = strdup(value); |
| 594 | + |
| 595 | + if (!val) |
| 596 | + return -1; |
| 597 | + |
| 598 | + zfree(&item->value); |
| 599 | + item->value = val; |
| 600 | + return 0; |
| 601 | +} |
| 602 | + |
| 603 | +static int collect_config(const char *var, const char *value, |
| 604 | + void *perf_config_set) |
| 605 | +{ |
| 606 | + int ret = -1; |
| 607 | + char *ptr, *key; |
| 608 | + char *section_name, *name; |
| 609 | + struct perf_config_section *section = NULL; |
| 610 | + struct perf_config_item *item = NULL; |
| 611 | + struct perf_config_set *set = perf_config_set; |
| 612 | + struct list_head *sections = &set->sections; |
| 613 | + |
| 614 | + key = ptr = strdup(var); |
| 615 | + if (!key) { |
| 616 | + pr_debug("%s: strdup failed\n", __func__); |
| 617 | + return -1; |
| 618 | + } |
| 619 | + |
| 620 | + section_name = strsep(&ptr, "."); |
| 621 | + name = ptr; |
| 622 | + if (name == NULL || value == NULL) |
| 623 | + goto out_free; |
| 624 | + |
| 625 | + section = find_section(sections, section_name); |
| 626 | + if (!section) { |
| 627 | + section = add_section(sections, section_name); |
| 628 | + if (!section) |
| 629 | + goto out_free; |
| 630 | + } |
| 631 | + |
| 632 | + item = find_config_item(name, section); |
| 633 | + if (!item) { |
| 634 | + item = add_config_item(section, name); |
| 635 | + if (!item) |
| 636 | + goto out_free; |
| 637 | + } |
| 638 | + |
| 639 | + ret = set_value(item, value); |
| 640 | + return ret; |
| 641 | + |
| 642 | +out_free: |
| 643 | + free(key); |
| 644 | + perf_config_set__delete(set); |
| 645 | + return -1; |
| 646 | +} |
| 647 | + |
| 648 | +struct perf_config_set *perf_config_set__new(void) |
| 649 | +{ |
| 650 | + struct perf_config_set *set = zalloc(sizeof(*set)); |
| 651 | + |
| 652 | + if (set) { |
| 653 | + INIT_LIST_HEAD(&set->sections); |
| 654 | + perf_config(collect_config, set); |
| 655 | + } |
| 656 | + |
| 657 | + return set; |
| 658 | +} |
| 659 | + |
| 660 | +static void perf_config_item__delete(struct perf_config_item *item) |
| 661 | +{ |
| 662 | + zfree(&item->name); |
| 663 | + zfree(&item->value); |
| 664 | + free(item); |
| 665 | +} |
| 666 | + |
| 667 | +static void perf_config_section__purge(struct perf_config_section *section) |
| 668 | +{ |
| 669 | + struct perf_config_item *item, *tmp; |
| 670 | + |
| 671 | + list_for_each_entry_safe(item, tmp, §ion->items, node) { |
| 672 | + list_del_init(&item->node); |
| 673 | + perf_config_item__delete(item); |
| 674 | + } |
| 675 | +} |
| 676 | + |
| 677 | +static void perf_config_section__delete(struct perf_config_section *section) |
| 678 | +{ |
| 679 | + perf_config_section__purge(section); |
| 680 | + zfree(§ion->name); |
| 681 | + free(section); |
| 682 | +} |
| 683 | + |
| 684 | +static void perf_config_set__purge(struct perf_config_set *set) |
| 685 | +{ |
| 686 | + struct perf_config_section *section, *tmp; |
| 687 | + |
| 688 | + list_for_each_entry_safe(section, tmp, &set->sections, node) { |
| 689 | + list_del_init(§ion->node); |
| 690 | + perf_config_section__delete(section); |
| 691 | + } |
| 692 | +} |
| 693 | + |
| 694 | +void perf_config_set__delete(struct perf_config_set *set) |
| 695 | +{ |
| 696 | + perf_config_set__purge(set); |
| 697 | + free(set); |
| 698 | +} |
| 699 | + |
527 | 700 | /*
|
528 | 701 | * Call this to report error for your variable that should not
|
529 | 702 | * get a boolean value (i.e. "[my] var" means "true").
|
|
0 commit comments