getopt_long.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include <unistd.h>
  2. #include <getopt.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. /**
  6. * getopt / getopt_long
  7. */
  8. int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex) {
  9. static char * nextchar = NULL;
  10. if (optind >= argc) {
  11. return -1;
  12. }
  13. do {
  14. if (!nextchar) {
  15. nextchar = argv[optind];
  16. if (*nextchar != '-') {
  17. return -1;
  18. } else {
  19. nextchar++;
  20. if (*nextchar == '\0') {
  21. /* Special case - is a non-option argument */
  22. return -1;
  23. }
  24. if (*nextchar == '-') {
  25. if (nextchar[1] == '\0') {
  26. /* End of arguments */
  27. optind++;
  28. return -1;
  29. } else if (longopts) {
  30. /* Scan through options */
  31. nextchar++;
  32. char tmp[strlen(nextchar)+1];
  33. strcpy(tmp, nextchar);
  34. char * eq = strchr(tmp, '=');
  35. if (eq) {
  36. *eq = '\0';
  37. optarg = nextchar + (eq - tmp + 1);
  38. } else {
  39. optarg = NULL;
  40. }
  41. int found = -1;
  42. for (int index = 0; longopts[index].name; ++index) {
  43. if (!strcmp(longopts[index].name, tmp)) {
  44. found = index;
  45. }
  46. }
  47. if (found == -1) {
  48. if (longindex) {
  49. *longindex = -1;
  50. }
  51. if (opterr) {
  52. fprintf(stderr, "unknown long argument: %s\n", tmp);
  53. }
  54. nextchar = NULL;
  55. optind++;
  56. optopt = '\0';
  57. return '?';
  58. } else {
  59. if (longindex) {
  60. *longindex = found;
  61. }
  62. if (longopts[found].has_arg == required_argument) {
  63. if (!optarg) {
  64. optarg = argv[optind+1];
  65. optind++;
  66. }
  67. }
  68. nextchar = NULL;
  69. optind++;
  70. if (!longopts[found].flag) {
  71. return longopts[found].val;
  72. } else {
  73. *longopts[found].flag = longopts[found].val;
  74. return 0;
  75. }
  76. }
  77. }
  78. /* else: --foo but not long, see if -: is set, otherwise continue as if - was an option */
  79. }
  80. }
  81. }
  82. if (*nextchar == '\0') {
  83. nextchar = NULL;
  84. optind++;
  85. continue;
  86. }
  87. if ((*nextchar < 'A' || *nextchar > 'z' || (*nextchar > 'Z' && *nextchar < 'a')) && (*nextchar != '?') && (*nextchar != '-')) {
  88. if (opterr) {
  89. fprintf(stderr, "Invalid option character: %c\n", *nextchar);
  90. }
  91. optopt = *nextchar;
  92. nextchar++;
  93. return '?';
  94. }
  95. char * opt = strchr(optstring, *nextchar);
  96. if (!opt) {
  97. if (opterr) {
  98. fprintf(stderr, "Invalid option character: %c\n", *nextchar);
  99. }
  100. optopt = *nextchar;
  101. nextchar++;
  102. return '?';
  103. }
  104. int optout = *nextchar;
  105. if (opt[1] == ':') {
  106. if (nextchar[1] != '\0') {
  107. optarg = &nextchar[1];
  108. nextchar = NULL;
  109. optind++;
  110. } else {
  111. optarg = argv[optind+1];
  112. optind += 2;
  113. nextchar = NULL;
  114. }
  115. } else {
  116. nextchar++;
  117. }
  118. return optout;
  119. } while (optind < argc);
  120. return -1;
  121. }