/src/system/Args.hpp

https://github.com/XCSoar/XCSoar · C++ Header · 228 lines · 190 code · 16 blank · 22 comment · 4 complexity · b63757d1908a804bdc88cc78c80ad33b MD5 · raw file

  1. /*
  2. Copyright_License {
  3. XCSoar Glide Computer - http://www.xcsoar.org/
  4. Copyright (C) 2000-2021 The XCSoar Project
  5. A detailed list of copyright holders can be found in the file "AUTHORS".
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. }
  18. */
  19. #ifndef ARGS_HPP
  20. #define ARGS_HPP
  21. #include "util/Compiler.h"
  22. #include "util/tstring.hpp"
  23. #include "util/NumberParser.hpp"
  24. #include "system/Path.hpp"
  25. #ifdef _UNICODE
  26. #include "system/ConvertPathName.hpp"
  27. #endif
  28. #include <list>
  29. #include <algorithm>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <cassert>
  34. #include <iterator>
  35. #ifdef MORE_USAGE
  36. extern void PrintMoreUsage();
  37. #endif
  38. class Args {
  39. std::list<char *> args;
  40. const char *name, *usage;
  41. #ifdef _WIN32
  42. char *cmdline;
  43. #endif
  44. public:
  45. Args(int argc, char **argv, const char *_usage)
  46. :name(argv[0]), usage(_usage) {
  47. assert(name != nullptr);
  48. assert(usage != nullptr);
  49. std::copy(argv + 1, argv + argc, std::back_inserter(args));
  50. #ifdef _WIN32
  51. cmdline = nullptr;
  52. #endif
  53. }
  54. Args(const Args &other) = delete;
  55. Args(Args &&other):name(other.name), usage(other.usage) {
  56. std::swap(args, other.args);
  57. #ifdef _WIN32
  58. std::swap(cmdline, other.cmdline);
  59. #endif
  60. }
  61. #ifdef _WIN32
  62. Args(const TCHAR *_cmdline, const char *_usage)
  63. :usage(_usage) {
  64. ParseCommandLine(_cmdline);
  65. }
  66. ~Args() {
  67. delete[] cmdline;
  68. }
  69. void ParseCommandLine(const char *_cmdline) {
  70. const char *s = _cmdline;
  71. cmdline = new char[strlen(s) + 1];
  72. char *d = cmdline; // current position in destination buffer
  73. char *option = cmdline;
  74. name = nullptr;
  75. bool in_qoute = false;
  76. do {
  77. if (*s == '"')
  78. in_qoute = !in_qoute;
  79. else if (*s == '\0' || (!in_qoute && *s == ' ')) {
  80. // collapse runs of unqouted ' 's to a single '\0'
  81. if (d > cmdline && *(d-1) != '\0') {
  82. *d++ = '\0';
  83. // remember potential start position of next option
  84. option = d;
  85. }
  86. } else {
  87. *d = *s;
  88. if (option == d) {
  89. // first quoted blank or non blank character of new option
  90. // program name is not included in command line on CE
  91. if (name == nullptr)
  92. name = option;
  93. else
  94. args.push_back(option);
  95. }
  96. d++;
  97. }
  98. } while (*s++);
  99. if (name == nullptr)
  100. name = "";
  101. }
  102. #ifdef _UNICODE
  103. void ParseCommandLine(const TCHAR *_cmdline) {
  104. WideToACPConverter convert(_cmdline);
  105. ParseCommandLine(convert);
  106. }
  107. #endif
  108. #endif
  109. Args &operator=(const Args &other) = delete;
  110. [[noreturn]]
  111. void UsageError() {
  112. fprintf(stderr, "Usage: %s %s\n", name, usage);
  113. #ifdef MORE_USAGE
  114. PrintMoreUsage();
  115. #endif
  116. exit(EXIT_FAILURE);
  117. }
  118. bool IsEmpty() const {
  119. return args.empty();
  120. }
  121. const char *GetNext() {
  122. assert(!IsEmpty());
  123. const char *p = args.front();
  124. Skip();
  125. return p;
  126. }
  127. void Skip() {
  128. args.pop_front();
  129. }
  130. const char *PeekNext() const {
  131. return IsEmpty() ? nullptr : args.front();
  132. }
  133. const char *ExpectNext() {
  134. if (IsEmpty())
  135. UsageError();
  136. return GetNext();
  137. }
  138. int ExpectNextInt() {
  139. const char *p = ExpectNext();
  140. assert(p != nullptr);
  141. char *endptr;
  142. int result = ParseInt(p, &endptr);
  143. if (p == endptr)
  144. UsageError();
  145. return result;
  146. }
  147. double ExpectNextDouble() {
  148. const char *p = ExpectNext();
  149. assert(p != nullptr);
  150. char *endptr;
  151. double result = ParseDouble(p, &endptr);
  152. if (p == endptr)
  153. UsageError();
  154. return result;
  155. }
  156. tstring ExpectNextT() {
  157. const char *p = ExpectNext();
  158. assert(p != nullptr);
  159. #ifdef _UNICODE
  160. PathName convert(p);
  161. return tstring(((Path)convert).c_str());
  162. #else
  163. return tstring(p);
  164. #endif
  165. }
  166. #ifdef _UNICODE
  167. AllocatedPath ExpectNextPath() {
  168. const char *p = ExpectNext();
  169. assert(p != nullptr);
  170. return AllocatedPath(PathName(p));
  171. }
  172. #else
  173. Path ExpectNextPath() {
  174. const char *p = ExpectNext();
  175. assert(p != nullptr);
  176. return Path(p);
  177. }
  178. #endif
  179. void ExpectEnd() {
  180. if (!IsEmpty())
  181. UsageError();
  182. }
  183. };
  184. #endif