getopt.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Marcus Boerger <helly@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <assert.h>
  19. #include <stdlib.h>
  20. #include "php_getopt.h"
  21. #define OPTERRCOLON (1)
  22. #define OPTERRNF (2)
  23. #define OPTERRARG (3)
  24. // Print error message to stderr and return -2 to distinguish it from '?' command line option.
  25. static int php_opt_error(int argc, char * const *argv, int optint, int optchr, int err, int show_err) /* {{{ */
  26. {
  27. if (show_err)
  28. {
  29. fprintf(stderr, "Error in argument %d, char %d: ", optint, optchr+1);
  30. switch(err)
  31. {
  32. case OPTERRCOLON:
  33. fprintf(stderr, ": in flags\n");
  34. break;
  35. case OPTERRNF:
  36. fprintf(stderr, "option not found %c\n", argv[optint][optchr]);
  37. break;
  38. case OPTERRARG:
  39. fprintf(stderr, "no argument for option %c\n", argv[optint][optchr]);
  40. break;
  41. default:
  42. fprintf(stderr, "unknown\n");
  43. break;
  44. }
  45. }
  46. return PHP_GETOPT_INVALID_ARG;
  47. }
  48. /* }}} */
  49. PHPAPI int php_optidx = -1;
  50. PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start) /* {{{ */
  51. {
  52. static int optchr = 0;
  53. static int dash = 0; /* have already seen the - */
  54. static char **prev_optarg = NULL;
  55. php_optidx = -1;
  56. if(prev_optarg && prev_optarg != optarg) {
  57. /* reset the state */
  58. optchr = 0;
  59. dash = 0;
  60. }
  61. prev_optarg = optarg;
  62. if (*optind >= argc) {
  63. return(EOF);
  64. }
  65. if (!dash) {
  66. if ((argv[*optind][0] != '-')) {
  67. return(EOF);
  68. } else {
  69. if (!argv[*optind][1])
  70. {
  71. /*
  72. * use to specify stdin. Need to let pgm process this and
  73. * the following args
  74. */
  75. return(EOF);
  76. }
  77. }
  78. }
  79. if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-')) {
  80. const char *pos;
  81. size_t arg_end = strlen(argv[*optind])-1;
  82. /* '--' indicates end of args if not followed by a known long option name */
  83. if (argv[*optind][2] == '\0') {
  84. (*optind)++;
  85. return(EOF);
  86. }
  87. arg_start = 2;
  88. /* Check for <arg>=<val> */
  89. if ((pos = php_memnstr(&argv[*optind][arg_start], "=", 1, argv[*optind]+arg_end)) != NULL) {
  90. arg_end = pos-&argv[*optind][arg_start];
  91. arg_start++;
  92. } else {
  93. arg_end--;
  94. }
  95. while (1) {
  96. php_optidx++;
  97. if (opts[php_optidx].opt_char == '-') {
  98. (*optind)++;
  99. return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
  100. } else if (opts[php_optidx].opt_name && !strncmp(&argv[*optind][2], opts[php_optidx].opt_name, arg_end) && arg_end == strlen(opts[php_optidx].opt_name)) {
  101. break;
  102. }
  103. }
  104. optchr = 0;
  105. dash = 0;
  106. arg_start += (int)strlen(opts[php_optidx].opt_name);
  107. } else {
  108. if (!dash) {
  109. dash = 1;
  110. optchr = 1;
  111. }
  112. /* Check if the guy tries to do a -: kind of flag */
  113. if (argv[*optind][optchr] == ':') {
  114. dash = 0;
  115. (*optind)++;
  116. return (php_opt_error(argc, argv, *optind-1, optchr, OPTERRCOLON, show_err));
  117. }
  118. arg_start = 1 + optchr;
  119. }
  120. if (php_optidx < 0) {
  121. while (1) {
  122. php_optidx++;
  123. if (opts[php_optidx].opt_char == '-') {
  124. int errind = *optind;
  125. int errchr = optchr;
  126. if (!argv[*optind][optchr+1]) {
  127. dash = 0;
  128. (*optind)++;
  129. } else {
  130. optchr++;
  131. arg_start++;
  132. }
  133. return(php_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
  134. } else if (argv[*optind][optchr] == opts[php_optidx].opt_char) {
  135. break;
  136. }
  137. }
  138. }
  139. if (opts[php_optidx].need_param) {
  140. /* Check for cases where the value of the argument
  141. is in the form -<arg> <val>, -<arg>=<varl> or -<arg><val> */
  142. dash = 0;
  143. if (!argv[*optind][arg_start]) {
  144. (*optind)++;
  145. if (*optind == argc) {
  146. /* Was the value required or is it optional? */
  147. if (opts[php_optidx].need_param == 1) {
  148. return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
  149. }
  150. /* Optional value is not supported with -<arg> <val> style */
  151. } else if (opts[php_optidx].need_param == 1) {
  152. *optarg = argv[(*optind)++];
  153. }
  154. } else if (argv[*optind][arg_start] == '=') {
  155. arg_start++;
  156. *optarg = &argv[*optind][arg_start];
  157. (*optind)++;
  158. } else {
  159. *optarg = &argv[*optind][arg_start];
  160. (*optind)++;
  161. }
  162. return opts[php_optidx].opt_char;
  163. } else {
  164. /* multiple options specified as one (exclude long opts) */
  165. if (arg_start >= 2 && !((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))) {
  166. if (!argv[*optind][optchr+1])
  167. {
  168. dash = 0;
  169. (*optind)++;
  170. } else {
  171. optchr++;
  172. }
  173. } else {
  174. (*optind)++;
  175. }
  176. return opts[php_optidx].opt_char;
  177. }
  178. assert(0);
  179. return(0); /* never reached */
  180. }
  181. /* }}} */