<commit_before>#define DEBUG 1
/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/6/28 20:51:44
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

#if DEBUG == 1
constexpr int D = 5;
#else
constexpr int D = 365;
#endif
constexpr int C = 26;

class Solve
{
  vector<ll> c;
  vector<vector<ll>> s;
  vector<int> t;
  vector<set<int>> contestDays;
  ll totalScore;

public:
  Solve() : c(C), s(D, vector<ll>(C, 0)), t(D), contestDays(C), totalScore{0}
  {
    for (auto i{0}; i < C; ++i)
    {
      cin >> c[i];
    }
    for (auto i{0}; i < D; ++i)
    {
      for (auto j{0}; j < C; ++j)
      {
        cin >> s[i][j];
      }
    }
    for (auto i{0}; i < C; ++i)
    {
      contestDays[i].insert(0);
      contestDays[i].insert(D + 1);
    }
  }

  void flush()
  {
    for (auto i{0}; i < D; ++i)
    {
      cin >> t[i];
      t[i]--;
    }
    calc_score();
    int M;
    cin >> M;
    for (auto i{0}; i < M; ++i)
    {
      int d, q;
      cin >> d >> q;
      --q;
      totalScore = change_score(d, q);
      cout << totalScore << endl;
    }
  }

private:
  ll change_score(int d, int q)
  {
    int p{t[d - 1]};
#if DEBUG == 1
    cerr << "p = " << p << ", q = " << q << endl;
#endif
    if (p == q)
    {
      return totalScore;
    }
    ll newScore{totalScore};
    t[d] = q;
    newScore -= s[d - 1][p];
    newScore += s[d - 1][q];
    {
      auto it{contestDays[p].find(d)};
      --it;
      auto x{*it};
      ++it;
      ++it;
      auto y{*it};
      auto dif{(y - d) * (d - x)};
      newScore += c[p] * dif;
#if DEBUG == 1
      cerr << "x = " << x << ", d = " << d << ", y = " << y << endl;
#endif
    }
    contestDays[p].erase(d);
    contestDays[q].insert(d);
    {
      auto it{contestDays[q].find(d)};
      --it;
      auto x{*it};
      ++it;
      ++it;
      auto y{*it};
      auto dif{(y - d) * (d - x)};
      newScore -= c[q] * dif;
#if DEBUG == 1
      cerr << "x = " << x << ", d = " << d << ", y = " << y << endl;
#endif
    }
    return newScore;
  }

  vector<ll> calc_score()
  {
    vector<ll> ans(D);
    vector<vector<int>> last(D + 1, vector<int>(C, 0));
    ll now{0};
    for (auto d{0}; d < D; ++d)
    {
      now += s[d][t[d]];
      contestDays[t[d]].insert(d + 1);
      last[d + 1] = last[d];
      last[d + 1][t[d]] = d + 1;
      ll penalty{0};
      for (auto i{0}; i < C; ++i)
      {
        penalty += c[i] * (d + 1 - last[d + 1][i]);
      }
      now -= penalty;
      ans[d] = now;
    }
    totalScore = now;
    return ans;
  }
};

// ----- main() -----

int main()
{
  ll d;
  cin >> d;
  Solve solve;
  solve.flush();
}
<commit_msg>tried C.cpp to 'C'<commit_after>#define DEBUG 1
/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/6/28 20:51:44
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

#if DEBUG == 1
constexpr int D = 5;
#else
constexpr int D = 365;
#endif
constexpr int C = 26;

class Solve
{
  vector<ll> c;
  vector<vector<ll>> s;
  vector<int> t;
  vector<set<int>> contestDays;
  ll totalScore;

public:
  Solve() : c(C), s(D, vector<ll>(C, 0)), t(D), contestDays(C), totalScore{0}
  {
    for (auto i{0}; i < C; ++i)
    {
      cin >> c[i];
    }
    for (auto i{0}; i < D; ++i)
    {
      for (auto j{0}; j < C; ++j)
      {
        cin >> s[i][j];
      }
    }
    for (auto i{0}; i < C; ++i)
    {
      contestDays[i].insert(0);
      contestDays[i].insert(D + 1);
    }
  }

  void flush()
  {
    for (auto i{0}; i < D; ++i)
    {
      cin >> t[i];
      t[i]--;
    }
    calc_score();
    int M;
    cin >> M;
    for (auto i{0}; i < M; ++i)
    {
      int d, q;
      cin >> d >> q;
      --q;
      totalScore = change_score(d, q);
      cout << totalScore << endl;
    }
  }

private:
  ll change_score(int d, int q)
  {
    int p{t[d - 1]};
#if DEBUG == 1
    cerr << "p = " << p << ", q = " << q << endl;
#endif
    if (p == q)
    {
      return totalScore;
    }
    ll newScore{totalScore};
    t[d] = q;
    newScore -= s[d - 1][p];
    newScore += s[d - 1][q];
#if DEBUG == 1
    cerr << "newScore = " << newScore << endl;
#endif
    {
      auto it{contestDays[p].find(d)};
      --it;
      auto x{*it};
      ++it;
      ++it;
      auto y{*it};
      auto dif{(y - d) * (d - x)};
      newScore += c[p] * dif;
#if DEBUG == 1
      cerr << "x = " << x << ", d = " << d << ", y = " << y << endl;
#endif
    }
    contestDays[p].erase(d);
    contestDays[q].insert(d);
    {
      auto it{contestDays[q].find(d)};
      --it;
      auto x{*it};
      ++it;
      ++it;
      auto y{*it};
      auto dif{(y - d) * (d - x)};
      newScore -= c[q] * dif;
#if DEBUG == 1
      cerr << "x = " << x << ", d = " << d << ", y = " << y << endl;
#endif
    }
    return newScore;
  }

  vector<ll> calc_score()
  {
    vector<ll> ans(D);
    vector<vector<int>> last(D + 1, vector<int>(C, 0));
    ll now{0};
    for (auto d{0}; d < D; ++d)
    {
      now += s[d][t[d]];
      contestDays[t[d]].insert(d + 1);
      last[d + 1] = last[d];
      last[d + 1][t[d]] = d + 1;
      ll penalty{0};
      for (auto i{0}; i < C; ++i)
      {
        penalty += c[i] * (d + 1 - last[d + 1][i]);
      }
      now -= penalty;
      ans[d] = now;
    }
    totalScore = now;
    return ans;
  }
};

// ----- main() -----

