<commit_before>#include "v8eval.h"
#include "dbgsrv.h"

#include <stdlib.h>
#include <string.h>

#include "libplatform/libplatform.h"

namespace v8eval {

static v8::Platform* platform = nullptr;

bool initialize() {
  if (platform) {
    return false;
  }

  if (!v8::V8::InitializeICU()) {
    return false;
  }

  platform = v8::platform::CreateDefaultPlatform();
  v8::V8::InitializePlatform(platform);

  return v8::V8::Initialize();
}

bool dispose() {
  if (!platform) {
    return false;
  }

  v8::V8::Dispose();

  v8::V8::ShutdownPlatform();
  delete platform;
  platform = nullptr;

  return true;
}

class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
 public:
  virtual void* Allocate(size_t length) {
    void* data = AllocateUninitialized(length);
    return data == NULL ? data : memset(data, 0, length);
  }

  virtual void* AllocateUninitialized(size_t length) {
    return malloc(length);
  }

  virtual void Free(void* data, size_t) {
    free(data);
  }
};

static ArrayBufferAllocator allocator;

_V8::_V8() {
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = &allocator;
  isolate_ = v8::Isolate::New(create_params);

  dbg_server_ = nullptr;
  dbg_isolate_ = nullptr;
  callback_ = nullptr;
  callback_opq_ = nullptr;

  // Use Isolate's local storage to store a pointer to the associated
  // V8 instance. This is retrieved in the V8 debugger's callback, as
  // the instance pointer is the only context we get from the caller.
  isolate_->SetData(0, this);

  v8::Locker locker(isolate_);

  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  context_.Reset(isolate_, new_context());
}

_V8::~_V8() {
  if (dbg_server_ != nullptr) {
    delete dbg_server_;
  }

  context_.Reset();
  isolate_->Dispose();
}

v8::Local<v8::Context> _V8::new_context() {
  if (context_.IsEmpty()) {
    v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
    return v8::Context::New(isolate_, nullptr, global);
  } else {
    return v8::Local<v8::Context>::New(isolate_, context_);
  }
}

v8::Local<v8::String> _V8::new_string(const char* str) {
  return v8::String::NewFromUtf8(isolate_, str ? str : "", v8::NewStringType::kNormal).ToLocalChecked();
}

static std::string to_std_string(v8::Local<v8::Value> value) {
  v8::String::Utf8Value str(value);
  return *str ? *str : "Error: Cannot convert to string";
}

v8::Local<v8::Value> _V8::json_parse(v8::Local<v8::Context> context, v8::Local<v8::String> str) {
  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Object> json = global->Get(context, new_string("JSON")).ToLocalChecked()->ToObject();
  v8::Local<v8::Function> parse = v8::Local<v8::Function>::Cast(json->Get(context, new_string("parse")).ToLocalChecked());

  v8::Local<v8::Value> result;
  v8::Local<v8::Value> value = str;
  if (!parse->Call(context, json, 1, &value).ToLocal(&result)) {
    return v8::Local<v8::Value>();  // empty
  } else {
    return result;
  }
}

v8::Local<v8::String> _V8::json_stringify(v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Object> json = global->Get(context, new_string("JSON")).ToLocalChecked()->ToObject();
  v8::Local<v8::Function> stringify = v8::Local<v8::Function>::Cast(json->Get(context, new_string("stringify")).ToLocalChecked());

  v8::Local<v8::Value> result;
  if (!stringify->Call(context, json, 1, &value).ToLocal(&result)) {
    return new_string("");
  } else {
    return result->ToString();
  }
}

std::string _V8::eval(const std::string& src) {
  v8::Locker locker(isolate_);

  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);

  v8::Local<v8::Context> context = new_context();
  v8::Context::Scope context_scope(context);

  v8::TryCatch try_catch(isolate_);

  v8::Local<v8::String> source = new_string(src.c_str());

  v8::Local<v8::String> name = new_string("v8eval");
  v8::ScriptOrigin origin(name);

  v8::Local<v8::Script> script;
  if (!v8::Script::Compile(context, source, &origin).ToLocal(&script)) {
    return to_std_string(try_catch.Exception());
  } else {
    v8::Local<v8::Value> result;
    if (!script->Run(context).ToLocal(&result)) {
      return to_std_string(try_catch.Exception());
    } else {
      return to_std_string(json_stringify(context, result));
    }
  }
}

std::string _V8::call(const std::string& func, const std::string& args) {
  v8::Locker locker(isolate_);

  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);

  v8::Local<v8::Context> context = new_context();
  v8::Context::Scope context_scope(context);

  v8::TryCatch try_catch(isolate_);

  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Value> result;
  if (!global->Get(context, new_string(func.c_str())).ToLocal(&result)) {
    return to_std_string(try_catch.Exception());
  } else if (!result->IsFunction()) {
    return "TypeError: '" + func + "' is not a function";
  }

  v8::Local<v8::Function> function = v8::Handle<v8::Function>::Cast(result);
  v8::Local<v8::Function> apply = v8::Handle<v8::Function>::Cast(function->Get(context, new_string("apply")).ToLocalChecked());
  v8::Local<v8::Value> arguments = json_parse(context, new_string(args.c_str()));
  if (arguments.IsEmpty() || !arguments->IsArray()) {
    return "TypeError: '" + args + "' is not an array";
  }

  v8::Local<v8::Value> values[] = { function, arguments };
  if (!apply->Call(context, function, 2, values).ToLocal(&result)) {
    return to_std_string(try_catch.Exception());
  } else {
    return to_std_string(json_stringify(context, result));
  }
}

bool _V8::debugger_enable(int port) {
  if (dbg_server_ != nullptr) {
    return false;
  }
  dbg_server_ = new DbgSrv(*this);
  if (!dbg_server_->start(port)) {
    delete dbg_server_;
    dbg_server_ = nullptr;
    return false;
  }
  return true;
}

void _V8::debugger_disable() {
  if (dbg_server_ != nullptr) {
    delete dbg_server_;
    dbg_server_ = nullptr;
  }
}

void _V8::debugger_message_handler(const v8::Debug::Message& message) {
  v8::Isolate* isolate = message.GetIsolate();
  _V8 *_v8 = (v8eval::_V8*)isolate->GetData(0);
  std::string string = *v8::String::Utf8Value(message.GetJSON());

  if (_v8->callback_ != nullptr) {
    _v8->callback_(string, _v8->callback_opq_);
  }
}

bool _V8::debugger_init(debugger_cb cb, void *cbopq) {
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = &allocator;
  dbg_isolate_ = v8::Isolate::New(create_params);

  if (callback_ != nullptr) {
    return false;
  }
  callback_ = cb;
  callback_opq_ = cbopq;

  // Set Debuger callback.
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  v8::Debug::SetMessageHandler(debugger_message_handler);

  return true;
}

void _V8::debugger_process() {
  // Process debug messages on behalf of the V8 instance.
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);

  v8::Debug::ProcessDebugMessages();
}

bool _V8::debugger_send(const std::string& cmd) {
  v8::Locker locker(dbg_isolate_);
  v8::Isolate::Scope isolate_scope(dbg_isolate_);
  v8::HandleScope handle_scope(dbg_isolate_);

  if (callback_ == nullptr) {
    return false;
  }

  v8::Local<v8::String> vstr = v8::String::NewFromUtf8(dbg_isolate_, cmd.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
  v8::String::Value v(vstr);
  v8::Debug::SendCommand(isolate_, *v, v.length());
  return true;
}

void _V8::debugger_stop() {
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  v8::Debug::SetMessageHandler(nullptr);

  callback_ = nullptr;
  callback_opq_ = nullptr;
  dbg_isolate_->Dispose();
  dbg_isolate_ = nullptr;
}

}  // namespace v8eval
<commit_msg>Trivial refactoring of nullptr comparison<commit_after>#include "v8eval.h"
#include "dbgsrv.h"

#include <stdlib.h>
#include <string.h>

#include "libplatform/libplatform.h"

namespace v8eval {

static v8::Platform* platform = nullptr;

bool initialize() {
  if (platform) {
    return false;
  }

  if (!v8::V8::InitializeICU()) {
    return false;
  }

  platform = v8::platform::CreateDefaultPlatform();
  v8::V8::InitializePlatform(platform);

  return v8::V8::Initialize();
}

bool dispose() {
  if (!platform) {
    return false;
  }

  v8::V8::Dispose();

  v8::V8::ShutdownPlatform();
  delete platform;
  platform = nullptr;

  return true;
}

class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
 public:
  virtual void* Allocate(size_t length) {
    void* data = AllocateUninitialized(length);
    return data == NULL ? data : memset(data, 0, length);
  }

  virtual void* AllocateUninitialized(size_t length) {
    return malloc(length);
  }

  virtual void Free(void* data, size_t) {
    free(data);
  }
};

static ArrayBufferAllocator allocator;

_V8::_V8() {
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = &allocator;
  isolate_ = v8::Isolate::New(create_params);

  dbg_server_ = nullptr;
  dbg_isolate_ = nullptr;
  callback_ = nullptr;
  callback_opq_ = nullptr;

  // Use Isolate's local storage to store a pointer to the associated
  // V8 instance. This is retrieved in the V8 debugger's callback, as
  // the instance pointer is the only context we get from the caller.
  isolate_->SetData(0, this);

  v8::Locker locker(isolate_);

  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  context_.Reset(isolate_, new_context());
}

_V8::~_V8() {
  if (dbg_server_) {
    delete dbg_server_;
  }

  context_.Reset();
  isolate_->Dispose();
}

v8::Local<v8::Context> _V8::new_context() {
  if (context_.IsEmpty()) {
    v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
    return v8::Context::New(isolate_, nullptr, global);
  } else {
    return v8::Local<v8::Context>::New(isolate_, context_);
  }
}

v8::Local<v8::String> _V8::new_string(const char* str) {
  return v8::String::NewFromUtf8(isolate_, str ? str : "", v8::NewStringType::kNormal).ToLocalChecked();
}

static std::string to_std_string(v8::Local<v8::Value> value) {
  v8::String::Utf8Value str(value);
  return *str ? *str : "Error: Cannot convert to string";
}

