getopt.c 5.5 KB

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