getopt_long.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #define _GNU_SOURCE
  2. #include <stddef.h>
  3. #include <getopt.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. extern int __optpos, __optreset;
  7. static void permute(char *const *argv, int dest, int src)
  8. {
  9. char **av = (char **)argv;
  10. char *tmp = av[src];
  11. int i;
  12. for (i=src; i>dest; i--)
  13. av[i] = av[i-1];
  14. av[dest] = tmp;
  15. }
  16. void __getopt_msg(const char *, const char *, const char *, size_t);
  17. static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly);
  18. static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
  19. {
  20. int ret, skipped, resumed;
  21. if (!optind || __optreset) {
  22. __optreset = 0;
  23. __optpos = 0;
  24. optind = 1;
  25. }
  26. if (optind >= argc || !argv[optind]) return -1;
  27. skipped = optind;
  28. if (optstring[0] != '+' && optstring[0] != '-') {
  29. int i;
  30. for (i=optind; ; i++) {
  31. if (i >= argc || !argv[i]) return -1;
  32. if (argv[i][0] == '-' && argv[i][1]) break;
  33. }
  34. optind = i;
  35. }
  36. resumed = optind;
  37. ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
  38. if (resumed > skipped) {
  39. int i, cnt = optind-resumed;
  40. for (i=0; i<cnt; i++)
  41. permute(argv, skipped, optind-1);
  42. optind = skipped + cnt;
  43. }
  44. return ret;
  45. }
  46. static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
  47. {
  48. optarg = 0;
  49. if (longopts && argv[optind][0] == '-' &&
  50. ((longonly && argv[optind][1]) ||
  51. (argv[optind][1] == '-' && argv[optind][2])))
  52. {
  53. int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
  54. int i, cnt, match;
  55. char *opt;
  56. for (cnt=i=0; longopts[i].name; i++) {
  57. const char *name = longopts[i].name;
  58. opt = argv[optind]+1;
  59. if (*opt == '-') opt++;
  60. for (; *name && *name == *opt; name++, opt++);
  61. if (*opt && *opt != '=') continue;
  62. match = i;
  63. if (!*name) {
  64. cnt = 1;
  65. break;
  66. }
  67. cnt++;
  68. }
  69. if (cnt==1) {
  70. i = match;
  71. optind++;
  72. optopt = longopts[i].val;
  73. if (*opt == '=') {
  74. if (!longopts[i].has_arg) {
  75. if (colon || !opterr)
  76. return '?';
  77. __getopt_msg(argv[0],
  78. ": option does not take an argument: ",
  79. longopts[i].name,
  80. strlen(longopts[i].name));
  81. return '?';
  82. }
  83. optarg = opt+1;
  84. } else {
  85. if (longopts[i].has_arg == required_argument) {
  86. if (!(optarg = argv[optind])) {
  87. if (colon) return ':';
  88. if (!opterr) return '?';
  89. __getopt_msg(argv[0],
  90. ": option requires an argument: ",
  91. longopts[i].name,
  92. strlen(longopts[i].name));
  93. return '?';
  94. }
  95. optind++;
  96. } else optarg = NULL;
  97. }
  98. if (idx) *idx = i;
  99. if (longopts[i].flag) {
  100. *longopts[i].flag = longopts[i].val;
  101. return 0;
  102. }
  103. return longopts[i].val;
  104. }
  105. if (argv[optind][1] == '-') {
  106. if (!colon && opterr)
  107. __getopt_msg(argv[0], cnt ?
  108. ": option is ambiguous: " :
  109. ": unrecognized option: ",
  110. argv[optind]+2,
  111. strlen(argv[optind]+2));
  112. optind++;
  113. return '?';
  114. }
  115. }
  116. return getopt(argc, argv, optstring);
  117. }
  118. int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
  119. {
  120. return __getopt_long(argc, argv, optstring, longopts, idx, 0);
  121. }
  122. int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
  123. {
  124. return __getopt_long(argc, argv, optstring, longopts, idx, 1);
  125. }