v8::Local<v8::Value> _V8::json_parse(v8::Local<v8::Context> context, v8::Local<v8::String> str) {
  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Object> json = global->Get(context, new_string("JSON")).ToLocalChecked()->ToObject();
  v8::Local<v8::Function> parse = v8::Local<v8::Function>::Cast(json->Get(context, new_string("parse")).ToLocalChecked());

  v8::Local<v8::Value> result;
  v8::Local<v8::Value> value = str;
  if (!parse->Call(context, json, 1, &value).ToLocal(&result)) {
    return v8::Local<v8::Value>();  // empty
  } else {
    return result;
  }
}

v8::Local<v8::String> _V8::json_stringify(v8::Local<v8::Context> context, v8::Local<v8::Value> value) {
  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Object> json = global->Get(context, new_string("JSON")).ToLocalChecked()->ToObject();
  v8::Local<v8::Function> stringify = v8::Local<v8::Function>::Cast(json->Get(context, new_string("stringify")).ToLocalChecked());

  v8::Local<v8::Value> result;
  if (!stringify->Call(context, json, 1, &value).ToLocal(&result)) {
    return new_string("");
  } else {
    return result->ToString();
  }
}

std::string _V8::eval(const std::string& src) {
  v8::Locker locker(isolate_);

  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);

  v8::Local<v8::Context> context = new_context();
  v8::Context::Scope context_scope(context);

  v8::TryCatch try_catch(isolate_);

  v8::Local<v8::String> source = new_string(src.c_str());

  v8::Local<v8::String> name = new_string("v8eval");
  v8::ScriptOrigin origin(name);

  v8::Local<v8::Script> script;
  if (!v8::Script::Compile(context, source, &origin).ToLocal(&script)) {
    return to_std_string(try_catch.Exception());
  } else {
    v8::Local<v8::Value> result;
    if (!script->Run(context).ToLocal(&result)) {
      return to_std_string(try_catch.Exception());
    } else {
      return to_std_string(json_stringify(context, result));
    }
  }
}

std::string _V8::call(const std::string& func, const std::string& args) {
  v8::Locker locker(isolate_);

  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);

  v8::Local<v8::Context> context = new_context();
  v8::Context::Scope context_scope(context);

  v8::TryCatch try_catch(isolate_);

  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Value> result;
  if (!global->Get(context, new_string(func.c_str())).ToLocal(&result)) {
    return to_std_string(try_catch.Exception());
  } else if (!result->IsFunction()) {
    return "TypeError: '" + func + "' is not a function";
  }

  v8::Local<v8::Function> function = v8::Handle<v8::Function>::Cast(result);
  v8::Local<v8::Function> apply = v8::Handle<v8::Function>::Cast(function->Get(context, new_string("apply")).ToLocalChecked());
  v8::Local<v8::Value> arguments = json_parse(context, new_string(args.c_str()));
  if (arguments.IsEmpty() || !arguments->IsArray()) {
    return "TypeError: '" + args + "' is not an array";
  }

  v8::Local<v8::Value> values[] = { function, arguments };
  if (!apply->Call(context, function, 2, values).ToLocal(&result)) {
    return to_std_string(try_catch.Exception());
  } else {
    return to_std_string(json_stringify(context, result));
  }
}

bool _V8::debugger_enable(int port) {
  if (dbg_server_) {
    return false;
  }
  dbg_server_ = new DbgSrv(*this);
  if (!dbg_server_->start(port)) {
    delete dbg_server_;
    dbg_server_ = nullptr;
    return false;
  }
  return true;
}

void _V8::debugger_disable() {
  if (dbg_server_) {
    delete dbg_server_;
    dbg_server_ = nullptr;
  }
}

void _V8::debugger_message_handler(const v8::Debug::Message& message) {
  v8::Isolate* isolate = message.GetIsolate();
  _V8 *_v8 = (v8eval::_V8*)isolate->GetData(0);
  std::string string = *v8::String::Utf8Value(message.GetJSON());

  if (_v8->callback_) {
    _v8->callback_(string, _v8->callback_opq_);
  }
}

bool _V8::debugger_init(debugger_cb cb, void *cbopq) {
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = &allocator;
  dbg_isolate_ = v8::Isolate::New(create_params);

  if (callback_) {
    return false;
  }
  callback_ = cb;
  callback_opq_ = cbopq;

  // Set Debuger callback.
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  v8::Debug::SetMessageHandler(debugger_message_handler);

  return true;
}

void _V8::debugger_process() {
  // Process debug messages on behalf of the V8 instance.
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);

  v8::Debug::ProcessDebugMessages();
}

bool _V8::debugger_send(const std::string& cmd) {
  v8::Locker locker(dbg_isolate_);
  v8::Isolate::Scope isolate_scope(dbg_isolate_);
  v8::HandleScope handle_scope(dbg_isolate_);

  if (!callback_) {
    return false;
  }

  v8::Local<v8::String> vstr = v8::String::NewFromUtf8(dbg_isolate_, cmd.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
  v8::String::Value v(vstr);
  v8::Debug::SendCommand(isolate_, *v, v.length());
  return true;
}

void _V8::debugger_stop() {
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  v8::Debug::SetMessageHandler(nullptr);

  callback_ = nullptr;
  callback_opq_ = nullptr;
  dbg_isolate_->Dispose();
  dbg_isolate_ = nullptr;
}

}  // namespace v8eval
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <stdlib.h>	//exit
#include <stdio.h>	//perror
#include <errno.h>	//perror
#include <sys/types.h>	//wait
#include <sys/wait.h>	//wait
#include <unistd.h>	//execvp, fork, gethost, getlogin
#include <string.h>	//strtok
#include <vector>
using namespace std;

//checks for comments and if stuff is after comments, it deletes it
void checkcomm(string &str){
	size_t comment = str.find("#");
	if(comment != string :: npos)
		str.erase(comment);
}

void forkPipes(char **argv, char **afterPipe);
void simpleFork(char **argv);
void getPipes(char** argv);

int main(/*int argc, char *argv[]*/){	//couldn't get argv to work

	//get username and hostname
	char login[100];

	if(getlogin_r(login, sizeof(login)-1)){
		perror("Error with getlogin_r");
	}

	char host[100];

	if(-1 == gethostname(host,sizeof(host)-1)){
        	perror("Error with gethostname.");
	}

	for(int pos=0; pos<30; pos++){
		if(host[pos] == '.'){
			host[pos] = '\0';
		}
	}

	//execute
	while(1){

		string input;
		char cmndline[1024];

		cout << login << "@" << host << "$ ";

		//get the input from user
		getline(cin, input);

		//check if user pushes enter
		if(input == "")
			continue;

		//check for comments
		checkcomm(input);

		//check if user inputs exit
		if( input.find("exit") != string::npos )
			exit(0);

		//change input from string to cstring
		strcpy(cmndline, input.c_str());

		//tokenize the commandline
		char *tok; //*save;
		char delim[]= " ;&|";

		int size=input.size()+1;
		//vector<int> order;

		tok=strtok(cmndline, delim);

		char **argv=new char*[size];

		int pos=0;
		while(tok != NULL)
		{
			argv[pos]=tok;
			pos++;
			tok = strtok(NULL,delim);
		}
		argv[pos]=NULL;

		//for(unsigned i=0; i < order.size(); i++)
		//	cout << order[i] << ' ';
		//simpleFork(argv);

		getPipes(argv);

		delete argv;
	}

	return 0;
}

void simpleFork(char **argv){
	int status = 0;
	int i = fork();
	if(i == -1){
		//error check fork
		perror("There was an error with fork()");
		exit(1);
	}
	else if(i == 0) {
		//error check execvp
		if (-1==execvp(argv[0], argv)) {
			perror("execvp didn't work correctly");
			exit(1);
		}
	}
	//in parent
	else if(i > 0){
		//error check parent
		if(wait(&status)==-1){
			perror("Error in wait");
			exit(1);
		}
	}
}

void getPipes(char** argv){
	bool pipeFound = false;

	char **args = argv;
	char **nextA = argv;

	for(int i=0; argv[i] != '\0'; i++){
		if(strcmp(argv[i], "|") == 0){
			pipeFound=true;
			argv[i] = '\0';

			char** beforeA = args;
			nextA = args + i + 1;
			forkPipes(beforeA, nextA);
		}
	}

	if(!pipeFound){
		//TODO
	}
}

void forkPipes(char **argv, char **afterPipe){
	int fd[2];
	int pid;
	int status;
	if(pipe(fd) == -1){
		perror("Error with pipe.");
		exit(EXIT_FAILURE);
	}

	pid = fork();
	if(pid == -1){
		perror("There was an error with piping fork.");
		exit(1);
	}
	else if(pid ==0){
		if(close(fd[0]) == -1){
			perror("Error with close in piping.");
			exit(1);
		}
		if(dup2(fd[1],1)==-1){
			perror("Error with dup2 in piping.");
		}
		if(execvp(argv[0], argv) == -1){
			perror("There was an error with execvp piping");
			exit(1);
		}
		else{
			exit(0);
		}
	}
	else{
		if(close(fd[0]) == -1){
			perror("Error with close in piping.");
			exit(1);
		}

		int fd0 = dup(0);
		if(fd0 == -1){
			perror("There was an error with dup.");
		}
		if(dup2(fd[0],0) == -1){
			perror("Error with dup2 in piping.");
		}
		while(waitpid(-1, &status, 0) >= 0);
		getPipes(afterPipe);
		if(dup2(fd0,0)==-1){
			perror("Error with dup2 in piping.");
		}

	}
}
<commit_msg>piping works<commit_after>#include <iostream>
#include <string>
#include <stdlib.h>	//exit
#include <stdio.h>	//perror
#include <errno.h>	//perror
#include <sys/types.h>	//wait
#include <sys/wait.h>	//wait
#include <unistd.h>	//execvp, fork, gethost, getlogin
#include <string.h>	//strtok
#include <vector>
using namespace std;

//checks for comments and if stuff is after comments, it deletes it
void checkcomm(string &str){
	size_t comment = str.find("#");
	//cout << "THis is pos of comment: " << comment << endl;
	str[comment] = '\0';
	if(comment != string :: npos)
		str.erase(str.begin()+comment, str.end());
	//cout << "This is str: " << str << endl;
}
void tokenize(char *cmnd, char **argv);
void forkPipes(char **argv, char **afterPipe);
void simpleFork(char **argv);
void getPipes(char** argv);

