PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/class/Getopt.php

http://github.com/ethna/ethna
PHP | 331 lines | 262 code | 12 blank | 57 comment | 18 complexity | 248f0d3a2f201f2c72eba4bf5a3b3c32 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4. * Getopt.php
  5. *
  6. * @author Yoshinari Takaoka <takaoka@beatcraft.com>
  7. * @license Public Domain
  8. * @package Ethna
  9. * @version $Id: adb71f2ff53da8464732977145d8d6d2e7da9d28 $
  10. */
  11. if (!defined('ETHNA_OPTVALUE_IS_DISABLED')) {
  12. define('ETHNA_OPTVALUE_IS_DISABLED', 1);
  13. }
  14. if (!defined('ETHNA_OPTVALUE_IS_REQUIRED')) {
  15. define('ETHNA_OPTVALUE_IS_REQUIRED', 2);
  16. }
  17. if (!defined('ETHNA_OPTVALUE_IS_OPTIONAL')) {
  18. define('ETHNA_OPTVALUE_IS_OPTIONAL', 3);
  19. }
  20. // {{{ Ethna_Getopt
  21. /**
  22. * ?????????????????
  23. * PEAR ???????????? Console_Getopt ???????????
  24. *
  25. * @author Yoshinari Takaoka <takaoka@beatcraft.com>
  26. * @access public
  27. * @package Ethna
  28. * @see http://pear.php.net/manual/en/package.console.console-getopt.php
  29. */
  30. class Ethna_Getopt
  31. {
  32. /**
  33. * PHP ????????$argv ????????
  34. * ini ????????? register_argc_argv ???????
  35. *
  36. * ??? PHP 4.2.0 ?????$argv ???????
  37. * register_globals ? ON ?????????
  38. * ??????Ethna ? ?????off????
  39. * ?????????????????????
  40. * ????????
  41. *
  42. * @return array - ?????????????????
  43. * ???? Ethna_Error
  44. */
  45. public function readPHPArgv()
  46. {
  47. global $argv;
  48. if (ini_get('register_argc_argv') == false) {
  49. return Ethna::raiseError(
  50. 'Could not read cmd args (register_argc_argv=Off?'
  51. );
  52. }
  53. return $argv;
  54. }
  55. /**
  56. * ??????????????????????????
  57. *
  58. * @param array $args - ????????????
  59. * @param string $shortoptions - ?????????????????????
  60. * @param array $longoptions - ?????????????????????
  61. *
  62. * @return array - ????????????????????????????
  63. * ? 2??????????????? Ethna_Error ?
  64. */
  65. public function getopt($args, $shortoptions, $longoptions = NULL)
  66. {
  67. $shortopts = $this->_parseShortOption($shortoptions);
  68. if (Ethna::isError($shortopts)) {
  69. return $shortopts;
  70. }
  71. $longopts = $this->_parseLongOption($longoptions);
  72. if (Ethna::isError($longopts)) {
  73. return $longopts;
  74. }
  75. $parsed_arguments = array();
  76. $nonparsed_arguments = array();
  77. for ($pos = 0; $pos < count($args); $pos++) {
  78. $arg = $args[$pos];
  79. $next_arg = isset($args[$pos + 1]) ? $args[$pos + 1] : NULL;
  80. $is_nextarg_is_value = false;
  81. $required = false;
  82. if (strpos($arg, '--') === 0) { // long option
  83. //
  84. // GNU getopt(3) ??????????????????
  85. // ?????????????????? --foo, --fuji
  86. // ????????????????? --fo ? --fu ?
  87. // ??????????????????
  88. //
  89. // PEAR ? Console_Getopt ??????????????
  90. // ??????????????? Ethna ???????
  91. // ???????????
  92. //
  93. // ????????????
  94. $lopt = str_replace('--', '', $arg);
  95. $opt_and_value = explode('=', $lopt);
  96. $opt = $opt_and_value[0];
  97. if (!array_key_exists($opt, $longopts)) {
  98. return Ethna::raiseError("unrecognized option --$opt");
  99. }
  100. // ????????????
  101. $required = $longopts[$opt];
  102. $value = NULL;
  103. if (count($opt_and_value) == 2) {
  104. $value = $opt_and_value[1]; // --foo=bar
  105. } elseif (strpos('-', $next_arg) !== 0
  106. && $required == ETHNA_OPTVALUE_IS_REQUIRED) {
  107. if (!empty($next_arg)) { // --foo bar
  108. // ?? $argv ???????
  109. // == ??????????????????????
  110. $value = $next_arg;
  111. $pos++;
  112. }
  113. }
  114. // ???????????
  115. switch ($required) {
  116. case ETHNA_OPTVALUE_IS_REQUIRED:
  117. if ($value === NULL) {
  118. return Ethna::raiseError(
  119. "option --$opt requires an argument"
  120. );
  121. }
  122. break;
  123. case ETHNA_OPTVALUE_IS_DISABLED:
  124. if ($value !== NULL) {
  125. return Ethna::raiseError(
  126. "option --$opt doesn't allow an argument"
  127. );
  128. }
  129. break;
  130. }
  131. // ????????????-- ??????????????
  132. // Console_Getopt ????????
  133. $parsed_arguments[] = array("--$opt", $value);
  134. } elseif (strpos($arg, '-') === 0) { // short option
  135. //
  136. // -abcd ????????????????
  137. // ?????????????????????????
  138. // ????????GNU getopt(3) ??????
  139. //
  140. // 1. abcd ?1?????????a, b, c, d ???
  141. //
  142. // 2. ':' (???) ?????????????????????
  143. // ??????????????????argv????????
  144. // ???????????????? argv ?????????
  145. // ???????????
  146. // 3. '::'(????) ????????????????????
  147. // ?????????????????????????argv?
  148. // ???????????
  149. //
  150. // 4. ???(?????)???????????????????
  151. // ?????????argv??????????
  152. //
  153. // @see LANG=C; man 3 getopt (??????????????????)
  154. // @see http://www.gnu.org/software/libtool/manual/libc/Using-Getopt.html
  155. //
  156. // TODO: ambiguous ?????????????????
  157. //
  158. $sopt = str_replace('-', '', $arg);
  159. $sopt_len = strlen($sopt);
  160. for ($sopt_pos = 0; $sopt_pos < $sopt_len; $sopt_pos++) {
  161. // ??????????
  162. $opt = $sopt[$sopt_pos];
  163. $value = NULL;
  164. $do_next_arg = false;
  165. $required = isset($shortopts[$opt]) ? $shortopts[$opt] : NULL;
  166. switch ($required) {
  167. case ETHNA_OPTVALUE_IS_REQUIRED:
  168. case ETHNA_OPTVALUE_IS_OPTIONAL:
  169. if ($sopt_len == 1
  170. && $required == ETHNA_OPTVALUE_IS_REQUIRED) {
  171. if ($next_arg[0] != '-') { // -a hoge
  172. // ?? $argv ???????
  173. // ???:: ?????????
  174. $value = $next_arg;
  175. $pos++;
  176. }
  177. } else {
  178. // ????????????
  179. $value = substr($sopt, $sopt_pos + 1);
  180. $value = (empty($value)) ? NULL : $value;
  181. }
  182. if ($required == ETHNA_OPTVALUE_IS_REQUIRED
  183. && empty($value)) {
  184. return Ethna::raiseError(
  185. "option -$opt requires an argument"
  186. );
  187. }
  188. // ':' ??? '::' ??????????????
  189. // ??????????????????argv???
  190. // ?????
  191. $do_next_arg = true;
  192. break;
  193. case ETHNA_OPTVALUE_IS_DISABLED:
  194. // ?????????????????????
  195. // ????????????????
  196. break;
  197. default:
  198. return Ethna::raiseError("unrecognized option -$opt");
  199. break;
  200. }
  201. // ????????????- ?????????????????
  202. // Console_Getopt ????????
  203. $parsed_arguments[] = array($opt, $value);
  204. if ($do_next_arg === true) {
  205. break;
  206. }
  207. }
  208. } else { // ??????????????
  209. // non-parsed ????????????
  210. // ??????????????
  211. // ???????????????????
  212. //
  213. // ??? POSIX_CORRECT ???????
  214. // GNU Getopt ????????????
  215. // Console_Getopt ??????????
  216. // ????????
  217. $nonparsed_arguments = array_slice($args, $pos);
  218. break;
  219. }
  220. }
  221. return array($parsed_arguments, $nonparsed_arguments);
  222. }
  223. /**
  224. * ????????????????
  225. *
  226. * @param string $sopts ?????????
  227. * @return array ???????????????
  228. * ??????? Ethna_Error
  229. * @access protected
  230. */
  231. protected function _parseShortOption($sopts)
  232. {
  233. if (empty($sopts)) {
  234. return array();
  235. }
  236. if (!preg_match('/^[A-Za-z:]+$/', $sopts)) {
  237. return Ethna::raiseError('invalid short options.');
  238. }
  239. $analyze_result = array();
  240. for ($pos = 0; $pos < strlen($sopts); $pos++) {
  241. $char = $sopts[$pos];
  242. $next_char = (isset($sopts[$pos + 1]))
  243. ? $sopts[$pos + 1]
  244. : NULL;
  245. $next2_char = (isset($sopts[$pos + 2]))
  246. ? $sopts[$pos + 2]
  247. : NULL;
  248. if ($char == ':') {
  249. continue;
  250. }
  251. // $sopts[$pos] is character.
  252. if ($next_char == ':' && $next2_char == ':') {
  253. $analyze_result[$char] = ETHNA_OPTVALUE_IS_OPTIONAL; // ????
  254. } elseif ($next_char == ':' && $next2_char != ':') {
  255. $analyze_result[$char] = ETHNA_OPTVALUE_IS_REQUIRED; // ????
  256. } else {
  257. $analyze_result[$char] = ETHNA_OPTVALUE_IS_DISABLED; // ????
  258. }
  259. }
  260. return $analyze_result;
  261. }
  262. /**
  263. * ????????????????
  264. *
  265. * @param array $lopts ?????????
  266. * @return array ???????????????
  267. * ??????? Ethna_Error
  268. * @access protected
  269. */
  270. protected function _parseLongOption($lopts)
  271. {
  272. if (empty($lopts)) {
  273. return array();
  274. }
  275. if (!is_array($lopts)) {
  276. return Ethna::raiseError('invalid long options.');
  277. }
  278. $analyze_result = array();
  279. foreach ($lopts as $opt) {
  280. if (preg_match('/==$/', $opt) > 0) {
  281. $opt = substr($opt, 0, -2);
  282. $analyze_result[$opt] = ETHNA_OPTVALUE_IS_OPTIONAL; // ????
  283. } elseif (preg_match('/=$/', $opt) > 0) {
  284. $opt = substr($opt, 0, -1);
  285. $analyze_result[$opt] = ETHNA_OPTVALUE_IS_REQUIRED; // ????
  286. } else {
  287. $analyze_result[$opt] = ETHNA_OPTVALUE_IS_DISABLED; // ????
  288. }
  289. }
  290. return $analyze_result;
  291. }
  292. }
  293. // }}}