hipack-get.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * hipack-get.c
  3. * Copyright (C) 2015 Adrian Perez <aperez@igalia.com>
  4. *
  5. * Distributed under terms of the MIT license.
  6. */
  7. #include "../hipack.h"
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <errno.h>
  11. #if !defined(__OpenBSD__)
  12. /* Make sure that strtonum() is defined as "static". */
  13. static long long strtonum (const char*, long long, long long, const char**);
  14. #include "strtonum.c"
  15. #endif /* !__OpenBSD__ */
  16. int
  17. main (int argc, const char *argv[])
  18. {
  19. if (argc < 2) {
  20. fprintf (stderr, "Usage: %s <-|PATH> [key...]\n", argv[0]);
  21. return EXIT_FAILURE;
  22. }
  23. bool use_stdin = argv[1][0] == '-' && argv[1][1] == '\0';
  24. FILE *fp = use_stdin ? stdin : fopen (argv[1], "rb");
  25. if (!fp) {
  26. fprintf (stderr, "%s: Cannot open '%s' (%s)\n",
  27. argv[0], argv[1], strerror (errno));
  28. return EXIT_FAILURE;
  29. }
  30. int retcode = EXIT_SUCCESS;
  31. hipack_reader_t reader = {
  32. .getchar = hipack_stdio_getchar,
  33. .getchar_data = fp,
  34. };
  35. hipack_dict_t *message = hipack_read (&reader);
  36. if (!message) {
  37. assert (reader.error);
  38. fprintf (stderr, "line %u, column %u: %s\n",
  39. reader.error_line, reader.error_column,
  40. (reader.error == HIPACK_READ_ERROR)
  41. ? strerror (errno) : reader.error);
  42. retcode = EXIT_FAILURE;
  43. }
  44. fclose (fp);
  45. if (retcode != EXIT_SUCCESS)
  46. return retcode;
  47. hipack_value_t *value = &((hipack_value_t) {
  48. .type = HIPACK_DICT,
  49. .v_dict = message
  50. });
  51. for (unsigned i = 2; i < argc && value; i++) {
  52. switch (hipack_value_type (value)) {
  53. case HIPACK_DICT: {
  54. /* Use argv[i] as dictionary key. */
  55. hipack_string_t *key = hipack_string_new_from_string (argv[i]);
  56. value = hipack_dict_get (value->v_dict, key);
  57. hipack_string_free (key);
  58. break;
  59. }
  60. case HIPACK_LIST: {
  61. /* Use argv[i] as a list index. */
  62. const char *error = NULL;
  63. long long index = strtonum (argv[i],
  64. 0,
  65. hipack_list_size (value->v_list),
  66. &error);
  67. if (error) {
  68. fprintf (stderr, "%s: number '%s' is %s\n",
  69. argv[0], argv[i], error);
  70. retcode = EXIT_FAILURE;
  71. goto cleanup_dict;
  72. }
  73. value = HIPACK_LIST_AT (value->v_list, index);
  74. break;
  75. }
  76. default:
  77. fprintf (stderr, "%s: value is not a list or dictionary\n",
  78. argv[0]);
  79. retcode = EXIT_FAILURE;
  80. goto cleanup_dict;
  81. }
  82. }
  83. if (value) {
  84. hipack_writer_t writer = {
  85. .putchar = hipack_stdio_putchar,
  86. .putchar_data = stdout,
  87. };
  88. if (hipack_write_value (&writer, value)) {
  89. fprintf (stderr, "%s: write error (%s)\n",
  90. argv[0], strerror (errno));
  91. retcode = EXIT_FAILURE;
  92. }
  93. putchar ('\n');
  94. } else {
  95. fprintf (stderr, "%s: No value for the specified key.\n", argv[0]);
  96. retcode = EXIT_FAILURE;
  97. }
  98. cleanup_dict:
  99. hipack_dict_free (message);
  100. return retcode;
  101. }