1/* 2 * This library is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU Lesser General Public 4 * License as published by the Free Software Foundation; either 5 * version 2 of the License, or (at your option) any later version. 6 * 7 * This library is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 * Lesser General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 * 16 * Copyright (C) 2019 Red Hat Inc. 17 * Authors: Jaroslav Kysela <perex@perex.cz> 18 */ 19 20#include <stdio.h> 21#include <string.h> 22#include <alsa/asoundlib.h> 23#include <alsa/use-case.h> 24#include "usecase.h" 25#include "aconfig.h" 26#include "version.h" 27 28struct renderer { 29 int (*init)(struct renderer *r); 30 void (*done)(struct renderer *r); 31 int (*verb_begin)(struct renderer *r, 32 const char *verb, 33 const char *comment); 34 int (*verb_end)(struct renderer *r); 35 int (*device_block_begin)(struct renderer *r); 36 int (*device_block_end)(struct renderer *r); 37 int (*device_begin)(struct renderer *r, 38 const char *device, 39 const char *comment); 40 int (*device_end)(struct renderer *r); 41 int (*modifier_block_begin)(struct renderer *r); 42 int (*modifier_block_end)(struct renderer *r); 43 int (*modifier_begin)(struct renderer *r, 44 const char *device, 45 const char *comment); 46 int (*modifier_end)(struct renderer *r); 47 int (*supported_begin)(struct renderer *r); 48 int (*supported_value)(struct renderer *r, const char *value, int last); 49 int (*supported_end)(struct renderer *r); 50 int (*conflict_begin)(struct renderer *r); 51 int (*conflict_value)(struct renderer *r, const char *value, int last); 52 int (*conflict_end)(struct renderer *r); 53 int (*value_begin)(struct renderer *r); 54 int (*value_end)(struct renderer *r); 55 int (*value)(struct renderer *r, const char *ident, const char *value); 56 void *opaque; 57}; 58 59/* 60 * Text renderer 61 */ 62 63struct text { 64 char a[1]; 65}; 66 67static char *tesc(const char *s, char *buf, size_t buf_len) 68{ 69 char *dst = buf; 70 char c = '\0'; 71 if (strchr(s, '"') || strchr(s, ' ') || strchr(s, '.')) { 72 *dst++ = c = '"'; 73 buf_len--; 74 } 75 while (*s && buf_len > 2) { 76 if (*s == '"') { 77 if (buf_len > 3) { 78 *dst++ = '\\'; 79 *dst++ = *s++; 80 buf_len -= 2; 81 continue; 82 } else { 83 break; 84 } 85 } 86 *dst++ = *s++; 87 } 88 if (c) 89 *dst++ = c; 90 *dst = '\0'; 91 return buf; 92} 93 94#define ESC(s, esc) tesc((s), (esc), sizeof(esc)) 95 96static int text_verb_start(struct renderer *r ATTRIBUTE_UNUSED, 97 const char *verb, const char *comment) 98{ 99 char buf1[128], buf2[128]; 100 printf("Verb.%s {\n", ESC(verb, buf1)); 101 if (comment && comment[0]) 102 printf("\tComment %s\n", ESC(comment, buf2)); 103 return 0; 104} 105 106static int text_verb_end(struct renderer *r ATTRIBUTE_UNUSED) 107{ 108 printf("}\n"); 109 return 0; 110} 111 112static int text_2nd_level_begin(struct renderer *r ATTRIBUTE_UNUSED, 113 const char *key, 114 const char *val, 115 const char *comment) 116{ 117 char buf1[128], buf2[128]; 118 printf("\t%s.%s {\n", key, ESC(val, buf1)); 119 if (comment && comment[0]) 120 printf("\t\tComment %s\n", ESC(comment, buf2)); 121 return 0; 122} 123 124static int text_2nd_level_end(struct renderer *r ATTRIBUTE_UNUSED) 125{ 126 printf("\t}\n"); 127 return 0; 128} 129 130static int text_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt) 131{ 132 printf("\t\t%s", txt); 133 return 0; 134} 135 136static int text_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt) 137{ 138 printf("\t\t\t%s", txt); 139 return 0; 140} 141 142static int text_dev_start(struct renderer *r, const char *dev, const char *comment) 143{ 144 return text_2nd_level_begin(r, "Device", dev, comment); 145} 146 147static int text_mod_start(struct renderer *r, const char *dev, const char *comment) 148{ 149 return text_2nd_level_begin(r, "Modifier", dev, comment); 150} 151 152static int text_supcon_start(struct renderer *r, const char *key) 153{ 154 if (text_2nd_level(r, key)) 155 return 1; 156 printf(" [\n"); 157 return 0; 158} 159 160static int text_supcon_value(struct renderer *r, const char *value, int last) 161{ 162 char buf[256]; 163 ESC(value, buf); 164 if (!last && strlen(buf) < sizeof(buf) - 2) 165 strcat(buf, ","); 166 if (text_3rd_level(r, buf)) 167 return 1; 168 printf("\n"); 169 return 0; 170} 171 172static int text_supcon_end(struct renderer *r) 173{ 174 return text_2nd_level(r, "]\n"); 175} 176 177static int text_sup_start(struct renderer *r) 178{ 179 return text_supcon_start(r, "SupportedDevices"); 180} 181 182static int text_con_start(struct renderer *r) 183{ 184 return text_supcon_start(r, "ConflictingDevices"); 185} 186 187static int text_value_begin(struct renderer *r) 188{ 189 return text_2nd_level(r, "Values {\n"); 190} 191 192static int text_value_end(struct renderer *r) 193{ 194 return text_2nd_level(r, "}\n"); 195} 196 197static int text_value(struct renderer *r, const char *ident, const char *value) 198{ 199 char buf1[256], buf2[256]; 200 int err; 201 202 ESC(ident, buf1); 203 err = text_3rd_level(r, buf1); 204 if (err < 0) 205 return err; 206 ESC(value, buf2); 207 printf(" %s\n", buf2); 208 return 0; 209} 210 211static struct renderer text_renderer = { 212 .verb_begin = text_verb_start, 213 .verb_end = text_verb_end, 214 .device_begin = text_dev_start, 215 .device_end = text_2nd_level_end, 216 .modifier_begin = text_mod_start, 217 .modifier_end = text_2nd_level_end, 218 .supported_begin = text_sup_start, 219 .supported_value = text_supcon_value, 220 .supported_end = text_supcon_end, 221 .conflict_begin = text_con_start, 222 .conflict_value = text_supcon_value, 223 .conflict_end = text_supcon_end, 224 .value_begin = text_value_begin, 225 .value_end = text_value_end, 226 .value = text_value, 227}; 228 229/* 230 * JSON renderer 231 */ 232 233struct json { 234 int block[5]; 235}; 236 237static char *jesc(const char *s, char *buf, size_t buf_len) 238{ 239 char *dst = buf; 240 char c = '"'; 241 *dst++ = c; 242 buf_len--; 243 while (*s && buf_len > 2) { 244 if (*s == '"') { 245 if (buf_len > 3) { 246 *dst++ = '\\'; 247 *dst++ = *s++; 248 buf_len -= 2; 249 continue; 250 } else { 251 break; 252 } 253 } 254 *dst++ = *s++; 255 } 256 *dst++ = c; 257 *dst = '\0'; 258 return buf; 259} 260 261#define JESC(s, esc) jesc((s), (esc), sizeof(esc)) 262 263static void json_block(struct renderer *r, int level, int last) 264{ 265 struct json *j = r->opaque; 266 printf((j->block[level] && !last) ? ",\n" : "\n"); 267 j->block[level] = last ? 0 : 1; 268} 269 270static int json_init(struct renderer *r ATTRIBUTE_UNUSED) 271{ 272 printf("{\n \"Verbs\": {"); 273 return 0; 274} 275 276static void json_done(struct renderer *r) 277{ 278 json_block(r, 0, 1); 279 printf(" }\n}\n"); 280} 281 282static int json_verb_start(struct renderer *r, const char *verb, const char *comment) 283{ 284 char buf[256]; 285 json_block(r, 0, 0); 286 printf(" %s: {", JESC(verb, buf)); 287 if (comment && comment[0]) { 288 json_block(r, 1, 0); 289 printf(" \"Comment\": %s", JESC(comment, buf)); 290 } 291 return 0; 292} 293 294static int json_verb_end(struct renderer *r) 295{ 296 json_block(r, 1, 1); 297 printf(" }"); 298 return 0; 299} 300 301static int json_2nd_level_block_end(struct renderer *r) 302{ 303 json_block(r, 2, 1); 304 printf(" }"); 305 return 0; 306} 307 308static int json_2nd_level_begin(struct renderer *r, 309 const char *val, 310 const char *comment) 311{ 312 char buf[256]; 313 json_block(r, 2, 0); 314 printf(" %s: {", JESC(val, buf)); 315 if (comment && comment[0]) { 316 json_block(r, 3, 0); 317 printf(" \"Comment\": %s", JESC(comment, buf)); 318 } 319 return 0; 320} 321 322static int json_2nd_level_end(struct renderer *r) 323{ 324 json_block(r, 3, 1); 325 printf(" }"); 326 return 0; 327} 328 329static int json_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt) 330{ 331 printf(" %s", txt); 332 return 0; 333} 334 335static int json_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt) 336{ 337 printf(" %s", txt); 338 return 0; 339} 340 341static int json_dev_block_start(struct renderer *r) 342{ 343 json_block(r, 1, 0); 344 printf(" \"Devices\": {"); 345 return 0; 346} 347 348static int json_mod_block_start(struct renderer *r) 349{ 350 json_block(r, 1, 0); 351 printf(" \"Modifiers\": {"); 352 return 0; 353} 354 355static int json_supcon_start(struct renderer *r, const char *key) 356{ 357 json_block(r, 3, 0); 358 if (json_2nd_level(r, key)) 359 return 1; 360 printf(": ["); 361 return 0; 362} 363 364static int json_supcon_value(struct renderer *r, const char *value, 365 int last ATTRIBUTE_UNUSED) 366{ 367 char buf[256]; 368 JESC(value, buf); 369 json_block(r, 4, 0); 370 return json_3rd_level(r, buf); 371} 372 373static int json_supcon_end(struct renderer *r) 374{ 375 json_block(r, 4, 1); 376 return json_2nd_level(r, "]"); 377} 378 379static int json_sup_start(struct renderer *r) 380{ 381 return json_supcon_start(r, "\"SupportedDevices\""); 382} 383 384static int json_con_start(struct renderer *r) 385{ 386 return json_supcon_start(r, "\"ConflictingDevices\""); 387} 388 389static int json_value_begin(struct renderer *r) 390{ 391 json_block(r, 3, 0); 392 return json_2nd_level(r, "\"Values\": {"); 393} 394 395static int json_value_end(struct renderer *r) 396{ 397 json_block(r, 4, 1); 398 return json_2nd_level(r, "}"); 399} 400 401static int json_value(struct renderer *r, const char *ident, const char *value) 402{ 403 char buf[256]; 404 int err; 405 406 json_block(r, 4, 0); 407 JESC(ident, buf); 408 err = json_3rd_level(r, buf); 409 if (err < 0) 410 return err; 411 JESC(value, buf); 412 printf(": %s", buf); 413 return 0; 414} 415 416static struct renderer json_renderer = { 417 .init = json_init, 418 .done = json_done, 419 .verb_begin = json_verb_start, 420 .verb_end = json_verb_end, 421 .device_block_begin = json_dev_block_start, 422 .device_block_end = json_2nd_level_block_end, 423 .device_begin = json_2nd_level_begin, 424 .device_end = json_2nd_level_end, 425 .modifier_block_begin = json_mod_block_start, 426 .modifier_block_end = json_2nd_level_block_end, 427 .modifier_begin = json_2nd_level_begin, 428 .modifier_end = json_2nd_level_end, 429 .supported_begin = json_sup_start, 430 .supported_value = json_supcon_value, 431 .supported_end = json_supcon_end, 432 .conflict_begin = json_con_start, 433 .conflict_value = json_supcon_value, 434 .conflict_end = json_supcon_end, 435 .value_begin = json_value_begin, 436 .value_end = json_value_end, 437 .value = json_value, 438}; 439 440/* 441 * universal dump functions 442 */ 443 444static int render_devlist(struct context *context, 445 struct renderer *render, 446 const char *verb, 447 const char *device, 448 const char *list, 449 int (*begin)(struct renderer *), 450 int (*value)(struct renderer *, const char *value, int last), 451 int (*end)(struct renderer *)) 452{ 453 snd_use_case_mgr_t *uc_mgr = context->uc_mgr; 454 const char **dev_list; 455 char buf[256]; 456 int err = 0, j, dev_num; 457 458 snprintf(buf, sizeof(buf), "%s/%s/%s", list, device, verb); 459 dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list); 460 if (dev_num < 0) { 461 fprintf(stderr, "%s: unable to get %s for verb '%s' for device '%s'\n", 462 context->command, list, verb, device); 463 return dev_num; 464 } 465 if (dev_num > 0) { 466 err = begin(render); 467 if (err < 0) 468 goto __err; 469 for (j = 0; j < dev_num; j++) { 470 err = value(render, dev_list[j], j + 1 == dev_num); 471 if (err < 0) 472 goto __err; 473 } 474 err = end(render); 475 } 476__err: 477 snd_use_case_free_list(dev_list, dev_num); 478 return err; 479} 480 481static int render_values(struct context *context, 482 struct renderer *render, 483 const char *verb, 484 const char *device) 485{ 486 snd_use_case_mgr_t *uc_mgr = context->uc_mgr; 487 const char **list, *value; 488 char buf[256]; 489 int err = 0, j, num; 490 491 snprintf(buf, sizeof(buf), "_identifiers/%s/%s", device, verb); 492 num = snd_use_case_get_list(uc_mgr, buf, &list); 493 if (num < 0) { 494 fprintf(stderr, "%s: unable to get _identifiers for verb '%s' for device '%s': %s\n", 495 context->command, verb, device, snd_strerror(num)); 496 return num; 497 } 498 if (num == 0) 499 goto __err; 500 if (render->value_begin) { 501 err = render->value_begin(render); 502 if (err < 0) 503 goto __err; 504 } 505 for (j = 0; j < num; j++) { 506 snprintf(buf, sizeof(buf), "%s/%s/%s", list[j], device, verb); 507 err = snd_use_case_get(uc_mgr, buf, &value); 508 if (err < 0) { 509 fprintf(stderr, "%s: unable to get value '%s' for verb '%s' for device '%s': %s\n", 510 context->command, list[j], verb, device, snd_strerror(err)); 511 goto __err; 512 } 513 err = render->value(render, list[j], value); 514 free((char *)value); 515 if (err < 0) 516 goto __err; 517 } 518 if (render->value_end) 519 err = render->value_end(render); 520__err: 521 snd_use_case_free_list(list, num); 522 return err; 523} 524 525static int render_device(struct context *context, 526 struct renderer *render, 527 const char *verb, 528 const char *device) 529{ 530 int err; 531 532 err = render_devlist(context, render, verb, device, 533 "_supporteddevs", 534 render->supported_begin, 535 render->supported_value, 536 render->supported_end); 537 if (err < 0) 538 return err; 539 err = render_devlist(context, render, verb, device, 540 "_conflictingdevs", 541 render->conflict_begin, 542 render->conflict_value, 543 render->conflict_end); 544 if (err < 0) 545 return err; 546 return render_values(context, render, verb, device); 547} 548 549static void render(struct context *context, struct renderer *render) 550{ 551 snd_use_case_mgr_t *uc_mgr = context->uc_mgr; 552 int i, j, num, dev_num; 553 const char **list, **dev_list, *verb, *comment; 554 char buf[256]; 555 556 num = snd_use_case_verb_list(uc_mgr, &list); 557 if (num < 0) { 558 fprintf(stderr, "%s: no verbs found\n", context->command); 559 return; 560 } 561 if (render->init && render->init(render)) 562 goto __end; 563 for (i = 0; i < num; i += 2) { 564 /* verb */ 565 verb = list[i + 0]; 566 comment = list[i + 1]; 567 if (render->verb_begin(render, verb, comment)) 568 break; 569 /* devices */ 570 snprintf(buf, sizeof(buf), "_devices/%s", verb); 571 dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list); 572 if (dev_num < 0) { 573 fprintf(stderr, "%s: unable to get devices for verb '%s'\n", 574 context->command, verb); 575 continue; 576 } 577 if (dev_num == 0) 578 goto __mods; 579 if (render->device_block_begin && render->device_block_begin(render)) { 580 snd_use_case_free_list(dev_list, dev_num); 581 goto __end; 582 } 583 for (j = 0; j < dev_num; j += 2) { 584 render->device_begin(render, dev_list[j + 0], dev_list[j + 1]); 585 if (render_device(context, render, verb, dev_list[j + 0])) { 586 snd_use_case_free_list(dev_list, dev_num); 587 goto __end; 588 } 589 render->device_end(render); 590 } 591 snd_use_case_free_list(dev_list, dev_num); 592 if (render->device_block_end && render->device_block_end(render)) 593 goto __end; 594__mods: 595 /* modifiers */ 596 snprintf(buf, sizeof(buf), "_modifiers/%s", verb); 597 dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list); 598 if (dev_num < 0) { 599 fprintf(stderr, "%s: unable to get modifiers for verb '%s'\n", 600 context->command, verb); 601 continue; 602 } 603 if (dev_num == 0) 604 goto __verb_end; 605 if (render->modifier_block_begin && render->modifier_block_begin(render)) { 606 snd_use_case_free_list(dev_list, dev_num); 607 goto __end; 608 } 609 for (j = 0; j < dev_num; j += 2) { 610 render->modifier_begin(render, dev_list[j + 0], dev_list[j + 1]); 611 render->modifier_end(render); 612 } 613 snd_use_case_free_list(dev_list, dev_num); 614 if (render->modifier_block_end && render->modifier_block_end(render)) 615 goto __end; 616__verb_end: 617 /* end */ 618 if (render->verb_end(render)) 619 break; 620 } 621 if (render->done) 622 render->done(render); 623__end: 624 snd_use_case_free_list(list, num); 625} 626 627void dump(struct context *context, const char *format) 628{ 629 struct renderer r; 630 struct text t; 631 struct json j; 632 633 r.opaque = NULL; 634 if (strcasecmp(format, "text") == 0 || 635 strcasecmp(format, "txt") == 0) { 636 memset(&t, 0, sizeof(t)); 637 r = text_renderer; 638 r.opaque = &t; 639 } else if (strcasecmp(format, "json") == 0) { 640 memset(&j, 0, sizeof(j)); 641 r = json_renderer; 642 r.opaque = &j; 643 } 644 if (r.opaque != NULL) { 645 render(context, &r); 646 return; 647 } 648 fprintf(stderr, "%s: unknown dump format '%s'\n", 649 context->command, format); 650} 651