1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
3 // Copyright (c) 2009 Boris Schaeling
4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
10 #define BOOST_USE_WINDOWS_H
11
12 #include <boost/program_options.hpp>
13 #include <boost/filesystem.hpp>
14 #include <boost/algorithm/string/join.hpp>
15 #include <boost/range/iterator_range.hpp>
16 #include <boost/range/algorithm/transform.hpp>
17 #include <boost/range/algorithm_ext/push_back.hpp>
18 #include <boost/lambda/lambda.hpp>
19 #include <boost/process/environment.hpp>
20 #include <boost/process/handles.hpp>
21 #include <vector>
22 #include <string>
23 #include <iterator>
24 #include <iostream>
25 #include <cstdlib>
26 #if defined(BOOST_POSIX_API)
27 # include <boost/lexical_cast.hpp>
28 # include <boost/iostreams/device/file_descriptor.hpp>
29 # include <boost/iostreams/stream.hpp>
30 # include <unistd.h>
31 #elif defined(BOOST_WINDOWS_API)
32 # include <windows.h>
33 #endif
34
35
36 using namespace boost::program_options;
37
main(int argc,char * argv[])38 int main(int argc, char *argv[])
39 {
40 options_description desc;
41 desc.add_options()
42 ("echo-stdout", value<std::string>())
43 ("echo-stderr", value<std::string>())
44 ("echo-stdout-stderr", value<std::string>())
45 ("echo-argv", bool_switch())
46 ("exit-code", value<int>())
47 ("wait", value<int>())
48 ("is-closed-stdin", bool_switch())
49 ("is-closed-stdout", bool_switch())
50 ("is-closed-stderr", bool_switch())
51 ("is-nul-stdin", bool_switch())
52 ("is-nul-stdout", bool_switch())
53 ("is-nul-stderr", bool_switch())
54 ("loop", bool_switch())
55 ("abort", bool_switch())
56 ("prefix", value<std::string>())
57 ("prefix-once", value<std::string>())
58 ("pwd", bool_switch())
59 ("query", value<std::string>())
60 ("stdin-to-stdout", bool_switch())
61 ("has-handle", value<std::uintptr_t>())
62 #if defined(BOOST_POSIX_API)
63 ("posix-echo-one", value<std::vector<std::string> >()->multitoken())
64 ("posix-echo-two", value<std::vector<std::string> >()->multitoken());
65 #elif defined(BOOST_WINDOWS_API)
66 ("windows-print-showwindow", bool_switch())
67 ("windows-print-flags", bool_switch());
68 #endif
69 variables_map vm;
70 command_line_parser parser(argc, argv);
71 store(parser.options(desc).allow_unregistered().run(), vm);
72 notify(vm);
73
74 if (vm.count("echo-stdout"))
75 {
76 std::cout << vm["echo-stdout"].as<std::string>() << std::endl;
77 }
78 else if (vm.count("echo-stderr"))
79 {
80 std::cerr << vm["echo-stderr"].as<std::string>() << std::endl;
81 }
82 else if (vm.count("echo-stdout-stderr"))
83 {
84 std::cout << vm["echo-stdout-stderr"].as<std::string>() << std::endl;
85 std::cerr << vm["echo-stdout-stderr"].as<std::string>() << std::endl;
86 }
87 else if (vm["echo-argv"].as<bool>())
88 {
89 std::vector<char*> args(argv+1, argv + argc);
90 for (auto & arg : args)
91 std::cout << arg << std::endl;
92 }
93 else if (vm.count("exit-code"))
94 {
95 return vm["exit-code"].as<int>();
96 }
97 else if (vm.count("wait"))
98 {
99 int sec = vm["wait"].as<int>();
100 #if defined(BOOST_POSIX_API)
101 sleep(sec);
102 #elif defined(BOOST_WINDOWS_API)
103 Sleep(sec * 1000);
104 #endif
105 }
106 else if (vm["is-closed-stdin"].as<bool>())
107 {
108 std::string s;
109 std::cin >> s;
110 return std::cin.eof() ? EXIT_SUCCESS : EXIT_FAILURE;
111 }
112 else if (vm["is-closed-stdout"].as<bool>())
113 {
114 std::cout << "foo" << std::endl;
115 return std::cout.bad() ? EXIT_SUCCESS : EXIT_FAILURE;
116 }
117 else if (vm["is-closed-stderr"].as<bool>())
118 {
119 std::cerr << "foo" << std::endl;
120 return std::cerr.bad() ? EXIT_SUCCESS : EXIT_FAILURE;
121 }
122 else if (vm["is-nul-stdin"].as<bool>())
123 {
124 #if defined(BOOST_POSIX_API)
125 char buffer[1];
126 int res = read(STDIN_FILENO, buffer, 1);
127 return res != -1 ? EXIT_SUCCESS : EXIT_FAILURE;
128 #elif defined(BOOST_WINDOWS_API)
129 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
130 if (h == INVALID_HANDLE_VALUE)
131 return EXIT_FAILURE;
132 char buffer[1];
133 DWORD read;
134 BOOL res = ReadFile(h, buffer, 1, &read, NULL);
135 CloseHandle(h);
136 return res ? EXIT_SUCCESS : EXIT_FAILURE;
137 #endif
138 }
139 else if (vm["is-nul-stdout"].as<bool>())
140 {
141 std::cout << "foo" << std::endl;
142 return std::cout.bad() ? EXIT_FAILURE : EXIT_SUCCESS;
143 }
144 else if (vm["is-nul-stderr"].as<bool>())
145 {
146 std::cerr << "foo" << std::endl;
147 return std::cerr.bad() ? EXIT_FAILURE : EXIT_SUCCESS;
148 }
149 else if (vm["loop"].as<bool>())
150 {
151 while (true);
152 }
153 else if (vm["abort"].as<bool>())
154 {
155 std::abort();
156 }
157 else if (vm.count("prefix"))
158 {
159 std::string line;
160 while (std::getline(std::cin, line))
161 std::cout << vm["prefix"].as<std::string>() << line << std::endl;
162 }
163 else if (vm.count("prefix-once"))
164 {
165 std::string line;
166
167 std::getline(std::cin, line);
168
169 std::cout << vm["prefix-once"].as<std::string>() << line << std::endl;
170 }
171 else if (vm["pwd"].as<bool>())
172 {
173 std::cout << boost::filesystem::current_path().string() << std::endl;
174 }
175 else if (vm.count("query"))
176 {
177 auto key = vm["query"].as<std::string>();
178 auto env = boost::this_process::environment();
179 auto val = env[key];
180 if (val.empty())
181 std::cout << "************** empty environment **************" << std::endl;
182 else
183 std::cout << val.to_string() << std::endl;
184 }
185 else if (vm["stdin-to-stdout"].as<bool>())
186 {
187 char ch;
188 while (std::cin >> std::noskipws >> ch)
189 std::cout << ch << std::flush;
190 }
191 #if defined(BOOST_POSIX_API)
192 else if (vm.count("posix-echo-one"))
193 {
194 using namespace boost::iostreams;
195 std::vector<std::string> v = vm["posix-echo-one"].as<std::vector<std::string> >();
196 int fd = boost::lexical_cast<int>(v[0]);
197 file_descriptor_sink sink(fd, close_handle);
198 stream<file_descriptor_sink> os(sink);
199 os << v[1] << std::endl;
200 }
201 else if (vm.count("posix-echo-two"))
202 {
203 using namespace boost::iostreams;
204 std::vector<std::string> v = vm["posix-echo-two"].as<std::vector<std::string> >();
205 int fd1 = boost::lexical_cast<int>(v[0]);
206 file_descriptor_sink sink1(fd1, close_handle);
207 stream<file_descriptor_sink> os1(sink1);
208 os1 << v[1] << std::endl;
209 int fd2 = boost::lexical_cast<int>(v[2]);
210 file_descriptor_sink sink2(fd2, close_handle);
211 stream<file_descriptor_sink> os2(sink2);
212 os2 << v[3] << std::endl;
213 }
214 #elif defined(BOOST_WINDOWS_API)
215 else if (vm["windows-print-showwindow"].as<bool>())
216 {
217 STARTUPINFO si;
218 GetStartupInfo(&si);
219 std::cout << si.wShowWindow << std::endl;
220 }
221 else if (vm["windows-print-flags"].as<bool>())
222 {
223 STARTUPINFO si;
224 GetStartupInfo(&si);
225 std::cout << si.dwFlags << std::endl;
226 }
227 #endif
228 else if (vm.count("has-handle"))
229 {
230 #if defined(BOOST_WINDOWS_API)
231 const auto handle = reinterpret_cast<boost::this_process::native_handle_type>(vm["has-handle"].as<std::uintptr_t>());
232 #else
233 const auto handle = static_cast<boost::this_process::native_handle_type>(vm["has-handle"].as<std::uintptr_t>());
234 #endif
235 auto all_handles = boost::this_process::get_handles();
236 return (std::find(all_handles.begin(), all_handles.end(), handle) != all_handles.end()) ? EXIT_SUCCESS : EXIT_FAILURE;
237 }
238 return EXIT_SUCCESS;
239 }
240