getopt.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * getopt.c - a simple getopt(3) implementation. See getopt.h for explanation.
  4. *
  5. * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
  6. * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
  7. */
  8. #define LOG_CATEGORY LOGC_CORE
  9. #include <common.h>
  10. #include <getopt.h>
  11. #include <log.h>
  12. void getopt_init_state(struct getopt_state *gs)
  13. {
  14. gs->index = 1;
  15. gs->arg_index = 1;
  16. }
  17. int __getopt(struct getopt_state *gs, int argc, char *const argv[],
  18. const char *optstring, bool silent)
  19. {
  20. char curopt; /* current option character */
  21. const char *curoptp; /* pointer to the current option in optstring */
  22. while (1) {
  23. log_debug("arg_index: %d index: %d\n", gs->arg_index,
  24. gs->index);
  25. /* `--` indicates the end of options */
  26. if (gs->arg_index == 1 && argv[gs->index] &&
  27. !strcmp(argv[gs->index], "--")) {
  28. gs->index++;
  29. return -1;
  30. }
  31. /* Out of arguments */
  32. if (gs->index >= argc)
  33. return -1;
  34. /* Can't parse non-options */
  35. if (*argv[gs->index] != '-')
  36. return -1;
  37. /* We have found an option */
  38. curopt = argv[gs->index][gs->arg_index];
  39. if (curopt)
  40. break;
  41. /*
  42. * no more options in current argv[] element; try the next one
  43. */
  44. gs->index++;
  45. gs->arg_index = 1;
  46. }
  47. /* look up current option in optstring */
  48. curoptp = strchr(optstring, curopt);
  49. if (!curoptp) {
  50. if (!silent)
  51. printf("%s: invalid option -- %c\n", argv[0], curopt);
  52. gs->opt = curopt;
  53. gs->arg_index++;
  54. return '?';
  55. }
  56. if (*(curoptp + 1) != ':') {
  57. /* option with no argument. Just return it */
  58. gs->arg = NULL;
  59. gs->arg_index++;
  60. return curopt;
  61. }
  62. if (*(curoptp + 1) && *(curoptp + 2) == ':') {
  63. /* optional argument */
  64. if (argv[gs->index][gs->arg_index + 1]) {
  65. /* optional argument with directly following arg */
  66. gs->arg = argv[gs->index++] + gs->arg_index + 1;
  67. gs->arg_index = 1;
  68. return curopt;
  69. }
  70. if (gs->index + 1 == argc) {
  71. /* We are at the last argv[] element */
  72. gs->arg = NULL;
  73. gs->index++;
  74. return curopt;
  75. }
  76. if (*argv[gs->index + 1] != '-') {
  77. /*
  78. * optional argument with arg in next argv[] element
  79. */
  80. gs->index++;
  81. gs->arg = argv[gs->index++];
  82. gs->arg_index = 1;
  83. return curopt;
  84. }
  85. /* no optional argument found */
  86. gs->arg = NULL;
  87. gs->arg_index = 1;
  88. gs->index++;
  89. return curopt;
  90. }
  91. if (argv[gs->index][gs->arg_index + 1]) {
  92. /* required argument with directly following arg */
  93. gs->arg = argv[gs->index++] + gs->arg_index + 1;
  94. gs->arg_index = 1;
  95. return curopt;
  96. }
  97. gs->index++;
  98. gs->arg_index = 1;
  99. if (gs->index >= argc || argv[gs->index][0] == '-') {
  100. if (!silent)
  101. printf("option requires an argument -- %c\n", curopt);
  102. gs->opt = curopt;
  103. return ':';
  104. }
  105. gs->arg = argv[gs->index++];
  106. return curopt;
  107. }