command_line_parser.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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 && !strcmp(search_for, option->name)) {
  47. if (longindex) {
  48. *longindex = index;
  49. }
  50. return option;
  51. }
  52. option = &longopts[++index];
  53. }
  54. return NULL;
  55. }
  56. int aws_cli_getopt_long(
  57. int argc,
  58. char *const argv[],
  59. const char *optstring,
  60. const struct aws_cli_option *longopts,
  61. int *longindex) {
  62. aws_cli_optarg = NULL;
  63. if (aws_cli_optind >= argc) {
  64. return -1;
  65. }
  66. char first_char = argv[aws_cli_optind][0];
  67. char second_char = argv[aws_cli_optind][1];
  68. char *option_start = NULL;
  69. const struct aws_cli_option *option = NULL;
  70. bool positional_arg_encountered = false;
  71. if (first_char == '-' && second_char != '-') {
  72. aws_cli_on_arg = true;
  73. positional_arg_encountered = false;
  74. option_start = &argv[aws_cli_optind][1];
  75. option = s_find_option_from_char(longopts, *option_start, longindex);
  76. } else if (first_char == '-' && second_char == '-') {
  77. aws_cli_on_arg = true;
  78. positional_arg_encountered = false;
  79. option_start = &argv[aws_cli_optind][2];
  80. option = s_find_option_from_c_str(longopts, option_start, longindex);
  81. } else {
  82. if (!aws_cli_on_arg) {
  83. aws_cli_positional_arg = argv[aws_cli_optind];
  84. positional_arg_encountered = true;
  85. } else {
  86. aws_cli_on_arg = false;
  87. aws_cli_positional_arg = NULL;
  88. }
  89. }
  90. aws_cli_optind++;
  91. if (option) {
  92. bool has_arg = false;
  93. aws_cli_on_arg = false;
  94. aws_cli_positional_arg = NULL;
  95. char *opt_value = memchr(optstring, option->val, strlen(optstring) + 1);
  96. if (!opt_value) {
  97. return '?';
  98. }
  99. if (opt_value[1] == ':') {
  100. has_arg = true;
  101. }
  102. if (has_arg) {
  103. if (aws_cli_optind >= argc) {
  104. return '?';
  105. }
  106. aws_cli_optarg = argv[aws_cli_optind++];
  107. }
  108. return option->val;
  109. }
  110. /* start of text to indicate we just have a text argument. */
  111. return positional_arg_encountered ? 0x02 : '?';
  112. }
  113. int aws_cli_dispatch_on_subcommand(
  114. int argc,
  115. char *const argv[],
  116. struct aws_cli_subcommand_dispatch *dispatch_table,
  117. int table_length,
  118. void *user_data) {
  119. if (argc >= 2) {
  120. struct aws_byte_cursor arg_name = aws_byte_cursor_from_c_str(argv[1]);
  121. for (int i = 0; i < table_length; ++i) {
  122. struct aws_byte_cursor cmd_name = aws_byte_cursor_from_c_str(dispatch_table[i].command_name);
  123. if (aws_byte_cursor_eq_ignore_case(&arg_name, &cmd_name)) {
  124. return dispatch_table[i].subcommand_fn(argc - 1, &argv[1], (const char *)arg_name.ptr, user_data);
  125. }
  126. }
  127. return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  128. }
  129. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  130. }