// file : tests/test/script/runner/driver.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2019 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include // numeric_limits #include #include // abort() #include #include // endl, *bit #include // istream::traits_type::eof() #include #include #include #include #include #include using namespace std; using namespace butl; // Call itself recursively causing stack overflow. Parameterized to avoid // "stack overflow" warning. // static void stack_overflow (bool overflow) { if (overflow) stack_overflow (true); } int main (int argc, char* argv[]) { using butl::optional; // Usage: driver [-i ] (-o )* (-e )* (-f )* // (-d )* [(-t (a|m|s|z)) | (-s )] // // Execute actions specified by -i, -o, -e, -f, -d options in the order as // they appear on the command line. After that terminate abnormally if -t // option is provided, otherwise exit normally with the status specified by // -s option (0 by default). // // -i // Forward STDIN data to the standard stream denoted by the file // descriptor. Read and discard if 0. // // -o // Print the line to STDOUT. // // -e // Print the line to STDERR. // // -f // Create an empty file with the path specified. // // -d // Create a directory with the path specified. Create parent directories // if required. // // -t // Abnormally terminate itself using one of the following methods: // // a - call abort() // m - dereference null-pointer // s - cause stack overflow using infinite function call recursion // z - divide integer by zero // // -s // Exit normally with the status specified. The default status is 0. // int ifd (3); optional status; char aterm ('\0'); // Abnormal termination method. cin.exceptions (ostream::failbit | ostream::badbit); cout.exceptions (ostream::failbit | ostream::badbit); cerr.exceptions (ostream::failbit | ostream::badbit); for (int i (1); i < argc; ++i) { string o (argv[i++]); assert (i < argc); string v (argv[i]); auto toi = [] (const string& s) -> int { int r (-1); try { size_t n; r = stoi (s, &n); assert (n == s.size ()); } catch (const exception&) { assert (false); } return r; }; if (o == "-i") { assert (ifd == 3); // Make sure is not set yet. ifd = toi (v); assert (ifd >= 0 && ifd < 3); if (ifd == 0) cin.ignore (numeric_limits::max ()); else if (cin.peek () != istream::traits_type::eof ()) { ostream& o (ifd == 1 ? cout : cerr); o << cin.rdbuf (); o.flush (); } } else if (o == "-o") { cout << v << endl; } else if (o == "-e") { cerr << v << endl; } else if (o == "-f") { ofdstream os (v); os.close (); } else if (o == "-d") { try_mkdir_p (dir_path (v)); } else if (o == "-t") { assert (aterm == '\0' && !status); // Make sure exit method is not set. assert (v.size () == 1 && v.find_first_of ("amsz") != string::npos); aterm = v[0]; } else if (o == "-s") { assert (!status && aterm == '\0'); // Make sure exit method is not set. status = toi (v); } else assert (false); } switch (aterm) { case 'a': abort (); break; case 'm': { int* p (nullptr); *p = 0; break; } case 's': stack_overflow (true); break; case 'z': { int z (0); z /= z; break; } } return status ? *status : 0; }