int main(/*int argc, char *argv[]*/){	//couldn't get argv to work

	//get username and hostname
	char login[100];

	if(getlogin_r(login, sizeof(login)-1)){
		perror("Error with getlogin_r");
	}

	char host[100];

	if(-1 == gethostname(host,sizeof(host)-1)){
        	perror("Error with gethostname.");
	}

	for(int pos=0; pos<30; pos++){
		if(host[pos] == '.'){
			host[pos] = '\0';
		}
	}

	//execute
	while(1){
		string input;
		char buf[1000];
		//char **argv;
		//argv = new char*[1024];

		cout << login << "@" << host << "$ ";

		//get the input from user
		getline(cin, input);

		//check if user pushes enter
		if(input == "")
			continue;

		//check for comments
		checkcomm(input);

		strcpy(buf, input.c_str());

		//check if user inputs exit
		if( input.find("exit") != string::npos )
			exit(1);

		//tokenize(buf, argv);

		//tokenize the commandline
		//char *tok;// *save;
		char delim[]= " \t\n";

		int size=input.size()+1;
		//vector<int> order;

		char **argv=new char*[size];
		int pos=0;
		argv[pos]=strtok(buf, delim);

		while(argv[pos] != NULL)
		{
			pos++;
			argv[pos] = strtok(NULL,delim);
		}
		//argv[pos]=NULL;

		//for(unsigned i=0; argv[i] != NULL ; i++)
		//	cout << argv[i] << ' ';
		//simpleFork(argv);

		getPipes(argv);

		delete[] argv;
	}

	return 0;
}

void simpleFork(char **argv, bool BG){
	int status = 0;
	int i = fork();
	if(i == -1){
		//error check fork
		perror("There was an error with fork()");
		exit(1);
	}
	else if(i == 0) {
		//error check execvp
		if (-1==execvp(argv[0], argv)) {
			perror("execvp didn't work correctly");
			exit(1);
		}
	}
	//in parent
	if(! BG){
		//error check parent
		if(wait(&status)==-1){
			perror("Error in wait");
			exit(1);
		}
	}
}

void getPipes(char** argv){
	bool pipeFound = false;
	//save spots for the beginning arguments and ending arguments
	char **args = argv;
	char **nextA = argv;

	//go through argv and check if pipes are found
	//if they are found, it goes into function forkpipes
	for(int i=0; argv[i] != '\0'; i++){
		if(strcmp(argv[i], "|") == 0){
			pipeFound=true;
			argv[i] = '\0';
			char** beforeA = args;
			nextA = args + i + 1;
			forkPipes(beforeA, nextA);
			break;
		}
	}
	//if pipe isn't found, it goes into the simple fork
	if(!pipeFound){
		bool BG = false;
		for(int i=0; nextA[i] != '\0'; i++){
			if(strcmp(nextA[i], "&") == 0)
				BG=true;
		}
		simpleFork(nextA, BG);
	}
}