int main()
{
  ll d;
  cin >> d;
  Solve solve;
  solve.flush();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <vector>
#include "comParse.h"
#include <cstring>
#include <unistd.h>

using namespace boost;
using namespace std;

int main() {
	while (true) {
		char** argv = NULL;
		vector<char*> commands;
		comParse comPr;
		do {
			cerr << "$ " << flush;

			string input = "";
			getline(cin, input);	// Get command

			commands = comPr.parseLine(input);
		} while (commands.size() == 1); // if empty line, repeat req for command. sz 1 = just NULL delim.

		argv = &commands[0];

		for (unsigned int i = 0; i < commands.size() - 1; i++) { // NULL at end
			if ( strcmp(commands.at(i), ";") == 0 ) {
				argv[i] = NULL;
				break;
			}
		}

		/* Confusing as heck, let me explain!
		 * char const* means pointer to a constant char
		 * so char const* const means a const pointer to a const char
		 * and char const* const* means a const pointer to a const char pointer!
		 * (Read declarations from right to left to make it make sense -
		 *  char const* = POINTER (*) to a CONST CHAR)
		 */
		//char const* const* c_arr = &commands[0]; // even if Not necessary: keep as really cool discovery!

		char ex[5] = "exit";
		if (strcmp(argv[0], ex) == 0) {
			comPr.deleteCStrings(commands); // Has heap allocated memory, always should be dealt with
			return 0; // EXIT command
		}

		int pid = fork();
		if (pid == -1) {	// Error in fork
			perror("error in fork");
			comPr.deleteCStrings(commands);
			exit(-1);
		} else if (pid == 0) {	// Child Process
			if (-1 == execvp(argv[0], argv)) {
				perror("error in execvp");
				exit(-1);
			}
		} else if (pid > 0) { // parent!
			if (-1 == wait(0))
				perror("wait");
		}

		comPr.deleteCStrings(commands);
	}

	return 0;
}

<commit_msg>added appropriate flags for errors. Discovered issue with ENOENT, where exit doesn't immediately work afterwards for a few times.<commit_after>#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <vector>
#include "comParse.h"
#include <cstring>
#include <unistd.h>

using namespace boost;
using namespace std;

int main() {
	while (true) {
		char** argv = NULL;
		vector<char*> commands;
		comParse comPr;
		do {
			cerr << "$ " << flush;

			string input = "";
			getline(cin, input);	// Get command

			commands = comPr.parseLine(input);
		} while (commands.size() == 1); // if empty line, repeat req for command. sz 1 = just NULL delim.

		argv = &commands[0];

		for (unsigned int i = 0; i < commands.size() - 1; i++) { // NULL at end
			if ( strcmp(commands.at(i), ";") == 0 ) {
				argv[i] = NULL;
				break;
			}
		}

		/* Confusing as heck, let me explain!
		 * char const* means pointer to a constant char
		 * so char const* const means a const pointer to a const char
		 * and char const* const* means a const pointer to a const char pointer!
		 * (Read declarations from right to left to make it make sense -
		 *  char const* = POINTER (*) to a CONST CHAR)
		 */
		//char const* const* c_arr = &commands[0]; // even if Not necessary: keep as really cool discovery!

		char ex[5] = "exit";
		if (strcmp(argv[0], ex) == 0) {
			comPr.deleteCStrings(commands); // Has heap allocated memory, always should be dealt with
			return 0; // EXIT command
		}

		int pid = fork();
		if (pid == -1) {	// Error in fork
			perror("error in fork");
			comPr.deleteCStrings(commands);
			exit(-1);
		} else if (pid == 0) {	// Child Process
			if (-1 == execvp(argv[0], argv)) {
				if (errno == EACCES) { // Access denied
					perror(argv[0]);
				} else if (errno == ENOEXEC) { // Not Exec
					perror(argv[0]);
				} else if (errno == ENOENT) { // Does not exist
					perror(argv[0])
				} else {
					perror("error in execvp");
					exit(-1);
				}
			}
		} else if (pid > 0) { // parent!
			if (-1 == wait(0))
				perror("wait");
			if (errno != 0 && errno != EACCES && errno != ENOEXEC && errno != ENOENT)
				exit(-1);
		}

		comPr.deleteCStrings(commands);
	}

	return 0;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int syntaxCheck(vector<string>&vect);
bool isConnector(string&);
bool isSymbol(string&);
bool isSemiColon(string &s);
bool validSymbol(string&);
void executor(vector<string> &vect);
void commandParser(vector<string> &v, string str);

typedef tokenizer<char_separator<char> > toknizer;
int main()
{
	while(1)
	{
		//prints simple prompt, gets user input
		cout << "$ ";
		string userinput;
		getline(cin,userinput);

		//declares tokenizer and storage for tokens
		string cmd=""; //gathers entire command until connector or end
		string sym=""; //will hold collected symbol ('||' vs '|')
		vector<string> cmdvect;

		char_separator<char> delim("","<&|#;>");
		toknizer parser(userinput,delim);

		for(toknizer::iterator it=parser.begin();it!=parser.end();++it)
		{
			if(*it=="#") { break; } //finish reading input if comment
			if(*it=="&" || *it=="|" || *it==";" ) //doesn't check validity/meaning of symbol yet
			{
				if(!cmd.empty()) //if there is currently a command recorded, push it onto vector, start reading in symbol
				{
					cmdvect.push_back(cmd);
					cmd.clear();
					sym+=(*it);
				}
				else if(cmd.empty() ||  !sym.empty())
				{
					sym+=(*it);
				}
			}
			//if none of cases above apply, can be assumed to be command
			else
			{
				if(!sym.empty())
				{
					cmdvect.push_back(sym);
					cmd+=(*it);
					sym.clear();
					//"empties" connector and resumes building command
				}
				else //otherwise, just keep building command
				{
					cmd+=(*it);
					string temp=*it;
					if(!isSymbol(temp)) //to avoid spaces in ">>"
					{ cmd+=" "; }//spaces out commands like "ls -a"
				}
			}

		} //end tokenizer loop

		if(!cmd.empty())
		{
			cmdvect.push_back(cmd); //adds last of input
		}
		if(!sym.empty())
		{
			cmdvect.push_back(sym);//and trailing connectors
		}
		for(unsigned n=0;n<cmdvect.size();++n)
		{
			cout << n << ": " << cmdvect.at(n) << endl;
		}
		int x=syntaxCheck(cmdvect);
		if(x==0)
		{
			cout << "All valid!\n";
			//executor(cmdvect);
		}
	}
	//end of while loop

	return 0;
} //end of main

void executor(vector<string> &vect)
{
	bool success=false;

	for(unsigned i=0;i<vect.size();++i)
	{
		if(vect.at(i)=="exit")
		{
			cout << "is exit" << endl;
		}
		//checks if current string is connector
		else if(isConnector(vect.at(i)))
		{
			if(vect.at(i)=="&&")
			{
				if(success==false || i==0 )
				{
					return;
				}
				else	{  continue;	}
			}
			if(vect.at(i)=="||")
			{
				if(success==false && i!=0)
				{
					continue;
				}
				else if(success==true || i==0  )	{ return; }
			}
			if(vect.at(i)==";" && i!=0)
			{
				continue;
			}
		}
		else
		{

		}
		//otherwise can be assumed to be a command

		//parse vect.at(i) into smaller vector
		vector<string>argvect;
		commandParser(argvect,vect.at(i));

		//store vector size for array allocation
		const size_t sz=argvect.size();
		char**argv=new char*[sz+1]; //REMEMBER- delete at end

		for(unsigned j=0;j<sz+1;++j)
		{
			if(j<sz)//using strdup since it dynamically allocates on its own
			{
				argv[j]=strdup(argvect.at(j).c_str());
			}
			else if(j==sz) //adds null at end
			{
				argv[j]=NULL;
			}
		}

		//fork and attempt to execute using execvp
		pid_t pid=fork();
		if(pid==-1) //error with fork
		{
			perror("fork");
		}
		else if(pid==0) //child
		{

			if(execvp(argv[0],argv)==-1)
			{
				success=false;  //redundant maybe?
				perror("execvp");
				exit(1);
			}

			_exit(0);
		}
		else //parent
		{
			if(wait(0)==-1)
			{
				perror("wait");
				exit(1);
			}
			success=true;
		}

		//deallocates argv as well as strdup's dynamic memory
		for(unsigned i=0;i<sz+1;++i)
		{
			delete [] argv[i];
		}
		delete [] argv;
	}
	return;
}

void commandParser(vector<string> &v, string str)
{
	char_separator<char> delim(" ");
	toknizer parser(str,delim);
	for(toknizer::iterator it=parser.begin();it!=parser.end();++it)
	{
		if(*it=="exit")
		{
			exit(0);
		}
		v.push_back(*it);
	}

	return;
}

int syntaxCheck(vector<string> &vect)
{
	//checks input for invalid syntax in connectors
	for(unsigned i=0; i<vect.size();++i)
	{
		//after initial parsing, vector passed in should always have
		//commands in even indices, and any symbols in odd indices.
		if(i%2==0) //if even index...
		{
			if(isSymbol(vect.at(i))) //...and is a symbol...
			{
				cerr << "Syntax error: missing argument.\n";
				return -1;  //...argument must be missing
			}
			else { continue; } //if not a symbol, assume to be intended command
		}
		else if(i%2!=0 ) //if odd index
		{

			if(!validSymbol(vect.at(i))) //and symbol is not valid
			{
				cerr << "Syntax error: invalid operator.\n";
				return -1; //will return an error
			}
			else if(isSymbol(vect.at(i)) && i+1==vect.size())
			{
				//if symbol but last one, argument is missing
				cerr << "Syntax error: missing argument.\n";
				return -1;
			}
			else //if valid, just continue checking
			{
				continue;
			}
		}

	}
	return 0; //no syntax errors found
}

bool isSemiColon(string &s) //literally only to allow ";" as a valid command ending.
{
	size_t sc=s.find(";");
	if(sc==string::npos) { return false;}
	return true;
}

bool isConnector(string &s)
{
	//function just checks if token is supposed to be a connector
	size_t i=s.find("&");
	size_t j=s.find("|");
	size_t k=s.find(";");

	if(i==string::npos && j==string::npos && k==string::npos)
	{
		return false;
	}
	return true;
}

bool isSymbol(string &s)
{
	size_t a=s.find(">");
	size_t b=s.find("<");
	size_t noSym = string::npos; //"no such symbol"
	//if no symbols are found in the string
	if(a==noSym && b==noSym)
	{
		return false; //assume it's not an attempt at connector/redirection symbol
	}
	return true;
}

bool validSymbol(string &str)
{
	//only supports few connectors now
	if(str=="&&") { return true; }
	else if(str=="||") { return true;}
	else if(str==";") { return true;}
	else if(str=="|") { return true;}
	else if(str=="<") { return true;}
	else if(str==">") { return true;}
	else if(str==">>") {return true;}
	//else if(str=="<<<") {return true;} //if time allows
	return false;
}
<commit_msg>Fixed strdup bug, replaced delete with free<commit_after>#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int cmdSyntaxCheck(string &s);
int syntaxCheck(vector<string>&vect);
bool isConnector(string&);
bool isSymbol(string&);
bool isSemiColon(string &s);
bool validSymbol(string&);
void executor(vector<string> &vect);
void commandParser(vector<string> &v, string str);

typedef tokenizer<char_separator<char> > toknizer;
int main()
{
	while(1)
	{
		//prints simple prompt, gets user input
		cout << "$ ";
		string userinput;
		getline(cin,userinput);

		//declares tokenizer and storage for tokens
		string cmd=""; //gathers entire command until connector or end
		string sym=""; //will hold collected symbol ('||' vs '|')
		vector<string> cmdvect;

		char_separator<char> delim("","<&|#;>");
		toknizer parser(userinput,delim);

		for(toknizer::iterator it=parser.begin();it!=parser.end();++it)
		{
			if(*it=="#") { break; } //finish reading input if comment
			if(*it=="&" || *it=="|" || *it==";" ) //doesn't check validity/meaning of symbol yet
			{
				if(!cmd.empty()) //if there is currently a command recorded, push it onto vector, start reading in symbol
				{
					cmdvect.push_back(cmd);
					cmd.clear();
					sym+=(*it);
				}
				else if(cmd.empty() ||  !sym.empty())
				{
					sym+=(*it);
				}
			}
			//if none of cases above apply, can be assumed to be command
			else
			{
				if(!sym.empty())
				{
					cmdvect.push_back(sym);
					cmd+=(*it);
					sym.clear();
					//"empties" connector and resumes building command
				}
				else //otherwise, just keep building command
				{
					cmd+=(*it);
					string temp=*it;
					if(!isSymbol(temp)) //to avoid spaces in ">>"
					{ cmd+=" "; }//spaces out commands like "ls -a"
				}
			}

		} //end tokenizer loop

		if(!cmd.empty())
		{
			cmdvect.push_back(cmd); //adds last of input
		}
		if(!sym.empty())
		{
			cmdvect.push_back(sym);//and trailing connectors
		}
		for(unsigned n=0;n<cmdvect.size();++n)
		{
			cout << n << ": " << cmdvect.at(n) << endl;
		}
		int x=syntaxCheck(cmdvect);
		if(x==0)
		{
			executor(cmdvect);
		}
	}
	//end of while loop

	return 0;
} //end of main

void executor(vector<string> &vect)
{
	bool success=false;

	for(unsigned i=0;i<vect.size();++i)
	{
		if(vect.at(i)=="exit")
		{
			cout << "is exit" << endl;
		}
		//checks if current string is connector
		else if(isConnector(vect.at(i)))
		{
			if(vect.at(i)=="&&")
			{
				if(success==false || i==0 )
				{
					return;
				}
				else	{  continue;	}
			}
			if(vect.at(i)=="||")
			{
				if(success==false && i!=0)
				{
					continue;
				}
				else if(success==true || i==0  )	{ return; }
			}
			if(vect.at(i)==";" && i!=0)
			{
				continue;
			}
		}
		else
		{

		}
		//otherwise can be assumed to be a command

		//parse vect.at(i) into smaller vector
		vector<string>argvect;
		commandParser(argvect,vect.at(i));

		//store vector size for array allocation
		const size_t sz=argvect.size();
		char**argv=new char*[sz+1]; //REMEMBER- delete at end

		for(unsigned j=0;j<sz+1;++j)
		{
			if(j<sz)//using strdup since it dynamically allocates on its own
			{
				argv[j]=strdup(argvect.at(j).c_str());
			}
			else if(j==sz) //adds null at end
			{
				argv[j]=NULL;
			}
		}

		//fork and attempt to execute using execvp
		pid_t pid=fork();
		if(pid==-1) //error with fork
		{
			perror("fork");
		}
		else if(pid==0) //child
		{

			if(execvp(argv[0],argv)==-1)
			{
				success=false;  //redundant maybe?
				perror("execvp");
				exit(1);
			}

			_exit(0);
		}
		else //parent
		{
			if(wait(0)==-1)
			{
				perror("wait");
				exit(1);
			}
			success=true;
		}

		//deallocates argv as well as strdup's dynamic memory
		for(unsigned i=0;i<sz+1;++i)
		{
			free(argv[i]);
		}
		delete [] argv;
	}
	return;
}

void commandParser(vector<string> &v, string str)
{
	char_separator<char> delim(" ");
	toknizer parser(str,delim);
	for(toknizer::iterator it=parser.begin();it!=parser.end();++it)
	{
		if(*it=="exit")
		{
			exit(0);
		}
		v.push_back(*it);
	}

	return;
}

int syntaxCheck(vector<string> &vect)
{
	//checks input for invalid syntax in connectors
	for(unsigned i=0; i<vect.size();++i)
	{
		//after initial parsing, vector passed in should always have
		//commands in even indices, and any symbols in odd indices.
		if(i%2==0) //if even index...
		{
			if(isConnector(vect.at(i))) //...and is a symbol...
			{
				cerr << "Syntax error: missing argument.\n";
				return -1;  //...argument must be missing
			}
			else if(isSymbol(vect.at(i))) //if io redirection symbol present
			{
				if(-1==(cmdSyntaxCheck(vect.at(i)))) //check it too
				{ return -1; }
				else { continue;}
			}
			else { continue; } //if "vanilla" command, just carry on
		}
		else if(i%2!=0 ) //if odd index
		{

			if(!validSymbol(vect.at(i))) //and symbol is not valid
			{
				cerr << "Syntax error: invalid operator.\n";
				return -1; //will return an error
			}
			else if(isSymbol(vect.at(i)) && i+1==vect.size())
			{
				//if symbol but last one, argument is missing
				cerr << "Syntax error: missing argument.\n";
				return -1;
			}
			else //if valid, just continue checking
			{
				continue;
			}
		}

	}
	return 0; //no syntax errors found
}

int cmdSyntaxCheck(string &s)
{
	vector<string> strv;
	commandParser(strv, s);
	for(unsigned i=0;i<strv.size();++i)
	{
		if(i%2==0) //similar to SyntaxCheck, but smaller scale
		{
			if(isSymbol(strv.at(i)))
			{ cerr << "Error: missing argument.\n"; return -1; }
		}
		else if(i%2!=0)
		{
			if(!validSymbol(strv.at(i)))
			{ cerr << "Error: not a valid operator.\n"; return -1; }
			if(isSymbol(strv.at(i)) && i+i==strv.size())
			{ cerr << "Error: missing argument.\n"; return -1;}
		}
	}

	return 0;
}

bool isSemiColon(string &s) //literally only to allow ";" as a valid command ending.
{
	size_t sc=s.find(";");
	if(sc==string::npos) { return false;}
	return true;
}

bool isConnector(string &s)
{
	//function just checks if token is supposed to be a connector
	size_t i=s.find("&");
	size_t j=s.find("|");
	size_t k=s.find(";");

	if(i==string::npos && j==string::npos && k==string::npos)
	{
		return false;
	}
	return true;
}

bool isSymbol(string &s)
{
	size_t a=s.find(">");
	size_t b=s.find("<");
	size_t noSym = string::npos; //"no such symbol"
	//if no symbols are found in the string
	if(a==noSym && b==noSym)
	{
		return false; //assume it's not an attempt at redirection symbol
	}
	return true;
}

bool validSymbol(string &str)
{
	if(str=="&&") { return true; }
	else if(str=="||") { return true;}
	else if(str==";") { return true;}
	else if(str=="|") { return true;}
	else if(str=="<") { return true;}
	else if(str==">") { return true;}
	else if(str==">>") {return true;}
	//else if(str=="<<<") {return true;} //if time allows
	return false;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <vector>
#include <stdlib.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>

using namespace std;

void parsePath(char * line, vector<string> &pathing) {

    if (line == NULL)
        return;

    char * pch;
    pch = strtok(line, ":");
    while (pch!=NULL) {
        string tmp = pch;
        pathing.push_back(tmp);
        pch = strtok(NULL, ":");
    }
}

void parse(char * line, vector<string> & input) {

    if (line == NULL)
        return;

    char * pch;
    int find_quote = 0;
	pch = strtok (line, " \n");
	while (pch!= NULL) {

        if (pch == NULL)
                break;

        find_quote = 0;
        if ((pch + strlen(pch) + 1) == NULL)
                cerr << "hello\n";
        if (((pch +strlen(pch) +1) != NULL) && (*(pch + strlen(pch) + 1) == '"'))
            find_quote = 1;

	    // Ignore after comments
	    if (*pch == '#')
		break;

	    // Check for && and ||
	    // Break input up
	    char * a = strstr(pch, "&&");
	    char * b = strstr(pch, "||");
	    char * c = strstr(pch, ";");
        char * d = strstr(pch, "<");
        char * e = strstr(pch, ">");
        char * f = strstr(pch, "|");

	    // If there are connectors, break up the string
	    // into parts and add them individually to the vector
	    if (a!=NULL || b!=NULL || c!=NULL || d!=NULL || e!=NULL || f!=NULL
                    || (isdigit(*pch) && pch[1] == '>')) {
		while (strlen(pch) != 0 ) {
            if (isdigit(pch[0]) && pch[1] == '>') {
                string tmp;
                int stringlen = 0;
                tmp += *pch;
                tmp += pch[1];
                if (pch[1] == '>' && pch[2] == '>') {
                    tmp += pch[2];
                    stringlen = 3;
                    tmp[3] = '\0';
                    }
                else {
                    stringlen = 2;
                    tmp[2] = '\0';
                }
                input.push_back(tmp);
                memmove(pch, pch +stringlen, strlen(pch) - stringlen);
                pch[strlen(pch) - stringlen] = '\0';

            }

            // Checks for && and ||
            if ((pch[0] == '&' && pch[1] == '&') ||
			(pch[0] == '|' && pch[1] == '|')) {

			    string tmp;
			    tmp += *pch;
			    tmp += *(pch+1);
			    tmp[2] = '\0';

			    input.push_back(tmp);
			    memmove(pch, pch+2, strlen(pch) - 2);
			    pch[strlen(pch)-2] = '\0';
		    }
		    // Check for semicolons
		    else if (*pch == ';') {
			    input.push_back(";");
			    memmove(pch, pch+1, strlen(pch) -1);
			    pch[strlen(pch)-1] = '\0';
		    }
            // Check for input/output redirectors
            else if (*pch == '<' || *pch =='>' || *pch == '|') {
                if (*pch == '>' && *(pch+1) == '>') {
                    input.push_back(">>");
                    memmove(pch, pch+2, strlen(pch)-2);
                    pch[strlen(pch)-2] = '\0';
                }
                else if (*pch == '<' && *(pch+1) == '<' && *(pch+2)=='<') {
                    input.push_back("<<<");
                    memmove(pch, pch+3, strlen(pch)-3);
                    pch[strlen(pch)-3] = '\0';
                }
                else {
                    string tmp;
                    tmp += *pch;
                    tmp[1] = '\0';
                    input.push_back(tmp);
                    memmove(pch, pch+1, strlen(pch)-1);
                    pch[strlen(pch)-1] = '\0';
                }
            }

            else {
			string word;
			int numletters = 0;
			char z = *pch;
			int i = 1;
            while ( z!= '\0' && z!= ';' && z!= '|' && z!= '&' && z!= '<' && z!= '>'
                            && !(isdigit(z) && pch[i] == '>')) {
			    word += z;
			    numletters++;
			    z = pch[i];
                i++;
			}
            if (numletters!=0)
			    input.push_back(word);
			memmove(pch, pch+numletters, strlen(pch) -numletters);
			pch[strlen(pch)-numletters] = '\0';
		    }

		    a = strstr(pch, "&&");
		    b = strstr(pch, "||");
		    c = strstr(pch, ";");
            d = strstr(pch, "<");
            e = strstr(pch, ">");
            f = strstr(pch, "|");
		}
	    }

	    // If no connectors, just add to vector
	    if (*pch != '\0' && *pch != '\n' && *pch != '#') {
            input.push_back(pch);

        }

        if (find_quote == 1)
            pch = strtok(NULL, "\"");
        else
	        pch = strtok (NULL, " \n");
	}
}

void execute(const vector<string> & input, const vector<string> & pathing,
        int start, int end) {

    //Call execvp, based on which elements in the string vector to use
    char * argv[20];

	    int i = 0;
	    int status;

	    for (i = 0; i <= (end - start); i++) {
		argv[i] = new char[20];
	    }

	    for (i = 0; i < (end-start); i++) {
		strcpy(argv[i], input[i+start].c_str());
            }

	    argv[i] = NULL;
            string cmd = argv[0];

            for (unsigned int j = 0; j < pathing.size(); j++) {
                string tmp = pathing[j] + "/" + cmd;
                strcpy(argv[0], tmp.c_str());
                status = execv(argv[0], argv);

            }
	    if (status == -1)
		perror("execv");
		exit(1);
}

void printusrhost() {

    // Get username
    char * usrname;
    struct passwd *pass = getpwuid(getuid());
    usrname = pass->pw_name;
    if (pass == NULL) {
	perror ("getpwuid");
    exit(1);
    }

    // Get hostname
    char hostname[20];

    if (gethostname(hostname, sizeof hostname) ==-1) {
	perror("gethostname");
	exit(1);
    }
    cout << usrname << "@" << hostname <<"$ ";

}

void int_handler(int x) {
        cout << endl;
}

int main() {

    if ((signal(SIGINT, int_handler)) == SIG_ERR)
        perror("signal");

    vector<string> input;
    vector<string> pathing;
    int status=0;
    char *pPath;

    pPath = getenv("PATH");
	if (pPath == NULL)
	    perror("PATH");
    parsePath(pPath, pathing);

    int savestdin;
    if ((savestdin = dup(0)) == -1)
        perror("dup");

    int savestdout;
    if ((savestdout = dup(1)) == -1)
        perror("dup");

    // Main loop
    while (1) {
        //Restore stdin and stdout
        if ((dup2(savestdin,0)) == -1)
            perror("dup2");

        if ((dup2(savestdout,0)) == -1)
            perror("dup2");

    printusrhost();

	status = 0;

	if (input.size() != 0)
	    input.clear();

	string string1;
	getline(cin, string1);

	parse((char *)string1.c_str(), input);

    //debugging
    //cerr << "AFTER PARSING: \n";
    //for (int i = 0; i < input.size(); i++)
            //cerr << input[i] << endl;

	if (input.size() == 0)
	    continue;

    for (unsigned int i = 0; i < input.size(); i++)
	    if (strcmp(input[i].c_str(), "exit") == 0) exit(0);

	int pid=fork();
    if (pid == -1)
        perror ("fork");
	int pid2;
	if (pid == 0) {
	    int start = 0;
	    int end = input.size();
	    unsigned i;

loop:
        end = input.size();

        for (i = start; i < input.size(); ) {

            if (input[i] == "cd") {
                string directory =  input[i+1];
                int ret;
                ret = chdir(directory.c_str());
                if (ret == -1)
                    perror ("chdir");

                if ((i+2) >= input.size())
                    exit(0);
                else if (input[i+2] == ";" || input[i+2] == "&&") {
                    start = i+3;
                    goto loop;
                }

            }

            //input output redirection
            if (input[i] == ">" || input[i] == ">>" || input[i]=="<"
                            || input[i] == "<<<" || input[i] == "|"
                            || (isdigit(input[i][0]) && input[i][1] == '>')) {

                if ((isdigit(input[i][0]) && input[i][1] == '>') || input[i][0] == '>') {

                    int flags = 0;
                    int file_no = 1;
                    flags |= O_CREAT | O_WRONLY;

                    if ((input[i][0] == '>' && input[i][1] == '>') ||
                                input[i][2] == '>')
                            flags |= O_APPEND;
                        else
                            flags |= O_TRUNC;

                    int fdo = open(input[i+1].c_str(), flags, S_IRUSR | S_IWUSR);
                    if (fdo==-1) {
                        perror("open");
                        exit(1);
                    }

                    if (isdigit(input[i][0]))
                        file_no = input[i][0] - '0';

                    status = close(file_no);
                    if (status == -1)
                        perror("close");

                    if ((dup(fdo)) == -1)
                        perror("dup");

                    if ((close(fdo)) == -1)
                        perror("close");

                    input.erase(input.begin() + i);
                    input.erase(input.begin() + i);

                    if (input[i][0] == '>' || input[i][0] == '<' || input[i][0] == '|'
                                            || (isdigit(input[i][0]) && input[i][1] == '>'))
                        continue;

                    else {
                        end = i;
                        break;
                    }

                }

                else if (input[i] == "<") {

                        int fdi = open(input[i+1].c_str(), O_RDONLY, 0);
                        if (fdi==-1) {
                            perror("open");
                            exit(1);
                        }

                        status = close(STDIN_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdi)) == -1)
                            perror("dup");

                        if ((close(fdi)) == -1)
                            perror("close");

                        input.erase(input.begin() + i);
                        input.erase(input.begin() + i);

                        if (input[i][0] == '>' || input[i][0] == '<' || input[i][0] == '|'
                                            || (isdigit(input[i][0]) && input[i][1] == '>'))
                            continue;

                        else {
                            end = i;
                            break;
                        }
                }

                else if (input[i] == "<<<") {

                    int pfd[2];

                    if ((pipe(pfd)) == -1)
                        perror("pipe");

                        char buf[128];
                        memset(buf, 0, 128);
                        strcpy(buf, input[i+1].c_str());

                        buf[strlen(buf)] = '\n';
                        buf[strlen(buf)+1] = '\0';

                        if ((write(pfd[1], buf, strlen(buf)) == -1))
                            perror("write");

                        if ((dup2(pfd[0], 0)) == -1)
                            perror("dup2");

                        if (close (pfd[1]) == -1)
                            perror("close");

                        input.erase(input.begin() + i);
                        input.erase(input.begin() + i);

                        if (input[i][0] == '>' || input[i][0] == '<' || input[i][0] == '|'
                                            || (isdigit(input[i][0]) && input[i][1] == '>'))
                            continue;

                        else {
                            end = i;
                            break;
                        }

                }
                else if (input[i] == "|") {
                    int pfd[2];

                    if ((pipe(pfd)) == -1)
                        perror("pipe");

                    int pid3 = fork();
                    if (pid3 == -1) {
                        perror("fork");
                        exit(1);
                    }
                    if (pid3==0) {

                        if ((dup2(pfd[1], 1)) == -1)
                            perror("dup2");

                        if ((close(pfd[0])) == -1)
                            perror("close");

                        end = i;
                        break;

                    }
                    else {
                        if((close(STDIN_FILENO)) == -1)
                            perror("close");

                        if ((dup2(pfd[0], 0)) == -1)
                            perror("dup2");

                        if ((close(pfd[1])) == -1)
                            perror("close");

                        if (-1 == wait(0))
                            perror("wait");

                        start = i+1;
                        goto loop;

                    }

                }
            }

            else if (input[i] == ";" || input[i] == "&&" || input[i] == "||") {

                string connector = input[i];

		        pid2 = fork();
		        if (pid2 == -1) {
			        perror("fork");
			        exit(1);
		        }
		        if (pid2!=0) {
			        if (-1 == wait(&status))
			            perror("wait");

			        if (connector == "&&" && status != 0)
			            exit(1);

			        if (connector == "||" && status == 0)
			            exit(0);

			        start = i + 1;
			        goto loop;

		        }
		        else {
			        end = i;
			        break;
		        }
		    }
	    i++;
        }

	    execute(input, pathing, start, end);

	}
	else {
	    status = wait(NULL);
	    if (status == -1)
		perror("wait");

            //chdir command
        for (int i = 0; i < input.size(); i++) {
            if (strcmp(input[i].c_str(), "cd") == 0) {
                string directory =  input[i+1];
                int ret;
                ret = chdir(directory.c_str());
                if (ret == -1)
                    perror ("chdir");

            }
        }
    }
    }

    exit(0);
}
<commit_msg>updated rshell<commit_after>#include <iostream>
#include <unistd.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <vector>
#include <stdlib.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>

using namespace std;

void parsePath(char * line, vector<string> &pathing) {

    if (line == NULL)
        return;

    char * pch;
    pch = strtok(line, ":");
    while (pch!=NULL) {
        string tmp = pch;
        pathing.push_back(tmp);
        pch = strtok(NULL, ":");
    }
}

void parse(char * line, vector<string> & input) {

    if (line == NULL)
        return;

    char * pch;
    int find_quote = 0;
	pch = strtok (line, " \n");
	while (pch!= NULL) {

        if (pch == NULL)
                break;

        find_quote = 0;
        if ((pch + strlen(pch) + 1) == NULL)
                cerr << "hello\n";
        if (((pch +strlen(pch) +1) != NULL) && (*(pch + strlen(pch) + 1) == '"'))
            find_quote = 1;

	    // Ignore after comments
	    if (*pch == '#')
		break;

	    // Check for && and ||
	    // Break input up
	    char * a = strstr(pch, "&&");
	    char * b = strstr(pch, "||");
	    char * c = strstr(pch, ";");
        char * d = strstr(pch, "<");
        char * e = strstr(pch, ">");
        char * f = strstr(pch, "|");

	    // If there are connectors, break up the string
	    // into parts and add them individually to the vector
	    if (a!=NULL || b!=NULL || c!=NULL || d!=NULL || e!=NULL || f!=NULL
                    || (isdigit(*pch) && pch[1] == '>')) {
		while (strlen(pch) != 0 ) {
            if (isdigit(pch[0]) && pch[1] == '>') {
                string tmp;
                int stringlen = 0;
                tmp += *pch;
                tmp += pch[1];
                if (pch[1] == '>' && pch[2] == '>') {
                    tmp += pch[2];
                    stringlen = 3;
                    tmp[3] = '\0';
                    }
                else {
                    stringlen = 2;
                    tmp[2] = '\0';
                }
                input.push_back(tmp);
                memmove(pch, pch +stringlen, strlen(pch) - stringlen);
                pch[strlen(pch) - stringlen] = '\0';

            }

            // Checks for && and ||
            if ((pch[0] == '&' && pch[1] == '&') ||
			(pch[0] == '|' && pch[1] == '|')) {

			    string tmp;
			    tmp += *pch;
			    tmp += *(pch+1);
			    tmp[2] = '\0';

			    input.push_back(tmp);
			    memmove(pch, pch+2, strlen(pch) - 2);
			    pch[strlen(pch)-2] = '\0';
		    }
		    // Check for semicolons
		    else if (*pch == ';') {
			    input.push_back(";");
			    memmove(pch, pch+1, strlen(pch) -1);
			    pch[strlen(pch)-1] = '\0';
		    }
            // Check for input/output redirectors
            else if (*pch == '<' || *pch =='>' || *pch == '|') {
                if (*pch == '>' && *(pch+1) == '>') {
                    input.push_back(">>");
                    memmove(pch, pch+2, strlen(pch)-2);
                    pch[strlen(pch)-2] = '\0';
                }
                else if (*pch == '<' && *(pch+1) == '<' && *(pch+2)=='<') {
                    input.push_back("<<<");
                    memmove(pch, pch+3, strlen(pch)-3);
                    pch[strlen(pch)-3] = '\0';
                }
                else {
                    string tmp;
                    tmp += *pch;
                    tmp[1] = '\0';
                    input.push_back(tmp);
                    memmove(pch, pch+1, strlen(pch)-1);
                    pch[strlen(pch)-1] = '\0';
                }
            }

            else {
			string word;
			int numletters = 0;
			char z = *pch;
			int i = 1;
            while ( z!= '\0' && z!= ';' && z!= '|' && z!= '&' && z!= '<' && z!= '>'
                            && !(isdigit(z) && pch[i] == '>')) {
			    word += z;
			    numletters++;
			    z = pch[i];
                i++;
			}
            if (numletters!=0)
			    input.push_back(word);
			memmove(pch, pch+numletters, strlen(pch) -numletters);
			pch[strlen(pch)-numletters] = '\0';
		    }

		    a = strstr(pch, "&&");
		    b = strstr(pch, "||");
		    c = strstr(pch, ";");
            d = strstr(pch, "<");
            e = strstr(pch, ">");
            f = strstr(pch, "|");
		}
	    }

	    // If no connectors, just add to vector
	    if (*pch != '\0' && *pch != '\n' && *pch != '#') {
            input.push_back(pch);

        }

        if (find_quote == 1)
            pch = strtok(NULL, "\"");
        else
	        pch = strtok (NULL, " \n");
	}
}

void execute(const vector<string> & input, const vector<string> & pathing,
        int start, int end) {

    //Call execv, based on which elements in the string vector to use
    char * argv[20];

	    int i = 0;
	    int status;

	    for (i = 0; i <= (end - start); i++) {
		argv[i] = new char[20];
	    }

	    for (i = 0; i < (end-start); i++) {
		strcpy(argv[i], input[i+start].c_str());
            }

	    argv[i] = NULL;
            string cmd = argv[0];

            for (unsigned int j = 0; j < pathing.size(); j++) {
                string tmp = pathing[j] + "/" + cmd;
                strcpy(argv[0], tmp.c_str());
                status = execv(argv[0], argv);

            }
	    if (status == -1)
		perror("execv");
		exit(1);
}

void printusrhost() {

    // Get username
    char * usrname;
    struct passwd *pass = getpwuid(getuid());
    usrname = pass->pw_name;
    if (pass == NULL) {
	perror ("getpwuid");
    exit(1);
    }

    // Get hostname
    char hostname[20];

    if (gethostname(hostname, sizeof hostname) ==-1) {
	perror("gethostname");
	exit(1);
    }
    cout << usrname << "@" << hostname <<"$ ";

}

void int_handler(int x) {
        cout << endl;
}

int main() {

    if ((signal(SIGINT, int_handler)) == SIG_ERR)
        perror("signal");

    vector<string> input;
    vector<string> pathing;
    int status=0;
    char *pPath;

    pPath = getenv("PATH");
	if (pPath == NULL)
	    perror("PATH");
    parsePath(pPath, pathing);

    int savestdin;
    if ((savestdin = dup(0)) == -1)
        perror("dup");

    int savestdout;
    if ((savestdout = dup(1)) == -1)
        perror("dup");

    // Main loop
    while (1) {
        //Restore stdin and stdout
        if ((dup2(savestdin,0)) == -1)
            perror("dup2");

        if ((dup2(savestdout,0)) == -1)
            perror("dup2");

    printusrhost();

	status = 0;

	if (input.size() != 0)
	    input.clear();

	string string1;
	getline(cin, string1);

	parse((char *)string1.c_str(), input);

    //debugging
    //cerr << "AFTER PARSING: \n";
    //for (int i = 0; i < input.size(); i++)
            //cerr << input[i] << endl;

	if (input.size() == 0)
	    continue;

    for (unsigned int i = 0; i < input.size(); i++)
	    if (strcmp(input[i].c_str(), "exit") == 0) exit(0);

	int pid=fork();
    if (pid == -1)
        perror ("fork");
	int pid2;
	if (pid == 0) {
	    int start = 0;
	    int end = input.size();
	    unsigned i;

loop:
        end = input.size();

        for (i = start; i < input.size(); ) {

            if (input[i] == "cd") {
                string directory =  input[i+1];
                int ret;
                ret = chdir(directory.c_str());
                if (ret == -1)
                    perror ("chdir");

                if ((i+2) >= input.size())
                    exit(0);
                else if (input[i+2] == ";" || input[i+2] == "&&") {
                    start = i+3;
                    goto loop;
                }

            }

            //input output redirection
            if (input[i] == ">" || input[i] == ">>" || input[i]=="<"
                            || input[i] == "<<<" || input[i] == "|"
                            || (isdigit(input[i][0]) && input[i][1] == '>')) {

                if ((isdigit(input[i][0]) && input[i][1] == '>') || input[i][0] == '>') {

                    int flags = 0;
                    int file_no = 1;
                    flags |= O_CREAT | O_WRONLY;

                    if ((input[i][0] == '>' && input[i][1] == '>') ||
                                input[i][2] == '>')
                            flags |= O_APPEND;
                        else
                            flags |= O_TRUNC;

                    int fdo = open(input[i+1].c_str(), flags, S_IRUSR | S_IWUSR);
                    if (fdo==-1) {
                        perror("open");
                        exit(1);
                    }

                    if (isdigit(input[i][0]))
                        file_no = input[i][0] - '0';

                    status = close(file_no);
                    if (status == -1)
                        perror("close");

                    if ((dup(fdo)) == -1)
                        perror("dup");

                    if ((close(fdo)) == -1)
                        perror("close");

                    input.erase(input.begin() + i);
                    input.erase(input.begin() + i);

                    if (input[i][0] == '>' || input[i][0] == '<' || input[i][0] == '|'
                                            || (isdigit(input[i][0]) && input[i][1] == '>'))
                        continue;

                    else {
                        end = i;
                        break;
                    }

                }

                else if (input[i] == "<") {

                        int fdi = open(input[i+1].c_str(), O_RDONLY, 0);
                        if (fdi==-1) {
                            perror("open");
                            exit(1);
                        }

                        status = close(STDIN_FILENO);
                        if (status == -1)
                            perror("close");

                        if ((dup(fdi)) == -1)
                            perror("dup");

                        if ((close(fdi)) == -1)
                            perror("close");

                        input.erase(input.begin() + i);
                        input.erase(input.begin() + i);

                        if (input[i][0] == '>' || input[i][0] == '<' || input[i][0] == '|'
                                            || (isdigit(input[i][0]) && input[i][1] == '>'))
                            continue;

                        else {
                            end = i;
                            break;
                        }
                }

                else if (input[i] == "<<<") {

                    int pfd[2];

                    if ((pipe(pfd)) == -1)
                        perror("pipe");

                        char buf[128];
                        memset(buf, 0, 128);
                        strcpy(buf, input[i+1].c_str());

                        buf[strlen(buf)] = '\n';
                        buf[strlen(buf)+1] = '\0';

                        if ((write(pfd[1], buf, strlen(buf)) == -1))
                            perror("write");

                        if ((dup2(pfd[0], 0)) == -1)
                            perror("dup2");

                        if (close (pfd[1]) == -1)
                            perror("close");

                        input.erase(input.begin() + i);
                        input.erase(input.begin() + i);

                        if (input[i][0] == '>' || input[i][0] == '<' || input[i][0] == '|'
                                            || (isdigit(input[i][0]) && input[i][1] == '>'))
                            continue;

                        else {
                            end = i;
                            break;
                        }

                }
                else if (input[i] == "|") {
                    int pfd[2];

                    if ((pipe(pfd)) == -1)
                        perror("pipe");

                    int pid3 = fork();
                    if (pid3 == -1) {
                        perror("fork");
                        exit(1);
                    }
                    if (pid3==0) {

                        if ((dup2(pfd[1], 1)) == -1)
                            perror("dup2");

                        if ((close(pfd[0])) == -1)
                            perror("close");

                        end = i;
                        break;

                    }
                    else {
                        if((close(STDIN_FILENO)) == -1)
                            perror("close");

                        if ((dup2(pfd[0], 0)) == -1)
                            perror("dup2");

                        if ((close(pfd[1])) == -1)
                            perror("close");

                        if (-1 == wait(0))
                            perror("wait");

                        start = i+1;
                        goto loop;

                    }

                }
            }

            else if (input[i] == ";" || input[i] == "&&" || input[i] == "||") {

                string connector = input[i];

		        pid2 = fork();
		        if (pid2 == -1) {
			        perror("fork");
			        exit(1);
		        }
		        if (pid2!=0) {
			        if (-1 == wait(&status))
			            perror("wait");

			        if (connector == "&&" && status != 0)
			            exit(1);

			        if (connector == "||" && status == 0)
			            exit(0);

			        start = i + 1;
			        goto loop;

		        }
		        else {
			        end = i;
			        break;
		        }
		    }
	    i++;
        }

	    execute(input, pathing, start, end);

	}
	else {
	    status = wait(NULL);
	    if (status == -1)
		perror("wait");

            //chdir command
        for (int i = 0; i < input.size(); i++) {
            if (strcmp(input[i].c_str(), "cd") == 0) {
                string directory =  input[i+1];
                int ret;
                ret = chdir(directory.c_str());
                if (ret == -1)
                    perror ("chdir");

            }
        }
    }
    }

    exit(0);
}
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the CutePaste project
 * Copyright (c) 2013 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QSslError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTcpSocket>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QFile>
#include <QScopedPointer>
#include <QTextStream>
#include <QStringList>
#include <QCoreApplication>

#include <QDebug>

int main(int argc, char **argv)
{
    QCoreApplication application{argc, argv};
    application.setOrganizationName("CutePaste");
    application.setApplicationName("CutePaste Desktop Console Frontend");

    QTextStream standardOutputStream{stdout};
    QFile dataFile;
    QString firstArgument{QCoreApplication::arguments().size() < 2 ? QString() : QCoreApplication::arguments().at(1)};
    if (!firstArgument.isEmpty()) {
        dataFile.setFileName(firstArgument);
        dataFile.open(QIODevice::ReadOnly);
    } else {
        dataFile.open(stdin, QIODevice::ReadOnly);
    }

    QByteArray pasteTextByteArray{dataFile.readAll()};

    QJsonObject requestJsonObject;
    requestJsonObject.insert(QStringLiteral("data"), QString::fromUtf8(pasteTextByteArray));
    requestJsonObject.insert(QStringLiteral("language"), QStringLiteral("text"));

    QJsonDocument requestJsonDocument{requestJsonObject};

    QString baseUrlString{QStringLiteral("http://pastebin.kde.org")};

    QNetworkRequest networkRequest;
    networkRequest.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
    networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    networkRequest.setUrl(QUrl(baseUrlString + "/api/json/create"));

    QNetworkAccessManager networkAccessManager;
    QScopedPointer<QNetworkReply> networkReplyScopedPointer(networkAccessManager.post(networkRequest, requestJsonDocument.toJson()));
    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::finished, [&]() {

        QJsonParseError jsonParseError;
        QByteArray replyJsonByteArray{networkReplyScopedPointer->readAll()};
        QJsonDocument replyJsonDocument{QJsonDocument::fromJson(replyJsonByteArray, &jsonParseError)};
        if (jsonParseError.error != QJsonParseError::NoError) {
            qDebug() << "The json network reply is not valid json:" << jsonParseError.errorString();
            QCoreApplication::quit();
        }

        if (!replyJsonDocument.isObject()) {
            qDebug() << "The json network reply is not an object";
            QCoreApplication::quit();
        }

        QJsonObject replyJsonObject{replyJsonDocument.object()};
        QJsonValue resultValue{replyJsonObject.value(QStringLiteral("result"))};

        if (!resultValue.isObject()) {
            qDebug() << "The json network reply does not contain an object for the \"result\" key";
            QCoreApplication::quit();
        }

        QJsonValue identifierValue{resultValue.toObject().value(QStringLiteral("id"))};

        if (!identifierValue.isString()) {
            qDebug() << "The json network reply does not contain a string for the \"id\" key";
            QCoreApplication::quit();
        }

        endl(standardOutputStream << baseUrlString << '/' << identifierValue.toString());

        QCoreApplication::quit();
    });

    QObject::connect(networkReplyScopedPointer.data(), static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [&](QNetworkReply::NetworkError networkReplyError) {
        if (networkReplyError != QNetworkReply::NoError)
            endl(standardOutputStream << networkReplyScopedPointer->errorString());
    });

    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::sslErrors, [&](QList<QSslError> networkReplySslErrors) {
        if (!networkReplySslErrors.isEmpty()) {
            for (auto &networkReplySslError: networkReplySslErrors)
                endl(standardOutputStream << networkReplySslError.errorString());
        }
    });

    int returnValue{application.exec()};

    dataFile.close();
    if (dataFile.error() != QFileDevice::NoError)
        endl(standardOutputStream << dataFile.errorString());

    return returnValue;
}
<commit_msg>Decorate the deduced type with specifier (modifier)<commit_after>/******************************************************************************
 * This file is part of the CutePaste project
 * Copyright (c) 2013 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <QSslError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTcpSocket>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QFile>
#include <QScopedPointer>
#include <QTextStream>
#include <QStringList>
#include <QCoreApplication>

#include <QDebug>

int main(int argc, char **argv)
{
    QCoreApplication application{argc, argv};
    application.setOrganizationName("CutePaste");
    application.setApplicationName("CutePaste Desktop Console Frontend");

    QTextStream standardOutputStream{stdout};
    QFile dataFile;
    QString firstArgument{QCoreApplication::arguments().size() < 2 ? QString() : QCoreApplication::arguments().at(1)};
    if (!firstArgument.isEmpty()) {
        dataFile.setFileName(firstArgument);
        dataFile.open(QIODevice::ReadOnly);
    } else {
        dataFile.open(stdin, QIODevice::ReadOnly);
    }

    QByteArray pasteTextByteArray{dataFile.readAll()};

    QJsonObject requestJsonObject;
    requestJsonObject.insert(QStringLiteral("data"), QString::fromUtf8(pasteTextByteArray));
    requestJsonObject.insert(QStringLiteral("language"), QStringLiteral("text"));

    QJsonDocument requestJsonDocument{requestJsonObject};

    QString baseUrlString{QStringLiteral("http://pastebin.kde.org")};

    QNetworkRequest networkRequest;
    networkRequest.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
    networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    networkRequest.setUrl(QUrl(baseUrlString + "/api/json/create"));

    QNetworkAccessManager networkAccessManager;
    QScopedPointer<QNetworkReply> networkReplyScopedPointer(networkAccessManager.post(networkRequest, requestJsonDocument.toJson()));
    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::finished, [&]() {

        QJsonParseError jsonParseError;
        QByteArray replyJsonByteArray{networkReplyScopedPointer->readAll()};
        QJsonDocument replyJsonDocument{QJsonDocument::fromJson(replyJsonByteArray, &jsonParseError)};
        if (jsonParseError.error != QJsonParseError::NoError) {
            qDebug() << "The json network reply is not valid json:" << jsonParseError.errorString();
            QCoreApplication::quit();
        }

        if (!replyJsonDocument.isObject()) {
            qDebug() << "The json network reply is not an object";
            QCoreApplication::quit();
        }

        QJsonObject replyJsonObject{replyJsonDocument.object()};
        QJsonValue resultValue{replyJsonObject.value(QStringLiteral("result"))};

        if (!resultValue.isObject()) {
            qDebug() << "The json network reply does not contain an object for the \"result\" key";
            QCoreApplication::quit();
        }

        QJsonValue identifierValue{resultValue.toObject().value(QStringLiteral("id"))};

        if (!identifierValue.isString()) {
            qDebug() << "The json network reply does not contain a string for the \"id\" key";
            QCoreApplication::quit();
        }

        endl(standardOutputStream << baseUrlString << '/' << identifierValue.toString());

        QCoreApplication::quit();
    });

    QObject::connect(networkReplyScopedPointer.data(), static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), [&](QNetworkReply::NetworkError networkReplyError) {
        if (networkReplyError != QNetworkReply::NoError)
            endl(standardOutputStream << networkReplyScopedPointer->errorString());
    });

    QObject::connect(networkReplyScopedPointer.data(), &QNetworkReply::sslErrors, [&](QList<QSslError> networkReplySslErrors) {
        if (!networkReplySslErrors.isEmpty()) {
            for (const auto &networkReplySslError : networkReplySslErrors)
                endl(standardOutputStream << networkReplySslError.errorString());
        }
    });

    int returnValue{application.exec()};

    dataFile.close();
    if (dataFile.error() != QFileDevice::NoError)
        endl(standardOutputStream << dataFile.errorString());

    return returnValue;
}
<|endoftext|>


<commit_before>/** Original implementation supporting both UNIX and TCP sockets.
 *
 * The UNIX socket implementation is based on the behaviour defined in the FastCGI specification, and also
 * includes optional support for logging via syslog, as defined in the specification.
 *
 * This implementation is *NOT* portable.
 */
