linux/tools/perf/util/strlist.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
   4 */
   5
   6#include "strlist.h"
   7#include <errno.h>
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <unistd.h>
  12#include <linux/zalloc.h>
  13
  14static
  15struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
  16{
  17        const char *s = entry;
  18        struct rb_node *rc = NULL;
  19        struct strlist *strlist = container_of(rblist, struct strlist, rblist);
  20        struct str_node *snode = malloc(sizeof(*snode));
  21
  22        if (snode != NULL) {
  23                if (strlist->dupstr) {
  24                        s = strdup(s);
  25                        if (s == NULL)
  26                                goto out_delete;
  27                }
  28                snode->s = s;
  29                rc = &snode->rb_node;
  30        }
  31
  32        return rc;
  33
  34out_delete:
  35        free(snode);
  36        return NULL;
  37}
  38
  39static void str_node__delete(struct str_node *snode, bool dupstr)
  40{
  41        if (dupstr)
  42                zfree((char **)&snode->s);
  43        free(snode);
  44}
  45
  46static
  47void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
  48{
  49        struct strlist *slist = container_of(rblist, struct strlist, rblist);
  50        struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
  51
  52        str_node__delete(snode, slist->dupstr);
  53}
  54
  55static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
  56{
  57        const char *str = entry;
  58        struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
  59
  60        return strcmp(snode->s, str);
  61}
  62
  63int strlist__add(struct strlist *slist, const char *new_entry)
  64{
  65        return rblist__add_node(&slist->rblist, new_entry);
  66}
  67
  68int strlist__load(struct strlist *slist, const char *filename)
  69{
  70        char entry[1024];
  71        int err;
  72        FILE *fp = fopen(filename, "r");
  73
  74        if (fp == NULL)
  75                return -errno;
  76
  77        while (fgets(entry, sizeof(entry), fp) != NULL) {
  78                const size_t len = strlen(entry);
  79
  80                if (len == 0)
  81                        continue;
  82                entry[len - 1] = '\0';
  83
  84                err = strlist__add(slist, entry);
  85                if (err != 0)
  86                        goto out;
  87        }
  88
  89        err = 0;
  90out:
  91        fclose(fp);
  92        return err;
  93}
  94
  95void strlist__remove(struct strlist *slist, struct str_node *snode)
  96{
  97        rblist__remove_node(&slist->rblist, &snode->rb_node);
  98}
  99
 100struct str_node *strlist__find(struct strlist *slist, const char *entry)
 101{
 102        struct str_node *snode = NULL;
 103        struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
 104
 105        if (rb_node)
 106                snode = container_of(rb_node, struct str_node, rb_node);
 107
 108        return snode;
 109}
 110
 111static int strlist__parse_list_entry(struct strlist *slist, const char *s,
 112                                     const char *subst_dir)
 113{
 114        int err;
 115        char *subst = NULL;
 116
 117        if (strncmp(s, "file://", 7) == 0)
 118                return strlist__load(slist, s + 7);
 119
 120        if (subst_dir) {
 121                err = -ENOMEM;
 122                if (asprintf(&subst, "%s/%s", subst_dir, s) < 0)
 123                        goto out;
 124
 125                if (access(subst, F_OK) == 0) {
 126                        err = strlist__load(slist, subst);
 127                        goto out;
 128                }
 129
 130                if (slist->file_only) {
 131                        err = -ENOENT;
 132                        goto out;
 133                }
 134        }
 135
 136        err = strlist__add(slist, s);
 137out:
 138        free(subst);
 139        return err;
 140}
 141
 142static int strlist__parse_list(struct strlist *slist, const char *s, const char *subst_dir)
 143{
 144        char *sep;
 145        int err;
 146
 147        while ((sep = strchr(s, ',')) != NULL) {
 148                *sep = '\0';
 149                err = strlist__parse_list_entry(slist, s, subst_dir);
 150                *sep = ',';
 151                if (err != 0)
 152                        return err;
 153                s = sep + 1;
 154        }
 155
 156        return *s ? strlist__parse_list_entry(slist, s, subst_dir) : 0;
 157}
 158
 159struct strlist *strlist__new(const char *list, const struct strlist_config *config)
 160{
 161        struct strlist *slist = malloc(sizeof(*slist));
 162
 163        if (slist != NULL) {
 164                bool dupstr = true;
 165                bool file_only = false;
 166                const char *dirname = NULL;
 167
 168                if (config) {
 169                        dupstr = !config->dont_dupstr;
 170                        dirname = config->dirname;
 171                        file_only = config->file_only;
 172                }
 173
 174                rblist__init(&slist->rblist);
 175                slist->rblist.node_cmp    = strlist__node_cmp;
 176                slist->rblist.node_new    = strlist__node_new;
 177                slist->rblist.node_delete = strlist__node_delete;
 178
 179                slist->dupstr    = dupstr;
 180                slist->file_only = file_only;
 181
 182                if (list && strlist__parse_list(slist, list, dirname) != 0)
 183                        goto out_error;
 184        }
 185
 186        return slist;
 187out_error:
 188        free(slist);
 189        return NULL;
 190}
 191
 192void strlist__delete(struct strlist *slist)
 193{
 194        if (slist != NULL)
 195                rblist__delete(&slist->rblist);
 196}
 197
 198struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
 199{
 200        struct str_node *snode = NULL;
 201        struct rb_node *rb_node;
 202
 203        rb_node = rblist__entry(&slist->rblist, idx);
 204        if (rb_node)
 205                snode = container_of(rb_node, struct str_node, rb_node);
 206
 207        return snode;
 208}
 209