void forkPipes(char **argv, char **afterPipe){
	int fd[2];
	int pid;
	//pipe new file descriptors
	if(pipe(fd) == -1){
		perror("Error with pipe.");
		exit(EXIT_FAILURE);
	}
	pid = fork();
	if(pid == -1){
		perror("There was an error with piping fork.");
		exit(1);
	}
	//in child
	else if(pid ==0){
		//close stdin
		if(close(fd[0]) == -1){
			perror("Error with close in piping.");
			exit(1);
		}
		//save stdout
		if(dup2(fd[1],1)==-1){
			perror("Error with dup2 in piping.");
		}
		//execute
		if(execvp(argv[0], argv) == -1){
			perror("There was an error with execvp piping");
			exit(1);
		}
		else{
			exit(0);
		}
	}

	//in parent
	//save stdin
	int savestdin=dup(0);

	if((savestdin == -1))
		perror("There was an error with dup.");
	//close std out
	if(close(fd[1]) == -1){
		perror("Error with close in piping.");
		exit(1);
	}
	//make stdin with dup2
	if(dup2(fd[0],0) == -1){
		perror("Error with dup2 in piping.");
	}

	//make sure the parent waits
	if(wait(0) == -1)
		perror("There was an error in wait.");

	//while(waitpid(-1, &status, 0) >= 0);
	//check for pipes after we execute
	getPipes(afterPipe);

	if(dup2(savestdin,0)==-1){
		perror("Error with dup2 in piping.");
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by the SCons build script so their names
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION     3
#define MINOR_VERSION     2
#define BUILD_NUMBER      10
#define PATCH_LEVEL       1
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0

// Define SONAME to have the SCons build the put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the SCons build script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    OS::SNPrintF(str, "%d.%d.%d.%d%s%s",
                 GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
                 is_simulator);
  } else {
    OS::SNPrintF(str, "%d.%d.%d%s%s",
                 GetMajor(), GetMinor(), GetBuild(), candidate,
                 is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      OS::SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
                   GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      OS::SNPrintF(str, "libv8-%d.%d.%d%s.so",
                   GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    OS::SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<commit_msg>Update version to 3.2.10.2.<commit_after>// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by the SCons build script so their names
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION     3
#define MINOR_VERSION     2
#define BUILD_NUMBER      10
#define PATCH_LEVEL       2
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0

// Define SONAME to have the SCons build the put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the SCons build script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    OS::SNPrintF(str, "%d.%d.%d.%d%s%s",
                 GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
                 is_simulator);
  } else {
    OS::SNPrintF(str, "%d.%d.%d%s%s",
                 GetMajor(), GetMinor(), GetBuild(), candidate,
                 is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      OS::SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
                   GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      OS::SNPrintF(str, "libv8-%d.%d.%d%s.so",
                   GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    OS::SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<|endoftext|>


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

using namespace std;

void displayPrompt(){
    char *user = getlogin(); //I assign the login name to a user pointer
    if(user == NULL){
        perror("getlogin");
        exit(1);
    }

    char hostname[100]; //I allocate space for the hostname
    if(gethostname(hostname, sizeof(hostname)) == -1){ //checking for errors withostname
        perror("gethostname");
        exit(1);
    }

    cout << user << '@' << hostname << '$' << ' '; //here I output the user and hostanme to the screen.

}

int extractCommands(string &commandLine, char **cmds){
    const char* args = commandLine.c_str(); //the user input is converted to a const char* as we need it for execvp
    char* args_Mutatable = const_cast<char*>(args); //it needs to be mutable for us to tokenize it
    char *single_command;
    single_command = strtok(args_Mutatable, " ;&|"); //execute strtok with delimeters

    int numOfArgs = 0; //when you add one --> argv[1]

    while(single_command != NULL){
        //cout << single_command << endl;
        cmds[numOfArgs] = strdup(single_command); //this processes each command into the command array for execution
        /*cout << "at position " << numOfArgs << ": " << cmds[numOfArgs];
        cout << endl;*/
        single_command = strtok(NULL, " ;&|");
        numOfArgs++;
    }

    return numOfArgs;
}

int executeCommand(char **args){
    int pid = fork();

    if(pid == -1){
        perror("There was some error with fork()");
        exit(1);
    }
    else if(pid == 0){
        if(-1 == execvp(args[0], args)){
            perror("There was an error with execvp");
            exit(1);
        }
    }
    else if(pid > 0){
        if(-1 == wait(0)){
            perror("There was an error with wait()");
        }
    }

    return 0; //if everything goes well, return 0
}

int main(){
    string userInput; //command line in string format
    char *cmds[10000];
    do{
        displayPrompt(); //displays current user and hostname

        getline(cin, userInput); //get's input from user and stores it in a string

        //cout << userInput << endl; //NEED TO DELETE UPON COMPLETETION

        int numArgs = extractCommands(userInput, cmds); //retrieve number of arguments by parsing the string

        if(numArgs <= 0){continue;} //if there are no arguments, simply continue

        /*checks if first argument is exit and quits iff it's the only argument*/
        if( (strcmp(cmds[0], "exit") == 0) && (numArgs == 1) ) { break; }
        else{
            if(executeCommand(cmds) != 0){
                cout << "Error in executing commands" << endl;
            }
        }

        //break;
    }while(1);

    return 0;
}

<commit_msg>added NULL at the end of tokenizing function<commit_after>#include <iostream>
#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <limits>

using namespace std;

void displayPrompt(){
    char *user = getlogin(); //I assign the login name to a user pointer
    if(user == NULL){
        perror("getlogin");
        exit(1);
    }

    char hostname[100]; //I allocate space for the hostname
    if(gethostname(hostname, sizeof(hostname)) == -1){ //checking for errors withostname
        perror("gethostname");
        exit(1);
    }

    cout << user << '@' << hostname << '$' << ' '; //here I output the user and hostanme to the screen.

}

int extractCommands(string &commandLine, char **cmds){
    const char* args = commandLine.c_str(); //the user input is converted to a const char* as we need it for execvp
    char* args_Mutatable = const_cast<char*>(args); //it needs to be mutable for us to tokenize it
    char *single_command;
    single_command = strtok(args_Mutatable, " ;&|"); //execute strtok with delimeters

    int numOfArgs = 0; //when you add one --> argv[1]

    while(single_command != NULL){
        //cout << single_command << endl;
        cmds[numOfArgs] = strdup(single_command); //this processes each command into the command array for execution
        /*cout << "at position " << numOfArgs << ": " << cmds[numOfArgs];
        cout << endl;*/
        single_command = strtok(NULL, " ;&|");
        numOfArgs++;
    }

    cmds[numOfArgs] = NULL;
    return numOfArgs;
}

int executeCommand(char **args){
    int pid = fork();

    if(pid == -1){
        perror("There was some error with fork()");
        exit(1);
    }
    else if(pid == 0){
        if(-1 == execvp(args[0], args)){
            perror("There was an error with execvp");
            exit(1);
        }
    }
    else if(pid > 0){
        if(-1 == wait(0)){
            perror("There was an error with wait()");
        }
    }

    return 0; //if everything goes well, return 0
}

int main(){
    string userInput; //command line in string format
    char *cmds[10000];
    do{
        displayPrompt(); //displays current user and hostname

        getline(cin, userInput); //get's input from user and stores it in a string

        //cout << userInput << endl; //NEED TO DELETE UPON COMPLETETION

        int numArgs = extractCommands(userInput, cmds); //retrieve number of arguments by parsing the string

        if(numArgs <= 0){continue;} //if there are no arguments, simply continue to the next iteration

        /*checks if first argument is exit and quits iff it's the only argument*/
        if( (strcmp(cmds[0], "exit") == 0) && (numArgs == 1) ) { break; }

        if(executeCommand(cmds) != 0){
            cout << "Error in executing commands" << endl;
        }

    }while(1);

    return 0;
}

<|endoftext|>


<commit_before>#include "rshell.h"

#include <iostream>
#include <string>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <vector>
#include <sstream>

using namespace std;

//  Constructors
//  Default constructor (creates an Rshell object for commands)
Rshell::Rshell()
{}

//  Rshell functions
//  These functions takes command input from the user and parses them
//  parseCommand(string& input, char line[][], char **argv) -
//      parses out whitespace and puts charaters from string into array of char
void Rshell::parseCommand(string& input, char line[100][256],  char **argv)
{
    unsigned row = 0;
    unsigned col = 0;
    bool quote = false;     //  Has a flag if the argument is in quotations
    clearArray(line);       //  Cleans array

    //  Parses string into the array (takes out whitespace)
    for(unsigned i = 0; i < input.size(); ++i)
    {
        if(!quote)
        {
            if(input.at(i) == '#')  //  Finishes with a comment
            {
                break;
            }
            if((input.at(i) == ' ') || (input.at(i) == '\t') ||
                (input.at(i) == '\n'))  //  Replaces whitespace with ' ' if dne
            {
                if(col > 0 )
                {
                    if(line[row][col-1] != ' ')
                    {
                        line[row][col] = ' ';
                        ++col;
                    }
                }
            }
            else if(input.at(i) == ';')     //  Treat ';' as a newline
            {
                row++;
                col = 0;
            }
            else if(input.at(i) == '&')     //  Checks for &&
            {
                parseConnect(input, i, line, '&', row, col);
            }
            else if(input.at(i) == '|')     //  Checks for ||
            {
                parseConnect(input, i, line, '|', row, col);
            }
            else    //  Any other character
            {
                line[row][col] = input.at(i);
                col++;
                if(input.at(i) == '"')      //  Checks for "
                {
                    quote = true;
                }
            }
        }
        else    //  Character is in quotes
        {
            line[row][col] = input.at(i);
            col++;
            if(input.at(i) == '"')
            {
                quote = false;
            }
        }
    }

    //  Once all cmd retrieved->end array with last row having '\0'
    row++;
    //  line[row][0] = '\0';

    //  Prints out 2d array
    for(unsigned i = 0; line[i][0] != '\0'; ++i)
    {
        for(unsigned j = 0; line[i][j] != '\0'; ++j)
        {
            //  cout << line[i][j];
        }
        cout << line[i] << endl;
        //  cout << endl;
    }
    return;
}

//  void parseConnect(string&, unsigned, char [][], char, unsigned&, unsigned&)-
//      checks if an '&' or '|'  is a connector or not
void Rshell::parseConnect(string& input, unsigned pos, char line[100][256], char con, unsigned& row, unsigned& col)
{
    if(col == 1)
    {
        line[row][col] = input.at(pos);
        col++;
        if(line[row][0] == con)         //  if prev char is connector
        {
            row++;
            col = 0;
        }
    }
    else
    {
        if(input.at(pos + 1) == con)    //  if next char is connector
        {
            row++;
            col = 0;
        }
        line[row][col] = input.at(pos);
        col++;
    }
    return;
}

void Rshell::clearArray(char line[100][256])
{
    for(unsigned row = 0; row < 100; ++row)
    {
        for(unsigned col = 0; col < 256; ++col)
        {
            line[row][col] = '\0';
        }
    }
    return;
}

<commit_msg>updated rshell.cpp to not add space before connector<commit_after>#include "rshell.h"

#include <iostream>
#include <string>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <vector>
#include <sstream>

using namespace std;

//  Constructors
//  Default constructor (creates an Rshell object for commands)
Rshell::Rshell()
{}

//  Rshell functions
//  These functions takes command input from the user and parses them
//  parseCommand(string& input, char line[][], char **argv) -
//      parses out whitespace and puts charaters from string into array of char
void Rshell::parseCommand(string& input, char line[100][256],  char **argv)
{
    unsigned row = 0;
    unsigned col = 0;
    bool quote = false;     //  Has a flag if the argument is in quotations
    clearArray(line);       //  Cleans array

    //  Parses string into the array (takes out whitespace)
    for(unsigned i = 0; i < input.size(); ++i)
    {
        if(!quote)
        {
            if(input.at(i) == '#')  //  Finishes with a comment
            {
                break;
            }
            if((input.at(i) == ' ') || (input.at(i) == '\t') ||
                (input.at(i) == '\n'))  //  Replaces whitespace with ' ' if dne
            {
                if((col > 0) &&
                    !((input.at(i + 1) == '&') ||
                    (input.at(i + 1) == '|') ||
                    (input.at(i + 1) == ';')))  //  Makes sure !connector
                {
                    if(line[row][col-1] != ' ')
                    {
                        line[row][col] = ' ';
                        ++col;
                    }
                }
            }
            else if(input.at(i) == ';')     //  Treat ';' as a newline
            {
                row++;
                col = 0;
            }
            else if(input.at(i) == '&')     //  Checks for &&
            {
                parseConnect(input, i, line, '&', row, col);
            }
            else if(input.at(i) == '|')     //  Checks for ||
            {
                parseConnect(input, i, line, '|', row, col);
            }
            else    //  Any other character
            {
                line[row][col] = input.at(i);
                col++;
                if(input.at(i) == '"')      //  Checks for "
                {
                    quote = true;
                }
            }
        }
        else    //  Character is in quotes
        {
            line[row][col] = input.at(i);
            col++;
            if(input.at(i) == '"')
            {
                quote = false;
            }
        }
    }

    //  Once all cmd retrieved->end array with last row having '\0'
    row++;

    //  Prints out 2d array
    for(unsigned i = 0; line[i][0] != '\0'; ++i)
    {
        for(unsigned j = 0; line[i][j] != '\0'; ++j)
        {
            // cout << "Pos[" << i << "][" << j << "]: " << line[i][j] << endl;
        }
        cout << line[i] << endl;
        //  cout << endl;
    }
    return;
}

//  void parseConnect(string&, unsigned, char [][], char, unsigned&, unsigned&)-
//      checks if an '&' or '|'  is a connector or not
void Rshell::parseConnect(string& input, unsigned pos, char line[100][256], char con, unsigned& row, unsigned& col)
{
    if(col == 1)
    {
        line[row][col] = input.at(pos);
        col++;
        if(line[row][0] == con)         //  if prev char is connector
        {
            row++;
            col = 0;
        }
    }
    else
    {
        if(input.at(pos + 1) == con)    //  if next char is connector
        {
            row++;
            col = 0;
        }
        line[row][col] = input.at(pos);
        col++;
    }
    return;
}

void Rshell::clearArray(char line[100][256])
{
    for(unsigned row = 0; row < 100; ++row)
    {
        for(unsigned col = 0; col < 256; ++col)
        {
            line[row][col] = '\0';
        }
    }
    return;
}

<|endoftext|>


<commit_before>// RSHELL.CPP
// Main source code for rshell

//#define RSHELL_DEBUG

#include "unistd.h"
#include "sys/wait.h"
#include "stdio.h"
#include "errno.h"

#include <iostream>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/regex.hpp>

#include "rshell.h"

const char* CONN_AMP = "&&";
const char* CONN_PIPE = "||";
const char* CONN_SEMIC = ";";

/* Initialize environment */
void init() {}

/* Main loop - controls command line, parsing, and execution logic */
int run() {

    std::vector<std::string> tokens_conn;
    std::vector<std::string> tokens_word;
    std::string usr_input;
    int prev_exit_code = 0;

    while(true) {

        usr_input = prompt();

        tokens_conn = tokenize(usr_input, "(\\|\\||\\&\\&|;)");
        for(unsigned int i = 0; i < tokens_conn.size(); i++) {
//            std::cout << prev_exit_code << std::endl;
#ifdef RSHELL_DEBUG
            std::cout << "<" << tokens_conn.at(i) << ">" << std::endl;
#endif

            if(tokens_conn.at(i) == "") continue;

            // assumption: a connector token has no whitespace
            if(         tokens_conn.at(i) == std::string(CONN_AMP)) {
                if(prev_exit_code != 0  && i != 0) break;
                else if(i == 0) {
                    std::cout << "syntax error: unexpected token \"" << CONN_AMP << "\"\n";
                    break;
                } else continue;
            } else if(  tokens_conn.at(i) == std::string(CONN_PIPE)) {
                if(prev_exit_code == 0 && i != 0) break;
                else if(i == 0) {
                    std::cout << "syntax error: unexpected token \"" << CONN_PIPE << "\"\n";
                    break;
                } else continue;
            } else if(  tokens_conn.at(i) == std::string(CONN_SEMIC)) {
                if(i == 0)  {
                    std::cout << "syntax error: unexpected token \"" << CONN_SEMIC << "\"\n";
                    break;
                } else continue;
            }

            tokens_word = toksplit(tokens_conn.at(i), " ");
            for(unsigned int j = 0; j < tokens_word.size(); j++) {

                std::string word = tokens_word.at(j);
                // kill empty words
                if(word == "") tokens_word.erase(tokens_word.begin() + j);

                // using boost for convenience - this can be implemented manually
                boost::trim_if(word, boost::is_any_of(" \t"));
            }

            // if ls is invoked, add colors flag
            if(tokens_word.at(0) == "ls") tokens_word.push_back("--color");

            std::vector<char*> cmd_argv(tokens_word.size() + 1);
            for(unsigned int k = 0; k < tokens_word.size(); k++) {
               cmd_argv[k] = &tokens_word[k][0];
#ifdef RSHELL_DEBUG
               std::cout << "\t" << "<" << tokens_word.at(k) << ">" << std::endl;
#endif
            }

            // exit only if first word is "exit", after formatting
            if(tokens_word.at(0) == "exit") return 0;

            prev_exit_code = execute(cmd_argv[0], cmd_argv.data());

            // if execvp returned and had error, stop the process
          //  if(err_num == 1) return 1;
        }
    }

    return 0;
}

/* Prints prompt text and takes in raw command line input */
std::string prompt() {

    char hostname[HOST_NAME_MAX];
    if(gethostname(hostname, HOST_NAME_MAX) == -1)
        perror("gethostname");

    std::cout << getlogin() << "@" << hostname;
    std::cout << "$ " << std::flush;

    std::string input_raw;
    std::getline(std::cin, input_raw);

    return input_raw;
}

/* fork and exec a program, complete error checking */
int execute(const char* path, char* const argv[]) {

#ifdef RSHELL_DEBUG
    std::cout << "executing " << path << std::endl;
#endif

    int pid = fork();

#ifdef RSHELL_DEBUG
    std::cout << "created process with id " << pid << std::endl;
#endif

    if(pid == -1) {
        perror("fork");
        return -1;
    } else if(pid == 0) {
        execvp(path, argv);
        perror(path);
        exit(1);
    } else {

        int exit_code;

        // pass exit code along
        if(waitpid(pid, &exit_code, 0) == -1) perror("waitpid");
        return exit_code;
    }

    return 0;
}

/* Overload to tokenize by whitespace */
std::vector<std::string> tokenize(std::string s) {
    return tokenize(s, "\\s");
}

/* Tokenize a string using boost regex */
std::vector<std::string> tokenize(std::string s, std::string r) {

    std::vector<std::string> token_vec;

//    boost::algorithm::split_regex(token_vec, s, boost::regex(r));

    // This part's hacky - it does a secondary regex on the string to
    //  search for connectors, then inserts them in between tokens.
    std::string::const_iterator s_start, s_end;
    s_start = s.begin();
    s_end = s.end();

    boost::match_results<std::string::const_iterator> results;
    boost::match_flag_type flags = boost::match_default;
    while(boost::regex_search(s_start, s_end, results, boost::regex(r), flags)) {

        token_vec.push_back(std::string(s_start, results[0].first));
        token_vec.push_back(results[0]);

        s_start = results[0].second;
        flags |= boost::match_prev_avail;
        flags |= boost::match_not_bob;
    }

    token_vec.push_back(std::string(s_start, s_end));

    // scrub vector of empty fields

    for(unsigned int i = 0; i < token_vec.size(); i++) {
#ifdef RSHELL_DEBUG
        std::cout << "[" << token_vec.at(i) << "]" << std::endl;
#endif
        if(token_vec.at(i) == "") token_vec.erase(token_vec.begin() + i);
    }

    return token_vec;
}

/* Tokenize a string using boost split */
std::vector<std::string> toksplit(std::string s, std::string toks) {

    std::vector<std::string> token_vec;
    boost::split(token_vec, s, boost::is_any_of(toks), boost::token_compress_on);
    return token_vec;
}
<commit_msg>removed misleading comments<commit_after>// RSHELL.CPP
// Main source code for rshell

//#define RSHELL_DEBUG

#include "unistd.h"
#include "sys/wait.h"
#include "stdio.h"
#include "errno.h"

#include <iostream>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/regex.hpp>

#include "rshell.h"

const char* CONN_AMP = "&&";
const char* CONN_PIPE = "||";
const char* CONN_SEMIC = ";";

/* Initialize environment */
void init() {}

/* Main loop - controls command line, parsing, and execution logic */
int run() {

    std::vector<std::string> tokens_conn;
    std::vector<std::string> tokens_word;
    std::string usr_input;
    int prev_exit_code = 0;

    while(true) {

        usr_input = prompt();

        tokens_conn = tokenize(usr_input, "(\\|\\||\\&\\&|;)");
        for(unsigned int i = 0; i < tokens_conn.size(); i++) {
//            std::cout << prev_exit_code << std::endl;
#ifdef RSHELL_DEBUG
            std::cout << "<" << tokens_conn.at(i) << ">" << std::endl;
#endif

            if(tokens_conn.at(i) == "") continue;

            // assumption: a connector token has no whitespace
            if(         tokens_conn.at(i) == std::string(CONN_AMP)) {
                if(prev_exit_code != 0  && i != 0) break;
                else if(i == 0) {
                    std::cout << "syntax error: unexpected token \"" << CONN_AMP << "\"\n";
                    break;
                } else continue;
            } else if(  tokens_conn.at(i) == std::string(CONN_PIPE)) {
                if(prev_exit_code == 0 && i != 0) break;
                else if(i == 0) {
                    std::cout << "syntax error: unexpected token \"" << CONN_PIPE << "\"\n";
                    break;
                } else continue;
            } else if(  tokens_conn.at(i) == std::string(CONN_SEMIC)) {
                if(i == 0)  {
                    std::cout << "syntax error: unexpected token \"" << CONN_SEMIC << "\"\n";
                    break;
                } else continue;
            }

            tokens_word = toksplit(tokens_conn.at(i), " ");
            for(unsigned int j = 0; j < tokens_word.size(); j++) {

                std::string word = tokens_word.at(j);
                // kill empty words
                if(word == "") tokens_word.erase(tokens_word.begin() + j);

                // using boost for convenience - this can be implemented manually
                boost::trim_if(word, boost::is_any_of(" \t"));
            }

            // if ls is invoked, add colors flag
            if(tokens_word.at(0) == "ls") tokens_word.push_back("--color");

            std::vector<char*> cmd_argv(tokens_word.size() + 1);
            for(unsigned int k = 0; k < tokens_word.size(); k++) {
               cmd_argv[k] = &tokens_word[k][0];
#ifdef RSHELL_DEBUG
               std::cout << "\t" << "<" << tokens_word.at(k) << ">" << std::endl;
#endif
            }

            // exit only if first word is "exit", after formatting
            if(tokens_word.at(0) == "exit") return 0;

            prev_exit_code = execute(cmd_argv[0], cmd_argv.data());

            // if execvp returned and had error, stop the process
          //  if(err_num == 1) return 1;
        }
    }

    return 0;
}

/* Prints prompt text and takes in raw command line input */
std::string prompt() {

    char hostname[HOST_NAME_MAX];
    if(gethostname(hostname, HOST_NAME_MAX) == -1)
        perror("gethostname");

    std::cout << getlogin() << "@" << hostname;
    std::cout << "$ " << std::flush;

    std::string input_raw;
    std::getline(std::cin, input_raw);

    return input_raw;
}

/* fork and exec a program, complete error checking */
int execute(const char* path, char* const argv[]) {

#ifdef RSHELL_DEBUG
    std::cout << "executing " << path << std::endl;
#endif

    int pid = fork();

#ifdef RSHELL_DEBUG
    std::cout << "created process with id " << pid << std::endl;
#endif

    if(pid == -1) {
        perror("fork");
        return -1;
    } else if(pid == 0) {
        execvp(path, argv);
        perror(path);
        exit(1);
    } else {

        int exit_code;

        // pass exit code along
        if(waitpid(pid, &exit_code, 0) == -1) perror("waitpid");
        return exit_code;
    }

    return 0;
}

/* Overload to tokenize by whitespace */
std::vector<std::string> tokenize(std::string s) {
    return tokenize(s, "\\s");
}

/* Tokenize a string using boost regex */
std::vector<std::string> tokenize(std::string s, std::string r) {

    std::vector<std::string> token_vec;

//    boost::algorithm::split_regex(token_vec, s, boost::regex(r));

    std::string::const_iterator s_start, s_end;
    s_start = s.begin();
    s_end = s.end();

    boost::match_results<std::string::const_iterator> results;
    boost::match_flag_type flags = boost::match_default;
    while(boost::regex_search(s_start, s_end, results, boost::regex(r), flags)) {

        token_vec.push_back(std::string(s_start, results[0].first));
        token_vec.push_back(results[0]);

        s_start = results[0].second;
        flags |= boost::match_prev_avail;
        flags |= boost::match_not_bob;
    }

    token_vec.push_back(std::string(s_start, s_end));

    // scrub vector of empty fields

    for(unsigned int i = 0; i < token_vec.size(); i++) {
#ifdef RSHELL_DEBUG
        std::cout << "[" << token_vec.at(i) << "]" << std::endl;
#endif
        if(token_vec.at(i) == "") token_vec.erase(token_vec.begin() + i);
    }

    return token_vec;
}

/* Tokenize a string using boost split */
std::vector<std::string> toksplit(std::string s, std::string toks) {

    std::vector<std::string> token_vec;
    boost::split(token_vec, s, boost::is_any_of(toks), boost::token_compress_on);
    return token_vec;
}
<|endoftext|>


<commit_before>#include "eval.hpp"

#include <vector>

#include "sexpr.hpp"

builtin::builtin(std::size_t argc, func_type func)
  : func(func),
    argc(argc) {

}

builtin::builtin(const builtin&) = default;
builtin::builtin(builtin&&) = default;

static value eval(const ref<env>& e, const ast::io& self);

value apply(const value& func, const value* first, const value* last) {
  return func.match<value>
	([&](const lambda& self) {
      return eval(augment(self.scope, self.args, first, last), *self.body);
    },
	  [&](const builtin& self) {
		return self.func(first);
	  },
	  [&](value) -> value {
		throw std::runtime_error("type error in application");
	  } );
}

struct eval_visitor {

  template<class T>
  T operator()(const ast::lit<T>& self, const ref<env>& ) const {
	return self.value;
  }

  value operator()(const ast::var& self, const ref<env>& e) const {
	try {
	  return e->find(self.name);
	} catch(std::out_of_range& e) {
	  throw std::runtime_error(e.what());
	}
  }

  value operator()(const ast::app& self, const ref<env>& e) const {
	const value func = eval(e, *self.func);

    std::vector<value> args;
    foldl(unit(), self.args, [&](unit, const ast::expr& self) {
        args.emplace_back(eval(e, self));
        return unit();
      });

    return apply(func, args.data(), args.data() + args.size());
  }

  value operator()(const ast::abs& self, const ref<env>& e) const {
    std::vector<symbol> args;
    for(symbol s : self.args) {
      args.push_back(s);
    }

	return lambda{args, self.body, e};
  }

  value operator()(const ast::seq& self, const ref<env>& e) const {
	const value init = unit();
	return foldl(init, self.items,
				 [&](const value&, const ast::io& self) -> value {
				   return eval(e, self);
				 });
  }

  value operator()(const ast::def& self, const ref<env>& e) const {
	// note: the type system will keep us from evaluating side effects if the
	// variable is already defined
	auto res = e->locals.emplace(self.name, eval(e, self.value));
	if(!res.second) {
	  throw std::runtime_error("redefined variable " + tool::quote(self.name.get()));
	}

	return unit();
  }

  value operator()(const ast::cond& self, const ref<env>& e) const {
    const value test = eval(e, *self.test);
    if(auto b = test.get<boolean>()) {
      if(*b) return eval(e, *self.conseq);
      else return eval(e, *self.alt);
    } else throw std::runtime_error("condition must be boolean");
  }

  value operator()(const ast::io& self, const ref<env>& e) const {
	return self.visit<value>(eval_visitor(), e);
  }

  value operator()(const ast::expr& self, const ref<env>& e) const {
	return self.visit<value>(eval_visitor(), e);
  }

  value operator()(const ast::record& self, const ref<env>& e) const {
    record res;
    foldl(unit(), self.attrs, [&](unit, const ast::record::attribute& attr) {
      res.attrs.emplace(attr.name, eval(e, attr.value));
      return unit();
    });
    return res;
  }

  value operator()(const ast::sel& self, const ref<env>& e) const {
    const symbol name = self.name;
    return builtin(1, [name](const value* args) -> value {
      return args[0].cast<record>().attrs.at(name);
      // return args[0].cast<record>().attrs.find(name)->second;
    });
  }

  template<class T>
  value operator()(const T& self, const ref<env>& e) const {
	throw std::logic_error("eval unimplemented: " + tool::type_name(typeid(T)));
  }

};

static value eval(const ref<env>& e, const ast::io& self) {
  return self.visit<value>(eval_visitor(), e);
}

value eval(const ref<env>& e, const ast::expr& self) {
  return self.visit<value>(eval_visitor(), e);
}

value eval(const ref<env>& e, const ast::toplevel& self) {
  return self.visit<value>(eval_visitor(), e);
}

namespace {
struct ostream {
  template<class T>
  void operator()(const T& self, std::ostream& out) const {
	out << self;
  }

  void operator()(const lambda& self, std::ostream& out) const {
	out << "#<lambda>";
  }

  void operator()(const builtin& self, std::ostream& out) const {
	out << "#<builtin>";
  }

  void operator()(const unit& self, std::ostream& out) const {
	out << "()";
  }

  void operator()(const boolean& self, std::ostream& out) const {
	out << (self ? "true" : "false");
  }

  void operator()(const integer& self, std::ostream& out) const {
    out << self; //  << "i";
  }

  void operator()(const real& self, std::ostream& out) const {
    out << self; // << "d";
  }

  void operator()(const record& self, std::ostream& out) const {
    out << "{";
    bool first = true;
    for(const auto& it : self.attrs) {
      if(first) first = false;
      else out << "; ";
      out << it.first << ": " << it.second;
    }
    out << "}";
  }

};
}

std::ostream& operator<<(std::ostream& out, const value& self) {
  self.visit(ostream(), out);
  return out;
}
<commit_msg>towards currying<commit_after>#include "eval.hpp"

#include <vector>

#include "sexpr.hpp"

builtin::builtin(std::size_t argc, func_type func)
  : func(func),
    argc(argc) {

}

builtin::builtin(const builtin&) = default;
builtin::builtin(builtin&&) = default;

static value eval(const ref<env>& e, const ast::io& self);

value apply(const value& func, const value* first, const value* last) {
  const std::size_t argc = last - first;

  return func.match<value>
	([&](const lambda& self) {
      if(argc < self.args.size()) {
        // unsaturated call: build lambda/builtin
        throw std::runtime_error("unimplemented: un-saturated calls");
      }

      if(argc > self.args.size()) {
        // over-saturated call: call result with args
        throw std::runtime_error("unimplemented: over-saturated calls");
      }

      // saturated call
      return eval(augment(self.scope, self.args, first, last), *self.body);
    },
	  [&](const builtin& self) {
        if(argc < self.argc) {
          // unsaturated call: build lambda/builtin
          throw std::runtime_error("unimplemented: un-saturated calls");
        }

        if(argc > self.argc) {
          // over-saturated call: call result with args
          throw std::runtime_error("unimplemented: over-saturated calls");
        }

        // saturated call
        return self.func(first);
	  },
	  [&](value) -> value {
		throw std::runtime_error("type error in application");
	  } );
}

struct eval_visitor {

  template<class T>
  T operator()(const ast::lit<T>& self, const ref<env>& ) const {
	return self.value;
  }

  value operator()(const ast::var& self, const ref<env>& e) const {
	try {
	  return e->find(self.name);
	} catch(std::out_of_range& e) {
	  throw std::runtime_error(e.what());
	}
  }

  value operator()(const ast::app& self, const ref<env>& e) const {
	const value func = eval(e, *self.func);

    std::vector<value> args;
    foldl(unit(), self.args, [&](unit, const ast::expr& self) {
        args.emplace_back(eval(e, self));
        return unit();
      });

    return apply(func, args.data(), args.data() + args.size());
  }

  value operator()(const ast::abs& self, const ref<env>& e) const {
    std::vector<symbol> args;
    for(symbol s : self.args) {
      args.push_back(s);
    }

	return lambda{args, self.body, e};
  }

  value operator()(const ast::seq& self, const ref<env>& e) const {
	const value init = unit();
	return foldl(init, self.items,
				 [&](const value&, const ast::io& self) -> value {
				   return eval(e, self);
				 });
  }

  value operator()(const ast::def& self, const ref<env>& e) const {
	// note: the type system will keep us from evaluating side effects if the
	// variable is already defined
	auto res = e->locals.emplace(self.name, eval(e, self.value));
	if(!res.second) {
	  throw std::runtime_error("redefined variable " + tool::quote(self.name.get()));
	}

	return unit();
  }

  value operator()(const ast::cond& self, const ref<env>& e) const {
    const value test = eval(e, *self.test);
    if(auto b = test.get<boolean>()) {
      if(*b) return eval(e, *self.conseq);
      else return eval(e, *self.alt);
    } else throw std::runtime_error("condition must be boolean");
  }

  value operator()(const ast::io& self, const ref<env>& e) const {
	return self.visit<value>(eval_visitor(), e);
  }

  value operator()(const ast::expr& self, const ref<env>& e) const {
	return self.visit<value>(eval_visitor(), e);
  }

  value operator()(const ast::record& self, const ref<env>& e) const {
    record res;
    foldl(unit(), self.attrs, [&](unit, const ast::record::attribute& attr) {
      res.attrs.emplace(attr.name, eval(e, attr.value));
      return unit();
    });
    return res;
  }

  value operator()(const ast::sel& self, const ref<env>& e) const {
    const symbol name = self.name;
    return builtin(1, [name](const value* args) -> value {
      return args[0].cast<record>().attrs.at(name);
      // return args[0].cast<record>().attrs.find(name)->second;
    });
  }

  template<class T>
  value operator()(const T& self, const ref<env>& e) const {
	throw std::logic_error("eval unimplemented: " + tool::type_name(typeid(T)));
  }

};

static value eval(const ref<env>& e, const ast::io& self) {
  return self.visit<value>(eval_visitor(), e);
}

value eval(const ref<env>& e, const ast::expr& self) {
  return self.visit<value>(eval_visitor(), e);
}

value eval(const ref<env>& e, const ast::toplevel& self) {
  return self.visit<value>(eval_visitor(), e);
}

namespace {
struct ostream {
  template<class T>
  void operator()(const T& self, std::ostream& out) const {
	out << self;
  }

  void operator()(const lambda& self, std::ostream& out) const {
	out << "#<lambda>";
  }

  void operator()(const builtin& self, std::ostream& out) const {
	out << "#<builtin>";
  }

  void operator()(const unit& self, std::ostream& out) const {
	out << "()";
  }

  void operator()(const boolean& self, std::ostream& out) const {
	out << (self ? "true" : "false");
  }

  void operator()(const integer& self, std::ostream& out) const {
    out << self; //  << "i";
  }

  void operator()(const real& self, std::ostream& out) const {
    out << self; // << "d";
  }

  void operator()(const record& self, std::ostream& out) const {
    out << "{";
    bool first = true;
    for(const auto& it : self.attrs) {
      if(first) first = false;
      else out << "; ";
      out << it.first << ": " << it.second;
    }
    out << "}";
  }

};
}

std::ostream& operator<<(std::ostream& out, const value& self) {
  self.visit(ostream(), out);
  return out;
}
<|endoftext|>


<commit_before>#include <tree_sitter/parser.h>
#include <stdint.h>
#include <vector>

using std::vector;

enum TokenType {
  NEWLINE,
  INDENT,
  DEDENT
};

struct Scanner {
  Scanner() : queued_dedent_count(0) {
    indent_length_stack.push_back(0);
  }

  void reset() {
    queued_dedent_count = 0;
    indent_length_stack.clear();
    indent_length_stack.push_back(0);
  }

  bool serialize(TSExternalTokenState state) {
    size_t i = 0;

    if (queued_dedent_count > UINT8_MAX) return false;
    state[i++] = queued_dedent_count;

    if (indent_length_stack.size() > UINT8_MAX) return false;
    state[i++] = indent_length_stack.size();

    vector<uint16_t>::iterator iter = indent_length_stack.begin(),
      end = indent_length_stack.end();

    for (; iter != end; ++iter) {
      if (*iter > UINT8_MAX) return false;
      state[i++] = *iter;
    }

    return true;
  }

  void deserialize(TSExternalTokenState state) {
    size_t i = 0;

    queued_dedent_count = state[i++];

    size_t indent_length_stack_size = state[i++];
    indent_length_stack.clear();
    for (size_t j = 0; j < indent_length_stack_size; j++) {
      indent_length_stack.push_back(state[i++]);
    }
  }

  void advance(TSLexer *lexer) {
    lexer->advance(lexer, false);
  }

  bool scan(TSLexer *lexer, const bool *valid_symbols) {
    if (valid_symbols[DEDENT] && queued_dedent_count > 0) {
      queued_dedent_count--;
      lexer->result_symbol = DEDENT;
      return true;
    }

    if (lexer->lookahead != '\n') return false;
    advance(lexer);

    uint32_t indent_length = 0;
    for (;;) {
      if (lexer->lookahead == '\n') {
        indent_length = 0;
        advance(lexer);
      } else if (lexer->lookahead == ' ') {
        indent_length++;
        advance(lexer);
      } else {
        break;
      }
    }

    if (indent_length > indent_length_stack.back()) {
      indent_length_stack.push_back(indent_length);
      lexer->result_symbol = INDENT;
      return true;
    }

    if (indent_length < indent_length_stack.back()) {
      indent_length_stack.pop_back();
      while (indent_length < indent_length_stack.back()) {
        indent_length_stack.pop_back();
        queued_dedent_count++;
      }

      if (valid_symbols[DEDENT]) {
        lexer->result_symbol = DEDENT;
        return true;
      } else {
        queued_dedent_count++;
      }
    }

    if (valid_symbols[NEWLINE]) {
      lexer->result_symbol = NEWLINE;
      return true;
    }

    return false;
  }

  vector<uint16_t> indent_length_stack;
  uint32_t queued_dedent_count;
};

extern "C" {

void *ts_language_python_external_scanner_create() {
  return new Scanner();
}

bool ts_language_python_external_scanner_scan(void *payload, TSLexer *lexer,
                                            const bool *valid_symbols) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->scan(lexer, valid_symbols);
}

void ts_language_python_external_scanner_reset(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->reset();
}

bool ts_language_python_external_scanner_serialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->serialize(state);
}

void ts_language_python_external_scanner_deserialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->deserialize(state);
}

void ts_language_python_external_scanner_destroy(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  delete scanner;
}

}
<commit_msg>Ok, try <limits><commit_after>#include <tree_sitter/parser.h>
#include <limits>
#include <vector>

using std::vector;

enum TokenType {
  NEWLINE,
  INDENT,
  DEDENT
};

struct Scanner {
  Scanner() : queued_dedent_count(0) {
    indent_length_stack.push_back(0);
  }

  void reset() {
    queued_dedent_count = 0;
    indent_length_stack.clear();
    indent_length_stack.push_back(0);
  }

  bool serialize(TSExternalTokenState state) {
    size_t i = 0;

    if (queued_dedent_count > UINT8_MAX) return false;
    state[i++] = queued_dedent_count;

    if (indent_length_stack.size() > 14) return false;
    state[i++] = indent_length_stack.size();

    vector<uint16_t>::iterator iter = indent_length_stack.begin(),
      end = indent_length_stack.end();

    for (; iter != end; ++iter) {
      if (*iter > UINT8_MAX) return false;
      state[i++] = *iter;
    }

    return true;
  }

  void deserialize(TSExternalTokenState state) {
    size_t i = 0;

    queued_dedent_count = state[i++];

    size_t indent_length_stack_size = state[i++];
    indent_length_stack.clear();
    for (size_t j = 0; j < indent_length_stack_size; j++) {
      indent_length_stack.push_back(state[i++]);
    }
  }

  void advance(TSLexer *lexer) {
    lexer->advance(lexer, false);
  }

  bool scan(TSLexer *lexer, const bool *valid_symbols) {
    if (valid_symbols[DEDENT] && queued_dedent_count > 0) {
      queued_dedent_count--;
      lexer->result_symbol = DEDENT;
      return true;
    }

    if (lexer->lookahead != '\n') return false;
    advance(lexer);

    uint32_t indent_length = 0;
    for (;;) {
      if (lexer->lookahead == '\n') {
        indent_length = 0;
        advance(lexer);
      } else if (lexer->lookahead == ' ') {
        indent_length++;
        advance(lexer);
      } else {
        break;
      }
    }

    if (indent_length > indent_length_stack.back()) {
      indent_length_stack.push_back(indent_length);
      lexer->result_symbol = INDENT;
      return true;
    }

    if (indent_length < indent_length_stack.back()) {
      indent_length_stack.pop_back();
      while (indent_length < indent_length_stack.back()) {
        indent_length_stack.pop_back();
        queued_dedent_count++;
      }

      if (valid_symbols[DEDENT]) {
        lexer->result_symbol = DEDENT;
        return true;
      } else {
        queued_dedent_count++;
      }
    }

    if (valid_symbols[NEWLINE]) {
      lexer->result_symbol = NEWLINE;
      return true;
    }

    return false;
  }

  vector<uint16_t> indent_length_stack;
  uint32_t queued_dedent_count;
};

extern "C" {

void *ts_language_python_external_scanner_create() {
  return new Scanner();
}

bool ts_language_python_external_scanner_scan(void *payload, TSLexer *lexer,
                                            const bool *valid_symbols) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->scan(lexer, valid_symbols);
}

void ts_language_python_external_scanner_reset(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->reset();
}

bool ts_language_python_external_scanner_serialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->serialize(state);
}