#include "SocketServer.h"

#include "fastcgi.h"

#include <QtEndian>
#include <QFileSystemWatcher>
#include <QHostAddress>
#include <QSocketNotifier>
#include <QTextStream>
#include <QTimer>

#include <errno.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/ip.h>

namespace FastCgiQt
{
	class SocketServer::Private
	{
		public:
			/// Lock the socket with the specified socket id.
			void lockSocket(int socket);
			/// Unlock the socket with the specified socket id.
			void releaseSocket(int socket);

			/// Socket handle
			int m_socket;

			/// Type of socket
			SocketServer::SocketType m_socketType;

			/** Notifier used to watch for new connections to the
			 * FastCGI socket.
			 */
			QSocketNotifier* m_socketNotifier;
	};

	bool SocketServer::isFinished() const
	{
		return !(d->m_socketNotifier && d->m_socketNotifier->isEnabled());
	}

	void SocketServer::Private::lockSocket(int socket)
	{
		::flock(socket, LOCK_EX);
	}

	void SocketServer::Private::releaseSocket(int socket)
	{
		::flock(socket, LOCK_UN);
	}

	bool SocketServer::listen(SocketType type, quint16 parameter)
	{
		d->m_socketType == type;
		if(type == UnixSocket)
		{
			// Check we're running as a FastCGI application
			sockaddr_un sa;
			socklen_t len = sizeof(sa);
			::memset(&sa, 0, len);
			d->m_socket = FCGI_LISTENSOCK_FILENO;

			// The recommended way of telling if we're running as fastcgi or not.
			const int error = ::getpeername(FCGI_LISTENSOCK_FILENO, reinterpret_cast<sockaddr*>(&sa), &len);
			if(error == -1 && errno != ENOTCONN)
			{
				qWarning("Asked to run FastCGI on a UNIX socket, but not being run correctly");
				return false;
			}

			// Wait for the event loop to start up before running
			QTimer::singleShot(0, this, SIGNAL(newConnection()));
		}
		else
		{
			Q_ASSERT(type == TcpSocket);
			// SOCK_STREAM specifies TCP instead of UDP
			d->m_socket = ::socket(AF_INET, SOCK_STREAM, 0);
			const in_port_t port = static_cast<in_port_t>(parameter);
			if(port == 0)
			{
					qWarning("Configured to listen on TCP, but there isn't a valid Port Number configured. Try --configure-fastcgi");
					return false;
			}

			// Initialise the socket address structure
			sockaddr_in sa;
			::memset(&sa, 0, sizeof(sa));
			sa.sin_family = AF_INET;
			sa.sin_port = qToBigEndian(port);

			// Try and bind to the port
			if(::bind(d->m_socket, reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) == -1)
			{
				qWarning("Failed to bind() to TCP port %d with error: %s", port, ::strerror(errno));
				return false;
			}
			// Now we've bound to the port, start listening
			if(::listen(d->m_socket, 1) == -1)
			{
				qWarning("Failed to listen() on port %d with error: %s", port, ::strerror(errno));
				return false;
			}
		}

		d->m_socketNotifier = new QSocketNotifier(d->m_socket, QSocketNotifier::Read, this),
		connect(
			d->m_socketNotifier,
			SIGNAL(activated(int)),
			this,
			SIGNAL(newConnection())
		);

		return true;
	}

