command_line_parser.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/byte_buf.h>
  6. #include <aws/common/command_line_parser.h>
  7. #include <ctype.h>
  8. int aws_cli_optind = 1;
  9. int aws_cli_opterr = -1;
  10. int aws_cli_optopt = 0;
  11. bool aws_cli_on_arg = false;
  12. const char *aws_cli_optarg = NULL;
  13. const char *aws_cli_positional_arg = NULL;
  14. static const struct aws_cli_option *s_find_option_from_char(
  15. const struct aws_cli_option *longopts,
  16. char search_for,
  17. int *longindex) {
  18. int index = 0;
  19. const struct aws_cli_option *option = &longopts[index];
  20. while (option->val != 0 || option->name) {
  21. if (option->val == search_for) {
  22. if (longindex) {
  23. *longindex = index;
  24. }
  25. return option;
  26. }
  27. option = &longopts[++index];
  28. }
  29. return NULL;
  30. }
  31. AWS_COMMON_API void aws_cli_reset_state(void) {
  32. aws_cli_optind = 1;
  33. aws_cli_opterr = -1;
  34. aws_cli_optopt = 0;
  35. aws_cli_on_arg = false;
  36. aws_cli_optarg = NULL;
  37. aws_cli_positional_arg = NULL;
  38. }
  39. static const struct aws_cli_option *s_find_option_from_c_str(
  40. const struct aws_cli_option *longopts,
  41. const char *search_for,
  42. int *longindex) {
  43. int index = 0;
  44. const struct aws_cli_option *option = &longopts[index];
  45. while (option->name || option->val != 0) {
  46. if (option->name) {
  47. if (option->name && !strcmp(search_for, option->name)) {
  48. if (longindex) {
  49. *longindex = index;
  50. }
  51. return option;
  52. }
  53. }
  54. option = &longopts[++index];
  55. }
  56. return NULL;
  57. }
  58. int aws_cli_getopt_long(
  59. int argc,
  60. char *const argv[],
  61. const char *optstring,
  62. const struct aws_cli_option *longopts,
  63. int *longindex) {
  64. aws_cli_optarg = NULL;
  65. if (aws_cli_optind >= argc) {
  66. return -1;
  67. }
  68. char first_char = argv[aws_cli_optind][0];
  69. char second_char = argv[aws_cli_optind][1];
  70. char *option_start = NULL;
  71. const struct aws_cli_option *option = NULL;
  72. bool positional_arg_encountered = false;
  73. if (first_char == '-' && second_char != '-') {
  74. aws_cli_on_arg = true;
  75. positional_arg_encountered = false;
  76. option_start = &argv[aws_cli_optind][1];
  77. option = s_find_option_from_char(longopts, *option_start, longindex);
  78. } else if (first_char == '-' && second_char == '-') {
  79. aws_cli_on_arg = true;
  80. positional_arg_encountered = false;
  81. option_start = &argv[aws_cli_optind][2];
  82. option = s_find_option_from_c_str(longopts, option_start, longindex);
  83. } else {
  84. if (!aws_cli_on_arg) {
  85. aws_cli_positional_arg = argv[aws_cli_optind];
  86. positional_arg_encountered = true;
  87. } else {
  88. aws_cli_on_arg = false;
  89. aws_cli_positional_arg = NULL;
  90. }
  91. }
  92. aws_cli_optind++;
  93. if (option) {
  94. bool has_arg = false;
  95. aws_cli_on_arg = false;
  96. aws_cli_positional_arg = NULL;
  97. char *opt_value = memchr(optstring, option->val, strlen(optstring) + 1);
  98. if (!opt_value) {
  99. return '?';
  100. }
  101. if (opt_value[1] == ':') {
  102. has_arg = true;
  103. }
  104. if (has_arg) {
  105. if (aws_cli_optind >= argc) {
  106. return '?';
  107. }
  108. aws_cli_optarg = argv[aws_cli_optind++];
  109. }
  110. return option->val;
  111. }
  112. /* start of text to indicate we just have a text argument. */
  113. return positional_arg_encountered ? 0x02 : '?';
  114. }
  115. int aws_cli_dispatch_on_subcommand(
  116. int argc,
  117. char *const argv[],
  118. struct aws_cli_subcommand_dispatch *dispatch_table,
  119. int table_length,
  120. void *user_data) {
  121. if (argc >= 2) {
  122. struct aws_byte_cursor arg_name = aws_byte_cursor_from_c_str(argv[1]);
  123. for (int i = 0; i < table_length; ++i) {
  124. struct aws_byte_cursor cmd_name = aws_byte_cursor_from_c_str(dispatch_table[i].command_name);
  125. if (aws_byte_cursor_eq_ignore_case(&arg_name, &cmd_name)) {
  126. return dispatch_table[i].subcommand_fn(argc - 1, &argv[1], (const char *)arg_name.ptr, user_data);
  127. }
  128. }
  129. return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  130. }
  131. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  132. }