void ts_language_python_external_scanner_deserialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->deserialize(state);
}

void ts_language_python_external_scanner_destroy(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  delete scanner;
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <shlwapi.h>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_util.h"
#include "base/trace_event.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/breakpad_win.h"
#include "chrome/app/client_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/util_constants.h"

namespace {
// The entry point signature of chrome.dll.
typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);

typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();

// Not generic, we only handle strings up to 128 chars.
bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
  BYTE out[128 * sizeof(wchar_t)];
  DWORD size = sizeof(out);
  DWORD type = 0;
  if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
    return false;
  if (type != REG_SZ)
    return false;
  value->assign(reinterpret_cast<wchar_t*>(out));
  return true;
}

// Gets chrome version according to the load path. |exe_path| must be the
// backslash terminated directory of the current chrome.exe.
bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
                std::wstring* version) {
  HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
                                                            HKEY_LOCAL_MACHINE;
  HKEY key;
  if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
    return false;

  // If 'new_chrome.exe' is present it means chrome was auto-updated while
  // running. We need to consult the opv value so we can load the old dll.
  // TODO(cpu) : This is solving the same problem as the environment variable
  // so one of them will eventually be deprecated.
  std::wstring new_chrome_exe(exe_path);
  new_chrome_exe.append(installer_util::kChromeNewExe);
  if (::PathFileExistsW(new_chrome_exe.c_str()) &&
      ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
    ::RegCloseKey(key);
    return true;
  }

  bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
  ::RegCloseKey(key);
  return ret;
}