	SocketServer::SocketType SocketServer::socketType() const
	{
		return d->m_socketType;
	}

	QTcpSocket* SocketServer::nextPendingConnection()
	{
		// Initialise socket address structure
		sockaddr_un sa;
		socklen_t len = sizeof(sa);
		::memset(&sa, 0, len);

		// Listen on the socket
		d->lockSocket(d->m_socket);
		const int newSocket = ::accept(d->m_socket, reinterpret_cast<sockaddr*>(&sa), &len);
		d->releaseSocket(d->m_socket);

		if(newSocket == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
		{
			return 0;
		}
		else
		{
			QTcpSocket* socket = new QTcpSocket(this);
			socket->setSocketDescriptor(newSocket);
			return socket;
		}
	}

	SocketServer::SocketTypes SocketServer::supportedSocketTypes()
	{
		return TcpSocket | UnixSocket;
	}

	SocketServer::SocketServer(QObject* parent)
	: QObject(parent)
	, d(new SocketServer::Private)
	{
		d->m_socketNotifier = 0;
	}

	SocketServer::~SocketServer()
	{
		if(d->m_socketNotifier)
		{
			Q_ASSERT(d->m_socket == d->m_socketNotifier->socket());
			// stop listening
			::close(d->m_socket);
			// stop watching
			d->m_socketNotifier->setEnabled(false);
		}
		delete d;
	}
};
<commit_msg>==/= typo fix Thanks to Hauke Wintjen<commit_after>/** Original implementation supporting both UNIX and TCP sockets.
 *
 * The UNIX socket implementation is based on the behaviour defined in the FastCGI specification, and also
 * includes optional support for logging via syslog, as defined in the specification.
 *
 * This implementation is *NOT* portable.
 */
#include "SocketServer.h"

#include "fastcgi.h"

#include <QtEndian>
#include <QFileSystemWatcher>
#include <QHostAddress>
#include <QSocketNotifier>
#include <QTextStream>
#include <QTimer>

#include <errno.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/ip.h>

namespace FastCgiQt
{
	class SocketServer::Private
	{
		public:
			/// Lock the socket with the specified socket id.
			void lockSocket(int socket);
			/// Unlock the socket with the specified socket id.
			void releaseSocket(int socket);

