├── .gitattributes ├── .github ├── FUNDING.yaml └── workflows │ └── module.yaml ├── LICENSE ├── META-INF └── com │ └── google │ └── android │ ├── update-binary │ └── updater-script ├── README.md ├── assets └── cover.png ├── install.sh ├── module.prop ├── src ├── powershell.cpp └── pstream.h └── system └── bin └── powershell /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf -------------------------------------------------------------------------------- /.github/FUNDING.yaml: -------------------------------------------------------------------------------- 1 | github: DerGoogler 2 | -------------------------------------------------------------------------------- /.github/workflows/module.yaml: -------------------------------------------------------------------------------- 1 | name: Build Magisk/KernelSU Module 2 | 3 | on: 4 | push: 5 | tags: [ v*.*.* ] 6 | 7 | jobs: 8 | build: 9 | name: Build Module 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Setup Apt Dependencies 15 | run: | 16 | sudo apt update -y && sudo apt upgrade -y 17 | sudo apt install zip unzip -y 18 | 19 | - name: Make 20 | shell: bash 21 | run: | 22 | zip -r "module.zip" * -x ".git" -x "README.md" -x "src/powershell.cpp" 23 | 24 | - name: Publish 25 | uses: softprops/action-gh-release@v1 26 | with: 27 | files: 'module.zip' 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Rick Astley. 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /META-INF/com/google/android/update-binary: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | ################# 4 | # Initialization 5 | ################# 6 | 7 | umask 022 8 | 9 | # echo before loading util_functions 10 | ui_print() { echo "$1"; } 11 | 12 | require_new_magisk() { 13 | ui_print "*******************************" 14 | ui_print " Please install Magisk v20.4+! " 15 | ui_print "*******************************" 16 | exit 1 17 | } 18 | 19 | ######################### 20 | # Load util_functions.sh 21 | ######################### 22 | 23 | OUTFD=$2 24 | ZIPFILE=$3 25 | 26 | mount /data 2>/dev/null 27 | 28 | [ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk 29 | . /data/adb/magisk/util_functions.sh 30 | [ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk 31 | 32 | install_module 33 | exit 0 -------------------------------------------------------------------------------- /META-INF/com/google/android/updater-script: -------------------------------------------------------------------------------- 1 | #MAGISK -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShell 2 | 3 | ![](https://raw.githubusercontent.com/DerGoogler/powershell/master/assets/cover.png) 4 | 5 | ## Example 6 | 7 | ```powershell 8 | powershell file.ps1 9 | ``` -------------------------------------------------------------------------------- /assets/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerGoogler/powershell/e6ab7a7f532ae4075e16e6fc970b037def29005b/assets/cover.png -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | SKIPMOUNT=false 2 | PROPFILE=false 3 | POSTFSDATA=false 4 | LATESTARTSERVICE=false 5 | 6 | on_install() { 7 | ui_print "- Extracting module files" 8 | unzip -qq -o "$ZIPFILE" 'system/*' -d $MODPATH >&2 9 | [ -d "$MODPATH/system/bin/" ] || mkdir -p "$MODPATH/system/bin/" 10 | } 11 | 12 | set_permissions() { 13 | # The following is the default rule, DO NOT remove 14 | set_perm_recursive $MODPATH 0 0 0755 0644 15 | set_perm $MODPATH/system/bin/powershell 0 0 0755 16 | } -------------------------------------------------------------------------------- /module.prop: -------------------------------------------------------------------------------- 1 | id=powershell 2 | name=Windows PowerShell 3 | version=7.4.2 4 | versionCode=742 5 | author=Der_Googler 6 | description=The Windows PowerShell Module is a tool that integrates PowerShell functionality into Android devices via the Magisk framework, allowing users to run PowerShell scripts and commands directly on their rooted devices. -------------------------------------------------------------------------------- /src/powershell.cpp: -------------------------------------------------------------------------------- 1 | #include "pstream.h" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | // run a process and create a streambuf that reads its stdout and stderr 8 | redi::ipstream proc("setenforce 0 && su -c am start -a android.intent.action.VIEW -d 'https://youtu.be/dQw4w9WgXcQ' && setenforce 1", redi::pstreams::pstdout | redi::pstreams::pstderr); 9 | std::string line; 10 | // read child's stdout 11 | while (std::getline(proc.out(), line)) 12 | std::cout << "stdout: " << line << '\n'; 13 | // if reading stdout stopped at EOF then reset the state: 14 | if (proc.eof() && proc.fail()) 15 | proc.clear(); 16 | // read child's stderr 17 | while (std::getline(proc.err(), line)) 18 | std::cout << "stderr: " << line << '\n'; 19 | } -------------------------------------------------------------------------------- /src/pstream.h: -------------------------------------------------------------------------------- 1 | // PStreams - POSIX Process I/O for C++ 2 | 3 | // Copyright (C) 2001 - 2020 Jonathan Wakely 4 | // Distributed under the Boost Software License, Version 1.0. 5 | // (See accompanying file LICENSE_1_0.txt or copy at 6 | // http://www.boost.org/LICENSE_1_0.txt) 7 | // 8 | // SPDX-License-Identifier: BSL-1.0 9 | 10 | /** 11 | * @file pstream.h 12 | * @brief Declares all PStreams classes. 13 | * @author Jonathan Wakely 14 | * 15 | * Defines classes redi::ipstream, redi::opstream, redi::pstream 16 | * and redi::rpstream. 17 | */ 18 | 19 | #ifndef REDI_PSTREAM_H_SEEN 20 | #define REDI_PSTREAM_H_SEEN 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include // for min() 29 | #include // for errno 30 | #include // for size_t, NULL 31 | #include // for exit() 32 | #include // for pid_t 33 | #include // for waitpid() 34 | #include // for ioctl() and FIONREAD 35 | #if defined(__sun) 36 | # include // for FIONREAD on Solaris 2.5 37 | #endif 38 | #include // for pipe() fork() exec() and filedes functions 39 | #include // for kill() 40 | #include // for fcntl() 41 | #if REDI_EVISCERATE_PSTREAMS 42 | # include // for FILE, fdopen() 43 | #endif 44 | 45 | 46 | /// The library version. 47 | #define PSTREAMS_VERSION 0x0103 // 1.0.3 48 | 49 | /** 50 | * @namespace redi 51 | * @brief All PStreams classes are declared in namespace redi. 52 | * 53 | * Like the standard iostreams, PStreams is a set of class templates, 54 | * taking a character type and traits type. As with the standard streams 55 | * they are most likely to be used with @c char and the default 56 | * traits type, so typedefs for this most common case are provided. 57 | * 58 | * The @c pstream_common class template is not intended to be used directly, 59 | * it is used internally to provide the common functionality for the 60 | * other stream classes. 61 | */ 62 | namespace redi 63 | { 64 | /// Common base class providing constants and typenames. 65 | struct pstreams 66 | { 67 | /// Type used to specify how to connect to the process. 68 | typedef std::ios_base::openmode pmode; 69 | 70 | /// Type used to hold the arguments for a command. 71 | typedef std::vector argv_type; 72 | 73 | /// Type used for file descriptors. 74 | typedef int fd_type; 75 | 76 | static const pmode pstdin = std::ios_base::out; ///< Write to stdin 77 | static const pmode pstdout = std::ios_base::in; ///< Read from stdout 78 | static const pmode pstderr = std::ios_base::app; ///< Read from stderr 79 | 80 | /// Create a new process group for the child process. 81 | static const pmode newpg = std::ios_base::trunc; 82 | 83 | protected: 84 | enum { 85 | bufsz = 32, ///< Size of pstreambuf buffers. 86 | pbsz = 2 ///< Number of putback characters kept. 87 | }; 88 | 89 | #if __cplusplus >= 201103L 90 | template 91 | using stringable = decltype((void)std::string(std::declval())); 92 | #endif 93 | }; 94 | 95 | /// Class template for stream buffer. 96 | template > 97 | class basic_pstreambuf 98 | : public std::basic_streambuf 99 | , public pstreams 100 | { 101 | public: 102 | // Type definitions for dependent types 103 | typedef CharT char_type; 104 | typedef Traits traits_type; 105 | typedef typename traits_type::int_type int_type; 106 | typedef typename traits_type::off_type off_type; 107 | typedef typename traits_type::pos_type pos_type; 108 | /** @deprecated use pstreams::fd_type instead. */ 109 | typedef fd_type fd_t; 110 | 111 | /// Default constructor. 112 | basic_pstreambuf(); 113 | 114 | /// Constructor that initialises the buffer with @a cmd. 115 | basic_pstreambuf(const std::string& cmd, pmode mode); 116 | 117 | /// Constructor that initialises the buffer with @a file and @a argv. 118 | basic_pstreambuf( const std::string& file, 119 | const argv_type& argv, 120 | pmode mode ); 121 | 122 | #if __cplusplus >= 201103L 123 | basic_pstreambuf(basic_pstreambuf&&) noexcept; 124 | basic_pstreambuf& operator=(basic_pstreambuf&&) noexcept; 125 | void swap(basic_pstreambuf&) noexcept; 126 | #endif 127 | 128 | /// Destructor. 129 | ~basic_pstreambuf(); 130 | 131 | /// Initialise the stream buffer with @a cmd. 132 | basic_pstreambuf* 133 | open(const std::string& cmd, pmode mode); 134 | 135 | /// Initialise the stream buffer with @a file and @a argv. 136 | basic_pstreambuf* 137 | open(const std::string& file, const argv_type& argv, pmode mode); 138 | 139 | /// Close the stream buffer and wait for the process to exit. 140 | basic_pstreambuf* 141 | close(); 142 | 143 | /// Send a signal to the process. 144 | basic_pstreambuf* 145 | kill(int signal = SIGTERM); 146 | 147 | /// Send a signal to the process' process group. 148 | basic_pstreambuf* 149 | killpg(int signal = SIGTERM); 150 | 151 | /// Close the pipe connected to the process' stdin. 152 | void 153 | peof(); 154 | 155 | /// Change active input source. 156 | bool 157 | read_err(bool readerr = true); 158 | 159 | /// Report whether the stream buffer has been initialised. 160 | bool 161 | is_open() const; 162 | 163 | /// Report whether the process has exited. 164 | bool 165 | exited(); 166 | 167 | #if REDI_EVISCERATE_PSTREAMS 168 | /// Obtain FILE pointers for each of the process' standard streams. 169 | std::size_t 170 | fopen(FILE*& in, FILE*& out, FILE*& err); 171 | #endif 172 | 173 | /// Return the exit status of the process. 174 | int 175 | status() const; 176 | 177 | /// Return the error number (errno) for the most recent failed operation. 178 | int 179 | error() const; 180 | 181 | protected: 182 | /// Transfer characters to the pipe when character buffer overflows. 183 | int_type 184 | overflow(int_type c); 185 | 186 | /// Transfer characters from the pipe when the character buffer is empty. 187 | int_type 188 | underflow(); 189 | 190 | /// Make a character available to be returned by the next extraction. 191 | int_type 192 | pbackfail(int_type c = traits_type::eof()); 193 | 194 | /// Write any buffered characters to the stream. 195 | int 196 | sync(); 197 | 198 | /// Insert multiple characters into the pipe. 199 | std::streamsize 200 | xsputn(const char_type* s, std::streamsize n); 201 | 202 | /// Insert a sequence of characters into the pipe. 203 | std::streamsize 204 | write(const char_type* s, std::streamsize n); 205 | 206 | /// Extract a sequence of characters from the pipe. 207 | std::streamsize 208 | read(char_type* s, std::streamsize n); 209 | 210 | /// Report how many characters can be read from active input without blocking. 211 | std::streamsize 212 | showmanyc(); 213 | 214 | protected: 215 | /// Enumerated type to indicate whether stdout or stderr is to be read. 216 | enum buf_read_src { rsrc_out = 0, rsrc_err = 1 }; 217 | 218 | /// Initialise pipes and fork process. 219 | pid_t 220 | fork(pmode mode); 221 | 222 | /// Wait for the child process to exit. 223 | int 224 | wait(bool nohang = false); 225 | 226 | /// Return the file descriptor for the output pipe. 227 | fd_type& 228 | wpipe(); 229 | 230 | /// Return the file descriptor for the active input pipe. 231 | fd_type& 232 | rpipe(); 233 | 234 | /// Return the file descriptor for the specified input pipe. 235 | fd_type& 236 | rpipe(buf_read_src which); 237 | 238 | void 239 | create_buffers(pmode mode); 240 | 241 | void 242 | destroy_buffers(pmode mode); 243 | 244 | /// Writes buffered characters to the process' stdin pipe. 245 | bool 246 | empty_buffer(); 247 | 248 | bool 249 | fill_buffer(bool non_blocking = false); 250 | 251 | /// Return the active input buffer. 252 | char_type* 253 | rbuffer(); 254 | 255 | buf_read_src 256 | switch_read_buffer(buf_read_src); 257 | 258 | private: 259 | #if __cplusplus >= 201103L 260 | using basic_streambuf = std::basic_streambuf; 261 | #else 262 | basic_pstreambuf(const basic_pstreambuf&); 263 | basic_pstreambuf& operator=(const basic_pstreambuf&); 264 | #endif 265 | 266 | void 267 | init_rbuffers(); 268 | 269 | pid_t ppid_; // pid of process 270 | fd_type wpipe_; // pipe used to write to process' stdin 271 | fd_type rpipe_[2]; // two pipes to read from, stdout and stderr 272 | char_type* wbuffer_; 273 | char_type* rbuffer_[2]; 274 | char_type* rbufstate_[3]; 275 | /// Index into rpipe_[] to indicate active source for read operations. 276 | buf_read_src rsrc_; 277 | int status_; // hold exit status of child process 278 | int error_; // hold errno if fork() or exec() fails 279 | }; 280 | 281 | /// Class template for common base class. 282 | template > 283 | class pstream_common 284 | : virtual public std::basic_ios 285 | , virtual public pstreams 286 | { 287 | protected: 288 | typedef basic_pstreambuf streambuf_type; 289 | typedef std::basic_ios ios_type; 290 | 291 | typedef pstreams::pmode pmode; 292 | typedef pstreams::argv_type argv_type; 293 | 294 | /// Default constructor. 295 | pstream_common(); 296 | 297 | /// Constructor that initialises the stream by starting a process. 298 | pstream_common(const std::string& cmd, pmode mode); 299 | 300 | /// Constructor that initialises the stream by starting a process. 301 | pstream_common(const std::string& file, const argv_type& argv, pmode mode); 302 | 303 | /// Pure virtual destructor. 304 | virtual 305 | ~pstream_common() = 0; 306 | 307 | #if __cplusplus >= 201103L 308 | pstream_common(pstream_common&& rhs) noexcept 309 | : command_(std::move(rhs.command_)) 310 | , buf_(std::move(rhs.buf_)) 311 | { 312 | /* derived class is responsible for ios_type::move(rhs) happening */ 313 | } 314 | 315 | pstream_common& 316 | operator=(pstream_common&& rhs) noexcept 317 | { 318 | command_ = std::move(rhs.command_); 319 | buf_ = std::move(rhs.buf_); 320 | return *this; 321 | } 322 | 323 | void 324 | swap(pstream_common& rhs) noexcept 325 | { 326 | /* derived class is responsible for ios_type::swap(rhs) happening */ 327 | command_.swap(rhs.command_); 328 | buf_.swap(rhs.buf_); 329 | } 330 | #endif // C++11 331 | 332 | /// Start a process. 333 | void 334 | do_open(const std::string& cmd, pmode mode); 335 | 336 | /// Start a process. 337 | void 338 | do_open(const std::string& file, const argv_type& argv, pmode mode); 339 | 340 | public: 341 | /// Close the pipe, returning the program's exit status, as 342 | /// pclose(3) does. 343 | int 344 | close(); 345 | 346 | /// Report whether the stream's buffer has been initialised. 347 | bool 348 | is_open() const; 349 | 350 | /// Return the command used to initialise the stream. 351 | const std::string& 352 | command() const; 353 | 354 | /// Return a pointer to the stream buffer. 355 | streambuf_type* 356 | rdbuf() const; 357 | 358 | #if REDI_EVISCERATE_PSTREAMS 359 | /// Obtain FILE pointers for each of the process' standard streams. 360 | std::size_t 361 | fopen(FILE*& in, FILE*& out, FILE*& err); 362 | #endif 363 | 364 | protected: 365 | std::string command_; ///< The command used to start the process. 366 | streambuf_type buf_; ///< The stream buffer. 367 | }; 368 | 369 | 370 | /** 371 | * @class basic_ipstream 372 | * @brief Class template for Input PStreams. 373 | * 374 | * Reading from an ipstream reads the command's standard output and/or 375 | * standard error (depending on how the ipstream is opened) 376 | * and the command's standard input is the same as that of the process 377 | * that created the object, unless altered by the command itself. 378 | */ 379 | 380 | template > 381 | class basic_ipstream 382 | : public std::basic_istream 383 | , public pstream_common 384 | , virtual public pstreams 385 | { 386 | typedef std::basic_istream istream_type; 387 | typedef pstream_common pbase_type; 388 | 389 | using pbase_type::buf_; // declare name in this scope 390 | 391 | // Ensure a basic_ipstream will read from at least one pipe 392 | pmode readable(pmode mode) 393 | { 394 | if (!(mode & (pstdout|pstderr))) 395 | mode |= pstdout; 396 | return mode; 397 | } 398 | 399 | public: 400 | /// Type used to specify how to connect to the process. 401 | typedef typename pbase_type::pmode pmode; 402 | 403 | /// Type used to hold the arguments for a command. 404 | typedef typename pbase_type::argv_type argv_type; 405 | 406 | /// Default constructor, creates an uninitialised stream. 407 | basic_ipstream() 408 | : istream_type(NULL), pbase_type() 409 | { } 410 | 411 | /** 412 | * @brief Constructor that initialises the stream by starting a process. 413 | * 414 | * Initialises the stream buffer by calling do_open() with the supplied 415 | * arguments. 416 | * 417 | * @param cmd a string containing a shell command. 418 | * @param mode the I/O mode to use when opening the pipe. 419 | * @see do_open(const std::string&, pmode) 420 | */ 421 | explicit 422 | basic_ipstream(const std::string& cmd, pmode mode = pstdout) 423 | : istream_type(NULL), pbase_type(cmd, readable(mode)) 424 | { } 425 | 426 | /** 427 | * @brief Constructor that initialises the stream by starting a process. 428 | * 429 | * Initialises the stream buffer by calling do_open() with the supplied 430 | * arguments. 431 | * 432 | * @param file a string containing the pathname of a program to execute. 433 | * @param argv a vector of argument strings passed to the new program. 434 | * @param mode the I/O mode to use when opening the pipe. 435 | * @see do_open(const std::string&, const argv_type&, pmode) 436 | */ 437 | basic_ipstream( const std::string& file, 438 | const argv_type& argv, 439 | pmode mode = pstdout ) 440 | : istream_type(NULL), pbase_type(file, argv, readable(mode)) 441 | { } 442 | 443 | /** 444 | * @brief Constructor that initialises the stream by starting a process. 445 | * 446 | * Initialises the stream buffer by calling 447 | * @c do_open(argv[0],argv,mode|pstdout) 448 | * 449 | * @param argv a vector of argument strings passed to the new program. 450 | * @param mode the I/O mode to use when opening the pipe. 451 | * @see do_open(const std::string&, const argv_type&, pmode) 452 | */ 453 | explicit 454 | basic_ipstream(const argv_type& argv, pmode mode = pstdout) 455 | : istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode)) 456 | { } 457 | 458 | #if __cplusplus >= 201103L 459 | template> 460 | explicit 461 | basic_ipstream(std::initializer_list args, pmode mode = pstdout) 462 | : basic_ipstream(argv_type(args.begin(), args.end()), mode) 463 | { } 464 | 465 | basic_ipstream(basic_ipstream&& rhs) 466 | : istream_type(std::move(rhs)) 467 | , pbase_type(std::move(rhs)) 468 | { istream_type::set_rdbuf(std::addressof(pbase_type::buf_)); } 469 | 470 | basic_ipstream& 471 | operator=(basic_ipstream&& rhs) 472 | { 473 | istream_type::operator=(std::move(rhs)); 474 | pbase_type::operator=(std::move(rhs)); 475 | return *this; 476 | } 477 | 478 | void 479 | swap(basic_ipstream& rhs) 480 | { 481 | istream_type::swap(rhs); 482 | pbase_type::swap(rhs); 483 | } 484 | #endif // C++11 485 | 486 | /** 487 | * @brief Destructor. 488 | * 489 | * Closes the stream and waits for the child to exit. 490 | */ 491 | ~basic_ipstream() 492 | { } 493 | 494 | /** 495 | * @brief Start a process. 496 | * 497 | * Calls do_open( @a cmd , @a mode|pstdout ). 498 | * 499 | * @param cmd a string containing a shell command. 500 | * @param mode the I/O mode to use when opening the pipe. 501 | * @see do_open(const std::string&, pmode) 502 | */ 503 | void 504 | open(const std::string& cmd, pmode mode = pstdout) 505 | { 506 | this->do_open(cmd, readable(mode)); 507 | } 508 | 509 | /** 510 | * @brief Start a process. 511 | * 512 | * Calls do_open( @a file , @a argv , @a mode|pstdout ). 513 | * 514 | * @param file a string containing the pathname of a program to execute. 515 | * @param argv a vector of argument strings passed to the new program. 516 | * @param mode the I/O mode to use when opening the pipe. 517 | * @see do_open(const std::string&, const argv_type&, pmode) 518 | */ 519 | void 520 | open( const std::string& file, 521 | const argv_type& argv, 522 | pmode mode = pstdout ) 523 | { 524 | this->do_open(file, argv, readable(mode)); 525 | } 526 | 527 | /** 528 | * @brief Set streambuf to read from process' @c stdout. 529 | * @return @c *this 530 | */ 531 | basic_ipstream& 532 | out() 533 | { 534 | this->buf_.read_err(false); 535 | return *this; 536 | } 537 | 538 | /** 539 | * @brief Set streambuf to read from process' @c stderr. 540 | * @return @c *this 541 | */ 542 | basic_ipstream& 543 | err() 544 | { 545 | this->buf_.read_err(true); 546 | return *this; 547 | } 548 | }; 549 | 550 | 551 | /** 552 | * @class basic_opstream 553 | * @brief Class template for Output PStreams. 554 | * 555 | * Writing to an open opstream writes to the standard input of the command; 556 | * the command's standard output is the same as that of the process that 557 | * created the pstream object, unless altered by the command itself. 558 | */ 559 | 560 | template > 561 | class basic_opstream 562 | : public std::basic_ostream 563 | , public pstream_common 564 | , virtual public pstreams 565 | { 566 | typedef std::basic_ostream ostream_type; 567 | typedef pstream_common pbase_type; 568 | 569 | using pbase_type::buf_; // declare name in this scope 570 | 571 | public: 572 | /// Type used to specify how to connect to the process. 573 | typedef typename pbase_type::pmode pmode; 574 | 575 | /// Type used to hold the arguments for a command. 576 | typedef typename pbase_type::argv_type argv_type; 577 | 578 | /// Default constructor, creates an uninitialised stream. 579 | basic_opstream() 580 | : ostream_type(NULL), pbase_type() 581 | { } 582 | 583 | /** 584 | * @brief Constructor that initialises the stream by starting a process. 585 | * 586 | * Initialises the stream buffer by calling do_open() with the supplied 587 | * arguments. 588 | * 589 | * @param cmd a string containing a shell command. 590 | * @param mode the I/O mode to use when opening the pipe. 591 | * @see do_open(const std::string&, pmode) 592 | */ 593 | explicit 594 | basic_opstream(const std::string& cmd, pmode mode = pstdin) 595 | : ostream_type(NULL), pbase_type(cmd, mode|pstdin) 596 | { } 597 | 598 | /** 599 | * @brief Constructor that initialises the stream by starting a process. 600 | * 601 | * Initialises the stream buffer by calling do_open() with the supplied 602 | * arguments. 603 | * 604 | * @param file a string containing the pathname of a program to execute. 605 | * @param argv a vector of argument strings passed to the new program. 606 | * @param mode the I/O mode to use when opening the pipe. 607 | * @see do_open(const std::string&, const argv_type&, pmode) 608 | */ 609 | basic_opstream( const std::string& file, 610 | const argv_type& argv, 611 | pmode mode = pstdin ) 612 | : ostream_type(NULL), pbase_type(file, argv, mode|pstdin) 613 | { } 614 | 615 | /** 616 | * @brief Constructor that initialises the stream by starting a process. 617 | * 618 | * Initialises the stream buffer by calling 619 | * @c do_open(argv[0],argv,mode|pstdin) 620 | * 621 | * @param argv a vector of argument strings passed to the new program. 622 | * @param mode the I/O mode to use when opening the pipe. 623 | * @see do_open(const std::string&, const argv_type&, pmode) 624 | */ 625 | explicit 626 | basic_opstream(const argv_type& argv, pmode mode = pstdin) 627 | : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin) 628 | { } 629 | 630 | #if __cplusplus >= 201103L 631 | /** 632 | * @brief Constructor that initialises the stream by starting a process. 633 | * 634 | * @param args a list of argument strings passed to the new program. 635 | * @param mode the I/O mode to use when opening the pipe. 636 | * @see do_open(const std::string&, const argv_type&, pmode) 637 | */ 638 | template> 639 | explicit 640 | basic_opstream(std::initializer_list args, pmode mode = pstdin) 641 | : basic_opstream(argv_type(args.begin(), args.end()), mode) 642 | { } 643 | 644 | basic_opstream(basic_opstream&& rhs) 645 | : ostream_type(std::move(rhs)) 646 | , pbase_type(std::move(rhs)) 647 | { ostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); } 648 | 649 | basic_opstream& 650 | operator=(basic_opstream&& rhs) 651 | { 652 | ostream_type::operator=(std::move(rhs)); 653 | pbase_type::operator=(std::move(rhs)); 654 | return *this; 655 | } 656 | 657 | void 658 | swap(basic_opstream& rhs) 659 | { 660 | ostream_type::swap(rhs); 661 | pbase_type::swap(rhs); 662 | } 663 | #endif // C++11 664 | 665 | /** 666 | * @brief Destructor 667 | * 668 | * Closes the stream and waits for the child to exit. 669 | */ 670 | ~basic_opstream() { } 671 | 672 | /** 673 | * @brief Start a process. 674 | * 675 | * Calls do_open( @a cmd , @a mode|pstdin ). 676 | * 677 | * @param cmd a string containing a shell command. 678 | * @param mode the I/O mode to use when opening the pipe. 679 | * @see do_open(const std::string&, pmode) 680 | */ 681 | void 682 | open(const std::string& cmd, pmode mode = pstdin) 683 | { 684 | this->do_open(cmd, mode|pstdin); 685 | } 686 | 687 | /** 688 | * @brief Start a process. 689 | * 690 | * Calls do_open( @a file , @a argv , @a mode|pstdin ). 691 | * 692 | * @param file a string containing the pathname of a program to execute. 693 | * @param argv a vector of argument strings passed to the new program. 694 | * @param mode the I/O mode to use when opening the pipe. 695 | * @see do_open(const std::string&, const argv_type&, pmode) 696 | */ 697 | void 698 | open( const std::string& file, 699 | const argv_type& argv, 700 | pmode mode = pstdin) 701 | { 702 | this->do_open(file, argv, mode|pstdin); 703 | } 704 | }; 705 | 706 | 707 | /** 708 | * @class basic_pstream 709 | * @brief Class template for Bidirectional PStreams. 710 | * 711 | * Writing to a pstream opened with @c pmode @c pstdin writes to the 712 | * standard input of the command. 713 | * Reading from a pstream opened with @c pmode @c pstdout and/or @c pstderr 714 | * reads the command's standard output and/or standard error. 715 | * Any of the process' @c stdin, @c stdout or @c stderr that is not 716 | * connected to the pstream (as specified by the @c pmode) 717 | * will be the same as the process that created the pstream object, 718 | * unless altered by the command itself. 719 | */ 720 | template > 721 | class basic_pstream 722 | : public std::basic_iostream 723 | , public pstream_common 724 | , virtual public pstreams 725 | { 726 | typedef std::basic_iostream iostream_type; 727 | typedef pstream_common pbase_type; 728 | 729 | using pbase_type::buf_; // declare name in this scope 730 | 731 | public: 732 | /// Type used to specify how to connect to the process. 733 | typedef typename pbase_type::pmode pmode; 734 | 735 | /// Type used to hold the arguments for a command. 736 | typedef typename pbase_type::argv_type argv_type; 737 | 738 | /// Default constructor, creates an uninitialised stream. 739 | basic_pstream() 740 | : iostream_type(NULL), pbase_type() 741 | { } 742 | 743 | /** 744 | * @brief Constructor that initialises the stream by starting a process. 745 | * 746 | * Initialises the stream buffer by calling do_open() with the supplied 747 | * arguments. 748 | * 749 | * @param cmd a string containing a shell command. 750 | * @param mode the I/O mode to use when opening the pipe. 751 | * @see do_open(const std::string&, pmode) 752 | */ 753 | explicit 754 | basic_pstream(const std::string& cmd, pmode mode = pstdout|pstdin) 755 | : iostream_type(NULL), pbase_type(cmd, mode) 756 | { } 757 | 758 | /** 759 | * @brief Constructor that initialises the stream by starting a process. 760 | * 761 | * Initialises the stream buffer by calling do_open() with the supplied 762 | * arguments. 763 | * 764 | * @param file a string containing the pathname of a program to execute. 765 | * @param argv a vector of argument strings passed to the new program. 766 | * @param mode the I/O mode to use when opening the pipe. 767 | * @see do_open(const std::string&, const argv_type&, pmode) 768 | */ 769 | basic_pstream( const std::string& file, 770 | const argv_type& argv, 771 | pmode mode = pstdout|pstdin ) 772 | : iostream_type(NULL), pbase_type(file, argv, mode) 773 | { } 774 | 775 | /** 776 | * @brief Constructor that initialises the stream by starting a process. 777 | * 778 | * Initialises the stream buffer by calling 779 | * @c do_open(argv[0],argv,mode) 780 | * 781 | * @param argv a vector of argument strings passed to the new program. 782 | * @param mode the I/O mode to use when opening the pipe. 783 | * @see do_open(const std::string&, const argv_type&, pmode) 784 | */ 785 | explicit 786 | basic_pstream(const argv_type& argv, pmode mode = pstdout|pstdin) 787 | : iostream_type(NULL), pbase_type(argv.at(0), argv, mode) 788 | { } 789 | 790 | #if __cplusplus >= 201103L 791 | /** 792 | * @brief Constructor that initialises the stream by starting a process. 793 | * 794 | * @param l a list of argument strings passed to the new program. 795 | * @param mode the I/O mode to use when opening the pipe. 796 | * @see do_open(const std::string&, const argv_type&, pmode) 797 | */ 798 | template> 799 | explicit 800 | basic_pstream(std::initializer_list l, pmode mode = pstdout|pstdin) 801 | : basic_pstream(argv_type(l.begin(), l.end()), mode) 802 | { } 803 | 804 | basic_pstream(basic_pstream&& rhs) 805 | : iostream_type(std::move(rhs)) 806 | , pbase_type(std::move(rhs)) 807 | { iostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); } 808 | 809 | basic_pstream& 810 | operator=(basic_pstream&& rhs) 811 | { 812 | iostream_type::operator=(std::move(rhs)); 813 | pbase_type::operator=(std::move(rhs)); 814 | return *this; 815 | } 816 | 817 | void 818 | swap(basic_pstream& rhs) 819 | { 820 | iostream_type::swap(rhs); 821 | pbase_type::swap(rhs); 822 | } 823 | #endif // C++11 824 | 825 | /** 826 | * @brief Destructor 827 | * 828 | * Closes the stream and waits for the child to exit. 829 | */ 830 | ~basic_pstream() { } 831 | 832 | /** 833 | * @brief Start a process. 834 | * 835 | * Calls do_open( @a cnd , @a mode ). 836 | * 837 | * @param cmd a string containing a shell command. 838 | * @param mode the I/O mode to use when opening the pipe. 839 | * @see do_open(const std::string&, pmode) 840 | */ 841 | void 842 | open(const std::string& cmd, pmode mode = pstdout|pstdin) 843 | { 844 | this->do_open(cmd, mode); 845 | } 846 | 847 | /** 848 | * @brief Start a process. 849 | * 850 | * Calls do_open( @a file , @a argv , @a mode ). 851 | * 852 | * @param file a string containing the pathname of a program to execute. 853 | * @param argv a vector of argument strings passed to the new program. 854 | * @param mode the I/O mode to use when opening the pipe. 855 | * @see do_open(const std::string&, const argv_type&, pmode) 856 | */ 857 | void 858 | open( const std::string& file, 859 | const argv_type& argv, 860 | pmode mode = pstdout|pstdin ) 861 | { 862 | this->do_open(file, argv, mode); 863 | } 864 | 865 | /** 866 | * @brief Set streambuf to read from process' @c stdout. 867 | * @return @c *this 868 | */ 869 | basic_pstream& 870 | out() 871 | { 872 | this->buf_.read_err(false); 873 | return *this; 874 | } 875 | 876 | /** 877 | * @brief Set streambuf to read from process' @c stderr. 878 | * @return @c *this 879 | */ 880 | basic_pstream& 881 | err() 882 | { 883 | this->buf_.read_err(true); 884 | return *this; 885 | } 886 | }; 887 | 888 | 889 | /** 890 | * @class basic_rpstream 891 | * @brief Class template for Restricted PStreams. 892 | * 893 | * Writing to an rpstream opened with @c pmode @c pstdin writes to the 894 | * standard input of the command. 895 | * It is not possible to read directly from an rpstream object, to use 896 | * an rpstream as in istream you must call either basic_rpstream::out() 897 | * or basic_rpstream::err(). This is to prevent accidental reads from 898 | * the wrong input source. If the rpstream was not opened with @c pmode 899 | * @c pstderr then the class cannot read the process' @c stderr, and 900 | * basic_rpstream::err() will return an istream that reads from the 901 | * process' @c stdout, and vice versa. 902 | * Reading from an rpstream opened with @c pmode @c pstdout and/or 903 | * @c pstderr reads the command's standard output and/or standard error. 904 | * Any of the process' @c stdin, @c stdout or @c stderr that is not 905 | * connected to the pstream (as specified by the @c pmode) 906 | * will be the same as the process that created the pstream object, 907 | * unless altered by the command itself. 908 | */ 909 | 910 | template > 911 | class basic_rpstream 912 | : public std::basic_ostream 913 | , private std::basic_istream 914 | , private pstream_common 915 | , virtual public pstreams 916 | { 917 | typedef std::basic_ostream ostream_type; 918 | typedef std::basic_istream istream_type; 919 | typedef pstream_common pbase_type; 920 | 921 | using pbase_type::buf_; // declare name in this scope 922 | 923 | public: 924 | /// Type used to specify how to connect to the process. 925 | typedef typename pbase_type::pmode pmode; 926 | 927 | /// Type used to hold the arguments for a command. 928 | typedef typename pbase_type::argv_type argv_type; 929 | 930 | /// Default constructor, creates an uninitialised stream. 931 | basic_rpstream() 932 | : ostream_type(NULL), istream_type(NULL), pbase_type() 933 | { } 934 | 935 | /** 936 | * @brief Constructor that initialises the stream by starting a process. 937 | * 938 | * Initialises the stream buffer by calling do_open() with the supplied 939 | * arguments. 940 | * 941 | * @param cmd a string containing a shell command. 942 | * @param mode the I/O mode to use when opening the pipe. 943 | * @see do_open(const std::string&, pmode) 944 | */ 945 | explicit 946 | basic_rpstream(const std::string& cmd, pmode mode = pstdout|pstdin) 947 | : ostream_type(NULL) , istream_type(NULL) , pbase_type(cmd, mode) 948 | { } 949 | 950 | /** 951 | * @brief Constructor that initialises the stream by starting a process. 952 | * 953 | * Initialises the stream buffer by calling do_open() with the supplied 954 | * arguments. 955 | * 956 | * @param file a string containing the pathname of a program to execute. 957 | * @param argv a vector of argument strings passed to the new program. 958 | * @param mode the I/O mode to use when opening the pipe. 959 | * @see do_open(const std::string&, const argv_type&, pmode) 960 | */ 961 | basic_rpstream( const std::string& file, 962 | const argv_type& argv, 963 | pmode mode = pstdout|pstdin ) 964 | : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode) 965 | { } 966 | 967 | /** 968 | * @brief Constructor that initialises the stream by starting a process. 969 | * 970 | * Initialises the stream buffer by calling 971 | * @c do_open(argv[0],argv,mode) 972 | * 973 | * @param argv a vector of argument strings passed to the new program. 974 | * @param mode the I/O mode to use when opening the pipe. 975 | * @see do_open(const std::string&, const argv_type&, pmode) 976 | */ 977 | explicit 978 | basic_rpstream(const argv_type& argv, pmode mode = pstdout|pstdin) 979 | : ostream_type(NULL), istream_type(NULL) 980 | , pbase_type(argv.at(0), argv, mode) 981 | { } 982 | 983 | #if __cplusplus >= 201103L 984 | /** 985 | * @brief Constructor that initialises the stream by starting a process. 986 | * 987 | * @param l a list of argument strings passed to the new program. 988 | * @param mode the I/O mode to use when opening the pipe. 989 | * @see do_open(const std::string&, const argv_type&, pmode) 990 | */ 991 | template> 992 | explicit 993 | basic_rpstream(std::initializer_list l, pmode mode = pstdout|pstdin) 994 | : basic_rpstream(argv_type(l.begin(), l.end()), mode) 995 | { } 996 | 997 | // TODO: figure out how to move istream and ostream bases separately, 998 | // but so the virtual basic_ios base is only modified once. 999 | #if 0 1000 | basic_rpstream(basic_rpstream&& rhs) 1001 | : iostream_type(std::move(rhs)) 1002 | , pbase_type(std::move(rhs)) 1003 | { iostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); } 1004 | 1005 | basic_rpstream& 1006 | operator=(basic_rpstream&& rhs) 1007 | { 1008 | iostream_type::operator=(std::move(rhs)); 1009 | pbase_type::operator=(std::move(rhs)); 1010 | return *this; 1011 | } 1012 | 1013 | void 1014 | swap(basic_rpstream& rhs) 1015 | { 1016 | iostream_type::swap(rhs); 1017 | pbase_type::swap(rhs); 1018 | } 1019 | #endif 1020 | #endif // C++11 1021 | 1022 | /// Destructor 1023 | ~basic_rpstream() { } 1024 | 1025 | /** 1026 | * @brief Start a process. 1027 | * 1028 | * Calls do_open( @a cmd , @a mode ). 1029 | * 1030 | * @param cmd a string containing a shell command. 1031 | * @param mode the I/O mode to use when opening the pipe. 1032 | * @see do_open(const std::string&, pmode) 1033 | */ 1034 | void 1035 | open(const std::string& cmd, pmode mode = pstdout|pstdin) 1036 | { 1037 | this->do_open(cmd, mode); 1038 | } 1039 | 1040 | /** 1041 | * @brief Start a process. 1042 | * 1043 | * Calls do_open( @a file , @a argv , @a mode ). 1044 | * 1045 | * @param file a string containing the pathname of a program to execute. 1046 | * @param argv a vector of argument strings passed to the new program. 1047 | * @param mode the I/O mode to use when opening the pipe. 1048 | * @see do_open(const std::string&, const argv_type&, pmode) 1049 | */ 1050 | void 1051 | open( const std::string& file, 1052 | const argv_type& argv, 1053 | pmode mode = pstdout|pstdin ) 1054 | { 1055 | this->do_open(file, argv, mode); 1056 | } 1057 | 1058 | /** 1059 | * @brief Obtain a reference to the istream that reads 1060 | * the process' @c stdout. 1061 | * @return @c *this 1062 | */ 1063 | istream_type& 1064 | out() 1065 | { 1066 | this->buf_.read_err(false); 1067 | return *this; 1068 | } 1069 | 1070 | /** 1071 | * @brief Obtain a reference to the istream that reads 1072 | * the process' @c stderr. 1073 | * @return @c *this 1074 | */ 1075 | istream_type& 1076 | err() 1077 | { 1078 | this->buf_.read_err(true); 1079 | return *this; 1080 | } 1081 | }; 1082 | 1083 | 1084 | /// Type definition for common template specialisation. 1085 | typedef basic_pstreambuf pstreambuf; 1086 | /// Type definition for common template specialisation. 1087 | typedef basic_ipstream ipstream; 1088 | /// Type definition for common template specialisation. 1089 | typedef basic_opstream opstream; 1090 | /// Type definition for common template specialisation. 1091 | typedef basic_pstream pstream; 1092 | /// Type definition for common template specialisation. 1093 | typedef basic_rpstream rpstream; 1094 | 1095 | 1096 | /** 1097 | * When inserted into an output pstream the manipulator calls 1098 | * basic_pstreambuf::peof() to close the output pipe, 1099 | * causing the child process to receive the end-of-file indicator 1100 | * on subsequent reads from its @c stdin stream. 1101 | * 1102 | * @brief Manipulator to close the pipe connected to the process' stdin. 1103 | * @param s An output PStream class. 1104 | * @return The stream object the manipulator was invoked on. 1105 | * @see basic_pstreambuf::peof() 1106 | * @relates basic_opstream basic_pstream basic_rpstream 1107 | */ 1108 | template 1109 | inline std::basic_ostream& 1110 | peof(std::basic_ostream& s) 1111 | { 1112 | typedef basic_pstreambuf pstreambuf_type; 1113 | if (pstreambuf_type* p = dynamic_cast(s.rdbuf())) 1114 | p->peof(); 1115 | return s; 1116 | } 1117 | 1118 | 1119 | /* 1120 | * member definitions for pstreambuf 1121 | */ 1122 | 1123 | 1124 | /** 1125 | * @class basic_pstreambuf 1126 | * Provides underlying streambuf functionality for the PStreams classes. 1127 | */ 1128 | 1129 | /** Creates an uninitialised stream buffer. */ 1130 | template 1131 | inline 1132 | basic_pstreambuf::basic_pstreambuf() 1133 | : ppid_(-1) // initialise to -1 to indicate no process run yet. 1134 | , wpipe_(-1) 1135 | , wbuffer_() 1136 | , rbuffer_() 1137 | , rbufstate_() 1138 | , rsrc_(rsrc_out) 1139 | , status_(-1) 1140 | , error_(0) 1141 | { 1142 | rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; 1143 | } 1144 | 1145 | /** 1146 | * Initialises the stream buffer by calling open() with the supplied 1147 | * arguments. 1148 | * 1149 | * @param cmd a string containing a shell command. 1150 | * @param mode the I/O mode to use when opening the pipe. 1151 | * @see open() 1152 | */ 1153 | template 1154 | inline 1155 | basic_pstreambuf::basic_pstreambuf(const std::string& cmd, pmode mode) 1156 | : ppid_(-1) // initialise to -1 to indicate no process run yet. 1157 | , wpipe_(-1) 1158 | , wbuffer_() 1159 | , rbuffer_() 1160 | , rbufstate_() 1161 | , rsrc_(rsrc_out) 1162 | , status_(-1) 1163 | , error_(0) 1164 | { 1165 | rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; 1166 | open(cmd, mode); 1167 | } 1168 | 1169 | /** 1170 | * Initialises the stream buffer by calling open() with the supplied 1171 | * arguments. 1172 | * 1173 | * @param file a string containing the name of a program to execute. 1174 | * @param argv a vector of argument strings passsed to the new program. 1175 | * @param mode the I/O mode to use when opening the pipe. 1176 | * @see open() 1177 | */ 1178 | template 1179 | inline 1180 | basic_pstreambuf::basic_pstreambuf( const std::string& file, 1181 | const argv_type& argv, 1182 | pmode mode ) 1183 | : ppid_(-1) // initialise to -1 to indicate no process run yet. 1184 | , wpipe_(-1) 1185 | , wbuffer_() 1186 | , rbuffer_() 1187 | , rbufstate_() 1188 | , rsrc_(rsrc_out) 1189 | , status_(-1) 1190 | , error_(0) 1191 | { 1192 | rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; 1193 | open(file, argv, mode); 1194 | } 1195 | 1196 | /** 1197 | * Closes the stream by calling close(). 1198 | * @see close() 1199 | */ 1200 | template 1201 | inline 1202 | basic_pstreambuf::~basic_pstreambuf() 1203 | { 1204 | close(); 1205 | } 1206 | 1207 | #if __cplusplus >= 201103L 1208 | /** 1209 | * Move constructor. 1210 | */ 1211 | template 1212 | inline 1213 | basic_pstreambuf::basic_pstreambuf( basic_pstreambuf&& rhs ) noexcept 1214 | : basic_streambuf(static_cast(rhs)) 1215 | , ppid_(rhs.ppid_) 1216 | , wpipe_(rhs.wpipe_) 1217 | , rpipe_{rhs.rpipe_[0], rhs.rpipe_[1]} 1218 | , wbuffer_(rhs.wbuffer_) 1219 | , rbuffer_{rhs.rbuffer_[0], rhs.rbuffer_[1]} 1220 | , rbufstate_{rhs.rbufstate_[0], rhs.rbufstate_[1], rhs.rbufstate_[2]} 1221 | , rsrc_(rhs.rsrc_) 1222 | , status_(rhs.status_) 1223 | , error_(rhs.error_) 1224 | { 1225 | rhs.ppid_ = -1; 1226 | rhs.wpipe_ = -1; 1227 | rhs.rpipe_[0] = rhs.rpipe_[1] = -1; 1228 | rhs.wbuffer_ = nullptr; 1229 | rhs.rbuffer_[0] = rhs.rbuffer_[1] = nullptr; 1230 | rhs.rbufstate_[0] = rhs.rbufstate_[1] = rhs.rbufstate_[2] = nullptr; 1231 | rhs.rsrc_ = rsrc_out; 1232 | rhs.status_ = -1; 1233 | rhs.error_ = 0; 1234 | rhs.setg(nullptr, nullptr, nullptr); 1235 | rhs.setp(nullptr, nullptr); 1236 | } 1237 | 1238 | template 1239 | inline basic_pstreambuf& 1240 | basic_pstreambuf::operator=( basic_pstreambuf&& rhs ) noexcept 1241 | { 1242 | close(); 1243 | basic_streambuf::operator=(static_cast(rhs)); 1244 | swap(rhs); 1245 | return *this; 1246 | } 1247 | 1248 | template 1249 | inline void 1250 | basic_pstreambuf::swap( basic_pstreambuf& rhs ) noexcept 1251 | { 1252 | basic_streambuf::swap(static_cast(rhs)); 1253 | std::swap(ppid_, rhs.ppid_); 1254 | std::swap(wpipe_, rhs.wpipe_); 1255 | std::swap(rpipe_, rhs.rpipe_); 1256 | std::swap(wbuffer_, rhs.wbuffer_); 1257 | std::swap(rbuffer_, rhs.rbuffer_); 1258 | std::swap(rbufstate_, rhs.rbufstate_); 1259 | std::swap(rsrc_, rhs.rsrc_); 1260 | std::swap(status_, rhs.status_); 1261 | std::swap(error_, rhs.error_); 1262 | } 1263 | #endif // C++11 1264 | 1265 | /** 1266 | * Starts a new process by passing @a command to the shell (/bin/sh) 1267 | * and opens pipes to the process with the specified @a mode. 1268 | * 1269 | * If @a mode contains @c pstdout the initial read source will be 1270 | * the child process' stdout, otherwise if @a mode contains @c pstderr 1271 | * the initial read source will be the child's stderr. 1272 | * 1273 | * Will duplicate the actions of the shell in searching for an 1274 | * executable file if the specified file name does not contain a slash (/) 1275 | * character. 1276 | * 1277 | * @warning 1278 | * There is no way to tell whether the shell command succeeded, this 1279 | * function will always succeed unless resource limits (such as 1280 | * memory usage, or number of processes or open files) are exceeded. 1281 | * This means is_open() will return true even if @a command cannot 1282 | * be executed. 1283 | * Use pstreambuf::open(const std::string&, const argv_type&, pmode) 1284 | * if you need to know whether the command failed to execute. 1285 | * 1286 | * @param command a string containing a shell command. 1287 | * @param mode a bitwise OR of one or more of @c out, @c in, @c err. 1288 | * @return NULL if the shell could not be started or the 1289 | * pipes could not be opened, @c this otherwise. 1290 | * @see execl(3) 1291 | */ 1292 | template 1293 | basic_pstreambuf* 1294 | basic_pstreambuf::open(const std::string& command, pmode mode) 1295 | { 1296 | const char * shell_path = "/bin/sh"; 1297 | #if 0 1298 | const std::string argv[] = { "sh", "-c", command }; 1299 | return this->open(shell_path, argv_type(argv, argv+3), mode); 1300 | #else 1301 | basic_pstreambuf* ret = NULL; 1302 | 1303 | if (!is_open()) 1304 | { 1305 | switch(fork(mode)) 1306 | { 1307 | case 0 : 1308 | // this is the new process, exec command 1309 | ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL); 1310 | 1311 | // can only reach this point if exec() failed 1312 | 1313 | // parent can get exit code from waitpid() 1314 | ::_exit(errno); 1315 | // using std::exit() would make static dtors run twice 1316 | 1317 | case -1 : 1318 | // couldn't fork, error already handled in pstreambuf::fork() 1319 | break; 1320 | 1321 | default : 1322 | // this is the parent process 1323 | // activate buffers 1324 | create_buffers(mode); 1325 | ret = this; 1326 | } 1327 | } 1328 | return ret; 1329 | #endif 1330 | } 1331 | 1332 | /** 1333 | * @brief Helper function to close a file descriptor. 1334 | * 1335 | * Inspects @a fd and calls close(3) if it has a non-negative value. 1336 | * 1337 | * @param fd a file descriptor. 1338 | * @relates basic_pstreambuf 1339 | */ 1340 | inline void 1341 | close_fd(pstreams::fd_type& fd) 1342 | { 1343 | if (fd >= 0 && ::close(fd) == 0) 1344 | fd = -1; 1345 | } 1346 | 1347 | /** 1348 | * @brief Helper function to close an array of file descriptors. 1349 | * 1350 | * Calls @c close_fd() on each member of the array. 1351 | * The length of the array is determined automatically by 1352 | * template argument deduction to avoid errors. 1353 | * 1354 | * @param fds an array of file descriptors. 1355 | * @relates basic_pstreambuf 1356 | */ 1357 | template 1358 | inline void 1359 | close_fd_array(pstreams::fd_type (&fds)[N]) 1360 | { 1361 | for (std::size_t i = 0; i < N; ++i) 1362 | close_fd(fds[i]); 1363 | } 1364 | 1365 | /** 1366 | * Starts a new process by executing @a file with the arguments in 1367 | * @a argv and opens pipes to the process with the specified @a mode. 1368 | * 1369 | * By convention @c argv[0] should be the file name of the file being 1370 | * executed. 1371 | * 1372 | * If @a mode contains @c pstdout the initial read source will be 1373 | * the child process' stdout, otherwise if @a mode contains @c pstderr 1374 | * the initial read source will be the child's stderr. 1375 | * 1376 | * Will duplicate the actions of the shell in searching for an 1377 | * executable file if the specified file name does not contain a slash (/) 1378 | * character. 1379 | * 1380 | * Iff @a file is successfully executed then is_open() will return true. 1381 | * Otherwise, pstreambuf::error() can be used to obtain the value of 1382 | * @c errno that was set by execvp(3) in the child process. 1383 | * 1384 | * The exit status of the new process will be returned by 1385 | * pstreambuf::status() after pstreambuf::exited() returns true. 1386 | * 1387 | * @param file a string containing the pathname of a program to execute. 1388 | * @param argv a vector of argument strings passed to the new program. 1389 | * @param mode a bitwise OR of one or more of @c out, @c in and @c err. 1390 | * @return NULL if a pipe could not be opened or if the program could 1391 | * not be executed, @c this otherwise. 1392 | * @see execvp(3) 1393 | */ 1394 | template 1395 | basic_pstreambuf* 1396 | basic_pstreambuf::open( const std::string& file, 1397 | const argv_type& argv, 1398 | pmode mode ) 1399 | { 1400 | basic_pstreambuf* ret = NULL; 1401 | 1402 | if (!is_open()) 1403 | { 1404 | // constants for read/write ends of pipe 1405 | enum { RD, WR }; 1406 | 1407 | // open another pipe and set close-on-exec 1408 | fd_type ck_exec[] = { -1, -1 }; 1409 | if (-1 == ::pipe(ck_exec) 1410 | || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC) 1411 | || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC)) 1412 | { 1413 | error_ = errno; 1414 | close_fd_array(ck_exec); 1415 | } 1416 | else 1417 | { 1418 | switch(fork(mode)) 1419 | { 1420 | case 0 : 1421 | // this is the new process, exec command 1422 | { 1423 | char** arg_v = new char*[argv.size()+1]; 1424 | for (std::size_t i = 0; i < argv.size(); ++i) 1425 | { 1426 | const std::string& src = argv[i]; 1427 | char*& dest = arg_v[i]; 1428 | dest = new char[src.size()+1]; 1429 | dest[ src.copy(dest, src.size()) ] = '\0'; 1430 | } 1431 | arg_v[argv.size()] = NULL; 1432 | 1433 | ::execvp(file.c_str(), arg_v); 1434 | 1435 | // can only reach this point if exec() failed 1436 | 1437 | // parent can get error code from ck_exec pipe 1438 | error_ = errno; 1439 | 1440 | while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1 1441 | && errno == EINTR) 1442 | { } 1443 | 1444 | ::close(ck_exec[WR]); 1445 | ::close(ck_exec[RD]); 1446 | 1447 | ::_exit(error_); 1448 | // using std::exit() would make static dtors run twice 1449 | } 1450 | 1451 | case -1 : 1452 | // couldn't fork, error already handled in pstreambuf::fork() 1453 | close_fd_array(ck_exec); 1454 | break; 1455 | 1456 | default : 1457 | // this is the parent process 1458 | 1459 | // check child called exec() successfully 1460 | ::close(ck_exec[WR]); 1461 | switch (::read(ck_exec[RD], &error_, sizeof(error_))) 1462 | { 1463 | case 0: 1464 | // activate buffers 1465 | create_buffers(mode); 1466 | ret = this; 1467 | break; 1468 | case -1: 1469 | error_ = errno; 1470 | break; 1471 | default: 1472 | // error_ contains error code from child 1473 | // call wait() to clean up and set ppid_ to 0 1474 | this->wait(); 1475 | break; 1476 | } 1477 | ::close(ck_exec[RD]); 1478 | } 1479 | } 1480 | } 1481 | return ret; 1482 | } 1483 | 1484 | /** 1485 | * Creates pipes as specified by @a mode and calls @c fork() to create 1486 | * a new process. If the fork is successful the parent process stores 1487 | * the child's PID and the opened pipes and the child process replaces 1488 | * its standard streams with the opened pipes. 1489 | * 1490 | * If an error occurs the error code will be set to one of the possible 1491 | * errors for @c pipe() or @c fork(). 1492 | * See your system's documentation for these error codes. 1493 | * 1494 | * @param mode an OR of pmodes specifying which of the child's 1495 | * standard streams to connect to. 1496 | * @return On success the PID of the child is returned in the parent's 1497 | * context and zero is returned in the child's context. 1498 | * On error -1 is returned and the error code is set appropriately. 1499 | */ 1500 | template 1501 | pid_t 1502 | basic_pstreambuf::fork(pmode mode) 1503 | { 1504 | pid_t pid = -1; 1505 | 1506 | // Three pairs of file descriptors, for pipes connected to the 1507 | // process' stdin, stdout and stderr 1508 | // (stored in a single array so close_fd_array() can close all at once) 1509 | fd_type fd[] = { -1, -1, -1, -1, -1, -1 }; 1510 | fd_type* const pin = fd; 1511 | fd_type* const pout = fd+2; 1512 | fd_type* const perr = fd+4; 1513 | 1514 | // constants for read/write ends of pipe 1515 | enum { RD, WR }; 1516 | 1517 | // N.B. 1518 | // For the pstreambuf pin is an output stream and 1519 | // pout and perr are input streams. 1520 | 1521 | if (!error_ && mode&pstdin && ::pipe(pin)) 1522 | error_ = errno; 1523 | 1524 | if (!error_ && mode&pstdout && ::pipe(pout)) 1525 | error_ = errno; 1526 | 1527 | if (!error_ && mode&pstderr && ::pipe(perr)) 1528 | error_ = errno; 1529 | 1530 | if (!error_) 1531 | { 1532 | pid = ::fork(); 1533 | switch (pid) 1534 | { 1535 | case 0 : 1536 | { 1537 | // this is the new process 1538 | 1539 | // for each open pipe close one end and redirect the 1540 | // respective standard stream to the other end 1541 | 1542 | if (*pin >= 0) 1543 | { 1544 | ::close(pin[WR]); 1545 | ::dup2(pin[RD], STDIN_FILENO); 1546 | ::close(pin[RD]); 1547 | } 1548 | if (*pout >= 0) 1549 | { 1550 | ::close(pout[RD]); 1551 | ::dup2(pout[WR], STDOUT_FILENO); 1552 | ::close(pout[WR]); 1553 | } 1554 | if (*perr >= 0) 1555 | { 1556 | ::close(perr[RD]); 1557 | ::dup2(perr[WR], STDERR_FILENO); 1558 | ::close(perr[WR]); 1559 | } 1560 | 1561 | #ifdef _POSIX_JOB_CONTROL 1562 | if (mode&newpg) 1563 | ::setpgid(0, 0); // Change to a new process group 1564 | #endif 1565 | 1566 | break; 1567 | } 1568 | case -1 : 1569 | { 1570 | // couldn't fork for some reason 1571 | error_ = errno; 1572 | // close any open pipes 1573 | close_fd_array(fd); 1574 | break; 1575 | } 1576 | default : 1577 | { 1578 | // this is the parent process, store process' pid 1579 | ppid_ = pid; 1580 | 1581 | // store one end of open pipes and close other end 1582 | if (*pin >= 0) 1583 | { 1584 | wpipe_ = pin[WR]; 1585 | ::close(pin[RD]); 1586 | } 1587 | if (*pout >= 0) 1588 | { 1589 | rpipe_[rsrc_out] = pout[RD]; 1590 | ::close(pout[WR]); 1591 | } 1592 | if (*perr >= 0) 1593 | { 1594 | rpipe_[rsrc_err] = perr[RD]; 1595 | ::close(perr[WR]); 1596 | } 1597 | } 1598 | } 1599 | } 1600 | else 1601 | { 1602 | // close any pipes we opened before failure 1603 | close_fd_array(fd); 1604 | } 1605 | return pid; 1606 | } 1607 | 1608 | /** 1609 | * Closes all pipes and calls wait() to wait for the process to finish. 1610 | * If an error occurs the error code will be set to one of the possible 1611 | * errors for @c waitpid(). 1612 | * See your system's documentation for these errors. 1613 | * 1614 | * @return @c this on successful close or @c NULL if there is no 1615 | * process to close or if an error occurs. 1616 | */ 1617 | template 1618 | basic_pstreambuf* 1619 | basic_pstreambuf::close() 1620 | { 1621 | const bool running = is_open(); 1622 | 1623 | basic_pstreambuf::sync(); // might call wait() and reap the child process 1624 | 1625 | // rather than trying to work out whether or not we need to clean up 1626 | // just do it anyway, all cleanup functions are safe to call twice. 1627 | 1628 | destroy_buffers(pstdin|pstdout|pstderr); 1629 | 1630 | // close pipes before wait() so child gets EOF/SIGPIPE 1631 | close_fd(wpipe_); 1632 | close_fd_array(rpipe_); 1633 | 1634 | do 1635 | { 1636 | error_ = 0; 1637 | } while (wait() == -1 && error() == EINTR); 1638 | 1639 | return running ? this : NULL; 1640 | } 1641 | 1642 | /** 1643 | * Used to be called on construction to initialise the arrays for reading. 1644 | * No longer used. 1645 | */ 1646 | template 1647 | #if __cplusplus >= 201402L && __has_cpp_attribute(deprecated) 1648 | [[deprecated]] 1649 | #elif __GNUC__ 1650 | __attribute__((deprecated)) 1651 | #endif 1652 | inline void 1653 | basic_pstreambuf::init_rbuffers() 1654 | { 1655 | rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; 1656 | rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL; 1657 | rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL; 1658 | } 1659 | 1660 | template 1661 | void 1662 | basic_pstreambuf::create_buffers(pmode mode) 1663 | { 1664 | if (mode & pstdin) 1665 | { 1666 | delete[] wbuffer_; 1667 | wbuffer_ = new char_type[bufsz]; 1668 | this->setp(wbuffer_, wbuffer_ + bufsz); 1669 | } 1670 | if (mode & pstdout) 1671 | { 1672 | delete[] rbuffer_[rsrc_out]; 1673 | rbuffer_[rsrc_out] = new char_type[bufsz]; 1674 | rsrc_ = rsrc_out; 1675 | this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz, 1676 | rbuffer_[rsrc_out] + pbsz); 1677 | } 1678 | if (mode & pstderr) 1679 | { 1680 | delete[] rbuffer_[rsrc_err]; 1681 | rbuffer_[rsrc_err] = new char_type[bufsz]; 1682 | if (!(mode & pstdout)) 1683 | { 1684 | rsrc_ = rsrc_err; 1685 | this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz, 1686 | rbuffer_[rsrc_err] + pbsz); 1687 | } 1688 | } 1689 | } 1690 | 1691 | template 1692 | void 1693 | basic_pstreambuf::destroy_buffers(pmode mode) 1694 | { 1695 | if (mode & pstdin) 1696 | { 1697 | this->setp(NULL, NULL); 1698 | delete[] wbuffer_; 1699 | wbuffer_ = NULL; 1700 | } 1701 | if (mode & pstdout) 1702 | { 1703 | if (rsrc_ == rsrc_out) 1704 | this->setg(NULL, NULL, NULL); 1705 | delete[] rbuffer_[rsrc_out]; 1706 | rbuffer_[rsrc_out] = NULL; 1707 | } 1708 | if (mode & pstderr) 1709 | { 1710 | if (rsrc_ == rsrc_err) 1711 | this->setg(NULL, NULL, NULL); 1712 | delete[] rbuffer_[rsrc_err]; 1713 | rbuffer_[rsrc_err] = NULL; 1714 | } 1715 | } 1716 | 1717 | template 1718 | typename basic_pstreambuf::buf_read_src 1719 | basic_pstreambuf::switch_read_buffer(buf_read_src src) 1720 | { 1721 | if (rsrc_ != src) 1722 | { 1723 | char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()}; 1724 | this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]); 1725 | for (std::size_t i = 0; i < 3; ++i) 1726 | rbufstate_[i] = tmpbufstate[i]; 1727 | rsrc_ = src; 1728 | } 1729 | return rsrc_; 1730 | } 1731 | 1732 | /** 1733 | * Suspends execution and waits for the associated process to exit, or 1734 | * until a signal is delivered whose action is to terminate the current 1735 | * process or to call a signal handling function. If the process has 1736 | * already exited (i.e. it is a "zombie" process) then wait() returns 1737 | * immediately. Waiting for the child process causes all its system 1738 | * resources to be freed. 1739 | * 1740 | * error() will return EINTR if wait() is interrupted by a signal. 1741 | * 1742 | * @param nohang true to return immediately if the process has not exited. 1743 | * @return 1 if the process has exited and wait() has not yet been called. 1744 | * 0 if @a nohang is true and the process has not exited yet. 1745 | * -1 if no process has been started or if an error occurs, 1746 | * in which case the error can be found using error(). 1747 | */ 1748 | template 1749 | int 1750 | basic_pstreambuf::wait(bool nohang) 1751 | { 1752 | int child_exited = -1; 1753 | if (is_open()) 1754 | { 1755 | int exit_status; 1756 | switch(::waitpid(ppid_, &exit_status, nohang ? WNOHANG : 0)) 1757 | { 1758 | case 0 : 1759 | // nohang was true and process has not exited 1760 | child_exited = 0; 1761 | break; 1762 | case -1 : 1763 | error_ = errno; 1764 | break; 1765 | default : 1766 | // process has exited 1767 | ppid_ = 0; 1768 | status_ = exit_status; 1769 | child_exited = 1; 1770 | // Close wpipe, would get SIGPIPE if we used it. 1771 | destroy_buffers(pstdin); 1772 | close_fd(wpipe_); 1773 | // Must free read buffers and pipes on destruction 1774 | // or next call to open()/close() 1775 | break; 1776 | } 1777 | } 1778 | return child_exited; 1779 | } 1780 | 1781 | /** 1782 | * Sends the specified signal to the process. A signal can be used to 1783 | * terminate a child process that would not exit otherwise. 1784 | * 1785 | * If an error occurs the error code will be set to one of the possible 1786 | * errors for @c kill(). See your system's documentation for these errors. 1787 | * 1788 | * @param signal A signal to send to the child process. 1789 | * @return @c this or @c NULL if @c kill() fails. 1790 | */ 1791 | template 1792 | inline basic_pstreambuf* 1793 | basic_pstreambuf::kill(int signal) 1794 | { 1795 | basic_pstreambuf* ret = NULL; 1796 | if (is_open()) 1797 | { 1798 | if (::kill(ppid_, signal)) 1799 | error_ = errno; 1800 | else 1801 | { 1802 | #if 0 1803 | // TODO call exited() to check for exit and clean up? leave to user? 1804 | if (signal==SIGTERM || signal==SIGKILL) 1805 | this->exited(); 1806 | #endif 1807 | ret = this; 1808 | } 1809 | } 1810 | return ret; 1811 | } 1812 | 1813 | /** 1814 | * Sends the specified signal to the process group of the child process. 1815 | * A signal can be used to terminate a child process that would not exit 1816 | * otherwise, or to kill the process and its own children. 1817 | * 1818 | * If an error occurs the error code will be set to one of the possible 1819 | * errors for @c getpgid() or @c kill(). See your system's documentation 1820 | * for these errors. If the child is in the current process group then 1821 | * NULL will be returned and the error code set to EPERM. 1822 | * 1823 | * @param signal A signal to send to the child process. 1824 | * @return @c this on success or @c NULL on failure. 1825 | */ 1826 | template 1827 | inline basic_pstreambuf* 1828 | basic_pstreambuf::killpg(int signal) 1829 | { 1830 | basic_pstreambuf* ret = NULL; 1831 | #ifdef _POSIX_JOB_CONTROL 1832 | if (is_open()) 1833 | { 1834 | pid_t pgid = ::getpgid(ppid_); 1835 | if (pgid == -1) 1836 | error_ = errno; 1837 | else if (pgid == ::getpgrp()) 1838 | error_ = EPERM; // Don't commit suicide 1839 | else if (::killpg(pgid, signal)) 1840 | error_ = errno; 1841 | else 1842 | ret = this; 1843 | } 1844 | #else 1845 | error_ = ENOTSUP; 1846 | #endif 1847 | return ret; 1848 | } 1849 | 1850 | /** 1851 | * This function can call pstreambuf::wait() and so may change the 1852 | * object's state if the child process has already exited. 1853 | * 1854 | * @return True if the associated process has exited, false otherwise. 1855 | * @see basic_pstreambuf::wait() 1856 | */ 1857 | template 1858 | inline bool 1859 | basic_pstreambuf::exited() 1860 | { 1861 | return ppid_ == 0 || wait(true)==1; 1862 | } 1863 | 1864 | 1865 | /** 1866 | * @return The exit status of the child process, or -1 if wait() 1867 | * has not yet been called to wait for the child to exit. 1868 | * @see basic_pstreambuf::wait() 1869 | */ 1870 | template 1871 | inline int 1872 | basic_pstreambuf::status() const 1873 | { 1874 | return status_; 1875 | } 1876 | 1877 | /** 1878 | * @return The error code of the most recently failed operation, or zero. 1879 | */ 1880 | template 1881 | inline int 1882 | basic_pstreambuf::error() const 1883 | { 1884 | return error_; 1885 | } 1886 | 1887 | /** 1888 | * Closes the output pipe, causing the child process to receive the 1889 | * end-of-file indicator on subsequent reads from its @c stdin stream. 1890 | */ 1891 | template 1892 | inline void 1893 | basic_pstreambuf::peof() 1894 | { 1895 | sync(); 1896 | destroy_buffers(pstdin); 1897 | close_fd(wpipe_); 1898 | } 1899 | 1900 | /** 1901 | * Unlike pstreambuf::exited(), this function will not call wait() and 1902 | * so will not change the object's state. This means that once a child 1903 | * process is executed successfully this function will continue to 1904 | * return true even after the process exits (until wait() is called.) 1905 | * 1906 | * @return true if a previous call to open() succeeded and wait() has 1907 | * not been called and determined that the process has exited, 1908 | * false otherwise. 1909 | */ 1910 | template 1911 | inline bool 1912 | basic_pstreambuf::is_open() const 1913 | { 1914 | return ppid_ > 0; 1915 | } 1916 | 1917 | /** 1918 | * Toggle the stream used for reading. If @a readerr is @c true then the 1919 | * process' @c stderr output will be used for subsequent extractions, if 1920 | * @a readerr is false the the process' stdout will be used. 1921 | * @param readerr @c true to read @c stderr, @c false to read @c stdout. 1922 | * @return @c true if the requested stream is open and will be used for 1923 | * subsequent extractions, @c false otherwise. 1924 | */ 1925 | template 1926 | inline bool 1927 | basic_pstreambuf::read_err(bool readerr) 1928 | { 1929 | buf_read_src src = readerr ? rsrc_err : rsrc_out; 1930 | if (rpipe_[src]>=0) 1931 | { 1932 | switch_read_buffer(src); 1933 | return true; 1934 | } 1935 | return false; 1936 | } 1937 | 1938 | /** 1939 | * Called when the internal character buffer is not present or is full, 1940 | * to transfer the buffer contents to the pipe. 1941 | * 1942 | * @param c a character to be written to the pipe. 1943 | * @return @c traits_type::eof() if an error occurs, otherwise if @a c 1944 | * is not equal to @c traits_type::eof() it will be buffered and 1945 | * a value other than @c traits_type::eof() returned to indicate 1946 | * success. 1947 | */ 1948 | template 1949 | typename basic_pstreambuf::int_type 1950 | basic_pstreambuf::overflow(int_type c) 1951 | { 1952 | if (!empty_buffer()) 1953 | return traits_type::eof(); 1954 | else if (!traits_type::eq_int_type(c, traits_type::eof())) 1955 | return this->sputc(c); 1956 | else 1957 | return traits_type::not_eof(c); 1958 | } 1959 | 1960 | 1961 | template 1962 | int 1963 | basic_pstreambuf::sync() 1964 | { 1965 | return !exited() && empty_buffer() ? 0 : -1; 1966 | } 1967 | 1968 | /** 1969 | * @param s character buffer. 1970 | * @param n buffer length. 1971 | * @return the number of characters written. 1972 | */ 1973 | template 1974 | std::streamsize 1975 | basic_pstreambuf::xsputn(const char_type* s, std::streamsize n) 1976 | { 1977 | std::streamsize done = 0; 1978 | while (done < n) 1979 | { 1980 | if (std::streamsize nbuf = this->epptr() - this->pptr()) 1981 | { 1982 | nbuf = std::min(nbuf, n - done); 1983 | traits_type::copy(this->pptr(), s + done, nbuf); 1984 | this->pbump(nbuf); 1985 | done += nbuf; 1986 | } 1987 | else if (!empty_buffer()) 1988 | break; 1989 | } 1990 | return done; 1991 | } 1992 | 1993 | /** 1994 | * @return true if the buffer was emptied, false otherwise. 1995 | */ 1996 | template 1997 | bool 1998 | basic_pstreambuf::empty_buffer() 1999 | { 2000 | const std::streamsize count = this->pptr() - this->pbase(); 2001 | if (count > 0) 2002 | { 2003 | const std::streamsize written = this->write(this->wbuffer_, count); 2004 | if (written > 0) 2005 | { 2006 | if (const std::streamsize unwritten = count - written) 2007 | traits_type::move(this->pbase(), this->pbase()+written, unwritten); 2008 | this->pbump(-written); 2009 | return true; 2010 | } 2011 | } 2012 | return false; 2013 | } 2014 | 2015 | /** 2016 | * Called when the internal character buffer is is empty, to re-fill it 2017 | * from the pipe. 2018 | * 2019 | * @return The first available character in the buffer, 2020 | * or @c traits_type::eof() in case of failure. 2021 | */ 2022 | template 2023 | typename basic_pstreambuf::int_type 2024 | basic_pstreambuf::underflow() 2025 | { 2026 | if (this->gptr() < this->egptr() || fill_buffer()) 2027 | return traits_type::to_int_type(*this->gptr()); 2028 | else 2029 | return traits_type::eof(); 2030 | } 2031 | 2032 | /** 2033 | * Attempts to make @a c available as the next character to be read by 2034 | * @c sgetc(). 2035 | * 2036 | * @param c a character to make available for extraction. 2037 | * @return @a c if the character can be made available, 2038 | * @c traits_type::eof() otherwise. 2039 | */ 2040 | template 2041 | typename basic_pstreambuf::int_type 2042 | basic_pstreambuf::pbackfail(int_type c) 2043 | { 2044 | if (this->gptr() != this->eback()) 2045 | { 2046 | this->gbump(-1); 2047 | if (!traits_type::eq_int_type(c, traits_type::eof())) 2048 | *this->gptr() = traits_type::to_char_type(c); 2049 | return traits_type::not_eof(c); 2050 | } 2051 | else 2052 | return traits_type::eof(); 2053 | } 2054 | 2055 | template 2056 | std::streamsize 2057 | basic_pstreambuf::showmanyc() 2058 | { 2059 | int avail = 0; 2060 | if (sizeof(char_type) == 1) 2061 | avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1; 2062 | #ifdef FIONREAD 2063 | else 2064 | { 2065 | if (::ioctl(rpipe(), FIONREAD, &avail) == -1) 2066 | avail = -1; 2067 | else if (avail) 2068 | avail /= sizeof(char_type); 2069 | } 2070 | #endif 2071 | return std::streamsize(avail); 2072 | } 2073 | 2074 | /** 2075 | * @return true if the buffer was filled, false otherwise. 2076 | */ 2077 | template 2078 | bool 2079 | basic_pstreambuf::fill_buffer(bool non_blocking) 2080 | { 2081 | const std::streamsize pb1 = this->gptr() - this->eback(); 2082 | const std::streamsize pb2 = pbsz; 2083 | const std::streamsize npb = std::min(pb1, pb2); 2084 | 2085 | char_type* const rbuf = rbuffer(); 2086 | 2087 | if (npb) 2088 | traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb); 2089 | 2090 | std::streamsize rc = -1; 2091 | 2092 | if (non_blocking) 2093 | { 2094 | const int flags = ::fcntl(rpipe(), F_GETFL); 2095 | if (flags != -1) 2096 | { 2097 | const bool blocking = !(flags & O_NONBLOCK); 2098 | if (blocking) 2099 | ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking 2100 | 2101 | error_ = 0; 2102 | rc = read(rbuf + pbsz, bufsz - pbsz); 2103 | 2104 | if (rc == -1 && error_ == EAGAIN) // nothing available 2105 | rc = 0; 2106 | else if (rc == 0) // EOF 2107 | rc = -1; 2108 | 2109 | if (blocking) 2110 | ::fcntl(rpipe(), F_SETFL, flags); // restore 2111 | } 2112 | } 2113 | else 2114 | rc = read(rbuf + pbsz, bufsz - pbsz); 2115 | 2116 | if (rc > 0 || (rc == 0 && non_blocking)) 2117 | { 2118 | this->setg( rbuf + pbsz - npb, 2119 | rbuf + pbsz, 2120 | rbuf + pbsz + rc ); 2121 | return true; 2122 | } 2123 | else 2124 | { 2125 | this->setg(NULL, NULL, NULL); 2126 | return false; 2127 | } 2128 | } 2129 | 2130 | /** 2131 | * Writes up to @a n characters to the pipe from the buffer @a s. 2132 | * 2133 | * @param s character buffer. 2134 | * @param n buffer length. 2135 | * @return the number of characters written. 2136 | */ 2137 | template 2138 | inline std::streamsize 2139 | basic_pstreambuf::write(const char_type* s, std::streamsize n) 2140 | { 2141 | std::streamsize nwritten = 0; 2142 | if (wpipe() >= 0) 2143 | { 2144 | nwritten = ::write(wpipe(), s, n * sizeof(char_type)); 2145 | if (nwritten == -1) 2146 | error_ = errno; 2147 | else 2148 | nwritten /= sizeof(char_type); 2149 | } 2150 | return nwritten; 2151 | } 2152 | 2153 | /** 2154 | * Reads up to @a n characters from the pipe to the buffer @a s. 2155 | * 2156 | * @param s character buffer. 2157 | * @param n buffer length. 2158 | * @return the number of characters read. 2159 | */ 2160 | template 2161 | inline std::streamsize 2162 | basic_pstreambuf::read(char_type* s, std::streamsize n) 2163 | { 2164 | std::streamsize nread = 0; 2165 | if (rpipe() >= 0) 2166 | { 2167 | nread = ::read(rpipe(), s, n * sizeof(char_type)); 2168 | if (nread == -1) 2169 | error_ = errno; 2170 | else 2171 | nread /= sizeof(char_type); 2172 | } 2173 | return nread; 2174 | } 2175 | 2176 | /** @return a reference to the output file descriptor */ 2177 | template 2178 | inline pstreams::fd_type& 2179 | basic_pstreambuf::wpipe() 2180 | { 2181 | return wpipe_; 2182 | } 2183 | 2184 | /** @return a reference to the active input file descriptor */ 2185 | template 2186 | inline pstreams::fd_type& 2187 | basic_pstreambuf::rpipe() 2188 | { 2189 | return rpipe_[rsrc_]; 2190 | } 2191 | 2192 | /** @return a reference to the specified input file descriptor */ 2193 | template 2194 | inline pstreams::fd_type& 2195 | basic_pstreambuf::rpipe(buf_read_src which) 2196 | { 2197 | return rpipe_[which]; 2198 | } 2199 | 2200 | /** @return a pointer to the start of the active input buffer area. */ 2201 | template 2202 | inline typename basic_pstreambuf::char_type* 2203 | basic_pstreambuf::rbuffer() 2204 | { 2205 | return rbuffer_[rsrc_]; 2206 | } 2207 | 2208 | 2209 | /* 2210 | * member definitions for pstream_common 2211 | */ 2212 | 2213 | /** 2214 | * @class pstream_common 2215 | * Abstract Base Class providing common functionality for basic_ipstream, 2216 | * basic_opstream and basic_pstream. 2217 | * pstream_common manages the basic_pstreambuf stream buffer that is used 2218 | * by the derived classes to initialise an iostream class. 2219 | */ 2220 | 2221 | /** Creates an uninitialised stream. */ 2222 | template 2223 | inline 2224 | pstream_common::pstream_common() 2225 | : std::basic_ios(NULL) 2226 | , command_() 2227 | , buf_() 2228 | { 2229 | this->std::basic_ios::rdbuf(&buf_); 2230 | } 2231 | 2232 | /** 2233 | * Initialises the stream buffer by calling 2234 | * do_open( @a command , @a mode ) 2235 | * 2236 | * @param cmd a string containing a shell command. 2237 | * @param mode the I/O mode to use when opening the pipe. 2238 | * @see do_open(const std::string&, pmode) 2239 | */ 2240 | template 2241 | inline 2242 | pstream_common::pstream_common(const std::string& cmd, pmode mode) 2243 | : std::basic_ios(NULL) 2244 | , command_(cmd) 2245 | , buf_() 2246 | { 2247 | this->std::basic_ios::rdbuf(&buf_); 2248 | do_open(cmd, mode); 2249 | } 2250 | 2251 | /** 2252 | * Initialises the stream buffer by calling 2253 | * do_open( @a file , @a argv , @a mode ) 2254 | * 2255 | * @param file a string containing the pathname of a program to execute. 2256 | * @param argv a vector of argument strings passed to the new program. 2257 | * @param mode the I/O mode to use when opening the pipe. 2258 | * @see do_open(const std::string&, const argv_type&, pmode) 2259 | */ 2260 | template 2261 | inline 2262 | pstream_common::pstream_common( const std::string& file, 2263 | const argv_type& argv, 2264 | pmode mode ) 2265 | : std::basic_ios(NULL) 2266 | , command_(file) 2267 | , buf_() 2268 | { 2269 | this->std::basic_ios::rdbuf(&buf_); 2270 | do_open(file, argv, mode); 2271 | } 2272 | 2273 | /** 2274 | * This is a pure virtual function to make @c pstream_common abstract. 2275 | * Because it is the destructor it will be called by derived classes 2276 | * and so must be defined. It is also protected, to discourage use of 2277 | * the PStreams classes through pointers or references to the base class. 2278 | * 2279 | * @sa If defining a pure virtual seems odd you should read 2280 | * http://www.gotw.ca/gotw/031.htm (and the rest of the site as well!) 2281 | */ 2282 | template 2283 | inline 2284 | pstream_common::~pstream_common() 2285 | { 2286 | } 2287 | 2288 | /** 2289 | * Calls rdbuf()->open( @a command , @a mode ) 2290 | * and sets @c failbit on error. 2291 | * 2292 | * @param cmd a string containing a shell command. 2293 | * @param mode the I/O mode to use when opening the pipe. 2294 | * @see basic_pstreambuf::open(const std::string&, pmode) 2295 | */ 2296 | template 2297 | inline void 2298 | pstream_common::do_open(const std::string& cmd, pmode mode) 2299 | { 2300 | if (!buf_.open((command_=cmd), mode)) 2301 | this->setstate(std::ios_base::failbit); 2302 | } 2303 | 2304 | /** 2305 | * Calls rdbuf()->open( @a file, @a argv, @a mode ) 2306 | * and sets @c failbit on error. 2307 | * 2308 | * @param file a string containing the pathname of a program to execute. 2309 | * @param argv a vector of argument strings passed to the new program. 2310 | * @param mode the I/O mode to use when opening the pipe. 2311 | * @see basic_pstreambuf::open(const std::string&, const argv_type&, pmode) 2312 | */ 2313 | template 2314 | inline void 2315 | pstream_common::do_open( const std::string& file, 2316 | const argv_type& argv, 2317 | pmode mode ) 2318 | { 2319 | if (!buf_.open((command_=file), argv, mode)) 2320 | this->setstate(std::ios_base::failbit); 2321 | } 2322 | 2323 | /** Calls rdbuf->close() and sets @c failbit on error. Returns 2324 | * process's exit status, as pclose(3) does. */ 2325 | template 2326 | inline int 2327 | pstream_common::close() 2328 | { 2329 | if (!buf_.close()) 2330 | this->setstate(std::ios_base::failbit); 2331 | return buf_.status(); 2332 | } 2333 | 2334 | /** 2335 | * @return rdbuf()->is_open(). 2336 | * @see basic_pstreambuf::is_open() 2337 | */ 2338 | template 2339 | inline bool 2340 | pstream_common::is_open() const 2341 | { 2342 | return buf_.is_open(); 2343 | } 2344 | 2345 | /** @return a string containing the command used to initialise the stream. */ 2346 | template 2347 | inline const std::string& 2348 | pstream_common::command() const 2349 | { 2350 | return command_; 2351 | } 2352 | 2353 | /** @return a pointer to the private stream buffer member. */ 2354 | // TODO document behaviour if buffer replaced. 2355 | template 2356 | inline typename pstream_common::streambuf_type* 2357 | pstream_common::rdbuf() const 2358 | { 2359 | return const_cast(&buf_); 2360 | } 2361 | 2362 | 2363 | #if REDI_EVISCERATE_PSTREAMS 2364 | /** 2365 | * @def REDI_EVISCERATE_PSTREAMS 2366 | * If this macro has a non-zero value then certain internals of the 2367 | * @c basic_pstreambuf template class are exposed. In general this is 2368 | * a Bad Thing, as the internal implementation is largely undocumented 2369 | * and may be subject to change at any time, so this feature is only 2370 | * provided because it might make PStreams useful in situations where 2371 | * it is necessary to do Bad Things. 2372 | */ 2373 | 2374 | /** 2375 | * @warning This function exposes the internals of the stream buffer and 2376 | * should be used with caution. It is the caller's responsibility 2377 | * to flush streams etc. in order to clear any buffered data. 2378 | * The POSIX.1 function fdopen(3) is used to obtain the 2379 | * @c FILE pointers from the streambuf's private file descriptor 2380 | * members so consult your system's documentation for 2381 | * fdopen(3). 2382 | * 2383 | * @param in A FILE* that will refer to the process' stdin. 2384 | * @param out A FILE* that will refer to the process' stdout. 2385 | * @param err A FILE* that will refer to the process' stderr. 2386 | * @return An OR of zero or more of @c pstdin, @c pstdout, @c pstderr. 2387 | * 2388 | * For each open stream shared with the child process a @c FILE* is 2389 | * obtained and assigned to the corresponding parameter. For closed 2390 | * streams @c NULL is assigned to the parameter. 2391 | * The return value can be tested to see which parameters should be 2392 | * @c !NULL by masking with the corresponding @c pmode value. 2393 | * 2394 | * @see fdopen(3) 2395 | */ 2396 | template 2397 | std::size_t 2398 | basic_pstreambuf::fopen(FILE*& in, FILE*& out, FILE*& err) 2399 | { 2400 | in = out = err = NULL; 2401 | std::size_t open_files = 0; 2402 | if (wpipe() > -1) 2403 | { 2404 | if ((in = ::fdopen(wpipe(), "w"))) 2405 | { 2406 | open_files |= pstdin; 2407 | } 2408 | } 2409 | if (rpipe(rsrc_out) > -1) 2410 | { 2411 | if ((out = ::fdopen(rpipe(rsrc_out), "r"))) 2412 | { 2413 | open_files |= pstdout; 2414 | } 2415 | } 2416 | if (rpipe(rsrc_err) > -1) 2417 | { 2418 | if ((err = ::fdopen(rpipe(rsrc_err), "r"))) 2419 | { 2420 | open_files |= pstderr; 2421 | } 2422 | } 2423 | return open_files; 2424 | } 2425 | 2426 | /** 2427 | * @warning This function exposes the internals of the stream buffer and 2428 | * should be used with caution. 2429 | * 2430 | * @param in A FILE* that will refer to the process' stdin. 2431 | * @param out A FILE* that will refer to the process' stdout. 2432 | * @param err A FILE* that will refer to the process' stderr. 2433 | * @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr. 2434 | * @see basic_pstreambuf::fopen() 2435 | */ 2436 | template 2437 | inline std::size_t 2438 | pstream_common::fopen(FILE*& fin, FILE*& fout, FILE*& ferr) 2439 | { 2440 | return buf_.fopen(fin, fout, ferr); 2441 | } 2442 | 2443 | #endif // REDI_EVISCERATE_PSTREAMS 2444 | 2445 | 2446 | } // namespace redi 2447 | 2448 | /** 2449 | * @mainpage PStreams Reference 2450 | * @htmlinclude mainpage.html 2451 | */ 2452 | 2453 | #endif // REDI_PSTREAM_H_SEEN 2454 | 2455 | // vim: ts=2 sw=2 expandtab 2456 | -------------------------------------------------------------------------------- /system/bin/powershell: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DerGoogler/powershell/e6ab7a7f532ae4075e16e6fc970b037def29005b/system/bin/powershell --------------------------------------------------------------------------------