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.
 
 
 

174 line
4.2 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2002—2016 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #pragma once
  13. //
  14. // The getopt functions
  15. // --------------------
  16. //
  17. #include <vector>
  18. #include <string>
  19. #include <cstring>
  20. namespace lol
  21. {
  22. class getopt
  23. {
  24. public:
  25. getopt(int argc, char ** argv)
  26. : m_argc(argc),
  27. m_argv(argv)
  28. {
  29. }
  30. getopt(int argc, char * const * argv)
  31. : m_argc(argc),
  32. m_argv(argv)
  33. {
  34. }
  35. void add_opt(int short_opt, char const *long_opt, bool has_arg)
  36. {
  37. optdesc o { long_opt, has_arg, nullptr, short_opt };
  38. m_opts.push_back(o);
  39. /* “The standards require that the argument [to isalnum()] is either
  40. * EOF or a value that is representable in the type unsigned char.” */
  41. if ((int)(unsigned char)short_opt == short_opt && isalnum(short_opt))
  42. {
  43. m_optstring += (char)short_opt;
  44. if (has_arg)
  45. m_optstring += ':';
  46. }
  47. }
  48. int parse()
  49. {
  50. /* XXX: this getopt_long implementation should not be trusted for other
  51. * applications without any serious peer reviewing. It “just works” with
  52. * zzuf and a few libcaca programs but may fail miserably in other
  53. * programs. */
  54. char **argv = (char **)(uintptr_t)m_argv;
  55. char *flag;
  56. if (this->index >= m_argc)
  57. return -1;
  58. flag = argv[this->index];
  59. if (flag[0] == '-' && flag[1] != '-')
  60. {
  61. char const *tmp;
  62. int ret = flag[1];
  63. if (ret == '\0')
  64. return -1;
  65. tmp = strchr(m_optstring.c_str(), ret);
  66. if (!tmp || ret == ':')
  67. return '?';
  68. ++this->index;
  69. if (tmp[1] == ':')
  70. {
  71. if (flag[2] != '\0')
  72. this->arg = flag + 2;
  73. else
  74. {
  75. if (this->index >= m_argc)
  76. goto too_few;
  77. this->arg = argv[this->index++];
  78. }
  79. return ret;
  80. }
  81. if (flag[2] != '\0')
  82. {
  83. flag[1] = '-';
  84. --this->index;
  85. ++argv[this->index];
  86. }
  87. return ret;
  88. }
  89. if (flag[0] == '-' && flag[1] == '-')
  90. {
  91. if (flag[2] == '\0')
  92. return -1;
  93. for (int i = 0; m_opts[i].name; ++i)
  94. {
  95. size_t l = strlen(m_opts[i].name);
  96. if (strncmp(flag + 2, m_opts[i].name, l))
  97. continue;
  98. switch (flag[2 + l])
  99. {
  100. case '=':
  101. if (!m_opts[i].has_arg)
  102. goto bad_opt;
  103. ++this->index;
  104. this->arg = flag + 2 + l + 1;
  105. return m_opts[i].val;
  106. case '\0':
  107. ++this->index;
  108. if (m_opts[i].has_arg)
  109. {
  110. if (this->index >= m_argc)
  111. goto too_few;
  112. this->arg = argv[this->index++];
  113. }
  114. return m_opts[i].val;
  115. default:
  116. break;
  117. }
  118. }
  119. bad_opt:
  120. fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag);
  121. return '?';
  122. too_few:
  123. fprintf(stderr, "%s: option `%s' requires an argument\n",
  124. argv[0], flag);
  125. return '?';
  126. }
  127. return -1;
  128. }
  129. int index = 1;
  130. char *arg = nullptr;
  131. private:
  132. struct optdesc
  133. {
  134. char const *name;
  135. int has_arg;
  136. int *flag;
  137. int val;
  138. };
  139. int m_argc;
  140. char * const *m_argv;
  141. std::string m_optstring;
  142. std::vector<optdesc> m_opts;
  143. };
  144. } // namespace lol