			/// Socket handle
			int m_socket;

			/// Type of socket
			SocketServer::SocketType m_socketType;

			/** Notifier used to watch for new connections to the
			 * FastCGI socket.
			 */
			QSocketNotifier* m_socketNotifier;
	};

	bool SocketServer::isFinished() const
	{
		return !(d->m_socketNotifier && d->m_socketNotifier->isEnabled());
	}

	void SocketServer::Private::lockSocket(int socket)
	{
		::flock(socket, LOCK_EX);
	}

	void SocketServer::Private::releaseSocket(int socket)
	{
		::flock(socket, LOCK_UN);
	}

	bool SocketServer::listen(SocketType type, quint16 parameter)
	{
		d->m_socketType = type;
		if(type == UnixSocket)
		{
			// Check we're running as a FastCGI application
			sockaddr_un sa;
			socklen_t len = sizeof(sa);
			::memset(&sa, 0, len);
			d->m_socket = FCGI_LISTENSOCK_FILENO;

			// The recommended way of telling if we're running as fastcgi or not.
			const int error = ::getpeername(FCGI_LISTENSOCK_FILENO, reinterpret_cast<sockaddr*>(&sa), &len);
			if(error == -1 && errno != ENOTCONN)
			{
				qWarning("Asked to run FastCGI on a UNIX socket, but not being run correctly");
				return false;
			}

			// Wait for the event loop to start up before running
			QTimer::singleShot(0, this, SIGNAL(newConnection()));
		}
		else
		{
			Q_ASSERT(type == TcpSocket);
			// SOCK_STREAM specifies TCP instead of UDP
			d->m_socket = ::socket(AF_INET, SOCK_STREAM, 0);
			const in_port_t port = static_cast<in_port_t>(parameter);
			if(port == 0)
			{
					qWarning("Configured to listen on TCP, but there isn't a valid Port Number configured. Try --configure-fastcgi");
					return false;
			}

			// Initialise the socket address structure
			sockaddr_in sa;
			::memset(&sa, 0, sizeof(sa));
			sa.sin_family = AF_INET;
			sa.sin_port = qToBigEndian(port);

			// Try and bind to the port
			if(::bind(d->m_socket, reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) == -1)
			{
				qWarning("Failed to bind() to TCP port %d with error: %s", port, ::strerror(errno));
				return false;
			}
			// Now we've bound to the port, start listening
			if(::listen(d->m_socket, 1) == -1)
			{
				qWarning("Failed to listen() on port %d with error: %s", port, ::strerror(errno));
				return false;
			}
		}

		d->m_socketNotifier = new QSocketNotifier(d->m_socket, QSocketNotifier::Read, this),
		connect(
			d->m_socketNotifier,
			SIGNAL(activated(int)),
			this,
			SIGNAL(newConnection())
		);

		return true;
	}