// Gets the path of the current exe with a trailing backslash.
std::wstring GetExecutablePath() {
  wchar_t path[MAX_PATH];
  ::GetModuleFileNameW(NULL, path, MAX_PATH);
  if (!::PathRemoveFileSpecW(path))
    return std::wstring();
  std::wstring exe_path(path);
  return exe_path.append(L"\\");
}

// Expects that |dir| has a trailing backslash. |dir| is modified so it
// contains the full path that was tried. Caller must check for the return
// value not being null to dermine if this path contains a valid dll.
HMODULE LoadChromeWithDirectory(std::wstring* dir) {
  ::SetCurrentDirectoryW(dir->c_str());
  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
#ifdef _WIN64
  if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClBrokerProcess) ||
      (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClLoaderProcess)) {
    // Load the 64-bit DLL when running in a 64-bit process.
    dir->append(installer_util::kChromeNaCl64Dll);
  } else {
    // Only NaCl broker and loader can be launched as Win64 processes.
    NOTREACHED();
    return NULL;
  }
#else
  dir->append(installer_util::kChromeDll);
#endif

#ifdef NDEBUG
  // Experimental pre-reading optimization
  // The idea is to pre read significant portion of chrome.dll in advance
  // so that subsequent hard page faults are avoided.
  if (!cmd_line.HasSwitch(switches::kProcessType)) {
    // The kernel brings in 8 pages for the code section at a time and 4 pages
    // for other sections. We can skip over these pages to avoid a soft page
    // fault which may not occur during code execution. However skipping 4K at
    // a time still has better performance over 32K and 16K according to data.
    // TODO(ananta)
    // Investigate this and tune.
    const size_t kStepSize = 4 * 1024;

    DWORD pre_read_size = 0;
    DWORD pre_read_step_size = kStepSize;
    DWORD pre_read = 1;

    HKEY key = NULL;
    if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
                       0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
      DWORD unused = sizeof(pre_read_size);
      RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
      RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
      RegQueryValueEx(key, L"PreRead", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read), &unused);
      RegCloseKey(key);
      key = NULL;
    }
    if (pre_read) {
      TRACE_EVENT_BEGIN("PreReadImage", 0, "");
      file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
      TRACE_EVENT_END("PreReadImage", 0, "");
    }
  }
