1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <stdlib.h> 25#include <string.h> 26#include <string.h> 27#include <stdio.h> 28 29#include <pulse/xmalloc.h> 30 31#include <pulsecore/source.h> 32#include <pulsecore/sink.h> 33#include <pulsecore/core-subscribe.h> 34#include <pulsecore/core-util.h> 35#include <pulsecore/macro.h> 36 37#include "namereg.h" 38 39struct namereg_entry { 40 pa_namereg_type_t type; 41 char *name; 42 void *data; 43}; 44 45static bool is_valid_char(char c) { 46 return 47 (c >= 'a' && c <= 'z') || 48 (c >= 'A' && c <= 'Z') || 49 (c >= '0' && c <= '9') || 50 c == '.' || 51 c == '-' || 52 c == '_'; 53} 54 55bool pa_namereg_is_valid_name(const char *name) { 56 const char *c; 57 58 pa_assert(name); 59 60 if (*name == 0) 61 return false; 62 63 for (c = name; *c && (c-name < PA_NAME_MAX); c++) 64 if (!is_valid_char(*c)) 65 return false; 66 67 if (*c) 68 return false; 69 70 return true; 71} 72 73bool pa_namereg_is_valid_name_or_wildcard(const char *name, pa_namereg_type_t type) { 74 75 pa_assert(name); 76 77 if (pa_namereg_is_valid_name(name)) 78 return true; 79 80 if (type == PA_NAMEREG_SINK && 81 pa_streq(name, "@DEFAULT_SINK@")) 82 return true; 83 84 if (type == PA_NAMEREG_SOURCE && 85 (pa_streq(name, "@DEFAULT_SOURCE@") || 86 pa_streq(name, "@DEFAULT_MONITOR@"))) 87 return true; 88 89 return false; 90} 91 92char* pa_namereg_make_valid_name(const char *name) { 93 const char *a; 94 char *b, *n; 95 96 if (*name == 0) 97 return NULL; 98 99 n = pa_xnew(char, strlen(name)+1); 100 101 for (a = name, b = n; *a && (a-name < PA_NAME_MAX); a++, b++) 102 *b = (char) (is_valid_char(*a) ? *a : '_'); 103 104 *b = 0; 105 106 return n; 107} 108 109const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, bool fail) { 110 struct namereg_entry *e; 111 char *n = NULL; 112 113 pa_assert(c); 114 pa_assert(name); 115 pa_assert(data); 116 117 if (!*name) 118 return NULL; 119 120 if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) && 121 !pa_namereg_is_valid_name(name)) { 122 123 if (fail) 124 return NULL; 125 126 if (!(name = n = pa_namereg_make_valid_name(name))) 127 return NULL; 128 } 129 130 if ((e = pa_hashmap_get(c->namereg, name)) && fail) { 131 pa_xfree(n); 132 return NULL; 133 } 134 135 if (e) { 136 unsigned i; 137 size_t l = strlen(name); 138 char *k; 139 140 if (l+4 > PA_NAME_MAX) { 141 pa_xfree(n); 142 return NULL; 143 } 144 145 k = pa_xmalloc(l+4); 146 147 for (i = 2; i <= 99; i++) { 148 pa_snprintf(k, l+4, "%s.%u", name, i); 149 150 if (!(e = pa_hashmap_get(c->namereg, k))) 151 break; 152 } 153 154 if (e) { 155 pa_xfree(n); 156 pa_xfree(k); 157 return NULL; 158 } 159 160 pa_xfree(n); 161 n = k; 162 } 163 164 e = pa_xnew(struct namereg_entry, 1); 165 e->type = type; 166 e->name = n ? n : pa_xstrdup(name); 167 e->data = data; 168 169 pa_assert_se(pa_hashmap_put(c->namereg, e->name, e) >= 0); 170 171 return e->name; 172} 173 174void pa_namereg_unregister(pa_core *c, const char *name) { 175 struct namereg_entry *e; 176 177 pa_assert(c); 178 pa_assert(name); 179 180 pa_assert_se(e = pa_hashmap_remove(c->namereg, name)); 181 pa_xfree(e->name); 182 pa_xfree(e); 183} 184 185void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) { 186 struct namereg_entry *e; 187 uint32_t idx; 188 pa_assert(c); 189 190 if (type == PA_NAMEREG_SOURCE && (!name || pa_streq(name, "@DEFAULT_SOURCE@"))) { 191 return c->default_source; 192 193 } else if (type == PA_NAMEREG_SINK && (!name || pa_streq(name, "@DEFAULT_SINK@"))) { 194 return c->default_sink; 195 196 } else if (type == PA_NAMEREG_SOURCE && name && pa_streq(name, "@DEFAULT_MONITOR@")) { 197 if (c->default_sink) 198 return c->default_sink->monitor_source; 199 else 200 return NULL; 201 } 202 203 if (!name) 204 return NULL; 205 206 if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) && 207 !pa_namereg_is_valid_name(name)) 208 return NULL; 209 210 if ((e = pa_hashmap_get(c->namereg, name))) 211 if (e->type == type) 212 return e->data; 213 214 if (pa_atou(name, &idx) < 0) 215 return NULL; 216 217 if (type == PA_NAMEREG_SINK) 218 return pa_idxset_get_by_index(c->sinks, idx); 219 else if (type == PA_NAMEREG_SOURCE) 220 return pa_idxset_get_by_index(c->sources, idx); 221 else if (type == PA_NAMEREG_SAMPLE && c->scache) 222 return pa_idxset_get_by_index(c->scache, idx); 223 else if (type == PA_NAMEREG_CARD) 224 return pa_idxset_get_by_index(c->cards, idx); 225 226 return NULL; 227} 228