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 <ctype.h> 25#include <stdlib.h> 26#include <string.h> 27 28#include <pulse/xmalloc.h> 29 30#include <pulsecore/hashmap.h> 31#include <pulsecore/idxset.h> 32#include <pulsecore/core-util.h> 33#include <pulsecore/macro.h> 34 35#include "modargs.h" 36 37struct pa_modargs { 38 pa_hashmap *raw; 39 pa_hashmap *unescaped; 40}; 41 42struct entry { 43 char *key, *value; 44}; 45 46static int add_key_value(pa_modargs *ma, char *key, char *value, const char* const valid_keys[], bool ignore_dupes) { 47 struct entry *e; 48 char *raw; 49 50 pa_assert(ma); 51 pa_assert(ma->raw); 52 pa_assert(ma->unescaped); 53 pa_assert(key); 54 pa_assert(value); 55 56 if (pa_hashmap_get(ma->unescaped, key)) { 57 pa_xfree(key); 58 pa_xfree(value); 59 60 if (ignore_dupes) 61 return 0; 62 else 63 return -1; 64 } 65 66 if (valid_keys) { 67 const char*const* v; 68 for (v = valid_keys; *v; v++) 69 if (pa_streq(*v, key)) 70 break; 71 72 if (!*v) { 73 pa_xfree(key); 74 pa_xfree(value); 75 return -1; 76 } 77 } 78 79 raw = pa_xstrdup(value); 80 81 e = pa_xnew(struct entry, 1); 82 e->key = key; 83 e->value = pa_unescape(value); 84 pa_hashmap_put(ma->unescaped, key, e); 85 86 if (pa_streq(raw, value)) 87 pa_xfree(raw); 88 else { 89 e = pa_xnew(struct entry, 1); 90 e->key = pa_xstrdup(key); 91 e->value = raw; 92 pa_hashmap_put(ma->raw, key, e); 93 } 94 95 return 0; 96} 97 98static void free_func(void *p) { 99 struct entry *e = p; 100 pa_assert(e); 101 102 pa_xfree(e->key); 103 pa_xfree(e->value); 104 pa_xfree(e); 105} 106 107static int parse(pa_modargs *ma, const char *args, const char* const* valid_keys, bool ignore_dupes) { 108 enum { 109 WHITESPACE, 110 KEY, 111 VALUE_START, 112 VALUE_SIMPLE, 113 VALUE_SIMPLE_ESCAPED, 114 VALUE_DOUBLE_QUOTES, 115 VALUE_DOUBLE_QUOTES_ESCAPED, 116 VALUE_TICKS, 117 VALUE_TICKS_ESCAPED 118 } state; 119 120 const char *p, *key = NULL, *value = NULL; 121 size_t key_len = 0, value_len = 0; 122 123 state = WHITESPACE; 124 125 for (p = args; *p; p++) { 126 switch (state) { 127 128 case WHITESPACE: 129 if (*p == '=') 130 goto fail; 131 else if (!isspace((unsigned char)*p)) { 132 key = p; 133 state = KEY; 134 key_len = 1; 135 } 136 break; 137 138 case KEY: 139 if (*p == '=') 140 state = VALUE_START; 141 else if (isspace((unsigned char)*p)) 142 goto fail; 143 else 144 key_len++; 145 break; 146 147 case VALUE_START: 148 if (*p == '\'') { 149 state = VALUE_TICKS; 150 value = p+1; 151 value_len = 0; 152 } else if (*p == '"') { 153 state = VALUE_DOUBLE_QUOTES; 154 value = p+1; 155 value_len = 0; 156 } else if (isspace((unsigned char)*p)) { 157 if (add_key_value(ma, 158 pa_xstrndup(key, key_len), 159 pa_xstrdup(""), 160 valid_keys, 161 ignore_dupes) < 0) 162 goto fail; 163 state = WHITESPACE; 164 } else if (*p == '\\') { 165 state = VALUE_SIMPLE_ESCAPED; 166 value = p; 167 value_len = 1; 168 } else { 169 state = VALUE_SIMPLE; 170 value = p; 171 value_len = 1; 172 } 173 break; 174 175 case VALUE_SIMPLE: 176 if (isspace((unsigned char)*p)) { 177 if (add_key_value(ma, 178 pa_xstrndup(key, key_len), 179 pa_xstrndup(value, value_len), 180 valid_keys, 181 ignore_dupes) < 0) 182 goto fail; 183 state = WHITESPACE; 184 } else if (*p == '\\') { 185 state = VALUE_SIMPLE_ESCAPED; 186 value_len++; 187 } else 188 value_len++; 189 break; 190 191 case VALUE_SIMPLE_ESCAPED: 192 state = VALUE_SIMPLE; 193 value_len++; 194 break; 195 196 case VALUE_DOUBLE_QUOTES: 197 if (*p == '"') { 198 if (add_key_value(ma, 199 pa_xstrndup(key, key_len), 200 pa_xstrndup(value, value_len), 201 valid_keys, 202 ignore_dupes) < 0) 203 goto fail; 204 state = WHITESPACE; 205 } else if (*p == '\\') { 206 state = VALUE_DOUBLE_QUOTES_ESCAPED; 207 value_len++; 208 } else 209 value_len++; 210 break; 211 212 case VALUE_DOUBLE_QUOTES_ESCAPED: 213 state = VALUE_DOUBLE_QUOTES; 214 value_len++; 215 break; 216 217 case VALUE_TICKS: 218 if (*p == '\'') { 219 if (add_key_value(ma, 220 pa_xstrndup(key, key_len), 221 pa_xstrndup(value, value_len), 222 valid_keys, 223 ignore_dupes) < 0) 224 goto fail; 225 state = WHITESPACE; 226 } else if (*p == '\\') { 227 state = VALUE_TICKS_ESCAPED; 228 value_len++; 229 } else 230 value_len++; 231 break; 232 233 case VALUE_TICKS_ESCAPED: 234 state = VALUE_TICKS; 235 value_len++; 236 break; 237 } 238 } 239 240 if (state == VALUE_START) { 241 if (add_key_value(ma, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys, ignore_dupes) < 0) 242 goto fail; 243 } else if (state == VALUE_SIMPLE) { 244 if (add_key_value(ma, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys, ignore_dupes) < 0) 245 goto fail; 246 } else if (state != WHITESPACE) 247 goto fail; 248 249 return 0; 250 251fail: 252 return -1; 253} 254 255pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { 256 pa_modargs *ma = pa_xnew(pa_modargs, 1); 257 258 ma->raw = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, free_func); 259 ma->unescaped = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, free_func); 260 261 if (args && parse(ma, args, valid_keys, false) < 0) 262 goto fail; 263 264 return ma; 265 266fail: 267 pa_modargs_free(ma); 268 return NULL; 269} 270 271int pa_modargs_append(pa_modargs *ma, const char *args, const char* const* valid_keys) { 272 return parse(ma, args, valid_keys, true); 273} 274 275int pa_modargs_remove_key(pa_modargs *ma, const char *key) { 276 if (pa_hashmap_remove_and_free(ma->unescaped, key) == 0) { 277 pa_hashmap_remove_and_free(ma->raw, key); 278 return 0; 279 } 280 281 return -1; 282} 283 284void pa_modargs_free(pa_modargs*ma) { 285 pa_assert(ma); 286 287 pa_hashmap_free(ma->raw); 288 pa_hashmap_free(ma->unescaped); 289 pa_xfree(ma); 290} 291 292const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) { 293 struct entry*e; 294 295 pa_assert(ma); 296 pa_assert(key); 297 298 if (!(e = pa_hashmap_get(ma->unescaped, key))) 299 return def; 300 301 return e->value; 302} 303 304static const char *modargs_get_value_raw(pa_modargs *ma, const char *key, const char *def) { 305 struct entry*e; 306 307 pa_assert(ma); 308 pa_assert(key); 309 310 if (!(e = pa_hashmap_get(ma->raw, key))) 311 if (!(e = pa_hashmap_get(ma->unescaped, key))) 312 return def; 313 314 return e->value; 315} 316 317int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { 318 const char *v; 319 320 pa_assert(value); 321 322 if (!(v = pa_modargs_get_value(ma, key, NULL))) 323 return 0; 324 325 if (pa_atou(v, value) < 0) 326 return -1; 327 328 return 0; 329} 330 331int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { 332 const char *v; 333 334 pa_assert(value); 335 336 if (!(v = pa_modargs_get_value(ma, key, NULL))) 337 return 0; 338 339 if (pa_atoi(v, value) < 0) 340 return -1; 341 342 return 0; 343} 344 345int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, bool *value) { 346 const char *v; 347 int r; 348 349 pa_assert(value); 350 351 if (!(v = pa_modargs_get_value(ma, key, NULL))) 352 return 0; 353 354 if (!*v) 355 return -1; 356 357 if ((r = pa_parse_boolean(v)) < 0) 358 return -1; 359 360 *value = r; 361 return 0; 362} 363 364int pa_modargs_get_value_double(pa_modargs *ma, const char *key, double *value) { 365 const char *v; 366 367 pa_assert(value); 368 369 if (!(v = pa_modargs_get_value(ma, key, NULL))) 370 return 0; 371 372 if (pa_atod(v, value) < 0) 373 return -1; 374 375 return 0; 376} 377 378int pa_modargs_get_value_volume(pa_modargs *ma, const char *key, pa_volume_t *value) { 379 const char *v; 380 381 pa_assert(value); 382 383 if (!(v = pa_modargs_get_value(ma, key, NULL))) 384 return 0; 385 386 if (pa_parse_volume(v, value) < 0) 387 return -1; 388 389 return 0; 390} 391 392int pa_modargs_get_sample_rate(pa_modargs *ma, uint32_t *rate) { 393 uint32_t rate_local; 394 395 pa_assert(rate); 396 397 rate_local = *rate; 398 if ((pa_modargs_get_value_u32(ma, "rate", &rate_local)) < 0 || 399 !pa_sample_rate_valid(rate_local)) 400 return -1; 401 402 *rate = rate_local; 403 404 return 0; 405} 406 407int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { 408 const char *format; 409 uint32_t channels; 410 pa_sample_spec ss; 411 412 pa_assert(rss); 413 414 ss = *rss; 415 if ((pa_modargs_get_sample_rate(ma, &ss.rate)) < 0) 416 return -1; 417 418 channels = ss.channels; 419 if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0 || 420 !pa_channels_valid(channels)) 421 return -1; 422 ss.channels = (uint8_t) channels; 423 424 if ((format = pa_modargs_get_value(ma, "format", NULL))) 425 if ((ss.format = pa_parse_sample_format(format)) < 0) 426 return -1; 427 428 if (!pa_sample_spec_valid(&ss)) 429 return -1; 430 431 *rss = ss; 432 433 return 0; 434} 435 436int pa_modargs_get_alternate_sample_rate(pa_modargs *ma, uint32_t *alternate_rate) { 437 uint32_t rate_local; 438 439 pa_assert(alternate_rate); 440 441 rate_local = *alternate_rate; 442 if ((pa_modargs_get_value_u32(ma, "alternate_rate", &rate_local)) < 0 || 443 !pa_sample_rate_valid(*alternate_rate)) 444 return -1; 445 446 *alternate_rate = rate_local; 447 448 return 0; 449} 450 451int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) { 452 pa_channel_map map; 453 const char *cm; 454 455 pa_assert(rmap); 456 457 map = *rmap; 458 459 if ((cm = pa_modargs_get_value(ma, name ? name : "channel_map", NULL))) 460 if (!pa_channel_map_parse(&map, cm)) 461 return -1; 462 463 if (!pa_channel_map_valid(&map)) 464 return -1; 465 466 *rmap = map; 467 return 0; 468} 469 470int pa_modargs_get_resample_method(pa_modargs *ma, pa_resample_method_t *rmethod) { 471 const char *m; 472 473 pa_assert(ma); 474 pa_assert(rmethod); 475 476 if ((m = pa_modargs_get_value(ma, "resample_method", NULL))) { 477 pa_resample_method_t method = pa_parse_resample_method(m); 478 479 if (method == PA_RESAMPLER_INVALID) 480 return -1; 481 482 *rmethod = method; 483 } 484 485 return 0; 486} 487 488int pa_modargs_get_sample_spec_and_channel_map( 489 pa_modargs *ma, 490 pa_sample_spec *rss, 491 pa_channel_map *rmap, 492 pa_channel_map_def_t def) { 493 494 pa_sample_spec ss; 495 pa_channel_map map; 496 497 pa_assert(rss); 498 pa_assert(rmap); 499 500 ss = *rss; 501 502 if (pa_modargs_get_sample_spec(ma, &ss) < 0) 503 return -1; 504 505 map = *rmap; 506 507 if (ss.channels != map.channels) 508 pa_channel_map_init_extend(&map, ss.channels, def); 509 510 if (pa_modargs_get_channel_map(ma, NULL, &map) < 0) 511 return -1; 512 513 if (map.channels != ss.channels) { 514 if (!pa_modargs_get_value(ma, "channels", NULL)) 515 ss.channels = map.channels; 516 else 517 return -1; 518 } 519 520 *rmap = map; 521 *rss = ss; 522 523 return 0; 524} 525 526int pa_modargs_get_proplist(pa_modargs *ma, const char *name, pa_proplist *p, pa_update_mode_t m) { 527 const char *v; 528 pa_proplist *n; 529 530 pa_assert(ma); 531 pa_assert(name); 532 pa_assert(p); 533 534 if (!(v = modargs_get_value_raw(ma, name, NULL))) 535 return 0; 536 537 if (!(n = pa_proplist_from_string(v))) 538 return -1; 539 540 pa_proplist_update(p, m, n); 541 pa_proplist_free(n); 542 543 return 0; 544} 545 546const char *pa_modargs_iterate(pa_modargs *ma, void **state) { 547 struct entry *e; 548 549 pa_assert(ma); 550 551 if (!(e = pa_hashmap_iterate(ma->unescaped, state, NULL))) 552 return NULL; 553 554 return e->key; 555} 556 557int pa_modargs_merge_missing(pa_modargs *dst, pa_modargs *src, const char* const valid_keys[]) { 558 void *state; 559 const char *key, *value; 560 int ret = 0; 561 562 for (state = NULL, key = pa_modargs_iterate(src, &state); key; key = pa_modargs_iterate(src, &state)) { 563 value = pa_modargs_get_value(src, key, NULL); 564 if (value && add_key_value(dst, pa_xstrdup(key), pa_xstrdup(value), valid_keys, true) < 0) { 565 pa_log_warn("Failed to add module argument '%s=%s'", key, value); 566 ret = -1; 567 /* continue to gather all errors */ 568 } 569 } 570 571 return ret; 572} 573