#endif  // NDEBUG

  return ::LoadLibraryExW(dir->c_str(), NULL,
                          LOAD_WITH_ALTERED_SEARCH_PATH);
}

// Set did_run "dr" in omaha's client state for this product.
bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
  std::wstring key_path(google_update::kRegPathClientState);
  key_path.append(L"\\").append(guid);
  HKEY reg_key;
  if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
                        REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
                        &reg_key, NULL) == ERROR_SUCCESS) {
    // Note that the length here must be in bytes and must account for the
    // terminating null char.
    ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
                     reinterpret_cast<const BYTE *>(value),
                     (::lstrlenW(value) + 1) * sizeof(wchar_t));
    ::RegCloseKey(reg_key);
    return true;
  }
  return false;
}

bool RecordDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"1");
}

bool ClearDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"0");
}

}
//=============================================================================

MainDllLoader::MainDllLoader() : dll_(NULL) {
}

MainDllLoader::~MainDllLoader() {
#ifdef PURIFY
  // We should never unload the dll. There is only risk and no gain from
  // doing so. The singleton dtors have been already run by AtExitManager.
  ::FreeLibrary(dll_);
#endif
}

// Loading chrome is an interesting afair. First we try loading from the current
// directory to support run-what-you-compile and other development scenarios.
// If that fails then we look at the 'CHROME_VERSION' env variable to determine
// if we should stick with an older dll version even if a new one is available
// to support upgrade-in-place scenarios, and if that fails we finally we look
// at the registry which should point us to the latest version.
HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
  std::wstring dir(GetExecutablePath());
  *file = dir;
  HMODULE dll = LoadChromeWithDirectory(file);
  if (dll)
    return dll;

  scoped_ptr<base::Environment> env(base::Environment::Create());

  std::string version_value;
  if (!env->GetVar(WideToUTF8(
          BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
          &version_value)) {
    std::wstring reg_path(GetRegistryPath());

    *version = UTF8ToWide(version_value);
    // Look into the registry to find the latest version.
    if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
      return NULL;
  }

  *file = dir;
  file->append(*version).append(L"\\");
  return LoadChromeWithDirectory(file);
}

