You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
3.9 KiB

  1. /* getopt.c
  2. * Simple getopt() implementation.
  3. *
  4. * Standard interface:
  5. * extern int getopt(int argc, char *const *argv, const char *opts);
  6. * extern int optind; current index in argv[]
  7. * extern char *optarg; argument for the current option
  8. * extern int optopt; the current option
  9. * extern int opterr; to control error printing
  10. *
  11. * Some minor extensions:
  12. * ignores leading `+' sign in opts[] (unemplemented GNU extension)
  13. * handles optional arguments, in form "x::" in opts[]
  14. * if opts[] starts with `:', will return `:' in case of missing required
  15. * argument, instead of '?'.
  16. *
  17. * Compile with -DGETOPT_NO_OPTERR to never print errors internally.
  18. * Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for
  19. * error reporting (ignored with -DGETOPT_NO_OPTERR).
  20. * Compile with -DGETOPT_CLASS=static to get static linkage.
  21. * Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed
  22. * with "my_", like my_getopt instead of getopt.
  23. * Compile with -DTEST to get a test executable.
  24. *
  25. * Written by Michael Tokarev. Public domain.
  26. */
  27. #include <string.h>
  28. #ifndef GETOPT_CLASS
  29. # define GETOPT_CLASS
  30. #endif
  31. #ifdef GETOPT_MY
  32. # define optarg my_optarg
  33. # define optind my_optind
  34. # define opterr my_opterr
  35. # define optopt my_optopt
  36. # define getopt my_getopt
  37. #endif
  38. GETOPT_CLASS char *optarg /* = NULL */;
  39. GETOPT_CLASS int optind = 1;
  40. GETOPT_CLASS int opterr = 1;
  41. GETOPT_CLASS int optopt;
  42. static char *nextc /* = NULL */;
  43. #if defined(GETOPT_NO_OPTERR)
  44. #define printerr(argv, msg)
  45. #elif defined(GETOPT_NO_STDIO)
  46. extern int write(int, void *, int);
  47. static void printerr(char *const *argv, const char *msg) {
  48. if (opterr) {
  49. char buf[64];
  50. unsigned pl = strlen(argv[0]);
  51. unsigned ml = strlen(msg);
  52. char *p;
  53. if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) {
  54. write(2, argv[0], pl);
  55. p = buf;
  56. }
  57. else {
  58. memcpy(buf, argv[0], ml);
  59. p = buf + pl;
  60. }
  61. *p++ = ':'; *p++ = ' ';
  62. memcpy(p, msg, ml); p += ml;
  63. *p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' ';
  64. *p++ = optopt;
  65. *p++ = '\n';
  66. write(2, buf, p - buf);
  67. }
  68. }
  69. #else
  70. #include <stdio.h>
  71. static void printerr(char *const *argv, const char *msg) {
  72. if (opterr)
  73. fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt);
  74. }
  75. #endif
  76. GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) {
  77. char *p;
  78. optarg = 0;
  79. if (*opts == '+') /* GNU extension (permutation) - isn't supported */
  80. ++opts;
  81. if (!optind) { /* a way to reset things */
  82. nextc = 0;
  83. optind = 1;
  84. }
  85. if (!nextc || !*nextc) { /* advance to the next argv element */
  86. /* done scanning? */
  87. if (optind >= argc)
  88. return -1;
  89. /* not an optional argument */
  90. if (argv[optind][0] != '-')
  91. return -1;
  92. /* bare `-' */
  93. if (argv[optind][1] == '\0')
  94. return -1;
  95. /* special case `--' argument */
  96. if (argv[optind][1] == '-' && argv[optind][2] == '\0') {
  97. ++optind;
  98. return -1;
  99. }
  100. nextc = argv[optind] + 1;
  101. }
  102. optopt = *nextc++;
  103. if (!*nextc)
  104. ++optind;
  105. p = strchr(opts, optopt);
  106. if (!p || optopt == ':') {
  107. printerr(argv, "illegal option");
  108. return '?';
  109. }
  110. if (p[1] == ':') {
  111. if (*nextc) {
  112. optarg = nextc;
  113. nextc = NULL;
  114. ++optind;
  115. }
  116. else if (p[2] != ':') { /* required argument */
  117. if (optind >= argc) {
  118. printerr(argv, "option requires an argument");
  119. return *opts == ':' ? ':' : '?';
  120. }
  121. else
  122. optarg = argv[optind++];
  123. }
  124. }
  125. return optopt;
  126. }
  127. #ifdef TEST
  128. #include <stdio.h>
  129. int main(int argc, char **argv) {
  130. int c;
  131. while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) {
  132. case 'a':
  133. case 'b':
  134. case 'c':
  135. printf("option %c %s\n", c, optarg ? optarg : "(none)");
  136. break;
  137. default:
  138. return -1;
  139. }
  140. for(c = optind; c < argc; ++c)
  141. printf("non-opt: %s\n", argv[c]);
  142. return 0;
  143. }
  144. #endif