	SocketServer::SocketType SocketServer::socketType() const
	{
		return d->m_socketType;
	}

	QTcpSocket* SocketServer::nextPendingConnection()
	{
		// Initialise socket address structure
		sockaddr_un sa;
		socklen_t len = sizeof(sa);
		::memset(&sa, 0, len);

		// Listen on the socket
		d->lockSocket(d->m_socket);
		const int newSocket = ::accept(d->m_socket, reinterpret_cast<sockaddr*>(&sa), &len);
		d->releaseSocket(d->m_socket);

		if(newSocket == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
		{
			return 0;
		}
		else
		{
			QTcpSocket* socket = new QTcpSocket(this);
			socket->setSocketDescriptor(newSocket);
			return socket;
		}
	}

	SocketServer::SocketTypes SocketServer::supportedSocketTypes()
	{
		return TcpSocket | UnixSocket;
	}

	SocketServer::SocketServer(QObject* parent)
	: QObject(parent)
	, d(new SocketServer::Private)
	{
		d->m_socketNotifier = 0;
	}

	SocketServer::~SocketServer()
	{
		if(d->m_socketNotifier)
		{
			Q_ASSERT(d->m_socket == d->m_socketNotifier->socket());
			// stop listening
			::close(d->m_socket);
			// stop watching
			d->m_socketNotifier->setEnabled(false);
		}
		delete d;
	}
};
<|endoftext|>