// Launching is a matter of loading the right dll, setting the CHROME_VERSION
// environment variable and just calling the entry point. Derived classes can
// add custom code in the OnBeforeLaunch callback.
int MainDllLoader::Launch(HINSTANCE instance,
                          sandbox::SandboxInterfaceInfo* sbox_info) {
  std::wstring version;
  std::wstring file;
  dll_ = Load(&version, &file);
  if (!dll_)
    return ResultCodes::MISSING_DATA;

  scoped_ptr<base::Environment> env(base::Environment::Create());
  env->SetVar(WideToUTF8(
      BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
      WideToUTF8(version));

  InitCrashReporterWithDllPath(file);
  OnBeforeLaunch(version);

  DLL_MAIN entry_point =
      reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
  if (!entry_point)
    return ResultCodes::BAD_PROCESS_TYPE;

  int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
  return OnBeforeExit(rc);
}

void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
  RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
      reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
          ::GetProcAddress(dll_,
                           "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
  if (!relaunch_function) {
    LOG(ERROR) << "Could not find exported function "
               << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
  } else {
    relaunch_function();
  }
}

//=============================================================================

class ChromeDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    std::wstring key(google_update::kRegPathClients);
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    key.append(L"\\").append(dist->GetAppGuid());
    return key;
  }

  virtual void OnBeforeLaunch(const std::wstring& version) {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    RecordDidRun(dist->GetAppGuid().c_str());
  }

  virtual int OnBeforeExit(int return_code) {
    // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
    // so we need to reset the did_run signal so omaha does not count
    // this run as active usage.
    if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
      BrowserDistribution* dist = BrowserDistribution::GetDistribution();
      ClearDidRun(dist->GetAppGuid().c_str());
    }
    return return_code;
  }
};

//=============================================================================

class ChromiumDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    return dist->GetVersionKey();
  }
};

MainDllLoader* MakeMainDllLoader() {
#if defined(GOOGLE_CHROME_BUILD)
  return new ChromeDllLoader();
#else
  return new ChromiumDllLoader();
#endif
}
<commit_msg>Revert 56978 - Use Environment::GetVar instead of the obscure EnvQueryStr function.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <shlwapi.h>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_util.h"
#include "base/trace_event.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/breakpad_win.h"
#include "chrome/app/client_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/util_constants.h"

namespace {
// The entry point signature of chrome.dll.
typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);

typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();

// Not generic, we only handle strings up to 128 chars.
bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
  BYTE out[128 * sizeof(wchar_t)];
  DWORD size = sizeof(out);
  DWORD type = 0;
  if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
    return false;
  if (type != REG_SZ)
    return false;
  value->assign(reinterpret_cast<wchar_t*>(out));
  return true;
}

// Gets chrome version according to the load path. |exe_path| must be the
// backslash terminated directory of the current chrome.exe.
bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
                std::wstring* version) {
  HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
                                                            HKEY_LOCAL_MACHINE;
  HKEY key;
  if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
    return false;

  // If 'new_chrome.exe' is present it means chrome was auto-updated while
  // running. We need to consult the opv value so we can load the old dll.
  // TODO(cpu) : This is solving the same problem as the environment variable
  // so one of them will eventually be deprecated.
  std::wstring new_chrome_exe(exe_path);
  new_chrome_exe.append(installer_util::kChromeNewExe);
  if (::PathFileExistsW(new_chrome_exe.c_str()) &&
      ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
    ::RegCloseKey(key);
    return true;
  }

  bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
  ::RegCloseKey(key);
  return ret;
}

// Gets the path of the current exe with a trailing backslash.
std::wstring GetExecutablePath() {
  wchar_t path[MAX_PATH];
  ::GetModuleFileNameW(NULL, path, MAX_PATH);
  if (!::PathRemoveFileSpecW(path))
    return std::wstring();
  std::wstring exe_path(path);
  return exe_path.append(L"\\");
}

// Not generic, we only handle strings up to 128 chars.
bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
  wchar_t out[128];
  DWORD count = sizeof(out)/sizeof(out[0]);
  DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
  if ((rv == 0) || (rv >= count))
    return false;
  *value = out;
  return true;
}

// Expects that |dir| has a trailing backslash. |dir| is modified so it
// contains the full path that was tried. Caller must check for the return
// value not being null to dermine if this path contains a valid dll.
HMODULE LoadChromeWithDirectory(std::wstring* dir) {
  ::SetCurrentDirectoryW(dir->c_str());
  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
#ifdef _WIN64
  if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClBrokerProcess) ||
      (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
      switches::kNaClLoaderProcess)) {
    // Load the 64-bit DLL when running in a 64-bit process.
    dir->append(installer_util::kChromeNaCl64Dll);
  } else {
    // Only NaCl broker and loader can be launched as Win64 processes.
    NOTREACHED();
    return NULL;
  }
#else
  dir->append(installer_util::kChromeDll);
#endif

#ifdef NDEBUG
  // Experimental pre-reading optimization
  // The idea is to pre read significant portion of chrome.dll in advance
  // so that subsequent hard page faults are avoided.
  if (!cmd_line.HasSwitch(switches::kProcessType)) {
    // The kernel brings in 8 pages for the code section at a time and 4 pages
    // for other sections. We can skip over these pages to avoid a soft page
    // fault which may not occur during code execution. However skipping 4K at
    // a time still has better performance over 32K and 16K according to data.
    // TODO(ananta)
    // Investigate this and tune.
    const size_t kStepSize = 4 * 1024;

    DWORD pre_read_size = 0;
    DWORD pre_read_step_size = kStepSize;
    DWORD pre_read = 1;

    HKEY key = NULL;
    if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
                       0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
      DWORD unused = sizeof(pre_read_size);
      RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
      RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
      RegQueryValueEx(key, L"PreRead", NULL, NULL,
                      reinterpret_cast<LPBYTE>(&pre_read), &unused);
      RegCloseKey(key);
      key = NULL;
    }
    if (pre_read) {
      TRACE_EVENT_BEGIN("PreReadImage", 0, "");
      file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
      TRACE_EVENT_END("PreReadImage", 0, "");
    }
  }
#endif  // NDEBUG

  return ::LoadLibraryExW(dir->c_str(), NULL,
                          LOAD_WITH_ALTERED_SEARCH_PATH);
}

// Set did_run "dr" in omaha's client state for this product.
bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
  std::wstring key_path(google_update::kRegPathClientState);
  key_path.append(L"\\").append(guid);
  HKEY reg_key;
  if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
                        REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
                        &reg_key, NULL) == ERROR_SUCCESS) {
    // Note that the length here must be in bytes and must account for the
    // terminating null char.
    ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
                     reinterpret_cast<const BYTE *>(value),
                     (::lstrlenW(value) + 1) * sizeof(wchar_t));
    ::RegCloseKey(reg_key);
    return true;
  }
  return false;
}

bool RecordDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"1");
}

bool ClearDidRun(const wchar_t* guid) {
  return SetDidRunState(guid, L"0");
}

}
//=============================================================================

MainDllLoader::MainDllLoader() : dll_(NULL) {
}

MainDllLoader::~MainDllLoader() {
#ifdef PURIFY
  // We should never unload the dll. There is only risk and no gain from
  // doing so. The singleton dtors have been already run by AtExitManager.
  ::FreeLibrary(dll_);
#endif
}

// Loading chrome is an interesting afair. First we try loading from the current
// directory to support run-what-you-compile and other development scenarios.
// If that fails then we look at the 'CHROME_VERSION' env variable to determine
// if we should stick with an older dll version even if a new one is available
// to support upgrade-in-place scenarios, and if that fails we finally we look
// at the registry which should point us to the latest version.
HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
  std::wstring dir(GetExecutablePath());
  *file = dir;
  HMODULE dll = LoadChromeWithDirectory(file);
  if (dll)
    return dll;

  if (!EnvQueryStr(
          BrowserDistribution::GetDistribution()->GetEnvVersionKey().c_str(),
          version)) {
    std::wstring reg_path(GetRegistryPath());
    // Look into the registry to find the latest version.
    if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
      return NULL;
  }

  *file = dir;
  file->append(*version).append(L"\\");
  return LoadChromeWithDirectory(file);
}

// Launching is a matter of loading the right dll, setting the CHROME_VERSION
// environment variable and just calling the entry point. Derived classes can
// add custom code in the OnBeforeLaunch callback.
int MainDllLoader::Launch(HINSTANCE instance,
                          sandbox::SandboxInterfaceInfo* sbox_info) {
  std::wstring version;
  std::wstring file;
  dll_ = Load(&version, &file);
  if (!dll_)
    return ResultCodes::MISSING_DATA;

  scoped_ptr<base::Environment> env(base::Environment::Create());
  env->SetVar(WideToUTF8(
      BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
      WideToUTF8(version));

  InitCrashReporterWithDllPath(file);
  OnBeforeLaunch(version);

  DLL_MAIN entry_point =
      reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
  if (!entry_point)
    return ResultCodes::BAD_PROCESS_TYPE;

  int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
  return OnBeforeExit(rc);
}

void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
  RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
      reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
          ::GetProcAddress(dll_,
                           "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
  if (!relaunch_function) {
    LOG(ERROR) << "Could not find exported function "
               << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
  } else {
    relaunch_function();
  }
}

//=============================================================================

class ChromeDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    std::wstring key(google_update::kRegPathClients);
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    key.append(L"\\").append(dist->GetAppGuid());
    return key;
  }

  virtual void OnBeforeLaunch(const std::wstring& version) {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    RecordDidRun(dist->GetAppGuid().c_str());
  }

  virtual int OnBeforeExit(int return_code) {
    // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
    // so we need to reset the did_run signal so omaha does not count
    // this run as active usage.
    if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
      BrowserDistribution* dist = BrowserDistribution::GetDistribution();
      ClearDidRun(dist->GetAppGuid().c_str());
    }
    return return_code;
  }
};

//=============================================================================

class ChromiumDllLoader : public MainDllLoader {
 public:
  virtual std::wstring GetRegistryPath() {
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    return dist->GetVersionKey();
  }
};

MainDllLoader* MakeMainDllLoader() {
#if defined(GOOGLE_CHROME_BUILD)
  return new ChromeDllLoader();
#else
  return new ChromiumDllLoader();
#endif
}
<|endoftext|>