summaryrefslogtreecommitdiff
path: root/src/mongo/shell
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/shell')
-rw-r--r--src/mongo/shell/bench.cpp1486
-rw-r--r--src/mongo/shell/bench.h793
-rw-r--r--src/mongo/shell/clientAndShell.cpp57
-rw-r--r--src/mongo/shell/dbshell.cpp701
-rw-r--r--src/mongo/shell/linenoise.cpp2839
-rw-r--r--src/mongo/shell/linenoise.h22
-rw-r--r--src/mongo/shell/linenoise_utf8.cpp237
-rw-r--r--src/mongo/shell/linenoise_utf8.h170
-rw-r--r--src/mongo/shell/mk_wcwidth.cpp538
-rw-r--r--src/mongo/shell/mk_wcwidth.h2
-rw-r--r--src/mongo/shell/shell_options.cpp482
-rw-r--r--src/mongo/shell/shell_options.h91
-rw-r--r--src/mongo/shell/shell_options_init.cpp51
-rw-r--r--src/mongo/shell/shell_utils.cpp506
-rw-r--r--src/mongo/shell/shell_utils.h106
-rw-r--r--src/mongo/shell/shell_utils_extended.cpp367
-rw-r--r--src/mongo/shell/shell_utils_extended.h10
-rw-r--r--src/mongo/shell/shell_utils_launcher.cpp1345
-rw-r--r--src/mongo/shell/shell_utils_launcher.h164
19 files changed, 5115 insertions, 4852 deletions
diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp
index 99311f23f62..bd446e49018 100644
--- a/src/mongo/shell/bench.cpp
+++ b/src/mongo/shell/bench.cpp
@@ -54,459 +54,505 @@
// TODO: Maybe extract as library to avoid code duplication?
namespace {
- inline pcrecpp::RE_Options flags2options(const char* flags) {
- pcrecpp::RE_Options options;
- options.set_utf8(true);
- while ( flags && *flags ) {
- if ( *flags == 'i' )
- options.set_caseless(true);
- else if ( *flags == 'm' )
- options.set_multiline(true);
- else if ( *flags == 'x' )
- options.set_extended(true);
- flags++;
- }
- return options;
- }
+inline pcrecpp::RE_Options flags2options(const char* flags) {
+ pcrecpp::RE_Options options;
+ options.set_utf8(true);
+ while (flags && *flags) {
+ if (*flags == 'i')
+ options.set_caseless(true);
+ else if (*flags == 'm')
+ options.set_multiline(true);
+ else if (*flags == 'x')
+ options.set_extended(true);
+ flags++;
+ }
+ return options;
+}
}
namespace mongo {
- using std::unique_ptr;
- using std::cout;
- using std::endl;
- using std::map;
-
- BenchRunEventCounter::BenchRunEventCounter() {
- reset();
- }
-
- BenchRunEventCounter::~BenchRunEventCounter() {}
+using std::unique_ptr;
+using std::cout;
+using std::endl;
+using std::map;
- void BenchRunEventCounter::reset() {
- _numEvents = 0;
- _totalTimeMicros = 0;
- }
-
- void BenchRunEventCounter::updateFrom(const BenchRunEventCounter &other) {
- _numEvents += other._numEvents;
- _totalTimeMicros += other._totalTimeMicros;
- }
-
- BenchRunStats::BenchRunStats() {
- reset();
- }
+BenchRunEventCounter::BenchRunEventCounter() {
+ reset();
+}
- BenchRunStats::~BenchRunStats() {}
+BenchRunEventCounter::~BenchRunEventCounter() {}
- void BenchRunStats::reset() {
- error = false;
- errCount = 0;
- opCount = 0;
+void BenchRunEventCounter::reset() {
+ _numEvents = 0;
+ _totalTimeMicros = 0;
+}
- findOneCounter.reset();
- updateCounter.reset();
- insertCounter.reset();
- deleteCounter.reset();
- queryCounter.reset();
- commandCounter.reset();
- trappedErrors.clear();
- }
+void BenchRunEventCounter::updateFrom(const BenchRunEventCounter& other) {
+ _numEvents += other._numEvents;
+ _totalTimeMicros += other._totalTimeMicros;
+}
- void BenchRunStats::updateFrom(const BenchRunStats &other) {
- if (other.error)
- error = true;
- errCount += other.errCount;
- opCount += other.opCount;
-
- findOneCounter.updateFrom(other.findOneCounter);
- updateCounter.updateFrom(other.updateCounter);
- insertCounter.updateFrom(other.insertCounter);
- deleteCounter.updateFrom(other.deleteCounter);
- queryCounter.updateFrom(other.queryCounter);
- commandCounter.updateFrom(other.commandCounter);
-
- for (size_t i = 0; i < other.trappedErrors.size(); ++i)
- trappedErrors.push_back(other.trappedErrors[i]);
- }
+BenchRunStats::BenchRunStats() {
+ reset();
+}
- BenchRunConfig::BenchRunConfig() {
- initializeToDefaults();
- }
+BenchRunStats::~BenchRunStats() {}
- void BenchRunConfig::initializeToDefaults() {
- host = "localhost";
- db = "test";
- username = "";
- password = "";
+void BenchRunStats::reset() {
+ error = false;
+ errCount = 0;
+ opCount = 0;
- parallel = 1;
- seconds = 1.0;
- hideResults = true;
- handleErrors = false;
- hideErrors = false;
+ findOneCounter.reset();
+ updateCounter.reset();
+ insertCounter.reset();
+ deleteCounter.reset();
+ queryCounter.reset();
+ commandCounter.reset();
+ trappedErrors.clear();
+}
- trapPattern.reset();
- noTrapPattern.reset();
- watchPattern.reset();
- noWatchPattern.reset();
+void BenchRunStats::updateFrom(const BenchRunStats& other) {
+ if (other.error)
+ error = true;
+ errCount += other.errCount;
+ opCount += other.opCount;
+
+ findOneCounter.updateFrom(other.findOneCounter);
+ updateCounter.updateFrom(other.updateCounter);
+ insertCounter.updateFrom(other.insertCounter);
+ deleteCounter.updateFrom(other.deleteCounter);
+ queryCounter.updateFrom(other.queryCounter);
+ commandCounter.updateFrom(other.commandCounter);
+
+ for (size_t i = 0; i < other.trappedErrors.size(); ++i)
+ trappedErrors.push_back(other.trappedErrors[i]);
+}
- ops = BSONObj();
+BenchRunConfig::BenchRunConfig() {
+ initializeToDefaults();
+}
- throwGLE = false;
- breakOnTrap = true;
- randomSeed = 1314159265358979323;
- }
+void BenchRunConfig::initializeToDefaults() {
+ host = "localhost";
+ db = "test";
+ username = "";
+ password = "";
- BenchRunConfig *BenchRunConfig::createFromBson( const BSONObj &args ) {
- BenchRunConfig *config = new BenchRunConfig();
- config->initializeFromBson( args );
- return config;
- }
+ parallel = 1;
+ seconds = 1.0;
+ hideResults = true;
+ handleErrors = false;
+ hideErrors = false;
- void BenchRunConfig::initializeFromBson( const BSONObj &args ) {
- initializeToDefaults();
-
- if ( args["host"].type() == String )
- this->host = args["host"].String();
- if ( args["db"].type() == String )
- this->db = args["db"].String();
- if ( args["username"].type() == String )
- this->username = args["username"].String();
- if ( args["password"].type() == String )
- this->password = args["password"].String();
-
- if ( args["parallel"].isNumber() )
- this->parallel = args["parallel"].numberInt();
- if ( args["randomSeed"].isNumber() )
- this->randomSeed = args["randomSeed"].numberInt();
- if ( args["seconds"].isNumber() )
- this->seconds = args["seconds"].number();
- if ( ! args["hideResults"].eoo() )
- this->hideResults = args["hideResults"].trueValue();
- if ( ! args["handleErrors"].eoo() )
- this->handleErrors = args["handleErrors"].trueValue();
- if ( ! args["hideErrors"].eoo() )
- this->hideErrors = args["hideErrors"].trueValue();
- if ( ! args["throwGLE"].eoo() )
- this->throwGLE = args["throwGLE"].trueValue();
- if ( ! args["breakOnTrap"].eoo() )
- this->breakOnTrap = args["breakOnTrap"].trueValue();
-
- uassert(16164, "loopCommands config not supported", args["loopCommands"].eoo());
-
- if ( ! args["trapPattern"].eoo() ){
- const char* regex = args["trapPattern"].regex();
- const char* flags = args["trapPattern"].regexFlags();
- this->trapPattern = std::shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) );
- }
+ trapPattern.reset();
+ noTrapPattern.reset();
+ watchPattern.reset();
+ noWatchPattern.reset();
- if ( ! args["noTrapPattern"].eoo() ){
- const char* regex = args["noTrapPattern"].regex();
- const char* flags = args["noTrapPattern"].regexFlags();
- this->noTrapPattern = std::shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) );
- }
+ ops = BSONObj();
- if ( ! args["watchPattern"].eoo() ){
- const char* regex = args["watchPattern"].regex();
- const char* flags = args["watchPattern"].regexFlags();
- this->watchPattern = std::shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) );
- }
+ throwGLE = false;
+ breakOnTrap = true;
+ randomSeed = 1314159265358979323;
+}
- if ( ! args["noWatchPattern"].eoo() ){
- const char* regex = args["noWatchPattern"].regex();
- const char* flags = args["noWatchPattern"].regexFlags();
- this->noWatchPattern = std::shared_ptr< pcrecpp::RE >( new pcrecpp::RE( regex, flags2options( flags ) ) );
- }
+BenchRunConfig* BenchRunConfig::createFromBson(const BSONObj& args) {
+ BenchRunConfig* config = new BenchRunConfig();
+ config->initializeFromBson(args);
+ return config;
+}
- this->ops = args["ops"].Obj().getOwned();
- }
+void BenchRunConfig::initializeFromBson(const BSONObj& args) {
+ initializeToDefaults();
+
+ if (args["host"].type() == String)
+ this->host = args["host"].String();
+ if (args["db"].type() == String)
+ this->db = args["db"].String();
+ if (args["username"].type() == String)
+ this->username = args["username"].String();
+ if (args["password"].type() == String)
+ this->password = args["password"].String();
+
+ if (args["parallel"].isNumber())
+ this->parallel = args["parallel"].numberInt();
+ if (args["randomSeed"].isNumber())
+ this->randomSeed = args["randomSeed"].numberInt();
+ if (args["seconds"].isNumber())
+ this->seconds = args["seconds"].number();
+ if (!args["hideResults"].eoo())
+ this->hideResults = args["hideResults"].trueValue();
+ if (!args["handleErrors"].eoo())
+ this->handleErrors = args["handleErrors"].trueValue();
+ if (!args["hideErrors"].eoo())
+ this->hideErrors = args["hideErrors"].trueValue();
+ if (!args["throwGLE"].eoo())
+ this->throwGLE = args["throwGLE"].trueValue();
+ if (!args["breakOnTrap"].eoo())
+ this->breakOnTrap = args["breakOnTrap"].trueValue();
+
+ uassert(16164, "loopCommands config not supported", args["loopCommands"].eoo());
+
+ if (!args["trapPattern"].eoo()) {
+ const char* regex = args["trapPattern"].regex();
+ const char* flags = args["trapPattern"].regexFlags();
+ this->trapPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ }
+
+ if (!args["noTrapPattern"].eoo()) {
+ const char* regex = args["noTrapPattern"].regex();
+ const char* flags = args["noTrapPattern"].regexFlags();
+ this->noTrapPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ }
+
+ if (!args["watchPattern"].eoo()) {
+ const char* regex = args["watchPattern"].regex();
+ const char* flags = args["watchPattern"].regexFlags();
+ this->watchPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ }
+
+ if (!args["noWatchPattern"].eoo()) {
+ const char* regex = args["noWatchPattern"].regex();
+ const char* flags = args["noWatchPattern"].regexFlags();
+ this->noWatchPattern =
+ std::shared_ptr<pcrecpp::RE>(new pcrecpp::RE(regex, flags2options(flags)));
+ }
+
+ this->ops = args["ops"].Obj().getOwned();
+}
- DBClientBase *BenchRunConfig::createConnection() const {
- const ConnectionString connectionString = uassertStatusOK(ConnectionString::parse(host));
+DBClientBase* BenchRunConfig::createConnection() const {
+ const ConnectionString connectionString = uassertStatusOK(ConnectionString::parse(host));
- std::string errorMessage;
- DBClientBase *connection = connectionString.connect(errorMessage);
- uassert( 16158, errorMessage, connection != NULL );
+ std::string errorMessage;
+ DBClientBase* connection = connectionString.connect(errorMessage);
+ uassert(16158, errorMessage, connection != NULL);
- return connection;
- }
+ return connection;
+}
- BenchRunState::BenchRunState( unsigned numWorkers )
- : _mutex(),
- _numUnstartedWorkers( numWorkers ),
- _numActiveWorkers( 0 ),
- _isShuttingDown( 0 ),
- _isCollectingStats( 0 ) {
- }
+BenchRunState::BenchRunState(unsigned numWorkers)
+ : _mutex(),
+ _numUnstartedWorkers(numWorkers),
+ _numActiveWorkers(0),
+ _isShuttingDown(0),
+ _isCollectingStats(0) {}
- BenchRunState::~BenchRunState() {
- wassert(_numActiveWorkers == 0 && _numUnstartedWorkers == 0);
- }
+BenchRunState::~BenchRunState() {
+ wassert(_numActiveWorkers == 0 && _numUnstartedWorkers == 0);
+}
- void BenchRunState::waitForState(State awaitedState) {
- stdx::unique_lock<stdx::mutex> lk(_mutex);
+void BenchRunState::waitForState(State awaitedState) {
+ stdx::unique_lock<stdx::mutex> lk(_mutex);
- switch ( awaitedState ) {
+ switch (awaitedState) {
case BRS_RUNNING:
- while ( _numUnstartedWorkers > 0 ) {
- massert( 16147, "Already finished.", _numUnstartedWorkers + _numActiveWorkers > 0 );
- _stateChangeCondition.wait( lk );
+ while (_numUnstartedWorkers > 0) {
+ massert(16147, "Already finished.", _numUnstartedWorkers + _numActiveWorkers > 0);
+ _stateChangeCondition.wait(lk);
}
break;
case BRS_FINISHED:
- while ( _numUnstartedWorkers + _numActiveWorkers > 0 ) {
- _stateChangeCondition.wait( lk );
+ while (_numUnstartedWorkers + _numActiveWorkers > 0) {
+ _stateChangeCondition.wait(lk);
}
break;
default:
- msgasserted(16152, mongoutils::str::stream() << "Cannot wait for state " << awaitedState);
- }
+ msgasserted(16152,
+ mongoutils::str::stream() << "Cannot wait for state " << awaitedState);
}
+}
- void BenchRunState::tellWorkersToFinish() {
- _isShuttingDown.store( 1 );
- }
+void BenchRunState::tellWorkersToFinish() {
+ _isShuttingDown.store(1);
+}
- void BenchRunState::tellWorkersToCollectStats() {
- _isCollectingStats.store( 1 );
- }
+void BenchRunState::tellWorkersToCollectStats() {
+ _isCollectingStats.store(1);
+}
- void BenchRunState::assertFinished() {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- verify(0 == _numUnstartedWorkers + _numActiveWorkers);
- }
+void BenchRunState::assertFinished() {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ verify(0 == _numUnstartedWorkers + _numActiveWorkers);
+}
- bool BenchRunState::shouldWorkerFinish() {
- return (_isShuttingDown.loadRelaxed() == 1);
- }
+bool BenchRunState::shouldWorkerFinish() {
+ return (_isShuttingDown.loadRelaxed() == 1);
+}
- bool BenchRunState::shouldWorkerCollectStats() {
- return (_isCollectingStats.loadRelaxed() == 1);
- }
+bool BenchRunState::shouldWorkerCollectStats() {
+ return (_isCollectingStats.loadRelaxed() == 1);
+}
- void BenchRunState::onWorkerStarted() {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- verify( _numUnstartedWorkers > 0 );
- --_numUnstartedWorkers;
- ++_numActiveWorkers;
- if (_numUnstartedWorkers == 0) {
- _stateChangeCondition.notify_all();
- }
+void BenchRunState::onWorkerStarted() {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ verify(_numUnstartedWorkers > 0);
+ --_numUnstartedWorkers;
+ ++_numActiveWorkers;
+ if (_numUnstartedWorkers == 0) {
+ _stateChangeCondition.notify_all();
}
+}
- void BenchRunState::onWorkerFinished() {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- verify( _numActiveWorkers > 0 );
- --_numActiveWorkers;
- if (_numActiveWorkers + _numUnstartedWorkers == 0) {
- _stateChangeCondition.notify_all();
- }
+void BenchRunState::onWorkerFinished() {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ verify(_numActiveWorkers > 0);
+ --_numActiveWorkers;
+ if (_numActiveWorkers + _numUnstartedWorkers == 0) {
+ _stateChangeCondition.notify_all();
}
+}
- BSONObj benchStart( const BSONObj& , void* );
- BSONObj benchFinish( const BSONObj& , void* );
+BSONObj benchStart(const BSONObj&, void*);
+BSONObj benchFinish(const BSONObj&, void*);
- static bool _hasSpecial( const BSONObj& obj ) {
- BSONObjIterator i( obj );
- while ( i.more() ) {
- BSONElement e = i.next();
- if ( e.fieldName()[0] == '#' )
- return true;
+static bool _hasSpecial(const BSONObj& obj) {
+ BSONObjIterator i(obj);
+ while (i.more()) {
+ BSONElement e = i.next();
+ if (e.fieldName()[0] == '#')
+ return true;
- if ( ! e.isABSONObj() )
- continue;
+ if (!e.isABSONObj())
+ continue;
- if ( _hasSpecial( e.Obj() ) )
- return true;
- }
- return false;
+ if (_hasSpecial(e.Obj()))
+ return true;
}
+ return false;
+}
- static BSONObj fixQuery( const BSONObj& obj, BsonTemplateEvaluator& btl ) {
- if ( ! _hasSpecial( obj ) )
- return obj;
- BSONObjBuilder b( obj.objsize() + 128 );
+static BSONObj fixQuery(const BSONObj& obj, BsonTemplateEvaluator& btl) {
+ if (!_hasSpecial(obj))
+ return obj;
+ BSONObjBuilder b(obj.objsize() + 128);
- verify(BsonTemplateEvaluator::StatusSuccess == btl.evaluate(obj, b));
- return b.obj();
- }
+ verify(BsonTemplateEvaluator::StatusSuccess == btl.evaluate(obj, b));
+ return b.obj();
+}
- BenchRunWorker::BenchRunWorker(size_t id, const BenchRunConfig *config, BenchRunState *brState,
- int64_t randomSeed)
- : _id(id), _config(config), _brState(brState), _randomSeed(randomSeed) {
- }
+BenchRunWorker::BenchRunWorker(size_t id,
+ const BenchRunConfig* config,
+ BenchRunState* brState,
+ int64_t randomSeed)
+ : _id(id), _config(config), _brState(brState), _randomSeed(randomSeed) {}
- BenchRunWorker::~BenchRunWorker() {}
+BenchRunWorker::~BenchRunWorker() {}
- void BenchRunWorker::start() {
- stdx::thread(stdx::bind(&BenchRunWorker::run, this));
- }
+void BenchRunWorker::start() {
+ stdx::thread(stdx::bind(&BenchRunWorker::run, this));
+}
- bool BenchRunWorker::shouldStop() const {
- return _brState->shouldWorkerFinish();
- }
+bool BenchRunWorker::shouldStop() const {
+ return _brState->shouldWorkerFinish();
+}
- bool BenchRunWorker::shouldCollectStats() const {
- return _brState->shouldWorkerCollectStats();
- }
+bool BenchRunWorker::shouldCollectStats() const {
+ return _brState->shouldWorkerCollectStats();
+}
- void doNothing(const BSONObj&) { }
+void doNothing(const BSONObj&) {}
- void BenchRunWorker::generateLoadOnConnection( DBClientBase* conn ) {
- verify( conn );
- long long count = 0;
- mongo::Timer timer;
+void BenchRunWorker::generateLoadOnConnection(DBClientBase* conn) {
+ verify(conn);
+ long long count = 0;
+ mongo::Timer timer;
- BsonTemplateEvaluator bsonTemplateEvaluator(_randomSeed);
- invariant(bsonTemplateEvaluator.setId(_id) == BsonTemplateEvaluator::StatusSuccess);
+ BsonTemplateEvaluator bsonTemplateEvaluator(_randomSeed);
+ invariant(bsonTemplateEvaluator.setId(_id) == BsonTemplateEvaluator::StatusSuccess);
- if (_config->username != "") {
- string errmsg;
- if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
- uasserted(15931, "Authenticating to connection for _benchThread failed: " + errmsg);
- }
+ if (_config->username != "") {
+ string errmsg;
+ if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
+ uasserted(15931, "Authenticating to connection for _benchThread failed: " + errmsg);
}
+ }
- while ( !shouldStop() ) {
- BSONObjIterator i( _config->ops );
- while ( i.more() ) {
-
- if ( shouldStop() ) break;
- auto& stats = shouldCollectStats() ? _stats : _statsBlackHole;
- BSONElement e = i.next();
-
- string ns = e["ns"].String();
- string op = e["op"].String();
+ while (!shouldStop()) {
+ BSONObjIterator i(_config->ops);
+ while (i.more()) {
+ if (shouldStop())
+ break;
+ auto& stats = shouldCollectStats() ? _stats : _statsBlackHole;
+ BSONElement e = i.next();
- int delay = e["delay"].eoo() ? 0 : e["delay"].Int();
+ string ns = e["ns"].String();
+ string op = e["op"].String();
- // Let's default to writeCmd == false.
- bool useWriteCmd = e["writeCmd"].eoo() ? false :
- e["writeCmd"].Bool();
+ int delay = e["delay"].eoo() ? 0 : e["delay"].Int();
- BSONObj context = e["context"].eoo() ? BSONObj() : e["context"].Obj();
+ // Let's default to writeCmd == false.
+ bool useWriteCmd = e["writeCmd"].eoo() ? false : e["writeCmd"].Bool();
- unique_ptr<Scope> scope;
- ScriptingFunction scopeFunc = 0;
- BSONObj scopeObj;
+ BSONObj context = e["context"].eoo() ? BSONObj() : e["context"].Obj();
- bool check = ! e["check"].eoo();
- if( check ){
- if ( e["check"].type() == CodeWScope || e["check"].type() == Code || e["check"].type() == String ) {
- scope = globalScriptEngine->getPooledScope(NULL, ns, "benchrun");
- verify( scope.get() );
+ unique_ptr<Scope> scope;
+ ScriptingFunction scopeFunc = 0;
+ BSONObj scopeObj;
- if ( e.type() == CodeWScope ) {
- scopeFunc = scope->createFunction( e["check"].codeWScopeCode() );
- scopeObj = BSONObj( e.codeWScopeScopeDataUnsafe() );
- }
- else {
- scopeFunc = scope->createFunction( e["check"].valuestr() );
- }
+ bool check = !e["check"].eoo();
+ if (check) {
+ if (e["check"].type() == CodeWScope || e["check"].type() == Code ||
+ e["check"].type() == String) {
+ scope = globalScriptEngine->getPooledScope(NULL, ns, "benchrun");
+ verify(scope.get());
- scope->init( &scopeObj );
- invariant(scopeFunc);
- }
- else {
- warning() << "Invalid check type detected in benchRun op : " << e << endl;
- check = false;
+ if (e.type() == CodeWScope) {
+ scopeFunc = scope->createFunction(e["check"].codeWScopeCode());
+ scopeObj = BSONObj(e.codeWScopeScopeDataUnsafe());
+ } else {
+ scopeFunc = scope->createFunction(e["check"].valuestr());
}
+
+ scope->init(&scopeObj);
+ invariant(scopeFunc);
+ } else {
+ warning() << "Invalid check type detected in benchRun op : " << e << endl;
+ check = false;
}
+ }
- try {
- if ( op == "nop") {
- // do nothing
+ try {
+ if (op == "nop") {
+ // do nothing
+ } else if (op == "findOne") {
+ BSONObj result;
+ {
+ BenchRunEventTrace _bret(&stats.findOneCounter);
+ result =
+ conn->findOne(ns, fixQuery(e["query"].Obj(), bsonTemplateEvaluator));
}
- else if ( op == "findOne" ) {
-
- BSONObj result;
- {
- BenchRunEventTrace _bret(&stats.findOneCounter);
- result = conn->findOne( ns , fixQuery( e["query"].Obj(),
- bsonTemplateEvaluator ) );
- }
- if( check ){
- int err = scope->invoke( scopeFunc , 0 , &result, 1000 * 60 , false );
- if( err ){
- log() << "Error checking in benchRun thread [findOne]" << causedBy( scope->getError() ) << endl;
+ if (check) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [findOne]"
+ << causedBy(scope->getError()) << endl;
- stats.errCount++;
+ stats.errCount++;
- return;
- }
+ return;
}
+ }
- if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [findOne] : " << result << endl;
-
+ if (!_config->hideResults || e["showResult"].trueValue())
+ log() << "Result from benchRun thread [findOne] : " << result << endl;
+
+ } else if (op == "command") {
+ bool ok;
+ BSONObj result;
+ {
+ BenchRunEventTrace _bret(&stats.commandCounter);
+ ok = conn->runCommand(ns,
+ fixQuery(e["command"].Obj(), bsonTemplateEvaluator),
+ result,
+ e["options"].numberInt());
}
- else if ( op == "command" ) {
-
- bool ok;
- BSONObj result;
- {
- BenchRunEventTrace _bret(&stats.commandCounter);
- ok = conn->runCommand( ns,
- fixQuery( e["command"].Obj(),
- bsonTemplateEvaluator ),
- result,
- e["options"].numberInt());
- }
- if (!ok) {
- stats.errCount++;
- }
- else if( check ){
- int err = scope->invoke( scopeFunc , 0 , &result, 1000 * 60 , false );
- if( err ){
- log() << "Error checking in benchRun thread [command]" << causedBy( scope->getError() ) << endl;
+ if (!ok) {
+ stats.errCount++;
+ } else if (check) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [command]"
+ << causedBy(scope->getError()) << endl;
- stats.errCount++;
+ stats.errCount++;
- return;
- }
+ return;
}
+ }
- if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [command] : " << result << endl;
-
+ if (!_config->hideResults || e["showResult"].trueValue())
+ log() << "Result from benchRun thread [command] : " << result << endl;
+
+ } else if (op == "find" || op == "query") {
+ int limit = e["limit"].eoo() ? 0 : e["limit"].numberInt();
+ int skip = e["skip"].eoo() ? 0 : e["skip"].Int();
+ int options = e["options"].eoo() ? 0 : e["options"].Int();
+ int batchSize = e["batchSize"].eoo() ? 0 : e["batchSize"].Int();
+ BSONObj filter = e["filter"].eoo() ? BSONObj() : e["filter"].Obj();
+ int expected = e["expected"].eoo() ? -1 : e["expected"].Int();
+
+ unique_ptr<DBClientCursor> cursor;
+ int count;
+
+ BSONObj fixedQuery = fixQuery(e["query"].Obj(), bsonTemplateEvaluator);
+
+ // use special query function for exhaust query option
+ if (options & QueryOption_Exhaust) {
+ BenchRunEventTrace _bret(&stats.queryCounter);
+ stdx::function<void(const BSONObj&)> castedDoNothing(doNothing);
+ count = conn->query(castedDoNothing, ns, fixedQuery, &filter, options);
+ } else {
+ BenchRunEventTrace _bret(&stats.queryCounter);
+ cursor =
+ conn->query(ns, fixedQuery, limit, skip, &filter, options, batchSize);
+ count = cursor->itcount();
}
- else if( op == "find" || op == "query" ) {
- int limit = e["limit"].eoo() ? 0 : e["limit"].numberInt();
- int skip = e["skip"].eoo() ? 0 : e["skip"].Int();
- int options = e["options"].eoo() ? 0 : e["options"].Int();
- int batchSize = e["batchSize"].eoo() ? 0 : e["batchSize"].Int();
- BSONObj filter = e["filter"].eoo() ? BSONObj() : e["filter"].Obj();
- int expected = e["expected"].eoo() ? -1 : e["expected"].Int();
+ if (expected >= 0 && count != expected) {
+ cout << "bench query on: " << ns << " expected: " << expected
+ << " got: " << count << endl;
+ verify(false);
+ }
- unique_ptr<DBClientCursor> cursor;
- int count;
+ if (check) {
+ BSONObj thisValue = BSON("count" << count << "context" << context);
+ int err = scope->invoke(scopeFunc, 0, &thisValue, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [find]"
+ << causedBy(scope->getError()) << endl;
- BSONObj fixedQuery = fixQuery(e["query"].Obj(), bsonTemplateEvaluator);
+ stats.errCount++;
- // use special query function for exhaust query option
- if (options & QueryOption_Exhaust) {
- BenchRunEventTrace _bret(&stats.queryCounter);
- stdx::function<void (const BSONObj&)> castedDoNothing(doNothing);
- count = conn->query(castedDoNothing, ns, fixedQuery, &filter, options);
- }
- else {
- BenchRunEventTrace _bret(&stats.queryCounter);
- cursor = conn->query(ns, fixedQuery, limit, skip, &filter, options,
- batchSize);
- count = cursor->itcount();
+ return;
}
+ }
- if ( expected >= 0 && count != expected ) {
- cout << "bench query on: " << ns << " expected: " << expected << " got: " << count << endl;
- verify(false);
+ if (!_config->hideResults || e["showResult"].trueValue())
+ log() << "Result from benchRun thread [query] : " << count << endl;
+
+ } else if (op == "update") {
+ bool multi = e["multi"].trueValue();
+ bool upsert = e["upsert"].trueValue();
+ BSONObj queryOrginal = e["query"].eoo() ? BSONObj() : e["query"].Obj();
+ BSONObj updateOriginal = e["update"].Obj();
+ BSONObj result;
+ bool safe = e["safe"].trueValue();
+
+ {
+ BenchRunEventTrace _bret(&stats.updateCounter);
+ BSONObj query = fixQuery(queryOrginal, bsonTemplateEvaluator);
+ BSONObj update = fixQuery(updateOriginal, bsonTemplateEvaluator);
+
+ if (useWriteCmd) {
+ // TODO: Replace after SERVER-11774.
+ BSONObjBuilder builder;
+ builder.append("update", nsToCollectionSubstring(ns));
+ BSONArrayBuilder docBuilder(builder.subarrayStart("updates"));
+ docBuilder.append(BSON("q" << query << "u" << update << "multi" << multi
+ << "upsert" << upsert));
+ docBuilder.done();
+ conn->runCommand(
+ nsToDatabaseSubstring(ns).toString(), builder.done(), result);
+ } else {
+ conn->update(ns, query, update, upsert, multi);
+ if (safe)
+ result = conn->getLastErrorDetailed();
}
+ }
- if( check ){
- BSONObj thisValue = BSON( "count" << count << "context" << context );
- int err = scope->invoke( scopeFunc , 0 , &thisValue, 1000 * 60 , false );
- if( err ){
- log() << "Error checking in benchRun thread [find]" << causedBy( scope->getError() ) << endl;
+ if (safe) {
+ if (check) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [update]"
+ << causedBy(scope->getError()) << endl;
stats.errCount++;
@@ -514,464 +560,406 @@ namespace mongo {
}
}
- if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [query] : " << count << endl;
+ if (!_config->hideResults || e["showResult"].trueValue())
+ log() << "Result from benchRun thread [safe update] : " << result
+ << endl;
+ if (!result["err"].eoo() && result["err"].type() == String &&
+ (_config->throwGLE || e["throwGLE"].trueValue()))
+ throw DBException((string) "From benchRun GLE" +
+ causedBy(result["err"].String()),
+ result["code"].eoo() ? 0 : result["code"].Int());
}
- else if( op == "update" ) {
-
- bool multi = e["multi"].trueValue();
- bool upsert = e["upsert"].trueValue();
- BSONObj queryOrginal = e["query"].eoo() ? BSONObj() : e["query"].Obj();
- BSONObj updateOriginal = e["update"].Obj();
- BSONObj result;
- bool safe = e["safe"].trueValue();
-
- {
- BenchRunEventTrace _bret(&stats.updateCounter);
- BSONObj query = fixQuery(queryOrginal, bsonTemplateEvaluator);
- BSONObj update = fixQuery(updateOriginal, bsonTemplateEvaluator);
-
- if (useWriteCmd) {
- // TODO: Replace after SERVER-11774.
- BSONObjBuilder builder;
- builder.append("update",
- nsToCollectionSubstring(ns));
- BSONArrayBuilder docBuilder(
- builder.subarrayStart("updates"));
- docBuilder.append(BSON("q" << query <<
- "u" << update <<
- "multi" << multi <<
- "upsert" << upsert));
- docBuilder.done();
- conn->runCommand(
- nsToDatabaseSubstring(ns).toString(),
- builder.done(), result);
- }
- else {
- conn->update(ns, query, update,
- upsert , multi);
- if (safe)
- result = conn->getLastErrorDetailed();
- }
+ } else if (op == "insert") {
+ bool safe = e["safe"].trueValue();
+ BSONObj result;
+
+ {
+ BenchRunEventTrace _bret(&stats.insertCounter);
+
+ BSONObj insertDoc = fixQuery(e["doc"].Obj(), bsonTemplateEvaluator);
+
+ if (useWriteCmd) {
+ BSONObjBuilder builder;
+ builder.append("insert", nsToCollectionSubstring(ns));
+ BSONArrayBuilder docBuilder(builder.subarrayStart("documents"));
+ docBuilder.append(insertDoc);
+ docBuilder.done();
+ // TODO: Replace after SERVER-11774.
+ conn->runCommand(
+ nsToDatabaseSubstring(ns).toString(), builder.done(), result);
+ } else {
+ conn->insert(ns, insertDoc);
+ if (safe)
+ result = conn->getLastErrorDetailed();
}
+ }
- if( safe ){
- if( check ){
- int err = scope->invoke( scopeFunc , 0 , &result, 1000 * 60 , false );
- if( err ){
- log() << "Error checking in benchRun thread [update]" << causedBy( scope->getError() ) << endl;
+ if (safe) {
+ if (check) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [insert]"
+ << causedBy(scope->getError()) << endl;
- stats.errCount++;
+ stats.errCount++;
- return;
- }
+ return;
}
+ }
- if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [safe update] : " << result << endl;
+ if (!_config->hideResults || e["showResult"].trueValue())
+ log() << "Result from benchRun thread [safe insert] : " << result
+ << endl;
- if( ! result["err"].eoo() && result["err"].type() == String && ( _config->throwGLE || e["throwGLE"].trueValue() ) )
- throw DBException( (string)"From benchRun GLE" + causedBy( result["err"].String() ),
- result["code"].eoo() ? 0 : result["code"].Int() );
- }
+ if (!result["err"].eoo() && result["err"].type() == String &&
+ (_config->throwGLE || e["throwGLE"].trueValue()))
+ throw DBException((string) "From benchRun GLE" +
+ causedBy(result["err"].String()),
+ result["code"].eoo() ? 0 : result["code"].Int());
}
- else if( op == "insert" ) {
- bool safe = e["safe"].trueValue();
- BSONObj result;
-
- {
- BenchRunEventTrace _bret(&stats.insertCounter);
-
- BSONObj insertDoc = fixQuery(e["doc"].Obj(), bsonTemplateEvaluator);
-
- if (useWriteCmd) {
- BSONObjBuilder builder;
- builder.append("insert", nsToCollectionSubstring(ns));
- BSONArrayBuilder docBuilder(
- builder.subarrayStart("documents"));
- docBuilder.append(insertDoc);
- docBuilder.done();
- // TODO: Replace after SERVER-11774.
- conn->runCommand(
- nsToDatabaseSubstring(ns).toString(),
- builder.done(), result);
- }
- else {
- conn->insert(ns, insertDoc);
- if (safe)
- result = conn->getLastErrorDetailed();
- }
+ } else if (op == "delete" || op == "remove") {
+ bool multi = e["multi"].eoo() ? true : e["multi"].trueValue();
+ BSONObj query = e["query"].eoo() ? BSONObj() : e["query"].Obj();
+ bool safe = e["safe"].trueValue();
+ BSONObj result;
+ {
+ BenchRunEventTrace _bret(&stats.deleteCounter);
+ BSONObj predicate = fixQuery(query, bsonTemplateEvaluator);
+ if (useWriteCmd) {
+ // TODO: Replace after SERVER-11774.
+ BSONObjBuilder builder;
+ builder.append("delete", nsToCollectionSubstring(ns));
+ BSONArrayBuilder docBuilder(builder.subarrayStart("deletes"));
+ int limit = (multi == true) ? 0 : 1;
+ docBuilder.append(BSON("q" << predicate << "limit" << limit));
+ docBuilder.done();
+ conn->runCommand(
+ nsToDatabaseSubstring(ns).toString(), builder.done(), result);
+ } else {
+ conn->remove(ns, predicate, !multi);
+ if (safe)
+ result = conn->getLastErrorDetailed();
}
+ }
- if( safe ){
- if( check ){
- int err = scope->invoke( scopeFunc , 0 , &result, 1000 * 60 , false );
- if( err ){
- log() << "Error checking in benchRun thread [insert]" << causedBy( scope->getError() ) << endl;
-
- stats.errCount++;
-
- return;
- }
- }
+ if (safe) {
+ if (check) {
+ int err = scope->invoke(scopeFunc, 0, &result, 1000 * 60, false);
+ if (err) {
+ log() << "Error checking in benchRun thread [delete]"
+ << causedBy(scope->getError()) << endl;
- if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [safe insert] : " << result << endl;
+ stats.errCount++;
- if( ! result["err"].eoo() && result["err"].type() == String && ( _config->throwGLE || e["throwGLE"].trueValue() ) )
- throw DBException( (string)"From benchRun GLE" + causedBy( result["err"].String() ),
- result["code"].eoo() ? 0 : result["code"].Int() );
- }
- }
- else if( op == "delete" || op == "remove" ) {
-
- bool multi = e["multi"].eoo() ? true : e["multi"].trueValue();
- BSONObj query = e["query"].eoo() ? BSONObj() : e["query"].Obj();
- bool safe = e["safe"].trueValue();
- BSONObj result;
- {
- BenchRunEventTrace _bret(&stats.deleteCounter);
- BSONObj predicate = fixQuery(query, bsonTemplateEvaluator);
- if (useWriteCmd) {
-
- // TODO: Replace after SERVER-11774.
- BSONObjBuilder builder;
- builder.append("delete",
- nsToCollectionSubstring(ns));
- BSONArrayBuilder docBuilder(
- builder.subarrayStart("deletes"));
- int limit = (multi == true) ? 0 : 1;
- docBuilder.append(
- BSON("q" << predicate <<
- "limit" << limit));
- docBuilder.done();
- conn->runCommand(
- nsToDatabaseSubstring(ns).toString(),
- builder.done(), result);
- }
- else {
- conn->remove(ns, predicate, !multi);
- if (safe)
- result = conn->getLastErrorDetailed();
+ return;
}
}
- if( safe ){
- if( check ){
- int err = scope->invoke( scopeFunc , 0 , &result, 1000 * 60 , false );
- if( err ){
- log() << "Error checking in benchRun thread [delete]" << causedBy( scope->getError() ) << endl;
-
- stats.errCount++;
+ if (!_config->hideResults || e["showResult"].trueValue())
+ log() << "Result from benchRun thread [safe remove] : " << result
+ << endl;
- return;
- }
- }
+ if (!result["err"].eoo() && result["err"].type() == String &&
+ (_config->throwGLE || e["throwGLE"].trueValue()))
+ throw DBException((string) "From benchRun GLE " +
+ causedBy(result["err"].String()),
+ result["code"].eoo() ? 0 : result["code"].Int());
+ }
+ } else if (op == "createIndex") {
+ conn->ensureIndex(ns, e["key"].Obj(), false, "", false);
+ } else if (op == "dropIndex") {
+ conn->dropIndex(ns, e["key"].Obj());
+ } else if (op == "let") {
+ string target = e["target"].eoo() ? string() : e["target"].String();
+ BSONElement value = e["value"].eoo() ? BSONElement() : e["value"];
+ BSONObjBuilder valBuilder;
+ BSONObjBuilder templateBuilder;
+ valBuilder.append(value);
+ bsonTemplateEvaluator.evaluate(valBuilder.done(), templateBuilder);
+ bsonTemplateEvaluator.setVariable(target,
+ templateBuilder.done().firstElement());
+ } else {
+ log() << "don't understand op: " << op << endl;
+ stats.error = true;
+ return;
+ }
+ // Count 1 for total ops. Successfully got through the try phrase
+ stats.opCount++;
+ } catch (DBException& ex) {
+ if (!_config->hideErrors || e["showError"].trueValue()) {
+ bool yesWatch =
+ (_config->watchPattern && _config->watchPattern->FullMatch(ex.what()));
+ bool noWatch =
+ (_config->noWatchPattern && _config->noWatchPattern->FullMatch(ex.what()));
+
+ if ((!_config->watchPattern && _config->noWatchPattern &&
+ !noWatch) || // If we're just ignoring things
+ (!_config->noWatchPattern && _config->watchPattern &&
+ yesWatch) || // If we're just watching things
+ (_config->watchPattern && _config->noWatchPattern && yesWatch && !noWatch))
+ log() << "Error in benchRun thread for op " << e << causedBy(ex) << endl;
+ }
- if( ! _config->hideResults || e["showResult"].trueValue() ) log() << "Result from benchRun thread [safe remove] : " << result << endl;
+ bool yesTrap = (_config->trapPattern && _config->trapPattern->FullMatch(ex.what()));
+ bool noTrap =
+ (_config->noTrapPattern && _config->noTrapPattern->FullMatch(ex.what()));
- if( ! result["err"].eoo() && result["err"].type() == String && ( _config->throwGLE || e["throwGLE"].trueValue() ) )
- throw DBException( (string)"From benchRun GLE " + causedBy( result["err"].String() ),
- result["code"].eoo() ? 0 : result["code"].Int() );
- }
- }
- else if ( op == "createIndex" ) {
- conn->ensureIndex(ns, e["key"].Obj(), false, "", false);
+ if ((!_config->trapPattern && _config->noTrapPattern && !noTrap) ||
+ (!_config->noTrapPattern && _config->trapPattern && yesTrap) ||
+ (_config->trapPattern && _config->noTrapPattern && yesTrap && !noTrap)) {
+ {
+ stats.trappedErrors.push_back(
+ BSON("error" << ex.what() << "op" << e << "count" << count));
}
- else if ( op == "dropIndex" ) {
- conn->dropIndex( ns , e["key"].Obj() );
- }
- else if( op == "let" ) {
- string target = e["target"].eoo() ? string() : e["target"].String();
- BSONElement value = e["value"].eoo() ? BSONElement() : e["value"];
- BSONObjBuilder valBuilder;
- BSONObjBuilder templateBuilder;
- valBuilder.append(value);
- bsonTemplateEvaluator.evaluate(valBuilder.done(), templateBuilder);
- bsonTemplateEvaluator.setVariable(target, templateBuilder.done().firstElement());
- }
- else {
- log() << "don't understand op: " << op << endl;
- stats.error = true;
+ if (_config->breakOnTrap)
return;
- }
- // Count 1 for total ops. Successfully got through the try phrase
- stats.opCount++;
}
- catch( DBException& ex ){
- if( ! _config->hideErrors || e["showError"].trueValue() ){
-
- bool yesWatch = ( _config->watchPattern && _config->watchPattern->FullMatch( ex.what() ) );
- bool noWatch = ( _config->noWatchPattern && _config->noWatchPattern->FullMatch( ex.what() ) );
+ if (!_config->handleErrors && !e["handleError"].trueValue())
+ return;
+
+ stats.errCount++;
+ } catch (...) {
+ if (!_config->hideErrors || e["showError"].trueValue())
+ log() << "Error in benchRun thread caused by unknown error for op " << e
+ << endl;
+ if (!_config->handleErrors && !e["handleError"].trueValue())
+ return;
+
+ stats.errCount++;
+ }
- if( ( ! _config->watchPattern && _config->noWatchPattern && ! noWatch ) || // If we're just ignoring things
- ( ! _config->noWatchPattern && _config->watchPattern && yesWatch ) || // If we're just watching things
- ( _config->watchPattern && _config->noWatchPattern && yesWatch && ! noWatch ) )
- log() << "Error in benchRun thread for op " << e << causedBy( ex ) << endl;
- }
+ if (++count % 100 == 0 && !useWriteCmd) {
+ conn->getLastError();
+ }
- bool yesTrap = ( _config->trapPattern && _config->trapPattern->FullMatch( ex.what() ) );
- bool noTrap = ( _config->noTrapPattern && _config->noTrapPattern->FullMatch( ex.what() ) );
+ if (delay > 0)
+ sleepmillis(delay);
+ }
+ }
- if( ( ! _config->trapPattern && _config->noTrapPattern && ! noTrap ) ||
- ( ! _config->noTrapPattern && _config->trapPattern && yesTrap ) ||
- ( _config->trapPattern && _config->noTrapPattern && yesTrap && ! noTrap ) ){
- {
- stats.trappedErrors.push_back( BSON( "error" << ex.what() << "op" << e << "count" << count ) );
- }
- if( _config->breakOnTrap ) return;
- }
- if( ! _config->handleErrors && ! e["handleError"].trueValue() ) return;
+ conn->getLastError();
+}
- stats.errCount++;
- }
- catch( ... ){
- if( ! _config->hideErrors || e["showError"].trueValue() ) log() << "Error in benchRun thread caused by unknown error for op " << e << endl;
- if( ! _config->handleErrors && ! e["handleError"].trueValue() ) return;
+namespace {
+class BenchRunWorkerStateGuard {
+ MONGO_DISALLOW_COPYING(BenchRunWorkerStateGuard);
- stats.errCount++;
- }
+public:
+ explicit BenchRunWorkerStateGuard(BenchRunState* brState) : _brState(brState) {
+ _brState->onWorkerStarted();
+ }
- if (++count % 100 == 0 && !useWriteCmd) {
- conn->getLastError();
- }
+ ~BenchRunWorkerStateGuard() {
+ _brState->onWorkerFinished();
+ }
- if (delay > 0)
- sleepmillis( delay );
+private:
+ BenchRunState* _brState;
+};
+} // namespace
+void BenchRunWorker::run() {
+ try {
+ std::unique_ptr<DBClientBase> conn(_config->createConnection());
+ if (!_config->username.empty()) {
+ string errmsg;
+ if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
+ uasserted(15932, "Authenticating to connection for benchThread failed: " + errmsg);
}
}
-
- conn->getLastError();
+ BenchRunWorkerStateGuard _workerStateGuard(_brState);
+ generateLoadOnConnection(conn.get());
+ } catch (DBException& e) {
+ error() << "DBException not handled in benchRun thread" << causedBy(e) << endl;
+ } catch (std::exception& e) {
+ error() << "std::exception not handled in benchRun thread" << causedBy(e) << endl;
+ } catch (...) {
+ error() << "Unknown exception not handled in benchRun thread." << endl;
}
+}
- namespace {
- class BenchRunWorkerStateGuard {
- MONGO_DISALLOW_COPYING(BenchRunWorkerStateGuard);
- public:
- explicit BenchRunWorkerStateGuard( BenchRunState *brState ) : _brState( brState ) {
- _brState->onWorkerStarted();
- }
+BenchRunner::BenchRunner(BenchRunConfig* config) : _brState(config->parallel), _config(config) {
+ _oid.init();
+ stdx::lock_guard<stdx::mutex> lk(_staticMutex);
+ _activeRuns[_oid] = this;
+}
- ~BenchRunWorkerStateGuard() {
- _brState->onWorkerFinished();
- }
+BenchRunner::~BenchRunner() {
+ for (size_t i = 0; i < _workers.size(); ++i)
+ delete _workers[i];
+}
- private:
- BenchRunState *_brState;
- };
- } // namespace
-
- void BenchRunWorker::run() {
- try {
- std::unique_ptr<DBClientBase> conn( _config->createConnection() );
- if ( !_config->username.empty() ) {
- string errmsg;
- if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
- uasserted(15932,
- "Authenticating to connection for benchThread failed: " + errmsg);
- }
+void BenchRunner::start() {
+ {
+ std::unique_ptr<DBClientBase> conn(_config->createConnection());
+ // Must authenticate to admin db in order to run serverStatus command
+ if (_config->username != "") {
+ string errmsg;
+ if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
+ uasserted(16704,
+ str::stream()
+ << "User " << _config->username
+ << " could not authenticate to admin db; admin db access is "
+ "required to use benchRun with auth enabled");
}
- BenchRunWorkerStateGuard _workerStateGuard( _brState );
- generateLoadOnConnection( conn.get() );
- }
- catch( DBException& e ){
- error() << "DBException not handled in benchRun thread" << causedBy( e ) << endl;
- }
- catch( std::exception& e ){
- error() << "std::exception not handled in benchRun thread" << causedBy( e ) << endl;
}
- catch( ... ){
- error() << "Unknown exception not handled in benchRun thread." << endl;
+
+ // Start threads
+ for (int64_t i = 0; i < _config->parallel; i++) {
+ // Make a unique random seed for the worker.
+ int64_t seed = _config->randomSeed + i;
+ BenchRunWorker* worker = new BenchRunWorker(i, _config.get(), &_brState, seed);
+ worker->start();
+ _workers.push_back(worker);
}
- }
- BenchRunner::BenchRunner( BenchRunConfig *config )
- : _brState(config->parallel),
- _config(config) {
+ _brState.waitForState(BenchRunState::BRS_RUNNING);
- _oid.init();
- stdx::lock_guard<stdx::mutex> lk(_staticMutex);
- _activeRuns[_oid] = this;
- }
-
- BenchRunner::~BenchRunner() {
- for (size_t i = 0; i < _workers.size(); ++i)
- delete _workers[i];
- }
-
- void BenchRunner::start( ) {
-
- {
- std::unique_ptr<DBClientBase> conn( _config->createConnection() );
- // Must authenticate to admin db in order to run serverStatus command
- if (_config->username != "") {
- string errmsg;
- if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
- uasserted(16704,
- str::stream() << "User " << _config->username
- << " could not authenticate to admin db; admin db access is "
- "required to use benchRun with auth enabled");
- }
- }
-
- // Start threads
- for ( int64_t i = 0; i < _config->parallel; i++ ) {
- // Make a unique random seed for the worker.
- int64_t seed = _config->randomSeed + i;
- BenchRunWorker *worker = new BenchRunWorker(i, _config.get(),
- &_brState, seed);
- worker->start();
- _workers.push_back(worker);
- }
-
- _brState.waitForState(BenchRunState::BRS_RUNNING);
-
- // initial stats
- _brState.tellWorkersToCollectStats();
- _brTimer = new mongo::Timer();
- }
- }
-
- void BenchRunner::stop() {
- _brState.tellWorkersToFinish();
- _brState.waitForState(BenchRunState::BRS_FINISHED);
- _microsElapsed = _brTimer->micros();
- delete _brTimer;
-
- {
- std::unique_ptr<DBClientBase> conn( _config->createConnection() );
- if (_config->username != "") {
- string errmsg;
- // this can only fail if admin access was revoked since start of run
- if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
- uasserted(16705,
- str::stream() << "User " << _config->username
- << " could not authenticate to admin db; admin db access is "
- "still required to use benchRun with auth enabled");
- }
- }
- }
-
- {
- stdx::lock_guard<stdx::mutex> lk(_staticMutex);
- _activeRuns.erase( _oid );
- }
- }
-
- BenchRunner* BenchRunner::createWithConfig( const BSONObj &configArgs ) {
- BenchRunConfig *config = BenchRunConfig::createFromBson( configArgs );
- return new BenchRunner(config);
- }
-
- BenchRunner* BenchRunner::get( OID oid ) {
- stdx::lock_guard<stdx::mutex> lk(_staticMutex);
- return _activeRuns[ oid ];
- }
-
- void BenchRunner::populateStats( BenchRunStats *stats ) {
- _brState.assertFinished();
- stats->reset();
- for ( size_t i = 0; i < _workers.size(); ++i )
- stats->updateFrom( _workers[i]->stats() );
+ // initial stats
+ _brState.tellWorkersToCollectStats();
+ _brTimer = new mongo::Timer();
}
+}
- static void appendAverageMicrosIfAvailable(
- BSONObjBuilder &buf, const std::string &name, const BenchRunEventCounter &counter) {
+void BenchRunner::stop() {
+ _brState.tellWorkersToFinish();
+ _brState.waitForState(BenchRunState::BRS_FINISHED);
+ _microsElapsed = _brTimer->micros();
+ delete _brTimer;
- if (counter.getNumEvents() > 0)
- buf.append(name,
- static_cast<double>(counter.getTotalTimeMicros()) / counter.getNumEvents());
- }
+ {
+ std::unique_ptr<DBClientBase> conn(_config->createConnection());
+ if (_config->username != "") {
+ string errmsg;
+ // this can only fail if admin access was revoked since start of run
+ if (!conn->auth("admin", _config->username, _config->password, errmsg)) {
+ uasserted(16705,
+ str::stream()
+ << "User " << _config->username
+ << " could not authenticate to admin db; admin db access is "
+ "still required to use benchRun with auth enabled");
+ }
+ }
+ }
- BSONObj BenchRunner::finish( BenchRunner* runner ) {
+ {
+ stdx::lock_guard<stdx::mutex> lk(_staticMutex);
+ _activeRuns.erase(_oid);
+ }
+}
- runner->stop();
+BenchRunner* BenchRunner::createWithConfig(const BSONObj& configArgs) {
+ BenchRunConfig* config = BenchRunConfig::createFromBson(configArgs);
+ return new BenchRunner(config);
+}
+
+BenchRunner* BenchRunner::get(OID oid) {
+ stdx::lock_guard<stdx::mutex> lk(_staticMutex);
+ return _activeRuns[oid];
+}
- BenchRunStats stats;
- runner->populateStats(&stats);
+void BenchRunner::populateStats(BenchRunStats* stats) {
+ _brState.assertFinished();
+ stats->reset();
+ for (size_t i = 0; i < _workers.size(); ++i)
+ stats->updateFrom(_workers[i]->stats());
+}
- // vector<BSONOBj> errors = runner->config.errors;
- bool error = stats.error;
+static void appendAverageMicrosIfAvailable(BSONObjBuilder& buf,
+ const std::string& name,
+ const BenchRunEventCounter& counter) {
+ if (counter.getNumEvents() > 0)
+ buf.append(name,
+ static_cast<double>(counter.getTotalTimeMicros()) / counter.getNumEvents());
+}
- if ( error )
- return BSON( "err" << 1 );
+BSONObj BenchRunner::finish(BenchRunner* runner) {
+ runner->stop();
- BSONObjBuilder buf;
- buf.append( "note" , "values per second" );
- buf.append( "errCount", static_cast<long long>(stats.errCount) );
- buf.append( "trapped", "error: not implemented" );
- appendAverageMicrosIfAvailable(buf, "findOneLatencyAverageMicros", stats.findOneCounter);
- appendAverageMicrosIfAvailable(buf, "insertLatencyAverageMicros", stats.insertCounter);
- appendAverageMicrosIfAvailable(buf, "deleteLatencyAverageMicros", stats.deleteCounter);
- appendAverageMicrosIfAvailable(buf, "updateLatencyAverageMicros", stats.updateCounter);
- appendAverageMicrosIfAvailable(buf, "queryLatencyAverageMicros", stats.queryCounter);
- appendAverageMicrosIfAvailable(buf, "commandsLatencyAverageMicros", stats.commandCounter);
+ BenchRunStats stats;
+ runner->populateStats(&stats);
- buf.append("totalOps", static_cast<long long>(stats.opCount));
+ // vector<BSONOBj> errors = runner->config.errors;
+ bool error = stats.error;
- auto appendPerSec = [&buf, runner](StringData name, double total) {
- buf.append(name, total / (runner->_microsElapsed / 1000000.0));
- };
+ if (error)
+ return BSON("err" << 1);
- appendPerSec("totalOps/s", stats.opCount);
- appendPerSec("findOne", stats.findOneCounter.getNumEvents());
- appendPerSec("insert", stats.insertCounter.getNumEvents());
- appendPerSec("delete", stats.deleteCounter.getNumEvents());
- appendPerSec("update", stats.updateCounter.getNumEvents());
- appendPerSec("query", stats.queryCounter.getNumEvents());
- appendPerSec("command", stats.commandCounter.getNumEvents());
+ BSONObjBuilder buf;
+ buf.append("note", "values per second");
+ buf.append("errCount", static_cast<long long>(stats.errCount));
+ buf.append("trapped", "error: not implemented");
+ appendAverageMicrosIfAvailable(buf, "findOneLatencyAverageMicros", stats.findOneCounter);
+ appendAverageMicrosIfAvailable(buf, "insertLatencyAverageMicros", stats.insertCounter);
+ appendAverageMicrosIfAvailable(buf, "deleteLatencyAverageMicros", stats.deleteCounter);
+ appendAverageMicrosIfAvailable(buf, "updateLatencyAverageMicros", stats.updateCounter);
+ appendAverageMicrosIfAvailable(buf, "queryLatencyAverageMicros", stats.queryCounter);
+ appendAverageMicrosIfAvailable(buf, "commandsLatencyAverageMicros", stats.commandCounter);
- BSONObj zoo = buf.obj();
+ buf.append("totalOps", static_cast<long long>(stats.opCount));
- delete runner;
- return zoo;
- }
+ auto appendPerSec = [&buf, runner](StringData name, double total) {
+ buf.append(name, total / (runner->_microsElapsed / 1000000.0));
+ };
- stdx::mutex BenchRunner::_staticMutex;
- map< OID, BenchRunner* > BenchRunner::_activeRuns;
+ appendPerSec("totalOps/s", stats.opCount);
+ appendPerSec("findOne", stats.findOneCounter.getNumEvents());
+ appendPerSec("insert", stats.insertCounter.getNumEvents());
+ appendPerSec("delete", stats.deleteCounter.getNumEvents());
+ appendPerSec("update", stats.updateCounter.getNumEvents());
+ appendPerSec("query", stats.queryCounter.getNumEvents());
+ appendPerSec("command", stats.commandCounter.getNumEvents());
- /**
- * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
- */
- BSONObj BenchRunner::benchRunSync( const BSONObj& argsFake, void* data ) {
+ BSONObj zoo = buf.obj();
- BSONObj start = benchStart( argsFake, data );
+ delete runner;
+ return zoo;
+}
- OID oid = OID( start.firstElement().String() );
- BenchRunner* runner = BenchRunner::get( oid );
+stdx::mutex BenchRunner::_staticMutex;
+map<OID, BenchRunner*> BenchRunner::_activeRuns;
- sleepmillis( (int)(1000.0 * runner->config().seconds) );
+/**
+ * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
+ */
+BSONObj BenchRunner::benchRunSync(const BSONObj& argsFake, void* data) {
+ BSONObj start = benchStart(argsFake, data);
- return benchFinish( start, data );
- }
+ OID oid = OID(start.firstElement().String());
+ BenchRunner* runner = BenchRunner::get(oid);
- /**
- * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
- */
- BSONObj BenchRunner::benchStart( const BSONObj& argsFake, void* data ) {
+ sleepmillis((int)(1000.0 * runner->config().seconds));
- verify( argsFake.firstElement().isABSONObj() );
- BSONObj args = argsFake.firstElement().Obj();
+ return benchFinish(start, data);
+}
- // Get new BenchRunner object
- BenchRunner* runner = BenchRunner::createWithConfig( args );
+/**
+ * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
+ */
+BSONObj BenchRunner::benchStart(const BSONObj& argsFake, void* data) {
+ verify(argsFake.firstElement().isABSONObj());
+ BSONObj args = argsFake.firstElement().Obj();
- runner->start();
- return BSON( "" << runner->oid().toString() );
- }
+ // Get new BenchRunner object
+ BenchRunner* runner = BenchRunner::createWithConfig(args);
- /**
- * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
- */
- BSONObj BenchRunner::benchFinish( const BSONObj& argsFake, void* data ) {
+ runner->start();
+ return BSON("" << runner->oid().toString());
+}
- OID oid = OID( argsFake.firstElement().String() );
+/**
+ * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
+ */
+BSONObj BenchRunner::benchFinish(const BSONObj& argsFake, void* data) {
+ OID oid = OID(argsFake.firstElement().String());
- // Get old BenchRunner object
- BenchRunner* runner = BenchRunner::get( oid );
+ // Get old BenchRunner object
+ BenchRunner* runner = BenchRunner::get(oid);
- BSONObj finalObj = BenchRunner::finish( runner );
+ BSONObj finalObj = BenchRunner::finish(runner);
- return BSON( "" << finalObj );
- }
+ return BSON("" << finalObj);
+}
-} // namespace mongo
+} // namespace mongo
diff --git a/src/mongo/shell/bench.h b/src/mongo/shell/bench.h
index a3ab7dc16ab..3fcb9e1db03 100644
--- a/src/mongo/shell/bench.h
+++ b/src/mongo/shell/bench.h
@@ -38,425 +38,446 @@
#include "mongo/util/timer.h"
namespace pcrecpp {
- class RE;
-} // namespace pcrecpp;
+class RE;
+} // namespace pcrecpp;
namespace mongo {
+/**
+ * Configuration object describing a bench run activity.
+ */
+class BenchRunConfig {
+ MONGO_DISALLOW_COPYING(BenchRunConfig);
+
+public:
+ /**
+ * Create a new BenchRunConfig object, and initialize it from the BSON
+ * document, "args".
+ *
+ * Caller owns the returned object, and is responsible for its deletion.
+ */
+ static BenchRunConfig* createFromBson(const BSONObj& args);
+
+ BenchRunConfig();
+
+ void initializeFromBson(const BSONObj& args);
+
+ // Create a new connection to the mongo instance specified by this configuration.
+ DBClientBase* createConnection() const;
+
+ /**
+ * Connection std::string describing the host to which to connect.
+ */
+ std::string host;
+
+ /**
+ * Name of the database on which to operate.
+ */
+ std::string db;
+
+ /**
+ * Optional username for authenticating to the database.
+ */
+ std::string username;
+
+ /**
+ * Optional password for authenticating to the database.
+ *
+ * Only useful if username is non-empty.
+ */
+ std::string password;
+
/**
- * Configuration object describing a bench run activity.
+ * Number of parallel threads to perform the bench run activity.
*/
- class BenchRunConfig {
- MONGO_DISALLOW_COPYING(BenchRunConfig);
- public:
-
- /**
- * Create a new BenchRunConfig object, and initialize it from the BSON
- * document, "args".
- *
- * Caller owns the returned object, and is responsible for its deletion.
- */
- static BenchRunConfig *createFromBson( const BSONObj &args );
-
- BenchRunConfig();
-
- void initializeFromBson( const BSONObj &args );
-
- // Create a new connection to the mongo instance specified by this configuration.
- DBClientBase *createConnection() const;
-
- /**
- * Connection std::string describing the host to which to connect.
- */
- std::string host;
-
- /**
- * Name of the database on which to operate.
- */
- std::string db;
-
- /**
- * Optional username for authenticating to the database.
- */
- std::string username;
-
- /**
- * Optional password for authenticating to the database.
- *
- * Only useful if username is non-empty.
- */
- std::string password;
-
- /**
- * Number of parallel threads to perform the bench run activity.
- */
- unsigned parallel;
-
- /**
- * Desired duration of the bench run activity, in seconds.
- *
- * NOTE: Only used by the javascript benchRun() and benchRunSync() functions.
- */
- double seconds;
-
- /// Base random seed for threads
- int64_t randomSeed;
-
- bool hideResults;
- bool handleErrors;
- bool hideErrors;
-
- std::shared_ptr< pcrecpp::RE > trapPattern;
- std::shared_ptr< pcrecpp::RE > noTrapPattern;
- std::shared_ptr< pcrecpp::RE > watchPattern;
- std::shared_ptr< pcrecpp::RE > noWatchPattern;
-
- /**
- * Operation description. A BSON array of objects, each describing a single
- * operation.
- *
- * Every thread in a benchRun job will perform these operations in sequence, restarting at
- * the beginning when the end is reached, until the job is stopped.
- *
- * TODO: Document the operation objects.
- *
- * TODO: Introduce support for performing each operation exactly N times.
- */
- BSONObj ops;
-
- bool throwGLE;
- bool breakOnTrap;
-
- private:
- /// Initialize a config object to its default values.
- void initializeToDefaults();
- };
+ unsigned parallel;
/**
- * An event counter for events that have an associated duration.
+ * Desired duration of the bench run activity, in seconds.
*
- * Not thread safe. Expected use is one instance per thread during parallel execution.
+ * NOTE: Only used by the javascript benchRun() and benchRunSync() functions.
*/
- class BenchRunEventCounter {
- MONGO_DISALLOW_COPYING(BenchRunEventCounter);
- public:
- /// Constructs a zeroed out counter.
- BenchRunEventCounter();
- ~BenchRunEventCounter();
-
- /**
- * Zero out the counter.
- */
- void reset();
-
- /**
- * Conceptually the equivalent of "+=". Adds "other" into this.
- */
- void updateFrom( const BenchRunEventCounter &other );
-
- /**
- * Count one instance of the event, which took "timeMicros" microseconds.
- */
- void countOne(long long timeMicros) {
- ++_numEvents;
- _totalTimeMicros += timeMicros;
- }
-
- /**
- * Get the total number of microseconds ellapsed during all observed events.
- */
- unsigned long long getTotalTimeMicros() const { return _totalTimeMicros; }
-
- /**
- * Get the number of observed events.
- */
- unsigned long long getNumEvents() const { return _numEvents; }
-
- private:
- unsigned long long _numEvents;
- long long _totalTimeMicros;
- };
+ double seconds;
+
+ /// Base random seed for threads
+ int64_t randomSeed;
+
+ bool hideResults;
+ bool handleErrors;
+ bool hideErrors;
+
+ std::shared_ptr<pcrecpp::RE> trapPattern;
+ std::shared_ptr<pcrecpp::RE> noTrapPattern;
+ std::shared_ptr<pcrecpp::RE> watchPattern;
+ std::shared_ptr<pcrecpp::RE> noWatchPattern;
/**
- * RAII object for tracing an event.
+ * Operation description. A BSON array of objects, each describing a single
+ * operation.
*
- * Construct an instance of this at the beginning of an event, and have it go out of scope at
- * the end, to facilitate tracking events.
+ * Every thread in a benchRun job will perform these operations in sequence, restarting at
+ * the beginning when the end is reached, until the job is stopped.
*
- * This type can be used to separately count failures and successes by passing two event
- * counters to the BenchRunEventCounter constructor, and calling "succeed()" on the object at
- * the end of a successful event. If an exception is thrown, the fail counter will receive the
- * event, and otherwise, the succes counter will.
+ * TODO: Document the operation objects.
*
- * In all cases, the counter objects must outlive the trace object.
+ * TODO: Introduce support for performing each operation exactly N times.
*/
- class BenchRunEventTrace {
- MONGO_DISALLOW_COPYING(BenchRunEventTrace);
- public:
- explicit BenchRunEventTrace(BenchRunEventCounter *eventCounter) {
- initialize(eventCounter, eventCounter, false);
- }
-
- BenchRunEventTrace(BenchRunEventCounter *successCounter,
- BenchRunEventCounter *failCounter,
- bool defaultToFailure=true) {
- initialize(successCounter, failCounter, defaultToFailure);
- }
-
- ~BenchRunEventTrace() {
- (_succeeded ? _successCounter : _failCounter)->countOne(_timer.micros());
- }
-
- void succeed() { _succeeded = true; }
- void fail() { _succeeded = false; }
-
- private:
- void initialize(BenchRunEventCounter *successCounter,
- BenchRunEventCounter *failCounter,
- bool defaultToFailure) {
- _successCounter = successCounter;
- _failCounter = failCounter;
- _succeeded = !defaultToFailure;
- }
-
- Timer _timer;
- BenchRunEventCounter *_successCounter;
- BenchRunEventCounter *_failCounter;
- bool _succeeded;
- };
+ BSONObj ops;
+
+ bool throwGLE;
+ bool breakOnTrap;
+
+private:
+ /// Initialize a config object to its default values.
+ void initializeToDefaults();
+};
+
+/**
+ * An event counter for events that have an associated duration.
+ *
+ * Not thread safe. Expected use is one instance per thread during parallel execution.
+ */
+class BenchRunEventCounter {
+ MONGO_DISALLOW_COPYING(BenchRunEventCounter);
+
+public:
+ /// Constructs a zeroed out counter.
+ BenchRunEventCounter();
+ ~BenchRunEventCounter();
+
+ /**
+ * Zero out the counter.
+ */
+ void reset();
+
+ /**
+ * Conceptually the equivalent of "+=". Adds "other" into this.
+ */
+ void updateFrom(const BenchRunEventCounter& other);
/**
- * Statistics object representing the result of a bench run activity.
+ * Count one instance of the event, which took "timeMicros" microseconds.
*/
- class BenchRunStats {
- MONGO_DISALLOW_COPYING(BenchRunStats);
- public:
- BenchRunStats();
- ~BenchRunStats();
+ void countOne(long long timeMicros) {
+ ++_numEvents;
+ _totalTimeMicros += timeMicros;
+ }
- void reset();
+ /**
+ * Get the total number of microseconds ellapsed during all observed events.
+ */
+ unsigned long long getTotalTimeMicros() const {
+ return _totalTimeMicros;
+ }
- void updateFrom( const BenchRunStats &other );
+ /**
+ * Get the number of observed events.
+ */
+ unsigned long long getNumEvents() const {
+ return _numEvents;
+ }
- bool error;
- unsigned long long errCount;
- unsigned long long opCount;
+private:
+ unsigned long long _numEvents;
+ long long _totalTimeMicros;
+};
- BenchRunEventCounter findOneCounter;
- BenchRunEventCounter updateCounter;
- BenchRunEventCounter insertCounter;
- BenchRunEventCounter deleteCounter;
- BenchRunEventCounter queryCounter;
- BenchRunEventCounter commandCounter;
+/**
+ * RAII object for tracing an event.
+ *
+ * Construct an instance of this at the beginning of an event, and have it go out of scope at
+ * the end, to facilitate tracking events.
+ *
+ * This type can be used to separately count failures and successes by passing two event
+ * counters to the BenchRunEventCounter constructor, and calling "succeed()" on the object at
+ * the end of a successful event. If an exception is thrown, the fail counter will receive the
+ * event, and otherwise, the succes counter will.
+ *
+ * In all cases, the counter objects must outlive the trace object.
+ */
+class BenchRunEventTrace {
+ MONGO_DISALLOW_COPYING(BenchRunEventTrace);
+
+public:
+ explicit BenchRunEventTrace(BenchRunEventCounter* eventCounter) {
+ initialize(eventCounter, eventCounter, false);
+ }
+
+ BenchRunEventTrace(BenchRunEventCounter* successCounter,
+ BenchRunEventCounter* failCounter,
+ bool defaultToFailure = true) {
+ initialize(successCounter, failCounter, defaultToFailure);
+ }
+
+ ~BenchRunEventTrace() {
+ (_succeeded ? _successCounter : _failCounter)->countOne(_timer.micros());
+ }
+
+ void succeed() {
+ _succeeded = true;
+ }
+ void fail() {
+ _succeeded = false;
+ }
+
+private:
+ void initialize(BenchRunEventCounter* successCounter,
+ BenchRunEventCounter* failCounter,
+ bool defaultToFailure) {
+ _successCounter = successCounter;
+ _failCounter = failCounter;
+ _succeeded = !defaultToFailure;
+ }
+
+ Timer _timer;
+ BenchRunEventCounter* _successCounter;
+ BenchRunEventCounter* _failCounter;
+ bool _succeeded;
+};
+
+/**
+ * Statistics object representing the result of a bench run activity.
+ */
+class BenchRunStats {
+ MONGO_DISALLOW_COPYING(BenchRunStats);
+
+public:
+ BenchRunStats();
+ ~BenchRunStats();
+
+ void reset();
+
+ void updateFrom(const BenchRunStats& other);
+
+ bool error;
+ unsigned long long errCount;
+ unsigned long long opCount;
+
+ BenchRunEventCounter findOneCounter;
+ BenchRunEventCounter updateCounter;
+ BenchRunEventCounter insertCounter;
+ BenchRunEventCounter deleteCounter;
+ BenchRunEventCounter queryCounter;
+ BenchRunEventCounter commandCounter;
+
+ std::map<std::string, long long> opcounters;
+ std::vector<BSONObj> trappedErrors;
+};
+
+/**
+ * State of a BenchRun activity.
+ *
+ * Logically, the states are "starting up", "running" and "finished."
+ */
+class BenchRunState {
+ MONGO_DISALLOW_COPYING(BenchRunState);
- std::map<std::string, long long> opcounters;
- std::vector<BSONObj> trappedErrors;
- };
+public:
+ enum State { BRS_STARTING_UP, BRS_RUNNING, BRS_FINISHED };
+ explicit BenchRunState(unsigned numWorkers);
+ ~BenchRunState();
+
+ //
+ // Functions called by the job-controlling thread, through an instance of BenchRunner.
+ //
+
+ /**
+ * Block until the current state is "awaitedState."
+ *
+ * massert() (uassert()?) if "awaitedState" is unreachable from
+ * the current state.
+ */
+ void waitForState(State awaitedState);
+
+ /**
+ * Notify the worker threads to wrap up. Does not block.
+ */
+ void tellWorkersToFinish();
+
+ /**
+ * Notify the worker threads to collect statistics. Does not block.
+ */
+ void tellWorkersToCollectStats();
+
+ /// Check that the current state is BRS_FINISHED.
+ void assertFinished();
+
+ //
+ // Functions called by the worker threads, through instances of BenchRunWorker.
+ //
+
+ /**
+ * Predicate that workers call to see if they should finish (as a result of a call
+ * to tellWorkersToFinish()).
+ */
+ bool shouldWorkerFinish();
+
+ /**
+ * Predicate that workers call to see if they should start collecting stats (as a result
+ * of a call to tellWorkersToCollectStats()).
+ */
+ bool shouldWorkerCollectStats();
+
+ /**
+ * Called by each BenchRunWorker from within its thread context, immediately before it
+ * starts sending requests to the configured mongo instance.
+ */
+ void onWorkerStarted();
+
+ /**
+ * Called by each BenchRunWorker from within its thread context, shortly after it finishes
+ * sending requests to the configured mongo instance.
+ */
+ void onWorkerFinished();
+
+private:
+ stdx::mutex _mutex;
+ stdx::condition_variable _stateChangeCondition;
+ unsigned _numUnstartedWorkers;
+ unsigned _numActiveWorkers;
+ AtomicUInt32 _isShuttingDown;
+ AtomicUInt32 _isCollectingStats;
+};
+
+/**
+ * A single worker in the bench run activity.
+ *
+ * Represents the behavior of one thread working in a bench run activity.
+ */
+class BenchRunWorker {
+ MONGO_DISALLOW_COPYING(BenchRunWorker);
+
+public:
/**
- * State of a BenchRun activity.
+ * Create a new worker, performing one thread's worth of the activity described in
+ * "config", and part of the larger activity with state "brState". Both "config"
+ * and "brState" must exist for the life of this object.
*
- * Logically, the states are "starting up", "running" and "finished."
+ * "id" is a positive integer which should uniquely identify the worker.
*/
- class BenchRunState {
- MONGO_DISALLOW_COPYING(BenchRunState);
- public:
- enum State { BRS_STARTING_UP, BRS_RUNNING, BRS_FINISHED };
-
- explicit BenchRunState(unsigned numWorkers);
- ~BenchRunState();
-
- //
- // Functions called by the job-controlling thread, through an instance of BenchRunner.
- //
-
- /**
- * Block until the current state is "awaitedState."
- *
- * massert() (uassert()?) if "awaitedState" is unreachable from
- * the current state.
- */
- void waitForState(State awaitedState);
-
- /**
- * Notify the worker threads to wrap up. Does not block.
- */
- void tellWorkersToFinish();
-
- /**
- * Notify the worker threads to collect statistics. Does not block.
- */
- void tellWorkersToCollectStats();
-
- /// Check that the current state is BRS_FINISHED.
- void assertFinished();
-
- //
- // Functions called by the worker threads, through instances of BenchRunWorker.
- //
-
- /**
- * Predicate that workers call to see if they should finish (as a result of a call
- * to tellWorkersToFinish()).
- */
- bool shouldWorkerFinish();
-
- /**
- * Predicate that workers call to see if they should start collecting stats (as a result
- * of a call to tellWorkersToCollectStats()).
- */
- bool shouldWorkerCollectStats();
-
- /**
- * Called by each BenchRunWorker from within its thread context, immediately before it
- * starts sending requests to the configured mongo instance.
- */
- void onWorkerStarted();
-
- /**
- * Called by each BenchRunWorker from within its thread context, shortly after it finishes
- * sending requests to the configured mongo instance.
- */
- void onWorkerFinished();
-
- private:
- stdx::mutex _mutex;
- stdx::condition_variable _stateChangeCondition;
- unsigned _numUnstartedWorkers;
- unsigned _numActiveWorkers;
- AtomicUInt32 _isShuttingDown;
- AtomicUInt32 _isCollectingStats;
- };
+ BenchRunWorker(size_t id,
+ const BenchRunConfig* config,
+ BenchRunState* brState,
+ int64_t randomSeed);
+ ~BenchRunWorker();
/**
- * A single worker in the bench run activity.
+ * Start performing the "work" behavior in a new thread.
+ */
+ void start();
+
+ /**
+ * Get the run statistics for a worker.
+ *
+ * Should only be observed _after_ the worker has signaled its completion by calling
+ * onWorkerFinished() on the BenchRunState passed into its constructor.
+ */
+ const BenchRunStats& stats() const {
+ return _stats;
+ }
+
+private:
+ /// The main method of the worker, executed inside the thread launched by start().
+ void run();
+
+ /// The function that actually sets about generating the load described in "_config".
+ void generateLoadOnConnection(DBClientBase* conn);
+
+ /// Predicate, used to decide whether or not it's time to terminate the worker.
+ bool shouldStop() const;
+ /// Predicate, used to decide whether or not it's time to collect statistics
+ bool shouldCollectStats() const;
+
+ size_t _id;
+ const BenchRunConfig* _config;
+ BenchRunState* _brState;
+ BenchRunStats _stats;
+ /// Dummy stats to use before observation period.
+ BenchRunStats _statsBlackHole;
+ int64_t _randomSeed;
+};
+
+/**
+ * Object representing a "bench run" activity.
+ */
+class BenchRunner {
+ MONGO_DISALLOW_COPYING(BenchRunner);
+
+public:
+ /**
+ * Utility method to create a new bench runner from a BSONObj representation
+ * of a configuration.
*
- * Represents the behavior of one thread working in a bench run activity.
+ * TODO: This is only really for the use of the javascript benchRun() methods,
+ * and should probably move out of the BenchRunner class.
*/
- class BenchRunWorker {
- MONGO_DISALLOW_COPYING(BenchRunWorker);
- public:
-
- /**
- * Create a new worker, performing one thread's worth of the activity described in
- * "config", and part of the larger activity with state "brState". Both "config"
- * and "brState" must exist for the life of this object.
- *
- * "id" is a positive integer which should uniquely identify the worker.
- */
- BenchRunWorker(size_t id, const BenchRunConfig *config,
- BenchRunState *brState, int64_t randomSeed);
- ~BenchRunWorker();
-
- /**
- * Start performing the "work" behavior in a new thread.
- */
- void start();
-
- /**
- * Get the run statistics for a worker.
- *
- * Should only be observed _after_ the worker has signaled its completion by calling
- * onWorkerFinished() on the BenchRunState passed into its constructor.
- */
- const BenchRunStats &stats() const { return _stats; }
-
- private:
- /// The main method of the worker, executed inside the thread launched by start().
- void run();
-
- /// The function that actually sets about generating the load described in "_config".
- void generateLoadOnConnection( DBClientBase *conn );
-
- /// Predicate, used to decide whether or not it's time to terminate the worker.
- bool shouldStop() const;
- /// Predicate, used to decide whether or not it's time to collect statistics
- bool shouldCollectStats() const;
-
- size_t _id;
- const BenchRunConfig *_config;
- BenchRunState *_brState;
- BenchRunStats _stats;
- /// Dummy stats to use before observation period.
- BenchRunStats _statsBlackHole;
- int64_t _randomSeed;
- };
+ static BenchRunner* createWithConfig(const BSONObj& configArgs);
/**
- * Object representing a "bench run" activity.
+ * Look up a bench runner object by OID.
+ *
+ * TODO: Same todo as for "createWithConfig".
+ */
+ static BenchRunner* get(OID oid);
+
+ /**
+ * Stop a running "runner", and return a BSON representation of its resultant
+ * BenchRunStats.
+ *
+ * TODO: Same as for "createWithConfig".
+ */
+ static BSONObj finish(BenchRunner* runner);
+
+ /**
+ * Create a new bench runner, to perform the activity described by "*config."
+ *
+ * Takes ownership of "config", and will delete it.
+ */
+ explicit BenchRunner(BenchRunConfig* config);
+ ~BenchRunner();
+
+ /**
+ * Start the activity. Only call once per instance of BenchRunner.
+ */
+ void start();
+
+ /**
+ * Stop the activity. Block until the activitiy has stopped.
+ */
+ void stop();
+
+ /**
+ * Store the collected event data from a completed bench run activity into "stats."
+ *
+ * Illegal to call until after stop() returns.
*/
- class BenchRunner {
- MONGO_DISALLOW_COPYING(BenchRunner);
- public:
- /**
- * Utility method to create a new bench runner from a BSONObj representation
- * of a configuration.
- *
- * TODO: This is only really for the use of the javascript benchRun() methods,
- * and should probably move out of the BenchRunner class.
- */
- static BenchRunner* createWithConfig( const BSONObj &configArgs );
-
- /**
- * Look up a bench runner object by OID.
- *
- * TODO: Same todo as for "createWithConfig".
- */
- static BenchRunner* get( OID oid );
-
- /**
- * Stop a running "runner", and return a BSON representation of its resultant
- * BenchRunStats.
- *
- * TODO: Same as for "createWithConfig".
- */
- static BSONObj finish( BenchRunner* runner );
-
- /**
- * Create a new bench runner, to perform the activity described by "*config."
- *
- * Takes ownership of "config", and will delete it.
- */
- explicit BenchRunner( BenchRunConfig *config );
- ~BenchRunner();
-
- /**
- * Start the activity. Only call once per instance of BenchRunner.
- */
- void start();
-
- /**
- * Stop the activity. Block until the activitiy has stopped.
- */
- void stop();
-
- /**
- * Store the collected event data from a completed bench run activity into "stats."
- *
- * Illegal to call until after stop() returns.
- */
- void populateStats(BenchRunStats *stats);
-
- OID oid() const { return _oid; }
-
- const BenchRunConfig &config() const { return *_config; } // TODO: Remove this function.
-
- // JS bindings
- static BSONObj benchFinish(const BSONObj& argsFake, void* data);
- static BSONObj benchStart(const BSONObj& argsFake, void* data);
- static BSONObj benchRunSync(const BSONObj& argsFake, void* data);
-
- private:
- // TODO: Same as for createWithConfig.
- static stdx::mutex _staticMutex;
- static std::map< OID, BenchRunner* > _activeRuns;
-
- OID _oid;
- BenchRunState _brState;
- Timer *_brTimer;
- unsigned long long _microsElapsed;
- std::unique_ptr<BenchRunConfig> _config;
- std::vector<BenchRunWorker *> _workers;
- };
+ void populateStats(BenchRunStats* stats);
+
+ OID oid() const {
+ return _oid;
+ }
+
+ const BenchRunConfig& config() const {
+ return *_config;
+ } // TODO: Remove this function.
+
+ // JS bindings
+ static BSONObj benchFinish(const BSONObj& argsFake, void* data);
+ static BSONObj benchStart(const BSONObj& argsFake, void* data);
+ static BSONObj benchRunSync(const BSONObj& argsFake, void* data);
+
+private:
+ // TODO: Same as for createWithConfig.
+ static stdx::mutex _staticMutex;
+ static std::map<OID, BenchRunner*> _activeRuns;
+
+ OID _oid;
+ BenchRunState _brState;
+ Timer* _brTimer;
+ unsigned long long _microsElapsed;
+ std::unique_ptr<BenchRunConfig> _config;
+ std::vector<BenchRunWorker*> _workers;
+};
} // namespace mongo
diff --git a/src/mongo/shell/clientAndShell.cpp b/src/mongo/shell/clientAndShell.cpp
index 07f9b5cd83a..2f55cef17aa 100644
--- a/src/mongo/shell/clientAndShell.cpp
+++ b/src/mongo/shell/clientAndShell.cpp
@@ -39,44 +39,43 @@
namespace mongo {
- using std::endl;
- using std::string;
- using std::vector;
+using std::endl;
+using std::string;
+using std::vector;
- class Client;
- class DBClientBase;
- class OperationContext;
+class Client;
+class DBClientBase;
+class OperationContext;
- bool dbexitCalled = false;
+bool dbexitCalled = false;
- void dbexit( ExitCode returnCode, const char *whyMsg ) {
- {
- stdx::lock_guard<stdx::mutex> lk( shell_utils::mongoProgramOutputMutex );
- dbexitCalled = true;
- }
-
- log() << "dbexit called" << endl;
+void dbexit(ExitCode returnCode, const char* whyMsg) {
+ {
+ stdx::lock_guard<stdx::mutex> lk(shell_utils::mongoProgramOutputMutex);
+ dbexitCalled = true;
+ }
- if (whyMsg) {
- log() << " b/c " << whyMsg << endl;
- }
+ log() << "dbexit called" << endl;
- log() << "exiting" << endl;
- quickExit( returnCode );
+ if (whyMsg) {
+ log() << " b/c " << whyMsg << endl;
}
- bool inShutdown() {
- return dbexitCalled;
- }
+ log() << "exiting" << endl;
+ quickExit(returnCode);
+}
- bool haveLocalShardingInfo( Client* client, const string& ns ) {
- return false;
- }
+bool inShutdown() {
+ return dbexitCalled;
+}
- DBClientBase* createDirectClient(OperationContext* txn) {
- uassert( 10256 , "no createDirectClient in clientOnly" , 0 );
- return 0;
- }
+bool haveLocalShardingInfo(Client* client, const string& ns) {
+ return false;
+}
+DBClientBase* createDirectClient(OperationContext* txn) {
+ uassert(10256, "no createDirectClient in clientOnly", 0);
+ return 0;
+}
}
diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp
index aa161945e0d..17abb93f6ba 100644
--- a/src/mongo/shell/dbshell.cpp
+++ b/src/mongo/shell/dbshell.cpp
@@ -82,70 +82,68 @@ using namespace mongo;
string historyFile;
bool gotInterrupted = false;
bool inMultiLine = false;
-static volatile bool atPrompt = false; // can eval before getting to prompt
+static volatile bool atPrompt = false; // can eval before getting to prompt
namespace mongo {
- Scope * shellMainScope;
+Scope* shellMainScope;
- extern bool dbexitCalled;
+extern bool dbexitCalled;
}
-void generateCompletions( const string& prefix , vector<string>& all ) {
- if ( prefix.find( '"' ) != string::npos )
+void generateCompletions(const string& prefix, vector<string>& all) {
+ if (prefix.find('"') != string::npos)
return;
try {
- BSONObj args = BSON( "0" << prefix );
- shellMainScope->invokeSafe("function callShellAutocomplete(x) {shellAutocomplete(x)}",
- &args,
- NULL);
+ BSONObj args = BSON("0" << prefix);
+ shellMainScope->invokeSafe(
+ "function callShellAutocomplete(x) {shellAutocomplete(x)}", &args, NULL);
BSONObjBuilder b;
- shellMainScope->append( b , "" , "__autocomplete__" );
+ shellMainScope->append(b, "", "__autocomplete__");
BSONObj res = b.obj();
BSONObj arr = res.firstElement().Obj();
- BSONObjIterator i( arr );
- while ( i.more() ) {
+ BSONObjIterator i(arr);
+ while (i.more()) {
BSONElement e = i.next();
- all.push_back( e.String() );
+ all.push_back(e.String());
}
- }
- catch ( ... ) {
+ } catch (...) {
}
}
-void completionHook( const char* text , linenoiseCompletions* lc ) {
+void completionHook(const char* text, linenoiseCompletions* lc) {
vector<string> all;
- generateCompletions( text , all );
+ generateCompletions(text, all);
- for ( unsigned i = 0; i < all.size(); ++i )
- linenoiseAddCompletion( lc , (char*)all[i].c_str() );
+ for (unsigned i = 0; i < all.size(); ++i)
+ linenoiseAddCompletion(lc, (char*)all[i].c_str());
}
void shellHistoryInit() {
stringstream ss;
- const char * h = shell_utils::getUserDir();
- if ( h )
+ const char* h = shell_utils::getUserDir();
+ if (h)
ss << h << "/";
ss << ".dbshell";
historyFile = ss.str();
- linenoiseHistoryLoad( historyFile.c_str() );
- linenoiseSetCompletionCallback( completionHook );
+ linenoiseHistoryLoad(historyFile.c_str());
+ linenoiseSetCompletionCallback(completionHook);
}
void shellHistoryDone() {
- linenoiseHistorySave( historyFile.c_str() );
+ linenoiseHistorySave(historyFile.c_str());
linenoiseHistoryFree();
}
-void shellHistoryAdd( const char * line ) {
- if ( line[0] == '\0' )
+void shellHistoryAdd(const char* line) {
+ if (line[0] == '\0')
return;
// dont record duplicate lines
static string lastLine;
- if ( lastLine == line )
+ if (lastLine == line)
return;
lastLine = line;
@@ -154,56 +152,55 @@ void shellHistoryAdd( const char * line ) {
// detected by using regular expresions. This is so we can avoid storing passwords
// in the history file in plaintext.
static pcrecpp::RE hiddenHelpers(
- "\\.\\s*(auth|createUser|updateUser|changeUserPassword)\\s*\\(");
+ "\\.\\s*(auth|createUser|updateUser|changeUserPassword)\\s*\\(");
// Also don't want the raw user management commands to show in the shell when run directly
// via runCommand.
static pcrecpp::RE hiddenCommands(
- "(run|admin)Command\\s*\\(\\s*{\\s*(createUser|updateUser)\\s*:");
- if (!hiddenHelpers.PartialMatch(line) && !hiddenCommands.PartialMatch(line))
- {
- linenoiseHistoryAdd( line );
+ "(run|admin)Command\\s*\\(\\s*{\\s*(createUser|updateUser)\\s*:");
+ if (!hiddenHelpers.PartialMatch(line) && !hiddenCommands.PartialMatch(line)) {
+ linenoiseHistoryAdd(line);
}
}
void killOps() {
- if ( mongo::shell_utils::_nokillop )
+ if (mongo::shell_utils::_nokillop)
return;
- if ( atPrompt )
+ if (atPrompt)
return;
- sleepmillis(10); // give current op a chance to finish
+ sleepmillis(10); // give current op a chance to finish
- mongo::shell_utils::connectionRegistry.
- killOperationsOnAllConnections(!shellGlobalParams.autoKillOp);
+ mongo::shell_utils::connectionRegistry.killOperationsOnAllConnections(
+ !shellGlobalParams.autoKillOp);
}
// Stubs for signal_handlers.cpp
namespace mongo {
- void logProcessDetailsForLogRotate() {}
-
- void exitCleanly(ExitCode code) {
- {
- stdx::lock_guard<stdx::mutex> lk(mongo::shell_utils::mongoProgramOutputMutex);
- mongo::dbexitCalled = true;
- }
+void logProcessDetailsForLogRotate() {}
- ::killOps();
- ::shellHistoryDone();
- quickExit(0);
+void exitCleanly(ExitCode code) {
+ {
+ stdx::lock_guard<stdx::mutex> lk(mongo::shell_utils::mongoProgramOutputMutex);
+ mongo::dbexitCalled = true;
}
+
+ ::killOps();
+ ::shellHistoryDone();
+ quickExit(0);
+}
}
-void quitNicely( int sig ) {
+void quitNicely(int sig) {
exitCleanly(EXIT_CLEAN);
}
// the returned string is allocated with strdup() or malloc() and must be freed by calling free()
-char * shellReadline( const char * prompt , int handlesigint = 0 ) {
+char* shellReadline(const char* prompt, int handlesigint = 0) {
atPrompt = true;
- char * ret = linenoise( prompt );
- if ( ! ret ) {
+ char* ret = linenoise(prompt);
+ if (!ret) {
gotInterrupted = true; // got ^C, break out of multiline
}
@@ -212,32 +209,31 @@ char * shellReadline( const char * prompt , int handlesigint = 0 ) {
}
void setupSignals() {
- signal( SIGINT , quitNicely );
+ signal(SIGINT, quitNicely);
}
-string fixHost( const std::string& url, const std::string& host, const std::string& port ) {
- if ( host.size() == 0 && port.size() == 0 ) {
- if ( url.find( "/" ) == string::npos ) {
+string fixHost(const std::string& url, const std::string& host, const std::string& port) {
+ if (host.size() == 0 && port.size() == 0) {
+ if (url.find("/") == string::npos) {
// check for ips
- if ( url.find( "." ) != string::npos )
+ if (url.find(".") != string::npos)
return url + "/test";
- if ( url.rfind( ":" ) != string::npos &&
- isdigit( url[url.rfind(":")+1] ) )
+ if (url.rfind(":") != string::npos && isdigit(url[url.rfind(":") + 1]))
return url + "/test";
}
return url;
}
- if ( url.find( "/" ) != string::npos ) {
+ if (url.find("/") != string::npos) {
cerr << "url can't have host or port if you specify them individually" << endl;
quickExit(-1);
}
- string newurl( ( host.size() == 0 ) ? "127.0.0.1" : host );
- if ( port.size() > 0 )
+ string newurl((host.size() == 0) ? "127.0.0.1" : host);
+ if (port.size() > 0)
newurl += ":" + port;
- else if ( host.find(':') == string::npos ) {
+ else if (host.find(':') == string::npos) {
// need to add port with IPv6 addresses
newurl += ":27017";
}
@@ -249,22 +245,23 @@ string fixHost( const std::string& url, const std::string& host, const std::stri
static string OpSymbols = "~!%^&*-+=|:,<>/?.";
-bool isOpSymbol( char c ) {
- for ( size_t i = 0; i < OpSymbols.size(); i++ )
- if ( OpSymbols[i] == c ) return true;
+bool isOpSymbol(char c) {
+ for (size_t i = 0; i < OpSymbols.size(); i++)
+ if (OpSymbols[i] == c)
+ return true;
return false;
}
-bool isUseCmd( const std::string& code ) {
+bool isUseCmd(const std::string& code) {
string cmd = code;
- if ( cmd.find( " " ) > 0 )
- cmd = cmd.substr( 0 , cmd.find( " " ) );
+ if (cmd.find(" ") > 0)
+ cmd = cmd.substr(0, cmd.find(" "));
return cmd == "use";
}
/**
* Skip over a quoted string, including quotes escaped with backslash
- *
+ *
* @param code String
* @param start Starting position within string, always > 0
* @param quote Quote character (single or double quote)
@@ -281,80 +278,84 @@ size_t skipOverString(const std::string& code, size_t start, char quote) {
// that the escaping backslash is not itself escaped. Comparisons of start and pos
// are to keep us from reading beyond the beginning of the quoted string.
//
- if (start == pos || code[pos - 1] != '\\' || // previous char was backslash
- start == pos - 1 || code[pos - 2] == '\\' // char before backslash was not another
- ) {
+ if (start == pos || code[pos - 1] != '\\' || // previous char was backslash
+ start == pos - 1 ||
+ code[pos - 2] == '\\' // char before backslash was not another
+ ) {
break; // The quote we found was not preceded by an unescaped backslash; it is real
}
- ++pos; // The quote we found was escaped with backslash, so it doesn't count
+ ++pos; // The quote we found was escaped with backslash, so it doesn't count
}
return pos;
}
-bool isBalanced( const std::string& code ) {
- if (isUseCmd( code ))
+bool isBalanced(const std::string& code) {
+ if (isUseCmd(code))
return true; // don't balance "use <dbname>" in case dbname contains special chars
int curlyBrackets = 0;
int squareBrackets = 0;
int parens = 0;
bool danglingOp = false;
- for ( size_t i=0; i<code.size(); i++ ) {
- switch( code[i] ) {
- case '/':
- if ( i + 1 < code.size() && code[i+1] == '/' ) {
- while ( i <code.size() && code[i] != '\n' )
+ for (size_t i = 0; i < code.size(); i++) {
+ switch (code[i]) {
+ case '/':
+ if (i + 1 < code.size() && code[i + 1] == '/') {
+ while (i < code.size() && code[i] != '\n')
+ i++;
+ }
+ continue;
+ case '{':
+ curlyBrackets++;
+ break;
+ case '}':
+ if (curlyBrackets <= 0)
+ return true;
+ curlyBrackets--;
+ break;
+ case '[':
+ squareBrackets++;
+ break;
+ case ']':
+ if (squareBrackets <= 0)
+ return true;
+ squareBrackets--;
+ break;
+ case '(':
+ parens++;
+ break;
+ case ')':
+ if (parens <= 0)
+ return true;
+ parens--;
+ break;
+ case '"':
+ case '\'':
+ i = skipOverString(code, i + 1, code[i]);
+ if (i >= code.size()) {
+ return true; // Do not let unterminated strings enter multi-line mode
+ }
+ break;
+ case '\\':
+ if (i + 1 < code.size() && code[i + 1] == '/')
i++;
- }
- continue;
- case '{':
- curlyBrackets++;
- break;
- case '}':
- if ( curlyBrackets <= 0 )
- return true;
- curlyBrackets--;
- break;
- case '[':
- squareBrackets++;
- break;
- case ']':
- if ( squareBrackets <= 0 )
- return true;
- squareBrackets--;
- break;
- case '(':
- parens++;
- break;
- case ')':
- if ( parens <= 0 )
- return true;
- parens--;
- break;
- case '"':
- case '\'':
- i = skipOverString(code, i + 1, code[i]);
- if (i >= code.size()) {
- return true; // Do not let unterminated strings enter multi-line mode
- }
- break;
- case '\\':
- if ( i + 1 < code.size() && code[i+1] == '/' ) i++;
- break;
- case '+':
- case '-':
- if ( i + 1 < code.size() && code[i+1] == code[i] ) {
- i++;
- continue; // postfix op (++/--) can't be a dangling op
- }
- break;
+ break;
+ case '+':
+ case '-':
+ if (i + 1 < code.size() && code[i + 1] == code[i]) {
+ i++;
+ continue; // postfix op (++/--) can't be a dangling op
+ }
+ break;
}
- if ( i >= code.size() ) {
+ if (i >= code.size()) {
danglingOp = false;
break;
}
- if ( isOpSymbol( code[i] ) ) danglingOp = true;
- else if ( !std::isspace( static_cast<unsigned char>( code[i] ) ) ) danglingOp = false;
+ if (isOpSymbol(code[i]))
+ danglingOp = true;
+ else if (!std::isspace(static_cast<unsigned char>(code[i])))
+ danglingOp = false;
}
return curlyBrackets == 0 && squareBrackets == 0 && parens == 0 && !danglingOp;
@@ -363,74 +364,74 @@ bool isBalanced( const std::string& code ) {
struct BalancedTest : public mongo::StartupTest {
public:
void run() {
- verify( isBalanced( "x = 5" ) );
- verify( isBalanced( "function(){}" ) );
- verify( isBalanced( "function(){\n}" ) );
- verify( ! isBalanced( "function(){" ) );
- verify( isBalanced( "x = \"{\";" ) );
- verify( isBalanced( "// {" ) );
- verify( ! isBalanced( "// \n {" ) );
- verify( ! isBalanced( "\"//\" {" ) );
- verify( isBalanced( "{x:/x\\//}" ) );
- verify( ! isBalanced( "{ \\/// }" ) );
- verify( isBalanced( "x = 5 + y " ) );
- verify( ! isBalanced( "x = " ) );
- verify( ! isBalanced( "x = // hello" ) );
- verify( ! isBalanced( "x = 5 +" ) );
- verify( isBalanced( " x ++" ) );
- verify( isBalanced( "-- x" ) );
- verify( !isBalanced( "a." ) );
- verify( !isBalanced( "a. " ) );
- verify( isBalanced( "a.b" ) );
-
- // SERVER-5809 and related cases --
- verify( isBalanced( "a = {s:\"\\\"\"}" ) ); // a = {s:"\""}
- verify( isBalanced( "db.test.save({s:\"\\\"\"})" ) ); // db.test.save({s:"\""})
- verify( isBalanced( "printjson(\" \\\" \")" ) ); // printjson(" \" ") -- SERVER-8554
- verify( isBalanced( "var a = \"\\\\\";" ) ); // var a = "\\";
- verify( isBalanced( "var a = (\"\\\\\") //\"" ) ); // var a = ("\\") //"
- verify( isBalanced( "var a = (\"\\\\\") //\\\"" ) ); // var a = ("\\") //\"
- verify( isBalanced( "var a = (\"\\\\\") //" ) ); // var a = ("\\") //
- verify( isBalanced( "var a = (\"\\\\\")" ) ); // var a = ("\\")
- verify( isBalanced( "var a = (\"\\\\\\\"\")" ) ); // var a = ("\\\"")
- verify( ! isBalanced( "var a = (\"\\\\\" //\"" ) ); // var a = ("\\" //"
- verify( ! isBalanced( "var a = (\"\\\\\" //" ) ); // var a = ("\\" //
- verify( ! isBalanced( "var a = (\"\\\\\"" ) ); // var a = ("\\"
+ verify(isBalanced("x = 5"));
+ verify(isBalanced("function(){}"));
+ verify(isBalanced("function(){\n}"));
+ verify(!isBalanced("function(){"));
+ verify(isBalanced("x = \"{\";"));
+ verify(isBalanced("// {"));
+ verify(!isBalanced("// \n {"));
+ verify(!isBalanced("\"//\" {"));
+ verify(isBalanced("{x:/x\\//}"));
+ verify(!isBalanced("{ \\/// }"));
+ verify(isBalanced("x = 5 + y "));
+ verify(!isBalanced("x = "));
+ verify(!isBalanced("x = // hello"));
+ verify(!isBalanced("x = 5 +"));
+ verify(isBalanced(" x ++"));
+ verify(isBalanced("-- x"));
+ verify(!isBalanced("a."));
+ verify(!isBalanced("a. "));
+ verify(isBalanced("a.b"));
+
+ // SERVER-5809 and related cases --
+ verify(isBalanced("a = {s:\"\\\"\"}")); // a = {s:"\""}
+ verify(isBalanced("db.test.save({s:\"\\\"\"})")); // db.test.save({s:"\""})
+ verify(isBalanced("printjson(\" \\\" \")")); // printjson(" \" ") -- SERVER-8554
+ verify(isBalanced("var a = \"\\\\\";")); // var a = "\\";
+ verify(isBalanced("var a = (\"\\\\\") //\"")); // var a = ("\\") //"
+ verify(isBalanced("var a = (\"\\\\\") //\\\"")); // var a = ("\\") //\"
+ verify(isBalanced("var a = (\"\\\\\") //")); // var a = ("\\") //
+ verify(isBalanced("var a = (\"\\\\\")")); // var a = ("\\")
+ verify(isBalanced("var a = (\"\\\\\\\"\")")); // var a = ("\\\"")
+ verify(!isBalanced("var a = (\"\\\\\" //\"")); // var a = ("\\" //"
+ verify(!isBalanced("var a = (\"\\\\\" //")); // var a = ("\\" //
+ verify(!isBalanced("var a = (\"\\\\\"")); // var a = ("\\"
}
} balanced_test;
-string finishCode( string code ) {
- while ( ! isBalanced( code ) ) {
+string finishCode(string code) {
+ while (!isBalanced(code)) {
inMultiLine = true;
code += "\n";
// cancel multiline if two blank lines are entered
- if ( code.find( "\n\n\n" ) != string::npos )
+ if (code.find("\n\n\n") != string::npos)
return ";";
- char * line = shellReadline( "... " , 1 );
- if ( gotInterrupted ) {
- if ( line )
- free( line );
+ char* line = shellReadline("... ", 1);
+ if (gotInterrupted) {
+ if (line)
+ free(line);
return "";
}
- if ( ! line )
+ if (!line)
return "";
- char * linePtr = line;
- while ( str::startsWith( linePtr, "... " ) )
+ char* linePtr = line;
+ while (str::startsWith(linePtr, "... "))
linePtr += 4;
code += linePtr;
- free( line );
+ free(line);
}
return code;
}
-bool execPrompt( mongo::Scope &scope, const char *promptFunction, string &prompt ) {
- string execStatement = string( "__prompt__ = " ) + promptFunction + "();";
- scope.exec( "delete __prompt__;", "", false, false, false, 0 );
- scope.exec( execStatement, "", false, false, false, 0 );
- if ( scope.type( "__prompt__" ) == String ) {
- prompt = scope.getString( "__prompt__" );
+bool execPrompt(mongo::Scope& scope, const char* promptFunction, string& prompt) {
+ string execStatement = string("__prompt__ = ") + promptFunction + "();";
+ scope.exec("delete __prompt__;", "", false, false, false, 0);
+ scope.exec(execStatement, "", false, false, false, 0);
+ if (scope.type("__prompt__") == String) {
+ prompt = scope.getString("__prompt__");
return true;
}
return false;
@@ -441,53 +442,51 @@ bool execPrompt( mongo::Scope &scope, const char *promptFunction, string &prompt
*
* @param whatToEdit Name of JavaScript variable to be edited, or any text string
*/
-static void edit( const string& whatToEdit ) {
-
+static void edit(const string& whatToEdit) {
// EDITOR may be defined in the JavaScript scope or in the environment
string editor;
- if ( shellMainScope->type( "EDITOR" ) == String ) {
- editor = shellMainScope->getString( "EDITOR" );
- }
- else {
- static const char * editorFromEnv = getenv( "EDITOR" );
- if ( editorFromEnv ) {
+ if (shellMainScope->type("EDITOR") == String) {
+ editor = shellMainScope->getString("EDITOR");
+ } else {
+ static const char* editorFromEnv = getenv("EDITOR");
+ if (editorFromEnv) {
editor = editorFromEnv;
}
}
- if ( editor.empty() ) {
+ if (editor.empty()) {
cout << "please define EDITOR as a JavaScript string or as an environment variable" << endl;
return;
}
// "whatToEdit" might look like a variable/property name
bool editingVariable = true;
- for ( const char* p = whatToEdit.c_str(); *p; ++p ) {
- if ( ! ( isalnum( *p ) || *p == '_' || *p == '.' ) ) {
+ for (const char* p = whatToEdit.c_str(); *p; ++p) {
+ if (!(isalnum(*p) || *p == '_' || *p == '.')) {
editingVariable = false;
break;
}
}
string js;
- if ( editingVariable ) {
- // If "whatToEdit" is undeclared or uninitialized, declare
- int varType = shellMainScope->type( whatToEdit.c_str() );
- if ( varType == Undefined ) {
- shellMainScope->exec( "var " + whatToEdit , "(shell)", false, true, false );
+ if (editingVariable) {
+ // If "whatToEdit" is undeclared or uninitialized, declare
+ int varType = shellMainScope->type(whatToEdit.c_str());
+ if (varType == Undefined) {
+ shellMainScope->exec("var " + whatToEdit, "(shell)", false, true, false);
}
// Convert "whatToEdit" to JavaScript (JSON) text
- if ( !shellMainScope->exec( "__jsout__ = tojson(" + whatToEdit + ")", "tojs", false, false, false ) )
- return; // Error already printed
+ if (!shellMainScope->exec(
+ "__jsout__ = tojson(" + whatToEdit + ")", "tojs", false, false, false))
+ return; // Error already printed
- js = shellMainScope->getString( "__jsout__" );
+ js = shellMainScope->getString("__jsout__");
- if ( strstr( js.c_str(), "[native code]" ) ) {
+ if (strstr(js.c_str(), "[native code]")) {
cout << "can't edit native functions" << endl;
return;
}
- }
- else {
+ } else {
js = whatToEdit;
}
@@ -495,110 +494,110 @@ static void edit( const string& whatToEdit ) {
string filename;
const int maxAttempts = 10;
int i;
- for ( i = 0; i < maxAttempts; ++i ) {
+ for (i = 0; i < maxAttempts; ++i) {
StringBuilder sb;
#ifdef _WIN32
char tempFolder[MAX_PATH];
- GetTempPathA( sizeof tempFolder, tempFolder );
- sb << tempFolder << "mongo_edit" << time( 0 ) + i << ".js";
+ GetTempPathA(sizeof tempFolder, tempFolder);
+ sb << tempFolder << "mongo_edit" << time(0) + i << ".js";
#else
- sb << "/tmp/mongo_edit" << time( 0 ) + i << ".js";
+ sb << "/tmp/mongo_edit" << time(0) + i << ".js";
#endif
filename = sb.str();
if (!::mongo::shell_utils::fileExists(filename))
break;
}
- if ( i == maxAttempts ) {
+ if (i == maxAttempts) {
cout << "couldn't create unique temp file after " << maxAttempts << " attempts" << endl;
return;
}
// Create the temp file
- FILE * tempFileStream;
- tempFileStream = fopen( filename.c_str(), "wt" );
- if ( ! tempFileStream ) {
- cout << "couldn't create temp file (" << filename << "): " << errnoWithDescription() << endl;
+ FILE* tempFileStream;
+ tempFileStream = fopen(filename.c_str(), "wt");
+ if (!tempFileStream) {
+ cout << "couldn't create temp file (" << filename << "): " << errnoWithDescription()
+ << endl;
return;
}
// Write JSON into the temp file
size_t fileSize = js.size();
- if ( fwrite( js.data(), sizeof( char ), fileSize, tempFileStream ) != fileSize ) {
+ if (fwrite(js.data(), sizeof(char), fileSize, tempFileStream) != fileSize) {
int systemErrno = errno;
- cout << "failed to write to temp file: " << errnoWithDescription( systemErrno ) << endl;
- fclose( tempFileStream );
- remove( filename.c_str() );
+ cout << "failed to write to temp file: " << errnoWithDescription(systemErrno) << endl;
+ fclose(tempFileStream);
+ remove(filename.c_str());
return;
}
- fclose( tempFileStream );
+ fclose(tempFileStream);
// Pass file to editor
StringBuilder sb;
sb << editor << " " << filename;
- int ret = ::system( sb.str().c_str() );
- if ( ret ) {
- if ( ret == -1 ) {
+ int ret = ::system(sb.str().c_str());
+ if (ret) {
+ if (ret == -1) {
int systemErrno = errno;
- cout << "failed to launch $EDITOR (" << editor << "): " << errnoWithDescription( systemErrno ) << endl;
- }
- else
+ cout << "failed to launch $EDITOR (" << editor
+ << "): " << errnoWithDescription(systemErrno) << endl;
+ } else
cout << "editor exited with error (" << ret << "), not applying changes" << endl;
- remove( filename.c_str() );
+ remove(filename.c_str());
return;
}
// The editor gave return code zero, so read the file back in
- tempFileStream = fopen( filename.c_str(), "rt" );
- if ( ! tempFileStream ) {
+ tempFileStream = fopen(filename.c_str(), "rt");
+ if (!tempFileStream) {
cout << "couldn't open temp file on return from editor: " << errnoWithDescription() << endl;
- remove( filename.c_str() );
+ remove(filename.c_str());
return;
}
sb.reset();
int bytes;
do {
char buf[1024];
- bytes = fread( buf, sizeof( char ), sizeof buf, tempFileStream );
- if ( ferror( tempFileStream ) ) {
+ bytes = fread(buf, sizeof(char), sizeof buf, tempFileStream);
+ if (ferror(tempFileStream)) {
cout << "failed to read temp file: " << errnoWithDescription() << endl;
- fclose( tempFileStream );
- remove( filename.c_str() );
+ fclose(tempFileStream);
+ remove(filename.c_str());
return;
}
- sb.append( StringData( buf, bytes ) );
- } while ( bytes );
+ sb.append(StringData(buf, bytes));
+ } while (bytes);
// Done with temp file, close and delete it
- fclose( tempFileStream );
- remove( filename.c_str() );
+ fclose(tempFileStream);
+ remove(filename.c_str());
- if ( editingVariable ) {
+ if (editingVariable) {
// Try to execute assignment to copy edited value back into the variable
- const string code = whatToEdit + string( " = " ) + sb.str();
- if ( !shellMainScope->exec( code, "tojs", false, true, false ) ) {
+ const string code = whatToEdit + string(" = ") + sb.str();
+ if (!shellMainScope->exec(code, "tojs", false, true, false)) {
cout << "error executing assignment: " << code << endl;
}
- }
- else {
- linenoisePreloadBuffer( sb.str().c_str() );
+ } else {
+ linenoisePreloadBuffer(sb.str().c_str());
}
}
-int _main( int argc, char* argv[], char **envp ) {
+int _main(int argc, char* argv[], char** envp) {
setupSignalHandlers(true);
setupSignals();
- mongo::shell_utils::RecordMyLocation( argv[ 0 ] );
+ mongo::shell_utils::RecordMyLocation(argv[0]);
shellGlobalParams.url = "test";
mongo::runGlobalInitializersOrDie(argc, argv, envp);
// hide password from ps output
- for ( int i = 0; i < (argc-1); ++i ) {
- if ( !strcmp(argv[i], "-p") || !strcmp( argv[i], "--password" ) ) {
+ for (int i = 0; i < (argc - 1); ++i) {
+ if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--password")) {
char* arg = argv[i + 1];
- while ( *arg ) {
+ while (*arg) {
*arg++ = 'x';
}
}
@@ -609,12 +608,13 @@ int _main( int argc, char* argv[], char **envp ) {
mongo::StartupTest::runTests();
- logger::globalLogManager()->getNamedDomain("javascriptOutput")->attachAppender(
- logger::MessageLogDomain::AppenderAutoPtr(
- new logger::ConsoleAppender<logger::MessageEventEphemeral>(
- new logger::MessageEventUnadornedEncoder)));
+ logger::globalLogManager()
+ ->getNamedDomain("javascriptOutput")
+ ->attachAppender(logger::MessageLogDomain::AppenderAutoPtr(
+ new logger::ConsoleAppender<logger::MessageEventEphemeral>(
+ new logger::MessageEventUnadornedEncoder)));
- if (!shellGlobalParams.nodb) { // connect to db
+ if (!shellGlobalParams.nodb) { // connect to db
stringstream ss;
if (mongo::serverGlobalParams.quiet)
ss << "__quiet = true;";
@@ -642,32 +642,30 @@ int _main( int argc, char* argv[], char **envp ) {
stringstream authStringStream;
authStringStream << "(function() { " << endl;
if (!shellGlobalParams.authenticationMechanism.empty()) {
- authStringStream << "DB.prototype._defaultAuthenticationMechanism = \"" <<
- escape(shellGlobalParams.authenticationMechanism) << "\";" << endl;
+ authStringStream << "DB.prototype._defaultAuthenticationMechanism = \""
+ << escape(shellGlobalParams.authenticationMechanism) << "\";" << endl;
}
if (!shellGlobalParams.gssapiServiceName.empty()) {
- authStringStream << "DB.prototype._defaultGssapiServiceName = \"" <<
- escape(shellGlobalParams.gssapiServiceName) << "\";" << endl;
+ authStringStream << "DB.prototype._defaultGssapiServiceName = \""
+ << escape(shellGlobalParams.gssapiServiceName) << "\";" << endl;
}
if (!shellGlobalParams.nodb && shellGlobalParams.username.size()) {
- authStringStream << "var username = \"" << escape(shellGlobalParams.username) << "\";" <<
- endl;
+ authStringStream << "var username = \"" << escape(shellGlobalParams.username) << "\";"
+ << endl;
if (shellGlobalParams.usingPassword) {
authStringStream << "var password = \"" << escape(shellGlobalParams.password) << "\";"
<< endl;
}
if (shellGlobalParams.authenticationDatabase.empty()) {
authStringStream << "var authDb = db;" << endl;
- }
- else {
+ } else {
authStringStream << "var authDb = db.getSiblingDB(\""
<< escape(shellGlobalParams.authenticationDatabase) << "\");" << endl;
}
- authStringStream << "authDb._authOrThrow({ " <<
- saslCommandUserFieldName << ": username ";
- if (shellGlobalParams.usingPassword) {
+ authStringStream << "authDb._authOrThrow({ " << saslCommandUserFieldName << ": username ";
+ if (shellGlobalParams.usingPassword) {
authStringStream << ", " << saslCommandPasswordFieldName << ": password ";
}
@@ -680,93 +678,92 @@ int _main( int argc, char* argv[], char **envp ) {
authStringStream << "}())";
mongo::shell_utils::_dbAuth = authStringStream.str();
- mongo::ScriptEngine::setConnectCallback( mongo::shell_utils::onConnect );
+ mongo::ScriptEngine::setConnectCallback(mongo::shell_utils::onConnect);
mongo::ScriptEngine::setup();
- mongo::globalScriptEngine->setScopeInitCallback( mongo::shell_utils::initScope );
- unique_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() );
+ mongo::globalScriptEngine->setScopeInitCallback(mongo::shell_utils::initScope);
+ unique_ptr<mongo::Scope> scope(mongo::globalScriptEngine->newScope());
shellMainScope = scope.get();
- if( shellGlobalParams.runShell )
+ if (shellGlobalParams.runShell)
cout << "type \"help\" for help" << endl;
-
+
// Load and execute /etc/mongorc.js before starting shell
std::string rcGlobalLocation;
#ifndef _WIN32
- rcGlobalLocation = "/etc/mongorc.js" ;
+ rcGlobalLocation = "/etc/mongorc.js";
#else
wchar_t programDataPath[MAX_PATH];
- if ( S_OK == SHGetFolderPathW(NULL,
- CSIDL_COMMON_APPDATA,
- NULL,
- 0,
- programDataPath) ) {
+ if (S_OK == SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, programDataPath)) {
rcGlobalLocation = str::stream() << toUtf8String(programDataPath)
<< "\\MongoDB\\mongorc.js";
}
-#endif
- if ( !rcGlobalLocation.empty() && ::mongo::shell_utils::fileExists(rcGlobalLocation) ) {
- if ( ! scope->execFile( rcGlobalLocation , false , true ) ) {
+#endif
+ if (!rcGlobalLocation.empty() && ::mongo::shell_utils::fileExists(rcGlobalLocation)) {
+ if (!scope->execFile(rcGlobalLocation, false, true)) {
cout << "The \"" << rcGlobalLocation << "\" file could not be executed" << endl;
}
}
- if ( !shellGlobalParams.script.empty() ) {
+ if (!shellGlobalParams.script.empty()) {
mongo::shell_utils::MongoProgramScope s;
- if ( ! scope->exec( shellGlobalParams.script , "(shell eval)" , true , true , false ) )
+ if (!scope->exec(shellGlobalParams.script, "(shell eval)", true, true, false))
return -4;
}
for (size_t i = 0; i < shellGlobalParams.files.size(); ++i) {
mongo::shell_utils::MongoProgramScope s;
- if ( shellGlobalParams.files.size() > 1 )
+ if (shellGlobalParams.files.size() > 1)
cout << "loading file: " << shellGlobalParams.files[i] << endl;
- if ( ! scope->execFile( shellGlobalParams.files[i] , false , true ) ) {
+ if (!scope->execFile(shellGlobalParams.files[i], false, true)) {
cout << "failed to load: " << shellGlobalParams.files[i] << endl;
return -3;
}
}
- if ( shellGlobalParams.files.size() == 0 && shellGlobalParams.script.empty() )
+ if (shellGlobalParams.files.size() == 0 && shellGlobalParams.script.empty())
shellGlobalParams.runShell = true;
- if ( shellGlobalParams.runShell ) {
-
+ if (shellGlobalParams.runShell) {
mongo::shell_utils::MongoProgramScope s;
// If they specify norc, assume it's not their first time
bool hasMongoRC = shellGlobalParams.norc;
string rcLocation;
- if ( !shellGlobalParams.norc ) {
+ if (!shellGlobalParams.norc) {
#ifndef _WIN32
- if ( getenv( "HOME" ) != NULL )
- rcLocation = str::stream() << getenv( "HOME" ) << "/.mongorc.js" ;
+ if (getenv("HOME") != NULL)
+ rcLocation = str::stream() << getenv("HOME") << "/.mongorc.js";
#else
- if ( getenv( "HOMEDRIVE" ) != NULL && getenv( "HOMEPATH" ) != NULL )
+ if (getenv("HOMEDRIVE") != NULL && getenv("HOMEPATH") != NULL)
rcLocation = str::stream() << toUtf8String(_wgetenv(L"HOMEDRIVE"))
<< toUtf8String(_wgetenv(L"HOMEPATH"))
<< "\\.mongorc.js";
#endif
- if ( !rcLocation.empty() && ::mongo::shell_utils::fileExists(rcLocation) ) {
+ if (!rcLocation.empty() && ::mongo::shell_utils::fileExists(rcLocation)) {
hasMongoRC = true;
- if ( ! scope->execFile( rcLocation , false , true ) ) {
- cout << "The \".mongorc.js\" file located in your home folder could not be executed" << endl;
+ if (!scope->execFile(rcLocation, false, true)) {
+ cout << "The \".mongorc.js\" file located in your home folder could not be "
+ "executed" << endl;
return -5;
}
}
}
- if ( !hasMongoRC && isatty(fileno(stdin)) ) {
- cout << "Welcome to the MongoDB shell.\n"
- "For interactive help, type \"help\".\n"
- "For more comprehensive documentation, see\n\thttp://docs.mongodb.org/\n"
- "Questions? Try the support group\n\thttp://groups.google.com/group/mongodb-user" << endl;
+ if (!hasMongoRC && isatty(fileno(stdin))) {
+ cout
+ << "Welcome to the MongoDB shell.\n"
+ "For interactive help, type \"help\".\n"
+ "For more comprehensive documentation, see\n\thttp://docs.mongodb.org/\n"
+ "Questions? Try the support group\n\thttp://groups.google.com/group/mongodb-user"
+ << endl;
File f;
f.open(rcLocation.c_str(), false); // Create empty .mongorc.js file
}
if (!shellGlobalParams.nodb && !mongo::serverGlobalParams.quiet && isatty(fileno(stdin))) {
- scope->exec( "shellHelper( 'show', 'startupWarnings' )", "(shellwarnings", false, true, false );
+ scope->exec(
+ "shellHelper( 'show', 'startupWarnings' )", "(shellwarnings", false, true, false);
}
shellHistoryInit();
@@ -774,116 +771,120 @@ int _main( int argc, char* argv[], char **envp ) {
string prompt;
int promptType;
- while ( 1 ) {
+ while (1) {
inMultiLine = false;
gotInterrupted = false;
- promptType = scope->type( "prompt" );
- if ( promptType == String ) {
- prompt = scope->getString( "prompt" );
- }
- else if ( ( promptType == Code ) &&
- execPrompt( *scope, "prompt", prompt ) ) {
- }
- else if ( execPrompt( *scope, "defaultPrompt", prompt ) ) {
- }
- else {
+ promptType = scope->type("prompt");
+ if (promptType == String) {
+ prompt = scope->getString("prompt");
+ } else if ((promptType == Code) && execPrompt(*scope, "prompt", prompt)) {
+ } else if (execPrompt(*scope, "defaultPrompt", prompt)) {
+ } else {
prompt = "> ";
}
- char * line = shellReadline( prompt.c_str() );
+ char* line = shellReadline(prompt.c_str());
- char * linePtr = line; // can't clobber 'line', we need to free() it later
- if ( linePtr ) {
- while ( linePtr[0] == ' ' )
+ char* linePtr = line; // can't clobber 'line', we need to free() it later
+ if (linePtr) {
+ while (linePtr[0] == ' ')
++linePtr;
- int lineLen = strlen( linePtr );
- while ( lineLen > 0 && linePtr[lineLen - 1] == ' ' )
+ int lineLen = strlen(linePtr);
+ while (lineLen > 0 && linePtr[lineLen - 1] == ' ')
linePtr[--lineLen] = 0;
}
- if ( ! linePtr || ( strlen( linePtr ) == 4 && strstr( linePtr , "exit" ) ) ) {
+ if (!linePtr || (strlen(linePtr) == 4 && strstr(linePtr, "exit"))) {
if (!mongo::serverGlobalParams.quiet)
cout << "bye" << endl;
- if ( line )
- free( line );
+ if (line)
+ free(line);
break;
}
string code = linePtr;
- if ( code == "exit" || code == "exit;" ) {
- free( line );
+ if (code == "exit" || code == "exit;") {
+ free(line);
break;
}
- if ( code == "cls" ) {
- free( line );
+ if (code == "cls") {
+ free(line);
linenoiseClearScreen();
continue;
}
- if ( code.size() == 0 ) {
- free( line );
+ if (code.size() == 0) {
+ free(line);
continue;
}
- if ( str::startsWith( linePtr, "edit " ) ) {
- shellHistoryAdd( linePtr );
+ if (str::startsWith(linePtr, "edit ")) {
+ shellHistoryAdd(linePtr);
- const char* s = linePtr + 5; // skip "edit "
- while( *s && isspace( *s ) )
+ const char* s = linePtr + 5; // skip "edit "
+ while (*s && isspace(*s))
s++;
- edit( s );
- free( line );
+ edit(s);
+ free(line);
continue;
}
gotInterrupted = false;
- code = finishCode( code );
- if ( gotInterrupted ) {
+ code = finishCode(code);
+ if (gotInterrupted) {
cout << endl;
- free( line );
+ free(line);
continue;
}
- if ( code.size() == 0 ) {
- free( line );
+ if (code.size() == 0) {
+ free(line);
break;
}
bool wascmd = false;
{
string cmd = linePtr;
- if ( cmd.find( " " ) > 0 )
- cmd = cmd.substr( 0 , cmd.find( " " ) );
+ if (cmd.find(" ") > 0)
+ cmd = cmd.substr(0, cmd.find(" "));
- if ( cmd.find( "\"" ) == string::npos ) {
+ if (cmd.find("\"") == string::npos) {
try {
- scope->exec( (string)"__iscmd__ = shellHelper[\"" + cmd + "\"];" , "(shellhelp1)" , false , true , true );
- if ( scope->getBoolean( "__iscmd__" ) ) {
- scope->exec( (string)"shellHelper( \"" + cmd + "\" , \"" + code.substr( cmd.size() ) + "\");" , "(shellhelp2)" , false , true , false );
+ scope->exec((string) "__iscmd__ = shellHelper[\"" + cmd + "\"];",
+ "(shellhelp1)",
+ false,
+ true,
+ true);
+ if (scope->getBoolean("__iscmd__")) {
+ scope->exec((string) "shellHelper( \"" + cmd + "\" , \"" +
+ code.substr(cmd.size()) + "\");",
+ "(shellhelp2)",
+ false,
+ true,
+ false);
wascmd = true;
}
- }
- catch ( std::exception& e ) {
+ } catch (std::exception& e) {
cout << "error2:" << e.what() << endl;
wascmd = true;
}
}
}
- if ( ! wascmd ) {
+ if (!wascmd) {
try {
- if ( scope->exec( code.c_str() , "(shell)" , false , true , false ) )
- scope->exec( "shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false );
- }
- catch ( std::exception& e ) {
+ if (scope->exec(code.c_str(), "(shell)", false, true, false))
+ scope->exec(
+ "shellPrintHelper( __lastres__ );", "(shell2)", true, true, false);
+ } catch (std::exception& e) {
cout << "error:" << e.what() << endl;
}
}
- shellHistoryAdd( code.c_str() );
- free( line );
+ shellHistoryAdd(code.c_str());
+ free(line);
}
shellHistoryDone();
@@ -903,24 +904,22 @@ int wmain(int argc, wchar_t* argvW[], wchar_t* envpW[]) {
try {
WindowsCommandLine wcl(argc, argvW, envpW);
returnCode = _main(argc, wcl.argv(), wcl.envp());
- }
- catch ( mongo::DBException& e ) {
+ } catch (mongo::DBException& e) {
cerr << "exception: " << e.what() << endl;
returnCode = 1;
}
quickExit(returnCode);
}
-#else // #ifdef _WIN32
-int main( int argc, char* argv[], char **envp ) {
+#else // #ifdef _WIN32
+int main(int argc, char* argv[], char** envp) {
static mongo::StaticObserver staticObserver;
int returnCode;
try {
- returnCode = _main( argc , argv, envp );
- }
- catch ( mongo::DBException& e ) {
+ returnCode = _main(argc, argv, envp);
+ } catch (mongo::DBException& e) {
cerr << "exception: " << e.what() << endl;
returnCode = 1;
}
quickExit(returnCode);
}
-#endif // #ifdef _WIN32
+#endif // #ifdef _WIN32
diff --git a/src/mongo/shell/linenoise.cpp b/src/mongo/shell/linenoise.cpp
index 43b42b9f028..5fd3371f374 100644
--- a/src/mongo/shell/linenoise.cpp
+++ b/src/mongo/shell/linenoise.cpp
@@ -32,7 +32,7 @@
* line editing lib needs to be 20,000 lines of C code.
*
* You can find the latest source code at:
- *
+ *
* http://github.com/antirez/linenoise
*
* Does a number of crazy assumptions that happen to be true in 99.9999% of
@@ -80,7 +80,7 @@
* ED2 (Clear entire screen)
* Sequence: ESC [ 2 J
* Effect: clear the whole screen
- *
+ *
*/
#ifdef _WIN32
@@ -144,7 +144,7 @@ struct linenoiseCompletions {
#define LINENOISE_MAX_LINE 4096
// make control-characters more readable
-#define ctrlChar( upperCaseASCII ) ( upperCaseASCII - 0x40 )
+#define ctrlChar(upperCaseASCII) (upperCaseASCII - 0x40)
/**
* Recompute widths of all characters in a UChar32 buffer
@@ -152,9 +152,9 @@ struct linenoiseCompletions {
* @param widths output buffer of character widths
* @param charCount number of characters in buffer
*/
-static void recomputeCharacterWidths( const UChar32* text, char* widths, int charCount ) {
- for ( int i = 0; i < charCount; ++i ) {
- widths[ i ] = mk_wcwidth( text[ i ] );
+static void recomputeCharacterWidths(const UChar32* text, char* widths, int charCount) {
+ for (int i = 0; i < charCount; ++i) {
+ widths[i] = mk_wcwidth(text[i]);
}
}
@@ -167,19 +167,21 @@ static void recomputeCharacterWidths( const UChar32* text, char* widths, int cha
* @param xOut returned x position (zero-based)
* @param yOut returned y position (zero-based)
*/
-static void calculateScreenPosition( int x, int y, int screenColumns, int charCount, int& xOut, int& yOut ) {
+static void calculateScreenPosition(
+ int x, int y, int screenColumns, int charCount, int& xOut, int& yOut) {
xOut = x;
yOut = y;
int charsRemaining = charCount;
- while ( charsRemaining > 0 ) {
- int charsThisRow = ( x + charsRemaining < screenColumns ) ? charsRemaining : screenColumns - x;
+ while (charsRemaining > 0) {
+ int charsThisRow =
+ (x + charsRemaining < screenColumns) ? charsRemaining : screenColumns - x;
xOut = x + charsThisRow;
yOut = y;
charsRemaining -= charsThisRow;
x = 0;
++y;
}
- if ( xOut == screenColumns ) { // we have to special-case line wrap
+ if (xOut == screenColumns) { // we have to special-case line wrap
xOut = 0;
++yOut;
}
@@ -190,50 +192,49 @@ static void calculateScreenPosition( int x, int y, int screenColumns, int charCo
* @param buf32 text to calculate
* @param len length of text to calculate
*/
-static int calculateColumnPosition( UChar32* buf32, int len) {
- int width = mk_wcswidth( reinterpret_cast<const int*>( buf32 ), len );
- if ( width == -1 )
+static int calculateColumnPosition(UChar32* buf32, int len) {
+ int width = mk_wcswidth(reinterpret_cast<const int*>(buf32), len);
+ if (width == -1)
return len;
else
return width;
}
-static bool isControlChar( UChar32 testChar ) {
- return ( testChar < ' ' ) || // C0 controls
- ( testChar >= 0x7F && testChar <= 0x9F ); // DEL and C1 controls
+static bool isControlChar(UChar32 testChar) {
+ return (testChar < ' ') || // C0 controls
+ (testChar >= 0x7F && testChar <= 0x9F); // DEL and C1 controls
}
-struct PromptBase { // a convenience struct for grouping prompt info
- Utf32String promptText; // our copy of the prompt text, edited
- char* promptCharWidths; // character widths from mk_wcwidth()
- int promptChars; // chars in promptText
- int promptExtraLines; // extra lines (beyond 1) occupied by prompt
- int promptIndentation; // column offset to end of prompt
- int promptLastLinePosition; // index into promptText where last line begins
- int promptPreviousInputLen; // promptChars of previous input line, for clearing
- int promptCursorRowOffset; // where the cursor is relative to the start of the prompt
- int promptScreenColumns; // width of screen in columns
- int promptPreviousLen; // help erasing
- int promptErrorCode; // error code (invalid UTF-8) or zero
-
- PromptBase() : promptPreviousInputLen( 0 ) { }
+struct PromptBase { // a convenience struct for grouping prompt info
+ Utf32String promptText; // our copy of the prompt text, edited
+ char* promptCharWidths; // character widths from mk_wcwidth()
+ int promptChars; // chars in promptText
+ int promptExtraLines; // extra lines (beyond 1) occupied by prompt
+ int promptIndentation; // column offset to end of prompt
+ int promptLastLinePosition; // index into promptText where last line begins
+ int promptPreviousInputLen; // promptChars of previous input line, for clearing
+ int promptCursorRowOffset; // where the cursor is relative to the start of the prompt
+ int promptScreenColumns; // width of screen in columns
+ int promptPreviousLen; // help erasing
+ int promptErrorCode; // error code (invalid UTF-8) or zero
+
+ PromptBase() : promptPreviousInputLen(0) {}
};
struct PromptInfo : public PromptBase {
-
- PromptInfo( const UChar8* textPtr, int columns ) {
+ PromptInfo(const UChar8* textPtr, int columns) {
promptExtraLines = 0;
promptLastLinePosition = 0;
promptPreviousLen = 0;
promptScreenColumns = columns;
- Utf32String tempUnicode( textPtr );
+ Utf32String tempUnicode(textPtr);
// strip control characters from the prompt -- we do allow newline
UChar32* pIn = tempUnicode.get();
UChar32* pOut = pIn;
- while ( *pIn ) {
+ while (*pIn) {
UChar32 c = *pIn;
- if ( '\n' == c || !isControlChar( c ) ) {
+ if ('\n' == c || !isControlChar(c)) {
*pOut = c;
++pOut;
}
@@ -244,16 +245,15 @@ struct PromptInfo : public PromptBase {
promptText = tempUnicode;
int x = 0;
- for ( int i = 0; i < promptChars; ++i ) {
+ for (int i = 0; i < promptChars; ++i) {
UChar32 c = promptText[i];
- if ( '\n' == c ) {
+ if ('\n' == c) {
x = 0;
++promptExtraLines;
promptLastLinePosition = i + 1;
- }
- else {
+ } else {
++x;
- if ( x >= promptScreenColumns ) {
+ if (x >= promptScreenColumns) {
x = 0;
++promptExtraLines;
promptLastLinePosition = i + 1;
@@ -267,52 +267,62 @@ struct PromptInfo : public PromptBase {
// Used with DynamicPrompt (history search)
//
-static const Utf32String forwardSearchBasePrompt( reinterpret_cast<const UChar8*>( "(i-search)`" ) );
-static const Utf32String reverseSearchBasePrompt( reinterpret_cast<const UChar8*>( "(reverse-i-search)`" ) );
-static const Utf32String endSearchBasePrompt( reinterpret_cast<const UChar8*>( "': " ) );
-static Utf32String previousSearchText; // remembered across invocations of linenoise()
+static const Utf32String forwardSearchBasePrompt(reinterpret_cast<const UChar8*>("(i-search)`"));
+static const Utf32String reverseSearchBasePrompt(
+ reinterpret_cast<const UChar8*>("(reverse-i-search)`"));
+static const Utf32String endSearchBasePrompt(reinterpret_cast<const UChar8*>("': "));
+static Utf32String previousSearchText; // remembered across invocations of linenoise()
// changing prompt for "(reverse-i-search)`text':" etc.
//
struct DynamicPrompt : public PromptBase {
- Utf32String searchText; // text we are searching for
- char* searchCharWidths; // character widths from mk_wcwidth()
- int searchTextLen; // chars in searchText
- int direction; // current search direction, 1=forward, -1=reverse
+ Utf32String searchText; // text we are searching for
+ char* searchCharWidths; // character widths from mk_wcwidth()
+ int searchTextLen; // chars in searchText
+ int direction; // current search direction, 1=forward, -1=reverse
- DynamicPrompt( PromptBase& pi, int initialDirection ) : searchTextLen( 0 ), direction( initialDirection ) {
+ DynamicPrompt(PromptBase& pi, int initialDirection)
+ : searchTextLen(0), direction(initialDirection) {
promptScreenColumns = pi.promptScreenColumns;
promptCursorRowOffset = 0;
- Utf32String emptyString( 1 );
+ Utf32String emptyString(1);
searchText = emptyString;
- const Utf32String* basePrompt = ( direction > 0 ) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
+ const Utf32String* basePrompt =
+ (direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
size_t promptStartLength = basePrompt->length();
promptChars = promptStartLength + endSearchBasePrompt.length();
- promptLastLinePosition = promptChars; // TODO fix this, we are asssuming that the history prompt won't wrap (!)
+ promptLastLinePosition =
+ promptChars; // TODO fix this, we are asssuming that the history prompt won't wrap (!)
promptPreviousLen = promptChars;
- Utf32String tempUnicode( promptChars + 1 );
- memcpy( tempUnicode.get(), basePrompt->get(), sizeof( UChar32 ) * promptStartLength );
- memcpy( &tempUnicode[promptStartLength], endSearchBasePrompt.get(), sizeof( UChar32 ) * ( endSearchBasePrompt.length() + 1 ) );
+ Utf32String tempUnicode(promptChars + 1);
+ memcpy(tempUnicode.get(), basePrompt->get(), sizeof(UChar32) * promptStartLength);
+ memcpy(&tempUnicode[promptStartLength],
+ endSearchBasePrompt.get(),
+ sizeof(UChar32) * (endSearchBasePrompt.length() + 1));
tempUnicode.initFromBuffer();
promptText = tempUnicode;
- calculateScreenPosition( 0, 0, pi.promptScreenColumns, promptChars, promptIndentation, promptExtraLines );
+ calculateScreenPosition(
+ 0, 0, pi.promptScreenColumns, promptChars, promptIndentation, promptExtraLines);
}
- void updateSearchPrompt( void ) {
- const Utf32String* basePrompt = ( direction > 0 ) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
+ void updateSearchPrompt(void) {
+ const Utf32String* basePrompt =
+ (direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
size_t promptStartLength = basePrompt->length();
promptChars = promptStartLength + searchTextLen + endSearchBasePrompt.length();
- Utf32String tempUnicode( promptChars + 1 );
- memcpy( tempUnicode.get(), basePrompt->get(), sizeof( UChar32 ) * promptStartLength );
- memcpy( &tempUnicode[promptStartLength], searchText.get(), sizeof( UChar32 ) * searchTextLen );
+ Utf32String tempUnicode(promptChars + 1);
+ memcpy(tempUnicode.get(), basePrompt->get(), sizeof(UChar32) * promptStartLength);
+ memcpy(&tempUnicode[promptStartLength], searchText.get(), sizeof(UChar32) * searchTextLen);
size_t endIndex = promptStartLength + searchTextLen;
- memcpy( &tempUnicode[endIndex], endSearchBasePrompt.get(), sizeof( UChar32 ) * ( endSearchBasePrompt.length() + 1 ) );
+ memcpy(&tempUnicode[endIndex],
+ endSearchBasePrompt.get(),
+ sizeof(UChar32) * (endSearchBasePrompt.length() + 1));
tempUnicode.initFromBuffer();
promptText = tempUnicode;
}
- void updateSearchText( const UChar32* textPtr ) {
- Utf32String tempUnicode( textPtr );
+ void updateSearchText(const UChar32* textPtr) {
+ Utf32String tempUnicode(textPtr);
searchTextLen = tempUnicode.chars();
searchText = tempUnicode;
updateSearchPrompt();
@@ -320,56 +330,53 @@ struct DynamicPrompt : public PromptBase {
};
class KillRing {
- static const int capacity = 10;
- int size;
- int index;
- char indexToSlot[10];
+ static const int capacity = 10;
+ int size;
+ int index;
+ char indexToSlot[10];
vector<Utf32String> theRing;
public:
- enum action { actionOther, actionKill, actionYank };
- action lastAction;
- size_t lastYankSize;
+ enum action { actionOther, actionKill, actionYank };
+ action lastAction;
+ size_t lastYankSize;
- KillRing() : size( 0 ), index( 0 ), lastAction( actionOther ) {
- theRing.reserve( capacity );
+ KillRing() : size(0), index(0), lastAction(actionOther) {
+ theRing.reserve(capacity);
}
- void kill( const UChar32* text, int textLen, bool forward ) {
- if ( textLen == 0 ) {
+ void kill(const UChar32* text, int textLen, bool forward) {
+ if (textLen == 0) {
return;
}
- Utf32String killedText( text, textLen );
- if ( lastAction == actionKill && size > 0 ) {
+ Utf32String killedText(text, textLen);
+ if (lastAction == actionKill && size > 0) {
int slot = indexToSlot[0];
int currentLen = theRing[slot].length();
int resultLen = currentLen + textLen;
- Utf32String temp( resultLen + 1 );
- if ( forward ) {
- memcpy( temp.get(), theRing[slot].get(), currentLen * sizeof( UChar32 ) );
- memcpy( &temp[currentLen], killedText.get(), textLen * sizeof( UChar32 ) );
- }
- else {
- memcpy( temp.get(), killedText.get(), textLen * sizeof( UChar32 ) );
- memcpy( &temp[textLen], theRing[slot].get(), currentLen * sizeof( UChar32 ) );
+ Utf32String temp(resultLen + 1);
+ if (forward) {
+ memcpy(temp.get(), theRing[slot].get(), currentLen * sizeof(UChar32));
+ memcpy(&temp[currentLen], killedText.get(), textLen * sizeof(UChar32));
+ } else {
+ memcpy(temp.get(), killedText.get(), textLen * sizeof(UChar32));
+ memcpy(&temp[textLen], theRing[slot].get(), currentLen * sizeof(UChar32));
}
temp[resultLen] = 0;
temp.initFromBuffer();
theRing[slot] = temp;
- }
- else {
- if ( size < capacity ) {
- if ( size > 0 ) {
- memmove( &indexToSlot[1], &indexToSlot[0], size );
+ } else {
+ if (size < capacity) {
+ if (size > 0) {
+ memmove(&indexToSlot[1], &indexToSlot[0], size);
}
indexToSlot[0] = size;
size++;
- theRing.push_back( killedText );
- }
- else {
+ theRing.push_back(killedText);
+ } else {
int slot = indexToSlot[capacity - 1];
theRing[slot] = killedText;
- memmove( &indexToSlot[1], &indexToSlot[0], capacity - 1 );
+ memmove(&indexToSlot[1], &indexToSlot[0], capacity - 1);
indexToSlot[0] = slot;
}
index = 0;
@@ -377,48 +384,50 @@ public:
}
Utf32String* yank() {
- return ( size > 0 ) ? &theRing[indexToSlot[index]] : 0;
+ return (size > 0) ? &theRing[indexToSlot[index]] : 0;
}
Utf32String* yankPop() {
- if ( size == 0 ) {
+ if (size == 0) {
return 0;
}
++index;
- if ( index == size ) {
+ if (index == size) {
index = 0;
}
return &theRing[indexToSlot[index]];
}
-
};
class InputBuffer {
- UChar32* buf32; // input buffer
- char* charWidths; // character widths from mk_wcwidth()
- int buflen; // buffer size in characters
- int len; // length of text in input buffer
- int pos; // character position in buffer ( 0 <= pos <= len )
+ UChar32* buf32; // input buffer
+ char* charWidths; // character widths from mk_wcwidth()
+ int buflen; // buffer size in characters
+ int len; // length of text in input buffer
+ int pos; // character position in buffer ( 0 <= pos <= len )
- void clearScreen( PromptBase& pi );
- int incrementalHistorySearch( PromptBase& pi, int startChar );
- int completeLine( PromptBase& pi );
- void refreshLine( PromptBase& pi );
+ void clearScreen(PromptBase& pi);
+ int incrementalHistorySearch(PromptBase& pi, int startChar);
+ int completeLine(PromptBase& pi);
+ void refreshLine(PromptBase& pi);
public:
- InputBuffer( UChar32* buffer, char* widthArray, int bufferLen ) : buf32( buffer ), charWidths( widthArray ), buflen( bufferLen - 1 ), len( 0 ), pos( 0 ) {
+ InputBuffer(UChar32* buffer, char* widthArray, int bufferLen)
+ : buf32(buffer), charWidths(widthArray), buflen(bufferLen - 1), len(0), pos(0) {
buf32[0] = 0;
}
- void preloadBuffer( const UChar8* preloadText ) {
+ void preloadBuffer(const UChar8* preloadText) {
size_t ucharCount;
int errorCode;
- copyString8to32( buf32, preloadText, buflen + 1, ucharCount, errorCode );
- recomputeCharacterWidths( buf32, charWidths, ucharCount );
+ copyString8to32(buf32, preloadText, buflen + 1, ucharCount, errorCode);
+ recomputeCharacterWidths(buf32, charWidths, ucharCount);
len = ucharCount;
pos = ucharCount;
}
- int getInputLine( PromptBase& pi );
- int length( void ) const { return len; }
+ int getInputLine(PromptBase& pi);
+ int length(void) const {
+ return len;
+ }
};
// Special codes for keyboard input:
@@ -444,20 +453,20 @@ public:
//
// Maximum unsigned 32-bit value = 0xFFFFFFFF; // For reference, max 32-bit value
// Highest allocated Unicode char = 0x001FFFFF; // For reference, max Unicode value
-static const int META = 0x40000000; // Meta key combination
-static const int CTRL = 0x20000000; // Ctrl key combination
-static const int SPECIAL_KEY = 0x10000000; // Common bit for all special keys
-static const int UP_ARROW_KEY = 0x10200000; // Special keys
-static const int DOWN_ARROW_KEY = 0x10400000;
-static const int RIGHT_ARROW_KEY = 0x10600000;
-static const int LEFT_ARROW_KEY = 0x10800000;
-static const int HOME_KEY = 0x10A00000;
-static const int END_KEY = 0x10C00000;
-static const int DELETE_KEY = 0x10E00000;
-static const int PAGE_UP_KEY = 0x11000000;
-static const int PAGE_DOWN_KEY = 0x11200000;
-
-static const char* unsupported_term[] = { "dumb", "cons25", "emacs", NULL };
+static const int META = 0x40000000; // Meta key combination
+static const int CTRL = 0x20000000; // Ctrl key combination
+static const int SPECIAL_KEY = 0x10000000; // Common bit for all special keys
+static const int UP_ARROW_KEY = 0x10200000; // Special keys
+static const int DOWN_ARROW_KEY = 0x10400000;
+static const int RIGHT_ARROW_KEY = 0x10600000;
+static const int LEFT_ARROW_KEY = 0x10800000;
+static const int HOME_KEY = 0x10A00000;
+static const int END_KEY = 0x10C00000;
+static const int DELETE_KEY = 0x10E00000;
+static const int PAGE_UP_KEY = 0x11000000;
+static const int PAGE_DOWN_KEY = 0x11200000;
+
+static const char* unsupported_term[] = {"dumb", "cons25", "emacs", NULL};
static linenoiseCompletionCallback* completionCallback = NULL;
#ifdef _WIN32
@@ -470,7 +479,7 @@ static struct termios orig_termios; /* in order to restore at exit */
static KillRing killRing;
-static int rawmode = 0; /* for atexit() function to check if restore is needed*/
+static int rawmode = 0; /* for atexit() function to check if restore is needed*/
static int atexit_registered = 0; /* register atexit just 1 time */
static int historyMaxLen = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int historyLen = 0;
@@ -483,72 +492,77 @@ static UChar8** history = NULL;
static int historyPreviousIndex = -2;
static bool historyRecallMostRecent = false;
-static void linenoiseAtExit( void );
+static void linenoiseAtExit(void);
-static bool isUnsupportedTerm( void ) {
- char* term = getenv( "TERM" );
- if ( term == NULL )
+static bool isUnsupportedTerm(void) {
+ char* term = getenv("TERM");
+ if (term == NULL)
return false;
- for ( int j = 0; unsupported_term[j]; ++j )
- if ( ! strcasecmp( term, unsupported_term[j] ) ) {
+ for (int j = 0; unsupported_term[j]; ++j)
+ if (!strcasecmp(term, unsupported_term[j])) {
return true;
}
return false;
}
static void beep() {
- fprintf( stderr, "\x7" ); // ctrl-G == bell/beep
- fflush( stderr );
+ fprintf(stderr, "\x7"); // ctrl-G == bell/beep
+ fflush(stderr);
}
-void linenoiseHistoryFree( void ) {
- if ( history ) {
- for ( int j = 0; j < historyLen; ++j )
- free( history[j] );
+void linenoiseHistoryFree(void) {
+ if (history) {
+ for (int j = 0; j < historyLen; ++j)
+ free(history[j]);
historyLen = 0;
- free( history );
+ free(history);
history = 0;
}
}
-static int enableRawMode( void ) {
+static int enableRawMode(void) {
#ifdef _WIN32
- if ( ! console_in ) {
- console_in = GetStdHandle( STD_INPUT_HANDLE );
- console_out = GetStdHandle( STD_OUTPUT_HANDLE );
+ if (!console_in) {
+ console_in = GetStdHandle(STD_INPUT_HANDLE);
+ console_out = GetStdHandle(STD_OUTPUT_HANDLE);
- GetConsoleMode( console_in, &oldMode );
- SetConsoleMode( console_in, oldMode & ~( ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT ) );
+ GetConsoleMode(console_in, &oldMode);
+ SetConsoleMode(console_in,
+ oldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT));
}
return 0;
#else
struct termios raw;
- if ( ! isatty( 0 ) ) goto fatal;
- if ( ! atexit_registered ) {
- atexit( linenoiseAtExit );
+ if (!isatty(0))
+ goto fatal;
+ if (!atexit_registered) {
+ atexit(linenoiseAtExit);
atexit_registered = 1;
}
- if ( tcgetattr( 0, &orig_termios ) == -1 ) goto fatal;
+ if (tcgetattr(0, &orig_termios) == -1)
+ goto fatal;
- raw = orig_termios; /* modify the original mode */
- /* input modes: no break, no CR to NL, no parity check, no strip char,
- * no start/stop output control. */
- raw.c_iflag &= ~( BRKINT | ICRNL | INPCK | ISTRIP | IXON );
+ raw = orig_termios; /* modify the original mode */
+ /* input modes: no break, no CR to NL, no parity check, no strip char,
+ * no start/stop output control. */
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
/* output modes - disable post processing */
// this is wrong, we don't want raw output, it turns newlines into straight linefeeds
- //raw.c_oflag &= ~(OPOST);
+ // raw.c_oflag &= ~(OPOST);
/* control modes - set 8 bit chars */
- raw.c_cflag |= ( CS8 );
+ raw.c_cflag |= (CS8);
/* local modes - echoing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
- raw.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* control chars - set return condition: min number of bytes and timer.
* We want read to return every single byte, without timeout. */
- raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+ raw.c_cc[VMIN] = 1;
+ raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
/* put terminal in raw mode after flushing */
- if ( tcsetattr( 0, TCSADRAIN, &raw ) < 0 ) goto fatal;
+ if (tcsetattr(0, TCSADRAIN, &raw) < 0)
+ goto fatal;
rawmode = 1;
return 0;
@@ -558,82 +572,83 @@ fatal:
#endif
}
-static void disableRawMode( void ) {
+static void disableRawMode(void) {
#ifdef _WIN32
- SetConsoleMode( console_in, oldMode );
+ SetConsoleMode(console_in, oldMode);
console_in = 0;
console_out = 0;
#else
- if ( rawmode && tcsetattr ( 0, TCSADRAIN, &orig_termios ) != -1 )
+ if (rawmode && tcsetattr(0, TCSADRAIN, &orig_termios) != -1)
rawmode = 0;
#endif
}
// At exit we'll try to fix the terminal to the initial conditions
-static void linenoiseAtExit( void ) {
+static void linenoiseAtExit(void) {
disableRawMode();
}
-static int getScreenColumns( void ) {
+static int getScreenColumns(void) {
int cols;
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO inf;
- GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &inf );
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &inf);
cols = inf.dwSize.X;
#else
struct winsize ws;
- cols = ( ioctl( 1, TIOCGWINSZ, &ws ) == -1 ) ? 80 : ws.ws_col;
+ cols = (ioctl(1, TIOCGWINSZ, &ws) == -1) ? 80 : ws.ws_col;
#endif
// cols is 0 in certain circumstances like inside debugger, which creates further issues
return (cols > 0) ? cols : 80;
}
-static int getScreenRows( void ) {
+static int getScreenRows(void) {
int rows;
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO inf;
- GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &inf );
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &inf);
rows = 1 + inf.srWindow.Bottom - inf.srWindow.Top;
#else
struct winsize ws;
- rows = ( ioctl( 1, TIOCGWINSZ, &ws ) == -1 ) ? 24 : ws.ws_row;
+ rows = (ioctl(1, TIOCGWINSZ, &ws) == -1) ? 24 : ws.ws_row;
#endif
return (rows > 0) ? rows : 24;
}
-static void setDisplayAttribute( bool enhancedDisplay ) {
+static void setDisplayAttribute(bool enhancedDisplay) {
#ifdef _WIN32
- if ( enhancedDisplay ) {
+ if (enhancedDisplay) {
CONSOLE_SCREEN_BUFFER_INFO inf;
- GetConsoleScreenBufferInfo( console_out, &inf );
+ GetConsoleScreenBufferInfo(console_out, &inf);
oldDisplayAttribute = inf.wAttributes;
BYTE oldLowByte = oldDisplayAttribute & 0xFF;
BYTE newLowByte;
- switch ( oldLowByte ) {
- case 0x07:
- //newLowByte = FOREGROUND_BLUE | FOREGROUND_INTENSITY; // too dim
- //newLowByte = FOREGROUND_BLUE; // even dimmer
- newLowByte = FOREGROUND_BLUE | FOREGROUND_GREEN; // most similar to xterm appearance
- break;
- case 0x70:
- newLowByte = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
- break;
- default:
- newLowByte = oldLowByte ^ 0xFF; // default to inverse video
- break;
+ switch (oldLowByte) {
+ case 0x07:
+ // newLowByte = FOREGROUND_BLUE | FOREGROUND_INTENSITY; // too dim
+ // newLowByte = FOREGROUND_BLUE; // even dimmer
+ newLowByte =
+ FOREGROUND_BLUE | FOREGROUND_GREEN; // most similar to xterm appearance
+ break;
+ case 0x70:
+ newLowByte = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
+ break;
+ default:
+ newLowByte = oldLowByte ^ 0xFF; // default to inverse video
+ break;
}
- inf.wAttributes = ( inf.wAttributes & 0xFF00 ) | newLowByte;
- SetConsoleTextAttribute( console_out, inf.wAttributes );
- }
- else {
- SetConsoleTextAttribute( console_out, oldDisplayAttribute );
+ inf.wAttributes = (inf.wAttributes & 0xFF00) | newLowByte;
+ SetConsoleTextAttribute(console_out, inf.wAttributes);
+ } else {
+ SetConsoleTextAttribute(console_out, oldDisplayAttribute);
}
#else
- if ( enhancedDisplay ) {
- if ( write( 1, "\x1b[1;34m", 7 ) == -1 ) return; /* bright blue (visible with both B&W bg) */
- }
- else {
- if ( write( 1, "\x1b[0m", 4 ) == -1 ) return; /* reset */
+ if (enhancedDisplay) {
+ if (write(1, "\x1b[1;34m", 7) == -1)
+ return; /* bright blue (visible with both B&W bg) */
+ } else {
+ if (write(1, "\x1b[0m", 4) == -1)
+ return; /* reset */
}
#endif
}
@@ -645,84 +660,97 @@ static void setDisplayAttribute( bool enhancedDisplay ) {
* @param len count of characters in the buffer
* @param pos current cursor position within the buffer (0 <= pos <= len)
*/
-static void dynamicRefresh( PromptBase& pi, UChar32* buf32, int len, int pos ) {
-
+static void dynamicRefresh(PromptBase& pi, UChar32* buf32, int len, int pos) {
// calculate the position of the end of the prompt
int xEndOfPrompt, yEndOfPrompt;
- calculateScreenPosition( 0, 0, pi.promptScreenColumns, pi.promptChars, xEndOfPrompt, yEndOfPrompt );
+ calculateScreenPosition(
+ 0, 0, pi.promptScreenColumns, pi.promptChars, xEndOfPrompt, yEndOfPrompt);
pi.promptIndentation = xEndOfPrompt;
// calculate the position of the end of the input line
int xEndOfInput, yEndOfInput;
- calculateScreenPosition( xEndOfPrompt,
- yEndOfPrompt,
- pi.promptScreenColumns,
- calculateColumnPosition( buf32, len ),
- xEndOfInput,
- yEndOfInput );
+ calculateScreenPosition(xEndOfPrompt,
+ yEndOfPrompt,
+ pi.promptScreenColumns,
+ calculateColumnPosition(buf32, len),
+ xEndOfInput,
+ yEndOfInput);
// calculate the desired position of the cursor
int xCursorPos, yCursorPos;
- calculateScreenPosition( xEndOfPrompt,
- yEndOfPrompt,
- pi.promptScreenColumns,
- calculateColumnPosition( buf32, pos ),
- xCursorPos,
- yCursorPos );
+ calculateScreenPosition(xEndOfPrompt,
+ yEndOfPrompt,
+ pi.promptScreenColumns,
+ calculateColumnPosition(buf32, pos),
+ xCursorPos,
+ yCursorPos);
#ifdef _WIN32
// position at the start of the prompt, clear to end of previous input
CONSOLE_SCREEN_BUFFER_INFO inf;
- GetConsoleScreenBufferInfo( console_out, &inf );
+ GetConsoleScreenBufferInfo(console_out, &inf);
inf.dwCursorPosition.X = 0;
inf.dwCursorPosition.Y -= pi.promptCursorRowOffset /*- pi.promptExtraLines*/;
- SetConsoleCursorPosition( console_out, inf.dwCursorPosition );
+ SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
DWORD count;
- FillConsoleOutputCharacterA( console_out, ' ', pi.promptPreviousLen + pi.promptPreviousInputLen, inf.dwCursorPosition, &count );
+ FillConsoleOutputCharacterA(console_out,
+ ' ',
+ pi.promptPreviousLen + pi.promptPreviousInputLen,
+ inf.dwCursorPosition,
+ &count);
pi.promptPreviousLen = pi.promptIndentation;
pi.promptPreviousInputLen = len;
// display the prompt
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return;
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return;
// display the input line
- if ( write32( 1, buf32, len ) == -1 ) return;
+ if (write32(1, buf32, len) == -1)
+ return;
// position the cursor
- GetConsoleScreenBufferInfo( console_out, &inf );
+ GetConsoleScreenBufferInfo(console_out, &inf);
inf.dwCursorPosition.X = xCursorPos; // 0-based on Win32
inf.dwCursorPosition.Y -= yEndOfInput - yCursorPos;
- SetConsoleCursorPosition( console_out, inf.dwCursorPosition );
-#else // _WIN32
+ SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
+#else // _WIN32
char seq[64];
int cursorRowMovement = pi.promptCursorRowOffset - pi.promptExtraLines;
- if ( cursorRowMovement > 0 ) { // move the cursor up as required
- snprintf( seq, sizeof seq, "\x1b[%dA", cursorRowMovement );
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ if (cursorRowMovement > 0) { // move the cursor up as required
+ snprintf(seq, sizeof seq, "\x1b[%dA", cursorRowMovement);
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
}
// position at the start of the prompt, clear to end of screen
- snprintf( seq, sizeof seq, "\x1b[1G\x1b[J" ); // 1-based on VT100
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ snprintf(seq, sizeof seq, "\x1b[1G\x1b[J"); // 1-based on VT100
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
// display the prompt
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return;
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return;
// display the input line
- if ( write32( 1, buf32, len ) == -1 ) return;
+ if (write32(1, buf32, len) == -1)
+ return;
// we have to generate our own newline on line wrap
- if ( xEndOfInput == 0 && yEndOfInput > 0 )
- if ( write( 1, "\n", 1 ) == -1 ) return;
+ if (xEndOfInput == 0 && yEndOfInput > 0)
+ if (write(1, "\n", 1) == -1)
+ return;
// position the cursor
cursorRowMovement = yEndOfInput - yCursorPos;
- if ( cursorRowMovement > 0 ) { // move the cursor up as required
- snprintf( seq, sizeof seq, "\x1b[%dA", cursorRowMovement );
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ if (cursorRowMovement > 0) { // move the cursor up as required
+ snprintf(seq, sizeof seq, "\x1b[%dA", cursorRowMovement);
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
}
// position the cursor within the line
- snprintf( seq, sizeof seq, "\x1b[%dG", xCursorPos + 1 ); // 1-based on VT100
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ snprintf(seq, sizeof seq, "\x1b[%dG", xCursorPos + 1); // 1-based on VT100
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
#endif
pi.promptCursorRowOffset = pi.promptExtraLines + yCursorPos; // remember row for next pass
@@ -732,28 +760,27 @@ static void dynamicRefresh( PromptBase& pi, UChar32* buf32, int len, int pos ) {
* Refresh the user's input line: the prompt is already onscreen and is not redrawn here
* @param pi PromptBase struct holding information about the prompt and our screen position
*/
-void InputBuffer::refreshLine( PromptBase& pi ) {
-
+void InputBuffer::refreshLine(PromptBase& pi) {
// check for a matching brace/bracket/paren, remember its position if found
int highlight = -1;
- if ( pos < len ) {
+ if (pos < len) {
/* this scans for a brace matching buf32[pos] to highlight */
int scanDirection = 0;
- if ( strchr( "}])", buf32[pos] ) )
+ if (strchr("}])", buf32[pos]))
scanDirection = -1; /* backwards */
- else if ( strchr( "{[(", buf32[pos] ) )
+ else if (strchr("{[(", buf32[pos]))
scanDirection = 1; /* forwards */
- if ( scanDirection ) {
+ if (scanDirection) {
int unmatched = scanDirection;
- for ( int i = pos + scanDirection; i >= 0 && i < len; i += scanDirection ) {
+ for (int i = pos + scanDirection; i >= 0 && i < len; i += scanDirection) {
/* TODO: the right thing when inside a string */
- if ( strchr( "}])", buf32[i] ) )
+ if (strchr("}])", buf32[i]))
--unmatched;
- else if ( strchr( "{[(", buf32[i] ) )
+ else if (strchr("{[(", buf32[i]))
++unmatched;
- if ( unmatched == 0 ) {
+ if (unmatched == 0) {
highlight = i;
break;
}
@@ -763,86 +790,98 @@ void InputBuffer::refreshLine( PromptBase& pi ) {
// calculate the position of the end of the input line
int xEndOfInput, yEndOfInput;
- calculateScreenPosition( pi.promptIndentation,
- 0,
- pi.promptScreenColumns,
- calculateColumnPosition( buf32, len ),
- xEndOfInput,
- yEndOfInput );
+ calculateScreenPosition(pi.promptIndentation,
+ 0,
+ pi.promptScreenColumns,
+ calculateColumnPosition(buf32, len),
+ xEndOfInput,
+ yEndOfInput);
// calculate the desired position of the cursor
int xCursorPos, yCursorPos;
- calculateScreenPosition( pi.promptIndentation,
- 0,
- pi.promptScreenColumns,
- calculateColumnPosition( buf32, pos ),
- xCursorPos,
- yCursorPos );
+ calculateScreenPosition(pi.promptIndentation,
+ 0,
+ pi.promptScreenColumns,
+ calculateColumnPosition(buf32, pos),
+ xCursorPos,
+ yCursorPos);
#ifdef _WIN32
// position at the end of the prompt, clear to end of previous input
CONSOLE_SCREEN_BUFFER_INFO inf;
- GetConsoleScreenBufferInfo( console_out, &inf );
+ GetConsoleScreenBufferInfo(console_out, &inf);
inf.dwCursorPosition.X = pi.promptIndentation; // 0-based on Win32
inf.dwCursorPosition.Y -= pi.promptCursorRowOffset - pi.promptExtraLines;
- SetConsoleCursorPosition( console_out, inf.dwCursorPosition );
+ SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
DWORD count;
- if ( len < pi.promptPreviousInputLen )
- FillConsoleOutputCharacterA( console_out, ' ', pi.promptPreviousInputLen, inf.dwCursorPosition, &count );
+ if (len < pi.promptPreviousInputLen)
+ FillConsoleOutputCharacterA(
+ console_out, ' ', pi.promptPreviousInputLen, inf.dwCursorPosition, &count);
pi.promptPreviousInputLen = len;
// display the input line
if (highlight == -1) {
- if ( write32( 1, buf32, len ) == -1 ) return;
- }
- else {
- if (write32( 1, buf32, highlight ) == -1 ) return;
- setDisplayAttribute( true ); /* bright blue (visible with both B&W bg) */
- if ( write32( 1, &buf32[highlight], 1 ) == -1 ) return;
- setDisplayAttribute( false );
- if ( write32( 1, buf32 + highlight + 1, len - highlight - 1 ) == -1 ) return;
+ if (write32(1, buf32, len) == -1)
+ return;
+ } else {
+ if (write32(1, buf32, highlight) == -1)
+ return;
+ setDisplayAttribute(true); /* bright blue (visible with both B&W bg) */
+ if (write32(1, &buf32[highlight], 1) == -1)
+ return;
+ setDisplayAttribute(false);
+ if (write32(1, buf32 + highlight + 1, len - highlight - 1) == -1)
+ return;
}
// position the cursor
- GetConsoleScreenBufferInfo( console_out, &inf );
+ GetConsoleScreenBufferInfo(console_out, &inf);
inf.dwCursorPosition.X = xCursorPos; // 0-based on Win32
inf.dwCursorPosition.Y -= yEndOfInput - yCursorPos;
- SetConsoleCursorPosition( console_out, inf.dwCursorPosition );
-#else // _WIN32
+ SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
+#else // _WIN32
char seq[64];
int cursorRowMovement = pi.promptCursorRowOffset - pi.promptExtraLines;
- if ( cursorRowMovement > 0 ) { // move the cursor up as required
- snprintf( seq, sizeof seq, "\x1b[%dA", cursorRowMovement );
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ if (cursorRowMovement > 0) { // move the cursor up as required
+ snprintf(seq, sizeof seq, "\x1b[%dA", cursorRowMovement);
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
}
// position at the end of the prompt, clear to end of screen
- snprintf( seq, sizeof seq, "\x1b[%dG\x1b[J", pi.promptIndentation + 1 ); // 1-based on VT100
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ snprintf(seq, sizeof seq, "\x1b[%dG\x1b[J", pi.promptIndentation + 1); // 1-based on VT100
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
- if ( highlight == -1 ) { // write unhighlighted text
- if ( write32( 1, buf32, len ) == -1 ) return;
- }
- else { // highlight the matching brace/bracket/parenthesis
- if ( write32( 1, buf32, highlight ) == -1 ) return;
- setDisplayAttribute( true );
- if ( write32( 1, &buf32[highlight], 1 ) == -1 ) return;
- setDisplayAttribute( false );
- if ( write32( 1, buf32 + highlight + 1, len - highlight - 1 ) == -1 ) return;
+ if (highlight == -1) { // write unhighlighted text
+ if (write32(1, buf32, len) == -1)
+ return;
+ } else { // highlight the matching brace/bracket/parenthesis
+ if (write32(1, buf32, highlight) == -1)
+ return;
+ setDisplayAttribute(true);
+ if (write32(1, &buf32[highlight], 1) == -1)
+ return;
+ setDisplayAttribute(false);
+ if (write32(1, buf32 + highlight + 1, len - highlight - 1) == -1)
+ return;
}
// we have to generate our own newline on line wrap
- if ( xEndOfInput == 0 && yEndOfInput > 0 )
- if ( write( 1, "\n", 1 ) == -1 ) return;
+ if (xEndOfInput == 0 && yEndOfInput > 0)
+ if (write(1, "\n", 1) == -1)
+ return;
// position the cursor
cursorRowMovement = yEndOfInput - yCursorPos;
- if ( cursorRowMovement > 0 ) { // move the cursor up as required
- snprintf( seq, sizeof seq, "\x1b[%dA", cursorRowMovement );
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ if (cursorRowMovement > 0) { // move the cursor up as required
+ snprintf(seq, sizeof seq, "\x1b[%dA", cursorRowMovement);
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
}
// position the cursor within the line
- snprintf( seq, sizeof seq, "\x1b[%dG", xCursorPos + 1 ); // 1-based on VT100
- if ( write( 1, seq, strlen( seq ) ) == -1 ) return;
+ snprintf(seq, sizeof seq, "\x1b[%dG", xCursorPos + 1); // 1-based on VT100
+ if (write(1, seq, strlen(seq)) == -1)
+ return;
#endif
pi.promptCursorRowOffset = pi.promptExtraLines + yCursorPos; // remember row for next pass
@@ -855,35 +894,34 @@ void InputBuffer::refreshLine( PromptBase& pi ) {
*
* @return UChar32 Unicode character
*/
-static UChar32 readUnicodeCharacter( void ) {
+static UChar32 readUnicodeCharacter(void) {
static UChar8 utf8String[5];
static size_t utf8Count = 0;
- while ( true ) {
+ while (true) {
UChar8 c;
- if ( read( 0, &c, 1 ) <= 0 ) return 0;
- if ( c <= 0x7F ) { // short circuit ASCII
+ if (read(0, &c, 1) <= 0)
+ return 0;
+ if (c <= 0x7F) { // short circuit ASCII
utf8Count = 0;
return c;
- }
- else if ( utf8Count < sizeof( utf8String ) - 1 ) {
- utf8String[ utf8Count++ ] = c;
- utf8String[ utf8Count ] = 0;
+ } else if (utf8Count < sizeof(utf8String) - 1) {
+ utf8String[utf8Count++] = c;
+ utf8String[utf8Count] = 0;
UChar32 unicodeChar[2];
size_t ucharCount;
int errorCode;
- copyString8to32( unicodeChar, utf8String, 2, ucharCount, errorCode );
- if ( ucharCount && errorCode == 0 ) {
+ copyString8to32(unicodeChar, utf8String, 2, ucharCount, errorCode);
+ if (ucharCount && errorCode == 0) {
utf8Count = 0;
return unicodeChar[0];
}
- }
- else {
+ } else {
utf8Count = 0; // this shouldn't happen: got four bytes but no UTF-8 character
}
}
}
-namespace EscapeSequenceProcessing { // move these out of global namespace
+namespace EscapeSequenceProcessing { // move these out of global namespace
// This chunk of code does parsing of the escape sequences sent by various Linux terminals.
//
@@ -907,16 +945,16 @@ namespace EscapeSequenceProcessing { // move these out of global namespace
// as input, does any required processing including reading more characters and calling other
// dispatch routines, then eventually returns the final (possibly extended or special) character.
//
-typedef UChar32 ( *CharacterDispatchRoutine )( UChar32 );
+typedef UChar32 (*CharacterDispatchRoutine)(UChar32);
// This structure is used by doDispatch() to hold a list of characters to test for and
// a list of routines to call if the character matches. The dispatch routine list is one
// longer than the character list; the final entry is used if no character matches.
//
struct CharacterDispatch {
- unsigned int len; // length of the chars list
- const char* chars; // chars to test
- CharacterDispatchRoutine* dispatch; // array of routines to call
+ unsigned int len; // length of the chars list
+ const char* chars; // chars to test
+ CharacterDispatchRoutine* dispatch; // array of routines to call
};
// This dispatch routine is given a dispatch table and then farms work out to routines
@@ -924,266 +962,279 @@ struct CharacterDispatch {
// read more input characters to decide what should eventually be returned. Eventually,
// a called routine returns either a character or -1 to indicate parsing failure.
//
-static UChar32 doDispatch( UChar32 c, CharacterDispatch& dispatchTable ) {
- for ( unsigned int i = 0; i < dispatchTable.len ; ++i ) {
- if ( static_cast<unsigned char>( dispatchTable.chars[i] ) == c ) {
- return dispatchTable.dispatch[i]( c );
+static UChar32 doDispatch(UChar32 c, CharacterDispatch& dispatchTable) {
+ for (unsigned int i = 0; i < dispatchTable.len; ++i) {
+ if (static_cast<unsigned char>(dispatchTable.chars[i]) == c) {
+ return dispatchTable.dispatch[i](c);
}
}
- return dispatchTable.dispatch[dispatchTable.len]( c );
+ return dispatchTable.dispatch[dispatchTable.len](c);
}
-static UChar32 thisKeyMetaCtrl = 0; // holds pre-set Meta and/or Ctrl modifiers
+static UChar32 thisKeyMetaCtrl = 0; // holds pre-set Meta and/or Ctrl modifiers
// Final dispatch routines -- return something
//
-static UChar32 normalKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | c; }
-static UChar32 upArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | UP_ARROW_KEY; }
-static UChar32 downArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | DOWN_ARROW_KEY; }
-static UChar32 rightArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | RIGHT_ARROW_KEY; }
-static UChar32 leftArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | LEFT_ARROW_KEY; }
-static UChar32 homeKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | HOME_KEY; }
-static UChar32 endKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | END_KEY; }
-static UChar32 pageUpKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | PAGE_UP_KEY; }
-static UChar32 pageDownKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | PAGE_DOWN_KEY; }
-static UChar32 deleteCharRoutine( UChar32 c ) { return thisKeyMetaCtrl | ctrlChar( 'H' ); } // key labeled Backspace
-static UChar32 deleteKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | DELETE_KEY; } // key labeled Delete
-static UChar32 ctrlUpArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | CTRL | UP_ARROW_KEY; }
-static UChar32 ctrlDownArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | CTRL | DOWN_ARROW_KEY; }
-static UChar32 ctrlRightArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | CTRL | RIGHT_ARROW_KEY; }
-static UChar32 ctrlLeftArrowKeyRoutine( UChar32 c ) { return thisKeyMetaCtrl | CTRL | LEFT_ARROW_KEY; }
-static UChar32 escFailureRoutine( UChar32 c ) { beep(); return -1; }
+static UChar32 normalKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | c;
+}
+static UChar32 upArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | UP_ARROW_KEY;
+}
+static UChar32 downArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | DOWN_ARROW_KEY;
+}
+static UChar32 rightArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | RIGHT_ARROW_KEY;
+}
+static UChar32 leftArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | LEFT_ARROW_KEY;
+}
+static UChar32 homeKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | HOME_KEY;
+}
+static UChar32 endKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | END_KEY;
+}
+static UChar32 pageUpKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | PAGE_UP_KEY;
+}
+static UChar32 pageDownKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | PAGE_DOWN_KEY;
+}
+static UChar32 deleteCharRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | ctrlChar('H');
+} // key labeled Backspace
+static UChar32 deleteKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | DELETE_KEY;
+} // key labeled Delete
+static UChar32 ctrlUpArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | CTRL | UP_ARROW_KEY;
+}
+static UChar32 ctrlDownArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | CTRL | DOWN_ARROW_KEY;
+}
+static UChar32 ctrlRightArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | CTRL | RIGHT_ARROW_KEY;
+}
+static UChar32 ctrlLeftArrowKeyRoutine(UChar32 c) {
+ return thisKeyMetaCtrl | CTRL | LEFT_ARROW_KEY;
+}
+static UChar32 escFailureRoutine(UChar32 c) {
+ beep();
+ return -1;
+}
// Handle ESC [ 1 ; 3 (or 5) <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket1Semicolon3or5Routines[] = {
- upArrowKeyRoutine,
- downArrowKeyRoutine,
- rightArrowKeyRoutine,
- leftArrowKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket1Semicolon3or5Dispatch = { 4, "ABCD", escLeftBracket1Semicolon3or5Routines };
+static CharacterDispatchRoutine escLeftBracket1Semicolon3or5Routines[] = {upArrowKeyRoutine,
+ downArrowKeyRoutine,
+ rightArrowKeyRoutine,
+ leftArrowKeyRoutine,
+ escFailureRoutine};
+static CharacterDispatch escLeftBracket1Semicolon3or5Dispatch = {
+ 4, "ABCD", escLeftBracket1Semicolon3or5Routines};
// Handle ESC [ 1 ; <more stuff> escape sequences
//
-static UChar32 escLeftBracket1Semicolon3Routine( UChar32 c ) {
+static UChar32 escLeftBracket1Semicolon3Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
+ if (c == 0)
+ return 0;
thisKeyMetaCtrl |= META;
- return doDispatch( c, escLeftBracket1Semicolon3or5Dispatch );
+ return doDispatch(c, escLeftBracket1Semicolon3or5Dispatch);
}
-static UChar32 escLeftBracket1Semicolon5Routine( UChar32 c ) {
+static UChar32 escLeftBracket1Semicolon5Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
+ if (c == 0)
+ return 0;
thisKeyMetaCtrl |= CTRL;
- return doDispatch( c, escLeftBracket1Semicolon3or5Dispatch );
+ return doDispatch(c, escLeftBracket1Semicolon3or5Dispatch);
}
static CharacterDispatchRoutine escLeftBracket1SemicolonRoutines[] = {
- escLeftBracket1Semicolon3Routine,
- escLeftBracket1Semicolon5Routine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket1SemicolonDispatch = { 2, "35", escLeftBracket1SemicolonRoutines };
+ escLeftBracket1Semicolon3Routine, escLeftBracket1Semicolon5Routine, escFailureRoutine};
+static CharacterDispatch escLeftBracket1SemicolonDispatch = {
+ 2, "35", escLeftBracket1SemicolonRoutines};
// Handle ESC [ 1 <more stuff> escape sequences
//
-static UChar32 escLeftBracket1SemicolonRoutine( UChar32 c ) {
+static UChar32 escLeftBracket1SemicolonRoutine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket1SemicolonDispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket1SemicolonDispatch);
}
static CharacterDispatchRoutine escLeftBracket1Routines[] = {
- homeKeyRoutine,
- escLeftBracket1SemicolonRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket1Dispatch = { 2, "~;", escLeftBracket1Routines };
+ homeKeyRoutine, escLeftBracket1SemicolonRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket1Dispatch = {2, "~;", escLeftBracket1Routines};
// Handle ESC [ 3 <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket3Routines[] = {
- deleteKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket3Dispatch = { 1, "~", escLeftBracket3Routines };
+static CharacterDispatchRoutine escLeftBracket3Routines[] = {deleteKeyRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket3Dispatch = {1, "~", escLeftBracket3Routines};
// Handle ESC [ 4 <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket4Routines[] = {
- endKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket4Dispatch = { 1, "~", escLeftBracket4Routines };
+static CharacterDispatchRoutine escLeftBracket4Routines[] = {endKeyRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket4Dispatch = {1, "~", escLeftBracket4Routines};
// Handle ESC [ 5 <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket5Routines[] = {
- pageUpKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket5Dispatch = { 1, "~", escLeftBracket5Routines };
+static CharacterDispatchRoutine escLeftBracket5Routines[] = {pageUpKeyRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket5Dispatch = {1, "~", escLeftBracket5Routines};
// Handle ESC [ 6 <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket6Routines[] = {
- pageDownKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket6Dispatch = { 1, "~", escLeftBracket6Routines };
+static CharacterDispatchRoutine escLeftBracket6Routines[] = {pageDownKeyRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket6Dispatch = {1, "~", escLeftBracket6Routines};
// Handle ESC [ 7 <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket7Routines[] = {
- homeKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket7Dispatch = { 1, "~", escLeftBracket7Routines };
+static CharacterDispatchRoutine escLeftBracket7Routines[] = {homeKeyRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket7Dispatch = {1, "~", escLeftBracket7Routines};
// Handle ESC [ 8 <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracket8Routines[] = {
- endKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracket8Dispatch = { 1, "~", escLeftBracket8Routines };
+static CharacterDispatchRoutine escLeftBracket8Routines[] = {endKeyRoutine, escFailureRoutine};
+static CharacterDispatch escLeftBracket8Dispatch = {1, "~", escLeftBracket8Routines};
// Handle ESC [ <digit> escape sequences
//
-static UChar32 escLeftBracket0Routine( UChar32 c ) {
- return escFailureRoutine( c );
+static UChar32 escLeftBracket0Routine(UChar32 c) {
+ return escFailureRoutine(c);
}
-static UChar32 escLeftBracket1Routine( UChar32 c ) {
+static UChar32 escLeftBracket1Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket1Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket1Dispatch);
}
-static UChar32 escLeftBracket2Routine( UChar32 c ) {
- return escFailureRoutine( c ); // Insert key, unused
+static UChar32 escLeftBracket2Routine(UChar32 c) {
+ return escFailureRoutine(c); // Insert key, unused
}
-static UChar32 escLeftBracket3Routine( UChar32 c ) {
+static UChar32 escLeftBracket3Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket3Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket3Dispatch);
}
-static UChar32 escLeftBracket4Routine( UChar32 c ) {
+static UChar32 escLeftBracket4Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket4Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket4Dispatch);
}
-static UChar32 escLeftBracket5Routine( UChar32 c ) {
+static UChar32 escLeftBracket5Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket5Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket5Dispatch);
}
-static UChar32 escLeftBracket6Routine( UChar32 c ) {
+static UChar32 escLeftBracket6Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket6Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket6Dispatch);
}
-static UChar32 escLeftBracket7Routine( UChar32 c ) {
+static UChar32 escLeftBracket7Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket7Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket7Dispatch);
}
-static UChar32 escLeftBracket8Routine( UChar32 c ) {
+static UChar32 escLeftBracket8Routine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracket8Dispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracket8Dispatch);
}
-static UChar32 escLeftBracket9Routine( UChar32 c ) {
- return escFailureRoutine( c );
+static UChar32 escLeftBracket9Routine(UChar32 c) {
+ return escFailureRoutine(c);
}
// Handle ESC [ <more stuff> escape sequences
//
-static CharacterDispatchRoutine escLeftBracketRoutines[] = {
- upArrowKeyRoutine,
- downArrowKeyRoutine,
- rightArrowKeyRoutine,
- leftArrowKeyRoutine,
- homeKeyRoutine,
- endKeyRoutine,
- escLeftBracket0Routine,
- escLeftBracket1Routine,
- escLeftBracket2Routine,
- escLeftBracket3Routine,
- escLeftBracket4Routine,
- escLeftBracket5Routine,
- escLeftBracket6Routine,
- escLeftBracket7Routine,
- escLeftBracket8Routine,
- escLeftBracket9Routine,
- escFailureRoutine
-};
-static CharacterDispatch escLeftBracketDispatch = { 16, "ABCDHF0123456789", escLeftBracketRoutines };
+static CharacterDispatchRoutine escLeftBracketRoutines[] = {upArrowKeyRoutine,
+ downArrowKeyRoutine,
+ rightArrowKeyRoutine,
+ leftArrowKeyRoutine,
+ homeKeyRoutine,
+ endKeyRoutine,
+ escLeftBracket0Routine,
+ escLeftBracket1Routine,
+ escLeftBracket2Routine,
+ escLeftBracket3Routine,
+ escLeftBracket4Routine,
+ escLeftBracket5Routine,
+ escLeftBracket6Routine,
+ escLeftBracket7Routine,
+ escLeftBracket8Routine,
+ escLeftBracket9Routine,
+ escFailureRoutine};
+static CharacterDispatch escLeftBracketDispatch = {16, "ABCDHF0123456789", escLeftBracketRoutines};
// Handle ESC O <char> escape sequences
//
-static CharacterDispatchRoutine escORoutines[] = {
- upArrowKeyRoutine,
- downArrowKeyRoutine,
- rightArrowKeyRoutine,
- leftArrowKeyRoutine,
- homeKeyRoutine,
- endKeyRoutine,
- ctrlUpArrowKeyRoutine,
- ctrlDownArrowKeyRoutine,
- ctrlRightArrowKeyRoutine,
- ctrlLeftArrowKeyRoutine,
- escFailureRoutine
-};
-static CharacterDispatch escODispatch = { 10, "ABCDHFabcd", escORoutines };
+static CharacterDispatchRoutine escORoutines[] = {upArrowKeyRoutine,
+ downArrowKeyRoutine,
+ rightArrowKeyRoutine,
+ leftArrowKeyRoutine,
+ homeKeyRoutine,
+ endKeyRoutine,
+ ctrlUpArrowKeyRoutine,
+ ctrlDownArrowKeyRoutine,
+ ctrlRightArrowKeyRoutine,
+ ctrlLeftArrowKeyRoutine,
+ escFailureRoutine};
+static CharacterDispatch escODispatch = {10, "ABCDHFabcd", escORoutines};
// Initial ESC dispatch -- could be a Meta prefix or the start of an escape sequence
//
-static UChar32 escLeftBracketRoutine( UChar32 c ) {
+static UChar32 escLeftBracketRoutine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escLeftBracketDispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escLeftBracketDispatch);
}
-static UChar32 escORoutine( UChar32 c ) {
+static UChar32 escORoutine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escODispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escODispatch);
}
-static UChar32 setMetaRoutine( UChar32 c ); // need forward reference
+static UChar32 setMetaRoutine(UChar32 c); // need forward reference
static CharacterDispatchRoutine escRoutines[] = {
- escLeftBracketRoutine,
- escORoutine,
- setMetaRoutine
-};
-static CharacterDispatch escDispatch = { 2, "[O", escRoutines };
+ escLeftBracketRoutine, escORoutine, setMetaRoutine};
+static CharacterDispatch escDispatch = {2, "[O", escRoutines};
// Initial dispatch -- we are not in the middle of anything yet
//
-static UChar32 escRoutine( UChar32 c ) {
+static UChar32 escRoutine(UChar32 c) {
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escDispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escDispatch);
}
static CharacterDispatchRoutine initialRoutines[] = {
- escRoutine,
- deleteCharRoutine,
- normalKeyRoutine
-};
-static CharacterDispatch initialDispatch = { 2, "\x1B\x7F", initialRoutines };
+ escRoutine, deleteCharRoutine, normalKeyRoutine};
+static CharacterDispatch initialDispatch = {2, "\x1B\x7F", initialRoutines};
// Special handling for the ESC key because it does double duty
//
-static UChar32 setMetaRoutine( UChar32 c ) {
+static UChar32 setMetaRoutine(UChar32 c) {
thisKeyMetaCtrl = META;
- if ( c == 0x1B ) { // another ESC, stay in ESC processing mode
+ if (c == 0x1B) { // another ESC, stay in ESC processing mode
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
- return doDispatch( c, escDispatch );
+ if (c == 0)
+ return 0;
+ return doDispatch(c, escDispatch);
}
- return doDispatch( c, initialDispatch );
+ return doDispatch(c, initialDispatch);
}
-} // namespace EscapeSequenceProcessing // move these out of global namespace
+} // namespace EscapeSequenceProcessing // move these out of global namespace
-#endif // #ifndef _WIN32
+#endif // #ifndef _WIN32
// linenoiseReadChar -- read a keystroke or keychord from the keyboard, and translate it
// into an encoded "keystroke". When convenient, extended keys are translated into their
@@ -1191,16 +1242,16 @@ static UChar32 setMetaRoutine( UChar32 c ) {
//
// A return value of zero means "no input available", and a return value of -1 means "invalid key".
//
-static UChar32 linenoiseReadChar( void ) {
+static UChar32 linenoiseReadChar(void) {
#ifdef _WIN32
INPUT_RECORD rec;
DWORD count;
int modifierKeys = 0;
bool escSeen = false;
- while ( true ) {
- ReadConsoleInputW( console_in, &rec, 1, &count );
-#if 0 // helper for debugging keystrokes, display info in the debug "Output" window in the debugger
+ while (true) {
+ ReadConsoleInputW(console_in, &rec, 1, &count);
+#if 0 // helper for debugging keystrokes, display info in the debug "Output" window in the debugger
{
if ( rec.EventType == KEY_EVENT ) {
//if ( rec.Event.KeyEvent.uChar.UnicodeChar ) {
@@ -1223,49 +1274,59 @@ static UChar32 linenoiseReadChar( void ) {
}
}
#endif
- if ( rec.EventType != KEY_EVENT ) {
+ if (rec.EventType != KEY_EVENT) {
continue;
}
// Windows provides for entry of characters that are not on your keyboard by sending the Unicode
// characters as a "key up" with virtual keycode 0x12 (VK_MENU == Alt key) ... accept these characters,
// otherwise only process characters on "key down"
- if ( !rec.Event.KeyEvent.bKeyDown && rec.Event.KeyEvent.wVirtualKeyCode != VK_MENU ) {
+ if (!rec.Event.KeyEvent.bKeyDown && rec.Event.KeyEvent.wVirtualKeyCode != VK_MENU) {
continue;
}
modifierKeys = 0;
// AltGr is encoded as ( LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED ), so don't treat this combination as either CTRL or META
// we just turn off those two bits, so it is still possible to combine CTRL and/or META with an AltGr key by using right-Ctrl and/or left-Alt
- if ( ( rec.Event.KeyEvent.dwControlKeyState & ( LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED ) ) == ( LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED ) ) {
- rec.Event.KeyEvent.dwControlKeyState &= ~( LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED );
+ if ((rec.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED)) ==
+ (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED)) {
+ rec.Event.KeyEvent.dwControlKeyState &= ~(LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
}
- if ( rec.Event.KeyEvent.dwControlKeyState & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED ) ) {
+ if (rec.Event.KeyEvent.dwControlKeyState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) {
modifierKeys |= CTRL;
}
- if ( rec.Event.KeyEvent.dwControlKeyState & ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) ) {
+ if (rec.Event.KeyEvent.dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) {
modifierKeys |= META;
}
- if ( escSeen ) {
+ if (escSeen) {
modifierKeys |= META;
}
- if ( rec.Event.KeyEvent.uChar.UnicodeChar == 0 ) {
- switch ( rec.Event.KeyEvent.wVirtualKeyCode ) {
- case VK_LEFT: return modifierKeys | LEFT_ARROW_KEY;
- case VK_RIGHT: return modifierKeys | RIGHT_ARROW_KEY;
- case VK_UP: return modifierKeys | UP_ARROW_KEY;
- case VK_DOWN: return modifierKeys | DOWN_ARROW_KEY;
- case VK_DELETE: return modifierKeys | DELETE_KEY;
- case VK_HOME: return modifierKeys | HOME_KEY;
- case VK_END: return modifierKeys | END_KEY;
- case VK_PRIOR: return modifierKeys | PAGE_UP_KEY;
- case VK_NEXT: return modifierKeys | PAGE_DOWN_KEY;
- default: continue; // in raw mode, ReadConsoleInput shows shift, ctrl ...
- } // ... ignore them
- }
- else if ( rec.Event.KeyEvent.uChar.UnicodeChar == ctrlChar( '[' ) ) { // ESC, set flag for later
+ if (rec.Event.KeyEvent.uChar.UnicodeChar == 0) {
+ switch (rec.Event.KeyEvent.wVirtualKeyCode) {
+ case VK_LEFT:
+ return modifierKeys | LEFT_ARROW_KEY;
+ case VK_RIGHT:
+ return modifierKeys | RIGHT_ARROW_KEY;
+ case VK_UP:
+ return modifierKeys | UP_ARROW_KEY;
+ case VK_DOWN:
+ return modifierKeys | DOWN_ARROW_KEY;
+ case VK_DELETE:
+ return modifierKeys | DELETE_KEY;
+ case VK_HOME:
+ return modifierKeys | HOME_KEY;
+ case VK_END:
+ return modifierKeys | END_KEY;
+ case VK_PRIOR:
+ return modifierKeys | PAGE_UP_KEY;
+ case VK_NEXT:
+ return modifierKeys | PAGE_DOWN_KEY;
+ default:
+ continue; // in raw mode, ReadConsoleInput shows shift, ctrl ...
+ } // ... ignore them
+ } else if (rec.Event.KeyEvent.uChar.UnicodeChar ==
+ ctrlChar('[')) { // ESC, set flag for later
escSeen = true;
continue;
- }
- else {
+ } else {
// we got a real character, return it
return modifierKeys | rec.Event.KeyEvent.uChar.UnicodeChar;
}
@@ -1274,71 +1335,67 @@ static UChar32 linenoiseReadChar( void ) {
#else
UChar32 c;
c = readUnicodeCharacter();
- if ( c == 0 ) return 0;
+ if (c == 0)
+ return 0;
- // If _DEBUG_LINUX_KEYBOARD is set, then ctrl-^ puts us into a keyboard debugging mode
- // where we print out decimal and decoded values for whatever the "terminal" program
- // gives us on different keystrokes. Hit ctrl-C to exit this mode.
- //
+// If _DEBUG_LINUX_KEYBOARD is set, then ctrl-^ puts us into a keyboard debugging mode
+// where we print out decimal and decoded values for whatever the "terminal" program
+// gives us on different keystrokes. Hit ctrl-C to exit this mode.
+//
#define _DEBUG_LINUX_KEYBOARD
#if defined(_DEBUG_LINUX_KEYBOARD)
- if ( c == ctrlChar( '^' ) ) { // ctrl-^, special debug mode, prints all keys hit, ctrl-C to get out
- printf( "\nEntering keyboard debugging mode (on ctrl-^), press ctrl-C to exit this mode\n" );
- while ( true ) {
+ if (c == ctrlChar('^')) { // ctrl-^, special debug mode, prints all keys hit, ctrl-C to get out
+ printf("\nEntering keyboard debugging mode (on ctrl-^), press ctrl-C to exit this mode\n");
+ while (true) {
unsigned char keys[10];
- int ret = read( 0, keys, 10 );
+ int ret = read(0, keys, 10);
- if ( ret <= 0 ) {
- printf( "\nret: %d\n", ret );
+ if (ret <= 0) {
+ printf("\nret: %d\n", ret);
}
- for ( int i = 0; i < ret; ++i ) {
- UChar32 key = static_cast<UChar32>( keys[i] );
+ for (int i = 0; i < ret; ++i) {
+ UChar32 key = static_cast<UChar32>(keys[i]);
char* friendlyTextPtr;
char friendlyTextBuf[10];
const char* prefixText = (key < 0x80) ? "" : "0x80+";
UChar32 keyCopy = (key < 0x80) ? key : key - 0x80;
- if ( keyCopy >= '!' && keyCopy <= '~' ) { // printable
+ if (keyCopy >= '!' && keyCopy <= '~') { // printable
friendlyTextBuf[0] = '\'';
friendlyTextBuf[1] = keyCopy;
friendlyTextBuf[2] = '\'';
friendlyTextBuf[3] = 0;
friendlyTextPtr = friendlyTextBuf;
- }
- else if ( keyCopy == ' ' ) {
- friendlyTextPtr = const_cast<char*>( "space" );
- }
- else if (keyCopy == 27 ) {
- friendlyTextPtr = const_cast<char*>( "ESC" );
- }
- else if (keyCopy == 0 ) {
- friendlyTextPtr = const_cast<char*>( "NUL" );
- }
- else if (keyCopy == 127 ) {
- friendlyTextPtr = const_cast<char*>( "DEL" );
- }
- else {
+ } else if (keyCopy == ' ') {
+ friendlyTextPtr = const_cast<char*>("space");
+ } else if (keyCopy == 27) {
+ friendlyTextPtr = const_cast<char*>("ESC");
+ } else if (keyCopy == 0) {
+ friendlyTextPtr = const_cast<char*>("NUL");
+ } else if (keyCopy == 127) {
+ friendlyTextPtr = const_cast<char*>("DEL");
+ } else {
friendlyTextBuf[0] = '^';
friendlyTextBuf[1] = keyCopy + 0x40;
friendlyTextBuf[2] = 0;
friendlyTextPtr = friendlyTextBuf;
}
- printf( "%d x%02X (%s%s) ", key, key, prefixText, friendlyTextPtr );
+ printf("%d x%02X (%s%s) ", key, key, prefixText, friendlyTextPtr);
}
- printf( "\x1b[1G\n" ); // go to first column of new line
+ printf("\x1b[1G\n"); // go to first column of new line
// drop out of this loop on ctrl-C
- if ( keys[0] == ctrlChar( 'C' ) ) {
- printf( "Leaving keyboard debugging mode (on ctrl-C)\n" );
- fflush( stdout );
+ if (keys[0] == ctrlChar('C')) {
+ printf("Leaving keyboard debugging mode (on ctrl-C)\n");
+ fflush(stdout);
return -2;
}
}
}
#endif // _DEBUG_LINUX_KEYBOARD
- EscapeSequenceProcessing::thisKeyMetaCtrl = 0; // no modifiers yet at initialDispatch
- return EscapeSequenceProcessing::doDispatch( c, EscapeSequenceProcessing::initialDispatch );
-#endif // #_WIN32
+ EscapeSequenceProcessing::thisKeyMetaCtrl = 0; // no modifiers yet at initialDispatch
+ return EscapeSequenceProcessing::doDispatch(c, EscapeSequenceProcessing::initialDispatch);
+#endif // #_WIN32
}
/**
@@ -1346,7 +1403,7 @@ static UChar32 linenoiseReadChar( void ) {
*
* @param lc pointer to a linenoiseCompletions struct
*/
-static void freeCompletions( linenoiseCompletions* lc ) {
+static void freeCompletions(linenoiseCompletions* lc) {
lc->completionStrings.clear();
}
@@ -1357,16 +1414,16 @@ static void freeCompletions( linenoiseCompletions* lc ) {
* @param c character to clean up
* @return cleaned-up character
*/
-static int cleanupCtrl( int c ) {
- if ( c & CTRL ) {
+static int cleanupCtrl(int c) {
+ if (c & CTRL) {
int d = c & 0x1FF;
- if ( d >= 'a' && d <= 'z' ) {
- c = ( c + ( 'a' - ctrlChar( 'A' ) ) ) & ~CTRL;
+ if (d >= 'a' && d <= 'z') {
+ c = (c + ('a' - ctrlChar('A'))) & ~CTRL;
}
- if ( d >= 'A' && d <= 'Z' ) {
- c = ( c + ( 'A' - ctrlChar( 'A' ) ) ) & ~CTRL;
+ if (d >= 'A' && d <= 'Z') {
+ c = (c + ('A' - ctrlChar('A'))) & ~CTRL;
}
- if ( d >= ctrlChar( 'A' ) && d <= ctrlChar( 'Z' ) ) {
+ if (d >= ctrlChar('A') && d <= ctrlChar('Z')) {
c = c & ~CTRL;
}
}
@@ -1385,254 +1442,266 @@ static const size_t completionCountCutoff = 100;
* text as the user selects a proposed completion string, or cancels the completion attempt.
* @param pi PromptBase struct holding information about the prompt and our screen position
*/
-int InputBuffer::completeLine( PromptBase& pi ) {
+int InputBuffer::completeLine(PromptBase& pi) {
linenoiseCompletions lc;
char c = 0;
// completionCallback() expects a parsable entity, so find the previous break character and extract
// a copy to parse. we also handle the case where tab is hit while not at end-of-line.
int startIndex = pos;
- while ( --startIndex >= 0 ) {
- if ( strchr( breakChars, buf32[startIndex] ) ) {
+ while (--startIndex >= 0) {
+ if (strchr(breakChars, buf32[startIndex])) {
break;
}
}
++startIndex;
int itemLength = pos - startIndex;
- Utf32String unicodeCopy( &buf32[startIndex], itemLength );
- Utf8String parseItem( unicodeCopy );
+ Utf32String unicodeCopy(&buf32[startIndex], itemLength);
+ Utf8String parseItem(unicodeCopy);
// get a list of completions
- completionCallback( reinterpret_cast< char * >( parseItem.get() ), &lc );
+ completionCallback(reinterpret_cast<char*>(parseItem.get()), &lc);
// if no completions, we are done
- if ( lc.completionStrings.size() == 0 ) {
+ if (lc.completionStrings.size() == 0) {
beep();
- freeCompletions( &lc );
+ freeCompletions(&lc);
return 0;
}
// at least one completion
int longestCommonPrefix = 0;
int displayLength = 0;
- if ( lc.completionStrings.size() == 1 ) {
+ if (lc.completionStrings.size() == 1) {
longestCommonPrefix = lc.completionStrings[0].length();
- }
- else {
+ } else {
bool keepGoing = true;
- while ( keepGoing ) {
- for ( size_t j = 0; j < lc.completionStrings.size() - 1; ++j ) {
+ while (keepGoing) {
+ for (size_t j = 0; j < lc.completionStrings.size() - 1; ++j) {
char c1 = lc.completionStrings[j][longestCommonPrefix];
char c2 = lc.completionStrings[j + 1][longestCommonPrefix];
- if ( ( 0 == c1 ) || ( 0 == c2 ) || ( c1 != c2 ) ) {
+ if ((0 == c1) || (0 == c2) || (c1 != c2)) {
keepGoing = false;
break;
}
}
- if ( keepGoing ) {
+ if (keepGoing) {
++longestCommonPrefix;
}
}
}
- if ( lc.completionStrings.size() != 1 ) { // beep if ambiguous
+ if (lc.completionStrings.size() != 1) { // beep if ambiguous
beep();
}
// if we can extend the item, extend it and return to main loop
- if ( longestCommonPrefix > itemLength ) {
+ if (longestCommonPrefix > itemLength) {
displayLength = len + longestCommonPrefix - itemLength;
- if ( displayLength > buflen ) {
+ if (displayLength > buflen) {
longestCommonPrefix -= displayLength - buflen; // don't overflow buffer
- displayLength = buflen; // truncate the insertion
- beep(); // and make a noise
+ displayLength = buflen; // truncate the insertion
+ beep(); // and make a noise
}
- Utf32String displayText( displayLength + 1 );
- memcpy( displayText.get(), buf32, sizeof( UChar32 ) * startIndex );
- memcpy( &displayText[startIndex], &lc.completionStrings[0][0], sizeof( UChar32 ) * longestCommonPrefix );
+ Utf32String displayText(displayLength + 1);
+ memcpy(displayText.get(), buf32, sizeof(UChar32) * startIndex);
+ memcpy(&displayText[startIndex],
+ &lc.completionStrings[0][0],
+ sizeof(UChar32) * longestCommonPrefix);
int tailIndex = startIndex + longestCommonPrefix;
- memcpy( &displayText[tailIndex], &buf32[pos], sizeof( UChar32 ) * ( displayLength - tailIndex + 1 ) );
- copyString32( buf32, displayText.get(), buflen + 1 );
+ memcpy(&displayText[tailIndex],
+ &buf32[pos],
+ sizeof(UChar32) * (displayLength - tailIndex + 1));
+ copyString32(buf32, displayText.get(), buflen + 1);
pos = startIndex + longestCommonPrefix;
len = displayLength;
- refreshLine( pi );
+ refreshLine(pi);
return 0;
}
// we can't complete any further, wait for second tab
do {
c = linenoiseReadChar();
- c = cleanupCtrl( c );
- } while ( c == static_cast<char>( -1 ) );
+ c = cleanupCtrl(c);
+ } while (c == static_cast<char>(-1));
// if any character other than tab, pass it to the main loop
- if ( c != ctrlChar( 'I' ) ) {
- freeCompletions( &lc );
+ if (c != ctrlChar('I')) {
+ freeCompletions(&lc);
return c;
}
// we got a second tab, maybe show list of possible completions
bool showCompletions = true;
bool onNewLine = false;
- if ( lc.completionStrings.size() > completionCountCutoff ) {
+ if (lc.completionStrings.size() > completionCountCutoff) {
int savePos = pos; // move cursor to EOL to avoid overwriting the command line
pos = len;
- refreshLine( pi );
+ refreshLine(pi);
pos = savePos;
- printf( "\nDisplay all %u possibilities? (y or n)",
- static_cast<unsigned int>( lc.completionStrings.size() ) );
- fflush( stdout );
+ printf("\nDisplay all %u possibilities? (y or n)",
+ static_cast<unsigned int>(lc.completionStrings.size()));
+ fflush(stdout);
onNewLine = true;
- while ( c != 'y' && c != 'Y' && c != 'n' && c != 'N' && c != ctrlChar( 'C' ) ) {
+ while (c != 'y' && c != 'Y' && c != 'n' && c != 'N' && c != ctrlChar('C')) {
do {
c = linenoiseReadChar();
- c = cleanupCtrl( c );
- } while ( c == static_cast<char>( -1 ) );
+ c = cleanupCtrl(c);
+ } while (c == static_cast<char>(-1));
}
- switch ( c ) {
- case 'n':
- case 'N':
- showCompletions = false;
- freeCompletions( &lc );
- break;
- case ctrlChar( 'C' ):
- showCompletions = false;
- freeCompletions( &lc );
- if ( write( 1, "^C", 2 ) == -1 ) return -1; // Display the ^C we got
- c = 0;
- break;
+ switch (c) {
+ case 'n':
+ case 'N':
+ showCompletions = false;
+ freeCompletions(&lc);
+ break;
+ case ctrlChar('C'):
+ showCompletions = false;
+ freeCompletions(&lc);
+ if (write(1, "^C", 2) == -1)
+ return -1; // Display the ^C we got
+ c = 0;
+ break;
}
}
// if showing the list, do it the way readline does it
bool stopList = false;
- if ( showCompletions ) {
+ if (showCompletions) {
int longestCompletion = 0;
- for ( size_t j = 0; j < lc.completionStrings.size(); ++j) {
+ for (size_t j = 0; j < lc.completionStrings.size(); ++j) {
itemLength = lc.completionStrings[j].length();
- if ( itemLength > longestCompletion ) {
+ if (itemLength > longestCompletion) {
longestCompletion = itemLength;
}
}
longestCompletion += 2;
int columnCount = pi.promptScreenColumns / longestCompletion;
- if ( columnCount < 1) {
+ if (columnCount < 1) {
columnCount = 1;
}
- if ( ! onNewLine ) { // skip this if we showed "Display all %d possibilities?"
+ if (!onNewLine) { // skip this if we showed "Display all %d possibilities?"
int savePos = pos; // move cursor to EOL to avoid overwriting the command line
pos = len;
- refreshLine( pi );
+ refreshLine(pi);
pos = savePos;
}
size_t pauseRow = getScreenRows() - 1;
- size_t rowCount = ( lc.completionStrings.size() + columnCount - 1) / columnCount;
- for ( size_t row = 0; row < rowCount; ++row ) {
- if ( row == pauseRow ) {
- printf( "\n--More--" );
- fflush( stdout );
+ size_t rowCount = (lc.completionStrings.size() + columnCount - 1) / columnCount;
+ for (size_t row = 0; row < rowCount; ++row) {
+ if (row == pauseRow) {
+ printf("\n--More--");
+ fflush(stdout);
c = 0;
bool doBeep = false;
- while ( c != ' ' && c != '\r' && c != '\n' && c != 'y' && c != 'Y' && c != 'n' && c != 'N' && c != 'q' && c != 'Q' && c != ctrlChar( 'C' ) ) {
- if ( doBeep ) {
+ while (c != ' ' && c != '\r' && c != '\n' && c != 'y' && c != 'Y' && c != 'n' &&
+ c != 'N' && c != 'q' && c != 'Q' && c != ctrlChar('C')) {
+ if (doBeep) {
beep();
}
doBeep = true;
do {
c = linenoiseReadChar();
- c = cleanupCtrl( c );
- } while ( c == static_cast<char>( -1 ) );
+ c = cleanupCtrl(c);
+ } while (c == static_cast<char>(-1));
}
- switch ( c ) {
- case ' ':
- case 'y':
- case 'Y':
- printf( "\r \r" );
- pauseRow += getScreenRows() - 1;
- break;
- case '\r':
- case '\n':
- printf( "\r \r" );
- ++pauseRow;
- break;
- case 'n':
- case 'N':
- case 'q':
- case 'Q':
- printf( "\r \r" );
- stopList = true;
- break;
- case ctrlChar( 'C' ):
- if ( write( 1, "^C", 2 ) == -1 ) return -1; // Display the ^C we got
- stopList = true;
- break;
+ switch (c) {
+ case ' ':
+ case 'y':
+ case 'Y':
+ printf("\r \r");
+ pauseRow += getScreenRows() - 1;
+ break;
+ case '\r':
+ case '\n':
+ printf("\r \r");
+ ++pauseRow;
+ break;
+ case 'n':
+ case 'N':
+ case 'q':
+ case 'Q':
+ printf("\r \r");
+ stopList = true;
+ break;
+ case ctrlChar('C'):
+ if (write(1, "^C", 2) == -1)
+ return -1; // Display the ^C we got
+ stopList = true;
+ break;
}
+ } else {
+ printf("\n");
}
- else {
- printf( "\n" );
- }
- if ( stopList ) {
+ if (stopList) {
break;
}
- for ( int column = 0; column < columnCount; ++column ) {
- size_t index = ( column * rowCount ) + row;
- if ( index < lc.completionStrings.size() ) {
+ for (int column = 0; column < columnCount; ++column) {
+ size_t index = (column * rowCount) + row;
+ if (index < lc.completionStrings.size()) {
itemLength = lc.completionStrings[index].length();
- fflush( stdout );
- if ( write32( 1, lc.completionStrings[index].get(), itemLength ) == -1 ) return -1;
- if ( ( ( column + 1 ) * rowCount ) + row < lc.completionStrings.size() ) {
- for ( int k = itemLength; k < longestCompletion; ++k ) {
- printf( " " );
+ fflush(stdout);
+ if (write32(1, lc.completionStrings[index].get(), itemLength) == -1)
+ return -1;
+ if (((column + 1) * rowCount) + row < lc.completionStrings.size()) {
+ for (int k = itemLength; k < longestCompletion; ++k) {
+ printf(" ");
}
}
}
}
}
- fflush( stdout );
- freeCompletions( &lc );
+ fflush(stdout);
+ freeCompletions(&lc);
}
// display the prompt on a new line, then redisplay the input buffer
- if ( ! stopList || c == ctrlChar( 'C' ) ) {
- if ( write( 1, "\n", 1 ) == -1 ) return 0;
+ if (!stopList || c == ctrlChar('C')) {
+ if (write(1, "\n", 1) == -1)
+ return 0;
}
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return 0;
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return 0;
#ifndef _WIN32
// we have to generate our own newline on line wrap on Linux
- if ( pi.promptIndentation == 0 && pi.promptExtraLines > 0 )
- if ( write( 1, "\n", 1 ) == -1 ) return 0;
+ if (pi.promptIndentation == 0 && pi.promptExtraLines > 0)
+ if (write(1, "\n", 1) == -1)
+ return 0;
#endif
pi.promptCursorRowOffset = pi.promptExtraLines;
- refreshLine( pi );
+ refreshLine(pi);
return 0;
}
/**
* Clear the screen ONLY (no redisplay of anything)
*/
-void linenoiseClearScreen( void ) {
+void linenoiseClearScreen(void) {
#ifdef _WIN32
COORD coord = {0, 0};
CONSOLE_SCREEN_BUFFER_INFO inf;
- HANDLE screenHandle = GetStdHandle( STD_OUTPUT_HANDLE );
- GetConsoleScreenBufferInfo( screenHandle, &inf );
- SetConsoleCursorPosition( screenHandle, coord );
+ HANDLE screenHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ GetConsoleScreenBufferInfo(screenHandle, &inf);
+ SetConsoleCursorPosition(screenHandle, coord);
DWORD count;
- FillConsoleOutputCharacterA( screenHandle, ' ', inf.dwSize.X * inf.dwSize.Y, coord, &count );
+ FillConsoleOutputCharacterA(screenHandle, ' ', inf.dwSize.X * inf.dwSize.Y, coord, &count);
#else
- if ( write( 1, "\x1b[H\x1b[2J", 7 ) <= 0 ) return;
+ if (write(1, "\x1b[H\x1b[2J", 7) <= 0)
+ return;
#endif
}
-void InputBuffer::clearScreen( PromptBase& pi ) {
+void InputBuffer::clearScreen(PromptBase& pi) {
linenoiseClearScreen();
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return;
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return;
#ifndef _WIN32
// we have to generate our own newline on line wrap on Linux
- if ( pi.promptIndentation == 0 && pi.promptExtraLines > 0 )
- if ( write( 1, "\n", 1 ) == -1 ) return;
+ if (pi.promptIndentation == 0 && pi.promptExtraLines > 0)
+ if (write(1, "\n", 1) == -1)
+ return;
#endif
pi.promptCursorRowOffset = pi.promptExtraLines;
- refreshLine( pi );
+ refreshLine(pi);
}
/**
@@ -1642,30 +1711,32 @@ void InputBuffer::clearScreen( PromptBase& pi ) {
* @param pi PromptBase struct holding information about the (old, static) prompt and our screen position
* @param startChar the character that began the search, used to set the initial direction
*/
-int InputBuffer::incrementalHistorySearch( PromptBase& pi, int startChar ) {
+int InputBuffer::incrementalHistorySearch(PromptBase& pi, int startChar) {
size_t bufferSize;
size_t ucharCount;
int errorCode;
// if not already recalling, add the current line to the history list so we don't have to special case it
- if ( historyIndex == historyLen - 1 ) {
- free( history[historyLen - 1] );
- bufferSize = sizeof( UChar32 ) * len + 1;
- unique_ptr< UChar8 []> tempBuffer( new UChar8[ bufferSize ] );
- copyString32to8( tempBuffer.get(), buf32, bufferSize );
- history[ historyLen - 1 ] = reinterpret_cast< UChar8 * >( strdup( reinterpret_cast< const char * >( tempBuffer.get() ) ) );
+ if (historyIndex == historyLen - 1) {
+ free(history[historyLen - 1]);
+ bufferSize = sizeof(UChar32) * len + 1;
+ unique_ptr<UChar8[]> tempBuffer(new UChar8[bufferSize]);
+ copyString32to8(tempBuffer.get(), buf32, bufferSize);
+ history[historyLen - 1] =
+ reinterpret_cast<UChar8*>(strdup(reinterpret_cast<const char*>(tempBuffer.get())));
}
int historyLineLength = len;
int historyLinePosition = pos;
UChar32 emptyBuffer[1];
char emptyWidths[1];
- InputBuffer empty( emptyBuffer, emptyWidths, 1 );
- empty.refreshLine( pi ); // erase the old input first
- DynamicPrompt dp( pi, ( startChar == ctrlChar( 'R' ) ) ? -1 : 1 );
+ InputBuffer empty(emptyBuffer, emptyWidths, 1);
+ empty.refreshLine(pi); // erase the old input first
+ DynamicPrompt dp(pi, (startChar == ctrlChar('R')) ? -1 : 1);
dp.promptPreviousLen = pi.promptPreviousLen;
dp.promptPreviousInputLen = pi.promptPreviousInputLen;
- dynamicRefresh( dp, buf32, historyLineLength, historyLinePosition ); // draw user's text with our prompt
+ dynamicRefresh(
+ dp, buf32, historyLineLength, historyLinePosition); // draw user's text with our prompt
// loop until we get an exit character
int c;
@@ -1673,187 +1744,199 @@ int InputBuffer::incrementalHistorySearch( PromptBase& pi, int startChar ) {
bool useSearchedLine = true;
bool searchAgain = false;
UChar32* activeHistoryLine = 0;
- while ( keepLooping ) {
+ while (keepLooping) {
c = linenoiseReadChar();
- c = cleanupCtrl( c ); // convert CTRL + <char> into normal ctrl
-
- switch ( c ) {
-
- // these characters keep the selected text but do not execute it
- case ctrlChar( 'A' ): // ctrl-A, move cursor to start of line
- case HOME_KEY:
- case ctrlChar( 'B' ): // ctrl-B, move cursor left by one character
- case LEFT_ARROW_KEY:
- case META + 'b': // meta-B, move cursor left by one word
- case META + 'B':
- case CTRL + LEFT_ARROW_KEY:
- case META + LEFT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
- case ctrlChar( 'D' ):
- case META + 'd': // meta-D, kill word to right of cursor
- case META + 'D':
- case ctrlChar( 'E' ): // ctrl-E, move cursor to end of line
- case END_KEY:
- case ctrlChar( 'F' ): // ctrl-F, move cursor right by one character
- case RIGHT_ARROW_KEY:
- case META + 'f': // meta-F, move cursor right by one word
- case META + 'F':
- case CTRL + RIGHT_ARROW_KEY:
- case META + RIGHT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
- case META + ctrlChar( 'H' ):
- case ctrlChar( 'J' ):
- case ctrlChar( 'K' ): // ctrl-K, kill from cursor to end of line
- case ctrlChar( 'M' ):
- case ctrlChar( 'N' ): // ctrl-N, recall next line in history
- case ctrlChar( 'P' ): // ctrl-P, recall previous line in history
- case DOWN_ARROW_KEY:
- case UP_ARROW_KEY:
- case ctrlChar( 'T' ): // ctrl-T, transpose characters
- case ctrlChar( 'U' ): // ctrl-U, kill all characters to the left of the cursor
- case ctrlChar( 'W' ):
- case META + 'y': // meta-Y, "yank-pop", rotate popped text
- case META + 'Y':
- case 127:
- case DELETE_KEY:
- case META + '<': // start of history
- case PAGE_UP_KEY:
- case META + '>': // end of history
- case PAGE_DOWN_KEY:
- keepLooping = false;
- break;
+ c = cleanupCtrl(c); // convert CTRL + <char> into normal ctrl
+
+ switch (c) {
+ // these characters keep the selected text but do not execute it
+ case ctrlChar('A'): // ctrl-A, move cursor to start of line
+ case HOME_KEY:
+ case ctrlChar('B'): // ctrl-B, move cursor left by one character
+ case LEFT_ARROW_KEY:
+ case META + 'b': // meta-B, move cursor left by one word
+ case META + 'B':
+ case CTRL + LEFT_ARROW_KEY:
+ case META + LEFT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
+ case ctrlChar('D'):
+ case META + 'd': // meta-D, kill word to right of cursor
+ case META + 'D':
+ case ctrlChar('E'): // ctrl-E, move cursor to end of line
+ case END_KEY:
+ case ctrlChar('F'): // ctrl-F, move cursor right by one character
+ case RIGHT_ARROW_KEY:
+ case META + 'f': // meta-F, move cursor right by one word
+ case META + 'F':
+ case CTRL + RIGHT_ARROW_KEY:
+ case META + RIGHT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
+ case META + ctrlChar('H'):
+ case ctrlChar('J'):
+ case ctrlChar('K'): // ctrl-K, kill from cursor to end of line
+ case ctrlChar('M'):
+ case ctrlChar('N'): // ctrl-N, recall next line in history
+ case ctrlChar('P'): // ctrl-P, recall previous line in history
+ case DOWN_ARROW_KEY:
+ case UP_ARROW_KEY:
+ case ctrlChar('T'): // ctrl-T, transpose characters
+ case ctrlChar('U'): // ctrl-U, kill all characters to the left of the cursor
+ case ctrlChar('W'):
+ case META + 'y': // meta-Y, "yank-pop", rotate popped text
+ case META + 'Y':
+ case 127:
+ case DELETE_KEY:
+ case META + '<': // start of history
+ case PAGE_UP_KEY:
+ case META + '>': // end of history
+ case PAGE_DOWN_KEY:
+ keepLooping = false;
+ break;
- // these characters revert the input line to its previous state
- case ctrlChar( 'C' ): // ctrl-C, abort this line
- case ctrlChar( 'G' ):
- case ctrlChar( 'L' ): // ctrl-L, clear screen and redisplay line
- keepLooping = false;
- useSearchedLine = false;
- if ( c != ctrlChar( 'L' ) ) {
- c = -1; // ctrl-C and ctrl-G just abort the search and do nothing else
- }
- break;
+ // these characters revert the input line to its previous state
+ case ctrlChar('C'): // ctrl-C, abort this line
+ case ctrlChar('G'):
+ case ctrlChar('L'): // ctrl-L, clear screen and redisplay line
+ keepLooping = false;
+ useSearchedLine = false;
+ if (c != ctrlChar('L')) {
+ c = -1; // ctrl-C and ctrl-G just abort the search and do nothing else
+ }
+ break;
- // these characters stay in search mode and update the display
- case ctrlChar( 'S' ):
- case ctrlChar( 'R' ):
- if ( dp.searchTextLen == 0 ) { // if no current search text, recall previous text
- if ( previousSearchText.length() ) {
- dp.updateSearchText( previousSearchText.get() );
+ // these characters stay in search mode and update the display
+ case ctrlChar('S'):
+ case ctrlChar('R'):
+ if (dp.searchTextLen == 0) { // if no current search text, recall previous text
+ if (previousSearchText.length()) {
+ dp.updateSearchText(previousSearchText.get());
+ }
}
- }
- if ( ( dp.direction == 1 && c == ctrlChar( 'R' ) ) ||
- ( dp.direction == -1 && c == ctrlChar( 'S' ) ) ) {
- dp.direction = 0 - dp.direction; // reverse direction
- dp.updateSearchPrompt(); // change the prompt
- }
- else {
- searchAgain = true; // same direction, search again
- }
- break;
+ if ((dp.direction == 1 && c == ctrlChar('R')) ||
+ (dp.direction == -1 && c == ctrlChar('S'))) {
+ dp.direction = 0 - dp.direction; // reverse direction
+ dp.updateSearchPrompt(); // change the prompt
+ } else {
+ searchAgain = true; // same direction, search again
+ }
+ break;
- // job control is its own thing
+// job control is its own thing
#ifndef _WIN32
- case ctrlChar( 'Z' ): // ctrl-Z, job control
- disableRawMode(); // Returning to Linux (whatever) shell, leave raw mode
- raise( SIGSTOP ); // Break out in mid-line
- enableRawMode(); // Back from Linux shell, re-enter raw mode
- {
- bufferSize = historyLineLength + 1;
- unique_ptr< UChar32 []> tempUnicode( new UChar32[ bufferSize ] );
- copyString8to32( tempUnicode.get(), history[ historyIndex ], bufferSize, ucharCount, errorCode );
- dynamicRefresh( dp, tempUnicode.get(), historyLineLength, historyLinePosition );
- }
- continue;
- break;
+ case ctrlChar('Z'): // ctrl-Z, job control
+ disableRawMode(); // Returning to Linux (whatever) shell, leave raw mode
+ raise(SIGSTOP); // Break out in mid-line
+ enableRawMode(); // Back from Linux shell, re-enter raw mode
+ {
+ bufferSize = historyLineLength + 1;
+ unique_ptr<UChar32[]> tempUnicode(new UChar32[bufferSize]);
+ copyString8to32(tempUnicode.get(),
+ history[historyIndex],
+ bufferSize,
+ ucharCount,
+ errorCode);
+ dynamicRefresh(dp, tempUnicode.get(), historyLineLength, historyLinePosition);
+ }
+ continue;
+ break;
#endif
- // these characters update the search string, and hence the selected input line
- case ctrlChar( 'H' ): // backspace/ctrl-H, delete char to left of cursor
- if ( dp.searchTextLen > 0 ) {
- unique_ptr<UChar32[]> tempUnicode( new UChar32[ dp.searchTextLen ] );
- --dp.searchTextLen;
- dp.searchText[ dp.searchTextLen ] = 0;
- copyString32( tempUnicode.get(), dp.searchText.get(), dp.searchTextLen + 1 );
- dp.updateSearchText( tempUnicode.get() );
- }
- else {
- beep();
- }
- break;
+ // these characters update the search string, and hence the selected input line
+ case ctrlChar('H'): // backspace/ctrl-H, delete char to left of cursor
+ if (dp.searchTextLen > 0) {
+ unique_ptr<UChar32[]> tempUnicode(new UChar32[dp.searchTextLen]);
+ --dp.searchTextLen;
+ dp.searchText[dp.searchTextLen] = 0;
+ copyString32(tempUnicode.get(), dp.searchText.get(), dp.searchTextLen + 1);
+ dp.updateSearchText(tempUnicode.get());
+ } else {
+ beep();
+ }
+ break;
- case ctrlChar( 'Y' ): // ctrl-Y, yank killed text
- break;
+ case ctrlChar('Y'): // ctrl-Y, yank killed text
+ break;
- default:
- if ( !isControlChar( c ) && c <= 0x0010FFFF ) { // not an action character
- unique_ptr< UChar32 []> tempUnicode( new UChar32[ dp.searchTextLen + 2 ] );
- copyString32( tempUnicode.get(), dp.searchText.get(), dp.searchTextLen + 2 );
- tempUnicode[ dp.searchTextLen ] = c;
- tempUnicode[ dp.searchTextLen + 1 ] = 0;
- dp.updateSearchText( tempUnicode.get() );
- }
- else {
- beep();
- }
- } // switch
+ default:
+ if (!isControlChar(c) && c <= 0x0010FFFF) { // not an action character
+ unique_ptr<UChar32[]> tempUnicode(new UChar32[dp.searchTextLen + 2]);
+ copyString32(tempUnicode.get(), dp.searchText.get(), dp.searchTextLen + 2);
+ tempUnicode[dp.searchTextLen] = c;
+ tempUnicode[dp.searchTextLen + 1] = 0;
+ dp.updateSearchText(tempUnicode.get());
+ } else {
+ beep();
+ }
+ } // switch
// if we are staying in search mode, search now
- if ( keepLooping ) {
+ if (keepLooping) {
bufferSize = historyLineLength + 1;
- activeHistoryLine = new UChar32[ bufferSize ];
- copyString8to32( activeHistoryLine, history[ historyIndex ], bufferSize, ucharCount, errorCode );
- if ( dp.searchTextLen > 0 ) {
+ activeHistoryLine = new UChar32[bufferSize];
+ copyString8to32(
+ activeHistoryLine, history[historyIndex], bufferSize, ucharCount, errorCode);
+ if (dp.searchTextLen > 0) {
bool found = false;
int historySearchIndex = historyIndex;
int lineLength = ucharCount;
int lineSearchPos = historyLinePosition;
- if ( searchAgain ) {
+ if (searchAgain) {
lineSearchPos += dp.direction;
}
searchAgain = false;
- while ( true ) {
- while ( ( dp.direction > 0 ) ? ( lineSearchPos < lineLength ) : ( lineSearchPos >= 0 ) ) {
- if ( strncmp32( dp.searchText.get(), &activeHistoryLine[ lineSearchPos ], dp.searchTextLen) == 0 ) {
+ while (true) {
+ while ((dp.direction > 0) ? (lineSearchPos < lineLength)
+ : (lineSearchPos >= 0)) {
+ if (strncmp32(dp.searchText.get(),
+ &activeHistoryLine[lineSearchPos],
+ dp.searchTextLen) == 0) {
found = true;
break;
}
lineSearchPos += dp.direction;
}
- if ( found ) {
+ if (found) {
historyIndex = historySearchIndex;
historyLineLength = lineLength;
historyLinePosition = lineSearchPos;
break;
- }
- else if ( ( dp.direction > 0 ) ? ( historySearchIndex < historyLen - 1 ) : ( historySearchIndex > 0 ) ) {
+ } else if ((dp.direction > 0) ? (historySearchIndex < historyLen - 1)
+ : (historySearchIndex > 0)) {
historySearchIndex += dp.direction;
- bufferSize = strlen( reinterpret_cast< char* >( history[ historySearchIndex ] ) ) + 1;
- delete [] activeHistoryLine;
- activeHistoryLine = new UChar32[ bufferSize ];
- copyString8to32( activeHistoryLine, history[ historySearchIndex ], bufferSize, ucharCount, errorCode );
+ bufferSize =
+ strlen(reinterpret_cast<char*>(history[historySearchIndex])) + 1;
+ delete[] activeHistoryLine;
+ activeHistoryLine = new UChar32[bufferSize];
+ copyString8to32(activeHistoryLine,
+ history[historySearchIndex],
+ bufferSize,
+ ucharCount,
+ errorCode);
lineLength = ucharCount;
- lineSearchPos = ( dp.direction > 0 ) ? 0 : ( lineLength - dp.searchTextLen );
- }
- else {
+ lineSearchPos = (dp.direction > 0) ? 0 : (lineLength - dp.searchTextLen);
+ } else {
beep();
break;
}
- }; // while
+ }; // while
}
- if ( activeHistoryLine ) {
- delete [] activeHistoryLine;
+ if (activeHistoryLine) {
+ delete[] activeHistoryLine;
}
bufferSize = historyLineLength + 1;
- activeHistoryLine = new UChar32[ bufferSize ];
- copyString8to32( activeHistoryLine, history[ historyIndex ], bufferSize, ucharCount, errorCode );
- dynamicRefresh( dp, activeHistoryLine, historyLineLength, historyLinePosition ); // draw user's text with our prompt
+ activeHistoryLine = new UChar32[bufferSize];
+ copyString8to32(
+ activeHistoryLine, history[historyIndex], bufferSize, ucharCount, errorCode);
+ dynamicRefresh(dp,
+ activeHistoryLine,
+ historyLineLength,
+ historyLinePosition); // draw user's text with our prompt
}
- } // while
+ } // while
// leaving history search, restore previous prompt, maybe make searched line current
PromptBase pb;
pb.promptChars = pi.promptIndentation;
- Utf32String tempUnicode( pb.promptChars + 1 );
- copyString32( tempUnicode.get(), &pi.promptText[ pi.promptLastLinePosition ], pb.promptChars + 1 );
+ Utf32String tempUnicode(pb.promptChars + 1);
+ copyString32(tempUnicode.get(), &pi.promptText[pi.promptLastLinePosition], pb.promptChars + 1);
tempUnicode.initFromBuffer();
pb.promptText = tempUnicode;
pb.promptExtraLines = 0;
@@ -1863,48 +1946,48 @@ int InputBuffer::incrementalHistorySearch( PromptBase& pi, int startChar ) {
pb.promptCursorRowOffset = dp.promptCursorRowOffset;
pb.promptScreenColumns = pi.promptScreenColumns;
pb.promptPreviousLen = dp.promptChars;
- if ( useSearchedLine && activeHistoryLine ) {
+ if (useSearchedLine && activeHistoryLine) {
historyRecallMostRecent = true;
- copyString32( buf32, activeHistoryLine, buflen + 1 );
+ copyString32(buf32, activeHistoryLine, buflen + 1);
len = historyLineLength;
pos = historyLinePosition;
}
- if ( activeHistoryLine ) {
- delete [] activeHistoryLine;
+ if (activeHistoryLine) {
+ delete[] activeHistoryLine;
}
- dynamicRefresh( pb, buf32, len, pos ); // redraw the original prompt with current input
+ dynamicRefresh(pb, buf32, len, pos); // redraw the original prompt with current input
pi.promptPreviousInputLen = len;
pi.promptCursorRowOffset = pi.promptExtraLines + pb.promptCursorRowOffset;
- previousSearchText = dp.searchText; // save search text for possible reuse on ctrl-R ctrl-R
- return c; // pass a character or -1 back to main loop
+ previousSearchText = dp.searchText; // save search text for possible reuse on ctrl-R ctrl-R
+ return c; // pass a character or -1 back to main loop
}
-static bool isCharacterAlphanumeric( UChar32 testChar ) {
- return iswalnum( testChar );
+static bool isCharacterAlphanumeric(UChar32 testChar) {
+ return iswalnum(testChar);
}
-int InputBuffer::getInputLine( PromptBase& pi ) {
-
+int InputBuffer::getInputLine(PromptBase& pi) {
// The latest history entry is always our current buffer
- if ( len > 0 ) {
- size_t bufferSize = sizeof( UChar32 ) * len + 1;
- unique_ptr< char []> tempBuffer( new char[ bufferSize ] );
- copyString32to8( reinterpret_cast< UChar8 * >( tempBuffer.get() ), buf32, bufferSize );
- linenoiseHistoryAdd( tempBuffer.get() );
- }
- else {
- linenoiseHistoryAdd( "" );
+ if (len > 0) {
+ size_t bufferSize = sizeof(UChar32) * len + 1;
+ unique_ptr<char[]> tempBuffer(new char[bufferSize]);
+ copyString32to8(reinterpret_cast<UChar8*>(tempBuffer.get()), buf32, bufferSize);
+ linenoiseHistoryAdd(tempBuffer.get());
+ } else {
+ linenoiseHistoryAdd("");
}
historyIndex = historyLen - 1;
historyRecallMostRecent = false;
// display the prompt
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return -1;
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return -1;
#ifndef _WIN32
// we have to generate our own newline on line wrap on Linux
- if ( pi.promptIndentation == 0 && pi.promptExtraLines > 0 )
- if ( write( 1, "\n", 1 ) == -1 ) return -1;
+ if (pi.promptIndentation == 0 && pi.promptExtraLines > 0)
+ if (write(1, "\n", 1) == -1)
+ return -1;
#endif
// the cursor starts out at the end of the prompt
@@ -1917,538 +2000,549 @@ int InputBuffer::getInputLine( PromptBase& pi ) {
int terminatingKeystroke = -1;
// if there is already text in the buffer, display it first
- if ( len > 0 ) {
- refreshLine( pi );
+ if (len > 0) {
+ refreshLine(pi);
}
// loop collecting characters, respond to line editing characters
- while ( true ) {
+ while (true) {
int c;
- if ( terminatingKeystroke == -1 ) {
- c = linenoiseReadChar(); // get a new keystroke
- }
- else {
+ if (terminatingKeystroke == -1) {
+ c = linenoiseReadChar(); // get a new keystroke
+ } else {
c = terminatingKeystroke; // use the terminating keystroke from search
terminatingKeystroke = -1; // clear it once we've used it
}
- c = cleanupCtrl( c ); // convert CTRL + <char> into normal ctrl
+ c = cleanupCtrl(c); // convert CTRL + <char> into normal ctrl
- if ( c == 0 ) {
+ if (c == 0) {
return len;
}
- if ( c == -1 ) {
- refreshLine( pi );
+ if (c == -1) {
+ refreshLine(pi);
continue;
}
- if ( c == -2 ) {
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return -1;
- refreshLine( pi );
+ if (c == -2) {
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return -1;
+ refreshLine(pi);
continue;
}
// ctrl-I/tab, command completion, needs to be before switch statement
- if ( c == ctrlChar( 'I' ) && completionCallback ) {
-
- if ( pos == 0 ) // SERVER-4967 -- in earlier versions, you could paste previous output
- continue; // back into the shell ... this output may have leading tabs.
- // This hack (i.e. what the old code did) prevents command completion
- // on an empty line but lets users paste text with leading tabs.
+ if (c == ctrlChar('I') && completionCallback) {
+ if (pos == 0) // SERVER-4967 -- in earlier versions, you could paste previous output
+ continue; // back into the shell ... this output may have leading tabs.
+ // This hack (i.e. what the old code did) prevents command completion
+ // on an empty line but lets users paste text with leading tabs.
killRing.lastAction = KillRing::actionOther;
historyRecallMostRecent = false;
// completeLine does the actual completion and replacement
- c = completeLine( pi );
+ c = completeLine(pi);
- if ( c < 0 ) // return on error
+ if (c < 0) // return on error
return len;
- if ( c == 0 ) // read next character when 0
+ if (c == 0) // read next character when 0
continue;
// deliberate fall-through here, so we use the terminating character
}
- switch ( c ) {
-
- case ctrlChar( 'A' ): // ctrl-A, move cursor to start of line
- case HOME_KEY:
- killRing.lastAction = KillRing::actionOther;
- pos = 0;
- refreshLine( pi );
- break;
-
- case ctrlChar( 'B' ): // ctrl-B, move cursor left by one character
- case LEFT_ARROW_KEY:
- killRing.lastAction = KillRing::actionOther;
- if ( pos > 0 ) {
- --pos;
- refreshLine( pi );
- }
- break;
+ switch (c) {
+ case ctrlChar('A'): // ctrl-A, move cursor to start of line
+ case HOME_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ pos = 0;
+ refreshLine(pi);
+ break;
- case META + 'b': // meta-B, move cursor left by one word
- case META + 'B':
- case CTRL + LEFT_ARROW_KEY:
- case META + LEFT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
- killRing.lastAction = KillRing::actionOther;
- if ( pos > 0 ) {
- while ( pos > 0 && !isCharacterAlphanumeric( buf32[pos - 1] ) ) {
- --pos;
- }
- while ( pos > 0 && isCharacterAlphanumeric( buf32[pos - 1] ) ) {
+ case ctrlChar('B'): // ctrl-B, move cursor left by one character
+ case LEFT_ARROW_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ if (pos > 0) {
--pos;
+ refreshLine(pi);
}
- refreshLine( pi );
- }
- break;
-
- case ctrlChar( 'C' ): // ctrl-C, abort this line
- killRing.lastAction = KillRing::actionOther;
- historyRecallMostRecent = false;
- errno = EAGAIN;
- --historyLen;
- free( history[historyLen] );
- // we need one last refresh with the cursor at the end of the line
- // so we don't display the next prompt over the previous input line
- pos = len; // pass len as pos for EOL
- refreshLine( pi );
- if ( write( 1, "^C", 2 ) == -1 ) return -1; // Display the ^C we got
- return -1;
+ break;
- case META + 'c': // meta-C, give word initial Cap
- case META + 'C':
- killRing.lastAction = KillRing::actionOther;
- historyRecallMostRecent = false;
- if ( pos < len ) {
- while ( pos < len && !isCharacterAlphanumeric( buf32[pos] ) ) {
- ++pos;
- }
- if ( pos < len && isCharacterAlphanumeric( buf32[pos] ) ) {
- if ( buf32[pos] >= 'a' && buf32[pos] <= 'z' ) {
- buf32[pos] += 'A' - 'a';
+ case META + 'b': // meta-B, move cursor left by one word
+ case META + 'B':
+ case CTRL + LEFT_ARROW_KEY:
+ case META + LEFT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
+ killRing.lastAction = KillRing::actionOther;
+ if (pos > 0) {
+ while (pos > 0 && !isCharacterAlphanumeric(buf32[pos - 1])) {
+ --pos;
}
- ++pos;
- }
- while ( pos < len && isCharacterAlphanumeric( buf32[pos] ) ) {
- if ( buf32[pos] >= 'A' && buf32[pos] <= 'Z' ) {
- buf32[pos] += 'a' - 'A';
+ while (pos > 0 && isCharacterAlphanumeric(buf32[pos - 1])) {
+ --pos;
}
- ++pos;
+ refreshLine(pi);
}
- refreshLine( pi );
- }
- break;
+ break;
- // ctrl-D, delete the character under the cursor
- // on an empty line, exit the shell
- case ctrlChar( 'D' ):
- killRing.lastAction = KillRing::actionOther;
- if ( len > 0 && pos < len ) {
+ case ctrlChar('C'): // ctrl-C, abort this line
+ killRing.lastAction = KillRing::actionOther;
historyRecallMostRecent = false;
- memmove( buf32 + pos, buf32 + pos + 1, sizeof( UChar32 ) * ( len - pos ) );
- --len;
- refreshLine( pi );
- }
- else if ( len == 0 ) {
+ errno = EAGAIN;
--historyLen;
- free( history[historyLen] );
+ free(history[historyLen]);
+ // we need one last refresh with the cursor at the end of the line
+ // so we don't display the next prompt over the previous input line
+ pos = len; // pass len as pos for EOL
+ refreshLine(pi);
+ if (write(1, "^C", 2) == -1)
+ return -1; // Display the ^C we got
return -1;
- }
- break;
- case META + 'd': // meta-D, kill word to right of cursor
- case META + 'D':
- if ( pos < len ) {
+ case META + 'c': // meta-C, give word initial Cap
+ case META + 'C':
+ killRing.lastAction = KillRing::actionOther;
historyRecallMostRecent = false;
- int endingPos = pos;
- while ( endingPos < len && !isCharacterAlphanumeric( buf32[endingPos] ) ) {
- ++endingPos;
+ if (pos < len) {
+ while (pos < len && !isCharacterAlphanumeric(buf32[pos])) {
+ ++pos;
+ }
+ if (pos < len && isCharacterAlphanumeric(buf32[pos])) {
+ if (buf32[pos] >= 'a' && buf32[pos] <= 'z') {
+ buf32[pos] += 'A' - 'a';
+ }
+ ++pos;
+ }
+ while (pos < len && isCharacterAlphanumeric(buf32[pos])) {
+ if (buf32[pos] >= 'A' && buf32[pos] <= 'Z') {
+ buf32[pos] += 'a' - 'A';
+ }
+ ++pos;
+ }
+ refreshLine(pi);
}
- while ( endingPos < len && isCharacterAlphanumeric( buf32[endingPos] ) ) {
- ++endingPos;
+ break;
+
+ // ctrl-D, delete the character under the cursor
+ // on an empty line, exit the shell
+ case ctrlChar('D'):
+ killRing.lastAction = KillRing::actionOther;
+ if (len > 0 && pos < len) {
+ historyRecallMostRecent = false;
+ memmove(buf32 + pos, buf32 + pos + 1, sizeof(UChar32) * (len - pos));
+ --len;
+ refreshLine(pi);
+ } else if (len == 0) {
+ --historyLen;
+ free(history[historyLen]);
+ return -1;
}
- killRing.kill( &buf32[pos], endingPos - pos, true );
- memmove( buf32 + pos, buf32 + endingPos, sizeof( UChar32 ) * ( len - endingPos + 1 ) );
- len -= endingPos - pos;
- refreshLine( pi );
- }
- killRing.lastAction = KillRing::actionKill;
- break;
+ break;
- case ctrlChar( 'E' ): // ctrl-E, move cursor to end of line
- case END_KEY:
- killRing.lastAction = KillRing::actionOther;
- pos = len;
- refreshLine( pi );
- break;
+ case META + 'd': // meta-D, kill word to right of cursor
+ case META + 'D':
+ if (pos < len) {
+ historyRecallMostRecent = false;
+ int endingPos = pos;
+ while (endingPos < len && !isCharacterAlphanumeric(buf32[endingPos])) {
+ ++endingPos;
+ }
+ while (endingPos < len && isCharacterAlphanumeric(buf32[endingPos])) {
+ ++endingPos;
+ }
+ killRing.kill(&buf32[pos], endingPos - pos, true);
+ memmove(
+ buf32 + pos, buf32 + endingPos, sizeof(UChar32) * (len - endingPos + 1));
+ len -= endingPos - pos;
+ refreshLine(pi);
+ }
+ killRing.lastAction = KillRing::actionKill;
+ break;
- case ctrlChar( 'F' ): // ctrl-F, move cursor right by one character
- case RIGHT_ARROW_KEY:
- killRing.lastAction = KillRing::actionOther;
- if ( pos < len ) {
- ++pos;
- refreshLine( pi );
- }
- break;
+ case ctrlChar('E'): // ctrl-E, move cursor to end of line
+ case END_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ pos = len;
+ refreshLine(pi);
+ break;
- case META + 'f': // meta-F, move cursor right by one word
- case META + 'F':
- case CTRL + RIGHT_ARROW_KEY:
- case META + RIGHT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
- killRing.lastAction = KillRing::actionOther;
- if ( pos < len ) {
- while ( pos < len && !isCharacterAlphanumeric( buf32[pos] ) ) {
+ case ctrlChar('F'): // ctrl-F, move cursor right by one character
+ case RIGHT_ARROW_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ if (pos < len) {
++pos;
+ refreshLine(pi);
}
- while ( pos < len && isCharacterAlphanumeric( buf32[pos] ) ) {
- ++pos;
- }
- refreshLine( pi );
- }
- break;
+ break;
- case ctrlChar( 'H' ): // backspace/ctrl-H, delete char to left of cursor
- killRing.lastAction = KillRing::actionOther;
- if ( pos > 0 ) {
- historyRecallMostRecent = false;
- memmove( buf32 + pos - 1, buf32 + pos, sizeof( UChar32 ) * ( 1 + len - pos ) );
- --pos;
- --len;
- refreshLine( pi );
- }
- break;
+ case META + 'f': // meta-F, move cursor right by one word
+ case META + 'F':
+ case CTRL + RIGHT_ARROW_KEY:
+ case META + RIGHT_ARROW_KEY: // Emacs allows Meta, bash & readline don't
+ killRing.lastAction = KillRing::actionOther;
+ if (pos < len) {
+ while (pos < len && !isCharacterAlphanumeric(buf32[pos])) {
+ ++pos;
+ }
+ while (pos < len && isCharacterAlphanumeric(buf32[pos])) {
+ ++pos;
+ }
+ refreshLine(pi);
+ }
+ break;
- // meta-Backspace, kill word to left of cursor
- case META + ctrlChar( 'H' ):
- if ( pos > 0 ) {
- historyRecallMostRecent = false;
- int startingPos = pos;
- while ( pos > 0 && !isCharacterAlphanumeric( buf32[pos - 1] ) ) {
+ case ctrlChar('H'): // backspace/ctrl-H, delete char to left of cursor
+ killRing.lastAction = KillRing::actionOther;
+ if (pos > 0) {
+ historyRecallMostRecent = false;
+ memmove(buf32 + pos - 1, buf32 + pos, sizeof(UChar32) * (1 + len - pos));
--pos;
+ --len;
+ refreshLine(pi);
}
- while ( pos > 0 && isCharacterAlphanumeric( buf32[pos - 1] ) ) {
- --pos;
+ break;
+
+ // meta-Backspace, kill word to left of cursor
+ case META + ctrlChar('H'):
+ if (pos > 0) {
+ historyRecallMostRecent = false;
+ int startingPos = pos;
+ while (pos > 0 && !isCharacterAlphanumeric(buf32[pos - 1])) {
+ --pos;
+ }
+ while (pos > 0 && isCharacterAlphanumeric(buf32[pos - 1])) {
+ --pos;
+ }
+ killRing.kill(&buf32[pos], startingPos - pos, false);
+ memmove(buf32 + pos,
+ buf32 + startingPos,
+ sizeof(UChar32) * (len - startingPos + 1));
+ len -= startingPos - pos;
+ refreshLine(pi);
}
- killRing.kill( &buf32[pos], startingPos - pos, false );
- memmove( buf32 + pos, buf32 + startingPos, sizeof( UChar32 ) * ( len - startingPos + 1 ) );
- len -= startingPos - pos;
- refreshLine( pi );
- }
- killRing.lastAction = KillRing::actionKill;
- break;
+ killRing.lastAction = KillRing::actionKill;
+ break;
- case ctrlChar( 'J' ): // ctrl-J/linefeed/newline, accept line
- case ctrlChar( 'M' ): // ctrl-M/return/enter
- killRing.lastAction = KillRing::actionOther;
- // we need one last refresh with the cursor at the end of the line
- // so we don't display the next prompt over the previous input line
- pos = len; // pass len as pos for EOL
- refreshLine( pi );
- historyPreviousIndex = historyRecallMostRecent ? historyIndex : -2;
- --historyLen;
- free( history[historyLen] );
- return len;
+ case ctrlChar('J'): // ctrl-J/linefeed/newline, accept line
+ case ctrlChar('M'): // ctrl-M/return/enter
+ killRing.lastAction = KillRing::actionOther;
+ // we need one last refresh with the cursor at the end of the line
+ // so we don't display the next prompt over the previous input line
+ pos = len; // pass len as pos for EOL
+ refreshLine(pi);
+ historyPreviousIndex = historyRecallMostRecent ? historyIndex : -2;
+ --historyLen;
+ free(history[historyLen]);
+ return len;
- case ctrlChar( 'K' ): // ctrl-K, kill from cursor to end of line
- killRing.kill( &buf32[pos], len - pos, true );
- buf32[pos] = '\0';
- len = pos;
- refreshLine( pi );
- killRing.lastAction = KillRing::actionKill;
- historyRecallMostRecent = false;
- break;
+ case ctrlChar('K'): // ctrl-K, kill from cursor to end of line
+ killRing.kill(&buf32[pos], len - pos, true);
+ buf32[pos] = '\0';
+ len = pos;
+ refreshLine(pi);
+ killRing.lastAction = KillRing::actionKill;
+ historyRecallMostRecent = false;
+ break;
- case ctrlChar( 'L' ): // ctrl-L, clear screen and redisplay line
- clearScreen( pi );
- break;
+ case ctrlChar('L'): // ctrl-L, clear screen and redisplay line
+ clearScreen(pi);
+ break;
- case META + 'l': // meta-L, lowercase word
- case META + 'L':
- killRing.lastAction = KillRing::actionOther;
- if ( pos < len ) {
- historyRecallMostRecent = false;
- while ( pos < len && !isCharacterAlphanumeric( buf32[pos] ) ) {
- ++pos;
- }
- while ( pos < len && isCharacterAlphanumeric( buf32[pos] ) ) {
- if ( buf32[pos] >= 'A' && buf32[pos] <= 'Z' ) {
- buf32[pos] += 'a' - 'A';
+ case META + 'l': // meta-L, lowercase word
+ case META + 'L':
+ killRing.lastAction = KillRing::actionOther;
+ if (pos < len) {
+ historyRecallMostRecent = false;
+ while (pos < len && !isCharacterAlphanumeric(buf32[pos])) {
+ ++pos;
}
- ++pos;
+ while (pos < len && isCharacterAlphanumeric(buf32[pos])) {
+ if (buf32[pos] >= 'A' && buf32[pos] <= 'Z') {
+ buf32[pos] += 'a' - 'A';
+ }
+ ++pos;
+ }
+ refreshLine(pi);
}
- refreshLine( pi );
- }
- break;
+ break;
- case ctrlChar( 'N' ): // ctrl-N, recall next line in history
- case ctrlChar( 'P' ): // ctrl-P, recall previous line in history
- case DOWN_ARROW_KEY:
- case UP_ARROW_KEY:
- killRing.lastAction = KillRing::actionOther;
- // if not already recalling, add the current line to the history list so we don't have to special case it
- if ( historyIndex == historyLen - 1 ) {
- free( history[historyLen - 1] );
- size_t tempBufferSize = sizeof( UChar32 ) * len + 1;
- unique_ptr< UChar8 []> tempBuffer( new UChar8[ tempBufferSize ] );
- copyString32to8( tempBuffer.get(), buf32, tempBufferSize );
- history[historyLen - 1] = reinterpret_cast< UChar8 * >( strdup( reinterpret_cast< const char * >( tempBuffer.get() ) ) );
- }
- if ( historyLen > 1 ) {
- if ( c == UP_ARROW_KEY ) {
- c = ctrlChar( 'P' );
- }
- if ( historyPreviousIndex != -2 && c != ctrlChar( 'P' ) ) {
- historyIndex = 1 + historyPreviousIndex; // emulate Windows down-arrow
- }
- else {
- historyIndex += ( c == ctrlChar( 'P' ) ) ? -1 : 1;
- }
- historyPreviousIndex = -2;
- if ( historyIndex < 0 ) {
- historyIndex = 0;
- break;
+ case ctrlChar('N'): // ctrl-N, recall next line in history
+ case ctrlChar('P'): // ctrl-P, recall previous line in history
+ case DOWN_ARROW_KEY:
+ case UP_ARROW_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ // if not already recalling, add the current line to the history list so we don't have to special case it
+ if (historyIndex == historyLen - 1) {
+ free(history[historyLen - 1]);
+ size_t tempBufferSize = sizeof(UChar32) * len + 1;
+ unique_ptr<UChar8[]> tempBuffer(new UChar8[tempBufferSize]);
+ copyString32to8(tempBuffer.get(), buf32, tempBufferSize);
+ history[historyLen - 1] = reinterpret_cast<UChar8*>(
+ strdup(reinterpret_cast<const char*>(tempBuffer.get())));
}
- else if ( historyIndex >= historyLen ) {
- historyIndex = historyLen - 1;
- break;
+ if (historyLen > 1) {
+ if (c == UP_ARROW_KEY) {
+ c = ctrlChar('P');
+ }
+ if (historyPreviousIndex != -2 && c != ctrlChar('P')) {
+ historyIndex = 1 + historyPreviousIndex; // emulate Windows down-arrow
+ } else {
+ historyIndex += (c == ctrlChar('P')) ? -1 : 1;
+ }
+ historyPreviousIndex = -2;
+ if (historyIndex < 0) {
+ historyIndex = 0;
+ break;
+ } else if (historyIndex >= historyLen) {
+ historyIndex = historyLen - 1;
+ break;
+ }
+ historyRecallMostRecent = true;
+ size_t ucharCount;
+ int errorCode;
+ copyString8to32(buf32, history[historyIndex], buflen, ucharCount, errorCode);
+ len = pos = ucharCount;
+ refreshLine(pi);
}
- historyRecallMostRecent = true;
- size_t ucharCount;
- int errorCode;
- copyString8to32( buf32, history[historyIndex], buflen, ucharCount, errorCode );
- len = pos = ucharCount;
- refreshLine( pi );
- }
- break;
-
- case ctrlChar( 'R' ): // ctrl-R, reverse history search
- case ctrlChar( 'S' ): // ctrl-S, forward history search
- terminatingKeystroke = incrementalHistorySearch( pi, c );
- break;
-
- case ctrlChar( 'T' ): // ctrl-T, transpose characters
- killRing.lastAction = KillRing::actionOther;
- if ( pos > 0 && len > 1 ) {
- historyRecallMostRecent = false;
- size_t leftCharPos = ( pos == len ) ? pos - 2 : pos - 1;
- char aux = buf32[leftCharPos];
- buf32[leftCharPos] = buf32[leftCharPos+1];
- buf32[leftCharPos+1] = aux;
- if ( pos != len )
- ++pos;
- refreshLine( pi );
- }
- break;
+ break;
- case ctrlChar( 'U' ): // ctrl-U, kill all characters to the left of the cursor
- if ( pos > 0 ) {
- historyRecallMostRecent = false;
- killRing.kill( &buf32[0], pos, false );
- len -= pos;
- memmove( buf32, buf32 + pos, sizeof( UChar32 ) * ( len + 1 ) );
- pos = 0;
- refreshLine( pi );
- }
- killRing.lastAction = KillRing::actionKill;
- break;
+ case ctrlChar('R'): // ctrl-R, reverse history search
+ case ctrlChar('S'): // ctrl-S, forward history search
+ terminatingKeystroke = incrementalHistorySearch(pi, c);
+ break;
- case META + 'u': // meta-U, uppercase word
- case META + 'U':
- killRing.lastAction = KillRing::actionOther;
- if ( pos < len ) {
- historyRecallMostRecent = false;
- while ( pos < len && !isCharacterAlphanumeric( buf32[pos] ) ) {
- ++pos;
- }
- while ( pos < len && isCharacterAlphanumeric( buf32[pos] ) ) {
- if ( buf32[pos] >= 'a' && buf32[pos] <= 'z' ) {
- buf32[pos] += 'A' - 'a';
- }
- ++pos;
+ case ctrlChar('T'): // ctrl-T, transpose characters
+ killRing.lastAction = KillRing::actionOther;
+ if (pos > 0 && len > 1) {
+ historyRecallMostRecent = false;
+ size_t leftCharPos = (pos == len) ? pos - 2 : pos - 1;
+ char aux = buf32[leftCharPos];
+ buf32[leftCharPos] = buf32[leftCharPos + 1];
+ buf32[leftCharPos + 1] = aux;
+ if (pos != len)
+ ++pos;
+ refreshLine(pi);
}
- refreshLine( pi );
- }
- break;
+ break;
- // ctrl-W, kill to whitespace (not word) to left of cursor
- case ctrlChar( 'W' ):
- if ( pos > 0 ) {
- historyRecallMostRecent = false;
- int startingPos = pos;
- while ( pos > 0 && buf32[pos - 1] == ' ' ) {
- --pos;
- }
- while ( pos > 0 && buf32[pos - 1] != ' ' ) {
- --pos;
+ case ctrlChar('U'): // ctrl-U, kill all characters to the left of the cursor
+ if (pos > 0) {
+ historyRecallMostRecent = false;
+ killRing.kill(&buf32[0], pos, false);
+ len -= pos;
+ memmove(buf32, buf32 + pos, sizeof(UChar32) * (len + 1));
+ pos = 0;
+ refreshLine(pi);
}
- killRing.kill( &buf32[pos], startingPos - pos, false );
- memmove( buf32 + pos, buf32 + startingPos, sizeof( UChar32 ) * ( len - startingPos + 1 ) );
- len -= startingPos - pos;
- refreshLine( pi );
- }
- killRing.lastAction = KillRing::actionKill;
- break;
+ killRing.lastAction = KillRing::actionKill;
+ break;
- case ctrlChar( 'Y' ): // ctrl-Y, yank killed text
- historyRecallMostRecent = false;
- {
- Utf32String* restoredText = killRing.yank();
- if ( restoredText ) {
- bool truncated = false;
- size_t ucharCount = restoredText->length();
- if (ucharCount > static_cast<size_t>(buflen - len)) {
- ucharCount = buflen - len;
- truncated = true;
+ case META + 'u': // meta-U, uppercase word
+ case META + 'U':
+ killRing.lastAction = KillRing::actionOther;
+ if (pos < len) {
+ historyRecallMostRecent = false;
+ while (pos < len && !isCharacterAlphanumeric(buf32[pos])) {
+ ++pos;
}
- memmove( buf32 + pos + ucharCount, buf32 + pos, sizeof( UChar32 ) * ( len - pos + 1 ) );
- memmove( buf32 + pos, restoredText->get(), sizeof( UChar32 ) * ucharCount );
- pos += ucharCount;
- len += ucharCount;
- refreshLine( pi );
- killRing.lastAction = KillRing::actionYank;
- killRing.lastYankSize = ucharCount;
- if (truncated) {
- beep();
+ while (pos < len && isCharacterAlphanumeric(buf32[pos])) {
+ if (buf32[pos] >= 'a' && buf32[pos] <= 'z') {
+ buf32[pos] += 'A' - 'a';
+ }
+ ++pos;
}
+ refreshLine(pi);
}
- else {
- beep();
- }
- }
- break;
+ break;
- case META + 'y': // meta-Y, "yank-pop", rotate popped text
- case META + 'Y':
- if ( killRing.lastAction == KillRing::actionYank ) {
- historyRecallMostRecent = false;
- Utf32String* restoredText = killRing.yankPop();
- if ( restoredText ) {
- bool truncated = false;
- size_t ucharCount = restoredText->length();
- if (ucharCount > static_cast<size_t>(killRing.lastYankSize + buflen - len)) {
- ucharCount = killRing.lastYankSize + buflen - len;
- truncated = true;
- }
- if ( ucharCount > killRing.lastYankSize ) {
- memmove( buf32 + pos + ucharCount - killRing.lastYankSize, buf32 + pos, sizeof( UChar32 ) * ( len - pos + 1 ) );
- memmove( buf32 + pos - killRing.lastYankSize, restoredText->get(), sizeof( UChar32 ) * ucharCount );
+ // ctrl-W, kill to whitespace (not word) to left of cursor
+ case ctrlChar('W'):
+ if (pos > 0) {
+ historyRecallMostRecent = false;
+ int startingPos = pos;
+ while (pos > 0 && buf32[pos - 1] == ' ') {
+ --pos;
}
- else {
- memmove( buf32 + pos - killRing.lastYankSize, restoredText->get(), sizeof( UChar32 ) * ucharCount );
- memmove( buf32 + pos + ucharCount - killRing.lastYankSize, buf32 + pos, sizeof( UChar32 ) * ( len - pos + 1 ) );
+ while (pos > 0 && buf32[pos - 1] != ' ') {
+ --pos;
}
- pos += ucharCount - killRing.lastYankSize;
- len += ucharCount - killRing.lastYankSize;
- killRing.lastYankSize = ucharCount;
- refreshLine( pi );
- if (truncated) {
+ killRing.kill(&buf32[pos], startingPos - pos, false);
+ memmove(buf32 + pos,
+ buf32 + startingPos,
+ sizeof(UChar32) * (len - startingPos + 1));
+ len -= startingPos - pos;
+ refreshLine(pi);
+ }
+ killRing.lastAction = KillRing::actionKill;
+ break;
+
+ case ctrlChar('Y'): // ctrl-Y, yank killed text
+ historyRecallMostRecent = false;
+ {
+ Utf32String* restoredText = killRing.yank();
+ if (restoredText) {
+ bool truncated = false;
+ size_t ucharCount = restoredText->length();
+ if (ucharCount > static_cast<size_t>(buflen - len)) {
+ ucharCount = buflen - len;
+ truncated = true;
+ }
+ memmove(buf32 + pos + ucharCount,
+ buf32 + pos,
+ sizeof(UChar32) * (len - pos + 1));
+ memmove(buf32 + pos, restoredText->get(), sizeof(UChar32) * ucharCount);
+ pos += ucharCount;
+ len += ucharCount;
+ refreshLine(pi);
+ killRing.lastAction = KillRing::actionYank;
+ killRing.lastYankSize = ucharCount;
+ if (truncated) {
+ beep();
+ }
+ } else {
beep();
}
- break;
}
- }
- beep();
- break;
+ break;
+
+ case META + 'y': // meta-Y, "yank-pop", rotate popped text
+ case META + 'Y':
+ if (killRing.lastAction == KillRing::actionYank) {
+ historyRecallMostRecent = false;
+ Utf32String* restoredText = killRing.yankPop();
+ if (restoredText) {
+ bool truncated = false;
+ size_t ucharCount = restoredText->length();
+ if (ucharCount >
+ static_cast<size_t>(killRing.lastYankSize + buflen - len)) {
+ ucharCount = killRing.lastYankSize + buflen - len;
+ truncated = true;
+ }
+ if (ucharCount > killRing.lastYankSize) {
+ memmove(buf32 + pos + ucharCount - killRing.lastYankSize,
+ buf32 + pos,
+ sizeof(UChar32) * (len - pos + 1));
+ memmove(buf32 + pos - killRing.lastYankSize,
+ restoredText->get(),
+ sizeof(UChar32) * ucharCount);
+ } else {
+ memmove(buf32 + pos - killRing.lastYankSize,
+ restoredText->get(),
+ sizeof(UChar32) * ucharCount);
+ memmove(buf32 + pos + ucharCount - killRing.lastYankSize,
+ buf32 + pos,
+ sizeof(UChar32) * (len - pos + 1));
+ }
+ pos += ucharCount - killRing.lastYankSize;
+ len += ucharCount - killRing.lastYankSize;
+ killRing.lastYankSize = ucharCount;
+ refreshLine(pi);
+ if (truncated) {
+ beep();
+ }
+ break;
+ }
+ }
+ beep();
+ break;
#ifndef _WIN32
- case ctrlChar( 'Z' ): // ctrl-Z, job control
- disableRawMode(); // Returning to Linux (whatever) shell, leave raw mode
- raise( SIGSTOP ); // Break out in mid-line
- enableRawMode(); // Back from Linux shell, re-enter raw mode
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) break; // Redraw prompt
- refreshLine( pi ); // Refresh the line
- break;
+ case ctrlChar('Z'): // ctrl-Z, job control
+ disableRawMode(); // Returning to Linux (whatever) shell, leave raw mode
+ raise(SIGSTOP); // Break out in mid-line
+ enableRawMode(); // Back from Linux shell, re-enter raw mode
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ break; // Redraw prompt
+ refreshLine(pi); // Refresh the line
+ break;
#endif
- // DEL, delete the character under the cursor
- case 127:
- case DELETE_KEY:
- killRing.lastAction = KillRing::actionOther;
- if ( len > 0 && pos < len ) {
- historyRecallMostRecent = false;
- memmove( buf32 + pos, buf32 + pos + 1, sizeof( UChar32 ) * ( len - pos ) );
- --len;
- refreshLine( pi );
- }
- break;
-
- case META + '<': // meta-<, beginning of history
- case PAGE_UP_KEY: // Page Up, beginning of history
- case META + '>': // meta->, end of history
- case PAGE_DOWN_KEY: // Page Down, end of history
- killRing.lastAction = KillRing::actionOther;
- // if not already recalling, add the current line to the history list so we don't have to special case it
- if ( historyIndex == historyLen - 1 ) {
- free( history[historyLen - 1] );
- size_t tempBufferSize = sizeof( UChar32 ) * len + 1;
- unique_ptr< UChar8 []> tempBuffer( new UChar8[ tempBufferSize ] );
- copyString32to8( tempBuffer.get(), buf32, tempBufferSize );
- history[historyLen - 1] = reinterpret_cast< UChar8 * >( strdup( reinterpret_cast< const char * >( tempBuffer.get() ) ) );
- }
- if ( historyLen > 1 ) {
- historyIndex = ( c == META + '<' || c == PAGE_UP_KEY ) ? 0 : historyLen - 1;
- historyPreviousIndex = -2;
- historyRecallMostRecent = true;
- size_t ucharCount;
- int errorCode;
- copyString8to32( buf32, history[historyIndex], buflen, ucharCount, errorCode );
- len = pos = ucharCount;
- refreshLine( pi );
- }
- break;
+ // DEL, delete the character under the cursor
+ case 127:
+ case DELETE_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ if (len > 0 && pos < len) {
+ historyRecallMostRecent = false;
+ memmove(buf32 + pos, buf32 + pos + 1, sizeof(UChar32) * (len - pos));
+ --len;
+ refreshLine(pi);
+ }
+ break;
- // not one of our special characters, maybe insert it in the buffer
- default:
- killRing.lastAction = KillRing::actionOther;
- historyRecallMostRecent = false;
- if ( c & ( META | CTRL ) ) { // beep on unknown Ctrl and/or Meta keys
- beep();
+ case META + '<': // meta-<, beginning of history
+ case PAGE_UP_KEY: // Page Up, beginning of history
+ case META + '>': // meta->, end of history
+ case PAGE_DOWN_KEY: // Page Down, end of history
+ killRing.lastAction = KillRing::actionOther;
+ // if not already recalling, add the current line to the history list so we don't have to special case it
+ if (historyIndex == historyLen - 1) {
+ free(history[historyLen - 1]);
+ size_t tempBufferSize = sizeof(UChar32) * len + 1;
+ unique_ptr<UChar8[]> tempBuffer(new UChar8[tempBufferSize]);
+ copyString32to8(tempBuffer.get(), buf32, tempBufferSize);
+ history[historyLen - 1] = reinterpret_cast<UChar8*>(
+ strdup(reinterpret_cast<const char*>(tempBuffer.get())));
+ }
+ if (historyLen > 1) {
+ historyIndex = (c == META + '<' || c == PAGE_UP_KEY) ? 0 : historyLen - 1;
+ historyPreviousIndex = -2;
+ historyRecallMostRecent = true;
+ size_t ucharCount;
+ int errorCode;
+ copyString8to32(buf32, history[historyIndex], buflen, ucharCount, errorCode);
+ len = pos = ucharCount;
+ refreshLine(pi);
+ }
break;
- }
- if ( len < buflen ) {
- if ( isControlChar( c ) ) { // don't insert control characters
+
+ // not one of our special characters, maybe insert it in the buffer
+ default:
+ killRing.lastAction = KillRing::actionOther;
+ historyRecallMostRecent = false;
+ if (c & (META | CTRL)) { // beep on unknown Ctrl and/or Meta keys
beep();
break;
}
- if ( len == pos ) { // at end of buffer
- buf32[pos] = c;
- ++pos;
- ++len;
- buf32[len] = '\0';
- int inputLen = calculateColumnPosition( buf32, len );
- if ( pi.promptIndentation + inputLen < pi.promptScreenColumns ) {
- if ( inputLen > pi.promptPreviousInputLen )
- pi.promptPreviousInputLen = inputLen;
- /* Avoid a full update of the line in the
- * trivial case. */
- if ( write32( 1, reinterpret_cast<UChar32 *>( &c ), 1) == -1 ) return -1;
+ if (len < buflen) {
+ if (isControlChar(c)) { // don't insert control characters
+ beep();
+ break;
}
- else {
- refreshLine( pi );
+ if (len == pos) { // at end of buffer
+ buf32[pos] = c;
+ ++pos;
+ ++len;
+ buf32[len] = '\0';
+ int inputLen = calculateColumnPosition(buf32, len);
+ if (pi.promptIndentation + inputLen < pi.promptScreenColumns) {
+ if (inputLen > pi.promptPreviousInputLen)
+ pi.promptPreviousInputLen = inputLen;
+ /* Avoid a full update of the line in the
+ * trivial case. */
+ if (write32(1, reinterpret_cast<UChar32*>(&c), 1) == -1)
+ return -1;
+ } else {
+ refreshLine(pi);
+ }
+ } else { // not at end of buffer, have to move characters to our right
+ memmove(buf32 + pos + 1, buf32 + pos, sizeof(UChar32) * (len - pos));
+ buf32[pos] = c;
+ ++len;
+ ++pos;
+ buf32[len] = '\0';
+ refreshLine(pi);
}
+ } else {
+ beep(); // buffer is full, beep on new characters
}
- else { // not at end of buffer, have to move characters to our right
- memmove( buf32 + pos + 1, buf32 + pos, sizeof( UChar32 ) * ( len - pos ) );
- buf32[pos] = c;
- ++len;
- ++pos;
- buf32[len] = '\0';
- refreshLine( pi );
- }
- }
- else {
- beep(); // buffer is full, beep on new characters
- }
- break;
+ break;
}
}
return len;
}
-string preloadedBufferContents; // used with linenoisePreloadBuffer
+string preloadedBufferContents; // used with linenoisePreloadBuffer
string preloadErrorMessage;
/**
@@ -2459,35 +2553,34 @@ string preloadErrorMessage;
*
* @param preloadText text to begin with on the next call to linenoise()
*/
-void linenoisePreloadBuffer( const char* preloadText ) {
-
- if ( ! preloadText ) {
+void linenoisePreloadBuffer(const char* preloadText) {
+ if (!preloadText) {
return;
}
- int bufferSize = strlen( preloadText ) + 1;
- unique_ptr< char []> tempBuffer( new char[ bufferSize ] );
- strncpy( &tempBuffer[0], preloadText, bufferSize );
+ int bufferSize = strlen(preloadText) + 1;
+ unique_ptr<char[]> tempBuffer(new char[bufferSize]);
+ strncpy(&tempBuffer[0], preloadText, bufferSize);
// remove characters that won't display correctly
char* pIn = &tempBuffer[0];
char* pOut = pIn;
bool controlsStripped = false;
bool whitespaceSeen = false;
- while ( *pIn ) {
- unsigned char c = *pIn++; // we need unsigned so chars 0x80 and above are allowed
- if ( '\r' == c ) { // silently skip CR
+ while (*pIn) {
+ unsigned char c = *pIn++; // we need unsigned so chars 0x80 and above are allowed
+ if ('\r' == c) { // silently skip CR
continue;
}
- if ( '\n' == c || '\t' == c ) { // note newline or tab
+ if ('\n' == c || '\t' == c) { // note newline or tab
whitespaceSeen = true;
continue;
}
- if ( isControlChar( c ) ) { // remove other control characters, flag for message
+ if (isControlChar(c)) { // remove other control characters, flag for message
controlsStripped = true;
*pOut++ = ' ';
continue;
}
- if ( whitespaceSeen ) { // convert whitespace to a single space
+ if (whitespaceSeen) { // convert whitespace to a single space
*pOut++ = ' ';
whitespaceSeen = false;
}
@@ -2496,18 +2589,18 @@ void linenoisePreloadBuffer( const char* preloadText ) {
*pOut = 0;
int processedLength = pOut - tempBuffer.get();
bool lineTruncated = false;
- if ( processedLength > ( LINENOISE_MAX_LINE - 1 ) ) {
+ if (processedLength > (LINENOISE_MAX_LINE - 1)) {
lineTruncated = true;
- tempBuffer[ LINENOISE_MAX_LINE - 1 ] = 0;
+ tempBuffer[LINENOISE_MAX_LINE - 1] = 0;
}
preloadedBufferContents = tempBuffer.get();
- if ( controlsStripped ) {
+ if (controlsStripped) {
preloadErrorMessage += " [Edited line: control characters were converted to spaces]\n";
}
- if ( lineTruncated ) {
+ if (lineTruncated) {
preloadErrorMessage += " [Edited line: the line length was reduced from ";
char buf[128];
- snprintf( buf, sizeof( buf ), "%d to %d]\n", processedLength, ( LINENOISE_MAX_LINE - 1 ) );
+ snprintf(buf, sizeof(buf), "%d to %d]\n", processedLength, (LINENOISE_MAX_LINE - 1));
preloadErrorMessage += buf;
}
}
@@ -2520,111 +2613,109 @@ void linenoisePreloadBuffer( const char* preloadText ) {
* @param prompt text of prompt to display to the user
* @return the returned string belongs to the caller on return and must be freed to prevent memory leaks
*/
-char* linenoise( const char* prompt ) {
- if ( isatty( STDIN_FILENO ) ) { // input is from a terminal
- UChar32 buf32[ LINENOISE_MAX_LINE ];
- char charWidths[ LINENOISE_MAX_LINE ];
- if ( ! preloadErrorMessage.empty() ) {
- printf( "%s", preloadErrorMessage.c_str() );
- fflush( stdout );
+char* linenoise(const char* prompt) {
+ if (isatty(STDIN_FILENO)) { // input is from a terminal
+ UChar32 buf32[LINENOISE_MAX_LINE];
+ char charWidths[LINENOISE_MAX_LINE];
+ if (!preloadErrorMessage.empty()) {
+ printf("%s", preloadErrorMessage.c_str());
+ fflush(stdout);
preloadErrorMessage.clear();
}
- PromptInfo pi( reinterpret_cast< const UChar8* >( prompt ), getScreenColumns() );
- if ( isUnsupportedTerm() ) {
- if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return 0;
- fflush( stdout );
- if ( preloadedBufferContents.empty() ) {
- unique_ptr<char[]> buf8( new char[ LINENOISE_MAX_LINE ] );
- if ( fgets( buf8.get(), LINENOISE_MAX_LINE, stdin ) == NULL ) {
+ PromptInfo pi(reinterpret_cast<const UChar8*>(prompt), getScreenColumns());
+ if (isUnsupportedTerm()) {
+ if (write32(1, pi.promptText.get(), pi.promptChars) == -1)
+ return 0;
+ fflush(stdout);
+ if (preloadedBufferContents.empty()) {
+ unique_ptr<char[]> buf8(new char[LINENOISE_MAX_LINE]);
+ if (fgets(buf8.get(), LINENOISE_MAX_LINE, stdin) == NULL) {
return NULL;
}
- size_t len = strlen( buf8.get() );
- while ( len && ( buf8[len - 1] == '\n' || buf8[len - 1] == '\r' ) ) {
+ size_t len = strlen(buf8.get());
+ while (len && (buf8[len - 1] == '\n' || buf8[len - 1] == '\r')) {
--len;
buf8[len] = '\0';
}
- return strdup( buf8.get() ); // caller must free buffer
- }
- else {
- char* buf8 = strdup( preloadedBufferContents.c_str() );
+ return strdup(buf8.get()); // caller must free buffer
+ } else {
+ char* buf8 = strdup(preloadedBufferContents.c_str());
preloadedBufferContents.clear();
- return buf8; // caller must free buffer
+ return buf8; // caller must free buffer
}
- }
- else {
- if ( enableRawMode() == -1 ) {
+ } else {
+ if (enableRawMode() == -1) {
return NULL;
}
- InputBuffer ib( buf32, charWidths, LINENOISE_MAX_LINE );
- if ( ! preloadedBufferContents.empty() ) {
- ib.preloadBuffer( reinterpret_cast< const UChar8 * >( preloadedBufferContents.c_str() ) );
+ InputBuffer ib(buf32, charWidths, LINENOISE_MAX_LINE);
+ if (!preloadedBufferContents.empty()) {
+ ib.preloadBuffer(reinterpret_cast<const UChar8*>(preloadedBufferContents.c_str()));
preloadedBufferContents.clear();
}
- int count = ib.getInputLine( pi );
+ int count = ib.getInputLine(pi);
disableRawMode();
- printf( "\n" );
- if ( count == -1 ) {
+ printf("\n");
+ if (count == -1) {
return NULL;
}
- size_t bufferSize = sizeof( UChar32 ) * ib.length() + 1;
- unique_ptr<UChar8[]> buf8( new UChar8[ bufferSize ] );
- copyString32to8( buf8.get(), buf32, bufferSize );
- return strdup( reinterpret_cast<char*>( buf8.get() ) ); // caller must free buffer
+ size_t bufferSize = sizeof(UChar32) * ib.length() + 1;
+ unique_ptr<UChar8[]> buf8(new UChar8[bufferSize]);
+ copyString32to8(buf8.get(), buf32, bufferSize);
+ return strdup(reinterpret_cast<char*>(buf8.get())); // caller must free buffer
}
- }
- else { // input not from a terminal, we should work with piped input, i.e. redirected stdin
- unique_ptr<char[]> buf8( new char[ LINENOISE_MAX_LINE ] );
- if ( fgets( buf8.get(), LINENOISE_MAX_LINE, stdin ) == NULL ) {
+ } else { // input not from a terminal, we should work with piped input, i.e. redirected stdin
+ unique_ptr<char[]> buf8(new char[LINENOISE_MAX_LINE]);
+ if (fgets(buf8.get(), LINENOISE_MAX_LINE, stdin) == NULL) {
return NULL;
}
// if fgets() gave us the newline, remove it
- int count = strlen( buf8.get() );
- if ( count > 0 && buf8[ count - 1 ] == '\n' ) {
+ int count = strlen(buf8.get());
+ if (count > 0 && buf8[count - 1] == '\n') {
--count;
- buf8[ count ] = '\0';
+ buf8[count] = '\0';
}
- return strdup( buf8.get() ); // caller must free buffer
+ return strdup(buf8.get()); // caller must free buffer
}
}
/* Register a callback function to be called for tab-completion. */
-void linenoiseSetCompletionCallback( linenoiseCompletionCallback* fn ) {
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback* fn) {
completionCallback = fn;
}
-void linenoiseAddCompletion( linenoiseCompletions* lc, const char* str ) {
- lc->completionStrings.push_back( Utf32String( reinterpret_cast<const UChar8*>( str ) ) );
+void linenoiseAddCompletion(linenoiseCompletions* lc, const char* str) {
+ lc->completionStrings.push_back(Utf32String(reinterpret_cast<const UChar8*>(str)));
}
-int linenoiseHistoryAdd( const char* line ) {
- if ( historyMaxLen == 0 ) {
+int linenoiseHistoryAdd(const char* line) {
+ if (historyMaxLen == 0) {
return 0;
}
- if ( history == NULL ) {
- history = reinterpret_cast< UChar8** >( malloc( sizeof( UChar8* ) * historyMaxLen ) );
+ if (history == NULL) {
+ history = reinterpret_cast<UChar8**>(malloc(sizeof(UChar8*) * historyMaxLen));
if (history == NULL) {
return 0;
}
- memset( history, 0, ( sizeof( char* ) * historyMaxLen ) );
+ memset(history, 0, (sizeof(char*) * historyMaxLen));
}
- UChar8* linecopy = reinterpret_cast< UChar8* >( strdup( line ) );
- if ( ! linecopy ) {
+ UChar8* linecopy = reinterpret_cast<UChar8*>(strdup(line));
+ if (!linecopy) {
return 0;
}
- if ( historyLen == historyMaxLen ) {
- free( history[0] );
- memmove( history, history + 1, sizeof( char* ) * ( historyMaxLen - 1 ) );
+ if (historyLen == historyMaxLen) {
+ free(history[0]);
+ memmove(history, history + 1, sizeof(char*) * (historyMaxLen - 1));
--historyLen;
- if ( --historyPreviousIndex < -1 ) {
+ if (--historyPreviousIndex < -1) {
historyPreviousIndex = -2;
}
}
// convert newlines in multi-line code to spaces before storing
UChar8* p = linecopy;
- while ( *p ) {
- if ( *p == '\n' ) {
+ while (*p) {
+ if (*p == '\n') {
*p = ' ';
}
++p;
@@ -2634,25 +2725,25 @@ int linenoiseHistoryAdd( const char* line ) {
return 1;
}
-int linenoiseHistorySetMaxLen( int len ) {
- if ( len < 1 ) {
+int linenoiseHistorySetMaxLen(int len) {
+ if (len < 1) {
return 0;
}
- if ( history ) {
+ if (history) {
int tocopy = historyLen;
- UChar8** newHistory = reinterpret_cast< UChar8** >( malloc( sizeof( UChar8* ) * len ) );
- if ( newHistory == NULL ) {
+ UChar8** newHistory = reinterpret_cast<UChar8**>(malloc(sizeof(UChar8*) * len));
+ if (newHistory == NULL) {
return 0;
}
- if ( len < tocopy ) {
+ if (len < tocopy) {
tocopy = len;
}
- memcpy( newHistory, history + historyMaxLen - tocopy, sizeof( UChar8* ) * tocopy );
- free( history );
+ memcpy(newHistory, history + historyMaxLen - tocopy, sizeof(UChar8*) * tocopy);
+ free(history);
history = newHistory;
}
historyMaxLen = len;
- if ( historyLen > historyMaxLen ) {
+ if (historyLen > historyMaxLen) {
historyLen = historyMaxLen;
}
return 1;
@@ -2660,18 +2751,18 @@ int linenoiseHistorySetMaxLen( int len ) {
/* Save the history in the specified file. On success 0 is returned
* otherwise -1 is returned. */
-int linenoiseHistorySave( const char* filename ) {
- FILE* fp = fopen( filename, "wt" );
- if ( fp == NULL ) {
+int linenoiseHistorySave(const char* filename) {
+ FILE* fp = fopen(filename, "wt");
+ if (fp == NULL) {
return -1;
}
- for ( int j = 0; j < historyLen; ++j ) {
- if ( history[j][0] != '\0' ) {
- fprintf ( fp, "%s\n", history[j] );
+ for (int j = 0; j < historyLen; ++j) {
+ if (history[j][0] != '\0') {
+ fprintf(fp, "%s\n", history[j]);
}
}
- fclose( fp );
+ fclose(fp);
return 0;
}
@@ -2680,25 +2771,25 @@ int linenoiseHistorySave( const char* filename ) {
*
* If the file exists and the operation succeeded 0 is returned, otherwise
* on error -1 is returned. */
-int linenoiseHistoryLoad( const char* filename ) {
- FILE *fp = fopen( filename, "rt" );
- if ( fp == NULL ) {
+int linenoiseHistoryLoad(const char* filename) {
+ FILE* fp = fopen(filename, "rt");
+ if (fp == NULL) {
return -1;
}
char buf[LINENOISE_MAX_LINE];
- while ( fgets( buf, LINENOISE_MAX_LINE, fp ) != NULL ) {
- char* p = strchr( buf, '\r' );
- if ( ! p ) {
- p = strchr( buf, '\n' );
+ while (fgets(buf, LINENOISE_MAX_LINE, fp) != NULL) {
+ char* p = strchr(buf, '\r');
+ if (!p) {
+ p = strchr(buf, '\n');
}
- if ( p ) {
+ if (p) {
*p = '\0';
}
- if ( p != buf ) {
- linenoiseHistoryAdd( buf );
+ if (p != buf) {
+ linenoiseHistoryAdd(buf);
}
}
- fclose( fp );
+ fclose(fp);
return 0;
}
diff --git a/src/mongo/shell/linenoise.h b/src/mongo/shell/linenoise.h
index 06edcbdfb88..1bdc2a76de8 100644
--- a/src/mongo/shell/linenoise.h
+++ b/src/mongo/shell/linenoise.h
@@ -38,17 +38,17 @@
struct linenoiseCompletions;
-typedef void( linenoiseCompletionCallback )( const char *, linenoiseCompletions * );
-void linenoiseSetCompletionCallback( linenoiseCompletionCallback * fn );
-void linenoiseAddCompletion( linenoiseCompletions * lc, const char * str );
+typedef void(linenoiseCompletionCallback)(const char*, linenoiseCompletions*);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback* fn);
+void linenoiseAddCompletion(linenoiseCompletions* lc, const char* str);
-char *linenoise( const char* prompt );
-void linenoisePreloadBuffer( const char* preloadText );
-int linenoiseHistoryAdd( const char* line );
-int linenoiseHistorySetMaxLen( int len );
-int linenoiseHistorySave( const char* filename );
-int linenoiseHistoryLoad( const char* filename );
-void linenoiseHistoryFree( void );
-void linenoiseClearScreen( void );
+char* linenoise(const char* prompt);
+void linenoisePreloadBuffer(const char* preloadText);
+int linenoiseHistoryAdd(const char* line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(const char* filename);
+int linenoiseHistoryLoad(const char* filename);
+void linenoiseHistoryFree(void);
+void linenoiseClearScreen(void);
#endif /* __LINENOISE_H */
diff --git a/src/mongo/shell/linenoise_utf8.cpp b/src/mongo/shell/linenoise_utf8.cpp
index 986e87259f6..1a01aec6696 100644
--- a/src/mongo/shell/linenoise_utf8.cpp
+++ b/src/mongo/shell/linenoise_utf8.cpp
@@ -45,21 +45,20 @@ namespace linenoise_utf8 {
* Errors in the UTF-8 encoding will be handled in two ways: the erroneous characters will be
* converted to the Unicode error character U+FFFD and flag bits will be set in the conversionErrorCode
* int.
- *
+ *
* @param uchar32output Destination UChar32 buffer
* @param utf8input Source UTF-8 string
* @param outputBufferSizeInCharacters Destination buffer size in characters
* @param outputUnicodeCharacterCount Number of UChar32 characters placed in output buffer
* @param conversionErrorCode Flag bits from enum BadUTF8, or zero if no error
*/
-void copyString8to32(
- UChar32* uchar32output,
- const UChar8* utf8input,
- size_t outputBufferSizeInCharacters,
- size_t & outputUnicodeCharacterCount,
- int & conversionErrorCode ) {
+void copyString8to32(UChar32* uchar32output,
+ const UChar8* utf8input,
+ size_t outputBufferSizeInCharacters,
+ size_t& outputUnicodeCharacterCount,
+ int& conversionErrorCode) {
conversionErrorCode = BadUTF8_no_error;
- if ( outputBufferSizeInCharacters == 0 ) {
+ if (outputBufferSizeInCharacters == 0) {
outputUnicodeCharacterCount = 0;
return;
}
@@ -68,149 +67,126 @@ void copyString8to32(
UChar32* pOut = uchar32output;
UChar32 uchar32;
int reducedBufferSize = outputBufferSizeInCharacters - 1;
- while ( *pIn && ( pOut - uchar32output ) < reducedBufferSize ) {
-
+ while (*pIn && (pOut - uchar32output) < reducedBufferSize) {
// default to error character so we don't set this in 18 places below
uchar32 = errorCharacter;
- if ( pIn[0] <= 0x7F ) { // 0x00000000 to 0x0000007F
+ if (pIn[0] <= 0x7F) { // 0x00000000 to 0x0000007F
uchar32 = pIn[0];
pIn += 1;
- }
- else if ( pIn[0] <= 0xDF ) { // 0x00000080 to 0x000007FF
- if ( ( pIn[0] >= 0xC2 ) && ( pIn[1] >= 0x80 ) && ( pIn[1] <= 0xBF ) ) {
- uchar32 = ( ( pIn[0] & 0x1F ) << 6 ) | ( pIn[1] & 0x3F );
+ } else if (pIn[0] <= 0xDF) { // 0x00000080 to 0x000007FF
+ if ((pIn[0] >= 0xC2) && (pIn[1] >= 0x80) && (pIn[1] <= 0xBF)) {
+ uchar32 = ((pIn[0] & 0x1F) << 6) | (pIn[1] & 0x3F);
pIn += 2;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else if ( pIn[0] == 0xE0 ) { // 0x00000800 to 0x00000FFF
- if ( ( pIn[1] >= 0xA0 ) && ( pIn[1] <= 0xBF ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
- uchar32 = ( ( pIn[1] & 0x3F ) << 6 ) | ( pIn[2] & 0x3F );
+ } else if (pIn[0] == 0xE0) { // 0x00000800 to 0x00000FFF
+ if ((pIn[1] >= 0xA0) && (pIn[1] <= 0xBF)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
+ uchar32 = ((pIn[1] & 0x3F) << 6) | (pIn[2] & 0x3F);
pIn += 3;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else if ( pIn[0] <= 0xEC ) { // 0x00001000 to 0x0000CFFF
- if ( ( pIn[1] >= 0x80 ) && ( pIn[1] <= 0xBF ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
- uchar32 = ( ( pIn[0] & 0x0F ) << 12 ) | ( ( pIn[1] & 0x3F ) << 6 ) | ( pIn[2] & 0x3F );
+ } else if (pIn[0] <= 0xEC) { // 0x00001000 to 0x0000CFFF
+ if ((pIn[1] >= 0x80) && (pIn[1] <= 0xBF)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
+ uchar32 = ((pIn[0] & 0x0F) << 12) | ((pIn[1] & 0x3F) << 6) | (pIn[2] & 0x3F);
pIn += 3;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else if ( pIn[0] == 0xED ) { // 0x0000D000 to 0x0000D7FF
- if ( ( pIn[1] >= 0x80 ) && ( pIn[1] <= 0x9F ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
- uchar32 = ( 0x0D << 12 ) | ( ( pIn[1] & 0x3F ) << 6 ) | ( pIn[2] & 0x3F );
+ } else if (pIn[0] == 0xED) { // 0x0000D000 to 0x0000D7FF
+ if ((pIn[1] >= 0x80) && (pIn[1] <= 0x9F)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
+ uchar32 = (0x0D << 12) | ((pIn[1] & 0x3F) << 6) | (pIn[2] & 0x3F);
pIn += 3;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
}
// // 0x0000D800 to 0x0000DFFF -- illegal surrogate value
- else if ( ( pIn[1] >= 0x80 ) && ( pIn[1] <= 0xBF ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
+ else if ((pIn[1] >= 0x80) && (pIn[1] <= 0xBF)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
conversionErrorCode |= BadUTF8_surrogate;
pIn += 3;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else if ( pIn[0] <= 0xEF ) { // 0x0000E000 to 0x0000FFFF
- if ( ( pIn[1] >= 0x80 ) && ( pIn[1] <= 0xBF ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
- uchar32 = ( ( pIn[0] & 0x0F ) << 12 ) | ( ( pIn[1] & 0x3F ) << 6 ) | ( pIn[2] & 0x3F );
+ } else if (pIn[0] <= 0xEF) { // 0x0000E000 to 0x0000FFFF
+ if ((pIn[1] >= 0x80) && (pIn[1] <= 0xBF)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
+ uchar32 = ((pIn[0] & 0x0F) << 12) | ((pIn[1] & 0x3F) << 6) | (pIn[2] & 0x3F);
pIn += 3;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else if ( pIn[0] == 0xF0 ) { // 0x00010000 to 0x0003FFFF
- if ( ( pIn[1] >= 0x90 ) && ( pIn[1] <= 0xBF ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
- if ( ( pIn[3] >= 0x80 ) && ( pIn[3] <= 0xBF ) ) {
- uchar32 = ( ( pIn[1] & 0x3F ) << 12 ) | ( ( pIn[2] & 0x3F ) << 6 ) | ( pIn[3] & 0x3F );
+ } else if (pIn[0] == 0xF0) { // 0x00010000 to 0x0003FFFF
+ if ((pIn[1] >= 0x90) && (pIn[1] <= 0xBF)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
+ if ((pIn[3] >= 0x80) && (pIn[3] <= 0xBF)) {
+ uchar32 =
+ ((pIn[1] & 0x3F) << 12) | ((pIn[2] & 0x3F) << 6) | (pIn[3] & 0x3F);
pIn += 4;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 3;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else if ( pIn[0] <= 0xF4 ) { // 0x00040000 to 0x0010FFFF
- if ( ( pIn[1] >= 0x80 ) && ( pIn[1] <= 0xBF ) ) {
- if ( ( pIn[2] >= 0x80 ) && ( pIn[2] <= 0xBF ) ) {
- if ( ( pIn[3] >= 0x80 ) && ( pIn[3] <= 0xBF ) ) {
- uchar32 = ( ( pIn[0] & 0x07 ) << 18 ) | ( ( pIn[1] & 0x3F ) << 12 ) | ( ( pIn[2] & 0x3F ) << 6 ) | ( pIn[3] & 0x3F );
+ } else if (pIn[0] <= 0xF4) { // 0x00040000 to 0x0010FFFF
+ if ((pIn[1] >= 0x80) && (pIn[1] <= 0xBF)) {
+ if ((pIn[2] >= 0x80) && (pIn[2] <= 0xBF)) {
+ if ((pIn[3] >= 0x80) && (pIn[3] <= 0xBF)) {
+ uchar32 = ((pIn[0] & 0x07) << 18) | ((pIn[1] & 0x3F) << 12) |
+ ((pIn[2] & 0x3F) << 6) | (pIn[3] & 0x3F);
pIn += 4;
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 3;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 2;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- }
- else {
+ } else {
conversionErrorCode |= BadUTF8_invalid_byte;
pIn += 1;
}
- if ( uchar32 != 0xFEFF ) { // do not store Byte Order Mark
+ if (uchar32 != 0xFEFF) { // do not store Byte Order Mark
*pOut++ = uchar32;
}
}
@@ -221,14 +197,14 @@ void copyString8to32(
/**
* Copy a null terminated UChar32 string to a UChar32 destination buffer
* Always null terminates the destination string if at least one character position is available
- *
+ *
* @param dest32 Destination UChar32 buffer
* @param source32 Source UChar32 string
* @param destLengthInCharacters Destination buffer length in characters
*/
-void copyString32( UChar32* dest32, const UChar32* source32, size_t destLengthInCharacters ) {
- if ( destLengthInCharacters ) {
- while ( *source32 && --destLengthInCharacters > 0 ) {
+void copyString32(UChar32* dest32, const UChar32* source32, size_t destLengthInCharacters) {
+ if (destLengthInCharacters) {
+ while (*source32 && --destLengthInCharacters > 0) {
*dest32++ = *source32++;
}
*dest32 = 0;
@@ -239,39 +215,39 @@ void copyString32( UChar32* dest32, const UChar32* source32, size_t destLengthIn
* Convert a specified number of UChar32 characters from a possibly null terminated UChar32 string to UTF-8
* and store it in a UChar8 destination buffer
* Always null terminates the destination string if at least one character position is available
- *
+ *
* @param dest8 Destination UChar8 buffer
* @param source32 Source UChar32 string
* @param outputBufferSizeInBytes Destination buffer size in bytes
* @param charCount Maximum number of UChar32 characters to process
* @return Count of bytes written to output buffer, not including null terminator
*/
-size_t copyString32to8counted( UChar8* dest8, const UChar32* source32, size_t outputBufferSizeInBytes, size_t charCount ) {
+size_t copyString32to8counted(UChar8* dest8,
+ const UChar32* source32,
+ size_t outputBufferSizeInBytes,
+ size_t charCount) {
size_t outputUTF8ByteCount = 0;
- if ( outputBufferSizeInBytes ) {
+ if (outputBufferSizeInBytes) {
size_t reducedBufferSize = outputBufferSizeInBytes - 4;
- while ( charCount-- && *source32 && outputUTF8ByteCount < reducedBufferSize ) {
+ while (charCount-- && *source32 && outputUTF8ByteCount < reducedBufferSize) {
UChar32 c = *source32++;
- if ( c <= 0x7F ) {
+ if (c <= 0x7F) {
*dest8++ = c;
outputUTF8ByteCount += 1;
- }
- else if ( c <= 0x7FF ) {
- *dest8++ = 0xC0 | ( c >> 6 );
- *dest8++ = 0x80 | ( 0x3F & c );
+ } else if (c <= 0x7FF) {
+ *dest8++ = 0xC0 | (c >> 6);
+ *dest8++ = 0x80 | (0x3F & c);
outputUTF8ByteCount += 2;
- }
- else if ( c <= 0xFFFF ) {
- *dest8++ = 0xE0 | ( c >> 12 );
- *dest8++ = 0x80 | ( 0x3F & ( c >> 6) );
- *dest8++ = 0x80 | ( 0x3F & c );
+ } else if (c <= 0xFFFF) {
+ *dest8++ = 0xE0 | (c >> 12);
+ *dest8++ = 0x80 | (0x3F & (c >> 6));
+ *dest8++ = 0x80 | (0x3F & c);
outputUTF8ByteCount += 3;
- }
- else if ( c <= 0x1FFFFF ) {
- *dest8++ = 0xF0 | ( c >> 18 );
- *dest8++ = 0x80 | ( 0x3F & ( c >> 12) );
- *dest8++ = 0x80 | ( 0x3F & ( c >> 6) );
- *dest8++ = 0x80 | ( 0x3F & c );
+ } else if (c <= 0x1FFFFF) {
+ *dest8++ = 0xF0 | (c >> 18);
+ *dest8++ = 0x80 | (0x3F & (c >> 12));
+ *dest8++ = 0x80 | (0x3F & (c >> 6));
+ *dest8++ = 0x80 | (0x3F & c);
outputUTF8ByteCount += 4;
}
}
@@ -283,25 +259,25 @@ size_t copyString32to8counted( UChar8* dest8, const UChar32* source32, size_t ou
/**
* Convert a null terminated UChar32 string to UTF-8 and store it in a UChar8 destination buffer
* Always null terminates the destination string if at least one character position is available
- *
+ *
* @param dest8 Destination UChar8 buffer
* @param source32 Source UChar32 string
* @param outputBufferSizeInBytes Destination buffer size in bytes
* @return Count of bytes written to output buffer, not including null terminator
*/
-size_t copyString32to8( UChar8* dest8, const UChar32* source32, size_t outputBufferSizeInBytes ) {
- return copyString32to8counted( dest8, source32, outputBufferSizeInBytes, 0x7FFFFFFF );
+size_t copyString32to8(UChar8* dest8, const UChar32* source32, size_t outputBufferSizeInBytes) {
+ return copyString32to8counted(dest8, source32, outputBufferSizeInBytes, 0x7FFFFFFF);
}
/**
* Count characters (i.e. Unicode code points, array elements) in a null terminated UChar32 string
- *
+ *
* @param str32 Source UChar32 string
* @return String length in characters
*/
-size_t strlen32( const UChar32* str32 ) {
+size_t strlen32(const UChar32* str32) {
size_t length = 0;
- while ( *str32++ ) {
+ while (*str32++) {
++length;
}
return length;
@@ -315,9 +291,9 @@ size_t strlen32( const UChar32* str32 ) {
* @param length Maximum number of characters to compare
* @return Negative if first < second, positive if first > second, zero if equal
*/
-int strncmp32( UChar32* first32, UChar32* second32, size_t length ) {
- while ( length-- ) {
- if ( *first32 == 0 || *first32 != *second32 ) {
+int strncmp32(UChar32* first32, UChar32* second32, size_t length) {
+ while (length--) {
+ if (*first32 == 0 || *first32 != *second32) {
return *first32 - *second32;
}
++first32;
@@ -334,27 +310,26 @@ int strncmp32( UChar32* first32, UChar32* second32, size_t length ) {
* @param sourceLengthInCharacters Number of source characters to convert and write
* @return Number of bytes written, -1 on error
*/
-int write32( int fileHandle, const UChar32* string32, unsigned int sourceLengthInCharacters ) {
+int write32(int fileHandle, const UChar32* string32, unsigned int sourceLengthInCharacters) {
size_t tempBufferBytes = 4 * sourceLengthInCharacters + 1;
- std::unique_ptr<char[]> tempCharString( new char[ tempBufferBytes ] );
- size_t count = copyString32to8counted( reinterpret_cast<UChar8*>( tempCharString.get() ),
- string32,
- tempBufferBytes,
- sourceLengthInCharacters );
+ std::unique_ptr<char[]> tempCharString(new char[tempBufferBytes]);
+ size_t count = copyString32to8counted(reinterpret_cast<UChar8*>(tempCharString.get()),
+ string32,
+ tempBufferBytes,
+ sourceLengthInCharacters);
#if defined(_WIN32)
- if ( _isatty( fileHandle ) ) {
- bool success = mongo::writeUtf8ToWindowsConsole( tempCharString.get(), count );
- if ( ! success ) {
+ if (_isatty(fileHandle)) {
+ bool success = mongo::writeUtf8ToWindowsConsole(tempCharString.get(), count);
+ if (!success) {
return -1;
}
return count;
- }
- else {
- return _write( fileHandle, tempCharString.get(), count );
+ } else {
+ return _write(fileHandle, tempCharString.get(), count);
}
#else
- return write( fileHandle, tempCharString.get(), count );
+ return write(fileHandle, tempCharString.get(), count);
#endif
}
-} // namespace linenoise_utf8
+} // namespace linenoise_utf8
diff --git a/src/mongo/shell/linenoise_utf8.h b/src/mongo/shell/linenoise_utf8.h
index 4cca38ad298..b459ea344dc 100644
--- a/src/mongo/shell/linenoise_utf8.h
+++ b/src/mongo/shell/linenoise_utf8.h
@@ -33,16 +33,12 @@
namespace linenoise_utf8 {
-typedef unsigned char UChar8; // UTF-8 octet
-typedef unsigned int UChar32; // Unicode code point
+typedef unsigned char UChar8; // UTF-8 octet
+typedef unsigned int UChar32; // Unicode code point
// Error bits (or-ed together) returned from utf8toUChar32string
//
-enum BadUTF8 {
- BadUTF8_no_error = 0x00,
- BadUTF8_invalid_byte = 0x01,
- BadUTF8_surrogate = 0x02
-};
+enum BadUTF8 { BadUTF8_no_error = 0x00, BadUTF8_invalid_byte = 0x01, BadUTF8_surrogate = 0x02 };
/**
* Convert a null terminated UTF-8 std::string from UTF-8 and store it in a UChar32 destination buffer
@@ -50,61 +46,63 @@ enum BadUTF8 {
* Errors in the UTF-8 encoding will be handled in two ways: the erroneous characters will be
* converted to the Unicode error character U+FFFD and flag bits will be set in the conversionErrorCode
* int.
- *
+ *
* @param uchar32output Destination UChar32 buffer
* @param utf8input Source UTF-8 string
* @param outputBufferSizeInCharacters Destination buffer size in characters
* @param outputUnicodeCharacterCount Number of UChar32 characters placed in output buffer
* @param conversionErrorCode Flag bits from enum BadUTF8, or zero if no error
*/
-void copyString8to32(
- UChar32* uchar32output,
- const UChar8* utf8input,
- size_t outputBufferSizeInCharacters,
- size_t & outputUnicodeCharacterCount,
- int & conversionErrorCode );
+void copyString8to32(UChar32* uchar32output,
+ const UChar8* utf8input,
+ size_t outputBufferSizeInCharacters,
+ size_t& outputUnicodeCharacterCount,
+ int& conversionErrorCode);
/**
* Copy a null terminated UChar32 std::string to a UChar32 destination buffer
* Always null terminates the destination std::string if at least one character position is available
- *
+ *
* @param dest32 Destination UChar32 buffer
* @param source32 Source UChar32 string
* @param destLengthInCharacters Destination buffer length in characters
*/
-void copyString32( UChar32* dest32, const UChar32* source32, size_t destLengthInCharacters );
+void copyString32(UChar32* dest32, const UChar32* source32, size_t destLengthInCharacters);
/**
* Convert a specified number of UChar32 characters from a possibly null terminated UChar32 std::string to UTF-8
* and store it in a UChar8 destination buffer
* Always null terminates the destination std::string if at least one character position is available
- *
+ *
* @param dest8 Destination UChar8 buffer
* @param source32 Source UChar32 string
* @param outputBufferSizeInBytes Destination buffer size in bytes
* @param charCount Maximum number of UChar32 characters to process
* @return Count of bytes written to output buffer, not including null terminator
*/
-size_t copyString32to8counted( UChar8* dest8, const UChar32* source32, size_t outputBufferSizeInBytes, size_t charCount );
+size_t copyString32to8counted(UChar8* dest8,
+ const UChar32* source32,
+ size_t outputBufferSizeInBytes,
+ size_t charCount);
/**
* Convert a null terminated UChar32 std::string to UTF-8 and store it in a UChar8 destination buffer
* Always null terminates the destination std::string if at least one character position is available
- *
+ *
* @param dest8 Destination UChar8 buffer
* @param source32 Source UChar32 string
* @param outputBufferSizeInBytes Destination buffer size in bytes
* @return Count of bytes written to output buffer, not including null terminator
*/
-size_t copyString32to8( UChar8* dest8, const UChar32* source32, size_t outputBufferSizeInBytes );
+size_t copyString32to8(UChar8* dest8, const UChar32* source32, size_t outputBufferSizeInBytes);
/**
* Count characters (i.e. Unicode code points, array elements) in a null terminated UChar32 string
- *
+ *
* @param str32 Source UChar32 string
* @return std::string length in characters
*/
-size_t strlen32( const UChar32* str32 );
+size_t strlen32(const UChar32* str32);
/**
* Compare two UChar32 null-terminated strings with length parameter
@@ -114,7 +112,7 @@ size_t strlen32( const UChar32* str32 );
* @param length Maximum number of characters to compare
* @return Negative if first < second, positive if first > second, zero if equal
*/
-int strncmp32( UChar32* first32, UChar32* second32, size_t length );
+int strncmp32(UChar32* first32, UChar32* second32, size_t length);
/**
* Internally convert an array of UChar32 characters of specified length to UTF-8 and write it to fileHandle
@@ -124,41 +122,55 @@ int strncmp32( UChar32* first32, UChar32* second32, size_t length );
* @param sourceLengthInCharacters Number of source characters to convert and write
* @return Number of bytes written, -1 on error
*/
-int write32( int fileHandle, const UChar32* string32, unsigned int sourceLengthInCharacters );
+int write32(int fileHandle, const UChar32* string32, unsigned int sourceLengthInCharacters);
/**
* Template and classes for UChar8 and UChar32 strings
*/
template <typename char_type>
struct UtfStringMixin {
- typedef char_type char_t; // inherited
+ typedef char_type char_t; // inherited
- UtfStringMixin() : _len( 0 ), _cap( 0 ), _chars( 0 ) {}
+ UtfStringMixin() : _len(0), _cap(0), _chars(0) {}
- UtfStringMixin( const UtfStringMixin& other ) // copies like std::string
- :_len( other._len ), _cap( other._len+1 ), _chars( other._chars ), _str( new char_t[_cap] )
- {
- memcpy( _str.get(), other._str.get(), _cap * sizeof( char_t ) );
+ UtfStringMixin(const UtfStringMixin& other) // copies like std::string
+ : _len(other._len),
+ _cap(other._len + 1),
+ _chars(other._chars),
+ _str(new char_t[_cap]) {
+ memcpy(_str.get(), other._str.get(), _cap * sizeof(char_t));
}
- UtfStringMixin& operator= (UtfStringMixin copy) {
- this->swap( copy );
+ UtfStringMixin& operator=(UtfStringMixin copy) {
+ this->swap(copy);
return *this;
}
- char_t* get() const { return _str.get(); }
- char_t& operator[](size_t idx) { return _str[idx]; }
- const char_t& operator[](size_t idx) const { return _str[idx]; }
+ char_t* get() const {
+ return _str.get();
+ }
+ char_t& operator[](size_t idx) {
+ return _str[idx];
+ }
+ const char_t& operator[](size_t idx) const {
+ return _str[idx];
+ }
- size_t length() const { return _len; }
- size_t capacity() const { return _cap; }
- size_t chars() const { return _chars; }
+ size_t length() const {
+ return _len;
+ }
+ size_t capacity() const {
+ return _cap;
+ }
+ size_t chars() const {
+ return _chars;
+ }
- void swap( UtfStringMixin& other ) {
- std::swap( _len, other._len );
- std::swap( _cap, other._cap );
- std::swap( _chars, other._chars );
- _str.swap( other._str );
+ void swap(UtfStringMixin& other) {
+ std::swap(_len, other._len);
+ std::swap(_cap, other._cap);
+ std::swap(_chars, other._chars);
+ _str.swap(other._str);
}
protected:
@@ -172,76 +184,74 @@ struct Utf32String;
struct Utf8String : public UtfStringMixin<UChar8> {
Utf8String() {}
- explicit Utf8String( const UChar32* s, int chars = -1 ) {
- if ( chars == -1 ) {
- initFrom32( s, strlen32( s ) );
- }
- else {
- initFrom32( s, chars );
+ explicit Utf8String(const UChar32* s, int chars = -1) {
+ if (chars == -1) {
+ initFrom32(s, strlen32(s));
+ } else {
+ initFrom32(s, chars);
}
}
- explicit Utf8String( const Utf32String& c ); // defined after utf32String
+ explicit Utf8String(const Utf32String& c); // defined after utf32String
private:
- void initFrom32( const UChar32* s, int chars ) {
+ void initFrom32(const UChar32* s, int chars) {
_chars = chars;
- _cap = _chars * sizeof( UChar32 ) + 1;
- _str.reset( new char_t[_cap] );
- _len = copyString32to8counted( _str.get(), s, _cap, chars );
+ _cap = _chars * sizeof(UChar32) + 1;
+ _str.reset(new char_t[_cap]);
+ _len = copyString32to8counted(_str.get(), s, _cap, chars);
}
};
struct Utf32String : public UtfStringMixin<UChar32> {
Utf32String() {}
- explicit Utf32String( const UChar32* s ) {
- _chars = _len = strlen32( s );
+ explicit Utf32String(const UChar32* s) {
+ _chars = _len = strlen32(s);
_cap = _len + 1;
- _str.reset( new UChar32[_cap] );
- memcpy( _str.get(), s, _cap * sizeof( UChar32 ) );
+ _str.reset(new UChar32[_cap]);
+ memcpy(_str.get(), s, _cap * sizeof(UChar32));
}
- explicit Utf32String( const UChar32* s, int textLen ) {
+ explicit Utf32String(const UChar32* s, int textLen) {
_chars = _len = textLen;
_cap = _len + 1;
- _str.reset( new UChar32[_cap] );
- memcpy( _str.get(), s, _len * sizeof( UChar32 ) );
+ _str.reset(new UChar32[_cap]);
+ memcpy(_str.get(), s, _len * sizeof(UChar32));
_str[_len] = 0;
}
- explicit Utf32String( const UChar8* s, int chars = -1 ) {
- initFrom8( s, chars );
+ explicit Utf32String(const UChar8* s, int chars = -1) {
+ initFrom8(s, chars);
}
- explicit Utf32String( const Utf8String& c ) {
- initFrom8( c.get(), c.chars() );
+ explicit Utf32String(const Utf8String& c) {
+ initFrom8(c.get(), c.chars());
}
- explicit Utf32String( size_t reserve ) {
+ explicit Utf32String(size_t reserve) {
_len = 0;
_cap = reserve;
_chars = 0;
- _str.reset( new UChar32[_cap] );
+ _str.reset(new UChar32[_cap]);
_str[0] = 0;
}
- void initFromBuffer( void ) {
- _chars = _len = strlen32( _str.get() );
+ void initFromBuffer(void) {
+ _chars = _len = strlen32(_str.get());
}
private:
- void initFrom8( const UChar8* s, int chars ) {
+ void initFrom8(const UChar8* s, int chars) {
Utf32String temp;
- if ( chars == -1 ) {
- temp._cap = strlen( reinterpret_cast<const char*>( s ) ) + 1; // worst case ASCII
- }
- else {
+ if (chars == -1) {
+ temp._cap = strlen(reinterpret_cast<const char*>(s)) + 1; // worst case ASCII
+ } else {
temp._cap = chars + 1;
}
- temp._str.reset( new char_t[temp._cap] );
+ temp._str.reset(new char_t[temp._cap]);
int error;
- copyString8to32( temp._str.get(), s, temp._cap, temp._chars, error );
+ copyString8to32(temp._str.get(), s, temp._cap, temp._chars, error);
temp._len = temp._chars;
- this->swap( temp );
+ this->swap(temp);
}
};
-inline Utf8String::Utf8String( const Utf32String& s ) {
- initFrom32( s.get(), s.chars() );
+inline Utf8String::Utf8String(const Utf32String& s) {
+ initFrom32(s.get(), s.chars());
}
-} // namespace linenoise_utf8
+} // namespace linenoise_utf8
diff --git a/src/mongo/shell/mk_wcwidth.cpp b/src/mongo/shell/mk_wcwidth.cpp
index 2088c345fac..58e3a368293 100644
--- a/src/mongo/shell/mk_wcwidth.cpp
+++ b/src/mongo/shell/mk_wcwidth.cpp
@@ -64,28 +64,28 @@
#include <wchar.h>
struct interval {
- int first;
- int last;
+ int first;
+ int last;
};
/* auxiliary function for binary search in interval table */
-static int bisearch(int ucs, const struct interval *table, int max) {
- int min = 0;
- int mid;
+static int bisearch(int ucs, const struct interval* table, int max) {
+ int min = 0;
+ int mid;
- if (ucs < table[0].first || ucs > table[max].last)
- return 0;
- while (max >= min) {
- mid = (min + max) / 2;
- if (ucs > table[mid].last)
- min = mid + 1;
- else if (ucs < table[mid].first)
- max = mid - 1;
- else
- return 1;
- }
+ if (ucs < table[0].first || ucs > table[max].last)
+ return 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (ucs > table[mid].last)
+ min = mid + 1;
+ else if (ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
- return 0;
+ return 0;
}
@@ -121,102 +121,189 @@ static int bisearch(int ucs, const struct interval *table, int max) {
* in ISO 10646.
*/
-int mk_wcwidth(int ucs)
-{
- /* sorted list of non-overlapping intervals of non-spacing characters */
- /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
- static const struct interval combining[] = {
- { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
- { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
- { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
- { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
- { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
- { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
- { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
- { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
- { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
- { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
- { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
- { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
- { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
- { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
- { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
- { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
- { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
- { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
- { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
- { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
- { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
- { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
- { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
- { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
- { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
- { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
- { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
- { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
- { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
- { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
- { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
- { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
- { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
- { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
- { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
- { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
- { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
- { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
- { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
- { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
- { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
- { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
- { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
- { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
- { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
- { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
- { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
- { 0xE0100, 0xE01EF }
- };
+int mk_wcwidth(int ucs) {
+ /* sorted list of non-overlapping intervals of non-spacing characters */
+ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+ static const struct interval combining[] = {{0x0300, 0x036F},
+ {0x0483, 0x0486},
+ {0x0488, 0x0489},
+ {0x0591, 0x05BD},
+ {0x05BF, 0x05BF},
+ {0x05C1, 0x05C2},
+ {0x05C4, 0x05C5},
+ {0x05C7, 0x05C7},
+ {0x0600, 0x0603},
+ {0x0610, 0x0615},
+ {0x064B, 0x065E},
+ {0x0670, 0x0670},
+ {0x06D6, 0x06E4},
+ {0x06E7, 0x06E8},
+ {0x06EA, 0x06ED},
+ {0x070F, 0x070F},
+ {0x0711, 0x0711},
+ {0x0730, 0x074A},
+ {0x07A6, 0x07B0},
+ {0x07EB, 0x07F3},
+ {0x0901, 0x0902},
+ {0x093C, 0x093C},
+ {0x0941, 0x0948},
+ {0x094D, 0x094D},
+ {0x0951, 0x0954},
+ {0x0962, 0x0963},
+ {0x0981, 0x0981},
+ {0x09BC, 0x09BC},
+ {0x09C1, 0x09C4},
+ {0x09CD, 0x09CD},
+ {0x09E2, 0x09E3},
+ {0x0A01, 0x0A02},
+ {0x0A3C, 0x0A3C},
+ {0x0A41, 0x0A42},
+ {0x0A47, 0x0A48},
+ {0x0A4B, 0x0A4D},
+ {0x0A70, 0x0A71},
+ {0x0A81, 0x0A82},
+ {0x0ABC, 0x0ABC},
+ {0x0AC1, 0x0AC5},
+ {0x0AC7, 0x0AC8},
+ {0x0ACD, 0x0ACD},
+ {0x0AE2, 0x0AE3},
+ {0x0B01, 0x0B01},
+ {0x0B3C, 0x0B3C},
+ {0x0B3F, 0x0B3F},
+ {0x0B41, 0x0B43},
+ {0x0B4D, 0x0B4D},
+ {0x0B56, 0x0B56},
+ {0x0B82, 0x0B82},
+ {0x0BC0, 0x0BC0},
+ {0x0BCD, 0x0BCD},
+ {0x0C3E, 0x0C40},
+ {0x0C46, 0x0C48},
+ {0x0C4A, 0x0C4D},
+ {0x0C55, 0x0C56},
+ {0x0CBC, 0x0CBC},
+ {0x0CBF, 0x0CBF},
+ {0x0CC6, 0x0CC6},
+ {0x0CCC, 0x0CCD},
+ {0x0CE2, 0x0CE3},
+ {0x0D41, 0x0D43},
+ {0x0D4D, 0x0D4D},
+ {0x0DCA, 0x0DCA},
+ {0x0DD2, 0x0DD4},
+ {0x0DD6, 0x0DD6},
+ {0x0E31, 0x0E31},
+ {0x0E34, 0x0E3A},
+ {0x0E47, 0x0E4E},
+ {0x0EB1, 0x0EB1},
+ {0x0EB4, 0x0EB9},
+ {0x0EBB, 0x0EBC},
+ {0x0EC8, 0x0ECD},
+ {0x0F18, 0x0F19},
+ {0x0F35, 0x0F35},
+ {0x0F37, 0x0F37},
+ {0x0F39, 0x0F39},
+ {0x0F71, 0x0F7E},
+ {0x0F80, 0x0F84},
+ {0x0F86, 0x0F87},
+ {0x0F90, 0x0F97},
+ {0x0F99, 0x0FBC},
+ {0x0FC6, 0x0FC6},
+ {0x102D, 0x1030},
+ {0x1032, 0x1032},
+ {0x1036, 0x1037},
+ {0x1039, 0x1039},
+ {0x1058, 0x1059},
+ {0x1160, 0x11FF},
+ {0x135F, 0x135F},
+ {0x1712, 0x1714},
+ {0x1732, 0x1734},
+ {0x1752, 0x1753},
+ {0x1772, 0x1773},
+ {0x17B4, 0x17B5},
+ {0x17B7, 0x17BD},
+ {0x17C6, 0x17C6},
+ {0x17C9, 0x17D3},
+ {0x17DD, 0x17DD},
+ {0x180B, 0x180D},
+ {0x18A9, 0x18A9},
+ {0x1920, 0x1922},
+ {0x1927, 0x1928},
+ {0x1932, 0x1932},
+ {0x1939, 0x193B},
+ {0x1A17, 0x1A18},
+ {0x1B00, 0x1B03},
+ {0x1B34, 0x1B34},
+ {0x1B36, 0x1B3A},
+ {0x1B3C, 0x1B3C},
+ {0x1B42, 0x1B42},
+ {0x1B6B, 0x1B73},
+ {0x1DC0, 0x1DCA},
+ {0x1DFE, 0x1DFF},
+ {0x200B, 0x200F},
+ {0x202A, 0x202E},
+ {0x2060, 0x2063},
+ {0x206A, 0x206F},
+ {0x20D0, 0x20EF},
+ {0x302A, 0x302F},
+ {0x3099, 0x309A},
+ {0xA806, 0xA806},
+ {0xA80B, 0xA80B},
+ {0xA825, 0xA826},
+ {0xFB1E, 0xFB1E},
+ {0xFE00, 0xFE0F},
+ {0xFE20, 0xFE23},
+ {0xFEFF, 0xFEFF},
+ {0xFFF9, 0xFFFB},
+ {0x10A01, 0x10A03},
+ {0x10A05, 0x10A06},
+ {0x10A0C, 0x10A0F},
+ {0x10A38, 0x10A3A},
+ {0x10A3F, 0x10A3F},
+ {0x1D167, 0x1D169},
+ {0x1D173, 0x1D182},
+ {0x1D185, 0x1D18B},
+ {0x1D1AA, 0x1D1AD},
+ {0x1D242, 0x1D244},
+ {0xE0001, 0xE0001},
+ {0xE0020, 0xE007F},
+ {0xE0100, 0xE01EF}};
- /* test for 8-bit control characters */
- if (ucs == 0)
- return 0;
- if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
- return -1;
+ /* test for 8-bit control characters */
+ if (ucs == 0)
+ return 0;
+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+ return -1;
- /* binary search in table of non-spacing characters */
- if (bisearch(ucs, combining,
- sizeof(combining) / sizeof(struct interval) - 1))
- return 0;
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1))
+ return 0;
- /* if we arrive here, ucs is not a combining or C0/C1 control character */
+ /* if we arrive here, ucs is not a combining or C0/C1 control character */
- return 1 +
- (ucs >= 0x1100 &&
- (ucs <= 0x115f || /* Hangul Jamo init. consonants */
- ucs == 0x2329 || ucs == 0x232a ||
- (ucs >= 0x2e80 && ucs <= 0xa4cf &&
- ucs != 0x303f) || /* CJK ... Yi */
- (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
- (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
- (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
- (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
- (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
- (ucs >= 0xffe0 && ucs <= 0xffe6) ||
- (ucs >= 0x20000 && ucs <= 0x2fffd) ||
- (ucs >= 0x30000 && ucs <= 0x3fffd)));
+ return 1 +
+ (ucs >= 0x1100 &&
+ (ucs <= 0x115f || /* Hangul Jamo init. consonants */
+ ucs == 0x2329 ||
+ ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */
+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+ (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+ (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
+ (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+ (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd)));
}
-int mk_wcswidth(const int *pwcs, size_t n)
-{
- int w, width = 0;
+int mk_wcswidth(const int* pwcs, size_t n) {
+ int w, width = 0;
- for (;*pwcs && n-- > 0; pwcs++)
- if ((w = mk_wcwidth(*pwcs)) < 0)
- return -1;
- else
- width += w;
+ for (; *pwcs && n-- > 0; pwcs++)
+ if ((w = mk_wcwidth(*pwcs)) < 0)
+ return -1;
+ else
+ width += w;
- return width;
+ return width;
}
@@ -229,83 +316,182 @@ int mk_wcswidth(const int *pwcs, size_t n)
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
-int mk_wcwidth_cjk(int ucs)
-{
- /* sorted list of non-overlapping intervals of East Asian Ambiguous
- * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
- static const struct interval ambiguous[] = {
- { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
- { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
- { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
- { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
- { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
- { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
- { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
- { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
- { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
- { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
- { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
- { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
- { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
- { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
- { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
- { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
- { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
- { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
- { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
- { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
- { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
- { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
- { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
- { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
- { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
- { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
- { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
- { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
- { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
- { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
- { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
- { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
- { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
- { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
- { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
- { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
- { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
- { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
- { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
- { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
- { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
- { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
- { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
- { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
- { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
- { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
- { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
- { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
- { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
- { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
- { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
- { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
- };
+int mk_wcwidth_cjk(int ucs) {
+ /* sorted list of non-overlapping intervals of East Asian Ambiguous
+ * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
+ static const struct interval ambiguous[] = {{0x00A1, 0x00A1},
+ {0x00A4, 0x00A4},
+ {0x00A7, 0x00A8},
+ {0x00AA, 0x00AA},
+ {0x00AE, 0x00AE},
+ {0x00B0, 0x00B4},
+ {0x00B6, 0x00BA},
+ {0x00BC, 0x00BF},
+ {0x00C6, 0x00C6},
+ {0x00D0, 0x00D0},
+ {0x00D7, 0x00D8},
+ {0x00DE, 0x00E1},
+ {0x00E6, 0x00E6},
+ {0x00E8, 0x00EA},
+ {0x00EC, 0x00ED},
+ {0x00F0, 0x00F0},
+ {0x00F2, 0x00F3},
+ {0x00F7, 0x00FA},
+ {0x00FC, 0x00FC},
+ {0x00FE, 0x00FE},
+ {0x0101, 0x0101},
+ {0x0111, 0x0111},
+ {0x0113, 0x0113},
+ {0x011B, 0x011B},
+ {0x0126, 0x0127},
+ {0x012B, 0x012B},
+ {0x0131, 0x0133},
+ {0x0138, 0x0138},
+ {0x013F, 0x0142},
+ {0x0144, 0x0144},
+ {0x0148, 0x014B},
+ {0x014D, 0x014D},
+ {0x0152, 0x0153},
+ {0x0166, 0x0167},
+ {0x016B, 0x016B},
+ {0x01CE, 0x01CE},
+ {0x01D0, 0x01D0},
+ {0x01D2, 0x01D2},
+ {0x01D4, 0x01D4},
+ {0x01D6, 0x01D6},
+ {0x01D8, 0x01D8},
+ {0x01DA, 0x01DA},
+ {0x01DC, 0x01DC},
+ {0x0251, 0x0251},
+ {0x0261, 0x0261},
+ {0x02C4, 0x02C4},
+ {0x02C7, 0x02C7},
+ {0x02C9, 0x02CB},
+ {0x02CD, 0x02CD},
+ {0x02D0, 0x02D0},
+ {0x02D8, 0x02DB},
+ {0x02DD, 0x02DD},
+ {0x02DF, 0x02DF},
+ {0x0391, 0x03A1},
+ {0x03A3, 0x03A9},
+ {0x03B1, 0x03C1},
+ {0x03C3, 0x03C9},
+ {0x0401, 0x0401},
+ {0x0410, 0x044F},
+ {0x0451, 0x0451},
+ {0x2010, 0x2010},
+ {0x2013, 0x2016},
+ {0x2018, 0x2019},
+ {0x201C, 0x201D},
+ {0x2020, 0x2022},
+ {0x2024, 0x2027},
+ {0x2030, 0x2030},
+ {0x2032, 0x2033},
+ {0x2035, 0x2035},
+ {0x203B, 0x203B},
+ {0x203E, 0x203E},
+ {0x2074, 0x2074},
+ {0x207F, 0x207F},
+ {0x2081, 0x2084},
+ {0x20AC, 0x20AC},
+ {0x2103, 0x2103},
+ {0x2105, 0x2105},
+ {0x2109, 0x2109},
+ {0x2113, 0x2113},
+ {0x2116, 0x2116},
+ {0x2121, 0x2122},
+ {0x2126, 0x2126},
+ {0x212B, 0x212B},
+ {0x2153, 0x2154},
+ {0x215B, 0x215E},
+ {0x2160, 0x216B},
+ {0x2170, 0x2179},
+ {0x2190, 0x2199},
+ {0x21B8, 0x21B9},
+ {0x21D2, 0x21D2},
+ {0x21D4, 0x21D4},
+ {0x21E7, 0x21E7},
+ {0x2200, 0x2200},
+ {0x2202, 0x2203},
+ {0x2207, 0x2208},
+ {0x220B, 0x220B},
+ {0x220F, 0x220F},
+ {0x2211, 0x2211},
+ {0x2215, 0x2215},
+ {0x221A, 0x221A},
+ {0x221D, 0x2220},
+ {0x2223, 0x2223},
+ {0x2225, 0x2225},
+ {0x2227, 0x222C},
+ {0x222E, 0x222E},
+ {0x2234, 0x2237},
+ {0x223C, 0x223D},
+ {0x2248, 0x2248},
+ {0x224C, 0x224C},
+ {0x2252, 0x2252},
+ {0x2260, 0x2261},
+ {0x2264, 0x2267},
+ {0x226A, 0x226B},
+ {0x226E, 0x226F},
+ {0x2282, 0x2283},
+ {0x2286, 0x2287},
+ {0x2295, 0x2295},
+ {0x2299, 0x2299},
+ {0x22A5, 0x22A5},
+ {0x22BF, 0x22BF},
+ {0x2312, 0x2312},
+ {0x2460, 0x24E9},
+ {0x24EB, 0x254B},
+ {0x2550, 0x2573},
+ {0x2580, 0x258F},
+ {0x2592, 0x2595},
+ {0x25A0, 0x25A1},
+ {0x25A3, 0x25A9},
+ {0x25B2, 0x25B3},
+ {0x25B6, 0x25B7},
+ {0x25BC, 0x25BD},
+ {0x25C0, 0x25C1},
+ {0x25C6, 0x25C8},
+ {0x25CB, 0x25CB},
+ {0x25CE, 0x25D1},
+ {0x25E2, 0x25E5},
+ {0x25EF, 0x25EF},
+ {0x2605, 0x2606},
+ {0x2609, 0x2609},
+ {0x260E, 0x260F},
+ {0x2614, 0x2615},
+ {0x261C, 0x261C},
+ {0x261E, 0x261E},
+ {0x2640, 0x2640},
+ {0x2642, 0x2642},
+ {0x2660, 0x2661},
+ {0x2663, 0x2665},
+ {0x2667, 0x266A},
+ {0x266C, 0x266D},
+ {0x266F, 0x266F},
+ {0x273D, 0x273D},
+ {0x2776, 0x277F},
+ {0xE000, 0xF8FF},
+ {0xFFFD, 0xFFFD},
+ {0xF0000, 0xFFFFD},
+ {0x100000, 0x10FFFD}};
- /* binary search in table of non-spacing characters */
- if (bisearch(ucs, ambiguous,
- sizeof(ambiguous) / sizeof(struct interval) - 1))
- return 2;
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1))
+ return 2;
- return mk_wcwidth(ucs);
+ return mk_wcwidth(ucs);
}
-int mk_wcswidth_cjk(const int *pwcs, size_t n)
-{
- int w, width = 0;
+int mk_wcswidth_cjk(const int* pwcs, size_t n) {
+ int w, width = 0;
- for (;*pwcs && n-- > 0; pwcs++)
- if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
- return -1;
- else
- width += w;
+ for (; *pwcs && n-- > 0; pwcs++)
+ if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
+ return -1;
+ else
+ width += w;
- return width;
+ return width;
}
diff --git a/src/mongo/shell/mk_wcwidth.h b/src/mongo/shell/mk_wcwidth.h
index fa81dc61af2..763ca339c1d 100644
--- a/src/mongo/shell/mk_wcwidth.h
+++ b/src/mongo/shell/mk_wcwidth.h
@@ -62,4 +62,4 @@
*/
extern int mk_wcwidth(int ucs);
-extern int mk_wcswidth(const int *pwcs, size_t n);
+extern int mk_wcswidth(const int* pwcs, size_t n);
diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp
index c016e16e241..a54f2bbc567 100644
--- a/src/mongo/shell/shell_options.cpp
+++ b/src/mongo/shell/shell_options.cpp
@@ -47,297 +47,299 @@
namespace mongo {
- using std::cout;
- using std::endl;
- using std::string;
- using std::vector;
+using std::cout;
+using std::endl;
+using std::string;
+using std::vector;
- ShellGlobalParams shellGlobalParams;
+ShellGlobalParams shellGlobalParams;
- Status addMongoShellOptions(moe::OptionSection* options) {
+Status addMongoShellOptions(moe::OptionSection* options) {
+ options->addOptionChaining(
+ "shell", "shell", moe::Switch, "run the shell after executing files");
- options->addOptionChaining("shell", "shell", moe::Switch,
- "run the shell after executing files");
+ options->addOptionChaining("nodb",
+ "nodb",
+ moe::Switch,
+ "don't connect to mongod on startup - no 'db address' arg expected");
- options->addOptionChaining("nodb", "nodb", moe::Switch,
- "don't connect to mongod on startup - no 'db address' arg expected");
+ options->addOptionChaining(
+ "norc", "norc", moe::Switch, "will not run the \".mongorc.js\" file on start up");
- options->addOptionChaining("norc", "norc", moe::Switch,
- "will not run the \".mongorc.js\" file on start up");
+ options->addOptionChaining("quiet", "quiet", moe::Switch, "be less chatty");
- options->addOptionChaining("quiet", "quiet", moe::Switch, "be less chatty");
+ options->addOptionChaining("port", "port", moe::String, "port to connect to");
- options->addOptionChaining("port", "port", moe::String, "port to connect to");
+ options->addOptionChaining("host", "host", moe::String, "server to connect to");
- options->addOptionChaining("host", "host", moe::String, "server to connect to");
+ options->addOptionChaining("eval", "eval", moe::String, "evaluate javascript");
- options->addOptionChaining("eval", "eval", moe::String, "evaluate javascript");
+ moe::OptionSection authenticationOptions("Authentication Options");
- moe::OptionSection authenticationOptions("Authentication Options");
+ authenticationOptions.addOptionChaining(
+ "username", "username,u", moe::String, "username for authentication");
- authenticationOptions.addOptionChaining("username", "username,u", moe::String,
- "username for authentication");
+ authenticationOptions.addOptionChaining(
+ "password", "password,p", moe::String, "password for authentication")
+ .setImplicit(moe::Value(std::string("")));
- authenticationOptions.addOptionChaining("password", "password,p", moe::String,
- "password for authentication")
- .setImplicit(moe::Value(std::string("")));
+ authenticationOptions.addOptionChaining("authenticationDatabase",
+ "authenticationDatabase",
+ moe::String,
+ "user source (defaults to dbname)")
+ .setDefault(moe::Value(std::string("")));
- authenticationOptions.addOptionChaining("authenticationDatabase", "authenticationDatabase",
- moe::String, "user source (defaults to dbname)")
- .setDefault(moe::Value(std::string("")));
+ authenticationOptions.addOptionChaining("authenticationMechanism",
+ "authenticationMechanism",
+ moe::String,
+ "authentication mechanism");
- authenticationOptions.addOptionChaining("authenticationMechanism",
- "authenticationMechanism", moe::String, "authentication mechanism");
+ authenticationOptions.addOptionChaining(
+ "gssapiServiceName",
+ "gssapiServiceName",
+ moe::String,
+ "Service name to use when authenticating using GSSAPI/Kerberos")
+ .setDefault(moe::Value(std::string(saslDefaultServiceName)));
- authenticationOptions.addOptionChaining("gssapiServiceName", "gssapiServiceName",
- moe::String,
- "Service name to use when authenticating using GSSAPI/Kerberos")
- .setDefault(moe::Value(std::string(saslDefaultServiceName)));
+ authenticationOptions.addOptionChaining(
+ "gssapiHostName",
+ "gssapiHostName",
+ moe::String,
+ "Remote host name to use for purpose of GSSAPI/Kerberos authentication");
- authenticationOptions.addOptionChaining("gssapiHostName", "gssapiHostName", moe::String,
- "Remote host name to use for purpose of GSSAPI/Kerberos authentication");
+ options->addSection(authenticationOptions);
- options->addSection(authenticationOptions);
+ options->addOptionChaining("help", "help,h", moe::Switch, "show this usage information");
- options->addOptionChaining("help", "help,h", moe::Switch, "show this usage information");
+ options->addOptionChaining("version", "version", moe::Switch, "show version information");
- options->addOptionChaining("version", "version", moe::Switch, "show version information");
+ options->addOptionChaining("verbose", "verbose", moe::Switch, "increase verbosity");
- options->addOptionChaining("verbose", "verbose", moe::Switch, "increase verbosity");
+ options->addOptionChaining(
+ "ipv6", "ipv6", moe::Switch, "enable IPv6 support (disabled by default)");
- options->addOptionChaining("ipv6", "ipv6", moe::Switch,
- "enable IPv6 support (disabled by default)");
-
- Status ret = Status::OK();
+ Status ret = Status::OK();
#ifdef MONGO_CONFIG_SSL
- ret = addSSLClientOptions(options);
- if (!ret.isOK()) {
- return ret;
- }
+ ret = addSSLClientOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
#endif
- options->addOptionChaining("dbaddress", "dbaddress", moe::String, "dbaddress")
- .hidden()
- .positional(1, 1);
-
- options->addOptionChaining("files", "files", moe::StringVector, "files")
- .hidden()
- .positional(2, -1);
-
- // for testing, kill op will also be disabled automatically if the tests starts a mongo
- // program
- options->addOptionChaining("nokillop", "nokillop", moe::Switch, "nokillop")
- .hidden();
-
- // for testing, will kill op without prompting
- options->addOptionChaining("autokillop", "autokillop", moe::Switch, "autokillop")
- .hidden();
-
- options->addOptionChaining("useLegacyWriteOps",
- "useLegacyWriteOps",
- moe::Switch,
- "use legacy write ops instead of write commands").hidden();
-
- options->addOptionChaining("writeMode",
- "writeMode",
- moe::String,
- "mode to determine how writes are done:"
- " commands, compatibility, legacy").hidden();
-
- options->addOptionChaining("readMode",
- "readMode",
- moe::String,
- "mode to determine how .find() queries are done:"
- " commands, compatibility").hidden();
-
- options->addOptionChaining("rpcProtocols",
- "rpcProtocols",
- moe::String,
- " none, opQueryOnly, opCommandOnly, all").hidden();
-
- return Status::OK();
- }
+ options->addOptionChaining("dbaddress", "dbaddress", moe::String, "dbaddress")
+ .hidden()
+ .positional(1, 1);
- std::string getMongoShellHelp(StringData name, const moe::OptionSection& options) {
- StringBuilder sb;
- sb << "MongoDB shell version: " << mongo::versionString << "\n";
- sb << "usage: " << name << " [options] [db address] [file names (ending in .js)]\n"
- << "db address can be:\n"
- << " foo foo database on local machine\n"
- << " 192.169.0.5/foo foo database on 192.168.0.5 machine\n"
- << " 192.169.0.5:9999/foo foo database on 192.168.0.5 machine on port 9999\n"
- << options.helpString() << "\n"
- << "file names: a list of files to run. files have to end in .js and will exit after "
- << "unless --shell is specified";
- return sb.str();
- }
+ options->addOptionChaining("files", "files", moe::StringVector, "files")
+ .hidden()
+ .positional(2, -1);
- bool handlePreValidationMongoShellOptions(const moe::Environment& params,
- const std::vector<std::string>& args) {
- if (params.count("help")) {
- std::cout << getMongoShellHelp(args[0], moe::startupOptions) << std::endl;
- return false;
- }
- if (params.count("version")) {
- cout << "MongoDB shell version: " << mongo::versionString << endl;
- return false;
- }
- return true;
- }
+ // for testing, kill op will also be disabled automatically if the tests starts a mongo
+ // program
+ options->addOptionChaining("nokillop", "nokillop", moe::Switch, "nokillop").hidden();
- Status storeMongoShellOptions(const moe::Environment& params,
- const std::vector<std::string>& args) {
+ // for testing, will kill op without prompting
+ options->addOptionChaining("autokillop", "autokillop", moe::Switch, "autokillop").hidden();
- if (params.count("quiet")) {
- mongo::serverGlobalParams.quiet = true;
- }
+ options->addOptionChaining("useLegacyWriteOps",
+ "useLegacyWriteOps",
+ moe::Switch,
+ "use legacy write ops instead of write commands").hidden();
+
+ options->addOptionChaining("writeMode",
+ "writeMode",
+ moe::String,
+ "mode to determine how writes are done:"
+ " commands, compatibility, legacy").hidden();
+
+ options->addOptionChaining("readMode",
+ "readMode",
+ moe::String,
+ "mode to determine how .find() queries are done:"
+ " commands, compatibility").hidden();
+
+ options->addOptionChaining("rpcProtocols",
+ "rpcProtocols",
+ moe::String,
+ " none, opQueryOnly, opCommandOnly, all").hidden();
+
+ return Status::OK();
+}
+
+std::string getMongoShellHelp(StringData name, const moe::OptionSection& options) {
+ StringBuilder sb;
+ sb << "MongoDB shell version: " << mongo::versionString << "\n";
+ sb << "usage: " << name << " [options] [db address] [file names (ending in .js)]\n"
+ << "db address can be:\n"
+ << " foo foo database on local machine\n"
+ << " 192.169.0.5/foo foo database on 192.168.0.5 machine\n"
+ << " 192.169.0.5:9999/foo foo database on 192.168.0.5 machine on port 9999\n"
+ << options.helpString() << "\n"
+ << "file names: a list of files to run. files have to end in .js and will exit after "
+ << "unless --shell is specified";
+ return sb.str();
+}
+
+bool handlePreValidationMongoShellOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ if (params.count("help")) {
+ std::cout << getMongoShellHelp(args[0], moe::startupOptions) << std::endl;
+ return false;
+ }
+ if (params.count("version")) {
+ cout << "MongoDB shell version: " << mongo::versionString << endl;
+ return false;
+ }
+ return true;
+}
+
+Status storeMongoShellOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ if (params.count("quiet")) {
+ mongo::serverGlobalParams.quiet = true;
+ }
#ifdef MONGO_CONFIG_SSL
- Status ret = storeSSLClientOptions(params);
- if (!ret.isOK()) {
- return ret;
- }
+ Status ret = storeSSLClientOptions(params);
+ if (!ret.isOK()) {
+ return ret;
+ }
#endif
- if (params.count("ipv6")) {
- mongo::enableIPv6();
- }
- if (params.count("verbose")) {
- logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
- }
+ if (params.count("ipv6")) {
+ mongo::enableIPv6();
+ }
+ if (params.count("verbose")) {
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
+ }
- if (params.count("port")) {
- shellGlobalParams.port = params["port"].as<string>();
- }
+ if (params.count("port")) {
+ shellGlobalParams.port = params["port"].as<string>();
+ }
- if (params.count("host")) {
- shellGlobalParams.dbhost = params["host"].as<string>();
- }
+ if (params.count("host")) {
+ shellGlobalParams.dbhost = params["host"].as<string>();
+ }
- if (params.count("eval")) {
- shellGlobalParams.script = params["eval"].as<string>();
- }
+ if (params.count("eval")) {
+ shellGlobalParams.script = params["eval"].as<string>();
+ }
- if (params.count("username")) {
- shellGlobalParams.username = params["username"].as<string>();
- }
+ if (params.count("username")) {
+ shellGlobalParams.username = params["username"].as<string>();
+ }
- if (params.count("password")) {
- shellGlobalParams.usingPassword = true;
- shellGlobalParams.password = params["password"].as<string>();
- }
+ if (params.count("password")) {
+ shellGlobalParams.usingPassword = true;
+ shellGlobalParams.password = params["password"].as<string>();
+ }
- if (params.count("authenticationDatabase")) {
- shellGlobalParams.authenticationDatabase =
- params["authenticationDatabase"].as<string>();
- }
+ if (params.count("authenticationDatabase")) {
+ shellGlobalParams.authenticationDatabase = params["authenticationDatabase"].as<string>();
+ }
- if (params.count("authenticationMechanism")) {
- shellGlobalParams.authenticationMechanism =
- params["authenticationMechanism"].as<string>();
- }
+ if (params.count("authenticationMechanism")) {
+ shellGlobalParams.authenticationMechanism = params["authenticationMechanism"].as<string>();
+ }
- if (params.count("gssapiServiceName")) {
- shellGlobalParams.gssapiServiceName = params["gssapiServiceName"].as<string>();
- }
+ if (params.count("gssapiServiceName")) {
+ shellGlobalParams.gssapiServiceName = params["gssapiServiceName"].as<string>();
+ }
- if (params.count("gssapiHostName")) {
- shellGlobalParams.gssapiHostName = params["gssapiHostName"].as<string>();
- }
+ if (params.count("gssapiHostName")) {
+ shellGlobalParams.gssapiHostName = params["gssapiHostName"].as<string>();
+ }
- if (params.count("shell")) {
- shellGlobalParams.runShell = true;
- }
- if (params.count("nodb")) {
- shellGlobalParams.nodb = true;
- }
- if (params.count("norc")) {
- shellGlobalParams.norc = true;
- }
- if (params.count("files")) {
- shellGlobalParams.files = params["files"].as< vector<string> >();
- }
- if (params.count("nokillop")) {
- mongo::shell_utils::_nokillop = true;
- }
- if (params.count("autokillop")) {
- shellGlobalParams.autoKillOp = true;
- }
- if (params.count("useLegacyWriteOps")) {
- shellGlobalParams.writeMode = "legacy";
- }
- if (params.count("writeMode")) {
- std::string mode = params["writeMode"].as<string>();
- if (mode != "commands" && mode != "legacy" && mode != "compatibility") {
- throw MsgAssertionException(17396,
- mongoutils::str::stream() <<
- "Unknown writeMode option: " << mode);
- }
- shellGlobalParams.writeMode = mode;
+ if (params.count("shell")) {
+ shellGlobalParams.runShell = true;
+ }
+ if (params.count("nodb")) {
+ shellGlobalParams.nodb = true;
+ }
+ if (params.count("norc")) {
+ shellGlobalParams.norc = true;
+ }
+ if (params.count("files")) {
+ shellGlobalParams.files = params["files"].as<vector<string>>();
+ }
+ if (params.count("nokillop")) {
+ mongo::shell_utils::_nokillop = true;
+ }
+ if (params.count("autokillop")) {
+ shellGlobalParams.autoKillOp = true;
+ }
+ if (params.count("useLegacyWriteOps")) {
+ shellGlobalParams.writeMode = "legacy";
+ }
+ if (params.count("writeMode")) {
+ std::string mode = params["writeMode"].as<string>();
+ if (mode != "commands" && mode != "legacy" && mode != "compatibility") {
+ throw MsgAssertionException(
+ 17396, mongoutils::str::stream() << "Unknown writeMode option: " << mode);
}
- if (params.count("readMode")) {
- std::string mode = params["readMode"].as<string>();
- if (mode != "commands" && mode != "compatibility") {
- throw MsgAssertionException(17397,
- mongoutils::str::stream()
+ shellGlobalParams.writeMode = mode;
+ }
+ if (params.count("readMode")) {
+ std::string mode = params["readMode"].as<string>();
+ if (mode != "commands" && mode != "compatibility") {
+ throw MsgAssertionException(17397,
+ mongoutils::str::stream()
<< "Unknown readMode option: '" << mode
<< "'. Valid modes are: {commands, compatibility}");
- }
- shellGlobalParams.readMode = mode;
}
- if (params.count("rpcProtocols")) {
- std::string protos = params["rpcProtocols"].as<string>();
- auto parsedRPCProtos = rpc::parseProtocolSet(protos);
- if (!parsedRPCProtos.isOK()) {
- throw MsgAssertionException(28653,
- str::stream()
- << "Unknown RPC Protocols: '" << protos
- << "'. Valid values are {none, opQueryOnly, "
- << "opCommandOnly, all}");
- }
- shellGlobalParams.rpcProtocols = parsedRPCProtos.getValue();
+ shellGlobalParams.readMode = mode;
+ }
+ if (params.count("rpcProtocols")) {
+ std::string protos = params["rpcProtocols"].as<string>();
+ auto parsedRPCProtos = rpc::parseProtocolSet(protos);
+ if (!parsedRPCProtos.isOK()) {
+ throw MsgAssertionException(28653,
+ str::stream() << "Unknown RPC Protocols: '" << protos
+ << "'. Valid values are {none, opQueryOnly, "
+ << "opCommandOnly, all}");
}
+ shellGlobalParams.rpcProtocols = parsedRPCProtos.getValue();
+ }
- /* This is a bit confusing, here are the rules:
- *
- * if nodb is set then all positional parameters are files
- * otherwise the first positional parameter might be a dbaddress, but
- * only if one of these conditions is met:
- * - it contains no '.' after the last appearance of '\' or '/'
- * - it doesn't end in '.js' and it doesn't specify a path to an existing file */
- if (params.count("dbaddress")) {
- string dbaddress = params["dbaddress"].as<string>();
- if (shellGlobalParams.nodb) {
- shellGlobalParams.files.insert( shellGlobalParams.files.begin(), dbaddress );
- }
- else {
- string basename = dbaddress.substr( dbaddress.find_last_of( "/\\" ) + 1 );
- if (basename.find_first_of( '.' ) == string::npos ||
- (basename.find(".js", basename.size() - 3) == string::npos &&
- !::mongo::shell_utils::fileExists(dbaddress))) {
- shellGlobalParams.url = dbaddress;
- }
- else {
- shellGlobalParams.files.insert( shellGlobalParams.files.begin(), dbaddress );
- }
+ /* This is a bit confusing, here are the rules:
+ *
+ * if nodb is set then all positional parameters are files
+ * otherwise the first positional parameter might be a dbaddress, but
+ * only if one of these conditions is met:
+ * - it contains no '.' after the last appearance of '\' or '/'
+ * - it doesn't end in '.js' and it doesn't specify a path to an existing file */
+ if (params.count("dbaddress")) {
+ string dbaddress = params["dbaddress"].as<string>();
+ if (shellGlobalParams.nodb) {
+ shellGlobalParams.files.insert(shellGlobalParams.files.begin(), dbaddress);
+ } else {
+ string basename = dbaddress.substr(dbaddress.find_last_of("/\\") + 1);
+ if (basename.find_first_of('.') == string::npos ||
+ (basename.find(".js", basename.size() - 3) == string::npos &&
+ !::mongo::shell_utils::fileExists(dbaddress))) {
+ shellGlobalParams.url = dbaddress;
+ } else {
+ shellGlobalParams.files.insert(shellGlobalParams.files.begin(), dbaddress);
}
}
+ }
- if ( shellGlobalParams.url == "*" ) {
- StringBuilder sb;
- sb << "ERROR: " << "\"*\" is an invalid db address";
- sb << getMongoShellHelp(args[0], moe::startupOptions);
- return Status(ErrorCodes::BadValue, sb.str());
- }
-
- return Status::OK();
+ if (shellGlobalParams.url == "*") {
+ StringBuilder sb;
+ sb << "ERROR: "
+ << "\"*\" is an invalid db address";
+ sb << getMongoShellHelp(args[0], moe::startupOptions);
+ return Status(ErrorCodes::BadValue, sb.str());
}
- Status validateMongoShellOptions(const moe::Environment& params) {
+ return Status::OK();
+}
+
+Status validateMongoShellOptions(const moe::Environment& params) {
#ifdef MONGO_CONFIG_SSL
- Status ret = validateSSLMongoShellOptions(params);
- if (!ret.isOK()) {
- return ret;
- }
-#endif
- return Status::OK();
+ Status ret = validateSSLMongoShellOptions(params);
+ if (!ret.isOK()) {
+ return ret;
}
+#endif
+ return Status::OK();
+}
}
diff --git a/src/mongo/shell/shell_options.h b/src/mongo/shell/shell_options.h
index a61e58ce9bf..cc4edb8e3e5 100644
--- a/src/mongo/shell/shell_options.h
+++ b/src/mongo/shell/shell_options.h
@@ -36,65 +36,64 @@
namespace mongo {
- namespace optionenvironment {
- class OptionSection;
- class Environment;
- } // namespace optionenvironment
+namespace optionenvironment {
+class OptionSection;
+class Environment;
+} // namespace optionenvironment
- namespace moe = mongo::optionenvironment;
+namespace moe = mongo::optionenvironment;
- struct ShellGlobalParams {
- std::string url;
- std::string dbhost;
- std::string port;
- std::vector<std::string> files;
+struct ShellGlobalParams {
+ std::string url;
+ std::string dbhost;
+ std::string port;
+ std::vector<std::string> files;
- std::string username;
- std::string password;
- bool usingPassword;
- std::string authenticationMechanism;
- std::string authenticationDatabase;
- std::string gssapiServiceName;
- std::string gssapiHostName;
+ std::string username;
+ std::string password;
+ bool usingPassword;
+ std::string authenticationMechanism;
+ std::string authenticationDatabase;
+ std::string gssapiServiceName;
+ std::string gssapiHostName;
- bool runShell;
- bool nodb;
- bool norc;
+ bool runShell;
+ bool nodb;
+ bool norc;
- std::string script;
+ std::string script;
- bool autoKillOp;
- bool useWriteCommandsDefault;
- std::string writeMode;
+ bool autoKillOp;
+ bool useWriteCommandsDefault;
+ std::string writeMode;
- std::string readMode;
+ std::string readMode;
- rpc::ProtocolSet rpcProtocols;
+ rpc::ProtocolSet rpcProtocols;
- ShellGlobalParams() : autoKillOp(false),
- useWriteCommandsDefault(true),
- writeMode("commands"),
- readMode("compatibility"),
- rpcProtocols(rpc::supports::kOpQueryOnly) {
- }
- };
+ ShellGlobalParams()
+ : autoKillOp(false),
+ useWriteCommandsDefault(true),
+ writeMode("commands"),
+ readMode("compatibility"),
+ rpcProtocols(rpc::supports::kOpQueryOnly) {}
+};
- extern ShellGlobalParams shellGlobalParams;
+extern ShellGlobalParams shellGlobalParams;
- Status addMongoShellOptions(moe::OptionSection* options);
+Status addMongoShellOptions(moe::OptionSection* options);
- std::string getMongoShellHelp(StringData name, const moe::OptionSection& options);
+std::string getMongoShellHelp(StringData name, const moe::OptionSection& options);
- /**
- * Handle options that should come before validation, such as "help".
- *
- * Returns false if an option was found that implies we should prematurely exit with success.
- */
- bool handlePreValidationMongoShellOptions(const moe::Environment& params,
- const std::vector<std::string>& args);
+/**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+bool handlePreValidationMongoShellOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
- Status storeMongoShellOptions(const moe::Environment& params,
- const std::vector<std::string>& args);
+Status storeMongoShellOptions(const moe::Environment& params, const std::vector<std::string>& args);
- Status validateMongoShellOptions(const moe::Environment& params);
+Status validateMongoShellOptions(const moe::Environment& params);
}
diff --git a/src/mongo/shell/shell_options_init.cpp b/src/mongo/shell/shell_options_init.cpp
index a19268e9f1a..ff6c0792ca5 100644
--- a/src/mongo/shell/shell_options_init.cpp
+++ b/src/mongo/shell/shell_options_init.cpp
@@ -35,34 +35,33 @@
#include "mongo/util/quick_exit.h"
namespace mongo {
- MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoShellOptions)(InitializerContext* context) {
- return addMongoShellOptions(&moe::startupOptions);
- }
-
- MONGO_STARTUP_OPTIONS_VALIDATE(MongoShellOptions)(InitializerContext* context) {
- if (!handlePreValidationMongoShellOptions(moe::startupOptionsParsed, context->args())) {
- quickExit(EXIT_SUCCESS);
- }
- Status ret = moe::startupOptionsParsed.validate();
- if (!ret.isOK()) {
- return ret;
- }
- ret = validateMongoShellOptions(moe::startupOptionsParsed);
- if (!ret.isOK()) {
- return ret;
- }
+MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoShellOptions)(InitializerContext* context) {
+ return addMongoShellOptions(&moe::startupOptions);
+}
- return Status::OK();
+MONGO_STARTUP_OPTIONS_VALIDATE(MongoShellOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoShellOptions(moe::startupOptionsParsed, context->args())) {
+ quickExit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
}
+ ret = validateMongoShellOptions(moe::startupOptionsParsed);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ return Status::OK();
+}
- MONGO_STARTUP_OPTIONS_STORE(MongoShellOptions)(InitializerContext* context) {
- Status ret = storeMongoShellOptions(moe::startupOptionsParsed, context->args());
- if (!ret.isOK()) {
- std::cerr << ret.toString() << std::endl;
- std::cerr << "try '" << context->args()[0] << " --help' for more information"
- << std::endl;
- quickExit(EXIT_BADOPTIONS);
- }
- return Status::OK();
+MONGO_STARTUP_OPTIONS_STORE(MongoShellOptions)(InitializerContext* context) {
+ Status ret = storeMongoShellOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information" << std::endl;
+ quickExit(EXIT_BADOPTIONS);
}
+ return Status::OK();
+}
}
diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp
index b70146559de..81dd1d5225f 100644
--- a/src/mongo/shell/shell_utils.cpp
+++ b/src/mongo/shell/shell_utils.cpp
@@ -48,330 +48,328 @@
namespace mongo {
- using std::set;
- using std::map;
- using std::string;
-
- namespace JSFiles {
- extern const JSFile servers;
- extern const JSFile shardingtest;
- extern const JSFile servers_misc;
- extern const JSFile replsettest;
- extern const JSFile replsetbridge;
- }
+using std::set;
+using std::map;
+using std::string;
+
+namespace JSFiles {
+extern const JSFile servers;
+extern const JSFile shardingtest;
+extern const JSFile servers_misc;
+extern const JSFile replsettest;
+extern const JSFile replsetbridge;
+}
- namespace shell_utils {
+namespace shell_utils {
- std::string _dbConnect;
- std::string _dbAuth;
+std::string _dbConnect;
+std::string _dbAuth;
- const char *argv0 = 0;
- void RecordMyLocation( const char *_argv0 ) { argv0 = _argv0; }
+const char* argv0 = 0;
+void RecordMyLocation(const char* _argv0) {
+ argv0 = _argv0;
+}
- // helpers
+// helpers
- BSONObj makeUndefined() {
- BSONObjBuilder b;
- b.appendUndefined( "" );
- return b.obj();
- }
- const BSONObj undefinedReturn = makeUndefined();
+BSONObj makeUndefined() {
+ BSONObjBuilder b;
+ b.appendUndefined("");
+ return b.obj();
+}
+const BSONObj undefinedReturn = makeUndefined();
- BSONElement singleArg(const BSONObj& args) {
- uassert( 12597 , "need to specify 1 argument" , args.nFields() == 1 );
- return args.firstElement();
- }
+BSONElement singleArg(const BSONObj& args) {
+ uassert(12597, "need to specify 1 argument", args.nFields() == 1);
+ return args.firstElement();
+}
- const char* getUserDir() {
+const char* getUserDir() {
#ifdef _WIN32
- return getenv( "USERPROFILE" );
+ return getenv("USERPROFILE");
#else
- return getenv( "HOME" );
+ return getenv("HOME");
#endif
- }
+}
- // real methods
+// real methods
- BSONObj Quit(const BSONObj& args, void* data) {
- // If no arguments are given first element will be EOO, which
- // converts to the integer value 0.
- goingAwaySoon();
- int exit_code = int( args.firstElement().number() );
- quickExit(exit_code);
- return undefinedReturn;
- }
+BSONObj Quit(const BSONObj& args, void* data) {
+ // If no arguments are given first element will be EOO, which
+ // converts to the integer value 0.
+ goingAwaySoon();
+ int exit_code = int(args.firstElement().number());
+ quickExit(exit_code);
+ return undefinedReturn;
+}
- BSONObj JSGetMemInfo( const BSONObj& args, void* data ) {
- ProcessInfo pi;
- uassert( 10258 , "processinfo not supported" , pi.supported() );
+BSONObj JSGetMemInfo(const BSONObj& args, void* data) {
+ ProcessInfo pi;
+ uassert(10258, "processinfo not supported", pi.supported());
- BSONObjBuilder e;
- e.append( "virtual" , pi.getVirtualMemorySize() );
- e.append( "resident" , pi.getResidentSize() );
+ BSONObjBuilder e;
+ e.append("virtual", pi.getVirtualMemorySize());
+ e.append("resident", pi.getResidentSize());
- BSONObjBuilder b;
- b.append( "ret" , e.obj() );
+ BSONObjBuilder b;
+ b.append("ret", e.obj());
- return b.obj();
- }
+ return b.obj();
+}
#if !defined(_WIN32)
- ThreadLocalValue< unsigned int > _randomSeed;
+ThreadLocalValue<unsigned int> _randomSeed;
#endif
- BSONObj JSSrand( const BSONObj &a, void* data ) {
- uassert( 12518, "srand requires a single numeric argument",
- a.nFields() == 1 && a.firstElement().isNumber() );
+BSONObj JSSrand(const BSONObj& a, void* data) {
+ uassert(12518,
+ "srand requires a single numeric argument",
+ a.nFields() == 1 && a.firstElement().isNumber());
#if !defined(_WIN32)
- _randomSeed.set( static_cast< unsigned int >( a.firstElement().numberLong() ) ); // grab least significant digits
+ _randomSeed.set(
+ static_cast<unsigned int>(a.firstElement().numberLong())); // grab least significant digits
#else
- srand( static_cast< unsigned int >( a.firstElement().numberLong() ) );
+ srand(static_cast<unsigned int>(a.firstElement().numberLong()));
#endif
- return undefinedReturn;
- }
+ return undefinedReturn;
+}
- BSONObj JSRand( const BSONObj &a, void* data ) {
- uassert( 12519, "rand accepts no arguments", a.nFields() == 0 );
- unsigned r;
+BSONObj JSRand(const BSONObj& a, void* data) {
+ uassert(12519, "rand accepts no arguments", a.nFields() == 0);
+ unsigned r;
#if !defined(_WIN32)
- r = rand_r( &_randomSeed.getRef() );
+ r = rand_r(&_randomSeed.getRef());
#else
- r = rand();
+ r = rand();
#endif
- return BSON( "" << double( r ) / ( double( RAND_MAX ) + 1 ) );
- }
+ return BSON("" << double(r) / (double(RAND_MAX) + 1));
+}
- BSONObj isWindows(const BSONObj& a, void* data) {
- uassert( 13006, "isWindows accepts no arguments", a.nFields() == 0 );
+BSONObj isWindows(const BSONObj& a, void* data) {
+ uassert(13006, "isWindows accepts no arguments", a.nFields() == 0);
#ifdef _WIN32
- return BSON( "" << true );
+ return BSON("" << true);
#else
- return BSON( "" << false );
+ return BSON("" << false);
#endif
- }
+}
- BSONObj isAddressSanitizerActive(const BSONObj& a, void* data) {
- bool isSanitized = false;
- // See the following for information on how we detect address sanitizer in clang and gcc.
- //
- // - http://clang.llvm.org/docs/AddressSanitizer.html#has-feature-address-sanitizer
- // - https://gcc.gnu.org/ml/gcc-patches/2012-11/msg01827.html
- //
+BSONObj isAddressSanitizerActive(const BSONObj& a, void* data) {
+ bool isSanitized = false;
+// See the following for information on how we detect address sanitizer in clang and gcc.
+//
+// - http://clang.llvm.org/docs/AddressSanitizer.html#has-feature-address-sanitizer
+// - https://gcc.gnu.org/ml/gcc-patches/2012-11/msg01827.html
+//
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
- isSanitized = true;
+ isSanitized = true;
#endif
#elif defined(__SANITIZE_ADDRESS__)
- isSanitized = true;
+ isSanitized = true;
#endif
- return BSON( "" << isSanitized );
- }
+ return BSON("" << isSanitized);
+}
- BSONObj getBuildInfo(const BSONObj& a, void* data) {
- uassert( 16822, "getBuildInfo accepts no arguments", a.nFields() == 0 );
- BSONObjBuilder b;
- appendBuildInfo(b);
- return BSON( "" << b.done() );
- }
+BSONObj getBuildInfo(const BSONObj& a, void* data) {
+ uassert(16822, "getBuildInfo accepts no arguments", a.nFields() == 0);
+ BSONObjBuilder b;
+ appendBuildInfo(b);
+ return BSON("" << b.done());
+}
- BSONObj isKeyTooLarge(const BSONObj& a, void* data) {
- uassert(17428, "keyTooLarge takes exactly 2 arguments", a.nFields() == 2);
- BSONObjIterator i(a);
- BSONObj index = i.next().Obj();
- BSONObj doc = i.next().Obj();
+BSONObj isKeyTooLarge(const BSONObj& a, void* data) {
+ uassert(17428, "keyTooLarge takes exactly 2 arguments", a.nFields() == 2);
+ BSONObjIterator i(a);
+ BSONObj index = i.next().Obj();
+ BSONObj doc = i.next().Obj();
- return BSON("" << isAnyIndexKeyTooLarge(index, doc));
- }
+ return BSON("" << isAnyIndexKeyTooLarge(index, doc));
+}
- BSONObj validateIndexKey(const BSONObj& a, void* data) {
- BSONObj key = a[0].Obj();
- Status indexValid = validateKeyPattern(key);
- if (!indexValid.isOK()) {
- return BSON("" << BSON("ok" << false << "type"
- << indexValid.codeString() << "errmsg" << indexValid.reason()));
- }
- return BSON("" << BSON("ok" << true));
- }
+BSONObj validateIndexKey(const BSONObj& a, void* data) {
+ BSONObj key = a[0].Obj();
+ Status indexValid = validateKeyPattern(key);
+ if (!indexValid.isOK()) {
+ return BSON("" << BSON("ok" << false << "type" << indexValid.codeString() << "errmsg"
+ << indexValid.reason()));
+ }
+ return BSON("" << BSON("ok" << true));
+}
- BSONObj replMonitorStats(const BSONObj& a, void* data) {
- uassert(17134, "replMonitorStats requires a single string argument (the ReplSet name)",
- a.nFields() == 1 && a.firstElement().type() == String);
+BSONObj replMonitorStats(const BSONObj& a, void* data) {
+ uassert(17134,
+ "replMonitorStats requires a single string argument (the ReplSet name)",
+ a.nFields() == 1 && a.firstElement().type() == String);
- ReplicaSetMonitorPtr rsm = ReplicaSetMonitor::get(a.firstElement().valuestrsafe());
- if (!rsm) {
- return BSON("" << "no ReplSetMonitor exists by that name");
- }
+ ReplicaSetMonitorPtr rsm = ReplicaSetMonitor::get(a.firstElement().valuestrsafe());
+ if (!rsm) {
+ return BSON(""
+ << "no ReplSetMonitor exists by that name");
+ }
- BSONObjBuilder result;
- rsm->appendInfo(result);
- return result.obj();
- }
+ BSONObjBuilder result;
+ rsm->appendInfo(result);
+ return result.obj();
+}
- BSONObj useWriteCommandsDefault(const BSONObj& a, void* data) {
- return BSON("" << shellGlobalParams.useWriteCommandsDefault);
- }
+BSONObj useWriteCommandsDefault(const BSONObj& a, void* data) {
+ return BSON("" << shellGlobalParams.useWriteCommandsDefault);
+}
- BSONObj writeMode(const BSONObj&, void*) {
- return BSON("" << shellGlobalParams.writeMode);
- }
+BSONObj writeMode(const BSONObj&, void*) {
+ return BSON("" << shellGlobalParams.writeMode);
+}
- BSONObj readMode(const BSONObj&, void*) {
- return BSON("" << shellGlobalParams.readMode);
- }
+BSONObj readMode(const BSONObj&, void*) {
+ return BSON("" << shellGlobalParams.readMode);
+}
- BSONObj interpreterVersion(const BSONObj& a, void* data) {
- uassert( 16453, "interpreterVersion accepts no arguments", a.nFields() == 0 );
- return BSON( "" << globalScriptEngine->getInterpreterVersionString() );
- }
+BSONObj interpreterVersion(const BSONObj& a, void* data) {
+ uassert(16453, "interpreterVersion accepts no arguments", a.nFields() == 0);
+ return BSON("" << globalScriptEngine->getInterpreterVersionString());
+}
- void installShellUtils( Scope& scope ) {
- scope.injectNative( "quit", Quit );
- scope.injectNative( "getMemInfo" , JSGetMemInfo );
- scope.injectNative( "_replMonitorStats" , replMonitorStats );
- scope.injectNative( "_srand" , JSSrand );
- scope.injectNative( "_rand" , JSRand );
- scope.injectNative( "_isWindows" , isWindows );
- scope.injectNative( "_isAddressSanitizerActive", isAddressSanitizerActive );
- scope.injectNative( "interpreterVersion", interpreterVersion );
- scope.injectNative( "getBuildInfo", getBuildInfo );
- scope.injectNative( "isKeyTooLarge", isKeyTooLarge );
- scope.injectNative( "validateIndexKey", validateIndexKey );
+void installShellUtils(Scope& scope) {
+ scope.injectNative("quit", Quit);
+ scope.injectNative("getMemInfo", JSGetMemInfo);
+ scope.injectNative("_replMonitorStats", replMonitorStats);
+ scope.injectNative("_srand", JSSrand);
+ scope.injectNative("_rand", JSRand);
+ scope.injectNative("_isWindows", isWindows);
+ scope.injectNative("_isAddressSanitizerActive", isAddressSanitizerActive);
+ scope.injectNative("interpreterVersion", interpreterVersion);
+ scope.injectNative("getBuildInfo", getBuildInfo);
+ scope.injectNative("isKeyTooLarge", isKeyTooLarge);
+ scope.injectNative("validateIndexKey", validateIndexKey);
#ifndef MONGO_SAFE_SHELL
- //can't launch programs
- installShellUtilsLauncher( scope );
- installShellUtilsExtended( scope );
+ // can't launch programs
+ installShellUtilsLauncher(scope);
+ installShellUtilsExtended(scope);
#endif
- }
+}
- void initScope( Scope &scope ) {
- // Need to define this method before JSFiles::utils is executed.
- scope.injectNative("_useWriteCommandsDefault", useWriteCommandsDefault);
- scope.injectNative("_writeMode", writeMode);
- scope.injectNative("_readMode", readMode);
- scope.externalSetup();
- mongo::shell_utils::installShellUtils( scope );
- scope.execSetup(JSFiles::servers);
- scope.execSetup(JSFiles::shardingtest);
- scope.execSetup(JSFiles::servers_misc);
- scope.execSetup(JSFiles::replsettest);
- scope.execSetup(JSFiles::replsetbridge);
-
- scope.injectNative("benchRun", BenchRunner::benchRunSync);
- scope.injectNative("benchRunSync", BenchRunner::benchRunSync);
- scope.injectNative("benchStart", BenchRunner::benchStart);
- scope.injectNative("benchFinish", BenchRunner::benchFinish);
-
- if ( !_dbConnect.empty() ) {
- uassert( 12513, "connect failed", scope.exec( _dbConnect , "(connect)" , false , true , false ) );
- }
- if ( !_dbAuth.empty() ) {
- uassert( 12514, "login failed", scope.exec( _dbAuth , "(auth)" , true , true , false ) );
- }
- }
+void initScope(Scope& scope) {
+ // Need to define this method before JSFiles::utils is executed.
+ scope.injectNative("_useWriteCommandsDefault", useWriteCommandsDefault);
+ scope.injectNative("_writeMode", writeMode);
+ scope.injectNative("_readMode", readMode);
+ scope.externalSetup();
+ mongo::shell_utils::installShellUtils(scope);
+ scope.execSetup(JSFiles::servers);
+ scope.execSetup(JSFiles::shardingtest);
+ scope.execSetup(JSFiles::servers_misc);
+ scope.execSetup(JSFiles::replsettest);
+ scope.execSetup(JSFiles::replsetbridge);
+
+ scope.injectNative("benchRun", BenchRunner::benchRunSync);
+ scope.injectNative("benchRunSync", BenchRunner::benchRunSync);
+ scope.injectNative("benchStart", BenchRunner::benchStart);
+ scope.injectNative("benchFinish", BenchRunner::benchFinish);
+
+ if (!_dbConnect.empty()) {
+ uassert(12513, "connect failed", scope.exec(_dbConnect, "(connect)", false, true, false));
+ }
+ if (!_dbAuth.empty()) {
+ uassert(12514, "login failed", scope.exec(_dbAuth, "(auth)", true, true, false));
+ }
+}
- Prompter::Prompter( const string &prompt ) :
- _prompt( prompt ),
- _confirmed() {
- }
+Prompter::Prompter(const string& prompt) : _prompt(prompt), _confirmed() {}
- bool Prompter::confirm() {
- if ( _confirmed ) {
- return true;
- }
+bool Prompter::confirm() {
+ if (_confirmed) {
+ return true;
+ }
- // The printf and scanf functions provide thread safe i/o.
-
- printf( "\n%s (y/n): ", _prompt.c_str() );
-
- char yn = '\0';
- int nScanMatches = scanf( "%c", &yn );
- bool matchedY = ( nScanMatches == 1 && ( yn == 'y' || yn == 'Y' ) );
-
- return _confirmed = matchedY;
- }
+ // The printf and scanf functions provide thread safe i/o.
- ConnectionRegistry::ConnectionRegistry() = default;
+ printf("\n%s (y/n): ", _prompt.c_str());
- void ConnectionRegistry::registerConnection( DBClientWithCommands &client ) {
- BSONObj info;
- if ( client.runCommand( "admin", BSON( "whatsmyuri" << 1 ), info ) ) {
- string connstr = dynamic_cast<DBClientBase&>( client ).getServerAddress();
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- _connectionUris[ connstr ].insert( info[ "you" ].str() );
- }
- }
+ char yn = '\0';
+ int nScanMatches = scanf("%c", &yn);
+ bool matchedY = (nScanMatches == 1 && (yn == 'y' || yn == 'Y'));
- void ConnectionRegistry::killOperationsOnAllConnections( bool withPrompt ) const {
- Prompter prompter( "do you want to kill the current op(s) on the server?" );
- stdx::lock_guard<stdx::mutex> lk( _mutex );
- for( map<string,set<string> >::const_iterator i = _connectionUris.begin();
- i != _connectionUris.end(); ++i ) {
+ return _confirmed = matchedY;
+}
- auto status = ConnectionString::parse(i->first);
- if (!status.isOK()) {
- continue;
- }
+ConnectionRegistry::ConnectionRegistry() = default;
- const ConnectionString cs(status.getValue());
+void ConnectionRegistry::registerConnection(DBClientWithCommands& client) {
+ BSONObj info;
+ if (client.runCommand("admin", BSON("whatsmyuri" << 1), info)) {
+ string connstr = dynamic_cast<DBClientBase&>(client).getServerAddress();
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ _connectionUris[connstr].insert(info["you"].str());
+ }
+}
- string errmsg;
- std::unique_ptr<DBClientWithCommands> conn( cs.connect( errmsg ) );
- if ( !conn ) {
- continue;
- }
-
- const set<string>& uris = i->second;
-
- BSONObj currentOpRes;
- conn->runPseudoCommand("admin",
- "currentOp",
- "$cmd.sys.inprog", {}, currentOpRes);
- auto inprog = currentOpRes["inprog"].embeddedObject();
- BSONForEach( op, inprog ) {
- if ( uris.count( op[ "client" ].String() ) ) {
- if ( !withPrompt || prompter.confirm() ) {
- BSONObjBuilder cmdBob;
- BSONObj info;
- cmdBob.append("op", op["opid"]);
- auto cmdArgs = cmdBob.done();
- conn->runPseudoCommand("admin", "killOp", "$cmd.sys.killop",
- cmdArgs, info);
- }
- else {
- return;
- }
- }
- }
- }
+void ConnectionRegistry::killOperationsOnAllConnections(bool withPrompt) const {
+ Prompter prompter("do you want to kill the current op(s) on the server?");
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ for (map<string, set<string>>::const_iterator i = _connectionUris.begin();
+ i != _connectionUris.end();
+ ++i) {
+ auto status = ConnectionString::parse(i->first);
+ if (!status.isOK()) {
+ continue;
+ }
+
+ const ConnectionString cs(status.getValue());
+
+ string errmsg;
+ std::unique_ptr<DBClientWithCommands> conn(cs.connect(errmsg));
+ if (!conn) {
+ continue;
}
-
- ConnectionRegistry connectionRegistry;
- bool _nokillop = false;
- void onConnect( DBClientWithCommands &c ) {
- if ( _nokillop ) {
- return;
+ const set<string>& uris = i->second;
+
+ BSONObj currentOpRes;
+ conn->runPseudoCommand("admin", "currentOp", "$cmd.sys.inprog", {}, currentOpRes);
+ auto inprog = currentOpRes["inprog"].embeddedObject();
+ BSONForEach(op, inprog) {
+ if (uris.count(op["client"].String())) {
+ if (!withPrompt || prompter.confirm()) {
+ BSONObjBuilder cmdBob;
+ BSONObj info;
+ cmdBob.append("op", op["opid"]);
+ auto cmdArgs = cmdBob.done();
+ conn->runPseudoCommand("admin", "killOp", "$cmd.sys.killop", cmdArgs, info);
+ } else {
+ return;
+ }
}
- c.setClientRPCProtocols(shellGlobalParams.rpcProtocols);
- connectionRegistry.registerConnection( c );
}
+ }
+}
- bool fileExists(const std::string& file) {
- try {
+ConnectionRegistry connectionRegistry;
+
+bool _nokillop = false;
+void onConnect(DBClientWithCommands& c) {
+ if (_nokillop) {
+ return;
+ }
+ c.setClientRPCProtocols(shellGlobalParams.rpcProtocols);
+ connectionRegistry.registerConnection(c);
+}
+
+bool fileExists(const std::string& file) {
+ try {
#ifdef _WIN32
- boost::filesystem::path p(toWideString(file.c_str()));
+ boost::filesystem::path p(toWideString(file.c_str()));
#else
- boost::filesystem::path p(file);
+ boost::filesystem::path p(file);
#endif
- return boost::filesystem::exists(p);
- }
- catch ( ... ) {
- return false;
- }
- }
+ return boost::filesystem::exists(p);
+ } catch (...) {
+ return false;
+ }
+}
- stdx::mutex &mongoProgramOutputMutex(*(new stdx::mutex()));
- }
+stdx::mutex& mongoProgramOutputMutex(*(new stdx::mutex()));
+}
}
diff --git a/src/mongo/shell/shell_utils.h b/src/mongo/shell/shell_utils.h
index ee773e9e029..b00b10f2d9c 100644
--- a/src/mongo/shell/shell_utils.h
+++ b/src/mongo/shell/shell_utils.h
@@ -35,56 +35,58 @@
namespace mongo {
- class Scope;
- class DBClientWithCommands;
-
- namespace shell_utils {
-
- extern std::string _dbConnect;
- extern std::string _dbAuth;
- extern bool _nokillop;
-
- void RecordMyLocation( const char *_argv0 );
- void installShellUtils( Scope& scope );
-
- void initScope( Scope &scope );
- void onConnect( DBClientWithCommands &c );
-
- const char* getUserDir();
-
- BSONElement singleArg(const BSONObj& args);
- extern const BSONObj undefinedReturn;
-
- /** Prompt for confirmation from cin. */
- class Prompter {
- public:
- Prompter( const std::string &prompt );
- /** @return prompted confirmation or cached confirmation. */
- bool confirm();
- private:
- const std::string _prompt;
- bool _confirmed;
- };
-
- /** Registry of server connections. */
- class ConnectionRegistry {
- public:
- ConnectionRegistry();
- void registerConnection( DBClientWithCommands &client );
- void killOperationsOnAllConnections( bool withPrompt ) const;
- private:
- std::map<std::string,std::set<std::string> > _connectionUris;
- mutable stdx::mutex _mutex;
- };
-
- extern ConnectionRegistry connectionRegistry;
-
- // This mutex helps the shell serialize output on exit, to avoid deadlocks at shutdown. So
- // it also protects the global dbexitCalled.
- extern stdx::mutex &mongoProgramOutputMutex;
-
- // Helper to tell if a file exists cross platform
- // TODO: Remove this when we have a cross platform file utility library
- bool fileExists(const std::string& file);
- }
+class Scope;
+class DBClientWithCommands;
+
+namespace shell_utils {
+
+extern std::string _dbConnect;
+extern std::string _dbAuth;
+extern bool _nokillop;
+
+void RecordMyLocation(const char* _argv0);
+void installShellUtils(Scope& scope);
+
+void initScope(Scope& scope);
+void onConnect(DBClientWithCommands& c);
+
+const char* getUserDir();
+
+BSONElement singleArg(const BSONObj& args);
+extern const BSONObj undefinedReturn;
+
+/** Prompt for confirmation from cin. */
+class Prompter {
+public:
+ Prompter(const std::string& prompt);
+ /** @return prompted confirmation or cached confirmation. */
+ bool confirm();
+
+private:
+ const std::string _prompt;
+ bool _confirmed;
+};
+
+/** Registry of server connections. */
+class ConnectionRegistry {
+public:
+ ConnectionRegistry();
+ void registerConnection(DBClientWithCommands& client);
+ void killOperationsOnAllConnections(bool withPrompt) const;
+
+private:
+ std::map<std::string, std::set<std::string>> _connectionUris;
+ mutable stdx::mutex _mutex;
+};
+
+extern ConnectionRegistry connectionRegistry;
+
+// This mutex helps the shell serialize output on exit, to avoid deadlocks at shutdown. So
+// it also protects the global dbexitCalled.
+extern stdx::mutex& mongoProgramOutputMutex;
+
+// Helper to tell if a file exists cross platform
+// TODO: Remove this when we have a cross platform file utility library
+bool fileExists(const std::string& file);
+}
}
diff --git a/src/mongo/shell/shell_utils_extended.cpp b/src/mongo/shell/shell_utils_extended.cpp
index 221d91b79fd..64cfc5773f9 100644
--- a/src/mongo/shell/shell_utils_extended.cpp
+++ b/src/mongo/shell/shell_utils_extended.cpp
@@ -47,215 +47,210 @@
namespace mongo {
- using std::ifstream;
- using std::string;
- using std::stringstream;
-
- /**
- * These utilities are thread safe but do not provide mutually exclusive access to resources
- * identified by the caller. Dependent filesystem paths should not be accessed by different
- * threads.
- */
- namespace shell_utils {
-
- BSONObj listFiles(const BSONObj& _args, void* data) {
- BSONObj cd = BSON( "0" << "." );
- BSONObj args = _args.isEmpty() ? cd : _args;
-
- uassert( 10257 , "need to specify 1 argument to listFiles" , args.nFields() == 1 );
-
- BSONArrayBuilder lst;
-
- string rootname = args.firstElement().valuestrsafe();
- boost::filesystem::path root( rootname );
- stringstream ss;
- ss << "listFiles: no such directory: " << rootname;
- string msg = ss.str();
- uassert( 12581, msg.c_str(), boost::filesystem::exists( root ) );
-
- boost::filesystem::directory_iterator end;
- boost::filesystem::directory_iterator i( root);
-
- while ( i != end ) {
- boost::filesystem::path p = *i;
- BSONObjBuilder b;
- b << "name" << p.generic_string();
- b << "baseName" << p.filename().generic_string();
- b.appendBool( "isDirectory", is_directory( p ) );
- if ( ! boost::filesystem::is_directory( p ) ) {
- try {
- b.append( "size" , (double)boost::filesystem::file_size( p ) );
- }
- catch ( ... ) {
- i++;
- continue;
- }
- }
-
- lst.append( b.obj() );
+using std::ifstream;
+using std::string;
+using std::stringstream;
+
+/**
+ * These utilities are thread safe but do not provide mutually exclusive access to resources
+ * identified by the caller. Dependent filesystem paths should not be accessed by different
+ * threads.
+ */
+namespace shell_utils {
+
+BSONObj listFiles(const BSONObj& _args, void* data) {
+ BSONObj cd = BSON("0"
+ << ".");
+ BSONObj args = _args.isEmpty() ? cd : _args;
+
+ uassert(10257, "need to specify 1 argument to listFiles", args.nFields() == 1);
+
+ BSONArrayBuilder lst;
+
+ string rootname = args.firstElement().valuestrsafe();
+ boost::filesystem::path root(rootname);
+ stringstream ss;
+ ss << "listFiles: no such directory: " << rootname;
+ string msg = ss.str();
+ uassert(12581, msg.c_str(), boost::filesystem::exists(root));
+
+ boost::filesystem::directory_iterator end;
+ boost::filesystem::directory_iterator i(root);
+
+ while (i != end) {
+ boost::filesystem::path p = *i;
+ BSONObjBuilder b;
+ b << "name" << p.generic_string();
+ b << "baseName" << p.filename().generic_string();
+ b.appendBool("isDirectory", is_directory(p));
+ if (!boost::filesystem::is_directory(p)) {
+ try {
+ b.append("size", (double)boost::filesystem::file_size(p));
+ } catch (...) {
i++;
+ continue;
}
-
- BSONObjBuilder ret;
- ret.appendArray( "", lst.done() );
- return ret.obj();
}
- BSONObj ls(const BSONObj& args, void* data) {
- BSONArrayBuilder ret;
- BSONObj o = listFiles(args, data);
- if( !o.isEmpty() ) {
- for( BSONObj::iterator i = o.firstElement().Obj().begin(); i.more(); ) {
- BSONObj f = i.next().Obj();
- string name = f["name"].String();
- if( f["isDirectory"].trueValue() ) {
- name += '/';
- }
- ret << name;
- }
+ lst.append(b.obj());
+ i++;
+ }
+
+ BSONObjBuilder ret;
+ ret.appendArray("", lst.done());
+ return ret.obj();
+}
+
+BSONObj ls(const BSONObj& args, void* data) {
+ BSONArrayBuilder ret;
+ BSONObj o = listFiles(args, data);
+ if (!o.isEmpty()) {
+ for (BSONObj::iterator i = o.firstElement().Obj().begin(); i.more();) {
+ BSONObj f = i.next().Obj();
+ string name = f["name"].String();
+ if (f["isDirectory"].trueValue()) {
+ name += '/';
}
- return BSON( "" << ret.arr() );
+ ret << name;
}
+ }
+ return BSON("" << ret.arr());
+}
- /** Set process wide current working directory. */
- BSONObj cd(const BSONObj& args, void* data) {
- uassert(16830,
- "cd requires one argument -- cd(directory)",
- args.nFields() == 1);
- uassert(16831,
- "cd requires a string argument -- cd(directory)",
- args.firstElement().type() == String);
+/** Set process wide current working directory. */
+BSONObj cd(const BSONObj& args, void* data) {
+ uassert(16830, "cd requires one argument -- cd(directory)", args.nFields() == 1);
+ uassert(16831,
+ "cd requires a string argument -- cd(directory)",
+ args.firstElement().type() == String);
#if defined(_WIN32)
- std::wstring dir = toWideString(args.firstElement().String().c_str());
- if (SetCurrentDirectoryW(dir.c_str())) {
- return BSONObj();
- }
+ std::wstring dir = toWideString(args.firstElement().String().c_str());
+ if (SetCurrentDirectoryW(dir.c_str())) {
+ return BSONObj();
+ }
#else
- std::string dir = args.firstElement().String();
- if (chdir(dir.c_str()) == 0) {
- return BSONObj();
- }
+ std::string dir = args.firstElement().String();
+ if (chdir(dir.c_str()) == 0) {
+ return BSONObj();
+ }
#endif
- uasserted(16832,
- mongoutils::str::stream() << "cd command failed: "
- << errnoWithDescription());
- return BSONObj();
- }
+ uasserted(16832, mongoutils::str::stream() << "cd command failed: " << errnoWithDescription());
+ return BSONObj();
+}
- BSONObj pwd(const BSONObj&, void* data) {
- boost::filesystem::path p = boost::filesystem::current_path();
- return BSON( "" << p.string() );
- }
+BSONObj pwd(const BSONObj&, void* data) {
+ boost::filesystem::path p = boost::filesystem::current_path();
+ return BSON("" << p.string());
+}
- BSONObj hostname(const BSONObj&, void* data) {
- return BSON( "" << getHostName() );
- }
+BSONObj hostname(const BSONObj&, void* data) {
+ return BSON("" << getHostName());
+}
- const int CANT_OPEN_FILE = 13300;
-
- BSONObj cat(const BSONObj& args, void* data) {
- BSONElement e = singleArg(args);
- stringstream ss;
- ifstream f(e.valuestrsafe());
- uassert(CANT_OPEN_FILE, "couldn't open file", f.is_open() );
-
- std::streamsize sz = 0;
- while( 1 ) {
- char ch = 0;
- // slow...maybe change one day
- f.get(ch);
- if( ch == 0 ) break;
- ss << ch;
- sz += 1;
- uassert(13301, "cat() : file to big to load as a variable", sz < 1024 * 1024 * 16);
- }
- return BSON( "" << ss.str() );
- }
+const int CANT_OPEN_FILE = 13300;
+
+BSONObj cat(const BSONObj& args, void* data) {
+ BSONElement e = singleArg(args);
+ stringstream ss;
+ ifstream f(e.valuestrsafe());
+ uassert(CANT_OPEN_FILE, "couldn't open file", f.is_open());
+
+ std::streamsize sz = 0;
+ while (1) {
+ char ch = 0;
+ // slow...maybe change one day
+ f.get(ch);
+ if (ch == 0)
+ break;
+ ss << ch;
+ sz += 1;
+ uassert(13301, "cat() : file to big to load as a variable", sz < 1024 * 1024 * 16);
+ }
+ return BSON("" << ss.str());
+}
- BSONObj md5sumFile(const BSONObj& args, void* data) {
- BSONElement e = singleArg(args);
- stringstream ss;
- FILE* f = fopen(e.valuestrsafe(), "rb");
- uassert(CANT_OPEN_FILE, "couldn't open file", f );
- ON_BLOCK_EXIT(fclose, f);
-
- md5digest d;
- md5_state_t st;
- md5_init(&st);
-
- enum {BUFLEN = 4*1024};
- char buffer[BUFLEN];
- int bytes_read;
- while( (bytes_read = fread(buffer, 1, BUFLEN, f)) ) {
- md5_append( &st , (const md5_byte_t*)(buffer) , bytes_read );
- }
+BSONObj md5sumFile(const BSONObj& args, void* data) {
+ BSONElement e = singleArg(args);
+ stringstream ss;
+ FILE* f = fopen(e.valuestrsafe(), "rb");
+ uassert(CANT_OPEN_FILE, "couldn't open file", f);
+ ON_BLOCK_EXIT(fclose, f);
+
+ md5digest d;
+ md5_state_t st;
+ md5_init(&st);
+
+ enum { BUFLEN = 4 * 1024 };
+ char buffer[BUFLEN];
+ int bytes_read;
+ while ((bytes_read = fread(buffer, 1, BUFLEN, f))) {
+ md5_append(&st, (const md5_byte_t*)(buffer), bytes_read);
+ }
- md5_finish(&st, d);
- return BSON( "" << digestToString( d ) );
- }
+ md5_finish(&st, d);
+ return BSON("" << digestToString(d));
+}
- BSONObj mkdir(const BSONObj& args, void* data) {
- uassert(16833,
- "mkdir requires one argument -- mkdir(directory)",
- args.nFields() == 1);
- uassert(16834,
- "mkdir requires a string argument -- mkdir(directory)",
- args.firstElement().type() == String);
- boost::filesystem::create_directories(args.firstElement().String());
- return BSON( "" << true );
- }
+BSONObj mkdir(const BSONObj& args, void* data) {
+ uassert(16833, "mkdir requires one argument -- mkdir(directory)", args.nFields() == 1);
+ uassert(16834,
+ "mkdir requires a string argument -- mkdir(directory)",
+ args.firstElement().type() == String);
+ boost::filesystem::create_directories(args.firstElement().String());
+ return BSON("" << true);
+}
- BSONObj removeFile(const BSONObj& args, void* data) {
- BSONElement e = singleArg(args);
- bool found = false;
+BSONObj removeFile(const BSONObj& args, void* data) {
+ BSONElement e = singleArg(args);
+ bool found = false;
- boost::filesystem::path root( e.valuestrsafe() );
- if ( boost::filesystem::exists( root ) ) {
- found = true;
- boost::filesystem::remove_all( root );
- }
+ boost::filesystem::path root(e.valuestrsafe());
+ if (boost::filesystem::exists(root)) {
+ found = true;
+ boost::filesystem::remove_all(root);
+ }
- BSONObjBuilder b;
- b.appendBool( "removed" , found );
- return b.obj();
- }
+ BSONObjBuilder b;
+ b.appendBool("removed", found);
+ return b.obj();
+}
- /**
- * @param args - [ source, destination ]
- * copies file 'source' to 'destination'. Errors if the 'destination' file already exists.
- */
- BSONObj copyFile(const BSONObj& args, void* data) {
- uassert(13619, "copyFile takes 2 arguments", args.nFields() == 2);
+/**
+ * @param args - [ source, destination ]
+ * copies file 'source' to 'destination'. Errors if the 'destination' file already exists.
+ */
+BSONObj copyFile(const BSONObj& args, void* data) {
+ uassert(13619, "copyFile takes 2 arguments", args.nFields() == 2);
- BSONObjIterator it(args);
- const std::string source = it.next().str();
- const std::string destination = it.next().str();
+ BSONObjIterator it(args);
+ const std::string source = it.next().str();
+ const std::string destination = it.next().str();
- boost::filesystem::copy_file(source, destination);
+ boost::filesystem::copy_file(source, destination);
- return undefinedReturn;
- }
+ return undefinedReturn;
+}
- BSONObj getHostName(const BSONObj& a, void* data) {
- uassert( 13411, "getHostName accepts no arguments", a.nFields() == 0 );
- char buf[260]; // HOST_NAME_MAX is usually 255
- verify(gethostname(buf, 260) == 0);
- buf[259] = '\0';
- return BSON("" << buf);
- }
+BSONObj getHostName(const BSONObj& a, void* data) {
+ uassert(13411, "getHostName accepts no arguments", a.nFields() == 0);
+ char buf[260]; // HOST_NAME_MAX is usually 255
+ verify(gethostname(buf, 260) == 0);
+ buf[259] = '\0';
+ return BSON("" << buf);
+}
- void installShellUtilsExtended( Scope& scope ) {
- scope.injectNative( "getHostName" , getHostName );
- scope.injectNative( "removeFile" , removeFile );
- scope.injectNative( "copyFile" , copyFile );
- scope.injectNative( "listFiles" , listFiles );
- scope.injectNative( "ls" , ls );
- scope.injectNative( "pwd", pwd );
- scope.injectNative( "cd", cd );
- scope.injectNative( "cat", cat );
- scope.injectNative( "hostname", hostname);
- scope.injectNative( "md5sumFile", md5sumFile );
- scope.injectNative( "mkdir" , mkdir );
- }
- }
+void installShellUtilsExtended(Scope& scope) {
+ scope.injectNative("getHostName", getHostName);
+ scope.injectNative("removeFile", removeFile);
+ scope.injectNative("copyFile", copyFile);
+ scope.injectNative("listFiles", listFiles);
+ scope.injectNative("ls", ls);
+ scope.injectNative("pwd", pwd);
+ scope.injectNative("cd", cd);
+ scope.injectNative("cat", cat);
+ scope.injectNative("hostname", hostname);
+ scope.injectNative("md5sumFile", md5sumFile);
+ scope.injectNative("mkdir", mkdir);
+}
+}
}
diff --git a/src/mongo/shell/shell_utils_extended.h b/src/mongo/shell/shell_utils_extended.h
index dc4c2d944e7..471fe98a73e 100644
--- a/src/mongo/shell/shell_utils_extended.h
+++ b/src/mongo/shell/shell_utils_extended.h
@@ -32,9 +32,9 @@
namespace mongo {
- class Scope;
-
- namespace shell_utils {
- void installShellUtilsExtended( Scope& scope );
- }
+class Scope;
+
+namespace shell_utils {
+void installShellUtilsExtended(Scope& scope);
+}
}
diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp
index 6d4991e999a..ddba7fc8e28 100644
--- a/src/mongo/shell/shell_utils_launcher.cpp
+++ b/src/mongo/shell/shell_utils_launcher.cpp
@@ -39,15 +39,15 @@
#include <vector>
#ifdef _WIN32
-# include <fcntl.h>
-# include <io.h>
-# define SIGKILL 9
+#include <fcntl.h>
+#include <io.h>
+#define SIGKILL 9
#else
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <signal.h>
-# include <sys/stat.h>
-# include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
#endif
#include "mongo/client/dbclientinterface.h"
@@ -61,160 +61,166 @@
namespace mongo {
- using std::unique_ptr;
- using std::cout;
- using std::endl;
- using std::make_pair;
- using std::map;
- using std::pair;
- using std::string;
- using std::stringstream;
- using std::vector;
+using std::unique_ptr;
+using std::cout;
+using std::endl;
+using std::make_pair;
+using std::map;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
- extern bool dbexitCalled;
+extern bool dbexitCalled;
#ifdef _WIN32
- inline int close(int fd) { return _close(fd); }
- inline int read(int fd, void* buf, size_t size) { return _read(fd, buf, size); }
- inline int pipe(int fds[2]) { return _pipe(fds, 4096, _O_TEXT | _O_NOINHERIT); }
+inline int close(int fd) {
+ return _close(fd);
+}
+inline int read(int fd, void* buf, size_t size) {
+ return _read(fd, buf, size);
+}
+inline int pipe(int fds[2]) {
+ return _pipe(fds, 4096, _O_TEXT | _O_NOINHERIT);
+}
#endif
- /**
- * These utilities are thread safe but do not provide mutually exclusive access to resources
- * identified by the caller. Resources identified by a pid or port should not be accessed
- * by different threads. Dependent filesystem paths should not be accessed by different
- * threads.
- */
- namespace shell_utils {
+/**
+ * These utilities are thread safe but do not provide mutually exclusive access to resources
+ * identified by the caller. Resources identified by a pid or port should not be accessed
+ * by different threads. Dependent filesystem paths should not be accessed by different
+ * threads.
+ */
+namespace shell_utils {
- ProgramOutputMultiplexer programOutputLogger;
+ProgramOutputMultiplexer programOutputLogger;
- bool ProgramRegistry::isPortRegistered( int port ) const {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- return _ports.count( port ) == 1;
- }
+bool ProgramRegistry::isPortRegistered(int port) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ return _ports.count(port) == 1;
+}
- ProcessId ProgramRegistry::pidForPort( int port ) const {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- verify( isPortRegistered( port ) );
- return _ports.find( port )->second.first;
- }
+ProcessId ProgramRegistry::pidForPort(int port) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ verify(isPortRegistered(port));
+ return _ports.find(port)->second.first;
+}
- int ProgramRegistry::portForPid(ProcessId pid) const {
- stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
- for (map<int, pair<ProcessId, int> >::const_iterator it = _ports.begin();
- it != _ports.end(); ++it)
- {
- if (it->second.first == pid) return it->first;
- }
+int ProgramRegistry::portForPid(ProcessId pid) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ for (map<int, pair<ProcessId, int>>::const_iterator it = _ports.begin(); it != _ports.end();
+ ++it) {
+ if (it->second.first == pid)
+ return it->first;
+ }
- return -1;
- }
+ return -1;
+}
- void ProgramRegistry::registerPort( int port, ProcessId pid, int output ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- verify( !isPortRegistered( port ) );
- _ports.insert( make_pair( port, make_pair( pid, output ) ) );
- }
+void ProgramRegistry::registerPort(int port, ProcessId pid, int output) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ verify(!isPortRegistered(port));
+ _ports.insert(make_pair(port, make_pair(pid, output)));
+}
- void ProgramRegistry::deletePort( int port ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- if ( !isPortRegistered( port ) ) {
- return;
- }
- close( _ports.find( port )->second.second );
- _ports.erase( port );
- }
+void ProgramRegistry::deletePort(int port) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ if (!isPortRegistered(port)) {
+ return;
+ }
+ close(_ports.find(port)->second.second);
+ _ports.erase(port);
+}
- void ProgramRegistry::getRegisteredPorts( vector<int> &ports ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- for( map<int,pair<ProcessId,int> >::const_iterator i = _ports.begin(); i != _ports.end();
- ++i ) {
- ports.push_back( i->first );
- }
- }
+void ProgramRegistry::getRegisteredPorts(vector<int>& ports) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ for (map<int, pair<ProcessId, int>>::const_iterator i = _ports.begin(); i != _ports.end();
+ ++i) {
+ ports.push_back(i->first);
+ }
+}
- bool ProgramRegistry::isPidRegistered( ProcessId pid ) const {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- return _pids.count( pid ) == 1;
- }
+bool ProgramRegistry::isPidRegistered(ProcessId pid) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ return _pids.count(pid) == 1;
+}
- void ProgramRegistry::registerPid( ProcessId pid, int output ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- verify( !isPidRegistered( pid ) );
- _pids.insert( make_pair( pid, output ) );
- }
+void ProgramRegistry::registerPid(ProcessId pid, int output) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ verify(!isPidRegistered(pid));
+ _pids.insert(make_pair(pid, output));
+}
- void ProgramRegistry::deletePid(ProcessId pid) {
- stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
- if (!isPidRegistered(pid)) {
- int port = portForPid(pid);
- if (port < 0) return;
- deletePort(port);
- return;
- }
- close(_pids.find(pid)->second);
- _pids.erase(pid);
- }
+void ProgramRegistry::deletePid(ProcessId pid) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ if (!isPidRegistered(pid)) {
+ int port = portForPid(pid);
+ if (port < 0)
+ return;
+ deletePort(port);
+ return;
+ }
+ close(_pids.find(pid)->second);
+ _pids.erase(pid);
+}
- void ProgramRegistry::getRegisteredPids( vector<ProcessId> &pids ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- for( map<ProcessId,int>::const_iterator i = _pids.begin(); i != _pids.end(); ++i ) {
- pids.push_back( i->first );
- }
- }
+void ProgramRegistry::getRegisteredPids(vector<ProcessId>& pids) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ for (map<ProcessId, int>::const_iterator i = _pids.begin(); i != _pids.end(); ++i) {
+ pids.push_back(i->first);
+ }
+}
- ProgramRegistry &registry = *( new ProgramRegistry() );
+ProgramRegistry& registry = *(new ProgramRegistry());
- void goingAwaySoon() {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- mongo::dbexitCalled = true;
- }
+void goingAwaySoon() {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ mongo::dbexitCalled = true;
+}
- void ProgramOutputMultiplexer::appendLine( int port, ProcessId pid, const char *line ) {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- if( mongo::dbexitCalled ) throw "program is terminating";
- stringstream buf;
- if ( port > 0 )
- buf << " m" << port << "| " << line;
- else
- buf << "sh" << pid << "| " << line;
- printf( "%s\n", buf.str().c_str() ); // cout << buf.str() << endl;
- fflush(stdout); // not implicit if stdout isn't directly outputting to a console.
- _buffer << buf.str() << endl;
- }
+void ProgramOutputMultiplexer::appendLine(int port, ProcessId pid, const char* line) {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ if (mongo::dbexitCalled)
+ throw "program is terminating";
+ stringstream buf;
+ if (port > 0)
+ buf << " m" << port << "| " << line;
+ else
+ buf << "sh" << pid << "| " << line;
+ printf("%s\n", buf.str().c_str()); // cout << buf.str() << endl;
+ fflush(stdout); // not implicit if stdout isn't directly outputting to a console.
+ _buffer << buf.str() << endl;
+}
- string ProgramOutputMultiplexer::str() const {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- string ret = _buffer.str();
- size_t len = ret.length();
- if ( len > 100000 ) {
- ret = ret.substr( len - 100000, 100000 );
- }
- return ret;
- }
-
- void ProgramOutputMultiplexer::clear() {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- _buffer.str( "" );
- }
-
- ProgramRunner::ProgramRunner( const BSONObj &args ) {
- verify( !args.isEmpty() );
+string ProgramOutputMultiplexer::str() const {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ string ret = _buffer.str();
+ size_t len = ret.length();
+ if (len > 100000) {
+ ret = ret.substr(len - 100000, 100000);
+ }
+ return ret;
+}
+
+void ProgramOutputMultiplexer::clear() {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ _buffer.str("");
+}
+
+ProgramRunner::ProgramRunner(const BSONObj& args) {
+ verify(!args.isEmpty());
- string program( args.firstElement().valuestrsafe() );
- verify( !program.empty() );
- boost::filesystem::path programPath = findProgram(program);
+ string program(args.firstElement().valuestrsafe());
+ verify(!program.empty());
+ boost::filesystem::path programPath = findProgram(program);
- string prefix( "mongod-" );
- bool isMongodProgram =
- string("mongod") == program ||
- program.compare( 0, prefix.size(), prefix ) == 0;
+ string prefix("mongod-");
+ bool isMongodProgram =
+ string("mongod") == program || program.compare(0, prefix.size(), prefix) == 0;
- prefix = "mongos-";
- bool isMongosProgram =
- string("mongos") == program ||
- program.compare( 0, prefix.size(), prefix ) == 0;
+ prefix = "mongos-";
+ bool isMongosProgram =
+ string("mongos") == program || program.compare(0, prefix.size(), prefix) == 0;
#if 0
if (isMongosProgram == "mongos") {
@@ -227,618 +233,607 @@ namespace mongo {
}
#endif
- _argv.push_back( programPath.string() );
+ _argv.push_back(programPath.string());
- _port = -1;
+ _port = -1;
- BSONObjIterator j( args );
- j.next(); // skip program name (handled above)
- while(j.more()) {
- BSONElement e = j.next();
- string str;
- if ( e.isNumber() ) {
- stringstream ss;
- ss << e.number();
- str = ss.str();
- }
- else {
- verify( e.type() == mongo::String );
- str = e.valuestr();
- }
- if ( str == "--port" )
- _port = -2;
- else if ( _port == -2 )
- _port = strtol( str.c_str(), 0, 10 );
- _argv.push_back(str);
- }
+ BSONObjIterator j(args);
+ j.next(); // skip program name (handled above)
+ while (j.more()) {
+ BSONElement e = j.next();
+ string str;
+ if (e.isNumber()) {
+ stringstream ss;
+ ss << e.number();
+ str = ss.str();
+ } else {
+ verify(e.type() == mongo::String);
+ str = e.valuestr();
+ }
+ if (str == "--port")
+ _port = -2;
+ else if (_port == -2)
+ _port = strtol(str.c_str(), 0, 10);
+ _argv.push_back(str);
+ }
- if ( ! isMongodProgram && ! isMongosProgram && program != "mongobridge" )
- _port = 0;
- else {
- if ( _port <= 0 )
- log() << "error: a port number is expected when running " << program << " from the shell" << endl;
- verify( _port > 0 );
- }
- if ( _port > 0 ) {
- bool haveDbForPort = registry.isPortRegistered( _port );
- if ( haveDbForPort ) {
- log() << "already have db for port: " << _port << endl;
- verify( !haveDbForPort );
- }
- }
+ if (!isMongodProgram && !isMongosProgram && program != "mongobridge")
+ _port = 0;
+ else {
+ if (_port <= 0)
+ log() << "error: a port number is expected when running " << program
+ << " from the shell" << endl;
+ verify(_port > 0);
+ }
+ if (_port > 0) {
+ bool haveDbForPort = registry.isPortRegistered(_port);
+ if (haveDbForPort) {
+ log() << "already have db for port: " << _port << endl;
+ verify(!haveDbForPort);
}
+ }
+}
- void ProgramRunner::start() {
- int pipeEnds[ 2 ];
- int status = pipe(pipeEnds);
- if (status != 0) {
- error() << "failed to create pipe: " << errnoWithDescription() << endl;
- fassertFailed(16701);
- }
-
- fflush( 0 );
- launchProcess(pipeEnds[1]); //sets _pid
+void ProgramRunner::start() {
+ int pipeEnds[2];
+ int status = pipe(pipeEnds);
+ if (status != 0) {
+ error() << "failed to create pipe: " << errnoWithDescription() << endl;
+ fassertFailed(16701);
+ }
- {
- stringstream ss;
- ss << "shell: started program (sh" << _pid << "): ";
- for (unsigned i = 0; i < _argv.size(); i++) {
- ss << " " << _argv[i];
- }
- log() << ss.str() << endl;
- }
+ fflush(0);
+ launchProcess(pipeEnds[1]); // sets _pid
- if ( _port > 0 )
- registry.registerPort( _port, _pid, pipeEnds[ 1 ] );
- else
- registry.registerPid( _pid, pipeEnds[ 1 ] );
- _pipe = pipeEnds[ 0 ];
+ {
+ stringstream ss;
+ ss << "shell: started program (sh" << _pid << "): ";
+ for (unsigned i = 0; i < _argv.size(); i++) {
+ ss << " " << _argv[i];
}
+ log() << ss.str() << endl;
+ }
- void ProgramRunner::operator()() {
- try {
- // This assumes there aren't any 0's in the mongo program output.
- // Hope that's ok.
- const unsigned bufSize = 128 * 1024;
- char buf[ bufSize ];
- char temp[ bufSize ];
- char *start = buf;
- while( 1 ) {
- int lenToRead = ( bufSize - 1 ) - ( start - buf );
- if ( lenToRead <= 0 ) {
- log() << "error: lenToRead: " << lenToRead << endl;
- log() << "first 300: " << string(buf,0,300) << endl;
- }
- verify( lenToRead > 0 );
- int ret = read( _pipe, (void *)start, lenToRead );
- if( mongo::dbexitCalled )
- break;
- verify( ret != -1 );
- start[ ret ] = '\0';
- if ( strlen( start ) != unsigned( ret ) )
- programOutputLogger.appendLine( _port, _pid, "WARNING: mongod wrote null bytes to output" );
- char *last = buf;
- for( char *i = strchr( buf, '\n' ); i; last = i + 1, i = strchr( last, '\n' ) ) {
- *i = '\0';
- programOutputLogger.appendLine( _port, _pid, last );
- }
- if ( ret == 0 ) {
- if ( *last )
- programOutputLogger.appendLine( _port, _pid, last );
- close( _pipe );
- break;
- }
- if ( last != buf ) {
- strncpy( temp, last, bufSize );
- temp[ bufSize-1 ] = '\0';
- strncpy( buf, temp, bufSize );
- buf[ bufSize-1 ] = '\0';
- }
- else {
- verify( strlen( buf ) < bufSize );
- }
- start = buf + strlen( buf );
- }
- }
- catch(...) {
- }
- }
-
- boost::filesystem::path ProgramRunner::findProgram( const string &prog ) {
- boost::filesystem::path p = prog;
+ if (_port > 0)
+ registry.registerPort(_port, _pid, pipeEnds[1]);
+ else
+ registry.registerPid(_pid, pipeEnds[1]);
+ _pipe = pipeEnds[0];
+}
+
+void ProgramRunner::operator()() {
+ try {
+ // This assumes there aren't any 0's in the mongo program output.
+ // Hope that's ok.
+ const unsigned bufSize = 128 * 1024;
+ char buf[bufSize];
+ char temp[bufSize];
+ char* start = buf;
+ while (1) {
+ int lenToRead = (bufSize - 1) - (start - buf);
+ if (lenToRead <= 0) {
+ log() << "error: lenToRead: " << lenToRead << endl;
+ log() << "first 300: " << string(buf, 0, 300) << endl;
+ }
+ verify(lenToRead > 0);
+ int ret = read(_pipe, (void*)start, lenToRead);
+ if (mongo::dbexitCalled)
+ break;
+ verify(ret != -1);
+ start[ret] = '\0';
+ if (strlen(start) != unsigned(ret))
+ programOutputLogger.appendLine(
+ _port, _pid, "WARNING: mongod wrote null bytes to output");
+ char* last = buf;
+ for (char* i = strchr(buf, '\n'); i; last = i + 1, i = strchr(last, '\n')) {
+ *i = '\0';
+ programOutputLogger.appendLine(_port, _pid, last);
+ }
+ if (ret == 0) {
+ if (*last)
+ programOutputLogger.appendLine(_port, _pid, last);
+ close(_pipe);
+ break;
+ }
+ if (last != buf) {
+ strncpy(temp, last, bufSize);
+ temp[bufSize - 1] = '\0';
+ strncpy(buf, temp, bufSize);
+ buf[bufSize - 1] = '\0';
+ } else {
+ verify(strlen(buf) < bufSize);
+ }
+ start = buf + strlen(buf);
+ }
+ } catch (...) {
+ }
+}
+
+boost::filesystem::path ProgramRunner::findProgram(const string& prog) {
+ boost::filesystem::path p = prog;
#ifdef _WIN32
- // The system programs either come versioned in the form of <utility>-<major.minor>
- // (e.g., mongorestore-2.4) or just <utility>. For windows, the appropriate extension
- // needs to be appended.
- //
- if (p.extension() != ".exe") {
- p = prog + ".exe";
- }
+ // The system programs either come versioned in the form of <utility>-<major.minor>
+ // (e.g., mongorestore-2.4) or just <utility>. For windows, the appropriate extension
+ // needs to be appended.
+ //
+ if (p.extension() != ".exe") {
+ p = prog + ".exe";
+ }
#endif
- if( boost::filesystem::exists(p) ) {
+ if (boost::filesystem::exists(p)) {
#ifndef _WIN32
- p = boost::filesystem::initial_path() / p;
+ p = boost::filesystem::initial_path() / p;
#endif
- return p;
- }
-
- {
- boost::filesystem::path t = boost::filesystem::current_path() / p;
- if( boost::filesystem::exists(t) ) return t;
- }
+ return p;
+ }
- {
- boost::filesystem::path t = boost::filesystem::initial_path() / p;
- if( boost::filesystem::exists(t) ) return t;
- }
+ {
+ boost::filesystem::path t = boost::filesystem::current_path() / p;
+ if (boost::filesystem::exists(t))
+ return t;
+ }
- return p; // not found; might find via system path
- }
+ {
+ boost::filesystem::path t = boost::filesystem::initial_path() / p;
+ if (boost::filesystem::exists(t))
+ return t;
+ }
- void ProgramRunner::launchProcess( int child_stdout ) {
+ return p; // not found; might find via system path
+}
+
+void ProgramRunner::launchProcess(int child_stdout) {
#ifdef _WIN32
- stringstream ss;
- for( unsigned i=0; i < _argv.size(); i++ ) {
- if (i) ss << ' ';
- if (_argv[i].find(' ') == string::npos)
- ss << _argv[i];
- else {
- ss << '"';
- // escape all embedded quotes
- for (size_t j=0; j<_argv[i].size(); ++j) {
- if (_argv[i][j]=='"') ss << '\\';
- ss << _argv[i][j];
- }
- ss << '"';
- }
- }
+ stringstream ss;
+ for (unsigned i = 0; i < _argv.size(); i++) {
+ if (i)
+ ss << ' ';
+ if (_argv[i].find(' ') == string::npos)
+ ss << _argv[i];
+ else {
+ ss << '"';
+ // escape all embedded quotes
+ for (size_t j = 0; j < _argv[i].size(); ++j) {
+ if (_argv[i][j] == '"')
+ ss << '\\';
+ ss << _argv[i][j];
+ }
+ ss << '"';
+ }
+ }
- string args = ss.str();
-
- std::unique_ptr<TCHAR[]> args_tchar (new TCHAR[args.size() + 1]);
- size_t i;
- for(i=0; i < args.size(); i++)
- args_tchar[i] = args[i];
- args_tchar[i] = 0;
-
- HANDLE h = (HANDLE)_get_osfhandle(child_stdout);
- verify(h != INVALID_HANDLE_VALUE);
- verify(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1));
-
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- si.hStdError = h;
- si.hStdOutput = h;
- si.dwFlags |= STARTF_USESTDHANDLES;
-
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(pi));
-
- bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0;
- if (!success) {
- LPSTR lpMsgBuf=0;
- DWORD dw = GetLastError();
- FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- dw,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPSTR)&lpMsgBuf,
- 0, NULL );
- stringstream ss;
- ss << "couldn't start process " << _argv[0] << "; " << lpMsgBuf;
- uassert(14042, ss.str(), success);
- LocalFree(lpMsgBuf);
- }
+ string args = ss.str();
+
+ std::unique_ptr<TCHAR[]> args_tchar(new TCHAR[args.size() + 1]);
+ size_t i;
+ for (i = 0; i < args.size(); i++)
+ args_tchar[i] = args[i];
+ args_tchar[i] = 0;
+
+ HANDLE h = (HANDLE)_get_osfhandle(child_stdout);
+ verify(h != INVALID_HANDLE_VALUE);
+ verify(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1));
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.hStdError = h;
+ si.hStdOutput = h;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(pi));
+
+ bool success =
+ CreateProcess(NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0;
+ if (!success) {
+ LPSTR lpMsgBuf = 0;
+ DWORD dw = GetLastError();
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&lpMsgBuf,
+ 0,
+ NULL);
+ stringstream ss;
+ ss << "couldn't start process " << _argv[0] << "; " << lpMsgBuf;
+ uassert(14042, ss.str(), success);
+ LocalFree(lpMsgBuf);
+ }
- CloseHandle(pi.hThread);
+ CloseHandle(pi.hThread);
- _pid = ProcessId::fromNative(pi.dwProcessId);
- registry._handles.insert( make_pair( _pid, pi.hProcess ) );
+ _pid = ProcessId::fromNative(pi.dwProcessId);
+ registry._handles.insert(make_pair(_pid, pi.hProcess));
#else
- unique_ptr<const char *[]> argvStorage( new const char* [_argv.size()+1] );
- const char** argv = argvStorage.get();
- for (unsigned i=0; i < _argv.size(); i++) {
- argv[i] = _argv[i].c_str();
- }
- argv[_argv.size()] = 0;
-
- unique_ptr<const char *[]> envStorage( new const char* [2] );
- const char** env = envStorage.get();
- env[0] = NULL;
- env[1] = NULL;
+ unique_ptr<const char* []> argvStorage(new const char* [_argv.size() + 1]);
+ const char** argv = argvStorage.get();
+ for (unsigned i = 0; i < _argv.size(); i++) {
+ argv[i] = _argv[i].c_str();
+ }
+ argv[_argv.size()] = 0;
- pid_t nativePid = fork();
- _pid = ProcessId::fromNative(nativePid);
- // Async signal unsafe functions should not be called in the child process.
+ unique_ptr<const char* []> envStorage(new const char* [2]);
+ const char** env = envStorage.get();
+ env[0] = NULL;
+ env[1] = NULL;
- verify( nativePid != -1 );
- if ( nativePid == 0 ) {
- // DON'T ASSERT IN THIS BLOCK - very bad things will happen
+ pid_t nativePid = fork();
+ _pid = ProcessId::fromNative(nativePid);
+ // Async signal unsafe functions should not be called in the child process.
- if ( dup2( child_stdout, STDOUT_FILENO ) == -1 ||
- dup2( child_stdout, STDERR_FILENO ) == -1 ) {
+ verify(nativePid != -1);
+ if (nativePid == 0) {
+ // DON'T ASSERT IN THIS BLOCK - very bad things will happen
- // Async signal unsafe code reporting a terminal error condition.
- cout << "Unable to dup2 child output: " << errnoWithDescription() << endl;
- quickExit(-1); //do not pass go, do not call atexit handlers
- }
+ if (dup2(child_stdout, STDOUT_FILENO) == -1 || dup2(child_stdout, STDERR_FILENO) == -1) {
+ // Async signal unsafe code reporting a terminal error condition.
+ cout << "Unable to dup2 child output: " << errnoWithDescription() << endl;
+ quickExit(-1); // do not pass go, do not call atexit handlers
+ }
- // NOTE execve is async signal safe, but it is not clear that execvp is async
- // signal safe.
- execvp( argv[ 0 ], const_cast<char**>(argv) );
+ // NOTE execve is async signal safe, but it is not clear that execvp is async
+ // signal safe.
+ execvp(argv[0], const_cast<char**>(argv));
- // Async signal unsafe code reporting a terminal error condition.
- cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl;
- quickExit(-1);
- }
+ // Async signal unsafe code reporting a terminal error condition.
+ cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl;
+ quickExit(-1);
+ }
#endif
- }
+}
- //returns true if process exited
- bool wait_for_pid(ProcessId pid, bool block=true, int* exit_code=NULL) {
+// returns true if process exited
+bool wait_for_pid(ProcessId pid, bool block = true, int* exit_code = NULL) {
#ifdef _WIN32
- verify(registry._handles.count(pid));
- HANDLE h = registry._handles[pid];
+ verify(registry._handles.count(pid));
+ HANDLE h = registry._handles[pid];
- if (block) {
- if (WaitForSingleObject(h, INFINITE)) {
- log() << "WaitForSingleObject failed: " << errnoWithDescription();
- }
- }
+ if (block) {
+ if (WaitForSingleObject(h, INFINITE)) {
+ log() << "WaitForSingleObject failed: " << errnoWithDescription();
+ }
+ }
- DWORD tmp;
- if(GetExitCodeProcess(h, &tmp)) {
- if ( tmp == STILL_ACTIVE ) {
- if (block)
- log() << "Process is STILL_ACTIVE even after blocking";
- return false;
- }
- CloseHandle(h);
- registry._handles.erase(pid);
- if (exit_code)
- *exit_code = tmp;
- return true;
- }
- else {
- log() << "GetExitCodeProcess failed: " << errnoWithDescription();
- return false;
- }
+ DWORD tmp;
+ if (GetExitCodeProcess(h, &tmp)) {
+ if (tmp == STILL_ACTIVE) {
+ if (block)
+ log() << "Process is STILL_ACTIVE even after blocking";
+ return false;
+ }
+ CloseHandle(h);
+ registry._handles.erase(pid);
+ if (exit_code)
+ *exit_code = tmp;
+ return true;
+ } else {
+ log() << "GetExitCodeProcess failed: " << errnoWithDescription();
+ return false;
+ }
#else
- int tmp;
- bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG)));
- if (exit_code)
- *exit_code = WEXITSTATUS(tmp);
- return ret;
+ int tmp;
+ bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG)));
+ if (exit_code)
+ *exit_code = WEXITSTATUS(tmp);
+ return ret;
#endif
- }
+}
- BSONObj RawMongoProgramOutput( const BSONObj &args, void* data ) {
- return BSON( "" << programOutputLogger.str() );
- }
-
- BSONObj ClearRawMongoProgramOutput( const BSONObj &args, void* data ) {
- programOutputLogger.clear();
- return undefinedReturn;
- }
+BSONObj RawMongoProgramOutput(const BSONObj& args, void* data) {
+ return BSON("" << programOutputLogger.str());
+}
- BSONObj CheckProgram(const BSONObj& args, void* data) {
- ProcessId pid = ProcessId::fromNative(singleArg(args).numberInt());
- bool isDead = wait_for_pid(pid, false);
- if (isDead) registry.deletePid(pid);
- return BSON( string( "" ) << (!isDead) );
- }
+BSONObj ClearRawMongoProgramOutput(const BSONObj& args, void* data) {
+ programOutputLogger.clear();
+ return undefinedReturn;
+}
- BSONObj WaitProgram( const BSONObj& a, void* data ) {
- ProcessId pid = ProcessId::fromNative(singleArg( a ).numberInt());
- int exit_code = -123456; // sentinel value
- wait_for_pid( pid, true, &exit_code );
- registry.deletePid( pid );
- return BSON( string("") << exit_code);
- }
+BSONObj CheckProgram(const BSONObj& args, void* data) {
+ ProcessId pid = ProcessId::fromNative(singleArg(args).numberInt());
+ bool isDead = wait_for_pid(pid, false);
+ if (isDead)
+ registry.deletePid(pid);
+ return BSON(string("") << (!isDead));
+}
- BSONObj StartMongoProgram( const BSONObj &a, void* data ) {
- _nokillop = true;
- ProgramRunner r( a );
- r.start();
- stdx::thread t( r );
- return BSON( string( "" ) << r.pid().asLongLong() );
- }
+BSONObj WaitProgram(const BSONObj& a, void* data) {
+ ProcessId pid = ProcessId::fromNative(singleArg(a).numberInt());
+ int exit_code = -123456; // sentinel value
+ wait_for_pid(pid, true, &exit_code);
+ registry.deletePid(pid);
+ return BSON(string("") << exit_code);
+}
- BSONObj RunMongoProgram( const BSONObj &a, void* data ) {
- ProgramRunner r( a );
- r.start();
- stdx::thread t( r );
- int exit_code = -123456; // sentinel value
- wait_for_pid( r.pid(), true, &exit_code );
- if ( r.port() > 0 ) {
- registry.deletePort( r.port() );
- }
- else {
- registry.deletePid( r.pid() );
- }
- return BSON( string( "" ) << exit_code );
- }
+BSONObj StartMongoProgram(const BSONObj& a, void* data) {
+ _nokillop = true;
+ ProgramRunner r(a);
+ r.start();
+ stdx::thread t(r);
+ return BSON(string("") << r.pid().asLongLong());
+}
- BSONObj RunProgram(const BSONObj &a, void* data) {
- ProgramRunner r( a );
- r.start();
- stdx::thread t( r );
- int exit_code = -123456; // sentinel value
- wait_for_pid(r.pid(), true, &exit_code);
- registry.deletePid( r.pid() );
- return BSON( string( "" ) << exit_code );
- }
+BSONObj RunMongoProgram(const BSONObj& a, void* data) {
+ ProgramRunner r(a);
+ r.start();
+ stdx::thread t(r);
+ int exit_code = -123456; // sentinel value
+ wait_for_pid(r.pid(), true, &exit_code);
+ if (r.port() > 0) {
+ registry.deletePort(r.port());
+ } else {
+ registry.deletePid(r.pid());
+ }
+ return BSON(string("") << exit_code);
+}
- BSONObj ResetDbpath( const BSONObj &a, void* data ) {
- verify( a.nFields() == 1 );
- string path = a.firstElement().valuestrsafe();
- verify( !path.empty() );
- if ( boost::filesystem::exists( path ) )
- boost::filesystem::remove_all( path );
- boost::filesystem::create_directory( path );
- return undefinedReturn;
- }
+BSONObj RunProgram(const BSONObj& a, void* data) {
+ ProgramRunner r(a);
+ r.start();
+ stdx::thread t(r);
+ int exit_code = -123456; // sentinel value
+ wait_for_pid(r.pid(), true, &exit_code);
+ registry.deletePid(r.pid());
+ return BSON(string("") << exit_code);
+}
- BSONObj PathExists( const BSONObj &a, void* data ) {
- verify( a.nFields() == 1 );
- string path = a.firstElement().valuestrsafe();
- verify( !path.empty() );
- bool exists = boost::filesystem::exists(path);
- return BSON( string( "" ) << exists );
- }
+BSONObj ResetDbpath(const BSONObj& a, void* data) {
+ verify(a.nFields() == 1);
+ string path = a.firstElement().valuestrsafe();
+ verify(!path.empty());
+ if (boost::filesystem::exists(path))
+ boost::filesystem::remove_all(path);
+ boost::filesystem::create_directory(path);
+ return undefinedReturn;
+}
- void copyDir( const boost::filesystem::path &from, const boost::filesystem::path &to ) {
- boost::filesystem::directory_iterator end;
- boost::filesystem::directory_iterator i( from );
- while( i != end ) {
- boost::filesystem::path p = *i;
- if ( p.leaf() != "mongod.lock" && p.leaf() != "WiredTiger.lock" ) {
- if ( boost::filesystem::is_directory( p ) ) {
- boost::filesystem::path newDir = to / p.leaf();
- boost::filesystem::create_directory( newDir );
- copyDir( p, newDir );
- }
- else {
- boost::filesystem::copy_file( p, to / p.leaf() );
- }
- }
- ++i;
- }
- }
+BSONObj PathExists(const BSONObj& a, void* data) {
+ verify(a.nFields() == 1);
+ string path = a.firstElement().valuestrsafe();
+ verify(!path.empty());
+ bool exists = boost::filesystem::exists(path);
+ return BSON(string("") << exists);
+}
- // NOTE target dbpath will be cleared first
- BSONObj CopyDbpath( const BSONObj &a, void* data ) {
- verify( a.nFields() == 2 );
- BSONObjIterator i( a );
- string from = i.next().str();
- string to = i.next().str();
- verify( !from.empty() );
- verify( !to.empty() );
- if ( boost::filesystem::exists( to ) )
- boost::filesystem::remove_all( to );
- boost::filesystem::create_directory( to );
- copyDir( from, to );
- return undefinedReturn;
- }
+void copyDir(const boost::filesystem::path& from, const boost::filesystem::path& to) {
+ boost::filesystem::directory_iterator end;
+ boost::filesystem::directory_iterator i(from);
+ while (i != end) {
+ boost::filesystem::path p = *i;
+ if (p.leaf() != "mongod.lock" && p.leaf() != "WiredTiger.lock") {
+ if (boost::filesystem::is_directory(p)) {
+ boost::filesystem::path newDir = to / p.leaf();
+ boost::filesystem::create_directory(newDir);
+ copyDir(p, newDir);
+ } else {
+ boost::filesystem::copy_file(p, to / p.leaf());
+ }
+ }
+ ++i;
+ }
+}
+
+// NOTE target dbpath will be cleared first
+BSONObj CopyDbpath(const BSONObj& a, void* data) {
+ verify(a.nFields() == 2);
+ BSONObjIterator i(a);
+ string from = i.next().str();
+ string to = i.next().str();
+ verify(!from.empty());
+ verify(!to.empty());
+ if (boost::filesystem::exists(to))
+ boost::filesystem::remove_all(to);
+ boost::filesystem::create_directory(to);
+ copyDir(from, to);
+ return undefinedReturn;
+}
- inline void kill_wrapper( ProcessId pid, int sig, int port, const BSONObj& opt ) {
+inline void kill_wrapper(ProcessId pid, int sig, int port, const BSONObj& opt) {
#ifdef _WIN32
- if (sig == SIGKILL || port == 0) {
- verify( registry._handles.count(pid) );
- TerminateProcess(registry._handles[pid], 1); // returns failure for "zombie" processes.
- return;
- }
+ if (sig == SIGKILL || port == 0) {
+ verify(registry._handles.count(pid));
+ TerminateProcess(registry._handles[pid], 1); // returns failure for "zombie" processes.
+ return;
+ }
- std::string eventName = getShutdownSignalName(pid.asUInt32());
+ std::string eventName = getShutdownSignalName(pid.asUInt32());
- HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, eventName.c_str());
- if (event == NULL) {
- int gle = GetLastError();
- if (gle != ERROR_FILE_NOT_FOUND) {
- warning() << "kill_wrapper OpenEvent failed: " << errnoWithDescription();
- }
- else {
- log() << "kill_wrapper OpenEvent failed to open event to the process "
- << pid.asUInt32()
- << ". It has likely died already or server is running an older version."
- << " Attempting to shutdown through admin command.";
-
- // Back-off to the old way of shutting down the server on Windows, in case we
- // are managing a pre-2.6.0rc0 service, which did not have the event.
- //
- try {
- DBClientConnection conn;
- conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port));
-
- BSONElement authObj = opt["auth"];
-
- if (!authObj.eoo()){
- string errMsg;
- conn.auth("admin", authObj["user"].String(),
- authObj["pwd"].String(), errMsg);
-
- if (!errMsg.empty()) {
- cout << "Failed to authenticate before shutdown: "
- << errMsg << endl;
- }
- }
-
- BSONObj info;
- BSONObjBuilder b;
- b.append("shutdown", 1);
- b.append("force", 1);
- conn.runCommand("admin", b.done(), info);
- }
- catch (...) {
- // Do nothing. This command never returns data to the client and the driver
- // doesn't like that.
- //
+ HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, eventName.c_str());
+ if (event == NULL) {
+ int gle = GetLastError();
+ if (gle != ERROR_FILE_NOT_FOUND) {
+ warning() << "kill_wrapper OpenEvent failed: " << errnoWithDescription();
+ } else {
+ log() << "kill_wrapper OpenEvent failed to open event to the process " << pid.asUInt32()
+ << ". It has likely died already or server is running an older version."
+ << " Attempting to shutdown through admin command.";
+
+ // Back-off to the old way of shutting down the server on Windows, in case we
+ // are managing a pre-2.6.0rc0 service, which did not have the event.
+ //
+ try {
+ DBClientConnection conn;
+ conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port));
+
+ BSONElement authObj = opt["auth"];
+
+ if (!authObj.eoo()) {
+ string errMsg;
+ conn.auth("admin", authObj["user"].String(), authObj["pwd"].String(), errMsg);
+
+ if (!errMsg.empty()) {
+ cout << "Failed to authenticate before shutdown: " << errMsg << endl;
}
}
- return;
+
+ BSONObj info;
+ BSONObjBuilder b;
+ b.append("shutdown", 1);
+ b.append("force", 1);
+ conn.runCommand("admin", b.done(), info);
+ } catch (...) {
+ // Do nothing. This command never returns data to the client and the driver
+ // doesn't like that.
+ //
}
+ }
+ return;
+ }
- ON_BLOCK_EXIT(CloseHandle, event);
+ ON_BLOCK_EXIT(CloseHandle, event);
- bool result = SetEvent(event);
- if (!result) {
- error() << "kill_wrapper SetEvent failed: " << errnoWithDescription();
- return;
- }
+ bool result = SetEvent(event);
+ if (!result) {
+ error() << "kill_wrapper SetEvent failed: " << errnoWithDescription();
+ return;
+ }
#else
- int x = kill( pid.toNative(), sig );
- if ( x ) {
- if ( errno == ESRCH ) {
- }
- else {
- log() << "killFailed: " << errnoWithDescription() << endl;
- verify( x == 0 );
- }
- }
+ int x = kill(pid.toNative(), sig);
+ if (x) {
+ if (errno == ESRCH) {
+ } else {
+ log() << "killFailed: " << errnoWithDescription() << endl;
+ verify(x == 0);
+ }
+ }
#endif
- }
+}
- int killDb( int port, ProcessId _pid, int signal, const BSONObj& opt ) {
- ProcessId pid;
- int exitCode = 0;
- if ( port > 0 ) {
- if( !registry.isPortRegistered( port ) ) {
- log() << "No db started on port: " << port << endl;
- return 0;
- }
- pid = registry.pidForPort( port );
- }
- else {
- pid = _pid;
- }
+int killDb(int port, ProcessId _pid, int signal, const BSONObj& opt) {
+ ProcessId pid;
+ int exitCode = 0;
+ if (port > 0) {
+ if (!registry.isPortRegistered(port)) {
+ log() << "No db started on port: " << port << endl;
+ return 0;
+ }
+ pid = registry.pidForPort(port);
+ } else {
+ pid = _pid;
+ }
- kill_wrapper( pid, signal, port, opt );
+ kill_wrapper(pid, signal, port, opt);
- int i = 0;
- for( ; i < 130; ++i ) {
- if ( i == 60 ) {
- log() << "process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl;
- kill_wrapper( pid, SIGKILL, port, opt );
- }
- if(wait_for_pid(pid, false, &exitCode))
- break;
- sleepmillis( 1000 );
- }
- if ( i == 130 ) {
- log() << "failed to terminate process on port " << port << ", with pid " << pid << endl;
- verify( "Failed to terminate process" == 0 );
- }
+ int i = 0;
+ for (; i < 130; ++i) {
+ if (i == 60) {
+ log() << "process on port " << port << ", with pid " << pid
+ << " not terminated, sending sigkill" << endl;
+ kill_wrapper(pid, SIGKILL, port, opt);
+ }
+ if (wait_for_pid(pid, false, &exitCode))
+ break;
+ sleepmillis(1000);
+ }
+ if (i == 130) {
+ log() << "failed to terminate process on port " << port << ", with pid " << pid << endl;
+ verify("Failed to terminate process" == 0);
+ }
- if ( port > 0 ) {
- registry.deletePort( port );
- }
- else {
- registry.deletePid( pid );
- }
- // FIXME I think the intention here is to do an extra sleep only when SIGKILL is sent to the child process.
- // We may want to change the 4 below to 29, since values of i greater than that indicate we sent a SIGKILL.
- if ( i > 4 || signal == SIGKILL ) {
- sleepmillis( 4000 ); // allow operating system to reclaim resources
- }
+ if (port > 0) {
+ registry.deletePort(port);
+ } else {
+ registry.deletePid(pid);
+ }
+ // FIXME I think the intention here is to do an extra sleep only when SIGKILL is sent to the child process.
+ // We may want to change the 4 below to 29, since values of i greater than that indicate we sent a SIGKILL.
+ if (i > 4 || signal == SIGKILL) {
+ sleepmillis(4000); // allow operating system to reclaim resources
+ }
- return exitCode;
- }
+ return exitCode;
+}
- int killDb( int port, ProcessId _pid, int signal ) {
- BSONObj dummyOpt;
- return killDb( port, _pid, signal, dummyOpt );
- }
-
- int getSignal( const BSONObj &a ) {
- int ret = SIGTERM;
- if ( a.nFields() >= 2 ) {
- BSONObjIterator i( a );
- i.next();
- BSONElement e = i.next();
- verify( e.isNumber() );
- ret = int( e.number() );
- }
- return ret;
- }
+int killDb(int port, ProcessId _pid, int signal) {
+ BSONObj dummyOpt;
+ return killDb(port, _pid, signal, dummyOpt);
+}
- BSONObj getStopMongodOpts( const BSONObj &a ) {
- if ( a.nFields() == 3 ) {
- BSONObjIterator i( a );
- i.next();
- i.next();
- BSONElement e = i.next();
+int getSignal(const BSONObj& a) {
+ int ret = SIGTERM;
+ if (a.nFields() >= 2) {
+ BSONObjIterator i(a);
+ i.next();
+ BSONElement e = i.next();
+ verify(e.isNumber());
+ ret = int(e.number());
+ }
+ return ret;
+}
- if ( e.isABSONObj() ){
- return e.embeddedObject();
- }
- }
+BSONObj getStopMongodOpts(const BSONObj& a) {
+ if (a.nFields() == 3) {
+ BSONObjIterator i(a);
+ i.next();
+ i.next();
+ BSONElement e = i.next();
- return BSONObj();
+ if (e.isABSONObj()) {
+ return e.embeddedObject();
}
+ }
- /** stopMongoProgram(port[, signal]) */
- BSONObj StopMongoProgram( const BSONObj &a, void* data ) {
- int nFields = a.nFields();
- verify( nFields >= 1 && nFields <= 3 );
- uassert( 15853 , "stopMongo needs a number" , a.firstElement().isNumber() );
- int port = int( a.firstElement().number() );
- int code = killDb( port, ProcessId::fromNative(0), getSignal( a ), getStopMongodOpts( a ));
- log() << "shell: stopped mongo program on port " << port << endl;
- return BSON( "" << (double)code );
- }
+ return BSONObj();
+}
- BSONObj StopMongoProgramByPid( const BSONObj &a, void* data ) {
- verify( a.nFields() == 1 || a.nFields() == 2 );
- uassert( 15852 , "stopMongoByPid needs a number" , a.firstElement().isNumber() );
- ProcessId pid = ProcessId::fromNative(int( a.firstElement().number() ));
- int code = killDb( 0, pid, getSignal( a ) );
- log() << "shell: stopped mongo program on pid " << pid << endl;
- return BSON( "" << (double)code );
- }
+/** stopMongoProgram(port[, signal]) */
+BSONObj StopMongoProgram(const BSONObj& a, void* data) {
+ int nFields = a.nFields();
+ verify(nFields >= 1 && nFields <= 3);
+ uassert(15853, "stopMongo needs a number", a.firstElement().isNumber());
+ int port = int(a.firstElement().number());
+ int code = killDb(port, ProcessId::fromNative(0), getSignal(a), getStopMongodOpts(a));
+ log() << "shell: stopped mongo program on port " << port << endl;
+ return BSON("" << (double)code);
+}
- void KillMongoProgramInstances() {
- vector< int > ports;
- registry.getRegisteredPorts( ports );
- for( vector< int >::iterator i = ports.begin(); i != ports.end(); ++i )
- killDb( *i, ProcessId::fromNative(0), SIGTERM );
- vector< ProcessId > pids;
- registry.getRegisteredPids( pids );
- for( vector< ProcessId >::iterator i = pids.begin(); i != pids.end(); ++i )
- killDb( 0, *i, SIGTERM );
- }
+BSONObj StopMongoProgramByPid(const BSONObj& a, void* data) {
+ verify(a.nFields() == 1 || a.nFields() == 2);
+ uassert(15852, "stopMongoByPid needs a number", a.firstElement().isNumber());
+ ProcessId pid = ProcessId::fromNative(int(a.firstElement().number()));
+ int code = killDb(0, pid, getSignal(a));
+ log() << "shell: stopped mongo program on pid " << pid << endl;
+ return BSON("" << (double)code);
+}
- MongoProgramScope::~MongoProgramScope() {
- DESTRUCTOR_GUARD(
- KillMongoProgramInstances();
- ClearRawMongoProgramOutput( BSONObj(), 0 );
- )
- }
+void KillMongoProgramInstances() {
+ vector<int> ports;
+ registry.getRegisteredPorts(ports);
+ for (vector<int>::iterator i = ports.begin(); i != ports.end(); ++i)
+ killDb(*i, ProcessId::fromNative(0), SIGTERM);
+ vector<ProcessId> pids;
+ registry.getRegisteredPids(pids);
+ for (vector<ProcessId>::iterator i = pids.begin(); i != pids.end(); ++i)
+ killDb(0, *i, SIGTERM);
+}
- void installShellUtilsLauncher( Scope& scope ) {
- scope.injectNative( "_startMongoProgram", StartMongoProgram );
- scope.injectNative( "runProgram", RunProgram );
- scope.injectNative( "run", RunProgram );
- scope.injectNative( "_runMongoProgram", RunMongoProgram );
- scope.injectNative( "_stopMongoProgram", StopMongoProgram );
- scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid );
- scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput );
- scope.injectNative( "clearRawMongoProgramOutput", ClearRawMongoProgramOutput );
- scope.injectNative( "waitProgram" , WaitProgram );
- scope.injectNative( "checkProgram" , CheckProgram );
- scope.injectNative( "resetDbpath", ResetDbpath );
- scope.injectNative( "pathExists", PathExists );
- scope.injectNative( "copyDbpath", CopyDbpath );
- }
- }
+MongoProgramScope::~MongoProgramScope() {
+ DESTRUCTOR_GUARD(KillMongoProgramInstances(); ClearRawMongoProgramOutput(BSONObj(), 0);)
+}
+
+void installShellUtilsLauncher(Scope& scope) {
+ scope.injectNative("_startMongoProgram", StartMongoProgram);
+ scope.injectNative("runProgram", RunProgram);
+ scope.injectNative("run", RunProgram);
+ scope.injectNative("_runMongoProgram", RunMongoProgram);
+ scope.injectNative("_stopMongoProgram", StopMongoProgram);
+ scope.injectNative("stopMongoProgramByPid", StopMongoProgramByPid);
+ scope.injectNative("rawMongoProgramOutput", RawMongoProgramOutput);
+ scope.injectNative("clearRawMongoProgramOutput", ClearRawMongoProgramOutput);
+ scope.injectNative("waitProgram", WaitProgram);
+ scope.injectNative("checkProgram", CheckProgram);
+ scope.injectNative("resetDbpath", ResetDbpath);
+ scope.injectNative("pathExists", PathExists);
+ scope.injectNative("copyDbpath", CopyDbpath);
+}
+}
}
diff --git a/src/mongo/shell/shell_utils_launcher.h b/src/mongo/shell/shell_utils_launcher.h
index c0e038cc016..49ec94f91d9 100644
--- a/src/mongo/shell/shell_utils_launcher.h
+++ b/src/mongo/shell/shell_utils_launcher.h
@@ -41,88 +41,92 @@
namespace mongo {
- class Scope;
-
- namespace shell_utils {
-
- // Scoped management of mongo program instances. Simple implementation:
- // destructor kills all mongod instances created by the shell.
- struct MongoProgramScope {
- MongoProgramScope() {} // Avoid 'unused variable' warning.
- ~MongoProgramScope();
- };
- void KillMongoProgramInstances();
-
- void goingAwaySoon();
- void installShellUtilsLauncher( Scope& scope );
-
- /** Record log lines from concurrent programs. All public members are thread safe. */
- class ProgramOutputMultiplexer {
- public:
- void appendLine( int port, ProcessId pid, const char *line );
- /** @return up to 100000 characters of the most recent log output. */
- std::string str() const;
- void clear();
- private:
- std::stringstream _buffer;
- };
-
- /**
- * A registry of spawned programs that are identified by a bound port or else a system pid.
- * All public member functions are thread safe.
- *
- * TODO: Clean this up to make the semantics more consistent between pids and ports
- */
- class ProgramRegistry {
- public:
-
- bool isPortRegistered( int port ) const;
- /** @return pid for a registered port. */
- ProcessId pidForPort( int port ) const;
- /** @return port (-1 if doesn't exist) for a registered pid. */
- int portForPid( ProcessId pid ) const;
- /** Register an unregistered port. */
- void registerPort( int port, ProcessId pid, int output );
- void deletePort( int port );
- void getRegisteredPorts( std::vector<int> &ports );
-
- bool isPidRegistered( ProcessId pid ) const;
- /** Register an unregistered pid. */
- void registerPid( ProcessId pid, int output );
- void deletePid( ProcessId pid );
- void getRegisteredPids( std::vector<ProcessId> &pids );
-
- private:
- std::map<int,std::pair<ProcessId,int> > _ports;
- std::map<ProcessId,int> _pids;
- mutable boost::recursive_mutex _mutex;
+class Scope;
+
+namespace shell_utils {
+
+// Scoped management of mongo program instances. Simple implementation:
+// destructor kills all mongod instances created by the shell.
+struct MongoProgramScope {
+ MongoProgramScope() {} // Avoid 'unused variable' warning.
+ ~MongoProgramScope();
+};
+void KillMongoProgramInstances();
+
+void goingAwaySoon();
+void installShellUtilsLauncher(Scope& scope);
+
+/** Record log lines from concurrent programs. All public members are thread safe. */
+class ProgramOutputMultiplexer {
+public:
+ void appendLine(int port, ProcessId pid, const char* line);
+ /** @return up to 100000 characters of the most recent log output. */
+ std::string str() const;
+ void clear();
+
+private:
+ std::stringstream _buffer;
+};
+
+/**
+ * A registry of spawned programs that are identified by a bound port or else a system pid.
+ * All public member functions are thread safe.
+ *
+ * TODO: Clean this up to make the semantics more consistent between pids and ports
+ */
+class ProgramRegistry {
+public:
+ bool isPortRegistered(int port) const;
+ /** @return pid for a registered port. */
+ ProcessId pidForPort(int port) const;
+ /** @return port (-1 if doesn't exist) for a registered pid. */
+ int portForPid(ProcessId pid) const;
+ /** Register an unregistered port. */
+ void registerPort(int port, ProcessId pid, int output);
+ void deletePort(int port);
+ void getRegisteredPorts(std::vector<int>& ports);
+
+ bool isPidRegistered(ProcessId pid) const;
+ /** Register an unregistered pid. */
+ void registerPid(ProcessId pid, int output);
+ void deletePid(ProcessId pid);
+ void getRegisteredPids(std::vector<ProcessId>& pids);
+
+private:
+ std::map<int, std::pair<ProcessId, int>> _ports;
+ std::map<ProcessId, int> _pids;
+ mutable boost::recursive_mutex _mutex;
#ifdef _WIN32
- public:
- std::map<ProcessId,HANDLE> _handles;
+public:
+ std::map<ProcessId, HANDLE> _handles;
#endif
- };
-
- /** Helper class for launching a program and logging its output. */
- class ProgramRunner {
- public:
- /** @param args The program's arguments, including the program name. */
- ProgramRunner( const BSONObj &args );
- /** Launch the program. */
- void start();
- /** Continuously read the program's output, generally from a special purpose thread. */
- void operator()();
- ProcessId pid() const { return _pid; }
- int port() const { return _port; }
-
- private:
- boost::filesystem::path findProgram( const std::string &prog );
- void launchProcess( int child_stdout );
-
- std::vector<std::string> _argv;
- int _port;
- int _pipe;
- ProcessId _pid;
- };
+};
+
+/** Helper class for launching a program and logging its output. */
+class ProgramRunner {
+public:
+ /** @param args The program's arguments, including the program name. */
+ ProgramRunner(const BSONObj& args);
+ /** Launch the program. */
+ void start();
+ /** Continuously read the program's output, generally from a special purpose thread. */
+ void operator()();
+ ProcessId pid() const {
+ return _pid;
+ }
+ int port() const {
+ return _port;
}
+
+private:
+ boost::filesystem::path findProgram(const std::string& prog);
+ void launchProcess(int child_stdout);
+
+ std::vector<std::string> _argv;
+ int _port;
+ int _pipe;
+ ProcessId _pid;
+};
+}
}