summaryrefslogtreecommitdiff
path: root/src/mongo/shell
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2012-08-29 20:54:51 +0200
committerAntonin Kral <a.kral@bobek.cz>2012-08-29 20:54:51 +0200
commit83957b73f9177f6e38bd5375bd93ca1f6a47188c (patch)
treef20b7d6ac9a9c64ff5bb6b5910a24abbb356b1d5 /src/mongo/shell
parent5071d203970edd4c995493d810abe20987e76fe9 (diff)
Imported Upstream version 2.2.0upstream/2.2.0
Diffstat (limited to 'src/mongo/shell')
-rw-r--r--src/mongo/shell/collection.js892
-rw-r--r--src/mongo/shell/createCPPfromJavaScriptFiles.js105
-rw-r--r--src/mongo/shell/db.js926
-rw-r--r--src/mongo/shell/dbshell.cpp1006
-rw-r--r--src/mongo/shell/linenoise.cpp2652
-rw-r--r--src/mongo/shell/linenoise.h54
-rw-r--r--src/mongo/shell/linenoise_utf8.cpp348
-rw-r--r--src/mongo/shell/linenoise_utf8.h234
-rw-r--r--src/mongo/shell/mk_wcwidth.cpp309
-rw-r--r--src/mongo/shell/mk_wcwidth.h62
-rwxr-xr-xsrc/mongo/shell/mongo.icobin0 -> 1078 bytes
-rw-r--r--src/mongo/shell/mongo.js102
-rw-r--r--src/mongo/shell/mongo.sln39
-rwxr-xr-xsrc/mongo/shell/mongo.vcxproj1244
-rw-r--r--src/mongo/shell/mongo.vcxproj.filters1208
-rw-r--r--src/mongo/shell/mr.js95
-rw-r--r--src/mongo/shell/query.js379
-rw-r--r--src/mongo/shell/replsetbridge.js26
-rw-r--r--src/mongo/shell/replsettest.js1031
-rwxr-xr-xsrc/mongo/shell/servers.js703
-rw-r--r--src/mongo/shell/servers_misc.js284
-rw-r--r--src/mongo/shell/shardingtest.js996
-rw-r--r--src/mongo/shell/shell_utils.cpp235
-rw-r--r--src/mongo/shell/shell_utils.h69
-rw-r--r--src/mongo/shell/shell_utils_extended.cpp225
-rw-r--r--src/mongo/shell/shell_utils_extended.h28
-rw-r--r--src/mongo/shell/shell_utils_launcher.cpp752
-rw-r--r--src/mongo/shell/shell_utils_launcher.h117
-rw-r--r--src/mongo/shell/utils.js1940
-rw-r--r--src/mongo/shell/utils_sh.js348
30 files changed, 16409 insertions, 0 deletions
diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js
new file mode 100644
index 00000000000..342f07b936f
--- /dev/null
+++ b/src/mongo/shell/collection.js
@@ -0,0 +1,892 @@
+// @file collection.js - DBCollection support in the mongo shell
+// db.colName is a DBCollection object
+// or db["colName"]
+
+if ( ( typeof DBCollection ) == "undefined" ){
+ DBCollection = function( mongo , db , shortName , fullName ){
+ this._mongo = mongo;
+ this._db = db;
+ this._shortName = shortName;
+ this._fullName = fullName;
+
+ this.verify();
+ }
+}
+
+DBCollection.prototype.verify = function(){
+ assert( this._fullName , "no fullName" );
+ assert( this._shortName , "no shortName" );
+ assert( this._db , "no db" );
+
+ assert.eq( this._fullName , this._db._name + "." + this._shortName , "name mismatch" );
+
+ assert( this._mongo , "no mongo in DBCollection" );
+}
+
+DBCollection.prototype.getName = function(){
+ return this._shortName;
+}
+
+DBCollection.prototype.help = function () {
+ var shortName = this.getName();
+ print("DBCollection help");
+ print("\tdb." + shortName + ".find().help() - show DBCursor help");
+ print("\tdb." + shortName + ".count()");
+ print("\tdb." + shortName + ".copyTo(newColl) - duplicates collection by copying all documents to newColl; no indexes are copied.");
+ print("\tdb." + shortName + ".convertToCapped(maxBytes) - calls {convertToCapped:'" + shortName + "', size:maxBytes}} command");
+ print("\tdb." + shortName + ".dataSize()");
+ print("\tdb." + shortName + ".distinct( key ) - eg. db." + shortName + ".distinct( 'x' )");
+ print("\tdb." + shortName + ".drop() drop the collection");
+ print("\tdb." + shortName + ".dropIndex(name)");
+ print("\tdb." + shortName + ".dropIndexes()");
+ print("\tdb." + shortName + ".ensureIndex(keypattern[,options]) - options is an object with these possible fields: name, unique, dropDups");
+ print("\tdb." + shortName + ".reIndex()");
+ print("\tdb." + shortName + ".find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return.");
+ print("\t e.g. db." + shortName + ".find( {x:77} , {name:1, x:1} )");
+ print("\tdb." + shortName + ".find(...).count()");
+ print("\tdb." + shortName + ".find(...).limit(n)");
+ print("\tdb." + shortName + ".find(...).skip(n)");
+ print("\tdb." + shortName + ".find(...).sort(...)");
+ print("\tdb." + shortName + ".findOne([query])");
+ print("\tdb." + shortName + ".findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )");
+ print("\tdb." + shortName + ".getDB() get DB object associated with collection");
+ print("\tdb." + shortName + ".getIndexes()");
+ print("\tdb." + shortName + ".group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )");
+ print("\tdb." + shortName + ".insert(obj)");
+ print("\tdb." + shortName + ".mapReduce( mapFunction , reduceFunction , <optional params> )");
+ print("\tdb." + shortName + ".remove(query)");
+ print("\tdb." + shortName + ".renameCollection( newName , <dropTarget> ) renames the collection.");
+ print("\tdb." + shortName + ".runCommand( name , <options> ) runs a db command with the given name where the first param is the collection name");
+ print("\tdb." + shortName + ".save(obj)");
+ print("\tdb." + shortName + ".stats()");
+ print("\tdb." + shortName + ".storageSize() - includes free space allocated to this collection");
+ print("\tdb." + shortName + ".totalIndexSize() - size in bytes of all the indexes");
+ print("\tdb." + shortName + ".totalSize() - storage allocated for all data and indexes");
+ print("\tdb." + shortName + ".update(query, object[, upsert_bool, multi_bool]) - instead of two flags, you can pass an object with fields: upsert, multi");
+ print("\tdb." + shortName + ".validate( <full> ) - SLOW");;
+ print("\tdb." + shortName + ".getShardVersion() - only for use with sharding");
+ print("\tdb." + shortName + ".getShardDistribution() - prints statistics about data distribution in the cluster");
+ print("\tdb." + shortName + ".getSplitKeysForChunks( <maxChunkSize> ) - calculates split points over all chunks and returns splitter function");
+ return __magicNoPrint;
+}
+
+DBCollection.prototype.getFullName = function(){
+ return this._fullName;
+}
+DBCollection.prototype.getMongo = function(){
+ return this._db.getMongo();
+}
+DBCollection.prototype.getDB = function(){
+ return this._db;
+}
+
+DBCollection.prototype._dbCommand = function( cmd , params ){
+ if ( typeof( cmd ) == "object" )
+ return this._db._dbCommand( cmd );
+
+ var c = {};
+ c[cmd] = this.getName();
+ if ( params )
+ Object.extend( c , params );
+ return this._db._dbCommand( c );
+}
+
+DBCollection.prototype.runCommand = DBCollection.prototype._dbCommand;
+
+DBCollection.prototype._massageObject = function( q ){
+ if ( ! q )
+ return {};
+
+ var type = typeof q;
+
+ if ( type == "function" )
+ return { $where : q };
+
+ if ( q.isObjectId )
+ return { _id : q };
+
+ if ( type == "object" )
+ return q;
+
+ if ( type == "string" ){
+ if ( q.length == 24 )
+ return { _id : q };
+
+ return { $where : q };
+ }
+
+ throw "don't know how to massage : " + type;
+
+}
+
+
+DBCollection.prototype._validateObject = function( o ){
+ if ( o._ensureSpecial && o._checkModify )
+ throw "can't save a DBQuery object";
+}
+
+DBCollection._allowedFields = { $id : 1 , $ref : 1 , $db : 1 , $MinKey : 1, $MaxKey : 1 };
+
+DBCollection.prototype._validateForStorage = function( o ){
+ this._validateObject( o );
+ for ( var k in o ){
+ if ( k.indexOf( "." ) >= 0 ) {
+ throw "can't have . in field names [" + k + "]" ;
+ }
+
+ if ( k.indexOf( "$" ) == 0 && ! DBCollection._allowedFields[k] ) {
+ throw "field names cannot start with $ [" + k + "]";
+ }
+
+ if ( o[k] !== null && typeof( o[k] ) === "object" ) {
+ this._validateForStorage( o[k] );
+ }
+ }
+};
+
+
+DBCollection.prototype.find = function( query , fields , limit , skip, batchSize, options ){
+ return new DBQuery( this._mongo , this._db , this ,
+ this._fullName , this._massageObject( query ) , fields , limit , skip , batchSize , options || this.getQueryOptions() );
+}
+
+DBCollection.prototype.findOne = function( query , fields, options ){
+ var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields ,
+ -1 /* limit */ , 0 /* skip*/, 0 /* batchSize */ , options || this.getQueryOptions() /* options */ );
+ if ( ! cursor.hasNext() )
+ return null;
+ var ret = cursor.next();
+ if ( cursor.hasNext() ) throw "findOne has more than 1 result!";
+ if ( ret.$err )
+ throw "error " + tojson( ret );
+ return ret;
+}
+
+DBCollection.prototype.insert = function( obj , _allow_dot ){
+ if ( ! obj )
+ throw "no object passed to insert!";
+ if ( ! _allow_dot ) {
+ this._validateForStorage( obj );
+ }
+ if ( typeof( obj._id ) == "undefined" && ! Array.isArray( obj ) ){
+ var tmp = obj; // don't want to modify input
+ obj = {_id: new ObjectId()};
+ for (var key in tmp){
+ obj[key] = tmp[key];
+ }
+ }
+ this._db._initExtraInfo();
+ this._mongo.insert( this._fullName , obj );
+ this._lastID = obj._id;
+ this._db._getExtraInfo("Inserted");
+}
+
+DBCollection.prototype.remove = function( t , justOne ){
+ for ( var k in t ){
+ if ( k == "_id" && typeof( t[k] ) == "undefined" ){
+ throw "can't have _id set to undefined in a remove expression"
+ }
+ }
+ this._db._initExtraInfo();
+ this._mongo.remove( this._fullName , this._massageObject( t ) , justOne ? true : false );
+ this._db._getExtraInfo("Removed");
+}
+
+DBCollection.prototype.update = function( query , obj , upsert , multi ){
+ assert( query , "need a query" );
+ assert( obj , "need an object" );
+
+ var firstKey = null;
+ for (var k in obj) { firstKey = k; break; }
+
+ if (firstKey != null && firstKey[0] == '$') {
+ // for mods we only validate partially, for example keys may have dots
+ this._validateObject( obj );
+ } else {
+ // we're basically inserting a brand new object, do full validation
+ this._validateForStorage( obj );
+ }
+
+ // can pass options via object for improved readability
+ if ( typeof(upsert) === 'object' ) {
+ assert( multi === undefined, "Fourth argument must be empty when specifying upsert and multi with an object." );
+
+ opts = upsert;
+ multi = opts.multi;
+ upsert = opts.upsert;
+ }
+
+ this._db._initExtraInfo();
+ this._mongo.update( this._fullName , query , obj , upsert ? true : false , multi ? true : false );
+ this._db._getExtraInfo("Updated");
+}
+
+DBCollection.prototype.save = function( obj ){
+ if ( obj == null || typeof( obj ) == "undefined" )
+ throw "can't save a null";
+
+ if ( typeof( obj ) == "number" || typeof( obj) == "string" )
+ throw "can't save a number or string"
+
+ if ( typeof( obj._id ) == "undefined" ){
+ obj._id = new ObjectId();
+ return this.insert( obj );
+ }
+ else {
+ return this.update( { _id : obj._id } , obj , true );
+ }
+}
+
+DBCollection.prototype._genIndexName = function( keys ){
+ var name = "";
+ for ( var k in keys ){
+ var v = keys[k];
+ if ( typeof v == "function" )
+ continue;
+
+ if ( name.length > 0 )
+ name += "_";
+ name += k + "_";
+
+ name += v;
+ }
+ return name;
+}
+
+DBCollection.prototype._indexSpec = function( keys, options ) {
+ var ret = { ns : this._fullName , key : keys , name : this._genIndexName( keys ) };
+
+ if ( ! options ){
+ }
+ else if ( typeof ( options ) == "string" )
+ ret.name = options;
+ else if ( typeof ( options ) == "boolean" )
+ ret.unique = true;
+ else if ( typeof ( options ) == "object" ){
+ if ( options.length ){
+ var nb = 0;
+ for ( var i=0; i<options.length; i++ ){
+ if ( typeof ( options[i] ) == "string" )
+ ret.name = options[i];
+ else if ( typeof( options[i] ) == "boolean" ){
+ if ( options[i] ){
+ if ( nb == 0 )
+ ret.unique = true;
+ if ( nb == 1 )
+ ret.dropDups = true;
+ }
+ nb++;
+ }
+ }
+ }
+ else {
+ Object.extend( ret , options );
+ }
+ }
+ else {
+ throw "can't handle: " + typeof( options );
+ }
+ /*
+ return ret;
+
+ var name;
+ var nTrue = 0;
+
+ if ( ! isObject( options ) ) {
+ options = [ options ];
+ }
+
+ if ( options.length ){
+ for( var i = 0; i < options.length; ++i ) {
+ var o = options[ i ];
+ if ( isString( o ) ) {
+ ret.name = o;
+ } else if ( typeof( o ) == "boolean" ) {
+ if ( o ) {
+ ++nTrue;
+ }
+ }
+ }
+ if ( nTrue > 0 ) {
+ ret.unique = true;
+ }
+ if ( nTrue > 1 ) {
+ ret.dropDups = true;
+ }
+ }
+*/
+ return ret;
+}
+
+DBCollection.prototype.createIndex = function( keys , options ){
+ var o = this._indexSpec( keys, options );
+ this._db.getCollection( "system.indexes" ).insert( o , true );
+}
+
+DBCollection.prototype.ensureIndex = function( keys , options ){
+ var name = this._indexSpec( keys, options ).name;
+ this._indexCache = this._indexCache || {};
+ if ( this._indexCache[ name ] ){
+ return;
+ }
+
+ this.createIndex( keys , options );
+ if ( this.getDB().getLastError() == "" ) {
+ this._indexCache[name] = true;
+ }
+}
+
+DBCollection.prototype.resetIndexCache = function(){
+ this._indexCache = {};
+}
+
+DBCollection.prototype.reIndex = function() {
+ return this._db.runCommand({ reIndex: this.getName() });
+}
+
+DBCollection.prototype.dropIndexes = function(){
+ this.resetIndexCache();
+
+ var res = this._db.runCommand( { deleteIndexes: this.getName(), index: "*" } );
+ assert( res , "no result from dropIndex result" );
+ if ( res.ok )
+ return res;
+
+ if ( res.errmsg.match( /not found/ ) )
+ return res;
+
+ throw "error dropping indexes : " + tojson( res );
+}
+
+
+DBCollection.prototype.drop = function(){
+ if ( arguments.length > 0 )
+ throw "drop takes no argument";
+ this.resetIndexCache();
+ var ret = this._db.runCommand( { drop: this.getName() } );
+ if ( ! ret.ok ){
+ if ( ret.errmsg == "ns not found" )
+ return false;
+ throw "drop failed: " + tojson( ret );
+ }
+ return true;
+}
+
+DBCollection.prototype.findAndModify = function(args){
+ var cmd = { findandmodify: this.getName() };
+ for (var key in args){
+ cmd[key] = args[key];
+ }
+
+ var ret = this._db.runCommand( cmd );
+ if ( ! ret.ok ){
+ if (ret.errmsg == "No matching object found"){
+ return null;
+ }
+ throw "findAndModifyFailed failed: " + tojson( ret );
+ }
+ return ret.value;
+}
+
+DBCollection.prototype.renameCollection = function( newName , dropTarget ){
+ return this._db._adminCommand( { renameCollection : this._fullName ,
+ to : this._db._name + "." + newName ,
+ dropTarget : dropTarget } )
+}
+
+DBCollection.prototype.validate = function(full) {
+ var cmd = { validate: this.getName() };
+
+ if (typeof(full) == 'object') // support arbitrary options here
+ Object.extend(cmd, full);
+ else
+ cmd.full = full;
+
+ var res = this._db.runCommand( cmd );
+
+ if (typeof(res.valid) == 'undefined') {
+ // old-style format just put everything in a string. Now using proper fields
+
+ res.valid = false;
+
+ var raw = res.result || res.raw;
+
+ if ( raw ){
+ var str = "-" + tojson( raw );
+ res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) );
+
+ var p = /lastExtentSize:(\d+)/;
+ var r = p.exec( str );
+ if ( r ){
+ res.lastExtentSize = Number( r[1] );
+ }
+ }
+ }
+
+ return res;
+}
+
+DBCollection.prototype.getShardVersion = function(){
+ return this._db._adminCommand( { getShardVersion : this._fullName } );
+}
+
+DBCollection.prototype.getIndexes = function(){
+ return this.getDB().getCollection( "system.indexes" ).find( { ns : this.getFullName() } ).toArray();
+}
+
+DBCollection.prototype.getIndices = DBCollection.prototype.getIndexes;
+DBCollection.prototype.getIndexSpecs = DBCollection.prototype.getIndexes;
+
+DBCollection.prototype.getIndexKeys = function(){
+ return this.getIndexes().map(
+ function(i){
+ return i.key;
+ }
+ );
+}
+
+
+DBCollection.prototype.count = function( x ){
+ return this.find( x ).count();
+}
+
+/**
+ * Drop free lists. Normally not used.
+ * Note this only does the collection itself, not the namespaces of its indexes (see cleanAll).
+ */
+DBCollection.prototype.clean = function() {
+ return this._dbCommand( { clean: this.getName() } );
+}
+
+
+
+/**
+ * <p>Drop a specified index.</p>
+ *
+ * <p>
+ * Name is the name of the index in the system.indexes name field. (Run db.system.indexes.find() to
+ * see example data.)
+ * </p>
+ *
+ * <p>Note : alpha: space is not reclaimed </p>
+ * @param {String} name of index to delete.
+ * @return A result object. result.ok will be true if successful.
+ */
+DBCollection.prototype.dropIndex = function(index) {
+ assert(index , "need to specify index to dropIndex" );
+
+ if ( ! isString( index ) && isObject( index ) )
+ index = this._genIndexName( index );
+
+ var res = this._dbCommand( "deleteIndexes" ,{ index: index } );
+ this.resetIndexCache();
+ return res;
+}
+
+DBCollection.prototype.copyTo = function( newName ){
+ return this.getDB().eval(
+ function( collName , newName ){
+ var from = db[collName];
+ var to = db[newName];
+ to.ensureIndex( { _id : 1 } );
+ var count = 0;
+
+ var cursor = from.find();
+ while ( cursor.hasNext() ){
+ var o = cursor.next();
+ count++;
+ to.save( o );
+ }
+
+ return count;
+ } , this.getName() , newName
+ );
+}
+
+DBCollection.prototype.getCollection = function( subName ){
+ return this._db.getCollection( this._shortName + "." + subName );
+}
+
+DBCollection.prototype.stats = function( scale ){
+ return this._db.runCommand( { collstats : this._shortName , scale : scale } );
+}
+
+DBCollection.prototype.dataSize = function(){
+ return this.stats().size;
+}
+
+DBCollection.prototype.storageSize = function(){
+ return this.stats().storageSize;
+}
+
+DBCollection.prototype.totalIndexSize = function( verbose ){
+ var stats = this.stats();
+ if (verbose){
+ for (var ns in stats.indexSizes){
+ print( ns + "\t" + stats.indexSizes[ns] );
+ }
+ }
+ return stats.totalIndexSize;
+}
+
+
+DBCollection.prototype.totalSize = function(){
+ var total = this.storageSize();
+ var mydb = this._db;
+ var shortName = this._shortName;
+ this.getIndexes().forEach(
+ function( spec ){
+ var coll = mydb.getCollection( shortName + ".$" + spec.name );
+ var mysize = coll.storageSize();
+ //print( coll + "\t" + mysize + "\t" + tojson( coll.validate() ) );
+ total += coll.dataSize();
+ }
+ );
+ return total;
+}
+
+
+DBCollection.prototype.convertToCapped = function( bytes ){
+ if ( ! bytes )
+ throw "have to specify # of bytes";
+ return this._dbCommand( { convertToCapped : this._shortName , size : bytes } )
+}
+
+DBCollection.prototype.exists = function(){
+ return this._db.system.namespaces.findOne( { name : this._fullName } );
+}
+
+DBCollection.prototype.isCapped = function(){
+ var e = this.exists();
+ return ( e && e.options && e.options.capped ) ? true : false;
+}
+
+DBCollection.prototype._distinct = function( keyString , query ){
+ return this._dbCommand( { distinct : this._shortName , key : keyString , query : query || {} } );
+ if ( ! res.ok )
+ throw "distinct failed: " + tojson( res );
+ return res.values;
+}
+
+DBCollection.prototype.distinct = function( keyString , query ){
+ var res = this._distinct( keyString , query );
+ if ( ! res.ok )
+ throw "distinct failed: " + tojson( res );
+ return res.values;
+}
+
+
+DBCollection.prototype.aggregate = function( ops ) {
+
+ var arr = ops;
+
+ if ( ! ops.length ) {
+ arr = [];
+ for ( var i=0; i<arguments.length; i++ ) {
+ arr.push( arguments[i] )
+ }
+ }
+
+ return this.runCommand( "aggregate" , { pipeline : arr } );
+}
+
+DBCollection.prototype.group = function( params ){
+ params.ns = this._shortName;
+ return this._db.group( params );
+}
+
+DBCollection.prototype.groupcmd = function( params ){
+ params.ns = this._shortName;
+ return this._db.groupcmd( params );
+}
+
+MapReduceResult = function( db , o ){
+ Object.extend( this , o );
+ this._o = o;
+ this._keys = Object.keySet( o );
+ this._db = db;
+ if ( this.result != null ) {
+ this._coll = this._db.getCollection( this.result );
+ }
+}
+
+MapReduceResult.prototype._simpleKeys = function(){
+ return this._o;
+}
+
+MapReduceResult.prototype.find = function(){
+ if ( this.results )
+ return this.results;
+ return DBCollection.prototype.find.apply( this._coll , arguments );
+}
+
+MapReduceResult.prototype.drop = function(){
+ if ( this._coll ) {
+ return this._coll.drop();
+ }
+}
+
+/**
+* just for debugging really
+*/
+MapReduceResult.prototype.convertToSingleObject = function(){
+ var z = {};
+ var it = this.results != null ? this.results : this._coll.find();
+ it.forEach( function(a){ z[a._id] = a.value; } );
+ return z;
+}
+
+DBCollection.prototype.convertToSingleObject = function(valueField){
+ var z = {};
+ this.find().forEach( function(a){ z[a._id] = a[valueField]; } );
+ return z;
+}
+
+/**
+* @param optional object of optional fields;
+*/
+DBCollection.prototype.mapReduce = function( map , reduce , optionsOrOutString ){
+ var c = { mapreduce : this._shortName , map : map , reduce : reduce };
+ assert( optionsOrOutString , "need to supply an optionsOrOutString" )
+
+ if ( typeof( optionsOrOutString ) == "string" )
+ c["out"] = optionsOrOutString;
+ else
+ Object.extend( c , optionsOrOutString );
+
+ var raw = this._db.runCommand( c );
+ if ( ! raw.ok ){
+ __mrerror__ = raw;
+ throw "map reduce failed:" + tojson(raw);
+ }
+ return new MapReduceResult( this._db , raw );
+
+}
+
+DBCollection.prototype.toString = function(){
+ return this.getFullName();
+}
+
+DBCollection.prototype.toString = function(){
+ return this.getFullName();
+}
+
+
+DBCollection.prototype.tojson = DBCollection.prototype.toString;
+
+DBCollection.prototype.shellPrint = DBCollection.prototype.toString;
+
+DBCollection.autocomplete = function(obj){
+ var colls = DB.autocomplete(obj.getDB());
+ var ret = [];
+ for (var i=0; i<colls.length; i++){
+ var c = colls[i];
+ if (c.length <= obj.getName().length) continue;
+ if (c.slice(0,obj.getName().length+1) != obj.getName()+'.') continue;
+
+ ret.push(c.slice(obj.getName().length+1));
+ }
+ return ret;
+}
+
+
+// Sharding additions
+
+/*
+Usage :
+
+mongo <mongos>
+> load('path-to-file/shardingAdditions.js')
+Loading custom sharding extensions...
+true
+
+> var collection = db.getMongo().getCollection("foo.bar")
+> collection.getShardDistribution() // prints statistics related to the collection's data distribution
+
+> collection.getSplitKeysForChunks() // generates split points for all chunks in the collection, based on the
+ // default maxChunkSize or alternately a specified chunk size
+> collection.getSplitKeysForChunks( 10 ) // Mb
+
+> var splitter = collection.getSplitKeysForChunks() // by default, the chunks are not split, the keys are just
+ // found. A splitter function is returned which will actually
+ // do the splits.
+
+> splitter() // ! Actually executes the splits on the cluster !
+
+*/
+
+DBCollection.prototype.getShardDistribution = function(){
+
+ var stats = this.stats()
+
+ if( ! stats.sharded ){
+ print( "Collection " + this + " is not sharded." )
+ return
+ }
+
+ var config = this.getMongo().getDB("config")
+
+ var numChunks = 0
+
+ for( var shard in stats.shards ){
+
+ var shardDoc = config.shards.findOne({ _id : shard })
+
+ print( "\nShard " + shard + " at " + shardDoc.host )
+
+ var shardStats = stats.shards[ shard ]
+
+ var chunks = config.chunks.find({ _id : sh._collRE( this ), shard : shard }).toArray()
+
+ numChunks += chunks.length
+
+ var estChunkData = shardStats.size / chunks.length
+ var estChunkCount = Math.floor( shardStats.count / chunks.length )
+
+ print( " data : " + sh._dataFormat( shardStats.size ) +
+ " docs : " + shardStats.count +
+ " chunks : " + chunks.length )
+ print( " estimated data per chunk : " + sh._dataFormat( estChunkData ) )
+ print( " estimated docs per chunk : " + estChunkCount )
+
+ }
+
+ print( "\nTotals" )
+ print( " data : " + sh._dataFormat( stats.size ) +
+ " docs : " + stats.count +
+ " chunks : " + numChunks )
+ for( var shard in stats.shards ){
+
+ var shardStats = stats.shards[ shard ]
+
+ var estDataPercent = Math.floor( shardStats.size / stats.size * 10000 ) / 100
+ var estDocPercent = Math.floor( shardStats.count / stats.count * 10000 ) / 100
+
+ print( " Shard " + shard + " contains " + estDataPercent + "% data, " + estDocPercent + "% docs in cluster, " +
+ "avg obj size on shard : " + sh._dataFormat( stats.shards[ shard ].avgObjSize ) )
+ }
+
+ print( "\n" )
+
+}
+
+
+DBCollection.prototype.getSplitKeysForChunks = function( chunkSize ){
+
+ var stats = this.stats()
+
+ if( ! stats.sharded ){
+ print( "Collection " + this + " is not sharded." )
+ return
+ }
+
+ var config = this.getMongo().getDB("config")
+
+ if( ! chunkSize ){
+ chunkSize = config.settings.findOne({ _id : "chunksize" }).value
+ print( "Chunk size not set, using default of " + chunkSize + "Mb" )
+ }
+ else{
+ print( "Using chunk size of " + chunkSize + "Mb" )
+ }
+
+ var shardDocs = config.shards.find().toArray()
+
+ var allSplitPoints = {}
+ var numSplits = 0
+
+ for( var i = 0; i < shardDocs.length; i++ ){
+
+ var shardDoc = shardDocs[i]
+ var shard = shardDoc._id
+ var host = shardDoc.host
+ var sconn = new Mongo( host )
+
+ var chunks = config.chunks.find({ _id : sh._collRE( this ), shard : shard }).toArray()
+
+ print( "\nGetting split points for chunks on shard " + shard + " at " + host )
+
+ var splitPoints = []
+
+ for( var j = 0; j < chunks.length; j++ ){
+ var chunk = chunks[j]
+ var result = sconn.getDB("admin").runCommand({ splitVector : this + "", min : chunk.min, max : chunk.max, maxChunkSize : chunkSize })
+ if( ! result.ok ){
+ print( " Had trouble getting split keys for chunk " + sh._pchunk( chunk ) + " :\n" )
+ printjson( result )
+ }
+ else{
+ splitPoints = splitPoints.concat( result.splitKeys )
+
+ if( result.splitKeys.length > 0 )
+ print( " Added " + result.splitKeys.length + " split points for chunk " + sh._pchunk( chunk ) )
+ }
+ }
+
+ print( "Total splits for shard " + shard + " : " + splitPoints.length )
+
+ numSplits += splitPoints.length
+ allSplitPoints[ shard ] = splitPoints
+
+ }
+
+ // Get most recent migration
+ var migration = config.changelog.find({ what : /^move.*/ }).sort({ time : -1 }).limit( 1 ).toArray()
+ if( migration.length == 0 )
+ print( "\nNo migrations found in changelog." )
+ else {
+ migration = migration[0]
+ print( "\nMost recent migration activity was on " + migration.ns + " at " + migration.time )
+ }
+
+ var admin = this.getMongo().getDB("admin")
+ var coll = this
+ var splitFunction = function(){
+
+ // Turn off the balancer, just to be safe
+ print( "Turning off balancer..." )
+ config.settings.update({ _id : "balancer" }, { $set : { stopped : true } }, true )
+ print( "Sleeping for 30s to allow balancers to detect change. To be extra safe, check config.changelog" +
+ " for recent migrations." )
+ sleep( 30000 )
+
+ for( shard in allSplitPoints ){
+ for( var i = 0; i < allSplitPoints[ shard ].length; i++ ){
+ var splitKey = allSplitPoints[ shard ][i]
+ print( "Splitting at " + tojson( splitKey ) )
+ printjson( admin.runCommand({ split : coll + "", middle : splitKey }) )
+ }
+ }
+
+ print( "Turning the balancer back on." )
+ config.settings.update({ _id : "balancer" }, { $set : { stopped : false } } )
+ sleep( 1 )
+ }
+
+ splitFunction.getSplitPoints = function(){ return allSplitPoints; }
+
+ print( "\nGenerated " + numSplits + " split keys, run output function to perform splits.\n" +
+ " ex : \n" +
+ " > var splitter = <collection>.getSplitKeysForChunks()\n" +
+ " > splitter() // Execute splits on cluster !\n" )
+
+ return splitFunction
+
+}
+
+DBCollection.prototype.setSlaveOk = function( value ) {
+ if( value == undefined ) value = true;
+ this._slaveOk = value;
+}
+
+DBCollection.prototype.getSlaveOk = function() {
+ if (this._slaveOk != undefined) return this._slaveOk;
+ return this._db.getSlaveOk();
+}
+
+DBCollection.prototype.getQueryOptions = function() {
+ var options = 0;
+ if (this.getSlaveOk()) options |= 4;
+ return options;
+}
+
diff --git a/src/mongo/shell/createCPPfromJavaScriptFiles.js b/src/mongo/shell/createCPPfromJavaScriptFiles.js
new file mode 100644
index 00000000000..ee581202bf3
--- /dev/null
+++ b/src/mongo/shell/createCPPfromJavaScriptFiles.js
@@ -0,0 +1,105 @@
+// createCPPfromJavaScriptFiles.js
+
+/* Copyright 2011 10gen Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+// This JavaScript file is run under Windows Script Host from the Visual Studio build.
+// It creates .CPP files from JavaScript files and is intended to duplicate the functionality
+// of the jsToH Python function in SConstruct. By using only standard Windows components
+// (Windows Script Host, JScript) we avoid the need for Visual Studio builders to install
+// Python, and we don't need to include the generated files in Git because they can be
+// recreated as required.
+
+var whitespace = " \t";
+function cppEscape( s ) {
+ for ( var i = 0, len = s.length; i < len; ++i ) {
+ if ( whitespace.indexOf( s.charAt( i ) ) === -1 ) {
+ s = s.substring( i );
+ break;
+ }
+ }
+ if ( i == len )
+ return "";
+ for ( i = s.length - 1; i >= 0; --i ) {
+ if ( whitespace.indexOf( s.charAt( i ) ) === -1 ) {
+ s = s.substr( 0, i + 1 );
+ break;
+ }
+ }
+ s = s.replace( /\\/g, "\\\\" );
+ s = s.replace( /"/g, '\\"' );
+ return s;
+};
+
+function jsToH( fso, outputFileNameString, inputFileNameStringArray ) {
+ var displayString = 'jsToH( "' + outputFileNameString + '", [';
+ var i, len = inputFileNameStringArray.length;
+ for ( i = 0; i < len; ++i ) {
+ displayString += '"' + inputFileNameStringArray[i] + '"';
+ if ( i < len - 1 )
+ displayString += ', ';
+ }
+ displayString += '] );'
+ WScript.Echo( displayString );
+ var h = ['#include "bson/stringdata.h"'
+ , 'namespace mongo {'
+ , 'struct JSFile{ const char* name; const StringData& source; };'
+ , 'namespace JSFiles{'
+ ];
+ for ( i = 0; i < len; ++i ) {
+ var filename = inputFileNameStringArray[i];
+ var objname = filename.substring( 0, filename.lastIndexOf( '.' ) ).substr( 1 + filename.lastIndexOf('/') );
+ var stringname = '_jscode_raw_' + objname;
+ h.push( 'const StringData ' + stringname + ' = ' );
+ var inputFile = fso.GetFile( filename );
+ var inputStream = inputFile.OpenAsTextStream( 1 /* ForReading */, 0 /* TristateFalse == ASCII */ );
+ while ( !inputStream.AtEndOfStream )
+ h.push( '"' + cppEscape(inputStream.ReadLine()) + '\\n" ' );
+ inputStream.Close();
+ h.push( ';' );
+ h.push( 'extern const JSFile ' + objname + ';' ); //symbols aren't exported w/o this
+ h.push( 'const JSFile ' + objname + ' = { "' + filename + '" , ' + stringname + ' };' );
+ }
+ h.push( "} // namespace JSFiles" );
+ h.push( "} // namespace mongo" );
+ h.push( "" );
+ var out = fso.CreateTextFile( outputFileNameString, true /* overwrite */ );
+ out.Write( h.join( '\n' ) );
+ out.Close();
+};
+
+function rebuildIfNeeded( fso, outputFileNameString, inputFileNameStringArray ) {
+ var rebuildNeeded = false;
+ if ( !fso.FileExists( outputFileNameString ) ) {
+ rebuildNeeded = true;
+ } else {
+ var outputFileDate = fso.GetFile( outputFileNameString ).DateLastModified;
+ for ( var i = 0, len = inputFileNameStringArray.length; i < len; ++i ) {
+ if ( fso.GetFile( inputFileNameStringArray[i] ).DateLastModified > outputFileDate ) {
+ rebuildNeeded = true;
+ break;
+ }
+ }
+ }
+ if ( rebuildNeeded )
+ jsToH( fso, outputFileNameString, inputFileNameStringArray );
+};
+
+var shell = new ActiveXObject( "WScript.Shell" );
+shell.CurrentDirectory = WScript.Arguments.Unnamed.Item( 0 );
+
+var fso = new ActiveXObject( "Scripting.FileSystemObject" );
+rebuildIfNeeded( fso, "shell/mongo.cpp", ["shell/utils.js", "shell/utils_sh.js", "shell/db.js", "shell/mongo.js", "shell/mr.js", "shell/query.js", "shell/collection.js"] );
+rebuildIfNeeded( fso, "shell/mongo-server.cpp", ["shell/servers.js", "shell/shardingtest.js", "shell/servers_misc.js", "shell/replsettest.js", "shell/replsetbridge.js"] );
diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js
new file mode 100644
index 00000000000..9cdf879ac0a
--- /dev/null
+++ b/src/mongo/shell/db.js
@@ -0,0 +1,926 @@
+// db.js
+
+if ( typeof DB == "undefined" ){
+ DB = function( mongo , name ){
+ this._mongo = mongo;
+ this._name = name;
+ }
+}
+
+DB.prototype.getMongo = function(){
+ assert( this._mongo , "why no mongo!" );
+ return this._mongo;
+}
+
+DB.prototype.getSiblingDB = function( name ){
+ return this.getMongo().getDB( name );
+}
+
+DB.prototype.getSisterDB = DB.prototype.getSiblingDB;
+
+DB.prototype.getName = function(){
+ return this._name;
+}
+
+DB.prototype.stats = function(scale){
+ return this.runCommand( { dbstats : 1 , scale : scale } );
+}
+
+DB.prototype.getCollection = function( name ){
+ return new DBCollection( this._mongo , this , name , this._name + "." + name );
+}
+
+DB.prototype.commandHelp = function( name ){
+ var c = {};
+ c[name] = 1;
+ c.help = true;
+ var res = this.runCommand( c );
+ if ( ! res.ok )
+ throw res.errmsg;
+ return res.help;
+}
+
+DB.prototype.runCommand = function( obj ){
+ if ( typeof( obj ) == "string" ){
+ var n = {};
+ n[obj] = 1;
+ obj = n;
+ }
+ return this.getCollection( "$cmd" ).findOne( obj );
+}
+
+DB.prototype._dbCommand = DB.prototype.runCommand;
+
+DB.prototype.adminCommand = function( obj ){
+ if ( this._name == "admin" )
+ return this.runCommand( obj );
+ return this.getSiblingDB( "admin" ).runCommand( obj );
+}
+
+DB.prototype._adminCommand = DB.prototype.adminCommand; // alias old name
+
+DB.prototype.addUser = function( username , pass, readOnly, replicatedTo, timeout ){
+ if ( pass == null || pass.length == 0 )
+ throw "password can't be empty";
+
+ readOnly = readOnly || false;
+ var c = this.getCollection( "system.users" );
+
+ var u = c.findOne( { user : username } ) || { user : username };
+ u.readOnly = readOnly;
+ u.pwd = hex_md5( username + ":mongo:" + pass );
+
+ try {
+ c.save( u );
+ } catch (e) {
+ // SyncClusterConnections call GLE automatically after every write and will throw an
+ // exception if the insert failed.
+ if ( tojson(e).indexOf( "login" ) >= 0 ){
+ // TODO: this check is a hack
+ print( "Creating user seems to have succeeded but threw an exception because we no " +
+ "longer have auth." );
+ } else {
+ throw "Could not insert into system.users: " + tojson(e);
+ }
+ }
+ print( tojson( u ) );
+
+ //
+ // When saving users to replica sets, the shell user will want to know if the user hasn't
+ // been fully replicated everywhere, since this will impact security. By default, replicate to
+ // majority of nodes with wtimeout 15 secs, though user can override
+ //
+
+ replicatedTo = replicatedTo != undefined && replicatedTo != null ? replicatedTo : "majority"
+
+ // in mongod version 2.1.0-, this worked
+ var le = {};
+ try {
+ le = this.getLastErrorObj( replicatedTo, timeout || 30 * 1000 );
+ // printjson( le )
+ }
+ catch (e) {
+ errjson = tojson(e);
+ if ( errjson.indexOf( "login" ) >= 0 || errjson.indexOf( "unauthorized" ) >= 0 ) {
+ // TODO: this check is a hack
+ print( "addUser succeeded, but cannot wait for replication since we no longer have auth" );
+ return "";
+ }
+ print( "could not find getLastError object : " + tojson( e ) )
+ }
+
+ // We can't detect replica set shards via mongos, so we'll sometimes get this error
+ // In this case though, we've already checked the local error before returning norepl, so
+ // the user has been written and we're happy
+ if( le.err == "norepl" ){
+ return
+ }
+
+ if ( le.err == "timeout" ){
+ throw "timed out while waiting for user authentication to replicate - " +
+ "database will not be fully secured until replication finishes"
+ }
+
+ if ( le.err )
+ throw "couldn't add user: " + le.err
+}
+
+DB.prototype.logout = function(){
+ return this.getMongo().logout(this.getName());
+};
+
+DB.prototype.removeUser = function( username ){
+ this.getCollection( "system.users" ).remove( { user : username } );
+}
+
+DB.prototype.__pwHash = function( nonce, username, pass ) {
+ return hex_md5( nonce + username + hex_md5( username + ":mongo:" + pass ) );
+}
+
+DB.prototype.auth = function( username , pass ){
+ var result = 0;
+ try {
+ result = this.getMongo().auth(this.getName(), username, pass);
+ }
+ catch (e) {
+ print(e);
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ Create a new collection in the database. Normally, collection creation is automatic. You would
+ use this function if you wish to specify special options on creation.
+
+ If the collection already exists, no action occurs.
+
+ <p>Options:</p>
+ <ul>
+ <li>
+ size: desired initial extent size for the collection. Must be <= 1000000000.
+ for fixed size (capped) collections, this size is the total/max size of the
+ collection.
+ </li>
+ <li>
+ capped: if true, this is a capped collection (where old data rolls out).
+ </li>
+ <li> max: maximum number of objects if capped (optional).</li>
+ </ul>
+
+ <p>Example: </p>
+
+ <code>db.createCollection("movies", { size: 10 * 1024 * 1024, capped:true } );</code>
+
+ * @param {String} name Name of new collection to create
+ * @param {Object} options Object with options for call. Options are listed above.
+ * @return SOMETHING_FIXME
+*/
+DB.prototype.createCollection = function(name, opt) {
+ var options = opt || {};
+ var cmd = { create: name, capped: options.capped, size: options.size };
+ if (options.max != undefined)
+ cmd.max = options.max;
+ if (options.autoIndexId != undefined)
+ cmd.autoIndexId = options.autoIndexId;
+ var res = this._dbCommand(cmd);
+ return res;
+}
+
+/**
+ * @deprecated use getProfilingStatus
+ * Returns the current profiling level of this database
+ * @return SOMETHING_FIXME or null on error
+ */
+DB.prototype.getProfilingLevel = function() {
+ var res = this._dbCommand( { profile: -1 } );
+ return res ? res.was : null;
+}
+
+/**
+ * @return the current profiling status
+ * example { was : 0, slowms : 100 }
+ * @return SOMETHING_FIXME or null on error
+ */
+DB.prototype.getProfilingStatus = function() {
+ var res = this._dbCommand( { profile: -1 } );
+ if ( ! res.ok )
+ throw "profile command failed: " + tojson( res );
+ delete res.ok
+ return res;
+}
+
+
+/**
+ Erase the entire database. (!)
+
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+*/
+DB.prototype.dropDatabase = function() {
+ if ( arguments.length )
+ throw "dropDatabase doesn't take arguments";
+ return this._dbCommand( { dropDatabase: 1 } );
+}
+
+/**
+ * Shuts down the database. Must be run while using the admin database.
+ * @param opts Options for shutdown. Possible options are:
+ * - force: (boolean) if the server should shut down, even if there is no
+ * up-to-date slave
+ * - timeoutSecs: (number) the server will continue checking over timeoutSecs
+ * if any other servers have caught up enough for it to shut down.
+ */
+DB.prototype.shutdownServer = function(opts) {
+ if( "admin" != this._name ){
+ return "shutdown command only works with the admin database; try 'use admin'";
+ }
+
+ cmd = {"shutdown" : 1};
+ opts = opts || {};
+ for (var o in opts) {
+ cmd[o] = opts[o];
+ }
+
+ try {
+ var res = this.runCommand(cmd);
+ if( res )
+ throw "shutdownServer failed: " + res.errmsg;
+ throw "shutdownServer failed";
+ }
+ catch ( e ){
+ assert( tojson( e ).indexOf( "error doing query: failed" ) >= 0 , "unexpected error: " + tojson( e ) );
+ print( "server should be down..." );
+ }
+}
+
+/**
+ Clone database on another server to here.
+ <p>
+ Generally, you should dropDatabase() first as otherwise the cloned information will MERGE
+ into whatever data is already present in this database. (That is however a valid way to use
+ clone if you are trying to do something intentionally, such as union three non-overlapping
+ databases into one.)
+ <p>
+ This is a low level administrative function will is not typically used.
+
+ * @param {String} from Where to clone from (dbhostname[:port]). May not be this database
+ (self) as you cannot clone to yourself.
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+ * See also: db.copyDatabase()
+*/
+DB.prototype.cloneDatabase = function(from) {
+ assert( isString(from) && from.length );
+ //this.resetIndexCache();
+ return this._dbCommand( { clone: from } );
+}
+
+
+/**
+ Clone collection on another server to here.
+ <p>
+ Generally, you should drop() first as otherwise the cloned information will MERGE
+ into whatever data is already present in this collection. (That is however a valid way to use
+ clone if you are trying to do something intentionally, such as union three non-overlapping
+ collections into one.)
+ <p>
+ This is a low level administrative function is not typically used.
+
+ * @param {String} from mongod instance from which to clnoe (dbhostname:port). May
+ not be this mongod instance, as clone from self is not allowed.
+ * @param {String} collection name of collection to clone.
+ * @param {Object} query query specifying which elements of collection are to be cloned.
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+ * See also: db.cloneDatabase()
+ */
+DB.prototype.cloneCollection = function(from, collection, query) {
+ assert( isString(from) && from.length );
+ assert( isString(collection) && collection.length );
+ collection = this._name + "." + collection;
+ query = query || {};
+ //this.resetIndexCache();
+ return this._dbCommand( { cloneCollection:collection, from:from, query:query } );
+}
+
+
+/**
+ Copy database from one server or name to another server or name.
+
+ Generally, you should dropDatabase() first as otherwise the copied information will MERGE
+ into whatever data is already present in this database (and you will get duplicate objects
+ in collections potentially.)
+
+ For security reasons this function only works when executed on the "admin" db. However,
+ if you have access to said db, you can copy any database from one place to another.
+
+ This method provides a way to "rename" a database by copying it to a new db name and
+ location. Additionally, it effectively provides a repair facility.
+
+ * @param {String} fromdb database name from which to copy.
+ * @param {String} todb database name to copy to.
+ * @param {String} fromhost hostname of the database (and optionally, ":port") from which to
+ copy the data. default if unspecified is to copy from self.
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+ * See also: db.clone()
+*/
+DB.prototype.copyDatabase = function(fromdb, todb, fromhost, username, password) {
+ assert( isString(fromdb) && fromdb.length );
+ assert( isString(todb) && todb.length );
+ fromhost = fromhost || "";
+ if ( username && password ) {
+ var n = this._adminCommand( { copydbgetnonce : 1, fromhost:fromhost } );
+ return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce:n.nonce, key:this.__pwHash( n.nonce, username, password ) } );
+ } else {
+ return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );
+ }
+}
+
+/**
+ Repair database.
+
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+*/
+DB.prototype.repairDatabase = function() {
+ return this._dbCommand( { repairDatabase: 1 } );
+}
+
+
+DB.prototype.help = function() {
+ print("DB methods:");
+ print("\tdb.addUser(username, password[, readOnly=false])");
+ print("\tdb.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [ just calls db.runCommand(...) ]");
+ print("\tdb.auth(username, password)");
+ print("\tdb.cloneDatabase(fromhost)");
+ print("\tdb.commandHelp(name) returns the help for the command");
+ print("\tdb.copyDatabase(fromdb, todb, fromhost)");
+ print("\tdb.createCollection(name, { size : ..., capped : ..., max : ... } )");
+ print("\tdb.currentOp() displays currently executing operations in the db");
+ print("\tdb.dropDatabase()");
+ print("\tdb.eval(func, args) run code server-side");
+ print("\tdb.fsyncLock() flush data to disk and lock server for backups");
+ print("\tdb.fsyncUnlock() unlocks server following a db.fsyncLock()");
+ print("\tdb.getCollection(cname) same as db['cname'] or db.cname");
+ print("\tdb.getCollectionNames()");
+ print("\tdb.getLastError() - just returns the err msg string");
+ print("\tdb.getLastErrorObj() - return full status object");
+ print("\tdb.getMongo() get the server connection object");
+ print("\tdb.getMongo().setSlaveOk() allow queries on a replication slave server");
+ print("\tdb.getName()");
+ print("\tdb.getPrevError()");
+ print("\tdb.getProfilingLevel() - deprecated");
+ print("\tdb.getProfilingStatus() - returns if profiling is on and slow threshold");
+ print("\tdb.getReplicationInfo()");
+ print("\tdb.getSiblingDB(name) get the db at the same server as this one");
+ print("\tdb.hostInfo() get details about the server's host");
+ print("\tdb.isMaster() check replica primary status");
+ print("\tdb.killOp(opid) kills the current operation in the db");
+ print("\tdb.listCommands() lists all the db commands");
+ print("\tdb.loadServerScripts() loads all the scripts in db.system.js");
+ print("\tdb.logout()");
+ print("\tdb.printCollectionStats()");
+ print("\tdb.printReplicationInfo()");
+ print("\tdb.printShardingStatus()");
+ print("\tdb.printSlaveReplicationInfo()");
+ print("\tdb.removeUser(username)");
+ print("\tdb.repairDatabase()");
+ print("\tdb.resetError()");
+ print("\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into { cmdObj : 1 }");
+ print("\tdb.serverStatus()");
+ print("\tdb.setProfilingLevel(level,<slowms>) 0=off 1=slow 2=all");
+ print("\tdb.setVerboseShell(flag) display extra information in shell output");
+ print("\tdb.shutdownServer()");
+ print("\tdb.stats()");
+ print("\tdb.version() current version of the server");
+
+ return __magicNoPrint;
+}
+
+DB.prototype.printCollectionStats = function(){
+ var mydb = this;
+ this.getCollectionNames().forEach(
+ function(z){
+ print( z );
+ printjson( mydb.getCollection(z).stats() );
+ print( "---" );
+ }
+ );
+}
+
+/**
+ * <p> Set profiling level for your db. Profiling gathers stats on query performance. </p>
+ *
+ * <p>Default is off, and resets to off on a database restart -- so if you want it on,
+ * turn it on periodically. </p>
+ *
+ * <p>Levels :</p>
+ * <ul>
+ * <li>0=off</li>
+ * <li>1=log very slow operations; optional argument slowms specifies slowness threshold</li>
+ * <li>2=log all</li>
+ * @param {String} level Desired level of profiling
+ * @param {String} slowms For slow logging, query duration that counts as slow (default 100ms)
+ * @return SOMETHING_FIXME or null on error
+ */
+DB.prototype.setProfilingLevel = function(level,slowms) {
+
+ if (level < 0 || level > 2) {
+ throw { dbSetProfilingException : "input level " + level + " is out of range [0..2]" };
+ }
+
+ var cmd = { profile: level };
+ if ( slowms )
+ cmd["slowms"] = slowms;
+ return this._dbCommand( cmd );
+}
+
+DB.prototype._initExtraInfo = function() {
+ if ( typeof _verboseShell === 'undefined' || !_verboseShell ) return;
+ this.startTime = new Date().getTime();
+}
+
+DB.prototype._getExtraInfo = function(action) {
+ if ( typeof _verboseShell === 'undefined' || !_verboseShell ) {
+ __callLastError = true;
+ return;
+ }
+
+ // explicit w:1 so that replset getLastErrorDefaults aren't used here which would be bad.
+ var res = this.getLastErrorCmd(1);
+ if (res) {
+ if (res.err != undefined && res.err != null) {
+ // error occured, display it
+ print(res.err);
+ return;
+ }
+
+ var info = action + " ";
+ // hack for inserted because res.n is 0
+ info += action != "Inserted" ? res.n : 1;
+ if (res.n > 0 && res.updatedExisting != undefined) info += " " + (res.updatedExisting ? "existing" : "new")
+ info += " record(s)";
+ var time = new Date().getTime() - this.startTime;
+ info += " in " + time + "ms";
+ print(info);
+ }
+}
+
+/**
+ * <p> Evaluate a js expression at the database server.</p>
+ *
+ * <p>Useful if you need to touch a lot of data lightly; in such a scenario
+ * the network transfer of the data could be a bottleneck. A good example
+ * is "select count(*)" -- can be done server side via this mechanism.
+ * </p>
+ *
+ * <p>
+ * If the eval fails, an exception is thrown of the form:
+ * </p>
+ * <code>{ dbEvalException: { retval: functionReturnValue, ok: num [, errno: num] [, errmsg: str] } }</code>
+ *
+ * <p>Example: </p>
+ * <code>print( "mycount: " + db.eval( function(){db.mycoll.find({},{_id:ObjId()}).length();} );</code>
+ *
+ * @param {Function} jsfunction Javascript function to run on server. Note this it not a closure, but rather just "code".
+ * @return result of your function, or null if error
+ *
+ */
+DB.prototype.eval = function(jsfunction) {
+ var cmd = { $eval : jsfunction };
+ if ( arguments.length > 1 ) {
+ cmd.args = argumentsToArray( arguments ).slice(1);
+ }
+
+ var res = this._dbCommand( cmd );
+
+ if (!res.ok)
+ throw tojson( res );
+
+ return res.retval;
+}
+
+DB.prototype.dbEval = DB.prototype.eval;
+
+
+/**
+ *
+ * <p>
+ * Similar to SQL group by. For example: </p>
+ *
+ * <code>select a,b,sum(c) csum from coll where active=1 group by a,b</code>
+ *
+ * <p>
+ * corresponds to the following in 10gen:
+ * </p>
+ *
+ * <code>
+ db.group(
+ {
+ ns: "coll",
+ key: { a:true, b:true },
+ // keyf: ...,
+ cond: { active:1 },
+ reduce: function(obj,prev) { prev.csum += obj.c; } ,
+ initial: { csum: 0 }
+ });
+ </code>
+ *
+ *
+ * <p>
+ * An array of grouped items is returned. The array must fit in RAM, thus this function is not
+ * suitable when the return set is extremely large.
+ * </p>
+ * <p>
+ * To order the grouped data, simply sort it client side upon return.
+ * <p>
+ Defaults
+ cond may be null if you want to run against all rows in the collection
+ keyf is a function which takes an object and returns the desired key. set either key or keyf (not both).
+ * </p>
+*/
+DB.prototype.groupeval = function(parmsObj) {
+
+ var groupFunction = function() {
+ var parms = args[0];
+ var c = db[parms.ns].find(parms.cond||{});
+ var map = new Map();
+ var pks = parms.key ? Object.keySet( parms.key ) : null;
+ var pkl = pks ? pks.length : 0;
+ var key = {};
+
+ while( c.hasNext() ) {
+ var obj = c.next();
+ if ( pks ) {
+ for( var i=0; i<pkl; i++ ){
+ var k = pks[i];
+ key[k] = obj[k];
+ }
+ }
+ else {
+ key = parms.$keyf(obj);
+ }
+
+ var aggObj = map.get(key);
+ if( aggObj == null ) {
+ var newObj = Object.extend({}, key); // clone
+ aggObj = Object.extend(newObj, parms.initial)
+ map.put( key , aggObj );
+ }
+ parms.$reduce(obj, aggObj);
+ }
+
+ return map.values();
+ }
+
+ return this.eval(groupFunction, this._groupFixParms( parmsObj ));
+}
+
+DB.prototype.groupcmd = function( parmsObj ){
+ var ret = this.runCommand( { "group" : this._groupFixParms( parmsObj ) } );
+ if ( ! ret.ok ){
+ throw "group command failed: " + tojson( ret );
+ }
+ return ret.retval;
+}
+
+DB.prototype.group = DB.prototype.groupcmd;
+
+DB.prototype._groupFixParms = function( parmsObj ){
+ var parms = Object.extend({}, parmsObj);
+
+ if( parms.reduce ) {
+ parms.$reduce = parms.reduce; // must have $ to pass to db
+ delete parms.reduce;
+ }
+
+ if( parms.keyf ) {
+ parms.$keyf = parms.keyf;
+ delete parms.keyf;
+ }
+
+ return parms;
+}
+
+DB.prototype.resetError = function(){
+ return this.runCommand( { reseterror : 1 } );
+}
+
+DB.prototype.forceError = function(){
+ return this.runCommand( { forceerror : 1 } );
+}
+
+DB.prototype.getLastError = function( w , wtimeout ){
+ var res = this.getLastErrorObj( w , wtimeout );
+ if ( ! res.ok )
+ throw "getlasterror failed: " + tojson( res );
+ return res.err;
+}
+DB.prototype.getLastErrorObj = function( w , wtimeout ){
+ var cmd = { getlasterror : 1 };
+ if ( w ){
+ cmd.w = w;
+ if ( wtimeout )
+ cmd.wtimeout = wtimeout;
+ }
+ var res = this.runCommand( cmd );
+
+ if ( ! res.ok )
+ throw "getlasterror failed: " + tojson( res );
+ return res;
+}
+DB.prototype.getLastErrorCmd = DB.prototype.getLastErrorObj;
+
+
+/* Return the last error which has occurred, even if not the very last error.
+
+ Returns:
+ { err : <error message>, nPrev : <how_many_ops_back_occurred>, ok : 1 }
+
+ result.err will be null if no error has occurred.
+ */
+DB.prototype.getPrevError = function(){
+ return this.runCommand( { getpreverror : 1 } );
+}
+
+DB.prototype.getCollectionNames = function(){
+ var all = [];
+
+ var nsLength = this._name.length + 1;
+
+ var c = this.getCollection( "system.namespaces" ).find();
+ while ( c.hasNext() ){
+ var name = c.next().name;
+
+ if ( name.indexOf( "$" ) >= 0 && name.indexOf( ".oplog.$" ) < 0 )
+ continue;
+
+ all.push( name.substring( nsLength ) );
+ }
+
+ return all.sort();
+}
+
+DB.prototype.tojson = function(){
+ return this._name;
+}
+
+DB.prototype.toString = function(){
+ return this._name;
+}
+
+DB.prototype.isMaster = function () { return this.runCommand("isMaster"); }
+
+DB.prototype.currentOp = function( arg ){
+ var q = {}
+ if ( arg ) {
+ if ( typeof( arg ) == "object" )
+ Object.extend( q , arg );
+ else if ( arg )
+ q["$all"] = true;
+ }
+ return this.$cmd.sys.inprog.findOne( q );
+}
+DB.prototype.currentOP = DB.prototype.currentOp;
+
+DB.prototype.killOp = function(op) {
+ if( !op )
+ throw "no opNum to kill specified";
+ return this.$cmd.sys.killop.findOne({'op':op});
+}
+DB.prototype.killOP = DB.prototype.killOp;
+
+DB.tsToSeconds = function(x){
+ if ( x.t && x.i )
+ return x.t / 1000;
+ return x / 4294967296; // low 32 bits are ordinal #s within a second
+}
+
+/**
+ Get a replication log information summary.
+ <p>
+ This command is for the database/cloud administer and not applicable to most databases.
+ It is only used with the local database. One might invoke from the JS shell:
+ <pre>
+ use local
+ db.getReplicationInfo();
+ </pre>
+ It is assumed that this database is a replication master -- the information returned is
+ about the operation log stored at local.oplog.$main on the replication master. (It also
+ works on a machine in a replica pair: for replica pairs, both machines are "masters" from
+ an internal database perspective.
+ <p>
+ * @return Object timeSpan: time span of the oplog from start to end if slave is more out
+ * of date than that, it can't recover without a complete resync
+*/
+DB.prototype.getReplicationInfo = function() {
+ var db = this.getSiblingDB("local");
+
+ var result = { };
+ var oplog;
+ if (db.system.namespaces.findOne({name:"local.oplog.rs"}) != null) {
+ oplog = 'oplog.rs';
+ }
+ else if (db.system.namespaces.findOne({name:"local.oplog.$main"}) != null) {
+ oplog = 'oplog.$main';
+ }
+ else {
+ result.errmsg = "neither master/slave nor replica set replication detected";
+ return result;
+ }
+
+ var ol_entry = db.system.namespaces.findOne({name:"local."+oplog});
+ if( ol_entry && ol_entry.options ) {
+ result.logSizeMB = ol_entry.options.size / ( 1024 * 1024 );
+ } else {
+ result.errmsg = "local."+oplog+", or its options, not found in system.namespaces collection";
+ return result;
+ }
+ ol = db.getCollection(oplog);
+
+ result.usedMB = ol.stats().size / ( 1024 * 1024 );
+ result.usedMB = Math.ceil( result.usedMB * 100 ) / 100;
+
+ var firstc = ol.find().sort({$natural:1}).limit(1);
+ var lastc = ol.find().sort({$natural:-1}).limit(1);
+ if( !firstc.hasNext() || !lastc.hasNext() ) {
+ result.errmsg = "objects not found in local.oplog.$main -- is this a new and empty db instance?";
+ result.oplogMainRowCount = ol.count();
+ return result;
+ }
+
+ var first = firstc.next();
+ var last = lastc.next();
+ {
+ var tfirst = first.ts;
+ var tlast = last.ts;
+
+ if( tfirst && tlast ) {
+ tfirst = DB.tsToSeconds( tfirst );
+ tlast = DB.tsToSeconds( tlast );
+ result.timeDiff = tlast - tfirst;
+ result.timeDiffHours = Math.round(result.timeDiff / 36)/100;
+ result.tFirst = (new Date(tfirst*1000)).toString();
+ result.tLast = (new Date(tlast*1000)).toString();
+ result.now = Date();
+ }
+ else {
+ result.errmsg = "ts element not found in oplog objects";
+ }
+ }
+
+ return result;
+};
+
+DB.prototype.printReplicationInfo = function() {
+ var result = this.getReplicationInfo();
+ if( result.errmsg ) {
+ if (!this.isMaster().ismaster) {
+ print("this is a slave, printing slave replication info.");
+ this.printSlaveReplicationInfo();
+ return;
+ }
+ print(tojson(result));
+ return;
+ }
+ print("configured oplog size: " + result.logSizeMB + "MB");
+ print("log length start to end: " + result.timeDiff + "secs (" + result.timeDiffHours + "hrs)");
+ print("oplog first event time: " + result.tFirst);
+ print("oplog last event time: " + result.tLast);
+ print("now: " + result.now);
+}
+
+DB.prototype.printSlaveReplicationInfo = function() {
+ function getReplLag(st) {
+ var now = new Date();
+ print("\t syncedTo: " + st.toString() );
+ var ago = (now-st)/1000;
+ var hrs = Math.round(ago/36)/100;
+ print("\t\t = " + Math.round(ago) + " secs ago (" + hrs + "hrs)");
+ };
+
+ function g(x) {
+ assert( x , "how could this be null (printSlaveReplicationInfo gx)" )
+ print("source: " + x.host);
+ if ( x.syncedTo ){
+ var st = new Date( DB.tsToSeconds( x.syncedTo ) * 1000 );
+ getReplLag(st);
+ }
+ else {
+ print( "\t doing initial sync" );
+ }
+ };
+
+ function r(x) {
+ assert( x , "how could this be null (printSlaveReplicationInfo rx)" );
+ if ( x.state == 1 ) {
+ return;
+ }
+
+ print("source: " + x.name);
+ if ( x.optime ) {
+ getReplLag(x.optimeDate);
+ }
+ else {
+ print( "\t no replication info, yet. State: " + x.stateStr );
+ }
+ };
+
+ var L = this.getSiblingDB("local");
+
+ if (L.system.replset.count() != 0) {
+ var status = this.adminCommand({'replSetGetStatus' : 1});
+ status.members.forEach(r);
+ }
+ else if( L.sources.count() != 0 ) {
+ L.sources.find().forEach(g);
+ }
+ else {
+ print("local.sources is empty; is this db a --slave?");
+ return;
+ }
+}
+
+DB.prototype.serverBuildInfo = function(){
+ return this._adminCommand( "buildinfo" );
+}
+
+DB.prototype.serverStatus = function(){
+ return this._adminCommand( "serverStatus" );
+}
+
+DB.prototype.hostInfo = function(){
+ return this._adminCommand( "hostInfo" );
+}
+
+DB.prototype.serverCmdLineOpts = function(){
+ return this._adminCommand( "getCmdLineOpts" );
+}
+
+DB.prototype.version = function(){
+ return this.serverBuildInfo().version;
+}
+
+DB.prototype.serverBits = function(){
+ return this.serverBuildInfo().bits;
+}
+
+DB.prototype.listCommands = function(){
+ var x = this.runCommand( "listCommands" );
+ for ( var name in x.commands ){
+ var c = x.commands[name];
+
+ var s = name + ": ";
+
+ switch ( c.lockType ){
+ case -1: s += "read-lock"; break;
+ case 0: s += "no-lock"; break;
+ case 1: s += "write-lock"; break;
+ default: s += c.lockType;
+ }
+
+ if (c.adminOnly) s += " adminOnly ";
+ if (c.adminOnly) s += " slaveOk ";
+
+ s += "\n ";
+ s += c.help.replace(/\n/g, '\n ');
+ s += "\n";
+
+ print( s );
+ }
+}
+
+DB.prototype.printShardingStatus = function( verbose ){
+ printShardingStatus( this.getSiblingDB( "config" ) , verbose );
+}
+
+DB.prototype.fsyncLock = function() {
+ return this.adminCommand({fsync:1, lock:true});
+}
+
+DB.prototype.fsyncUnlock = function() {
+ return this.getSiblingDB("admin").$cmd.sys.unlock.findOne()
+}
+
+DB.autocomplete = function(obj){
+ var colls = obj.getCollectionNames();
+ var ret=[];
+ for (var i=0; i<colls.length; i++){
+ if (colls[i].match(/^[a-zA-Z0-9_.\$]+$/))
+ ret.push(colls[i]);
+ }
+ return ret;
+}
+
+DB.prototype.setSlaveOk = function( value ) {
+ if( value == undefined ) value = true;
+ this._slaveOk = value;
+}
+
+DB.prototype.getSlaveOk = function() {
+ if (this._slaveOk != undefined) return this._slaveOk;
+ return this._mongo.getSlaveOk();
+}
+
+/* Loads any scripts contained in system.js into the client shell.
+*/
+DB.prototype.loadServerScripts = function(){
+ this.system.js.find().forEach(function(u){eval(u._id + " = " + u.value);});
+}
diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp
new file mode 100644
index 00000000000..608c8ab77c7
--- /dev/null
+++ b/src/mongo/shell/dbshell.cpp
@@ -0,0 +1,1006 @@
+// dbshell.cpp
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/pch.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <fstream>
+#include <pcrecpp.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/cmdline.h"
+#include "mongo/db/repl/rs_member.h"
+#include "mongo/scripting/engine.h"
+#include "mongo/shell/linenoise.h"
+#include "mongo/shell/shell_utils.h"
+#include "mongo/shell/shell_utils_launcher.h"
+#include "mongo/util/file.h"
+#include "mongo/util/password.h"
+#include "mongo/util/stacktrace.h"
+#include "mongo/util/startup_test.h"
+#include "mongo/util/version.h"
+
+#ifdef _WIN32
+#define isatty _isatty
+#else
+#include <unistd.h>
+#endif
+
+using namespace std;
+using namespace mongo;
+
+string historyFile;
+bool gotInterrupted = false;
+bool inMultiLine = false;
+static volatile bool atPrompt = false; // can eval before getting to prompt
+bool autoKillOp = false;
+
+#if !defined(__freebsd__) && !defined(__openbsd__) && !defined(_WIN32)
+// this is for ctrl-c handling
+#include <setjmp.h>
+jmp_buf jbuf;
+#endif
+
+namespace mongo {
+
+ Scope * shellMainScope;
+
+ extern bool dbexitCalled;
+}
+
+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, 0, 1000 );
+ BSONObjBuilder b;
+ shellMainScope->append( b , "" , "__autocomplete__" );
+ BSONObj res = b.obj();
+ BSONObj arr = res.firstElement().Obj();
+
+ BSONObjIterator i( arr );
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ all.push_back( e.String() );
+ }
+ }
+ catch ( ... ) {
+ }
+}
+
+void completionHook( const char* text , linenoiseCompletions* lc ) {
+ vector<string> all;
+ generateCompletions( text , all );
+
+ 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 )
+ ss << h << "/";
+ ss << ".dbshell";
+ historyFile = ss.str();
+
+ linenoiseHistoryLoad( historyFile.c_str() );
+ linenoiseSetCompletionCallback( completionHook );
+}
+
+void shellHistoryDone() {
+ linenoiseHistorySave( historyFile.c_str() );
+ linenoiseHistoryFree();
+}
+void shellHistoryAdd( const char * line ) {
+ if ( line[0] == '\0' )
+ return;
+
+ // dont record duplicate lines
+ static string lastLine;
+ if ( lastLine == line )
+ return;
+ lastLine = line;
+
+ // We don't want any .auth() or .addUser() commands added, but we want to
+ // be able to add things like `.author`, so be smart about how this is
+ // detected by using regular expresions.
+ static pcrecpp::RE hiddenCommands("\\.(auth|addUser)\\s*\\(");
+ if (!hiddenCommands.PartialMatch(line))
+ {
+ linenoiseHistoryAdd( line );
+ }
+}
+
+#ifdef CTRLC_HANDLE
+void intr( int sig ) {
+ longjmp( jbuf , 1 );
+}
+#endif
+
+void killOps() {
+ if ( mongo::shell_utils::_nokillop )
+ return;
+
+ if ( atPrompt )
+ return;
+
+ sleepmillis(10); // give current op a chance to finish
+
+ mongo::shell_utils::connectionRegistry.killOperationsOnAllConnections( !autoKillOp );
+}
+
+void quitNicely( int sig ) {
+ mongo::dbexitCalled = true;
+ if ( sig == SIGINT && inMultiLine ) {
+ gotInterrupted = 1;
+ return;
+ }
+
+#if !defined(_WIN32)
+ if ( sig == SIGPIPE )
+ mongo::rawOut( "mongo got signal SIGPIPE\n" );
+#endif
+
+ killOps();
+ shellHistoryDone();
+ ::_exit(0);
+}
+
+// the returned string is allocated with strdup() or malloc() and must be freed by calling free()
+char * shellReadline( const char * prompt , int handlesigint = 0 ) {
+ atPrompt = true;
+
+#ifdef CTRLC_HANDLE
+ if ( ! handlesigint ) {
+ char* ret = linenoise( prompt );
+ atPrompt = false;
+ return ret;
+ }
+ if ( setjmp( jbuf ) ) {
+ gotInterrupted = 1;
+ sigrelse(SIGINT);
+ signal( SIGINT , quitNicely );
+ return 0;
+ }
+ signal( SIGINT , intr );
+#endif
+
+ char * ret = linenoise( prompt );
+ if ( ! ret ) {
+ gotInterrupted = true; // got ^C, break out of multiline
+ }
+
+ signal( SIGINT , quitNicely );
+ atPrompt = false;
+ return ret;
+}
+
+#ifdef _WIN32
+char * strsignal(int sig){
+ switch (sig){
+ case SIGINT: return "SIGINT";
+ case SIGTERM: return "SIGTERM";
+ case SIGABRT: return "SIGABRT";
+ case SIGSEGV: return "SIGSEGV";
+ case SIGFPE: return "SIGFPE";
+ default: return "unknown";
+ }
+}
+#endif
+
+void quitAbruptly( int sig ) {
+ ostringstream ossSig;
+ ossSig << "mongo got signal " << sig << " (" << strsignal( sig ) << "), stack trace: " << endl;
+ mongo::rawOut( ossSig.str() );
+
+ ostringstream ossBt;
+ mongo::printStackTrace( ossBt );
+ mongo::rawOut( ossBt.str() );
+
+ mongo::shell_utils::KillMongoProgramInstances();
+ ::_exit( 14 );
+}
+
+// this will be called in certain c++ error cases, for example if there are two active
+// exceptions
+void myterminate() {
+ mongo::rawOut( "terminate() called in shell, printing stack:" );
+ mongo::printStackTrace();
+ ::_exit( 14 );
+}
+
+void setupSignals() {
+ signal( SIGINT , quitNicely );
+ signal( SIGTERM , quitNicely );
+ signal( SIGABRT , quitAbruptly );
+ signal( SIGSEGV , quitAbruptly );
+ signal( SIGFPE , quitAbruptly );
+
+#if !defined(_WIN32) // surprisingly these are the only ones that don't work on windows
+ signal( SIGPIPE , quitNicely ); // Maybe just log and continue?
+ signal( SIGBUS , quitAbruptly );
+#endif
+
+ set_terminate( myterminate );
+}
+
+string fixHost( string url , string host , string port ) {
+ //cout << "fixHost url: " << url << " host: " << host << " port: " << port << endl;
+
+ if ( host.size() == 0 && port.size() == 0 ) {
+ if ( url.find( "/" ) == string::npos ) {
+ // check for ips
+ if ( url.find( "." ) != string::npos )
+ return url + "/test";
+
+ if ( url.rfind( ":" ) != string::npos &&
+ isdigit( url[url.rfind(":")+1] ) )
+ return url + "/test";
+ }
+ return url;
+ }
+
+ if ( url.find( "/" ) != string::npos ) {
+ cerr << "url can't have host or port if you specify them individually" << endl;
+ ::_exit(-1);
+ }
+
+ if ( host.size() == 0 )
+ host = "127.0.0.1";
+
+ string newurl = host;
+ if ( port.size() > 0 )
+ newurl += ":" + port;
+ else if ( host.find(':') == string::npos ) {
+ // need to add port with IPv6 addresses
+ newurl += ":27017";
+ }
+
+ newurl += "/" + url;
+
+ return newurl;
+}
+
+static string OpSymbols = "~!%^&*-+=|:,<>/?.";
+
+bool isOpSymbol( char c ) {
+ for ( size_t i = 0; i < OpSymbols.size(); i++ )
+ if ( OpSymbols[i] == c ) return true;
+ return false;
+}
+
+bool isUseCmd( string code ) {
+ string cmd = code;
+ if ( cmd.find( " " ) > 0 )
+ cmd = cmd.substr( 0 , cmd.find( " " ) );
+ return cmd == "use";
+}
+
+bool isBalanced( 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' )
+ 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 '"':
+ i++;
+ while ( i < code.size() && code[i] != '"' ) i++;
+ break;
+ case '\'':
+ i++;
+ while ( i < code.size() && code[i] != '\'' ) i++;
+ 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;
+ }
+ 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;
+ }
+
+ return curlyBrackets == 0 && squareBrackets == 0 && parens == 0 && !danglingOp;
+}
+
+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") );
+ }
+} balanced_test;
+
+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 )
+ return ";";
+ char * line = shellReadline( "... " , 1 );
+ if ( gotInterrupted ) {
+ if ( line )
+ free( line );
+ return "";
+ }
+ if ( ! line )
+ return "";
+
+ char * linePtr = line;
+ while ( startsWith( linePtr, "... " ) )
+ linePtr += 4;
+
+ code += linePtr;
+ free( line );
+ }
+ return code;
+}
+
+#include <boost/program_options.hpp>
+namespace po = boost::program_options;
+
+void show_help_text( const char* name, po::options_description options ) {
+ cout << "MongoDB shell version: " << mongo::versionString << endl;
+ cout << "usage: " << name << " [options] [db address] [file names (ending in .js)]" << endl
+ << "db address can be:" << endl
+ << " foo foo database on local machine" << endl
+ << " 192.169.0.5/foo foo database on 192.168.0.5 machine" << endl
+ << " 192.169.0.5:9999/foo foo database on 192.168.0.5 machine on port 9999" << endl
+ << options << endl
+ << "file names: a list of files to run. files have to end in .js and will exit after "
+ << "unless --shell is specified" << endl;
+};
+
+bool fileExists( string file ) {
+ try {
+ boost::filesystem::path p( file );
+ return boost::filesystem::exists( file );
+ }
+ catch ( ... ) {
+ return false;
+ }
+}
+
+namespace mongo {
+ extern bool isShell;
+}
+
+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;
+}
+
+/**
+ * Edit a variable or input buffer text in an external editor -- EDITOR must be defined
+ *
+ * @param whatToEdit Name of JavaScript variable to be edited, or any text string
+ */
+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 ) {
+ editor = editorFromEnv;
+ }
+ }
+ 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 == '.' ) ) {
+ editingVariable = false;
+ break;
+ }
+ }
+
+ string js;
+ if ( editingVariable ) {
+ // Convert "whatToEdit" to JavaScript (JSON) text
+ if ( !shellMainScope->exec( "__jsout__ = tojson(" + whatToEdit + ")", "tojs", false, false, false ) )
+ return; // Error already printed
+
+ js = shellMainScope->getString( "__jsout__" );
+
+ if ( strstr( js.c_str(), "[native code]" ) ) {
+ cout << "can't edit native functions" << endl;
+ return;
+ }
+ }
+ else {
+ js = whatToEdit;
+ }
+
+ // Pick a name to use for the temp file
+ string filename;
+ const int maxAttempts = 10;
+ int 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";
+#else
+ sb << "/tmp/mongo_edit" << time( 0 ) + i << ".js";
+#endif
+ filename = sb.str();
+ if ( ! fileExists( filename ) )
+ break;
+ }
+ 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;
+ return;
+ }
+
+ // Write JSON into the temp file
+ size_t fileSize = js.size();
+ 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() );
+ return;
+ }
+ fclose( tempFileStream );
+
+ // Pass file to editor
+ StringBuilder sb;
+ sb << editor << " " << filename;
+ 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 << "editor exited with error (" << ret << "), not applying changes" << endl;
+ 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 ) {
+ cout << "couldn't open temp file on return from editor: " << errnoWithDescription() << endl;
+ remove( filename.c_str() );
+ return;
+ }
+ sb.reset();
+ int bytes;
+ do {
+ char buf[1024];
+ 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() );
+ return;
+ }
+ sb.append( StringData( buf, bytes ) );
+ } while ( bytes );
+
+ // Done with temp file, close and delete it
+ fclose( tempFileStream );
+ remove( filename.c_str() );
+
+ 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 ) ) {
+ cout << "error executing assignment: " << code << endl;
+ }
+ }
+ else {
+ linenoisePreloadBuffer( sb.str().c_str() );
+ }
+}
+
+int _main( int argc, char* argv[] ) {
+ mongo::isShell = true;
+ setupSignals();
+
+ mongo::shell_utils::RecordMyLocation( argv[ 0 ] );
+
+ string url = "test";
+ string dbhost;
+ string port;
+ vector<string> files;
+
+ string username;
+ string password;
+
+ bool runShell = false;
+ bool nodb = false;
+ bool norc = false;
+
+ string script;
+
+ po::options_description shell_options( "options" );
+ po::options_description hidden_options( "Hidden options" );
+ po::options_description cmdline_options( "Command line options" );
+ po::positional_options_description positional_options;
+
+ shell_options.add_options()
+ ( "shell", "run the shell after executing files" )
+ ( "nodb", "don't connect to mongod on startup - no 'db address' arg expected" )
+ ( "norc", "will not run the \".mongorc.js\" file on start up" )
+ ( "quiet", "be less chatty" )
+ ( "port", po::value<string>( &port ), "port to connect to" )
+ ( "host", po::value<string>( &dbhost ), "server to connect to" )
+ ( "eval", po::value<string>( &script ), "evaluate javascript" )
+ ( "username,u", po::value<string>(&username), "username for authentication" )
+ ( "password,p", new mongo::PasswordValue( &password ), "password for authentication" )
+ ( "help,h", "show this usage information" )
+ ( "version", "show version information" )
+ ( "verbose", "increase verbosity" )
+ ( "ipv6", "enable IPv6 support (disabled by default)" )
+#ifdef MONGO_SSL
+ ( "ssl", "use SSL for all connections" )
+#endif
+ ;
+
+ hidden_options.add_options()
+ ( "dbaddress", po::value<string>(), "dbaddress" )
+ ( "files", po::value< vector<string> >(), "files" )
+ ( "nokillop", "nokillop" ) // for testing, kill op will also be disabled automatically if the tests starts a mongo program
+ ( "autokillop", "autokillop" ) // for testing, will kill op without prompting
+ ;
+
+ positional_options.add( "dbaddress", 1 );
+ positional_options.add( "files", -1 );
+
+ cmdline_options.add( shell_options ).add( hidden_options );
+
+ po::variables_map params;
+
+ /* using the same style as db.cpp uses because eventually we're going
+ * to merge some of this stuff. */
+ int command_line_style = (((po::command_line_style::unix_style ^
+ po::command_line_style::allow_guessing) |
+ po::command_line_style::allow_long_disguise) ^
+ po::command_line_style::allow_sticky);
+
+ try {
+ po::store(po::command_line_parser(argc, argv).options(cmdline_options).
+ positional(positional_options).
+ style(command_line_style).run(), params);
+ po::notify( params );
+ }
+ catch ( po::error &e ) {
+ cout << "ERROR: " << e.what() << endl << endl;
+ show_help_text( argv[0], shell_options );
+ return mongo::EXIT_BADOPTIONS;
+ }
+
+ // hide password from ps output
+ for ( int i = 0; i < (argc-1); ++i ) {
+ if ( !strcmp(argv[i], "-p") || !strcmp( argv[i], "--password" ) ) {
+ char* arg = argv[i + 1];
+ while ( *arg ) {
+ *arg++ = 'x';
+ }
+ }
+ }
+
+ if ( params.count( "shell" ) ) {
+ runShell = true;
+ }
+ if ( params.count( "nodb" ) ) {
+ nodb = true;
+ }
+ if ( params.count( "norc" ) ) {
+ norc = true;
+ }
+ if ( params.count( "help" ) ) {
+ show_help_text( argv[0], shell_options );
+ return mongo::EXIT_CLEAN;
+ }
+ if ( params.count( "files" ) ) {
+ files = params["files"].as< vector<string> >();
+ }
+ if ( params.count( "version" ) ) {
+ cout << "MongoDB shell version: " << mongo::versionString << endl;
+ return mongo::EXIT_CLEAN;
+ }
+ if ( params.count( "quiet" ) ) {
+ mongo::cmdLine.quiet = true;
+ }
+#ifdef MONGO_SSL
+ if ( params.count( "ssl" ) ) {
+ mongo::cmdLine.sslOnNormalPorts = true;
+ }
+#endif
+ if ( params.count( "nokillop" ) ) {
+ mongo::shell_utils::_nokillop = true;
+ }
+ if ( params.count( "autokillop" ) ) {
+ autoKillOp = true;
+ }
+
+ /* 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 (nodb) {
+ files.insert( 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 && !fileExists( dbaddress ) ) ) {
+ url = dbaddress;
+ }
+ else {
+ files.insert( files.begin(), dbaddress );
+ }
+ }
+ }
+ if ( params.count( "ipv6" ) ) {
+ mongo::enableIPv6();
+ }
+ if ( params.count( "verbose" ) ) {
+ logLevel = 1;
+ }
+
+ if ( url == "*" ) {
+ cout << "ERROR: " << "\"*\" is an invalid db address" << endl << endl;
+ show_help_text( argv[0], shell_options );
+ return mongo::EXIT_BADOPTIONS;
+ }
+
+ if ( ! mongo::cmdLine.quiet )
+ cout << "MongoDB shell version: " << mongo::versionString << endl;
+
+ mongo::StartupTest::runTests();
+
+ if ( !nodb ) { // connect to db
+ //if ( ! mongo::cmdLine.quiet ) cout << "url: " << url << endl;
+
+ stringstream ss;
+ if ( mongo::cmdLine.quiet )
+ ss << "__quiet = true;";
+ ss << "db = connect( \"" << fixHost( url , dbhost , port ) << "\")";
+
+ mongo::shell_utils::_dbConnect = ss.str();
+
+ if ( params.count( "password" ) && password.empty() )
+ password = mongo::askPassword();
+
+ if ( username.size() && password.size() ) {
+ stringstream ss;
+ ss << "if ( ! db.auth( \"" << username << "\" , \"" << password << "\" ) ){ throw 'login failed'; }";
+ mongo::shell_utils::_dbAuth = ss.str();
+ }
+ }
+
+ mongo::ScriptEngine::setConnectCallback( mongo::shell_utils::onConnect );
+ mongo::ScriptEngine::setup();
+ mongo::globalScriptEngine->setScopeInitCallback( mongo::shell_utils::initScope );
+ auto_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() );
+ shellMainScope = scope.get();
+
+ if( runShell )
+ cout << "type \"help\" for help" << endl;
+
+ if ( !script.empty() ) {
+ mongo::shell_utils::MongoProgramScope s;
+ if ( ! scope->exec( script , "(shell eval)" , true , true , false ) )
+ return -4;
+ }
+
+ for (size_t i = 0; i < files.size(); ++i) {
+ mongo::shell_utils::MongoProgramScope s;
+
+ if ( files.size() > 1 )
+ cout << "loading file: " << files[i] << endl;
+
+ if ( ! scope->execFile( files[i] , false , true , false ) ) {
+ cout << "failed to load: " << files[i] << endl;
+ return -3;
+ }
+ }
+
+ if ( files.size() == 0 && script.empty() )
+ runShell = true;
+
+ if ( runShell ) {
+
+ mongo::shell_utils::MongoProgramScope s;
+ bool hasMongoRC = norc; // If they specify norc, assume it's not their first time
+ string rcLocation;
+ if ( !norc ) {
+#ifndef _WIN32
+ if ( getenv( "HOME" ) != NULL )
+ rcLocation = str::stream() << getenv( "HOME" ) << "/.mongorc.js" ;
+#else
+ if ( getenv( "HOMEDRIVE" ) != NULL && getenv( "HOMEPATH" ) != NULL )
+ rcLocation = str::stream() << getenv( "HOMEDRIVE" ) << getenv( "HOMEPATH" ) << "\\.mongorc.js";
+#endif
+ if ( !rcLocation.empty() && fileExists(rcLocation) ) {
+ hasMongoRC = true;
+ if ( ! scope->execFile( rcLocation , false , true , false , 0 ) ) {
+ cout << "The \".mongorc.js\" file located in your home folder could not be executed" << endl;
+ return -5;
+ }
+ }
+ }
+
+ if ( !hasMongoRC && isatty(0) ) {
+ 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;
+ fstream f;
+ f.open(rcLocation.c_str(), ios_base::out );
+ f.close();
+ }
+
+ shellHistoryInit();
+
+ string prompt;
+ int promptType;
+
+ //v8::Handle<v8::Object> shellHelper = baseContext_->Global()->Get( v8::String::New( "shellHelper" ) )->ToObject();
+
+ while ( 1 ) {
+ inMultiLine = false;
+ gotInterrupted = false;
+// shellMainScope->localConnect;
+ //DBClientWithCommands *c = getConnection( JSContext *cx, JSObject *obj );
+
+ promptType = scope->type( "prompt" );
+ if ( promptType == String ) {
+ prompt = scope->getString( "prompt" );
+ }
+ else if ( ( promptType == Code ) &&
+ execPrompt( *scope, "prompt", prompt ) ) {
+ }
+ else if ( execPrompt( *scope, "replSetMemberStatePrompt", prompt ) ) {
+ }
+ else {
+ prompt = "> ";
+ }
+
+ char * line = shellReadline( prompt.c_str() );
+
+ 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] == ' ' )
+ linePtr[--lineLen] = 0;
+ }
+
+ if ( ! linePtr || ( strlen( linePtr ) == 4 && strstr( linePtr , "exit" ) ) ) {
+ if ( ! mongo::cmdLine.quiet )
+ cout << "bye" << endl;
+ if ( line )
+ free( line );
+ break;
+ }
+
+ string code = linePtr;
+ if ( code == "exit" || code == "exit;" ) {
+ free( line );
+ break;
+ }
+ if ( code == "cls" ) {
+ free( line );
+ linenoiseClearScreen();
+ continue;
+ }
+
+ if ( code.size() == 0 ) {
+ free( line );
+ continue;
+ }
+
+ if ( startsWith( linePtr, "edit " ) ) {
+ shellHistoryAdd( linePtr );
+
+ const char* s = linePtr + 5; // skip "edit "
+ while( *s && isspace( *s ) )
+ s++;
+
+ edit( s );
+ free( line );
+ continue;
+ }
+
+ gotInterrupted = false;
+ code = finishCode( code );
+ if ( gotInterrupted ) {
+ cout << endl;
+ free( line );
+ continue;
+ }
+
+ 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( "\"" ) == 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 );
+ wascmd = true;
+ }
+ }
+ catch ( std::exception& e ) {
+ cout << "error2:" << e.what() << endl;
+ wascmd = true;
+ }
+ }
+ }
+
+ 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 ) {
+ cout << "error:" << e.what() << endl;
+ }
+ }
+
+ shellHistoryAdd( code.c_str() );
+ free( line );
+ }
+
+ shellHistoryDone();
+ }
+
+ mongo::dbexitCalled = true;
+ return 0;
+}
+
+#ifdef _WIN32
+int wmain( int argc, wchar_t* argvW[] ) {
+ static mongo::StaticObserver staticObserver;
+ UINT initialConsoleInputCodePage = GetConsoleCP();
+ UINT initialConsoleOutputCodePage = GetConsoleOutputCP();
+ SetConsoleCP( CP_UTF8 );
+ SetConsoleOutputCP( CP_UTF8 );
+ int returnValue = -1;
+ try {
+ WindowsCommandLine wcl( argc, argvW );
+ returnValue = _main( argc, wcl.argv() );
+ }
+ catch ( mongo::DBException& e ) {
+ cerr << "exception: " << e.what() << endl;
+ }
+ SetConsoleCP( initialConsoleInputCodePage );
+ SetConsoleOutputCP( initialConsoleOutputCodePage );
+ ::_exit(returnValue);
+}
+#else // #ifdef _WIN32
+int main( int argc, char* argv[] ) {
+ static mongo::StaticObserver staticObserver;
+ int returnCode;
+ try {
+ returnCode = _main( argc , argv );
+ }
+ catch ( mongo::DBException& e ) {
+ cerr << "exception: " << e.what() << endl;
+ returnCode = 1;
+ }
+ _exit(returnCode);
+}
+#endif // #ifdef _WIN32
diff --git a/src/mongo/shell/linenoise.cpp b/src/mongo/shell/linenoise.cpp
new file mode 100644
index 00000000000..2b77514bce2
--- /dev/null
+++ b/src/mongo/shell/linenoise.cpp
@@ -0,0 +1,2652 @@
+/* linenoise.c -- guerrilla line editing library against the idea that a
+ * 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
+ * the 2010 UNIX computers around.
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Switch to gets() if $TERM is something we can't support.
+ * - Filter bogus Ctrl+<char> combinations.
+ * - Win32 support
+ *
+ * Bloat:
+ * - Completion?
+ * - History search like Ctrl+r in readline?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * with three sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * CHA (Cursor Horizontal Absolute)
+ * Sequence: ESC [ n G
+ * Effect: moves cursor to column n (1 based)
+ *
+ * EL (Erase Line)
+ * Sequence: ESC [ n K
+ * Effect: if n is 0 or missing, clear from cursor to end of line
+ * Effect: if n is 1, clear from beginning of line to cursor
+ * Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ * Sequence: ESC [ n C
+ * Effect: moves cursor forward of n chars
+ *
+ * The following are used to clear the screen: ESC [ H ESC [ 2 J
+ * This is actually composed of two sequences:
+ *
+ * cursorhome
+ * Sequence: ESC [ H
+ * Effect: moves the cursor to upper left corner
+ *
+ * ED2 (Clear entire screen)
+ * Sequence: ESC [ 2 J
+ * Effect: clear the whole screen
+ *
+ */
+
+#ifdef _WIN32
+
+#include <conio.h>
+#include <windows.h>
+#include <io.h>
+#define snprintf _snprintf // Microsoft headers use underscores in some names
+#define strcasecmp _stricmp
+#define strdup _strdup
+#define isatty _isatty
+#define write _write
+#define STDIN_FILENO 0
+
+#else /* _WIN32 */
+
+#include <signal.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <cctype>
+#include <wctype.h>
+
+#endif /* _WIN32 */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "linenoise.h"
+#include "linenoise_utf8.h"
+#include "mk_wcwidth.h"
+#include <string>
+#include <vector>
+#include <boost/smart_ptr/scoped_array.hpp>
+
+using std::string;
+using std::vector;
+
+using boost::scoped_array;
+
+using linenoise_utf8::UChar8;
+using linenoise_utf8::UChar32;
+using linenoise_utf8::copyString8to32;
+using linenoise_utf8::copyString32;
+using linenoise_utf8::copyString32to8;
+using linenoise_utf8::strlen32;
+using linenoise_utf8::strncmp32;
+using linenoise_utf8::write32;
+using linenoise_utf8::Utf8String;
+using linenoise_utf8::Utf32String;
+
+struct linenoiseCompletions {
+ vector<Utf32String> completionStrings;
+};
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+
+// make control-characters more readable
+#define ctrlChar( upperCaseASCII ) ( upperCaseASCII - 0x40 )
+
+/**
+ * Recompute widths of all characters in a UChar32 buffer
+ * @param text input buffer of Unicode characters
+ * @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 ] );
+ }
+}
+
+/**
+ * Calculate a new screen position given a starting position, screen width and character count
+ * @param x initial x position (zero-based)
+ * @param y initial y position (zero-based)
+ * @param screenColumns screen column count
+ * @param charCount character positions to advance
+ * @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 ) {
+ xOut = x;
+ yOut = y;
+ int charsRemaining = charCount;
+ 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
+ xOut = 0;
+ ++yOut;
+ }
+}
+
+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 PromptInfo : public PromptBase {
+
+ PromptInfo( const UChar8* textPtr, int columns ) {
+ promptExtraLines = 0;
+ promptLastLinePosition = 0;
+ promptPreviousLen = 0;
+ promptScreenColumns = columns;
+ Utf32String tempUnicode( textPtr );
+
+ // strip control characters from the prompt -- we do allow newline
+ UChar32* pIn = tempUnicode.get();
+ UChar32* pOut = pIn;
+ while ( *pIn ) {
+ UChar32 c = *pIn;
+ if ( '\n' == c || !isControlChar( c ) ) {
+ *pOut = c;
+ ++pOut;
+ }
+ ++pIn;
+ }
+ *pOut = 0;
+ promptChars = pOut - tempUnicode.get();
+ promptText = tempUnicode;
+
+ int x = 0;
+ for ( int i = 0; i < promptChars; ++i ) {
+ UChar32 c = promptText[i];
+ if ( '\n' == c ) {
+ x = 0;
+ ++promptExtraLines;
+ promptLastLinePosition = i + 1;
+ }
+ else {
+ ++x;
+ if ( x >= promptScreenColumns ) {
+ x = 0;
+ ++promptExtraLines;
+ promptLastLinePosition = i + 1;
+ }
+ }
+ }
+ promptIndentation = promptChars - promptLastLinePosition;
+ promptCursorRowOffset = promptExtraLines;
+ }
+};
+
+// 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()
+
+// 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
+
+ DynamicPrompt( PromptBase& pi, int initialDirection ) : searchTextLen( 0 ), direction( initialDirection ) {
+ promptScreenColumns = pi.promptScreenColumns;
+ promptCursorRowOffset = 0;
+ Utf32String emptyString( 1 );
+ searchText = emptyString;
+ 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 (!)
+ promptPreviousLen = promptChars;
+ 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 );
+ }
+
+ 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 );
+ size_t endIndex = promptStartLength + searchTextLen;
+ memcpy( &tempUnicode[endIndex], endSearchBasePrompt.get(), sizeof( UChar32 ) * ( endSearchBasePrompt.length() + 1 ) );
+ tempUnicode.initFromBuffer();
+ promptText = tempUnicode;
+ }
+
+ void updateSearchText( const UChar32* textPtr ) {
+ Utf32String tempUnicode( textPtr );
+ searchTextLen = tempUnicode.chars();
+ searchText = tempUnicode;
+ updateSearchPrompt();
+ }
+};
+
+class KillRing {
+ 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;
+
+ KillRing() : size( 0 ), index( 0 ), lastAction( actionOther ) {
+ theRing.reserve( capacity );
+ }
+
+ void kill( const UChar32* text, int textLen, bool forward ) {
+ if ( textLen == 0 ) {
+ return;
+ }
+ 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 ) );
+ }
+ temp[resultLen] = 0;
+ temp.initFromBuffer();
+ theRing[slot] = temp;
+ }
+ else {
+ if ( size < capacity ) {
+ if ( size > 0 ) {
+ memmove( &indexToSlot[1], &indexToSlot[0], size );
+ }
+ indexToSlot[0] = size;
+ size++;
+ theRing.push_back( killedText );
+ }
+ else {
+ int slot = indexToSlot[capacity - 1];
+ theRing[slot] = killedText;
+ memmove( &indexToSlot[1], &indexToSlot[0], capacity - 1 );
+ indexToSlot[0] = slot;
+ }
+ index = 0;
+ }
+ }
+
+ Utf32String* yank() {
+ return ( size > 0 ) ? &theRing[indexToSlot[index]] : 0;
+ }
+
+ Utf32String* yankPop() {
+ if ( size == 0 ) {
+ return 0;
+ }
+ ++index;
+ 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 )
+
+ 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 ) {
+ buf32[0] = 0;
+ }
+ void preloadBuffer( const UChar8* preloadText ) {
+ size_t ucharCount;
+ int errorCode;
+ 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; }
+};
+
+// Special codes for keyboard input:
+//
+// Between Windows and the various Linux "terminal" programs, there is some
+// pretty diverse behavior in the "scan codes" and escape sequences we are
+// presented with. So ... we'll translate them all into our own pidgin
+// pseudocode, trying to stay out of the way of UTF-8 and international
+// characters. Here's the general plan.
+//
+// "User input keystrokes" (key chords, whatever) will be encoded as a single value.
+// The low 21 bits are reserved for Unicode characters. Popular function-type keys
+// get their own codes in the range 0x10200000 to (if needed) 0x1FE00000, currently
+// just arrow keys, Home, End and Delete. Keypresses with Ctrl get ORed with
+// 0x20000000, with Alt get ORed with 0x40000000. So, Ctrl+Alt+Home is encoded
+// as 0x20000000 + 0x40000000 + 0x10A00000 == 0x70A00000. To keep things complicated,
+// the Alt key is equivalent to prefixing the keystroke with ESC, so ESC followed by
+// D is treated the same as Alt + D ... we'll just use Emacs terminology and call
+// this "Meta". So, we will encode both ESC followed by D and Alt held down while D
+// is pressed the same, as Meta-D, encoded as 0x40000064.
+//
+// Here are the definitions of our component constants:
+//
+// 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 linenoiseCompletionCallback* completionCallback = NULL;
+
+#ifdef _WIN32
+static HANDLE console_in, console_out;
+static DWORD oldMode;
+static WORD oldDisplayAttribute;
+#else
+static struct termios orig_termios; /* in order to restore at exit */
+#endif
+
+static KillRing killRing;
+
+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;
+static int historyIndex = 0;
+static UChar8** history = NULL;
+
+// used to emulate Windows command prompt on down-arrow after a recall
+// we use -2 as our "not set" value because we add 1 to the previous index on down-arrow,
+// and zero is a valid index (so -1 is a valid "previous index")
+static int historyPreviousIndex = -2;
+static bool historyRecallMostRecent = false;
+
+static void linenoiseAtExit( void );
+
+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] ) ) {
+ return true;
+ }
+ return false;
+}
+
+static void beep() {
+ fprintf( stderr, "\x7" ); // ctrl-G == bell/beep
+ fflush( stderr );
+}
+
+void linenoiseHistoryFree( void ) {
+ if ( history ) {
+ for ( int j = 0; j < historyLen; ++j )
+ free( history[j] );
+ historyLen = 0;
+ free( history );
+ history = 0;
+ }
+}
+
+static int enableRawMode( void ) {
+#ifdef _WIN32
+ 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 ) );
+ }
+ return 0;
+#else
+ struct termios raw;
+
+ if ( ! isatty( 0 ) ) goto fatal;
+ if ( ! atexit_registered ) {
+ atexit( linenoiseAtExit );
+ atexit_registered = 1;
+ }
+ 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 );
+ /* output modes - disable post processing */
+ // this is wrong, we don't want raw output, it turns newlines into straight linefeeds
+ //raw.c_oflag &= ~(OPOST);
+ /* control modes - set 8 bit chars */
+ 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 );
+ /* 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 */
+
+ /* put terminal in raw mode after flushing */
+ if ( tcsetattr( 0, TCSADRAIN, &raw ) < 0 ) goto fatal;
+ rawmode = 1;
+ return 0;
+
+fatal:
+ errno = ENOTTY;
+ return -1;
+#endif
+}
+
+static void disableRawMode( void ) {
+#ifdef _WIN32
+ SetConsoleMode( console_in, oldMode );
+ console_in = 0;
+ console_out = 0;
+#else
+ 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 ) {
+ disableRawMode();
+}
+
+static int getScreenColumns( void ) {
+ int cols;
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO 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;
+#endif
+ // cols is 0 in certain circumstances like inside debugger, which creates further issues
+ return (cols > 0) ? cols : 80;
+}
+
+static int getScreenRows( void ) {
+ int rows;
+#ifdef _WIN32
+ CONSOLE_SCREEN_BUFFER_INFO 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;
+#endif
+ return (rows > 0) ? rows : 24;
+}
+
+static void setDisplayAttribute( bool enhancedDisplay ) {
+#ifdef _WIN32
+ if ( enhancedDisplay ) {
+ CONSOLE_SCREEN_BUFFER_INFO 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;
+ }
+ 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 */
+ }
+#endif
+}
+
+/**
+ * Display the dynamic incremental search prompt and the current user input line.
+ * @param pi PromptBase struct holding information about the prompt and our screen position
+ * @param buf32 input buffer to be displayed
+ * @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 ) {
+
+ // calculate the position of the end of the prompt
+ int 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, len, xEndOfInput, yEndOfInput );
+
+ // calculate the desired position of the cursor
+ int xCursorPos, yCursorPos;
+ calculateScreenPosition( xEndOfPrompt, yEndOfPrompt, pi.promptScreenColumns, 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 );
+ inf.dwCursorPosition.X = 0;
+ inf.dwCursorPosition.Y -= pi.promptCursorRowOffset /*- pi.promptExtraLines*/;
+ SetConsoleCursorPosition( console_out, inf.dwCursorPosition );
+ DWORD 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;
+
+ // display the input line
+ if ( write32( 1, buf32, len ) == -1 ) return;
+
+ // position the cursor
+ GetConsoleScreenBufferInfo( console_out, &inf );
+ inf.dwCursorPosition.X = xCursorPos; // 0-based on Win32
+ inf.dwCursorPosition.Y -= yEndOfInput - yCursorPos;
+ 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;
+ }
+ // 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;
+
+ // display the prompt
+ if ( write32( 1, pi.promptText.get(), pi.promptChars ) == -1 ) return;
+
+ // display the input line
+ 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;
+
+ // 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;
+ }
+ // 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;
+#endif
+
+ pi.promptCursorRowOffset = pi.promptExtraLines + yCursorPos; // remember row for next pass
+}
+
+/**
+ * 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 ) {
+
+ // check for a matching brace/bracket/paren, remember its position if found
+ int highlight = -1;
+ if ( pos < len ) {
+ /* this scans for a brace matching buf32[pos] to highlight */
+ int scanDirection = 0;
+ if ( strchr( "}])", buf32[pos] ) )
+ scanDirection = -1; /* backwards */
+ else if ( strchr( "{[(", buf32[pos] ) )
+ scanDirection = 1; /* forwards */
+
+ if ( scanDirection ) {
+ int unmatched = scanDirection;
+ for ( int i = pos + scanDirection; i >= 0 && i < len; i += scanDirection ) {
+ /* TODO: the right thing when inside a string */
+ if ( strchr( "}])", buf32[i] ) )
+ --unmatched;
+ else if ( strchr( "{[(", buf32[i] ) )
+ ++unmatched;
+
+ if ( unmatched == 0 ) {
+ highlight = i;
+ break;
+ }
+ }
+ }
+ }
+
+ // calculate the position of the end of the input line
+ int xEndOfInput, yEndOfInput;
+ calculateScreenPosition( pi.promptIndentation, 0, pi.promptScreenColumns, len, xEndOfInput, yEndOfInput );
+
+ // calculate the desired position of the cursor
+ int xCursorPos, yCursorPos;
+ calculateScreenPosition( pi.promptIndentation, 0, pi.promptScreenColumns, 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 );
+ inf.dwCursorPosition.X = pi.promptIndentation; // 0-based on Win32
+ inf.dwCursorPosition.Y -= pi.promptCursorRowOffset - pi.promptExtraLines;
+ SetConsoleCursorPosition( console_out, inf.dwCursorPosition );
+ DWORD 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;
+ }
+
+ // position the cursor
+ GetConsoleScreenBufferInfo( console_out, &inf );
+ inf.dwCursorPosition.X = xCursorPos; // 0-based on Win32
+ inf.dwCursorPosition.Y -= yEndOfInput - yCursorPos;
+ 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;
+ }
+ // 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;
+
+ 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;
+
+ // 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;
+ }
+ // 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;
+#endif
+
+ pi.promptCursorRowOffset = pi.promptExtraLines + yCursorPos; // remember row for next pass
+}
+
+#ifndef _WIN32
+
+/**
+ * Read a UTF-8 sequence from the non-Windows keyboard and return the Unicode (UChar32) character it encodes
+ *
+ * @return UChar32 Unicode character
+ */
+static UChar32 readUnicodeCharacter( void ) {
+ static UChar8 utf8String[5];
+ static size_t utf8Count = 0;
+ while ( true ) {
+ UChar8 c;
+ 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;
+ UChar32 unicodeChar[2];
+ size_t ucharCount;
+ int errorCode;
+ copyString8to32( unicodeChar, utf8String, 2, ucharCount, errorCode );
+ if ( ucharCount && errorCode == 0 ) {
+ utf8Count = 0;
+ return unicodeChar[0];
+ }
+ }
+ else {
+ utf8Count = 0; // this shouldn't happen: got four bytes but no UTF-8 character
+ }
+ }
+}
+
+namespace EscapeSequenceProcessing { // move these out of global namespace
+
+// This chunk of code does parsing of the escape sequences sent by various Linux terminals.
+//
+// It handles arrow keys, Home, End and Delete keys by interpreting the sequences sent by
+// gnome terminal, xterm, rxvt, konsole, aterm and yakuake including the Alt and Ctrl key
+// combinations that are understood by linenoise.
+//
+// The parsing uses tables, a bunch of intermediate dispatch routines and a doDispatch
+// loop that reads the tables and sends control to "deeper" routines to continue the
+// parsing. The starting call to doDispatch( c, initialDispatch ) will eventually return
+// either a character (with optional CTRL and META bits set), or -1 if parsing fails, or
+// zero if an attempt to read from the keyboard fails.
+//
+// This is rather sloppy escape sequence processing, since we're not paying attention to what the
+// actual TERM is set to and are processing all key sequences for all terminals, but it works with
+// the most common keystrokes on the most common terminals. It's intricate, but the nested 'if'
+// statements required to do it directly would be worse. This way has the advantage of allowing
+// changes and extensions without having to touch a lot of code.
+
+// This is a typedef for the routine called by doDispatch(). It takes the current character
+// 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 );
+
+// 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
+};
+
+// This dispatch routine is given a dispatch table and then farms work out to routines
+// listed in the table based on the character it is called with. The dispatch routines can
+// 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 );
+ }
+ }
+ return dispatchTable.dispatch[dispatchTable.len]( c );
+}
+
+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; }
+
+// Handle ESC [ 1 ; 3 (or 5) <more stuff> escape sequences
+//
+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 ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ thisKeyMetaCtrl |= META;
+ return doDispatch( c, escLeftBracket1Semicolon3or5Dispatch );
+}
+static UChar32 escLeftBracket1Semicolon5Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ thisKeyMetaCtrl |= CTRL;
+ return doDispatch( c, escLeftBracket1Semicolon3or5Dispatch );
+}
+static CharacterDispatchRoutine escLeftBracket1SemicolonRoutines[] = {
+ escLeftBracket1Semicolon3Routine,
+ escLeftBracket1Semicolon5Routine,
+ escFailureRoutine
+};
+static CharacterDispatch escLeftBracket1SemicolonDispatch = { 2, "35", escLeftBracket1SemicolonRoutines };
+
+// Handle ESC [ 1 <more stuff> escape sequences
+//
+static UChar32 escLeftBracket1SemicolonRoutine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket1SemicolonDispatch );
+}
+static CharacterDispatchRoutine 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 };
+
+// Handle ESC [ 4 <more stuff> escape sequences
+//
+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 };
+
+// Handle ESC [ 6 <more stuff> escape sequences
+//
+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 };
+
+// Handle ESC [ 8 <more stuff> escape sequences
+//
+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 escLeftBracket1Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket1Dispatch );
+}
+static UChar32 escLeftBracket2Routine( UChar32 c ) {
+ return escFailureRoutine( c ); // Insert key, unused
+}
+static UChar32 escLeftBracket3Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket3Dispatch );
+}
+static UChar32 escLeftBracket4Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket4Dispatch );
+}
+static UChar32 escLeftBracket5Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket5Dispatch );
+}
+static UChar32 escLeftBracket6Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket6Dispatch );
+}
+static UChar32 escLeftBracket7Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket7Dispatch );
+}
+static UChar32 escLeftBracket8Routine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracket8Dispatch );
+}
+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 };
+
+// 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 };
+
+// Initial ESC dispatch -- could be a Meta prefix or the start of an escape sequence
+//
+static UChar32 escLeftBracketRoutine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escLeftBracketDispatch );
+}
+static UChar32 escORoutine( UChar32 c ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escODispatch );
+}
+static UChar32 setMetaRoutine( UChar32 c ); // need forward reference
+static CharacterDispatchRoutine 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 ) {
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escDispatch );
+}
+static CharacterDispatchRoutine 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 ) {
+ thisKeyMetaCtrl = META;
+ if ( c == 0x1B ) { // another ESC, stay in ESC processing mode
+ c = readUnicodeCharacter();
+ if ( c == 0 ) return 0;
+ return doDispatch( c, escDispatch );
+ }
+ return doDispatch( c, initialDispatch );
+}
+
+} // namespace EscapeSequenceProcessing // move these out of global namespace
+
+#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
+// simpler Emacs keystrokes, so an unmodified "left arrow" becomes Ctrl-B.
+//
+// A return value of zero means "no input available", and a return value of -1 means "invalid key".
+//
+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
+ {
+ if ( rec.EventType == KEY_EVENT ) {
+ //if ( rec.Event.KeyEvent.uChar.UnicodeChar ) {
+ char buf[1024];
+ sprintf(
+ buf,
+ "Unicode character 0x%04X, repeat count %d, virtual keycode 0x%04X, virtual scancode 0x%04X, key %s%s%s%s%s\n",
+ rec.Event.KeyEvent.uChar.UnicodeChar,
+ rec.Event.KeyEvent.wRepeatCount,
+ rec.Event.KeyEvent.wVirtualKeyCode,
+ rec.Event.KeyEvent.wVirtualScanCode,
+ rec.Event.KeyEvent.bKeyDown ? "down" : "up",
+ (rec.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) ? " L-Ctrl" : "",
+ (rec.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED) ? " R-Ctrl" : "",
+ (rec.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) ? " L-Alt" : "",
+ (rec.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED) ? " R-Alt" : ""
+ );
+ OutputDebugStringA( buf );
+ //}
+ }
+ }
+#endif
+ 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 ) {
+ 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 & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED ) ) {
+ modifierKeys |= CTRL;
+ }
+ if ( rec.Event.KeyEvent.dwControlKeyState & ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) ) {
+ modifierKeys |= META;
+ }
+ 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
+ escSeen = true;
+ continue;
+ }
+ else {
+ // we got a real character, return it
+ return modifierKeys | rec.Event.KeyEvent.uChar.UnicodeChar;
+ }
+ }
+
+#else
+ UChar32 c;
+ c = readUnicodeCharacter();
+ 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.
+ //
+#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 ) {
+ unsigned char keys[10];
+ int ret = read( 0, keys, 10 );
+
+ if ( ret <= 0 ) {
+ printf( "\nret: %d\n", ret );
+ }
+ 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
+ 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 {
+ friendlyTextBuf[0] = '^';
+ friendlyTextBuf[1] = keyCopy + 0x40;
+ friendlyTextBuf[2] = 0;
+ friendlyTextPtr = friendlyTextBuf;
+ }
+ printf( "%d x%02X (%s%s) ", key, key, prefixText, friendlyTextPtr );
+ }
+ 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 );
+ return -2;
+ }
+ }
+ }
+#endif // _DEBUG_LINUX_KEYBOARD
+
+ EscapeSequenceProcessing::thisKeyMetaCtrl = 0; // no modifiers yet at initialDispatch
+ return EscapeSequenceProcessing::doDispatch( c, EscapeSequenceProcessing::initialDispatch );
+#endif // #_WIN32
+}
+
+/**
+ * Free memory used in a recent command completion session
+ *
+ * @param lc pointer to a linenoiseCompletions struct
+ */
+static void freeCompletions( linenoiseCompletions* lc ) {
+ lc->completionStrings.clear();
+}
+
+/**
+ * convert {CTRL + 'A'}, {CTRL + 'a'} and {CTRL + ctrlChar( 'A' )} into ctrlChar( 'A' )
+ * leave META alone
+ *
+ * @param c character to clean up
+ * @return cleaned-up character
+ */
+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 >= ctrlChar( 'A' ) && d <= ctrlChar( 'Z' ) ) {
+ c = c & ~CTRL;
+ }
+ }
+ return c;
+}
+
+// break characters that may precede items to be completed
+static const char breakChars[] = " =+-/\\*?\"'`&<>;|@{([])}";
+
+// maximum number of completions to display without asking
+static const size_t completionCountCutoff = 100;
+
+/**
+ * Handle command completion, using a completionCallback() routine to provide possible substitutions
+ * This routine handles the mechanics of updating the user's input buffer with possible replacement of
+ * 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 ) {
+ 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] ) ) {
+ break;
+ }
+ }
+ ++startIndex;
+ int itemLength = pos - startIndex;
+ Utf32String unicodeCopy( &buf32[startIndex], itemLength );
+ Utf8String parseItem( unicodeCopy );
+
+ // get a list of completions
+ completionCallback( reinterpret_cast< char * >( parseItem.get() ), &lc );
+
+ // if no completions, we are done
+ if ( lc.completionStrings.size() == 0 ) {
+ beep();
+ freeCompletions( &lc );
+ return 0;
+ }
+
+ // at least one completion
+ int longestCommonPrefix = 0;
+ int displayLength = 0;
+ if ( lc.completionStrings.size() == 1 ) {
+ longestCommonPrefix = lc.completionStrings[0].length();
+ }
+ else {
+ bool keepGoing = true;
+ 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 ) ) {
+ keepGoing = false;
+ break;
+ }
+ }
+ if ( keepGoing ) {
+ ++longestCommonPrefix;
+ }
+ }
+ }
+ 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 ) {
+ displayLength = len + longestCommonPrefix - itemLength;
+ if ( displayLength > buflen ) {
+ longestCommonPrefix -= displayLength - buflen; // don't overflow buffer
+ 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 );
+ int tailIndex = startIndex + longestCommonPrefix;
+ memcpy( &displayText[tailIndex], &buf32[pos], sizeof( UChar32 ) * ( displayLength - tailIndex + 1 ) );
+ copyString32( buf32, displayText.get(), buflen + 1 );
+ pos = startIndex + longestCommonPrefix;
+ len = displayLength;
+ 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 ) );
+
+ // if any character other than tab, pass it to the main loop
+ 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 ) {
+ int savePos = pos; // move cursor to EOL to avoid overwriting the command line
+ pos = len;
+ refreshLine( pi );
+ pos = savePos;
+ 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' ) ) {
+ do {
+ c = linenoiseReadChar();
+ 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;
+ }
+ }
+
+ // if showing the list, do it the way readline does it
+ bool stopList = false;
+ if ( showCompletions ) {
+ int longestCompletion = 0;
+ for ( size_t j = 0; j < lc.completionStrings.size(); ++j) {
+ itemLength = lc.completionStrings[j].length();
+ if ( itemLength > longestCompletion ) {
+ longestCompletion = itemLength;
+ }
+ }
+ longestCompletion += 2;
+ int columnCount = pi.promptScreenColumns / longestCompletion;
+ if ( columnCount < 1) {
+ columnCount = 1;
+ }
+ 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 );
+ 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 );
+ 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 ) {
+ beep();
+ }
+ doBeep = true;
+ do {
+ c = linenoiseReadChar();
+ 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;
+ }
+ }
+ else {
+ printf( "\n" );
+ }
+ if ( stopList ) {
+ break;
+ }
+ 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 );
+ 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 ( 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;
+#endif
+ pi.promptCursorRowOffset = pi.promptExtraLines;
+ refreshLine( pi );
+ return 0;
+}
+
+/**
+ * Clear the screen ONLY (no redisplay of anything)
+ */
+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 );
+ DWORD count;
+ FillConsoleOutputCharacterA( screenHandle, ' ', inf.dwSize.X * inf.dwSize.Y, coord, &count );
+#else
+ if ( write( 1, "\x1b[H\x1b[2J", 7 ) <= 0 ) return;
+#endif
+}
+
+void InputBuffer::clearScreen( PromptBase& pi ) {
+ linenoiseClearScreen();
+ 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;
+#endif
+ pi.promptCursorRowOffset = pi.promptExtraLines;
+ refreshLine( pi );
+}
+
+/**
+ * Incremental history search -- take over the prompt and keyboard as the user types a search string,
+ * deletes characters from it, changes direction, and either accepts the found line (for execution or
+ * editing) or cancels.
+ * @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 ) {
+ 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;
+ scoped_array< 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 );
+
+ dp.promptPreviousLen = pi.promptPreviousLen;
+ dp.promptPreviousInputLen = pi.promptPreviousInputLen;
+ dynamicRefresh( dp, buf32, historyLineLength, historyLinePosition ); // draw user's text with our prompt
+
+ // loop until we get an exit character
+ int c;
+ bool keepLooping = true;
+ bool useSearchedLine = true;
+ bool searchAgain = false;
+ UChar32* activeHistoryLine = 0;
+ 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;
+
+ // 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() );
+ }
+ }
+ 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
+#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;
+ scoped_array< 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 ) {
+ scoped_array<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;
+
+ default:
+ if ( !isControlChar( c ) && c <= 0x0010FFFF ) { // not an action character
+ scoped_array< 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 ) {
+ bufferSize = historyLineLength + 1;
+ 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 ) {
+ 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 ) {
+ found = true;
+ break;
+ }
+ lineSearchPos += dp.direction;
+ }
+ if ( found ) {
+ historyIndex = historySearchIndex;
+ historyLineLength = lineLength;
+ historyLinePosition = lineSearchPos;
+ break;
+ }
+ 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 );
+ lineLength = ucharCount;
+ lineSearchPos = ( dp.direction > 0 ) ? 0 : ( lineLength - dp.searchTextLen );
+ }
+ else {
+ beep();
+ break;
+ }
+ }; // while
+ }
+ 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
+ }
+ } // 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 );
+ tempUnicode.initFromBuffer();
+ pb.promptText = tempUnicode;
+ pb.promptExtraLines = 0;
+ pb.promptIndentation = pi.promptIndentation;
+ pb.promptLastLinePosition = 0;
+ pb.promptPreviousInputLen = historyLineLength;
+ pb.promptCursorRowOffset = dp.promptCursorRowOffset;
+ pb.promptScreenColumns = pi.promptScreenColumns;
+ pb.promptPreviousLen = dp.promptChars;
+ if ( useSearchedLine && activeHistoryLine ) {
+ historyRecallMostRecent = true;
+ copyString32( buf32, activeHistoryLine, buflen + 1 );
+ len = historyLineLength;
+ pos = historyLinePosition;
+ }
+ if ( activeHistoryLine ) {
+ delete [] activeHistoryLine;
+ }
+ 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
+}
+
+static bool isCharacterAlphanumeric( UChar32 testChar ) {
+ return iswalnum( testChar );
+}
+
+int InputBuffer::getInputLine( PromptBase& pi ) {
+
+ // The latest history entry is always our current buffer
+ if ( len > 0 ) {
+ size_t bufferSize = sizeof( UChar32 ) * len + 1;
+ scoped_array< 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;
+
+#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;
+#endif
+
+ // the cursor starts out at the end of the prompt
+ pi.promptCursorRowOffset = pi.promptExtraLines;
+
+ // kill and yank start in "other" mode
+ killRing.lastAction = KillRing::actionOther;
+
+ // when history search returns control to us, we execute its terminating keystroke
+ int terminatingKeystroke = -1;
+
+ // if there is already text in the buffer, display it first
+ if ( len > 0 ) {
+ refreshLine( pi );
+ }
+
+ // loop collecting characters, respond to line editing characters
+ while ( true ) {
+ int c;
+ 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
+
+ if ( c == 0 ) {
+ return len;
+ }
+
+ if ( c == -1 ) {
+ refreshLine( pi );
+ continue;
+ }
+
+ 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.
+
+ killRing.lastAction = KillRing::actionOther;
+ historyRecallMostRecent = false;
+
+ // completeLine does the actual completion and replacement
+ c = completeLine( pi );
+
+ if ( c < 0 ) // return on error
+ return len;
+
+ 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;
+
+ 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] ) ) {
+ --pos;
+ }
+ 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;
+
+ 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';
+ }
+ ++pos;
+ }
+ while ( pos < len && isCharacterAlphanumeric( buf32[pos] ) ) {
+ if ( buf32[pos] >= 'A' && buf32[pos] <= 'Z' ) {
+ buf32[pos] += 'a' - 'A';
+ }
+ ++pos;
+ }
+ refreshLine( pi );
+ }
+ 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;
+ }
+ 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( 'E' ): // ctrl-E, move cursor to end of line
+ case END_KEY:
+ killRing.lastAction = KillRing::actionOther;
+ pos = len;
+ refreshLine( pi );
+ 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 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;
+
+ 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;
+
+ // 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.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( '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 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';
+ }
+ ++pos;
+ }
+ refreshLine( pi );
+ }
+ 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;
+ scoped_array< 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;
+ }
+ 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 );
+ }
+ 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;
+
+ 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 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;
+ }
+ refreshLine( pi );
+ }
+ 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;
+ }
+ 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 ) {
+ size_t ucharCount = restoredText->length();
+ 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;
+ }
+ else {
+ beep();
+ }
+ }
+ 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 ) {
+ size_t ucharCount = restoredText->length();
+ 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 );
+ 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;
+#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;
+ scoped_array< 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;
+
+ // 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 < buflen ) {
+ if ( isControlChar( c ) ) { // don't insert control characters
+ beep();
+ break;
+ }
+ if ( len == pos ) { // at end of buffer
+ buf32[pos] = c;
+ ++pos;
+ ++len;
+ buf32[len] = '\0';
+ if ( pi.promptIndentation + len < pi.promptScreenColumns ) {
+ if ( len > pi.promptPreviousInputLen )
+ pi.promptPreviousInputLen = len;
+ /* 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
+ }
+ break;
+ }
+ }
+ return len;
+}
+
+string preloadedBufferContents; // used with linenoisePreloadBuffer
+string preloadErrorMessage;
+
+/**
+ * linenoisePreloadBuffer provides text to be inserted into the command buffer
+ *
+ * the provided text will be processed to be usable and will be used to preload
+ * the input buffer on the next call to linenoise()
+ *
+ * @param preloadText text to begin with on the next call to linenoise()
+ */
+void linenoisePreloadBuffer( const char* preloadText ) {
+
+ if ( ! preloadText ) {
+ return;
+ }
+ int bufferSize = strlen( preloadText ) + 1;
+ scoped_array< 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
+ continue;
+ }
+ if ( '\n' == c || '\t' == c ) { // note newline or tab
+ whitespaceSeen = true;
+ continue;
+ }
+ if ( isControlChar( c ) ) { // remove other control characters, flag for message
+ controlsStripped = true;
+ *pOut++ = ' ';
+ continue;
+ }
+ if ( whitespaceSeen ) { // convert whitespace to a single space
+ *pOut++ = ' ';
+ whitespaceSeen = false;
+ }
+ *pOut++ = c;
+ }
+ *pOut = 0;
+ int processedLength = pOut - tempBuffer.get();
+ bool lineTruncated = false;
+ if ( processedLength > ( LINENOISE_MAX_LINE - 1 ) ) {
+ lineTruncated = true;
+ tempBuffer[ LINENOISE_MAX_LINE - 1 ] = 0;
+ }
+ preloadedBufferContents = tempBuffer.get();
+ if ( controlsStripped ) {
+ preloadErrorMessage += " [Edited line: control characters were converted to spaces]\n";
+ }
+ 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 ) );
+ preloadErrorMessage += buf;
+ }
+}
+
+/**
+ * linenoise is a readline replacement.
+ *
+ * call it with a prompt to display and it will return a line of input from the user
+ *
+ * @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 );
+ 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() ) {
+ scoped_array<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' ) ) {
+ --len;
+ buf8[len] = '\0';
+ }
+ return strdup( buf8.get() ); // caller must free buffer
+ }
+ else {
+ char* buf8 = strdup( preloadedBufferContents.c_str() );
+ preloadedBufferContents.clear();
+ return buf8; // caller must free buffer
+ }
+ }
+ 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() ) );
+ preloadedBufferContents.clear();
+ }
+ int count = ib.getInputLine( pi );
+ disableRawMode();
+ printf( "\n" );
+ if ( count == -1 ) {
+ return NULL;
+ }
+ size_t bufferSize = sizeof( UChar32 ) * ib.length() + 1;
+ scoped_array<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
+ scoped_array<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' ) {
+ --count;
+ buf8[ count ] = '\0';
+ }
+ return strdup( buf8.get() ); // caller must free buffer
+ }
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback( linenoiseCompletionCallback* fn ) {
+ completionCallback = fn;
+}
+
+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 ) {
+ return 0;
+ }
+ if ( history == NULL ) {
+ history = reinterpret_cast< UChar8** >( malloc( sizeof( UChar8* ) * historyMaxLen ) );
+ if (history == NULL) {
+ return 0;
+ }
+ memset( history, 0, ( sizeof( char* ) * historyMaxLen ) );
+ }
+ 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 ) );
+ --historyLen;
+ if ( --historyPreviousIndex < -1 ) {
+ historyPreviousIndex = -2;
+ }
+ }
+
+ // convert newlines in multi-line code to spaces before storing
+ UChar8* p = linecopy;
+ while ( *p ) {
+ if ( *p == '\n' ) {
+ *p = ' ';
+ }
+ ++p;
+ }
+ history[historyLen] = linecopy;
+ ++historyLen;
+ return 1;
+}
+
+int linenoiseHistorySetMaxLen( int len ) {
+ if ( len < 1 ) {
+ return 0;
+ }
+ if ( history ) {
+ int tocopy = historyLen;
+ UChar8** newHistory = reinterpret_cast< UChar8** >( malloc( sizeof( UChar8* ) * len ) );
+ if ( newHistory == NULL ) {
+ return 0;
+ }
+ if ( len < tocopy ) {
+ tocopy = len;
+ }
+ memcpy( newHistory, history + historyMaxLen - tocopy, sizeof( UChar8* ) * tocopy );
+ free( history );
+ history = newHistory;
+ }
+ historyMaxLen = len;
+ if ( historyLen > historyMaxLen ) {
+ historyLen = historyMaxLen;
+ }
+ return 1;
+}
+
+/* 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 ) {
+ return -1;
+ }
+
+ for ( int j = 0; j < historyLen; ++j ) {
+ if ( history[j][0] != '\0' ) {
+ fprintf ( fp, "%s\n", history[j] );
+ }
+ }
+ fclose( fp );
+ return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * 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 ) {
+ 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' );
+ }
+ if ( p ) {
+ *p = '\0';
+ }
+ if ( p != buf ) {
+ linenoiseHistoryAdd( buf );
+ }
+ }
+ fclose( fp );
+ return 0;
+}
diff --git a/src/mongo/shell/linenoise.h b/src/mongo/shell/linenoise.h
new file mode 100644
index 00000000000..06edcbdfb88
--- /dev/null
+++ b/src/mongo/shell/linenoise.h
@@ -0,0 +1,54 @@
+/* linenoise.h -- guerrilla line editing library against the idea that a
+ * line editing lib needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+struct linenoiseCompletions;
+
+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 );
+
+#endif /* __LINENOISE_H */
diff --git a/src/mongo/shell/linenoise_utf8.cpp b/src/mongo/shell/linenoise_utf8.cpp
new file mode 100644
index 00000000000..d906c9676f2
--- /dev/null
+++ b/src/mongo/shell/linenoise_utf8.cpp
@@ -0,0 +1,348 @@
+// linenoise_utf8.cpp
+/*
+ * Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/shell/linenoise_utf8.h"
+
+#ifdef _WIN32
+#include <io.h>
+#include "mongo/platform/windows_basic.h"
+#include "mongo/util/text.h"
+#else
+#include <unistd.h>
+#endif
+
+namespace linenoise_utf8 {
+
+/**
+ * Convert a null terminated UTF-8 string from UTF-8 and store it in a UChar32 destination buffer
+ * Always null terminates the destination string if at least one character position is available
+ * 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 ) {
+ conversionErrorCode = BadUTF8_no_error;
+ if ( outputBufferSizeInCharacters == 0 ) {
+ outputUnicodeCharacterCount = 0;
+ return;
+ }
+ static const UChar32 errorCharacter = 0xFFFD;
+ const UChar8* pIn = utf8input;
+ UChar32* pOut = uchar32output;
+ UChar32 uchar32;
+ int reducedBufferSize = outputBufferSizeInCharacters - 1;
+ 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
+ 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 );
+ pIn += 2;
+ }
+ 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 );
+ pIn += 3;
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 2;
+ }
+ }
+ 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 );
+ pIn += 3;
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 2;
+ }
+ }
+ 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 );
+ pIn += 3;
+ }
+ 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 ) ) {
+ conversionErrorCode |= BadUTF8_surrogate;
+ pIn += 3;
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 2;
+ }
+ }
+ 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 );
+ pIn += 3;
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 2;
+ }
+ }
+ 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 );
+ pIn += 4;
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 3;
+ }
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 2;
+ }
+ }
+ 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 );
+ pIn += 4;
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 3;
+ }
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 2;
+ }
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 1;
+ }
+ }
+ else {
+ conversionErrorCode |= BadUTF8_invalid_byte;
+ pIn += 1;
+ }
+ if ( uchar32 != 0xFEFF ) { // do not store Byte Order Mark
+ *pOut++ = uchar32;
+ }
+ }
+ *pOut = 0;
+ outputUnicodeCharacterCount = pOut - uchar32output;
+}
+
+/**
+ * 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 ) {
+ *dest32++ = *source32++;
+ }
+ *dest32 = 0;
+ }
+}
+
+/**
+ * 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 outputUTF8ByteCount = 0;
+ if ( outputBufferSizeInBytes ) {
+ size_t reducedBufferSize = outputBufferSizeInBytes - 4;
+ while ( *source32 && charCount-- && outputUTF8ByteCount < reducedBufferSize ) {
+ UChar32 c = *source32++;
+ if ( c <= 0x7F ) {
+ *dest8++ = c;
+ outputUTF8ByteCount += 1;
+ }
+ 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 );
+ outputUTF8ByteCount += 3;
+ }
+ else if ( c <= 0x1FFFFF ) {
+ *dest8++ = 0xF0 | ( c >> 18 );
+ *dest8++ = 0x80 | ( 0x3F & ( c >> 12) );
+ *dest8++ = 0x80 | ( 0x3F & ( c >> 6) );
+ *dest8++ = 0x80 | ( 0x3F & c );
+ outputUTF8ByteCount += 4;
+ }
+ }
+ *dest8 = 0;
+ }
+ return outputUTF8ByteCount;
+}
+
+/**
+ * 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 );
+}
+
+/**
+ * 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 length = 0;
+ while ( *str32++ ) {
+ ++length;
+ }
+ return length;
+}
+
+/**
+ * Compare two UChar32 null-terminated strings with length parameter
+ *
+ * @param first32 First string to compare
+ * @param second32 Second string to compare
+ * @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 ) {
+ return *first32 - *second32;
+ }
+ ++first32;
+ ++second32;
+ }
+ return 0;
+}
+
+/**
+ * Internally convert an array of UChar32 characters of specified length to UTF-8 and write it to fileHandle
+ *
+ * @param fileHandle File handle to write to
+ * @param string32 Source UChar32 characters, may not be null terminated
+ * @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 ) {
+ size_t tempBufferBytes = 4 * sourceLengthInCharacters + 1;
+ boost::scoped_array<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 ) {
+ return -1;
+ }
+ return count;
+ }
+ else {
+ return _write( fileHandle, tempCharString.get(), count );
+ }
+#else
+ return write( fileHandle, tempCharString.get(), count );
+#endif
+}
+
+} // namespace linenoise_utf8
diff --git a/src/mongo/shell/linenoise_utf8.h b/src/mongo/shell/linenoise_utf8.h
new file mode 100644
index 00000000000..cb418223732
--- /dev/null
+++ b/src/mongo/shell/linenoise_utf8.h
@@ -0,0 +1,234 @@
+// linenoise_utf8.h
+/*
+ * Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <boost/smart_ptr/scoped_array.hpp>
+#include <string.h>
+
+namespace linenoise_utf8 {
+
+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
+};
+
+/**
+ * Convert a null terminated UTF-8 string from UTF-8 and store it in a UChar32 destination buffer
+ * Always null terminates the destination string if at least one character position is available
+ * 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 );
+
+/**
+ * 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 );
+
+/**
+ * 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 );
+
+/**
+ * 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 );
+
+/**
+ * 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 );
+
+/**
+ * Compare two UChar32 null-terminated strings with length parameter
+ *
+ * @param first32 First string to compare
+ * @param second32 Second string to compare
+ * @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 );
+
+/**
+ * Internally convert an array of UChar32 characters of specified length to UTF-8 and write it to fileHandle
+ *
+ * @param fileHandle File handle to write to
+ * @param string32 Source UChar32 character array, may not be null terminated
+ * @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 );
+
+/**
+ * Template and classes for UChar8 and UChar32 strings
+ */
+template <typename char_type>
+struct UtfStringMixin {
+ typedef char_type char_t; // inherited
+
+ 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& 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]; }
+
+ 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 );
+ }
+
+protected:
+ size_t _len; // in units of char_t without nul
+ size_t _cap; // size of _str buffer including nul
+ size_t _chars; // number of codepoints
+ boost::scoped_array<char_t> _str;
+};
+
+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 Utf32String& c ); // defined after utf32String
+
+private:
+ 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 );
+ }
+};
+
+struct Utf32String : public UtfStringMixin<UChar32> {
+ Utf32String() {}
+ explicit Utf32String( const UChar32* s ) {
+ _chars = _len = strlen32( s );
+ _cap = _len + 1;
+ _str.reset( new UChar32[_cap] );
+ memcpy( _str.get(), s, _cap * sizeof( UChar32 ) );
+ }
+ 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[_len] = 0;
+ }
+ explicit Utf32String( const UChar8* s, int chars = -1 ) {
+ initFrom8( s, chars );
+ }
+ explicit Utf32String( const Utf8String& c ) {
+ initFrom8( c.get(), c.chars() );
+ }
+ explicit Utf32String( size_t reserve ) {
+ _len = 0;
+ _cap = reserve;
+ _chars = 0;
+ _str.reset( new UChar32[_cap] );
+ _str[0] = 0;
+ }
+ void initFromBuffer( void ) {
+ _chars = _len = strlen32( _str.get() );
+ }
+
+private:
+ 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 {
+ temp._cap = chars + 1;
+ }
+ temp._str.reset( new char_t[temp._cap] );
+ int error;
+ copyString8to32( temp._str.get(), s, temp._cap, temp._chars, error );
+ temp._len = temp._chars;
+ this->swap( temp );
+ }
+};
+
+inline Utf8String::Utf8String( const Utf32String& s ) {
+ initFrom32( s.get(), s.chars() );
+}
+
+} // namespace linenoise_utf8
diff --git a/src/mongo/shell/mk_wcwidth.cpp b/src/mongo/shell/mk_wcwidth.cpp
new file mode 100644
index 00000000000..217bd714b04
--- /dev/null
+++ b/src/mongo/shell/mk_wcwidth.cpp
@@ -0,0 +1,309 @@
+/*
+ * This is an implementation of wcwidth() and wcswidth() (defined in
+ * IEEE Std 1002.1-2001) for Unicode.
+ *
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+ *
+ * In fixed-width output devices, Latin characters all occupy a single
+ * "cell" position of equal width, whereas ideographic CJK characters
+ * occupy two such cells. Interoperability between terminal-line
+ * applications and (teletype-style) character terminals using the
+ * UTF-8 encoding requires agreement on which character should advance
+ * the cursor by how many cell positions. No established formal
+ * standards exist at present on which Unicode character shall occupy
+ * how many cell positions on character terminals. These routines are
+ * a first attempt of defining such behavior based on simple rules
+ * applied to data provided by the Unicode Consortium.
+ *
+ * For some graphical characters, the Unicode standard explicitly
+ * defines a character-cell width via the definition of the East Asian
+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+ * In all these cases, there is no ambiguity about which width a
+ * terminal shall use. For characters in the East Asian Ambiguous (A)
+ * class, the width choice depends purely on a preference of backward
+ * compatibility with either historic CJK or Western practice.
+ * Choosing single-width for these characters is easy to justify as
+ * the appropriate long-term solution, as the CJK practice of
+ * displaying these characters as double-width comes from historic
+ * implementation simplicity (8-bit encoded characters were displayed
+ * single-width and 16-bit ones double-width, even for Greek,
+ * Cyrillic, etc.) and not any typographic considerations.
+ *
+ * Much less clear is the choice of width for the Not East Asian
+ * (Neutral) class. Existing practice does not dictate a width for any
+ * of these characters. It would nevertheless make sense
+ * typographically to allocate two character cells to characters such
+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+ * represented adequately with a single-width glyph. The following
+ * routines at present merely assign a single-cell width to all
+ * neutral characters, in the interest of simplicity. This is not
+ * entirely satisfactory and should be reconsidered before
+ * establishing a formal standard in this area. At the moment, the
+ * decision which Not East Asian (Neutral) characters should be
+ * represented by double-width glyphs cannot yet be answered by
+ * applying a simple rule from the Unicode database content. Setting
+ * up a proper standard for the behavior of UTF-8 character terminals
+ * will require a careful analysis not only of each Unicode character,
+ * but also of each presentation form, something the author of these
+ * routines has avoided to do so far.
+ *
+ * http://www.unicode.org/unicode/reports/tr11/
+ *
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+
+#include <wchar.h>
+
+struct interval {
+ 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;
+
+ 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;
+}
+
+
+/* The following two functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ * - The null character (U+0000) has a column width of 0.
+ *
+ * - Other C0/C1 control characters and DEL will lead to a return
+ * value of -1.
+ *
+ * - Non-spacing and enclosing combining characters (general
+ * category code Mn or Me in the Unicode database) have a
+ * column width of 0.
+ *
+ * - SOFT HYPHEN (U+00AD) has a column width of 1.
+ *
+ * - Other format characters (general category code Cf in the Unicode
+ * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ * have a column width of 0.
+ *
+ * - Spacing characters in the East Asian Wide (W) or East Asian
+ * Full-width (F) category as defined in Unicode Technical
+ * Report #11 have a column width of 2.
+ *
+ * - All remaining characters (including all printable
+ * ISO 8859-1 and WGL4 characters, Unicode control characters,
+ * etc.) have a column width of 1.
+ *
+ * This implementation assumes that wchar_t characters are encoded
+ * 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 }
+ };
+
+ /* 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;
+
+ /* 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)));
+}
+
+
+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;
+
+ return width;
+}
+
+
+/*
+ * The following functions are the same as mk_wcwidth() and
+ * mk_wcswidth(), except that spacing characters in the East Asian
+ * Ambiguous (A) category as defined in Unicode Technical Report #11
+ * have a column width of 2. This variant might be useful for users of
+ * CJK legacy encodings who want to migrate to UCS without changing
+ * 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 }
+ };
+
+ /* binary search in table of non-spacing characters */
+ if (bisearch(ucs, ambiguous,
+ sizeof(ambiguous) / sizeof(struct interval) - 1))
+ return 2;
+
+ return mk_wcwidth(ucs);
+}
+
+
+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;
+
+ return width;
+}
diff --git a/src/mongo/shell/mk_wcwidth.h b/src/mongo/shell/mk_wcwidth.h
new file mode 100644
index 00000000000..f544addb628
--- /dev/null
+++ b/src/mongo/shell/mk_wcwidth.h
@@ -0,0 +1,62 @@
+/*
+ * This is an implementation of wcwidth() and wcswidth() (defined in
+ * IEEE Std 1002.1-2001) for Unicode.
+ *
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+ *
+ * In fixed-width output devices, Latin characters all occupy a single
+ * "cell" position of equal width, whereas ideographic CJK characters
+ * occupy two such cells. Interoperability between terminal-line
+ * applications and (teletype-style) character terminals using the
+ * UTF-8 encoding requires agreement on which character should advance
+ * the cursor by how many cell positions. No established formal
+ * standards exist at present on which Unicode character shall occupy
+ * how many cell positions on character terminals. These routines are
+ * a first attempt of defining such behavior based on simple rules
+ * applied to data provided by the Unicode Consortium.
+ *
+ * For some graphical characters, the Unicode standard explicitly
+ * defines a character-cell width via the definition of the East Asian
+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+ * In all these cases, there is no ambiguity about which width a
+ * terminal shall use. For characters in the East Asian Ambiguous (A)
+ * class, the width choice depends purely on a preference of backward
+ * compatibility with either historic CJK or Western practice.
+ * Choosing single-width for these characters is easy to justify as
+ * the appropriate long-term solution, as the CJK practice of
+ * displaying these characters as double-width comes from historic
+ * implementation simplicity (8-bit encoded characters were displayed
+ * single-width and 16-bit ones double-width, even for Greek,
+ * Cyrillic, etc.) and not any typographic considerations.
+ *
+ * Much less clear is the choice of width for the Not East Asian
+ * (Neutral) class. Existing practice does not dictate a width for any
+ * of these characters. It would nevertheless make sense
+ * typographically to allocate two character cells to characters such
+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+ * represented adequately with a single-width glyph. The following
+ * routines at present merely assign a single-cell width to all
+ * neutral characters, in the interest of simplicity. This is not
+ * entirely satisfactory and should be reconsidered before
+ * establishing a formal standard in this area. At the moment, the
+ * decision which Not East Asian (Neutral) characters should be
+ * represented by double-width glyphs cannot yet be answered by
+ * applying a simple rule from the Unicode database content. Setting
+ * up a proper standard for the behavior of UTF-8 character terminals
+ * will require a careful analysis not only of each Unicode character,
+ * but also of each presentation form, something the author of these
+ * routines has avoided to do so far.
+ *
+ * http://www.unicode.org/unicode/reports/tr11/
+ *
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+
+extern int mk_wcwidth(int ucs);
diff --git a/src/mongo/shell/mongo.ico b/src/mongo/shell/mongo.ico
new file mode 100755
index 00000000000..1eba9ed5131
--- /dev/null
+++ b/src/mongo/shell/mongo.ico
Binary files differ
diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js
new file mode 100644
index 00000000000..5e18f38fb63
--- /dev/null
+++ b/src/mongo/shell/mongo.js
@@ -0,0 +1,102 @@
+// mongo.js
+
+// NOTE 'Mongo' may be defined here or in MongoJS.cpp. Add code to init, not to this constructor.
+if ( typeof Mongo == "undefined" ){
+ Mongo = function( host ){
+ this.init( host );
+ }
+}
+
+if ( ! Mongo.prototype ){
+ throw "Mongo.prototype not defined";
+}
+
+if ( ! Mongo.prototype.find )
+ Mongo.prototype.find = function( ns , query , fields , limit , skip , batchSize , options ){ throw "find not implemented"; }
+if ( ! Mongo.prototype.insert )
+ Mongo.prototype.insert = function( ns , obj ){ throw "insert not implemented"; }
+if ( ! Mongo.prototype.remove )
+ Mongo.prototype.remove = function( ns , pattern ){ throw "remove not implemented;" }
+if ( ! Mongo.prototype.update )
+ Mongo.prototype.update = function( ns , query , obj , upsert ){ throw "update not implemented;" }
+
+if ( typeof mongoInject == "function" ){
+ mongoInject( Mongo.prototype );
+}
+
+Mongo.prototype.setSlaveOk = function( value ) {
+ if( value == undefined ) value = true;
+ this.slaveOk = value;
+}
+
+Mongo.prototype.getSlaveOk = function() {
+ return this.slaveOk || false;
+}
+
+Mongo.prototype.getDB = function( name ){
+ if (jsTest.options().keyFile && ((typeof this.authenticated == 'undefined') || !this.authenticated)) {
+ jsTest.authenticate(this)
+ }
+ return new DB( this , name );
+}
+
+Mongo.prototype.getDBs = function(){
+ var res = this.getDB( "admin" ).runCommand( { "listDatabases" : 1 } );
+ if ( ! res.ok )
+ throw "listDatabases failed:" + tojson( res );
+ return res;
+}
+
+Mongo.prototype.adminCommand = function( cmd ){
+ return this.getDB( "admin" ).runCommand( cmd );
+}
+
+Mongo.prototype.setLogLevel = function( logLevel ){
+ return this.adminCommand({ setParameter : 1, logLevel : logLevel })
+}
+
+Mongo.prototype.getDBNames = function(){
+ return this.getDBs().databases.map(
+ function(z){
+ return z.name;
+ }
+ );
+}
+
+Mongo.prototype.getCollection = function(ns){
+ var idx = ns.indexOf( "." );
+ if ( idx < 0 )
+ throw "need . in ns";
+ var db = ns.substring( 0 , idx );
+ var c = ns.substring( idx + 1 );
+ return this.getDB( db ).getCollection( c );
+}
+
+Mongo.prototype.toString = function(){
+ return "connection to " + this.host;
+}
+Mongo.prototype.tojson = Mongo.prototype.toString;
+
+connect = function( url , user , pass ){
+ chatty( "connecting to: " + url )
+
+ if ( user && ! pass )
+ throw "you specified a user and not a password. either you need a password, or you're using the old connect api";
+
+ var idx = url.lastIndexOf( "/" );
+
+ var db;
+
+ if ( idx < 0 )
+ db = new Mongo().getDB( url );
+ else
+ db = new Mongo( url.substring( 0 , idx ) ).getDB( url.substring( idx + 1 ) );
+
+ if ( user && pass ){
+ if ( ! db.auth( user , pass ) ){
+ throw "couldn't login";
+ }
+ }
+
+ return db;
+}
diff --git a/src/mongo/shell/mongo.sln b/src/mongo/shell/mongo.sln
new file mode 100644
index 00000000000..66b8450b2ed
--- /dev/null
+++ b/src/mongo/shell/mongo.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mongo", "mongo.vcxproj", "{FE959BD8-8EE2-4555-AE59-9FA14FFD410E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A} = {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpiderMonkey pre-build step", "..\..\third_party\js-1.7\SpiderMonkey-prebuild.vcxproj", "{7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Debug|Win32.Build.0 = Debug|Win32
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Debug|x64.ActiveCfg = Debug|x64
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Debug|x64.Build.0 = Debug|x64
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Release|Win32.ActiveCfg = Release|Win32
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Release|Win32.Build.0 = Release|Win32
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Release|x64.ActiveCfg = Release|x64
+ {FE959BD8-8EE2-4555-AE59-9FA14FFD410E}.Release|x64.Build.0 = Release|x64
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Debug|Win32.Build.0 = Debug|Win32
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Debug|x64.ActiveCfg = Debug|x64
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Debug|x64.Build.0 = Debug|x64
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Release|Win32.ActiveCfg = Release|Win32
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Release|Win32.Build.0 = Release|Win32
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Release|x64.ActiveCfg = Release|x64
+ {7FA15DF8-14C8-4FD5-897B-6FACE8FDCF2A}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/mongo/shell/mongo.vcxproj b/src/mongo/shell/mongo.vcxproj
new file mode 100755
index 00000000000..5fc8aff9adf
--- /dev/null
+++ b/src/mongo/shell/mongo.vcxproj
@@ -0,0 +1,1244 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win2008PlusDebug|Win32">
+ <Configuration>Win2008PlusDebug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win2008PlusDebug|x64">
+ <Configuration>Win2008PlusDebug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win2008PlusRelease|Win32">
+ <Configuration>Win2008PlusRelease</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win2008PlusRelease|x64">
+ <Configuration>Win2008PlusRelease</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{FE959BD8-8EE2-4555-AE59-9FA14FFD410E}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>mongo</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">
+ <IncludePath>..\..\third_party\js-1.7;..\..\third_party\pcre-8.30;..\;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include</IncludePath>
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <LargeAddressAware>true</LargeAddressAware>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <LargeAddressAware>true</LargeAddressAware>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <LargeAddressAware>true</LargeAddressAware>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <LargeAddressAware>true</LargeAddressAware>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..;..\..;..\..\third_party\boost</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <DisableSpecificWarnings>4355;4800;4267;4244</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>ws2_32.lib;psapi.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <PreBuildEvent>
+ <Command>"$(ProjectDir)..\..\third_party\js-1.7\jskwgen.exe" "$(ProjectDir)..\..\third_party\js-1.7\jsautokw.h"
+cscript //Nologo createCPPfromJavaScriptFiles.js "$(ProjectDir).."</Command>
+ <Message>Build jsautokw.h for SpiderMonkey, create mongo.cpp and mongo-server.cpp from JavaScript source files</Message>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\third_party\js-1.7\jsapi.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsarena.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsarray.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsatom.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsbool.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jscntxt.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdate.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdbgapi.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdhash.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdtoa.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsemit.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsexn.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsfun.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsgc.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jshash.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsinterp.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsiter.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jslock.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jslog2.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jslong.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsmath.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsnum.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsobj.c">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">$(IntDir)\$(InputName)1.obj</ObjectFileName>
+ <XMLDocumentationFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">$(IntDir)\$(InputName)1.xml</XMLDocumentationFileName>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsopcode.c">
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4047;4146</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4047;4146</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">4047;4146</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">4047;4146</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4047;4146;4267;4244</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4047;4146;4267;4244</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4047;4146;4267;4244</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4047;4146;4267;4244</DisableSpecificWarnings>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsparse.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsprf.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsregexp.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsscan.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsscope.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsscript.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsstr.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsutil.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsxdrapi.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsxml.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\prmjtime.c">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">JSFILE;EXPORT_JS_API;JS_C_STRINGS_ARE_UTF8;XP_WIN;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">4355;4800;4267;4244;4334</DisableSpecificWarnings>
+ </ClCompile>
+ <ClCompile Include="..\client\authentication_table.cpp" />
+ <ClCompile Include="..\client\connection_factory.cpp" />
+ <ClCompile Include="..\db\dbmessage.cpp" />
+ <ClCompile Include="..\util\concurrency\mutexdebugger.cpp" />
+ <ClCompile Include="..\util\time_support.cpp" />
+ <ClCompile Include="linenoise_utf8.cpp" />
+ <ClCompile Include="mk_wcwidth.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v2\src\v2_operations.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v2\src\v2_path.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v2\src\v2_portability.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\codecvt_error_category.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\operations.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\path.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\path_traits.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\portability.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\unique_path.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\utf8_codecvt_facet.cpp">
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">$(IntDir)filesystem_utf8_codecvt_facet.obj</ObjectFileName>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\windows_file_codecvt.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\cmdline.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\config_file.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\convert.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\options_description.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\parsers.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\positional_options.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\split.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\utf8_codecvt_facet.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\value_semantic.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\variables_map.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\winmain.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\system\src\error_code.cpp" />
+ <ClCompile Include="..\..\third_party\boost\libs\thread\src\win32\thread.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\thread\src\win32\tss_dll.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\thread\src\win32\tss_pe.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">BOOST_THREAD_BUILD_LIB;BOOST_ALL_NO_LIB;XP_WIN;HAVE_CONFIG_H;OLDJS;MONGO_EXPOSE_MACROS;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="..\bson\oid.cpp" />
+ <ClCompile Include="..\client\clientAndShell.cpp" />
+ <ClCompile Include="..\client\connpool.cpp" />
+ <ClCompile Include="..\client\dbclient_rs.cpp" />
+ <ClCompile Include="..\client\syncclusterconnection.cpp" />
+ <ClCompile Include="..\db\commands.cpp" />
+ <ClCompile Include="..\db\lasterror.cpp" />
+ <ClCompile Include="..\db\nonce.cpp" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcrecpp.cc" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_chartables.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_compile.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_config.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_dfa_exec.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_exec.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_fullinfo.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_get.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_globals.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_maketables.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_newline.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_ord2utf8.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_refcount.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_scanner.cc" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_stringpiece.cc" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_study.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_tables.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_ucd.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_valid_utf8.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_version.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_xclass.c" />
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcreposix.c" />
+ <ClCompile Include="..\scripting\bench.cpp" />
+ <ClCompile Include="..\scripting\engine_spidermonkey.cpp" />
+ <ClCompile Include="..\scripting\sm_db.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win2008PlusDebug|x64'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Win2008PlusRelease|x64'">true</ExcludedFromBuild>
+ </ClCompile>
+ <ClCompile Include="..\scripting\utils.cpp" />
+ <ClCompile Include="linenoise.cpp" />
+ <ClCompile Include="..\util\background.cpp" />
+ <ClCompile Include="..\util\concurrency\spin_lock.cpp" />
+ <ClCompile Include="..\util\log.cpp" />
+ <ClCompile Include="..\util\net\message.cpp" />
+ <ClCompile Include="..\util\net\message_port.cpp" />
+ <ClCompile Include="..\util\net\sock.cpp" />
+ <ClCompile Include="..\util\password.cpp" />
+ <ClCompile Include="..\util\ramlog.cpp" />
+ <ClCompile Include="..\util\signal_handlers.cpp" />
+ <ClCompile Include="..\util\stacktrace.cpp" />
+ <ClCompile Include="..\util\startup_test.cpp" />
+ <ClCompile Include="..\util\stringutils.cpp" />
+ <ClCompile Include="..\util\text.cpp" />
+ <ClCompile Include="..\util\processinfo_win32.cpp" />
+ <ClCompile Include="..\util\assert_util.cpp" />
+ <ClCompile Include="..\util\md5main.cpp" />
+ <ClCompile Include="..\util\md5.cpp" />
+ <ClCompile Include="..\util\base64.cpp" />
+ <ClCompile Include="..\util\debug_util.cpp" />
+ <ClCompile Include="..\client\dbclient.cpp" />
+ <ClCompile Include="..\client\dbclientcursor.cpp" />
+ <ClCompile Include="..\db\jsobj.cpp" />
+ <ClCompile Include="..\db\json.cpp" />
+ <ClCompile Include="..\pch.cpp" />
+ <ClCompile Include="..\scripting\engine.cpp" />
+ <ClCompile Include="..\util\timer.cpp" />
+ <ClCompile Include="..\util\util.cpp" />
+ <ClCompile Include="..\util\version.cpp" />
+ <ClCompile Include="dbshell.cpp" />
+ <ClCompile Include="mongo-server.cpp" />
+ <ClCompile Include="mongo.cpp" />
+ <ClCompile Include="shell_utils.cpp" />
+ <ClCompile Include="shell_utils_extended.cpp" />
+ <ClCompile Include="shell_utils_launcher.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\third_party\js-1.7\jskeyword.tbl" />
+ <None Include="..\..\third_party\js-1.7\jsopcode.tbl" />
+ <None Include="collection.js" />
+ <None Include="db.js" />
+ <None Include="mongo.js" />
+ <None Include="mr.js" />
+ <None Include="query.js" />
+ <None Include="replsetbridge.js" />
+ <None Include="replsettest.js" />
+ <None Include="servers.js" />
+ <None Include="servers_misc.js" />
+ <None Include="shardingtest.js" />
+ <None Include="utils.js" />
+ <None Include="utils_sh.js" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\third_party\js-1.7\jsapi.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsarena.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsarray.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsatom.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsbit.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsbool.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsclist.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jscntxt.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jscompat.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsconfig.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jscpucfg.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsdate.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsdbgapi.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsdhash.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsdtoa.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsemit.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsexn.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsfile.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsfun.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsgc.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jshash.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsinterp.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsiter.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jslibmath.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jslock.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jslong.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsmath.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsnum.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsobj.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsopcode.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsosdep.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsotypes.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsparse.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsprf.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsprvtd.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jspubtd.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsregexp.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsscan.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsscope.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsscript.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsstddef.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsstr.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jstypes.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsutil.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsxdrapi.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\jsxml.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\prmjtime.h" />
+ <ClInclude Include="..\..\third_party\js-1.7\resource.h" />
+ <ClInclude Include="..\client\authentication_table.h" />
+ <ClInclude Include="..\client\dbclientinterface.h" />
+ <ClInclude Include="..\platform\atomic_intrinsics.h" />
+ <ClInclude Include="..\platform\atomic_intrinsics_win32.h" />
+ <ClInclude Include="..\platform\atomic_word.h" />
+ <ClInclude Include="..\platform\basic.h" />
+ <ClInclude Include="..\platform\compiler.h" />
+ <ClInclude Include="..\platform\compiler_msvc.h" />
+ <ClInclude Include="..\platform\float_utils.h" />
+ <ClInclude Include="..\platform\windows_basic.h" />
+ <ClInclude Include="linenoise_utf8.h" />
+ <ClInclude Include="mk_wcwidth.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\config.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcrecpp.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcrecpparg.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcrecpp_internal.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre_internal.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre_scanner.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre_stringpiece.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\ucp.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\ucpinternal.h" />
+ <ClInclude Include="..\..\third_party\pcre-8.30\ucptable.h" />
+ <ClInclude Include="..\bson\bson-inl.h" />
+ <ClInclude Include="..\bson\bsonelement.h" />
+ <ClInclude Include="..\bson\bsonmisc.h" />
+ <ClInclude Include="..\bson\bsonobj.h" />
+ <ClInclude Include="..\bson\bsonobjbuilder.h" />
+ <ClInclude Include="..\bson\bsonobjiterator.h" />
+ <ClInclude Include="..\bson\bsontypes.h" />
+ <ClInclude Include="..\bson\bson_db.h" />
+ <ClInclude Include="..\bson\inline_decls.h" />
+ <ClInclude Include="..\bson\oid.h" />
+ <ClInclude Include="..\bson\ordering.h" />
+ <ClInclude Include="..\bson\stringdata.h" />
+ <ClInclude Include="..\bson\util\atomic_int.h" />
+ <ClInclude Include="..\bson\util\builder.h" />
+ <ClInclude Include="..\bson\util\misc.h" />
+ <ClInclude Include="..\client\connpool.h" />
+ <ClInclude Include="..\client\constants.h" />
+ <ClInclude Include="..\client\dbclientcursor.h" />
+ <ClInclude Include="..\client\dbclient_rs.h" />
+ <ClInclude Include="..\client\redef_macros.h" />
+ <ClInclude Include="..\client\syncclusterconnection.h" />
+ <ClInclude Include="..\client\undef_macros.h" />
+ <ClInclude Include="..\db\client.h" />
+ <ClInclude Include="..\db\clientcursor.h" />
+ <ClInclude Include="..\db\client_common.h" />
+ <ClInclude Include="..\db\cloner.h" />
+ <ClInclude Include="..\db\cmdline.h" />
+ <ClInclude Include="..\db\commands.h" />
+ <ClInclude Include="..\db\concurrency.h" />
+ <ClInclude Include="..\db\curop-inl.h" />
+ <ClInclude Include="..\db\curop.h" />
+ <ClInclude Include="..\db\cursor.h" />
+ <ClInclude Include="..\db\database.h" />
+ <ClInclude Include="..\db\databaseholder.h" />
+ <ClInclude Include="..\db\db.h" />
+ <ClInclude Include="..\db\dbhelpers.h" />
+ <ClInclude Include="..\db\dbmessage.h" />
+ <ClInclude Include="..\db\diskloc.h" />
+ <ClInclude Include="..\db\dur.h" />
+ <ClInclude Include="..\db\d_concurrency.h" />
+ <ClInclude Include="..\db\d_globals.h" />
+ <ClInclude Include="..\db\index.h" />
+ <ClInclude Include="..\db\indexkey.h" />
+ <ClInclude Include="..\db\instance.h" />
+ <ClInclude Include="..\db\jsobj.h" />
+ <ClInclude Include="..\db\jsobjmanipulator.h" />
+ <ClInclude Include="..\db\json.h" />
+ <ClInclude Include="..\db\key.h" />
+ <ClInclude Include="..\db\lasterror.h" />
+ <ClInclude Include="linenoise.h" />
+ <ClInclude Include="..\db\matcher.h" />
+ <ClInclude Include="..\db\mongommf.h" />
+ <ClInclude Include="..\db\mongomutex.h" />
+ <ClInclude Include="..\db\namespace-inl.h" />
+ <ClInclude Include="..\db\namespace.h" />
+ <ClInclude Include="..\db\namespacestring.h" />
+ <ClInclude Include="..\db\nonce.h" />
+ <ClInclude Include="..\db\oplog.h" />
+ <ClInclude Include="..\db\oplogreader.h" />
+ <ClInclude Include="..\db\pdfile.h" />
+ <ClInclude Include="..\db\projection.h" />
+ <ClInclude Include="..\db\querypattern.h" />
+ <ClInclude Include="..\db\queryutil-inl.h" />
+ <ClInclude Include="..\db\queryutil.h" />
+ <ClInclude Include="..\db\repl.h" />
+ <ClInclude Include="..\db\replutil.h" />
+ <ClInclude Include="..\db\repl\health.h" />
+ <ClInclude Include="..\db\repl\rs.h" />
+ <ClInclude Include="..\db\repl\rs_config.h" />
+ <ClInclude Include="..\db\repl\rs_exception.h" />
+ <ClInclude Include="..\db\repl\rs_member.h" />
+ <ClInclude Include="..\db\repl\rs_optime.h" />
+ <ClInclude Include="..\db\security.h" />
+ <ClInclude Include="..\db\security_common.h" />
+ <ClInclude Include="..\db\stats\top.h" />
+ <ClInclude Include="..\pch.h" />
+ <ClInclude Include="..\scripting\engine.h" />
+ <ClInclude Include="..\scripting\engine_spidermonkey.h" />
+ <ClInclude Include="..\s\d_chunk_manager.h" />
+ <ClInclude Include="..\s\shard.h" />
+ <ClInclude Include="..\s\util.h" />
+ <ClInclude Include="..\targetver.h" />
+ <ClInclude Include="..\util\allocator.h" />
+ <ClInclude Include="..\util\assert_util.h" />
+ <ClInclude Include="..\util\background.h" />
+ <ClInclude Include="..\util\base64.h" />
+ <ClInclude Include="..\util\concurrency\list.h" />
+ <ClInclude Include="..\util\concurrency\msg.h" />
+ <ClInclude Include="..\util\concurrency\mutex.h" />
+ <ClInclude Include="..\util\concurrency\mutexdebugger.h" />
+ <ClInclude Include="..\util\concurrency\race.h" />
+ <ClInclude Include="..\util\concurrency\rwlock.h" />
+ <ClInclude Include="..\util\concurrency\rwlockimpl.h" />
+ <ClInclude Include="..\util\concurrency\shared_mutex_win.hpp" />
+ <ClInclude Include="..\util\concurrency\spin_lock.h" />
+ <ClInclude Include="..\util\concurrency\task.h" />
+ <ClInclude Include="..\util\concurrency\threadlocal.h" />
+ <ClInclude Include="..\util\concurrency\thread_pool.h" />
+ <ClInclude Include="..\util\concurrency\value.h" />
+ <ClInclude Include="..\util\debug_util.h" />
+ <ClInclude Include="..\util\embedded_builder.h" />
+ <ClInclude Include="..\util\file.h" />
+ <ClInclude Include="..\util\file_allocator.h" />
+ <ClInclude Include="..\util\goodies.h" />
+ <ClInclude Include="..\util\hashtab.h" />
+ <ClInclude Include="..\util\heapcheck.h" />
+ <ClInclude Include="..\util\hex.h" />
+ <ClInclude Include="..\util\log.h" />
+ <ClInclude Include="..\util\md5.h" />
+ <ClInclude Include="..\util\md5.hpp" />
+ <ClInclude Include="..\util\mongoutils\html.h" />
+ <ClInclude Include="..\util\mongoutils\str.h" />
+ <ClInclude Include="..\util\net\hostandport.h" />
+ <ClInclude Include="..\util\net\listen.h" />
+ <ClInclude Include="..\util\net\message.h" />
+ <ClInclude Include="..\util\net\message_port.h" />
+ <ClInclude Include="..\util\net\sock.h" />
+ <ClInclude Include="..\util\optime.h" />
+ <ClInclude Include="..\util\password.h" />
+ <ClInclude Include="..\util\paths.h" />
+ <ClInclude Include="..\util\processinfo.h" />
+ <ClInclude Include="..\util\progress_meter.h" />
+ <ClInclude Include="..\util\ramlog.h" />
+ <ClInclude Include="..\util\signal_handlers.h" />
+ <ClInclude Include="..\util\stacktrace.h" />
+ <ClInclude Include="..\util\startup_test.h" />
+ <ClInclude Include="..\util\stringutils.h" />
+ <ClInclude Include="..\util\text.h" />
+ <ClInclude Include="..\util\timer-win32-inl.h" />
+ <ClInclude Include="..\util\timer.h" />
+ <ClInclude Include="..\util\time_support.h" />
+ <ClInclude Include="..\util\version.h" />
+ <ClInclude Include="shell_utils.h" />
+ <ClInclude Include="shell_utils_extended.h" />
+ <ClInclude Include="shell_utils_launcher.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\db\db.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/mongo/shell/mongo.vcxproj.filters b/src/mongo/shell/mongo.vcxproj.filters
new file mode 100644
index 00000000000..c530723a23a
--- /dev/null
+++ b/src/mongo/shell/mongo.vcxproj.filters
@@ -0,0 +1,1208 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Boost">
+ <UniqueIdentifier>{d630f16b-0ee6-4e3a-ae6d-7108f2c1e50a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="bson">
+ <UniqueIdentifier>{a33442e2-39da-4c70-8310-6de9fa70cd71}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="bson\util">
+ <UniqueIdentifier>{27dae3d6-9b4d-4618-824b-96ae899f7f2c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="client">
+ <UniqueIdentifier>{fc0f6c1a-9627-4254-9b5e-0bcb8b3257f3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="db">
+ <UniqueIdentifier>{1044ce7b-72c4-4892-82c0-f46d8708a6ff}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="db\repl">
+ <UniqueIdentifier>{fc91e28f-f11f-4875-b0f5-638e704872d0}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="db\stats">
+ <UniqueIdentifier>{311ce022-bacb-4778-86ec-b17a92107a0c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="s">
+ <UniqueIdentifier>{c155f2dc-07c4-4fde-99ca-f8ed2eb5a2c0}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="scripting">
+ <UniqueIdentifier>{2d0fd975-0cc9-43dc-ac8e-53cb8c3a0040}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party">
+ <UniqueIdentifier>{b68efe41-5e2c-4bef-b538-5265a839fc7a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\pcre">
+ <UniqueIdentifier>{291e0d72-13ca-42d7-b0fd-2e7b5f89639f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="util">
+ <UniqueIdentifier>{2a0d6120-434d-4732-ac31-2a7bf077f6ee}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="util\concurrency">
+ <UniqueIdentifier>{a1e59094-b70c-463a-8dc1-691efe337f14}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="util\net">
+ <UniqueIdentifier>{474e6ad2-cf05-44b1-bfa9-95b86c0177d2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="util\mongoutils">
+ <UniqueIdentifier>{f5c2814a-be7e-47b4-a217-097f47ddd591}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="JavaScript source files">
+ <UniqueIdentifier>{473e7192-9f2a-47c5-ad95-e5b75d4f48f9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\pcre\Header Files">
+ <UniqueIdentifier>{d615e21d-d5a5-44bf-8633-bc0eae7a762a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\pcre\Source Files">
+ <UniqueIdentifier>{a6e3cfe2-28b6-4a25-a9cf-7c1ada600611}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\SpiderMonkey">
+ <UniqueIdentifier>{76ff04cb-0cf7-4580-a182-99d5dd692a09}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\SpiderMonkey\Header Files">
+ <UniqueIdentifier>{4c306191-f715-41eb-9e8e-7c7af9a347b8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="third_party\SpiderMonkey\Source Files">
+ <UniqueIdentifier>{0622c796-87f3-4f5e-a75f-cb5964cf729d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Generated from JavaScript source">
+ <UniqueIdentifier>{96e4c411-7ab4-4bcd-b7c6-a33059f5d492}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{a8fe0b4e-5fb7-486f-a3d1-d14fd85c33f2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{bd5bff22-c052-4aa7-96ae-c49becf1a0ef}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="util\Header Files">
+ <UniqueIdentifier>{202be73d-a11f-48a4-bee2-280b66dbb432}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="util\Source Files">
+ <UniqueIdentifier>{6603da1a-0530-4d55-aff7-61c46a010198}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="db\Header Files">
+ <UniqueIdentifier>{5d0b1ae0-ec8a-4c09-9cac-6f7b0de60de9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="db\Source FIles">
+ <UniqueIdentifier>{9e8a8d7a-2910-4943-b8ed-0247d6221434}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="platform">
+ <UniqueIdentifier>{de9ce563-1b79-44a3-a88b-2ca15f134666}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\scripting\engine.cpp">
+ <Filter>scripting</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\dbclient.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\dbclientcursor.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\pch.cpp" />
+ <ClCompile Include="..\client\connpool.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\scripting\utils.cpp">
+ <Filter>scripting</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\syncclusterconnection.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\scripting\engine_spidermonkey.cpp">
+ <Filter>scripting</Filter>
+ </ClCompile>
+ <ClCompile Include="mongo.cpp">
+ <Filter>Generated from JavaScript source</Filter>
+ </ClCompile>
+ <ClCompile Include="mongo-server.cpp">
+ <Filter>Generated from JavaScript source</Filter>
+ </ClCompile>
+ <ClCompile Include="..\scripting\bench.cpp">
+ <Filter>scripting</Filter>
+ </ClCompile>
+ <ClCompile Include="..\bson\oid.cpp">
+ <Filter>bson</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\dbclient_rs.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\concurrency\spin_lock.cpp">
+ <Filter>util\concurrency</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\net\message.cpp">
+ <Filter>util\net</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\net\message_port.cpp">
+ <Filter>util\net</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\net\sock.cpp">
+ <Filter>util\net</Filter>
+ </ClCompile>
+ <ClCompile Include="..\scripting\sm_db.cpp">
+ <Filter>scripting</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\clientAndShell.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\thread\src\win32\thread.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\thread\src\win32\tss_dll.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\thread\src\win32\tss_pe.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\system\src\error_code.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v2\src\v2_operations.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v2\src\v2_path.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v2\src\v2_portability.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\codecvt_error_category.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\operations.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\path.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\path_traits.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\portability.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\unique_path.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\utf8_codecvt_facet.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\filesystem\v3\src\windows_file_codecvt.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\cmdline.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\config_file.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\convert.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\options_description.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\parsers.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\positional_options.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\split.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\utf8_codecvt_facet.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\value_semantic.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\variables_map.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\boost\libs\program_options\src\winmain.cpp">
+ <Filter>Boost</Filter>
+ </ClCompile>
+ <ClCompile Include="..\db\commands.cpp">
+ <Filter>db\Source FIles</Filter>
+ </ClCompile>
+ <ClCompile Include="..\db\jsobj.cpp">
+ <Filter>db\Source FIles</Filter>
+ </ClCompile>
+ <ClCompile Include="..\db\json.cpp">
+ <Filter>db\Source FIles</Filter>
+ </ClCompile>
+ <ClCompile Include="..\db\lasterror.cpp">
+ <Filter>db\Source FIles</Filter>
+ </ClCompile>
+ <ClCompile Include="..\db\nonce.cpp">
+ <Filter>db\Source FIles</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\debug_util.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\md5.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\stringutils.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\text.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\assert_util.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\background.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\base64.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\log.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\md5main.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\password.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\processinfo_win32.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\ramlog.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\util.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\version.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\text.cpp">
+ <Filter>shell</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\debug_util.cpp">
+ <Filter>shell</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\md5.cpp">
+ <Filter>util\Main</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\startup_test.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\stacktrace.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\timer.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_chartables.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_compile.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_config.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_dfa_exec.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_exec.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_fullinfo.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_get.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_globals.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_maketables.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_newline.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_ord2utf8.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_refcount.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_scanner.cc">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_stringpiece.cc">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_study.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_tables.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_ucd.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_valid_utf8.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_version.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcre_xclass.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcrecpp.cc">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\pcre-8.30\pcreposix.c">
+ <Filter>third_party\pcre\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsapi.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsarena.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsarray.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsatom.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsbool.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jscntxt.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdate.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdbgapi.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdhash.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsdtoa.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsemit.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsexn.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsfun.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsgc.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jshash.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsinterp.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsiter.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jslock.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jslog2.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jslong.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsmath.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsnum.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsobj.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsopcode.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsparse.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsprf.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsregexp.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsscan.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsscope.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsscript.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsstr.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsutil.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsxdrapi.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\jsxml.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\third_party\js-1.7\prmjtime.c">
+ <Filter>third_party\SpiderMonkey\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dbshell.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="shell_utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="shell_utils_extended.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="shell_utils_launcher.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\signal_handlers.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="linenoise.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="linenoise_utf8.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mk_wcwidth.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\time_support.cpp">
+ <Filter>util\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\db\dbmessage.cpp">
+ <Filter>db\Source FIles</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\connection_factory.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ <ClCompile Include="..\util\concurrency\mutexdebugger.cpp">
+ <Filter>util\concurrency</Filter>
+ </ClCompile>
+ <ClCompile Include="..\client\authentication_table.cpp">
+ <Filter>client</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="collection.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="db.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="mongo.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="mr.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="query.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="servers.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="utils.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="utils_sh.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="servers_misc.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="replsetbridge.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="replsettest.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="shardingtest.js">
+ <Filter>JavaScript source files</Filter>
+ </None>
+ <None Include="..\..\third_party\js-1.7\jskeyword.tbl">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </None>
+ <None Include="..\..\third_party\js-1.7\jsopcode.tbl">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\bson\util\atomic_int.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\pch.h" />
+ <ClInclude Include="..\bson\bson-inl.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bson_db.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bsonelement.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bsonmisc.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bsonobj.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bsonobjbuilder.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bsonobjiterator.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\bsontypes.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\util\builder.h">
+ <Filter>bson\util</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\connpool.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\constants.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\s\d_chunk_manager.h">
+ <Filter>s</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\dbclient_rs.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\dbclientcursor.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\scripting\engine.h">
+ <Filter>scripting</Filter>
+ </ClInclude>
+ <ClInclude Include="..\scripting\engine_spidermonkey.h">
+ <Filter>scripting</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl\health.h">
+ <Filter>db\repl</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\net\hostandport.h">
+ <Filter>util\net</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\mongoutils\html.h">
+ <Filter>util\mongoutils</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\inline_decls.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\list.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\net\listen.h">
+ <Filter>util\net</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\net\message.h">
+ <Filter>util\net</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\net\message_port.h">
+ <Filter>util\net</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\util\misc.h">
+ <Filter>bson\util</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\msg.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\mutex.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\mutexdebugger.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\oid.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\ordering.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\race.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\redef_macros.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl\rs_config.h">
+ <Filter>db\repl</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl\rs_optime.h">
+ <Filter>db\repl</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl\rs_exception.h">
+ <Filter>db\repl</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl\rs_member.h">
+ <Filter>db\repl</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\rwlockimpl.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\rwlock.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\s\shard.h">
+ <Filter>s</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\shared_mutex_win.hpp">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\net\sock.h">
+ <Filter>util\net</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\spin_lock.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\mongoutils\str.h">
+ <Filter>util\mongoutils</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson\stringdata.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\syncclusterconnection.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\task.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\threadlocal.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\thread_pool.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\stats\top.h">
+ <Filter>db\stats</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\undef_macros.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ <ClInclude Include="..\s\util.h">
+ <Filter>s</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\concurrency\value.h">
+ <Filter>util\concurrency</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\client.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\client_common.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\clientcursor.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\cloner.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\cmdline.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\commands.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\concurrency.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\curop-inl.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\curop.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\namespace-inl.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\namespace.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\cursor.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\d_concurrency.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\d_globals.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\database.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\databaseholder.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\db.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\dbhelpers.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\dbmessage.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\diskloc.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\dur.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\index.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\indexkey.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\instance.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\jsobj.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\jsobjmanipulator.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\json.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\key.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\lasterror.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\matcher.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\mongommf.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\mongomutex.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\namespacestring.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\nonce.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\oplog.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\oplogreader.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\pdfile.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\projection.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\querypattern.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\queryutil-inl.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\queryutil.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\replutil.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\repl\rs.h">
+ <Filter>db\repl</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\security.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\security_common.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\client.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\client_common.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\clientcursor.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\cloner.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\cmdline.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\commands.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\concurrency.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\namespace-inl.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\db\namespace.h">
+ <Filter>db\Header</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\progress_meter.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\allocator.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\assert_util.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\background.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\base64.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\debug_util.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\embedded_builder.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\file.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\file_allocator.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\goodies.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\hashtab.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\heapcheck.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\hex.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\log.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\md5.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\md5.hpp">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\optime.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\password.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\paths.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\processinfo.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\ramlog.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\stringutils.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\text.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\time_support.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\timer.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\version.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\startup_test.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\stacktrace.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\targetver.h" />
+ <ClInclude Include="..\util\timer-win32-inl.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\config.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre_internal.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcrecpp.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre_stringpiece.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcrecpp_internal.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\ucp.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\ucpinternal.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\ucptable.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcre_scanner.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\pcre-8.30\pcrecpparg.h">
+ <Filter>third_party\pcre\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsarena.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsarray.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsatom.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsbit.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsbool.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsclist.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jscntxt.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jscompat.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsconfig.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jscpucfg.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsdate.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsdbgapi.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsdhash.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsdtoa.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsemit.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsexn.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsfile.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsfun.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsgc.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jshash.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsinterp.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsiter.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jslibmath.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jslock.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jslong.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsmath.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsnum.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsobj.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsopcode.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsosdep.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsotypes.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsparse.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsprf.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsprvtd.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jspubtd.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsregexp.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsscan.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsscope.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsscript.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsstddef.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsstr.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jstypes.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsutil.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsxdrapi.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsxml.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\prmjtime.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\resource.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="shell_utils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="shell_utils_launcher.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="shell_utils_extended.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\signal_handlers.h">
+ <Filter>util\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="linenoise.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="linenoise_utf8.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mk_wcwidth.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\third_party\js-1.7\jsapi.h">
+ <Filter>third_party\SpiderMonkey\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\dbclientinterface.h">
+ <Filter>db\Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\atomic_intrinsics.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\atomic_intrinsics_win32.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\atomic_word.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\basic.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\compiler.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\compiler_msvc.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\float_utils.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\platform\windows_basic.h">
+ <Filter>platform</Filter>
+ </ClInclude>
+ <ClInclude Include="..\client\authentication_table.h">
+ <Filter>client</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\db\db.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/mongo/shell/mr.js b/src/mongo/shell/mr.js
new file mode 100644
index 00000000000..7b0814dd557
--- /dev/null
+++ b/src/mongo/shell/mr.js
@@ -0,0 +1,95 @@
+// mr.js
+
+MR = {};
+
+MR.init = function(){
+ $max = 0;
+ $arr = [];
+ emit = MR.emit;
+ $numEmits = 0;
+ $numReduces = 0;
+ $numReducesToDB = 0;
+ gc(); // this is just so that keep memory size sane
+}
+
+MR.cleanup = function(){
+ MR.init();
+ gc();
+}
+
+MR.emit = function(k,v){
+ $numEmits++;
+ var num = nativeHelper.apply( get_num_ , [ k ] );
+ var data = $arr[num];
+ if ( ! data ){
+ data = { key : k , values : new Array(1000) , count : 0 };
+ $arr[num] = data;
+ }
+ data.values[data.count++] = v;
+ $max = Math.max( $max , data.count );
+}
+
+MR.doReduce = function( useDB ){
+ $numReduces++;
+ if ( useDB )
+ $numReducesToDB++;
+ $max = 0;
+ for ( var i=0; i<$arr.length; i++){
+ var data = $arr[i];
+ if ( ! data )
+ continue;
+
+ if ( useDB ){
+ var x = tempcoll.findOne( { _id : data.key } );
+ if ( x ){
+ data.values[data.count++] = x.value;
+ }
+ }
+
+ var r = $reduce( data.key , data.values.slice( 0 , data.count ) );
+ if ( r && r.length && r[0] ){
+ data.values = r;
+ data.count = r.length;
+ }
+ else{
+ data.values[0] = r;
+ data.count = 1;
+ }
+
+ $max = Math.max( $max , data.count );
+
+ if ( useDB ){
+ if ( data.count == 1 ){
+ tempcoll.save( { _id : data.key , value : data.values[0] } );
+ }
+ else {
+ tempcoll.save( { _id : data.key , value : data.values.slice( 0 , data.count ) } );
+ }
+ }
+ }
+}
+
+MR.check = function(){
+ if ( $max < 2000 && $arr.length < 1000 ){
+ return 0;
+ }
+ MR.doReduce();
+ if ( $max < 2000 && $arr.length < 1000 ){
+ return 1;
+ }
+ MR.doReduce( true );
+ $arr = [];
+ $max = 0;
+ reset_num();
+ gc();
+ return 2;
+}
+
+MR.finalize = function(){
+ tempcoll.find().forEach(
+ function(z){
+ z.value = $finalize( z._id , z.value );
+ tempcoll.save( z );
+ }
+ );
+}
diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js
new file mode 100644
index 00000000000..29351be2ebb
--- /dev/null
+++ b/src/mongo/shell/query.js
@@ -0,0 +1,379 @@
+// query.js
+
+if ( typeof DBQuery == "undefined" ){
+ DBQuery = function( mongo , db , collection , ns , query , fields , limit , skip , batchSize , options ){
+
+ this._mongo = mongo; // 0
+ this._db = db; // 1
+ this._collection = collection; // 2
+ this._ns = ns; // 3
+
+ this._query = query || {}; // 4
+ this._fields = fields; // 5
+ this._limit = limit || 0; // 6
+ this._skip = skip || 0; // 7
+ this._batchSize = batchSize || 0;
+ this._options = options || 0;
+
+ this._cursor = null;
+ this._numReturned = 0;
+ this._special = false;
+ this._prettyShell = false;
+ }
+ print( "DBQuery probably won't have array access " );
+}
+
+DBQuery.prototype.help = function () {
+ print("find() modifiers")
+ print("\t.sort( {...} )")
+ print("\t.limit( n )")
+ print("\t.skip( n )")
+ print("\t.count() - total # of objects matching query, ignores skip,limit")
+ print("\t.size() - total # of objects cursor would return, honors skip,limit")
+ print("\t.explain([verbose])")
+ print("\t.hint(...)")
+ print("\t.addOption(n) - adds op_query options -- see wire protocol")
+ print("\t._addSpecial(name, value) - http://dochub.mongodb.org/core/advancedqueries#AdvancedQueries-Metaqueryoperators")
+ print("\t.batchSize(n) - sets the number of docs to return per getMore")
+ print("\t.showDiskLoc() - adds a $diskLoc field to each returned object")
+ print("\t.min(idxDoc)")
+ print("\t.max(idxDoc)")
+
+ print("\nCursor methods");
+ print("\t.toArray() - iterates through docs and returns an array of the results")
+ print("\t.forEach( func )")
+ print("\t.map( func )")
+ print("\t.hasNext()")
+ print("\t.next()")
+ print("\t.objsLeftInBatch() - returns count of docs left in current batch (when exhausted, a new getMore will be issued)")
+ print("\t.count(applySkipLimit) - runs command at server")
+ print("\t.itcount() - iterates through documents and counts them")
+}
+
+DBQuery.prototype.clone = function(){
+ var q = new DBQuery( this._mongo , this._db , this._collection , this._ns ,
+ this._query , this._fields ,
+ this._limit , this._skip , this._batchSize , this._options );
+ q._special = this._special;
+ return q;
+}
+
+DBQuery.prototype._ensureSpecial = function(){
+ if ( this._special )
+ return;
+
+ var n = { query : this._query };
+ this._query = n;
+ this._special = true;
+}
+
+DBQuery.prototype._checkModify = function(){
+ if ( this._cursor )
+ throw "query already executed";
+}
+
+DBQuery.prototype._exec = function(){
+ if ( ! this._cursor ){
+ assert.eq( 0 , this._numReturned );
+ this._cursor = this._mongo.find( this._ns , this._query , this._fields , this._limit , this._skip , this._batchSize , this._options );
+ this._cursorSeen = 0;
+ }
+ return this._cursor;
+}
+
+DBQuery.prototype.limit = function( limit ){
+ this._checkModify();
+ this._limit = limit;
+ return this;
+}
+
+DBQuery.prototype.batchSize = function( batchSize ){
+ this._checkModify();
+ this._batchSize = batchSize;
+ return this;
+}
+
+
+DBQuery.prototype.addOption = function( option ){
+ this._options |= option;
+ return this;
+}
+
+DBQuery.prototype.skip = function( skip ){
+ this._checkModify();
+ this._skip = skip;
+ return this;
+}
+
+DBQuery.prototype.hasNext = function(){
+ this._exec();
+
+ if ( this._limit > 0 && this._cursorSeen >= this._limit )
+ return false;
+ var o = this._cursor.hasNext();
+ return o;
+}
+
+DBQuery.prototype.next = function(){
+ this._exec();
+
+ var o = this._cursor.hasNext();
+ if ( o )
+ this._cursorSeen++;
+ else
+ throw "error hasNext: " + o;
+
+ var ret = this._cursor.next();
+ if ( ret.$err && this._numReturned == 0 && ! this.hasNext() )
+ throw "error: " + tojson( ret );
+
+ this._numReturned++;
+ return ret;
+}
+
+DBQuery.prototype.objsLeftInBatch = function(){
+ this._exec();
+
+ var ret = this._cursor.objsLeftInBatch();
+ if ( ret.$err )
+ throw "error: " + tojson( ret );
+
+ return ret;
+}
+
+DBQuery.prototype.readOnly = function(){
+ this._exec();
+ this._cursor.readOnly();
+ return this;
+}
+
+DBQuery.prototype.toArray = function(){
+ if ( this._arr )
+ return this._arr;
+
+ var a = [];
+ while ( this.hasNext() )
+ a.push( this.next() );
+ this._arr = a;
+ return a;
+}
+
+DBQuery.prototype.count = function( applySkipLimit ){
+ var cmd = { count: this._collection.getName() };
+ if ( this._query ){
+ if ( this._special )
+ cmd.query = this._query.query;
+ else
+ cmd.query = this._query;
+ }
+ cmd.fields = this._fields || {};
+
+ if ( applySkipLimit ){
+ if ( this._limit )
+ cmd.limit = this._limit;
+ if ( this._skip )
+ cmd.skip = this._skip;
+ }
+
+ var res = this._db.runCommand( cmd );
+ if( res && res.n != null ) return res.n;
+ throw "count failed: " + tojson( res );
+}
+
+DBQuery.prototype.size = function(){
+ return this.count( true );
+}
+
+DBQuery.prototype.countReturn = function(){
+ var c = this.count();
+
+ if ( this._skip )
+ c = c - this._skip;
+
+ if ( this._limit > 0 && this._limit < c )
+ return this._limit;
+
+ return c;
+}
+
+/**
+* iterative count - only for testing
+*/
+DBQuery.prototype.itcount = function(){
+ var num = 0;
+ while ( this.hasNext() ){
+ num++;
+ this.next();
+ }
+ return num;
+}
+
+DBQuery.prototype.length = function(){
+ return this.toArray().length;
+}
+
+DBQuery.prototype._addSpecial = function( name , value ){
+ this._ensureSpecial();
+ this._query[name] = value;
+ return this;
+}
+
+DBQuery.prototype.sort = function( sortBy ){
+ return this._addSpecial( "orderby" , sortBy );
+}
+
+DBQuery.prototype.hint = function( hint ){
+ return this._addSpecial( "$hint" , hint );
+}
+
+DBQuery.prototype.min = function( min ) {
+ return this._addSpecial( "$min" , min );
+}
+
+DBQuery.prototype.max = function( max ) {
+ return this._addSpecial( "$max" , max );
+}
+
+DBQuery.prototype.showDiskLoc = function() {
+ return this._addSpecial( "$showDiskLoc" , true);
+}
+
+/**
+ * Sets the read preference for this cursor.
+ *
+ * @param mode {string} read prefrence mode to use.
+ * @param tagSet {Array.<Object>} optional. The list of tags to use, order matters.
+ *
+ * @return this cursor
+ */
+DBQuery.prototype.readPref = function( mode, tagSet ) {
+ var readPrefObj = {
+ mode: mode
+ };
+
+ if ( tagSet ){
+ readPrefObj.tags = tagSet;
+ }
+
+ return this._addSpecial( "$readPreference", readPrefObj );
+};
+
+DBQuery.prototype.forEach = function( func ){
+ while ( this.hasNext() )
+ func( this.next() );
+}
+
+DBQuery.prototype.map = function( func ){
+ var a = [];
+ while ( this.hasNext() )
+ a.push( func( this.next() ) );
+ return a;
+}
+
+DBQuery.prototype.arrayAccess = function( idx ){
+ return this.toArray()[idx];
+}
+DBQuery.prototype.comment = function (comment) {
+ var n = this.clone();
+ n._ensureSpecial();
+ n._addSpecial("$comment", comment);
+ return this.next();
+}
+
+DBQuery.prototype.explain = function (verbose) {
+ /* verbose=true --> include allPlans, oldPlan fields */
+ var n = this.clone();
+ n._ensureSpecial();
+ n._query.$explain = true;
+ n._limit = Math.abs(n._limit) * -1;
+ var e = n.next();
+
+ function cleanup(obj){
+ if (typeof(obj) != 'object'){
+ return;
+ }
+
+ delete obj.allPlans;
+ delete obj.oldPlan;
+
+ if (typeof(obj.length) == 'number'){
+ for (var i=0; i < obj.length; i++){
+ cleanup(obj[i]);
+ }
+ }
+
+ if (obj.shards){
+ for (var key in obj.shards){
+ cleanup(obj.shards[key]);
+ }
+ }
+
+ if (obj.clauses){
+ cleanup(obj.clauses);
+ }
+ }
+
+ if (!verbose)
+ cleanup(e);
+
+ return e;
+}
+
+DBQuery.prototype.snapshot = function(){
+ this._ensureSpecial();
+ this._query.$snapshot = true;
+ return this;
+}
+
+DBQuery.prototype.pretty = function(){
+ this._prettyShell = true;
+ return this;
+}
+
+DBQuery.prototype.shellPrint = function(){
+ try {
+ var start = new Date().getTime();
+ var n = 0;
+ while ( this.hasNext() && n < DBQuery.shellBatchSize ){
+ var s = this._prettyShell ? tojson( this.next() ) : tojson( this.next() , "" , true );
+ print( s );
+ n++;
+ }
+ if (typeof _verboseShell !== 'undefined' && _verboseShell) {
+ var time = new Date().getTime() - start;
+ print("Fetched " + n + " record(s) in " + time + "ms");
+ }
+ if ( this.hasNext() ){
+ print( "Type \"it\" for more" );
+ ___it___ = this;
+ }
+ else {
+ ___it___ = null;
+ }
+ }
+ catch ( e ){
+ print( e );
+ }
+
+}
+
+DBQuery.prototype.toString = function(){
+ return "DBQuery: " + this._ns + " -> " + tojson( this.query );
+}
+
+DBQuery.shellBatchSize = 20;
+
+/**
+ * Query option flag bit constants.
+ * @see http://dochub.mongodb.org/core/mongowireprotocol#MongoWireProtocol-OPQUERY
+ */
+DBQuery.Option = {
+ tailable: 0x2,
+ slaveOk: 0x4,
+ oplogReplay: 0x8,
+ noTimeout: 0x10,
+ awaitData: 0x20,
+ exhaust: 0x40,
+ partial: 0x80
+};
+
diff --git a/src/mongo/shell/replsetbridge.js b/src/mongo/shell/replsetbridge.js
new file mode 100644
index 00000000000..bd5691372c3
--- /dev/null
+++ b/src/mongo/shell/replsetbridge.js
@@ -0,0 +1,26 @@
+ReplSetBridge = function(rst, from, to) {
+ var n = rst.nodes.length;
+
+ var startPort = rst.startPort+n;
+ this.port = (startPort+(from*n+to));
+ this.host = rst.host+":"+this.port;
+
+ this.dest = rst.host+":"+rst.ports[to];
+ this.start();
+};
+
+ReplSetBridge.prototype.start = function() {
+ var args = ["mongobridge", "--port", this.port, "--dest", this.dest];
+ print("ReplSetBridge starting: "+tojson(args));
+ this.bridge = startMongoProgram.apply( null , args );
+ print("ReplSetBridge started " + this.bridge);
+};
+
+ReplSetBridge.prototype.stop = function() {
+ print("ReplSetBridge stopping: " + this.port);
+ stopMongod(this.port, 9);
+};
+
+ReplSetBridge.prototype.toString = function() {
+ return this.host+" -> "+this.dest;
+};
diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js
new file mode 100644
index 00000000000..c97bbc7ad04
--- /dev/null
+++ b/src/mongo/shell/replsettest.js
@@ -0,0 +1,1031 @@
+/**
+ * Sets up a replica set. To make the set running, call {@link #startSet},
+ * followed by {@link #initiate} (and optionally,
+ * {@link #awaitSecondaryNodes} to block till the set is fully operational).
+ * Note that some of the replica start up parameters are not passed here,
+ * but to the #startSet method.
+ *
+ * @param {Object} opts
+ *
+ * {
+ * name {string}: name of this replica set. Default: 'testReplSet'
+ * host {string}: name of the host machine. Hostname will be used
+ * if not specified.
+ * useHostName {boolean}: if true, use hostname of machine,
+ * otherwise use localhost
+ * nodes {number|Object|Array.<Object>}: number of replicas. Default: 0.
+ * Can also be an Object (or Array).
+ * Format for Object:
+ * {
+ * <any string>: replica member option Object. @see MongoRunner.runMongod
+ * <any string2>: and so on...
+ * }
+ *
+ * Format for Array:
+ * An array of replica member option Object. @see MongoRunner.runMongod
+ *
+ * Note: For both formats, a special boolean property 'arbiter' can be
+ * specified to denote a member is an arbiter.
+ *
+ * oplogSize {number}: Default: 40
+ * useSeedList {boolean}: Use the connection string format of this set
+ * as the replica set name (overrides the name property). Default: false
+ * bridged {boolean}: Whether to set a mongobridge between replicas.
+ * Default: false
+ * keyFile {string}
+ * shardSvr {boolean}: Default: false
+ * startPort {number}: port offset to be used for each replica. Default: 31000
+ * }
+ *
+ * Member variables:
+ * numNodes {number} - number of nodes
+ * nodes {Array.<Mongo>} - connection to replica set members
+ */
+ReplSetTest = function( opts ){
+ this.name = opts.name || "testReplSet";
+ this.useHostName = opts.useHostName == undefined ? true : opts.useHostName;
+ this.host = this.useHostName ? (opts.host || getHostName()) : 'localhost';
+ this.numNodes = opts.nodes || 0;
+ this.oplogSize = opts.oplogSize || 40;
+ this.useSeedList = opts.useSeedList || false;
+ this.bridged = opts.bridged || false;
+ this.ports = [];
+ this.keyFile = opts.keyFile
+ this.shardSvr = opts.shardSvr || false;
+
+ this.startPort = opts.startPort || 31000;
+
+ this.nodeOptions = {}
+ if( isObject( this.numNodes ) ){
+ var len = 0
+ for( var i in this.numNodes ){
+ var options = this.nodeOptions[ "n" + len ] = this.numNodes[i]
+ if( i.startsWith( "a" ) ) options.arbiter = true
+ len++
+ }
+ this.numNodes = len
+ }
+ else if( Array.isArray( this.numNodes ) ){
+ for( var i = 0; i < this.numNodes.length; i++ )
+ this.nodeOptions[ "n" + i ] = this.numNodes[i]
+ this.numNodes = this.numNodes.length
+ }
+
+ if(this.bridged) {
+ this.bridgePorts = [];
+
+ var allPorts = allocatePorts( this.numNodes * 2 , this.startPort );
+ for(var i=0; i < this.numNodes; i++) {
+ this.ports[i] = allPorts[i*2];
+ this.bridgePorts[i] = allPorts[i*2 + 1];
+ }
+
+ this.initBridges();
+ }
+ else {
+ this.ports = allocatePorts( this.numNodes , this.startPort );
+ }
+
+ this.nodes = []
+ this.initLiveNodes()
+
+ Object.extend( this, ReplSetTest.Health )
+ Object.extend( this, ReplSetTest.State )
+
+}
+
+ReplSetTest.prototype.initBridges = function() {
+ for(var i=0; i<this.ports.length; i++) {
+ startMongoProgram( "mongobridge", "--port", this.bridgePorts[i], "--dest", this.host + ":" + this.ports[i] );
+ }
+}
+
+// List of nodes as host:port strings.
+ReplSetTest.prototype.nodeList = function() {
+ var list = [];
+ for(var i=0; i<this.ports.length; i++) {
+ list.push( this.host + ":" + this.ports[i]);
+ }
+
+ return list;
+}
+
+// Here we store a reference to all reachable nodes.
+ReplSetTest.prototype.initLiveNodes = function() {
+ this.liveNodes = { master: null, slaves: [] }
+}
+
+ReplSetTest.prototype.getNodeId = function(node) {
+
+ if( node.toFixed ) return parseInt( node )
+
+ for( var i = 0; i < this.nodes.length; i++ ){
+ if( this.nodes[i] == node ) return i
+ }
+
+ if( node instanceof ObjectId ){
+ for( var i = 0; i < this.nodes.length; i++ ){
+ if( this.nodes[i].runId == node ) return i
+ }
+ }
+
+ if( node.nodeId ) return parseInt( node.nodeId )
+
+ return undefined
+
+}
+
+ReplSetTest.prototype.getPort = function( n ){
+
+ n = this.getNodeId( n )
+
+ print( "ReplSetTest n: " + n + " ports: " + tojson( this.ports ) + "\t" + this.ports[n] + " " + typeof(n) );
+ return this.ports[ n ];
+}
+
+ReplSetTest.prototype.getPath = function( n ){
+
+ if( n.host )
+ n = this.getNodeId( n )
+
+ var p = "/data/db/" + this.name + "-"+n;
+ if ( ! this._alldbpaths )
+ this._alldbpaths = [ p ];
+ else
+ this._alldbpaths.push( p );
+ return p;
+}
+
+ReplSetTest.prototype.getReplSetConfig = function() {
+ var cfg = {};
+
+ cfg['_id'] = this.name;
+ cfg.members = [];
+
+ for(i=0; i<this.ports.length; i++) {
+ member = {};
+ member['_id'] = i;
+
+ if(this.bridged)
+ var port = this.bridgePorts[i];
+ else
+ var port = this.ports[i];
+
+ member['host'] = this.host + ":" + port;
+ if( this.nodeOptions[ "n" + i ] && this.nodeOptions[ "n" + i ].arbiter )
+ member['arbiterOnly'] = true
+
+ cfg.members.push(member);
+ }
+
+ return cfg;
+}
+
+ReplSetTest.prototype.getURL = function(){
+ var hosts = [];
+
+ for(i=0; i<this.ports.length; i++) {
+
+ // Don't include this node in the replica set list
+ if(this.bridged && this.ports[i] == this.ports[n]) {
+ continue;
+ }
+
+ var port;
+ // Connect on the right port
+ if(this.bridged) {
+ port = this.bridgePorts[i];
+ }
+ else {
+ port = this.ports[i];
+ }
+
+ var str = this.host + ":" + port;
+ hosts.push(str);
+ }
+
+ return this.name + "/" + hosts.join(",");
+}
+
+ReplSetTest.prototype.getOptions = function( n , extra , putBinaryFirst ){
+
+ if ( ! extra )
+ extra = {};
+
+ if ( ! extra.oplogSize )
+ extra.oplogSize = this.oplogSize;
+
+ var a = []
+
+
+ if ( putBinaryFirst )
+ a.push( "mongod" );
+
+ if ( extra.noReplSet ) {
+ delete extra.noReplSet;
+ }
+ else {
+ a.push( "--replSet" );
+
+ if( this.useSeedList ) {
+ a.push( this.getURL() );
+ }
+ else {
+ a.push( this.name );
+ }
+ }
+
+ a.push( "--noprealloc", "--smallfiles" );
+
+ a.push( "--rest" );
+
+ a.push( "--port" );
+ a.push( this.getPort( n ) );
+
+ a.push( "--dbpath" );
+ a.push( this.getPath( ( n.host ? this.getNodeId( n ) : n ) ) );
+
+ if( this.keyFile ){
+ a.push( "--keyFile" )
+ a.push( keyFile )
+ }
+
+ if( jsTestOptions().noJournal ) a.push( "--nojournal" )
+ if( jsTestOptions().noJournalPrealloc ) a.push( "--nopreallocj" )
+ if( jsTestOptions().keyFile && !this.keyFile) {
+ a.push( "--keyFile" )
+ a.push( jsTestOptions().keyFile )
+ }
+
+ for ( var k in extra ){
+ var v = extra[k];
+ if( k in MongoRunner.logicalOptions ) continue
+ a.push( "--" + k );
+ if ( v != null ){
+ if( v.replace ){
+ v = v.replace(/\$node/g, "" + ( n.host ? this.getNodeId( n ) : n ) )
+ v = v.replace(/\$set/g, this.name )
+ v = v.replace(/\$path/g, this.getPath( n ) )
+ }
+ a.push( v );
+ }
+ }
+
+ return a;
+}
+
+ReplSetTest.prototype.startSet = function( options ) {
+
+ var nodes = [];
+ print( "ReplSetTest Starting Set" );
+
+ for( n = 0 ; n < this.ports.length; n++ ) {
+ node = this.start(n, options)
+ nodes.push(node);
+ }
+
+ this.nodes = nodes;
+ return this.nodes;
+}
+
+ReplSetTest.prototype.callIsMaster = function() {
+
+ var master = null;
+ this.initLiveNodes();
+
+ for(var i=0; i<this.nodes.length; i++) {
+
+ try {
+ var n = this.nodes[i].getDB('admin').runCommand({ismaster:1});
+
+ if(n['ismaster'] == true) {
+ master = this.nodes[i]
+ this.liveNodes.master = master
+ }
+ else {
+ this.nodes[i].setSlaveOk();
+ this.liveNodes.slaves.push(this.nodes[i]);
+ }
+
+ }
+ catch(err) {
+ print("ReplSetTest Could not call ismaster on node " + i);
+ }
+ }
+
+ return master || false;
+}
+
+ReplSetTest.awaitRSClientHosts = function( conn, host, hostOk, rs ) {
+ var hostCount = host.length;
+ if( hostCount ){
+ for( var i = 0; i < hostCount; i++ ) {
+ ReplSetTest.awaitRSClientHosts( conn, host[i], hostOk, rs );
+ }
+ return;
+ }
+
+ if( hostOk == undefined ) hostOk = { ok : true }
+ if( host.host ) host = host.host
+ if( rs && rs.getMaster ) rs = rs.name
+
+ print( "Awaiting " + host + " to be " + tojson( hostOk ) + " for " + conn + " (rs: " + rs + ")" )
+
+ var tests = 0
+ assert.soon( function() {
+ var rsClientHosts = conn.getDB( "admin" ).runCommand( "connPoolStats" )[ "replicaSets" ]
+ if( tests++ % 10 == 0 )
+ printjson( rsClientHosts )
+
+ for ( rsName in rsClientHosts ){
+ if( rs && rs != rsName ) continue
+ for ( var i = 0; i < rsClientHosts[rsName].hosts.length; i++ ){
+ var clientHost = rsClientHosts[rsName].hosts[ i ];
+ if( clientHost.addr != host ) continue
+
+ // Check that *all* host properties are set correctly
+ var propOk = true
+ for( var prop in hostOk ){
+ if ( isObject( hostOk[prop] )) {
+ if ( !friendlyEqual( hostOk[prop], clientHost[prop] )){
+ propOk = false;
+ break;
+ }
+ }
+ else if ( clientHost[prop] != hostOk[prop] ){
+ propOk = false;
+ break;
+ }
+ }
+
+ if( propOk ) return true;
+
+ }
+ }
+ return false;
+ }, "timed out waiting for replica set client to recognize hosts",
+ 3 * 20 * 1000 /* ReplicaSetMonitorWatcher updates every 20s */ )
+
+}
+
+ReplSetTest.prototype.awaitSecondaryNodes = function( timeout ) {
+ var master = this.getMaster();
+ var slaves = this.liveNodes.slaves;
+ var len = slaves.length;
+
+ jsTest.attempt({context: this, timeout: 60000, desc: "Awaiting secondaries"}, function() {
+ var ready = true;
+ for(var i=0; i<len; i++) {
+ var isMaster = slaves[i].getDB("admin").runCommand({ismaster: 1});
+ var arbiter = isMaster['arbiterOnly'] == undefined ? false : isMaster['arbiterOnly'];
+ ready = ready && ( isMaster['secondary'] || arbiter );
+ }
+ return ready;
+ });
+}
+
+ReplSetTest.prototype.getMaster = function( timeout ) {
+ var tries = 0;
+ var sleepTime = 500;
+ var t = timeout || 000;
+ var master = null;
+
+ master = jsTest.attempt({context: this, timeout: 60000, desc: "Finding master"}, this.callIsMaster);
+ return master;
+}
+
+ReplSetTest.prototype.getPrimary = ReplSetTest.prototype.getMaster
+
+ReplSetTest.prototype.getSecondaries = function( timeout ){
+ var master = this.getMaster( timeout )
+ var secs = []
+ for( var i = 0; i < this.nodes.length; i++ ){
+ if( this.nodes[i] != master ){
+ secs.push( this.nodes[i] )
+ }
+ }
+ return secs
+}
+
+ReplSetTest.prototype.getSecondary = function( timeout ){
+ return this.getSecondaries( timeout )[0];
+}
+
+ReplSetTest.prototype.status = function( timeout ){
+ var master = this.callIsMaster()
+ if( ! master ) master = this.liveNodes.slaves[0]
+ return master.getDB("admin").runCommand({replSetGetStatus: 1})
+}
+
+// Add a node to the test set
+ReplSetTest.prototype.add = function( config ) {
+ if(this.ports.length == 0) {
+ var nextPort = allocatePorts( 1, this.startPort )[0];
+ }
+ else {
+ var nextPort = this.ports[this.ports.length-1] + 1;
+ }
+ print("ReplSetTest Next port: " + nextPort);
+ this.ports.push(nextPort);
+ printjson(this.ports);
+
+ var nextId = this.nodes.length;
+ printjson(this.nodes);
+ print("ReplSetTest nextId:" + nextId);
+ var newNode = this.start( nextId );
+
+ return newNode;
+}
+
+ReplSetTest.prototype.remove = function( nodeId ) {
+ nodeId = this.getNodeId( nodeId )
+ this.nodes.splice( nodeId, 1 );
+ this.ports.splice( nodeId, 1 );
+}
+
+ReplSetTest.prototype.initiate = function( cfg , initCmd , timeout ) {
+ var master = this.nodes[0].getDB("admin");
+ var config = cfg || this.getReplSetConfig();
+ var cmd = {};
+ var cmdKey = initCmd || 'replSetInitiate';
+ var timeout = timeout || 30000;
+ cmd[cmdKey] = config;
+ printjson(cmd);
+
+ jsTest.attempt({context:this, timeout: timeout, desc: "Initiate replica set"}, function() {
+ var result = master.runCommand(cmd);
+ printjson(result);
+ return result['ok'] == 1;
+ });
+
+ // Setup authentication if running test with authentication
+ if (jsTestOptions().keyFile && !this.keyFile) {
+ if (!this.shardSvr) {
+ master = this.getMaster();
+ jsTest.addAuth(master);
+ jsTest.authenticateNodes(this.nodes);
+ }
+ }
+}
+
+ReplSetTest.prototype.reInitiate = function() {
+ var master = this.nodes[0];
+ var c = master.getDB("local")['system.replset'].findOne();
+ var config = this.getReplSetConfig();
+ config.version = c.version + 1;
+ this.initiate( config , 'replSetReconfig' );
+}
+
+ReplSetTest.prototype.getLastOpTimeWritten = function() {
+ this.getMaster();
+ jsTest.attempt({context : this, desc : "awaiting oplog query", timeout: 30000},
+ function() {
+ try {
+ this.latest = this.liveNodes.master.getDB("local")['oplog.rs'].find({}).sort({'$natural': -1}).limit(1).next()['ts'];
+ }
+ catch(e) {
+ print("ReplSetTest caught exception " + e);
+ return false;
+ }
+ return true;
+ });
+};
+
+ReplSetTest.prototype.awaitReplication = function(timeout) {
+ timeout = timeout || 30000;
+
+ this.getLastOpTimeWritten();
+
+ print("ReplSetTest " + this.latest);
+
+ jsTest.attempt({context: this, timeout: timeout, desc: "awaiting replication"},
+ function() {
+ try {
+ var synced = true;
+ for(var i=0; i<this.liveNodes.slaves.length; i++) {
+ var slave = this.liveNodes.slaves[i];
+
+ // Continue if we're connected to an arbiter
+ if(res = slave.getDB("admin").runCommand({replSetGetStatus: 1})) {
+ if(res.myState == 7) {
+ continue;
+ }
+ }
+
+ slave.getDB("admin").getMongo().setSlaveOk();
+ var log = slave.getDB("local")['oplog.rs'];
+ if(log.find({}).sort({'$natural': -1}).limit(1).hasNext()) {
+ var entry = log.find({}).sort({'$natural': -1}).limit(1).next();
+ printjson( entry );
+ var ts = entry['ts'];
+ print("ReplSetTest await TS for " + slave + " is " + ts.t+":"+ts.i + " and latest is " + this.latest.t+":"+this.latest.i);
+
+ if (this.latest.t < ts.t || (this.latest.t == ts.t && this.latest.i < ts.i)) {
+ this.latest = this.liveNodes.master.getDB("local")['oplog.rs'].find({}).sort({'$natural': -1}).limit(1).next()['ts'];
+ }
+
+ print("ReplSetTest await oplog size for " + slave + " is " + log.count());
+ synced = (synced && friendlyEqual(this.latest,ts))
+ }
+ else {
+ print( "ReplSetTest waiting for " + slave + " to have an oplog built." )
+ synced = false;
+ }
+ }
+
+ if(synced) {
+ print("ReplSetTest await synced=" + synced);
+ }
+ return synced;
+ }
+ catch (e) {
+ print("ReplSetTest.awaitReplication: caught exception "+e);
+
+ // we might have a new master now
+ this.getLastOpTimeWritten();
+
+ return false;
+ }
+ });
+}
+
+ReplSetTest.prototype.getHashes = function( db ){
+ this.getMaster();
+ var res = {};
+ res.master = this.liveNodes.master.getDB( db ).runCommand( "dbhash" )
+ res.slaves = this.liveNodes.slaves.map( function(z){ return z.getDB( db ).runCommand( "dbhash" ); } )
+ return res;
+}
+
+/**
+ * Starts up a server. Options are saved by default for subsequent starts.
+ *
+ *
+ * Options { remember : true } re-applies the saved options from a prior start.
+ * Options { noRemember : true } ignores the current properties.
+ * Options { appendOptions : true } appends the current options to those remembered.
+ * Options { startClean : true } clears the data directory before starting.
+ *
+ * @param {int|conn|[int|conn]} n array or single server number (0, 1, 2, ...) or conn
+ * @param {object} [options]
+ * @param {boolean} [restart] If false, the data directory will be cleared
+ * before the server starts. Default: false.
+ *
+ */
+ReplSetTest.prototype.start = function( n , options , restart , wait ){
+
+ if( n.length ){
+
+ var nodes = n
+ var started = []
+
+ for( var i = 0; i < nodes.length; i++ ){
+ if( this.start( nodes[i], Object.merge({}, options), restart, wait ) ){
+ started.push( nodes[i] )
+ }
+ }
+
+ return started
+
+ }
+
+ print( "ReplSetTest n is : " + n )
+
+ defaults = { useHostName : this.useHostName,
+ oplogSize : this.oplogSize,
+ keyFile : this.keyFile,
+ port : this.getPort( n ),
+ noprealloc : "",
+ smallfiles : "",
+ rest : "",
+ replSet : this.useSeedList ? this.getURL() : this.name,
+ dbpath : "$set-$node" }
+
+ defaults = Object.merge( defaults, ReplSetTest.nodeOptions || {} )
+
+ // TODO : should we do something special if we don't currently know about this node?
+ n = this.getNodeId( n )
+
+ //
+ // Note : this replaces the binVersion of the shared startSet() options the first time
+ // through, so the full set is guaranteed to have different versions if size > 1. If using
+ // start() independently, independent version choices will be made
+ //
+ if( options && options.binVersion ){
+ options.binVersion =
+ MongoRunner.versionIterator( options.binVersion )
+ }
+
+ options = Object.merge( defaults, options )
+ options = Object.merge( options, this.nodeOptions[ "n" + n ] )
+
+ options.restart = restart
+
+ var pathOpts = { node : n, set : this.name }
+ options.pathOpts = Object.merge( options.pathOpts || {}, pathOpts )
+
+ if( tojson(options) != tojson({}) )
+ printjson(options)
+
+ // make sure to call getPath, otherwise folders wont be cleaned
+ this.getPath(n);
+
+ print("ReplSetTest " + (restart ? "(Re)" : "") + "Starting....");
+
+ var rval = this.nodes[n] = MongoRunner.runMongod( options )
+
+ if( ! rval ) return rval
+
+ // Add replica set specific attributes
+ this.nodes[n].nodeId = n
+
+ printjson( this.nodes )
+
+ wait = wait || false
+ if( ! wait.toFixed ){
+ if( wait ) wait = 0
+ else wait = -1
+ }
+
+ if( wait < 0 ) return rval
+
+ // Wait for startup
+ this.waitForHealth( rval, this.UP, wait )
+
+ return rval
+
+}
+
+
+/**
+ * Restarts a db without clearing the data directory by default. If the server is not
+ * stopped first, this function will not work.
+ *
+ * Option { startClean : true } forces clearing the data directory.
+ * Option { auth : Object } object that contains the auth details for admin credentials.
+ * Should contain the fields 'user' and 'pwd'
+ *
+ * @param {int|conn|[int|conn]} n array or single server number (0, 1, 2, ...) or conn
+ */
+ReplSetTest.prototype.restart = function( n , options, signal, wait ){
+ // Can specify wait as third parameter, if using default signal
+ if( signal == true || signal == false ){
+ wait = signal
+ signal = undefined
+ }
+
+ this.stop( n, signal, wait && wait.toFixed ? wait : true, options )
+ started = this.start( n , options , true, wait );
+
+ if (jsTestOptions().keyFile && !this.keyFile) {
+ if (started.length) {
+ // if n was an array of conns, start will return an array of connections
+ for (var i = 0; i < started.length; i++) {
+ jsTest.authenticate(started[i]);
+ }
+ } else {
+ jsTest.authenticate(started);
+ }
+ }
+ return started;
+}
+
+ReplSetTest.prototype.stopMaster = function( signal , wait, opts ) {
+ var master = this.getMaster();
+ var master_id = this.getNodeId( master );
+ return this.stop( master_id , signal , wait, opts );
+}
+
+/**
+ * Stops a particular node or nodes, specified by conn or id
+ *
+ * @param {number} n the index of the replica set member to stop
+ * @param {number} signal the signal number to use for killing
+ * @param {boolean} wait
+ * @param {Object} opts @see MongoRunner.stopMongod
+ */
+ReplSetTest.prototype.stop = function( n , signal, wait /* wait for stop */, opts ){
+
+ // Flatten array of nodes to stop
+ if( n.length ){
+ nodes = n
+
+ var stopped = []
+ for( var i = 0; i < nodes.length; i++ ){
+ if( this.stop( nodes[i], signal, wait, opts ) )
+ stopped.push( nodes[i] )
+ }
+
+ return stopped
+ }
+
+ // Can specify wait as second parameter, if using default signal
+ if( signal == true || signal == false ){
+ wait = signal
+ signal = undefined
+ }
+
+ wait = wait || false
+ if( ! wait.toFixed ){
+ if( wait ) wait = 0
+ else wait = -1
+ }
+
+ var port = this.getPort( n );
+ print('ReplSetTest stop *** Shutting down mongod in port ' + port + ' ***');
+ var ret = MongoRunner.stopMongod( port , signal, opts );
+
+ if( ! ret || wait < 0 ) return ret
+
+ // Wait for shutdown
+ this.waitForHealth( n, this.DOWN, wait )
+
+ return true
+}
+
+/**
+ * Kill all members of this replica set.
+ *
+ * @param {number} signal The signal number to use for killing the members
+ * @param {boolean} forRestart will not cleanup data directory or teardown
+ * bridges if set to true.
+ * @param {Object} opts @see MongoRunner.stopMongod
+ */
+ReplSetTest.prototype.stopSet = function( signal , forRestart, opts ) {
+ for(var i=0; i < this.ports.length; i++) {
+ this.stop( i, signal, false, opts );
+ }
+ if ( forRestart ) { return; }
+ if ( this._alldbpaths ){
+ print("ReplSetTest stopSet deleting all dbpaths");
+ for( i=0; i<this._alldbpaths.length; i++ ){
+ resetDbpath( this._alldbpaths[i] );
+ }
+ }
+ if ( this.bridges ) {
+ var mybridgevec;
+ while (mybridgevec = this.bridges.pop()) {
+ var mybridge;
+ while (mybridge = mybridgevec.pop()) {
+ mybridge.stop();
+ }
+ }
+ }
+
+ print('ReplSetTest stopSet *** Shut down repl set - test worked ****' )
+};
+
+
+/**
+ * Waits until there is a master node
+ */
+ReplSetTest.prototype.waitForMaster = function( timeout ){
+
+ var master = undefined
+
+ jsTest.attempt({context: this, timeout: timeout, desc: "waiting for master"}, function() {
+ return ( master = this.getMaster() )
+ });
+
+ return master
+}
+
+
+/**
+ * Wait for a health indicator to go to a particular state or states.
+ *
+ * @param node is a single node or list of nodes, by id or conn
+ * @param state is a single state or list of states
+ *
+ */
+ReplSetTest.prototype.waitForHealth = function( node, state, timeout ){
+ this.waitForIndicator( node, state, "health", timeout )
+}
+
+/**
+ * Wait for a state indicator to go to a particular state or states.
+ *
+ * @param node is a single node or list of nodes, by id or conn
+ * @param state is a single state or list of states
+ *
+ */
+ReplSetTest.prototype.waitForState = function( node, state, timeout ){
+ this.waitForIndicator( node, state, "state", timeout )
+}
+
+/**
+ * Wait for a rs indicator to go to a particular state or states.
+ *
+ * @param node is a single node or list of nodes, by id or conn
+ * @param states is a single state or list of states
+ * @param ind is the indicator specified
+ *
+ */
+ReplSetTest.prototype.waitForIndicator = function( node, states, ind, timeout ){
+
+ if( node.length ){
+
+ var nodes = node
+ for( var i = 0; i < nodes.length; i++ ){
+ if( states.length )
+ this.waitForIndicator( nodes[i], states[i], ind, timeout )
+ else
+ this.waitForIndicator( nodes[i], states, ind, timeout )
+ }
+
+ return;
+ }
+
+ timeout = timeout || 30000;
+
+ if( ! node.getDB ){
+ node = this.nodes[node]
+ }
+
+ if( ! states.length ) states = [ states ]
+
+ print( "ReplSetTest waitForIndicator " + ind + " on " + node )
+ printjson( states )
+ print( "ReplSetTest waitForIndicator from node " + node )
+
+ var lastTime = null
+ var currTime = new Date().getTime()
+ var status = undefined
+
+ jsTest.attempt({context: this, timeout: timeout, desc: "waiting for state indicator " + ind + " for " + timeout + "ms" }, function() {
+
+ status = this.status()
+
+ var printStatus = false
+ if( lastTime == null || ( currTime = new Date().getTime() ) - (1000 * 5) > lastTime ){
+ if( lastTime == null ) print( "ReplSetTest waitForIndicator Initial status ( timeout : " + timeout + " ) :" )
+ printjson( status )
+ lastTime = new Date().getTime()
+ printStatus = true
+ }
+
+ if (typeof status.members == 'undefined') {
+ return false;
+ }
+
+ for( var i = 0; i < status.members.length; i++ ){
+ if( printStatus ) print( "Status for : " + status.members[i].name + ", checking " + node.host + "/" + node.name )
+ if( status.members[i].name == node.host || status.members[i].name == node.name ){
+ for( var j = 0; j < states.length; j++ ){
+ if( printStatus ) print( "Status " + " : " + status.members[i][ind] + " target state : " + states[j] )
+ if( status.members[i][ind] == states[j] ) return true;
+ }
+ }
+ }
+
+ return false
+
+ });
+
+ print( "ReplSetTest waitForIndicator final status:" )
+ printjson( status )
+
+}
+
+ReplSetTest.Health = {}
+ReplSetTest.Health.UP = 1
+ReplSetTest.Health.DOWN = 0
+
+ReplSetTest.State = {}
+ReplSetTest.State.PRIMARY = 1
+ReplSetTest.State.SECONDARY = 2
+ReplSetTest.State.RECOVERING = 3
+ReplSetTest.State.ARBITER = 7
+
+/**
+ * Overflows a replica set secondary or secondaries, specified by id or conn.
+ */
+ReplSetTest.prototype.overflow = function( secondaries ){
+
+ // Create a new collection to overflow, allow secondaries to replicate
+ var master = this.getMaster()
+ var overflowColl = master.getCollection( "_overflow.coll" )
+ overflowColl.insert({ replicated : "value" })
+ this.awaitReplication()
+
+ this.stop( secondaries, undefined, 5 * 60 * 1000 )
+
+ var count = master.getDB("local").oplog.rs.count();
+ var prevCount = -1;
+
+ // Keep inserting till we hit our capped coll limits
+ while (count != prevCount) {
+
+ print("ReplSetTest overflow inserting 10000");
+
+ for (var i = 0; i < 10000; i++) {
+ overflowColl.insert({ overflow : "value" });
+ }
+ prevCount = count;
+ this.awaitReplication();
+
+ count = master.getDB("local").oplog.rs.count();
+
+ print( "ReplSetTest overflow count : " + count + " prev : " + prevCount );
+
+ }
+
+ // Restart all our secondaries and wait for recovery state
+ this.start( secondaries, { remember : true }, true, true )
+ this.waitForState( secondaries, this.RECOVERING, 5 * 60 * 1000 )
+
+}
+
+
+
+
+/**
+ * Bridging allows you to test network partitioning. For example, you can set
+ * up a replica set, run bridge(), then kill the connection between any two
+ * nodes x and y with partition(x, y).
+ *
+ * Once you have called bridging, you cannot reconfigure the replica set.
+ */
+ReplSetTest.prototype.bridge = function( opts ) {
+ if (this.bridges) {
+ print("ReplSetTest bridge bridges have already been created!");
+ return;
+ }
+
+ var n = this.nodes.length;
+
+ // create bridges
+ this.bridges = [];
+ for (var i=0; i<n; i++) {
+ var nodeBridges = [];
+ for (var j=0; j<n; j++) {
+ if (i == j) {
+ continue;
+ }
+ nodeBridges[j] = new ReplSetBridge(this, i, j);
+ }
+ this.bridges.push(nodeBridges);
+ }
+ print("ReplSetTest bridge bridges: " + this.bridges);
+
+ // restart everyone independently
+ this.stopSet(null, true, opts );
+ for (var i=0; i<n; i++) {
+ this.restart(i, {noReplSet : true});
+ }
+
+ // create new configs
+ for (var i=0; i<n; i++) {
+ config = this.nodes[i].getDB("local").system.replset.findOne();
+
+ if (!config) {
+ print("ReplSetTest bridge couldn't find config for "+this.nodes[i]);
+ printjson(this.nodes[i].getDB("local").system.namespaces.find().toArray());
+ assert(false);
+ }
+
+ var updateMod = {"$set" : {}};
+ for (var j = 0; j<config.members.length; j++) {
+ if (config.members[j].host == this.host+":"+this.ports[i]) {
+ continue;
+ }
+
+ updateMod['$set']["members."+j+".host"] = this.bridges[i][j].host;
+ }
+ print("ReplSetTest bridge for node " + i + ":");
+ printjson(updateMod);
+ this.nodes[i].getDB("local").system.replset.update({},updateMod);
+ }
+
+ this.stopSet( null, true, opts );
+
+ // start set
+ for (var i=0; i<n; i++) {
+ this.restart(i);
+ }
+
+ return this.getMaster();
+};
+
+/**
+ * This kills the bridge between two nodes. As parameters, specify the from and
+ * to node numbers.
+ *
+ * For example, with a three-member replica set, we'd have nodes 0, 1, and 2,
+ * with the following bridges: 0->1, 0->2, 1->0, 1->2, 2->0, 2->1. We can kill
+ * the connection between nodes 0 and 2 by calling replTest.partition(0,2) or
+ * replTest.partition(2,0) (either way is identical). Then the replica set would
+ * have the following bridges: 0->1, 1->0, 1->2, 2->1.
+ */
+ReplSetTest.prototype.partition = function(from, to) {
+ this.bridges[from][to].stop();
+ this.bridges[to][from].stop();
+};
+
+/**
+ * This reverses a partition created by partition() above.
+ */
+ReplSetTest.prototype.unPartition = function(from, to) {
+ this.bridges[from][to].start();
+ this.bridges[to][from].start();
+};
diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js
new file mode 100755
index 00000000000..9bdc04dd0f4
--- /dev/null
+++ b/src/mongo/shell/servers.js
@@ -0,0 +1,703 @@
+_parsePath = function() {
+ var dbpath = "";
+ for( var i = 0; i < arguments.length; ++i )
+ if ( arguments[ i ] == "--dbpath" )
+ dbpath = arguments[ i + 1 ];
+
+ if ( dbpath == "" )
+ throw "No dbpath specified";
+
+ return dbpath;
+}
+
+_parsePort = function() {
+ var port = "";
+ for( var i = 0; i < arguments.length; ++i )
+ if ( arguments[ i ] == "--port" )
+ port = arguments[ i + 1 ];
+
+ if ( port == "" )
+ throw "No port specified";
+ return port;
+}
+
+connectionURLTheSame = function( a , b ){
+
+ if ( a == b )
+ return true;
+
+ if ( ! a || ! b )
+ return false;
+
+ if( a.host ) return connectionURLTheSame( a.host, b )
+ if( b.host ) return connectionURLTheSame( a, b.host )
+
+ if( a.name ) return connectionURLTheSame( a.name, b )
+ if( b.name ) return connectionURLTheSame( a, b.name )
+
+ if( a.indexOf( "/" ) < 0 && b.indexOf( "/" ) < 0 ){
+ a = a.split( ":" )
+ b = b.split( ":" )
+
+ if( a.length != b.length ) return false
+
+ if( a.length == 2 && a[1] != b[1] ) return false
+
+ if( a[0] == "localhost" || a[0] == "127.0.0.1" ) a[0] = getHostName()
+ if( b[0] == "localhost" || b[0] == "127.0.0.1" ) b[0] = getHostName()
+
+ return a[0] == b[0]
+ }
+ else {
+ var a0 = a.split( "/" )[0]
+ var b0 = b.split( "/" )[0]
+ return a0 == b0
+ }
+}
+
+assert( connectionURLTheSame( "foo" , "foo" ) )
+assert( ! connectionURLTheSame( "foo" , "bar" ) )
+
+assert( connectionURLTheSame( "foo/a,b" , "foo/b,a" ) )
+assert( ! connectionURLTheSame( "foo/a,b" , "bar/a,b" ) )
+
+createMongoArgs = function( binaryName , args ){
+ var fullArgs = [ binaryName ];
+
+ if ( args.length == 1 && isObject( args[0] ) ){
+ var o = args[0];
+ for ( var k in o ){
+ if ( o.hasOwnProperty(k) ){
+ if ( k == "v" && isNumber( o[k] ) ){
+ var n = o[k];
+ if ( n > 0 ){
+ if ( n > 10 ) n = 10;
+ var temp = "-";
+ while ( n-- > 0 ) temp += "v";
+ fullArgs.push( temp );
+ }
+ }
+ else {
+ fullArgs.push( "--" + k );
+ if ( o[k] != "" )
+ fullArgs.push( "" + o[k] );
+ }
+ }
+ }
+ }
+ else {
+ for ( var i=0; i<args.length; i++ )
+ fullArgs.push( args[i] )
+ }
+
+ return fullArgs;
+}
+
+
+MongoRunner = function(){}
+
+MongoRunner.dataDir = "/data/db"
+MongoRunner.dataPath = "/data/db/"
+MongoRunner.usedPortMap = {}
+MongoRunner.logicalOptions = { runId : true,
+ pathOpts : true,
+ remember : true,
+ noRemember : true,
+ appendOptions : true,
+ restart : true,
+ noCleanData : true,
+ cleanData : true,
+ startClean : true,
+ forceLock : true,
+ useLogFiles : true,
+ useHostName : true,
+ useHostname : true,
+ noReplSet : true,
+ forgetPort : true,
+ arbiter : true,
+ noJournalPrealloc : true,
+ noJournal : true,
+ binVersion : true }
+
+MongoRunner.toRealPath = function( path, pathOpts ){
+
+ // Replace all $pathOptions with actual values
+ pathOpts = pathOpts || {}
+ path = path.replace( /\$dataPath/g, MongoRunner.dataPath )
+ path = path.replace( /\$dataDir/g, MongoRunner.dataDir )
+ for( key in pathOpts ){
+ path = path.replace( RegExp( "\\$" + RegExp.escape(key), "g" ), pathOpts[ key ] )
+ }
+
+ // Relative path
+ if( ! path.startsWith( "/" ) ){
+ if( path != "" && ! path.endsWith( "/" ) )
+ path += "/"
+
+ path = MongoRunner.dataPath + path
+ }
+
+ return path
+
+}
+
+MongoRunner.toRealDir = function( path, pathOpts ){
+
+ path = MongoRunner.toRealPath( path, pathOpts )
+
+ if( path.endsWith( "/" ) )
+ path = path.substring( 0, path.length - 1 )
+
+ return path
+}
+
+MongoRunner.toRealFile = MongoRunner.toRealDir
+
+MongoRunner.nextOpenPort = function(){
+
+ var i = 0;
+ while( MongoRunner.usedPortMap[ "" + ( 27000 + i ) ] ) i++;
+ MongoRunner.usedPortMap[ "" + ( 27000 + i ) ] = true
+
+ return 27000 + i
+
+}
+
+/**
+ * Returns an iterator object which yields successive versions on toString(), starting from a
+ * random initial position, from an array of versions.
+ *
+ * If passed a single version string or an already-existing version iterator, just returns the
+ * object itself, since it will yield correctly on toString()
+ *
+ * @param {Array.<String>}|{String}|{versionIterator}
+ */
+MongoRunner.versionIterator = function( arr ){
+
+ // If this isn't an array of versions, or is already an iterator, just use it
+ if( typeof arr == "string" ) return arr
+ if( arr.isVersionIterator ) return arr
+
+ // Starting pos
+ var i = parseInt( Random.rand() * arr.length )
+
+ var it = {
+ toString : function(){
+ i = ( i + 1 ) % arr.length
+ print( "Returning next version : " + i + " from " + tojson( arr ) + "..." )
+ return arr[ i ]
+ },
+ isVersionIterator : true
+ }
+
+ return it
+}
+
+/**
+ * Converts the args object by pairing all keys with their value and appending
+ * dash-dash (--) to the keys. The only exception to this rule are keys that
+ * are defined in MongoRunner.logicalOptions, of which they will be ignored.
+ *
+ * @param {string} binaryName
+ * @param {Object} args
+ *
+ * @return {Array.<String>} an array of parameter strings that can be passed
+ * to the binary.
+ */
+MongoRunner.arrOptions = function( binaryName , args ){
+
+ var fullArgs = [ "" ]
+
+ if ( isObject( args ) || ( args.length == 1 && isObject( args[0] ) ) ){
+
+ var o = isObject( args ) ? args : args[0]
+
+ // If we've specified a particular binary version, use that
+ if( o.binVersion && o.binVersion != "latest" && o.binVersion != "" )
+ binaryName += "-" + o.binVersion
+
+ // Manage legacy options
+ var isValidOptionForBinary = function( option, value ){
+
+ if( ! o.binVersion ) return true
+
+ // Version 1.x options
+ if( o.binVersion.startsWith( "1." ) ){
+
+ return [ "nopreallocj" ].indexOf( option ) < 0
+ }
+
+ return true
+ }
+
+ for ( var k in o ){
+
+ // Make sure our logical option should be added to the array of options
+ if( ! o.hasOwnProperty( k ) ||
+ k in MongoRunner.logicalOptions ||
+ ! isValidOptionForBinary( k, o[k] ) ) continue
+
+ if ( ( k == "v" || k == "verbose" ) && isNumber( o[k] ) ){
+ var n = o[k]
+ if ( n > 0 ){
+ if ( n > 10 ) n = 10
+ var temp = "-"
+ while ( n-- > 0 ) temp += "v"
+ fullArgs.push( temp )
+ }
+ }
+ else {
+ if( o[k] == undefined || o[k] == null ) continue
+ fullArgs.push( "--" + k )
+ if ( o[k] != "" )
+ fullArgs.push( "" + o[k] )
+ }
+ }
+ }
+ else {
+ for ( var i=0; i<args.length; i++ )
+ fullArgs.push( args[i] )
+ }
+
+ fullArgs[ 0 ] = binaryName
+ return fullArgs
+}
+
+MongoRunner.arrToOpts = function( arr ){
+
+ var opts = {}
+ for( var i = 1; i < arr.length; i++ ){
+ if( arr[i].startsWith( "-" ) ){
+ var opt = arr[i].replace( /^-/, "" ).replace( /^-/, "" )
+
+ if( arr.length > i + 1 && ! arr[ i + 1 ].startsWith( "-" ) ){
+ opts[ opt ] = arr[ i + 1 ]
+ i++
+ }
+ else{
+ opts[ opt ] = ""
+ }
+
+ if( opt.replace( /v/g, "" ) == "" ){
+ opts[ "verbose" ] = opt.length
+ }
+ }
+ }
+
+ return opts
+}
+
+MongoRunner.savedOptions = {}
+
+MongoRunner.mongoOptions = function( opts ){
+
+ // If we're a mongo object
+ if( opts.getDB ){
+ opts = { restart : opts.runId }
+ }
+
+ // Initialize and create a copy of the opts
+ opts = Object.merge( opts || {}, {} )
+
+ if( ! opts.restart ) opts.restart = false
+
+ // RunId can come from a number of places
+ // If restart is passed as an old connection
+ if( opts.restart && opts.restart.getDB ){
+ opts.runId = opts.restart.runId
+ opts.restart = true
+ }
+ // If it's the runId itself
+ else if( isObject( opts.restart ) ){
+ opts.runId = opts.restart
+ opts.restart = true
+ }
+
+ if( isObject( opts.remember ) ){
+ opts.runId = opts.remember
+ opts.remember = true
+ }
+ else if( opts.remember == undefined ){
+ // Remember by default if we're restarting
+ opts.remember = opts.restart
+ }
+
+ // If we passed in restart : <conn> or runId : <conn>
+ if( isObject( opts.runId ) && opts.runId.runId ) opts.runId = opts.runId.runId
+
+ if( opts.restart && opts.remember ) opts = Object.merge( MongoRunner.savedOptions[ opts.runId ], opts )
+
+ // Create a new runId
+ opts.runId = opts.runId || ObjectId()
+
+ // Save the port if required
+ if( ! opts.forgetPort ) opts.port = opts.port || MongoRunner.nextOpenPort()
+
+ var shouldRemember = ( ! opts.restart && ! opts.noRemember ) || ( opts.restart && opts.appendOptions )
+
+ if ( shouldRemember ){
+ MongoRunner.savedOptions[ opts.runId ] = Object.merge( opts, {} )
+ }
+
+ opts.port = opts.port || MongoRunner.nextOpenPort()
+ MongoRunner.usedPortMap[ "" + parseInt( opts.port ) ] = true
+
+ opts.pathOpts = Object.merge( opts.pathOpts || {}, { port : "" + opts.port, runId : "" + opts.runId } )
+
+ // Normalize the binary version if it exists
+ if( opts.binVersion && opts.binVersion != "latest" && opts.binVersion != "" ){
+
+ // Convert to string
+ opts.binVersion = opts.binVersion + ""
+
+ // opts.binVersion = ( opts.binVersion + "" ).replace( /r|v/g, "" )
+
+ var numSeps = opts.binVersion.replace( /[^\.]/g, "" ).length
+ if( numSeps == 0 ) opts.binVersion += ".0.0"
+ else if( numSeps == 1 ) opts.binVersion += ".0"
+
+ // opts.binVersion = "r" + opts.binVersion
+ }
+
+ return opts
+}
+
+/**
+ * @option {object} opts
+ *
+ * {
+ * dbpath {string}
+ * useLogFiles {boolean}: use with logFile option.
+ * logFile {string}: path to the log file. If not specified and useLogFiles
+ * is true, automatically creates a log file inside dbpath.
+ * noJournalPrealloc {boolean}
+ * noJournal {boolean}
+ * keyFile
+ * replSet
+ * oplogSize
+ * }
+ */
+MongoRunner.mongodOptions = function( opts ){
+
+ opts = MongoRunner.mongoOptions( opts )
+
+ opts.dbpath = MongoRunner.toRealDir( opts.dbpath || "$dataDir/mongod-$port",
+ opts.pathOpts )
+
+ opts.pathOpts = Object.merge( opts.pathOpts, { dbpath : opts.dbpath } )
+
+ if( ! opts.logFile && opts.useLogFiles ){
+ opts.logFile = opts.dbpath + "/mongod.log"
+ }
+ else if( opts.logFile ){
+ opts.logFile = MongoRunner.toRealFile( opts.logFile, opts.pathOpts )
+ }
+
+ if( jsTestOptions().noJournalPrealloc || opts.noJournalPrealloc )
+ opts.nopreallocj = ""
+
+ if( jsTestOptions().noJournal || opts.noJournal )
+ opts.nojournal = ""
+
+ if( jsTestOptions().keyFile && !opts.keyFile) {
+ opts.keyFile = jsTestOptions().keyFile
+ }
+
+ if( opts.noReplSet ) opts.replSet = null
+ if( opts.arbiter ) opts.oplogSize = 1
+
+ return opts
+}
+
+MongoRunner.mongosOptions = function( opts ){
+
+ opts = MongoRunner.mongoOptions( opts )
+
+ // Normalize configdb option to be host string if currently a host
+ if( opts.configdb && opts.configdb.getDB ){
+ opts.configdb = opts.configdb.host
+ }
+
+ opts.pathOpts = Object.merge( opts.pathOpts,
+ { configdb : opts.configdb.replace( /:|,/g, "-" ) } )
+
+ if( ! opts.logFile && opts.useLogFiles ){
+ opts.logFile = MongoRunner.toRealFile( "$dataDir/mongos-$configdb-$port.log",
+ opts.pathOpts )
+ }
+ else if( opts.logFile ){
+ opts.logFile = MongoRunner.toRealFile( opts.logFile, opts.pathOpts )
+ }
+
+ if( jsTestOptions().keyFile && !opts.keyFile) {
+ opts.keyFile = jsTestOptions().keyFile
+ }
+
+ return opts
+}
+
+/**
+ * Starts a mongod instance.
+ *
+ * @param {Object} opts
+ *
+ * {
+ * useHostName {boolean}: Uses hostname of machine if true
+ * forceLock {boolean}: Deletes the lock file if set to true
+ * dbpath {string}: location of db files
+ * cleanData {boolean}: Removes all files in dbpath if true
+ * startClean {boolean}: same as cleanData
+ * noCleanData {boolean}: Do not clean files (cleanData takes priority)
+ *
+ * @see MongoRunner.mongodOptions for other options
+ * }
+ *
+ * @return {Mongo} connection object to the started mongod instance.
+ *
+ * @see MongoRunner.arrOptions
+ */
+MongoRunner.runMongod = function( opts ){
+
+ var useHostName = false
+ var runId = null
+ if( isObject( opts ) ) {
+
+ opts = MongoRunner.mongodOptions( opts )
+
+ useHostName = opts.useHostName || opts.useHostname
+ runId = opts.runId
+
+ if( opts.forceLock ) removeFile( opts.dbpath + "/mongod.lock" )
+ if( ( opts.cleanData || opts.startClean ) || ( ! opts.restart && ! opts.noCleanData ) ){
+ print( "Resetting db path '" + opts.dbpath + "'" )
+ resetDbpath( opts.dbpath )
+ }
+
+ opts = MongoRunner.arrOptions( "mongod", opts )
+ }
+
+ var mongod = startMongoProgram.apply( null, opts )
+ mongod.commandLine = MongoRunner.arrToOpts( opts )
+ mongod.name = (useHostName ? getHostName() : "localhost") + ":" + mongod.commandLine.port
+ mongod.host = mongod.name
+ mongod.port = parseInt( mongod.commandLine.port )
+ mongod.runId = runId || ObjectId()
+ mongod.savedOptions = MongoRunner.savedOptions[ mongod.runId ]
+
+ return mongod
+}
+
+MongoRunner.runMongos = function( opts ){
+
+ var useHostName = false
+ var runId = null
+ if( isObject( opts ) ) {
+
+ opts = MongoRunner.mongosOptions( opts )
+
+ useHostName = opts.useHostName || opts.useHostname
+ runId = opts.runId
+
+ opts = MongoRunner.arrOptions( "mongos", opts )
+ }
+
+ var mongos = startMongoProgram.apply( null, opts )
+ mongos.commandLine = MongoRunner.arrToOpts( opts )
+ mongos.name = (useHostName ? getHostName() : "localhost") + ":" + mongos.commandLine.port
+ mongos.host = mongos.name
+ mongos.port = parseInt( mongos.commandLine.port )
+ mongos.runId = runId || ObjectId()
+ mongos.savedOptions = MongoRunner.savedOptions[ mongos.runId ]
+
+ return mongos
+}
+
+/**
+ * Kills a mongod process.
+ *
+ * @param {number} port the port of the process to kill
+ * @param {number} signal The signal number to use for killing
+ * @param {Object} opts Additional options. Format:
+ * {
+ * auth: {
+ * user {string}: admin user name
+ * pwd {string}: admin password
+ * }
+ * }
+ *
+ * Note: The auth option is required in a authenticated mongod running in Windows since
+ * it uses the shutdown command, which requires admin credentials.
+ */
+MongoRunner.stopMongod = function( port, signal, opts ){
+
+ if( ! port ) {
+ print( "Cannot stop mongo process " + port )
+ return
+ }
+
+ signal = signal || 15
+
+ if( port.port )
+ port = parseInt( port.port )
+
+ if( port instanceof ObjectId ){
+ var opts = MongoRunner.savedOptions( port )
+ if( opts ) port = parseInt( opts.port )
+ }
+
+ var exitCode = stopMongod( parseInt( port ), parseInt( signal ), opts )
+
+ delete MongoRunner.usedPortMap[ "" + parseInt( port ) ]
+
+ return exitCode
+}
+
+MongoRunner.stopMongos = MongoRunner.stopMongod
+
+MongoRunner.isStopped = function( port ){
+
+ if( ! port ) {
+ print( "Cannot detect if process " + port + " is stopped." )
+ return
+ }
+
+ if( port.port )
+ port = parseInt( port.port )
+
+ if( port instanceof ObjectId ){
+ var opts = MongoRunner.savedOptions( port )
+ if( opts ) port = parseInt( opts.port )
+ }
+
+ return MongoRunner.usedPortMap[ "" + parseInt( port ) ] ? false : true
+}
+
+__nextPort = 27000;
+startMongodTest = function (port, dirname, restart, extraOptions ) {
+ if (!port)
+ port = __nextPort++;
+ var f = startMongodEmpty;
+ if (restart)
+ f = startMongodNoReset;
+ if (!dirname)
+ dirname = "" + port; // e.g., data/db/27000
+
+ var useHostname = false;
+ if (extraOptions) {
+ useHostname = extraOptions.useHostname;
+ delete extraOptions.useHostname;
+ }
+
+
+ var options =
+ {
+ port: port,
+ dbpath: "/data/db/" + dirname,
+ noprealloc: "",
+ smallfiles: "",
+ oplogSize: "40",
+ nohttpinterface: ""
+ };
+
+ if( jsTestOptions().noJournal ) options["nojournal"] = ""
+ if( jsTestOptions().noJournalPrealloc ) options["nopreallocj"] = ""
+ if( jsTestOptions().auth ) options["auth"] = ""
+ if( jsTestOptions().keyFile && (!extraOptions || !extraOptions['keyFile']) ) options['keyFile'] = jsTestOptions().keyFile
+
+ if ( extraOptions )
+ Object.extend( options , extraOptions );
+
+ var conn = f.apply(null, [ options ] );
+
+ conn.name = (useHostname ? getHostName() : "localhost") + ":" + port;
+
+ if (options['auth'] || options['keyFile']) {
+ if (!this.shardsvr && !options.replSet) {
+ jsTest.addAuth(conn);
+ }
+ jsTest.authenticate(conn);
+ }
+ return conn;
+}
+
+// Start a mongod instance and return a 'Mongo' object connected to it.
+// This function's arguments are passed as command line arguments to mongod.
+// The specified 'dbpath' is cleared if it exists, created if not.
+// var conn = startMongodEmpty("--port", 30000, "--dbpath", "asdf");
+startMongodEmpty = function () {
+ var args = createMongoArgs("mongod", arguments);
+
+ var dbpath = _parsePath.apply(null, args);
+ resetDbpath(dbpath);
+
+ return startMongoProgram.apply(null, args);
+}
+startMongod = function () {
+ print("startMongod WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING ONLY");
+ return startMongodEmpty.apply(null, arguments);
+}
+startMongodNoReset = function(){
+ var args = createMongoArgs( "mongod" , arguments );
+ return startMongoProgram.apply( null, args );
+}
+
+startMongos = function(args){
+ return MongoRunner.runMongos(args);
+}
+
+/* Start mongod or mongos and return a Mongo() object connected to there.
+ This function's first argument is "mongod" or "mongos" program name, \
+ and subsequent arguments to this function are passed as
+ command line arguments to the program.
+*/
+startMongoProgram = function(){
+ var port = _parsePort.apply( null, arguments );
+
+ _startMongoProgram.apply( null, arguments );
+
+ var m;
+ assert.soon
+ ( function() {
+ try {
+ m = new Mongo( "127.0.0.1:" + port );
+ return true;
+ } catch( e ) {
+ }
+ return false;
+ }, "unable to connect to mongo program on port " + port, 600 * 1000 );
+
+ return m;
+}
+
+runMongoProgram = function() {
+ var args = argumentsToArray( arguments );
+ if ( jsTestOptions().auth ) {
+ var progName = args[0];
+ args = args.slice(1);
+ args.unshift( progName, '-u', jsTestOptions().adminUser,
+ '-p', jsTestOptions().adminPassword );
+ }
+ return _runMongoProgram.apply( null, args );
+}
+
+// Start a mongo program instance. This function's first argument is the
+// program name, and subsequent arguments to this function are passed as
+// command line arguments to the program. Returns pid of the spawned program.
+startMongoProgramNoConnect = function() {
+ var args = argumentsToArray( arguments );
+ if ( jsTestOptions().auth ) {
+ var progName = args[0];
+ args = args.slice(1);
+ args.unshift( progName, '-u', jsTestOptions().adminUser,
+ '-p', jsTestOptions().adminPassword );
+ }
+ return _startMongoProgram.apply( null, args );
+}
+
+myPort = function() {
+ var m = db.getMongo();
+ if ( m.host.match( /:/ ) )
+ return m.host.match( /:(.*)/ )[ 1 ];
+ else
+ return 27017;
+}
diff --git a/src/mongo/shell/servers_misc.js b/src/mongo/shell/servers_misc.js
new file mode 100644
index 00000000000..f66db5709fe
--- /dev/null
+++ b/src/mongo/shell/servers_misc.js
@@ -0,0 +1,284 @@
+/**
+ * Run a mongod process.
+ *
+ * After initializing a MongodRunner, you must call start() on it.
+ * @param {int} port port to run db on, use allocatePorts(num) to requision
+ * @param {string} dbpath path to use
+ * @param {boolean} peer pass in false (DEPRECATED, was used for replica pair host)
+ * @param {boolean} arbiter pass in false (DEPRECATED, was used for replica pair host)
+ * @param {array} extraArgs other arguments for the command line
+ * @param {object} options other options include no_bind to not bind_ip to 127.0.0.1
+ * (necessary for replica set testing)
+ */
+MongodRunner = function( port, dbpath, peer, arbiter, extraArgs, options ) {
+ this.port_ = port;
+ this.dbpath_ = dbpath;
+ this.peer_ = peer;
+ this.arbiter_ = arbiter;
+ this.extraArgs_ = extraArgs;
+ this.options_ = options ? options : {};
+};
+
+/**
+ * Start this mongod process.
+ *
+ * @param {boolean} reuseData If the data directory should be left intact (default is to wipe it)
+ */
+MongodRunner.prototype.start = function( reuseData ) {
+ var args = [];
+ if ( reuseData ) {
+ args.push( "mongod" );
+ }
+ args.push( "--port" );
+ args.push( this.port_ );
+ args.push( "--dbpath" );
+ args.push( this.dbpath_ );
+ args.push( "--nohttpinterface" );
+ args.push( "--noprealloc" );
+ args.push( "--smallfiles" );
+ if (!this.options_.no_bind) {
+ args.push( "--bind_ip" );
+ args.push( "127.0.0.1" );
+ }
+ if ( this.extraArgs_ ) {
+ args = args.concat( this.extraArgs_ );
+ }
+ removeFile( this.dbpath_ + "/mongod.lock" );
+ if ( reuseData ) {
+ return startMongoProgram.apply( null, args );
+ } else {
+ return startMongod.apply( null, args );
+ }
+}
+
+MongodRunner.prototype.port = function() { return this.port_; }
+
+MongodRunner.prototype.toString = function() { return [ this.port_, this.dbpath_, this.peer_, this.arbiter_ ].toString(); }
+
+ToolTest = function( name ){
+ this.name = name;
+ this.port = allocatePorts(1)[0];
+ this.baseName = "jstests_tool_" + name;
+ this.root = "/data/db/" + this.baseName;
+ this.dbpath = this.root + "/";
+ this.ext = this.root + "_external/";
+ this.extFile = this.root + "_external/a";
+ resetDbpath( this.dbpath );
+ resetDbpath( this.ext );
+}
+
+ToolTest.prototype.startDB = function( coll ){
+ assert( ! this.m , "db already running" );
+
+ this.m = startMongoProgram( "mongod" , "--port", this.port , "--dbpath" , this.dbpath , "--nohttpinterface", "--noprealloc" , "--smallfiles" , "--bind_ip", "127.0.0.1" );
+ this.db = this.m.getDB( this.baseName );
+ if ( coll )
+ return this.db.getCollection( coll );
+ return this.db;
+}
+
+ToolTest.prototype.stop = function(){
+ if ( ! this.m )
+ return;
+ stopMongod( this.port );
+ this.m = null;
+ this.db = null;
+
+ print('*** ' + this.name + " completed successfully ***");
+}
+
+ToolTest.prototype.runTool = function(){
+ var a = [ "mongo" + arguments[0] ];
+
+ var hasdbpath = false;
+
+ for ( var i=1; i<arguments.length; i++ ){
+ a.push( arguments[i] );
+ if ( arguments[i] == "--dbpath" )
+ hasdbpath = true;
+ }
+
+ if ( ! hasdbpath ){
+ a.push( "--host" );
+ a.push( "127.0.0.1:" + this.port );
+ }
+
+ return runMongoProgram.apply( null , a );
+}
+
+
+ReplTest = function( name, ports ){
+ this.name = name;
+ this.ports = ports || allocatePorts( 2 );
+}
+
+ReplTest.prototype.getPort = function( master ){
+ if ( master )
+ return this.ports[ 0 ];
+ return this.ports[ 1 ]
+}
+
+ReplTest.prototype.getPath = function( master ){
+ var p = "/data/db/" + this.name + "-";
+ if ( master )
+ p += "master";
+ else
+ p += "slave"
+ return p;
+}
+
+ReplTest.prototype.getOptions = function( master , extra , putBinaryFirst, norepl ){
+
+ if ( ! extra )
+ extra = {};
+
+ if ( ! extra.oplogSize )
+ extra.oplogSize = "40";
+
+ var a = []
+ if ( putBinaryFirst )
+ a.push( "mongod" )
+ a.push( "--nohttpinterface", "--noprealloc", "--bind_ip" , "127.0.0.1" , "--smallfiles" );
+
+ a.push( "--port" );
+ a.push( this.getPort( master ) );
+
+ a.push( "--dbpath" );
+ a.push( this.getPath( master ) );
+
+ if( jsTestOptions().noJournal ) a.push( "--nojournal" )
+ if( jsTestOptions().noJournalPrealloc ) a.push( "--nopreallocj" )
+ if( jsTestOptions().keyFile ) {
+ a.push( "--keyFile" )
+ a.push( jsTestOptions().keyFile )
+ }
+
+ if ( !norepl ) {
+ if ( master ){
+ a.push( "--master" );
+ }
+ else {
+ a.push( "--slave" );
+ a.push( "--source" );
+ a.push( "127.0.0.1:" + this.ports[0] );
+ }
+ }
+
+ for ( var k in extra ){
+ var v = extra[k];
+ if( k in MongoRunner.logicalOptions ) continue
+ a.push( "--" + k );
+ if ( v != null )
+ a.push( v );
+ }
+
+ return a;
+}
+
+ReplTest.prototype.start = function( master , options , restart, norepl ){
+ var lockFile = this.getPath( master ) + "/mongod.lock";
+ removeFile( lockFile );
+ var o = this.getOptions( master , options , restart, norepl );
+
+
+ if ( restart )
+ return startMongoProgram.apply( null , o );
+ else
+ return startMongod.apply( null , o );
+}
+
+ReplTest.prototype.stop = function( master , signal ){
+ if ( arguments.length == 0 ){
+ this.stop( true );
+ this.stop( false );
+ return;
+ }
+
+ print('*** ' + this.name + " completed successfully ***");
+ return stopMongod( this.getPort( master ) , signal || 15 );
+}
+
+allocatePorts = function( n , startPort ) {
+ var ret = [];
+ var start = startPort || 31000;
+ for( var i = start; i < start + n; ++i )
+ ret.push( i );
+ return ret;
+}
+
+
+SyncCCTest = function( testName , extraMongodOptions ){
+ this._testName = testName;
+ this._connections = [];
+
+ for ( var i=0; i<3; i++ ){
+ this._connections.push( startMongodTest( 30000 + i , testName + i , false, extraMongodOptions ) );
+ }
+
+ this.url = this._connections.map( function(z){ return z.name; } ).join( "," );
+ this.conn = new Mongo( this.url );
+}
+
+SyncCCTest.prototype.stop = function(){
+ for ( var i=0; i<this._connections.length; i++){
+ stopMongod( 30000 + i );
+ }
+
+ print('*** ' + this._testName + " completed successfully ***");
+}
+
+SyncCCTest.prototype.checkHashes = function( dbname , msg ){
+ var hashes = this._connections.map(
+ function(z){
+ return z.getDB( dbname ).runCommand( "dbhash" );
+ }
+ );
+
+ for ( var i=1; i<hashes.length; i++ ){
+ assert.eq( hashes[0].md5 , hashes[i].md5 , "checkHash on " + dbname + " " + msg + "\n" + tojson( hashes ) )
+ }
+}
+
+SyncCCTest.prototype.tempKill = function( num ){
+ num = num || 0;
+ stopMongod( 30000 + num );
+}
+
+SyncCCTest.prototype.tempStart = function( num ){
+ num = num || 0;
+ this._connections[num] = startMongodTest( 30000 + num , this._testName + num , true );
+}
+
+
+function startParallelShell( jsCode, port ){
+ var x;
+
+ var args = ["mongo"];
+ if (port) {
+ args.push("--port", port);
+ }
+
+ if (TestData) {
+ jsCode = "TestData = " + tojson(TestData) + ";jsTest.authenticate(db.getMongo());" + jsCode;
+ }
+
+ args.push("--eval", jsCode);
+
+ if (typeof db == "object") {
+ args.push(db.getMongo().host);
+ }
+
+ x = startMongoProgramNoConnect.apply(null, args);
+ return function(){
+ waitProgram( x );
+ };
+}
+
+var testingReplication = false;
+
+function skipIfTestingReplication(){
+ if (testingReplication) {
+ print("skipIfTestingReplication skipping");
+ quit(0);
+ }
+}
diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js
new file mode 100644
index 00000000000..6d4dc5b1ca8
--- /dev/null
+++ b/src/mongo/shell/shardingtest.js
@@ -0,0 +1,996 @@
+/**
+ * Starts up a sharded cluster with the given specifications. The cluster
+ * will be fully operational after the execution of this constructor function.
+ *
+ * @param {Object} testName Contains the key value pair for the cluster
+ * configuration. Accpeted keys are:
+ *
+ * {
+ * name {string}: name for this test
+ * verbose {number}: the verbosity for the mongos
+ * keyFile {string}: the location of the keyFile
+ * chunksize {number}:
+ * nopreallocj {boolean|number}:
+ *
+ * mongos {number|Object|Array.<Object>}: number of mongos or mongos
+ * configuration object(s)(*). @see MongoRunner.runMongos
+ *
+ * rs {Object|Array.<Object>}: replica set configuration object. Can
+ * contain:
+ * {
+ * nodes {number}: number of replica members. Defaults to 3.
+ * For other options, @see ReplSetTest#start
+ * }
+ *
+ * shards {number|Object|Array.<Object>}: number of shards or shard
+ * configuration object(s)(*). @see MongoRunner.runMongod
+ *
+ * config {number|Object|Array.<Object>}: number of config server or
+ * config server configuration object(s)(*). The presence of this field
+ * implies other.separateConfig = true, and if has 3 or more members,
+ * implies other.sync = true. @see MongoRunner.runMongod
+ *
+ * (*) There are two ways For multiple configuration objects.
+ * (1) Using the object format. Example:
+ *
+ * { d0: { verbose: 5 }, d1: { auth: '' }, rs2: { oplogsize: 10 }}
+ *
+ * In this format, d = mongod, s = mongos & c = config servers
+ *
+ * (2) Using the array format. Example:
+ *
+ * [{ verbose: 5 }, { auth: '' }]
+ *
+ * Note: you can only have single server shards for array format.
+ *
+ * other: {
+ * nopreallocj: same as above
+ * rs: same as above
+ * chunksize: same as above
+ *
+ * shardOptions {Object}: same as the shards property above.
+ * Can be used to specify options that are common all shards.
+ *
+ * sync {boolean}: Use SyncClusterConnection, and readies
+ * 3 config servers.
+ * separateConfig {boolean}: if false, recycle one of the running mongod
+ * as a config server. The config property can override this. False by
+ * default.
+ * configOptions {Object}: same as the config property above.
+ * Can be used to specify options that are common all config servers.
+ * mongosOptions {Object}: same as the mongos property above.
+ * Can be used to specify options that are common all mongos.
+ *
+ * // replica Set only:
+ * rsOptions {Object}: same as the rs property above. Can be used to
+ * specify options that are common all replica members.
+ * useHostname {boolean}: if true, use hostname of machine,
+ * otherwise use localhost
+ * numReplicas {number}
+ * }
+ * }
+ *
+ * Member variables:
+ * s {Mongo} - connection to the first mongos
+ * s0, s1, ... {Mongo} - connection to different mongos
+ * rs0, rs1, ... {ReplSetTest} - test objects to replica sets
+ * shard0, shard1, ... {Mongo} - connection to shards (not available for replica sets)
+ * d0, d1, ... {Mongo} - same as shard0, shard1, ...
+ * config0, config1, ... {Mongo} - connection to config servers
+ * c0, c1, ... {Mongo} - same as config0, config1, ...
+ */
+ShardingTest = function( testName , numShards , verboseLevel , numMongos , otherParams ){
+
+ this._startTime = new Date();
+
+ // Check if testName is an object, if so, pull params from there
+ var keyFile = undefined
+ otherParams = Object.merge( otherParams || {}, {} )
+ otherParams.extraOptions = otherParams.extraOptions || {}
+
+ if( isObject( testName ) ){
+
+ var params = Object.merge( testName, {} )
+
+ testName = params.name || "test"
+
+ otherParams = Object.merge( params.other || {}, {} )
+ otherParams.extraOptions = otherParams.extraOptions || {}
+
+ numShards = params.shards || 2
+ verboseLevel = params.verbose || 0
+ numMongos = params.mongos || 1
+
+ keyFile = params.keyFile || otherParams.keyFile || otherParams.extraOptions.keyFile
+ otherParams.nopreallocj = params.nopreallocj || otherParams.nopreallocj
+ otherParams.rs = params.rs || ( params.other ? params.other.rs : undefined )
+ otherParams.chunksize = params.chunksize || ( params.other ? params.other.chunksize : undefined )
+
+ var tempCount = 0;
+
+ // Allow specifying options like :
+ // { mongos : [ { noprealloc : "" } ], config : [ { smallfiles : "" } ], shards : { rs : true, d : true } }
+ if( Array.isArray( numShards ) ){
+ for( var i = 0; i < numShards.length; i++ ){
+ otherParams[ "d" + i ] = numShards[i];
+ }
+
+ numShards = numShards.length;
+ }
+ else if( isObject( numShards ) ){
+ tempCount = 0;
+ for( var i in numShards ) {
+ otherParams[ i ] = numShards[i];
+ tempCount++;
+ }
+
+ numShards = tempCount;
+ }
+
+ if( Array.isArray( numMongos ) ){
+ for( var i = 0; i < numMongos.length; i++ ) {
+ otherParams[ "s" + i ] = numMongos[i];
+ }
+
+ numMongos = numMongos.length;
+ }
+ else if( isObject( numMongos ) ){
+ tempCount = 0;
+ for( var i in numMongos ) {
+ otherParams[ i ] = numMongos[i];
+ tempCount++;
+ }
+
+ numMongos = tempCount;
+ }
+
+ if( Array.isArray( params.config ) ){
+ for( var i = 0; i < params.config.length; i++ ){
+ otherParams[ "c" + i ] = params.config[i];
+ }
+
+ // If we're specifying explicit config options, we need separate config servers
+ otherParams.separateConfig = true;
+ if( params.config.length == 3 ) otherParams.sync = true;
+ else otherParams.sync = false;
+ }
+ else if( isObject( params.config ) ){
+ tempCount = 0;
+ for( var i in params.config ) {
+ otherParams[ i ] = params.config[i];
+ tempCount++;
+ }
+
+ // If we're specifying explicit config options, we need separate config servers
+ otherParams.separateConfig = true;
+ if( params.config.length == 3 ) otherParams.sync = true;
+ else otherParams.sync = false;
+ }
+ else if( params.config && params.config == 3 ) {
+ otherParams.separateConfig = otherParams.separateConfig || true;
+ otherParams.sync = true;
+ }
+ }
+ else {
+ // Handle legacy stuff
+ keyFile = otherParams.extraOptions.keyFile
+ }
+
+ this._testName = testName
+ this._otherParams = otherParams
+
+ var pathOpts = this.pathOpts = { testName : testName }
+
+ var hasRS = false
+ for( var k in otherParams ){
+ if( k.startsWith( "rs" ) && otherParams[k] != undefined ){
+ hasRS = true
+ break
+ }
+ }
+
+ if( hasRS ){
+ otherParams.separateConfig = true
+ otherParams.useHostname = otherParams.useHostname == undefined ? true : otherParams.useHostname
+ }
+
+ var localhost = otherParams.useHostname ? getHostName() : "localhost";
+
+ this._alldbpaths = []
+ this._connections = []
+ this._shardServers = this._connections
+ this._rs = []
+ this._rsObjects = []
+
+ for ( var i = 0; i < numShards; i++ ) {
+ if( otherParams.rs || otherParams["rs" + i] ){
+
+ otherParams.separateConfig = true
+
+ var setName = testName + "-rs" + i;
+
+ rsDefaults = { useHostname : otherParams.useHostname,
+ noJournalPrealloc : otherParams.nopreallocj,
+ oplogSize : 40,
+ pathOpts : Object.merge( pathOpts, { shard : i } )}
+
+ rsDefaults = Object.merge( rsDefaults, ShardingTest.rsOptions || {} )
+ rsDefaults = Object.merge( rsDefaults, otherParams.rs )
+ rsDefaults = Object.merge( rsDefaults, otherParams.rsOptions )
+ rsDefaults = Object.merge( rsDefaults, otherParams["rs" + i] )
+ rsDefaults.nodes = rsDefaults.nodes || otherParams.numReplicas
+
+ var numReplicas = rsDefaults.nodes || 3
+ delete rsDefaults.nodes
+
+ print( "Replica set test!" )
+
+ var rs = new ReplSetTest( { name : setName , nodes : numReplicas , startPort : 31100 + ( i * 100 ), useHostName : otherParams.useHostname, keyFile : keyFile, shardSvr : true } );
+ this._rs[i] = { setName : setName , test : rs , nodes : rs.startSet( rsDefaults ) , url : rs.getURL() };
+ rs.initiate();
+ this["rs" + i] = rs
+
+ this._rsObjects[i] = rs
+
+ this._alldbpaths.push( null )
+ this._connections.push( null )
+ }
+ else {
+ var options = { useHostname : otherParams.useHostname,
+ noJournalPrealloc : otherParams.nopreallocj,
+ port : 30000 + i,
+ pathOpts : Object.merge( pathOpts, { shard : i } ),
+ dbpath : "$testName$shard",
+ keyFile : keyFile
+ }
+
+ options = Object.merge( options, ShardingTest.shardOptions || {} )
+
+ if( otherParams.shardOptions && otherParams.shardOptions.binVersion ){
+ otherParams.shardOptions.binVersion =
+ MongoRunner.versionIterator( otherParams.shardOptions.binVersion )
+ }
+
+ options = Object.merge( options, otherParams.shardOptions )
+ options = Object.merge( options, otherParams["d" + i] )
+
+ var conn = MongoRunner.runMongod( options );
+
+ this._alldbpaths.push( testName +i )
+ this._connections.push( conn );
+ this["shard" + i] = conn
+ this["d" + i] = conn
+
+ this._rs[i] = null
+ this._rsObjects[i] = null
+ }
+ }
+
+ // Do replication on replica sets if required
+ for ( var i = 0; i < numShards; i++ ){
+ if( ! otherParams.rs && ! otherParams["rs" + i] ) continue
+
+ var rs = this._rs[i].test;
+
+ rs.getMaster().getDB( "admin" ).foo.save( { x : 1 } )
+ rs.awaitReplication();
+
+ var rsConn = new Mongo( rs.getURL() );
+ rsConn.name = rs.getURL();
+ this._connections[i] = rsConn
+ this["shard" + i] = rsConn
+ rsConn.rs = rs
+ }
+
+ this._configServers = []
+ this._configNames = []
+
+ if ( otherParams.sync && ! otherParams.separateConfig && numShards < 3 )
+ throw "if you want sync, you need at least 3 servers";
+
+ for ( var i = 0; i < ( otherParams.sync ? 3 : 1 ) ; i++ ) {
+
+ var conn = null
+
+ if( otherParams.separateConfig ){
+
+ var options = { useHostname : otherParams.useHostname,
+ noJournalPrealloc : otherParams.nopreallocj,
+ port : 29000 + i,
+ pathOpts : Object.merge( pathOpts, { config : i } ),
+ dbpath : "$testName-config$config",
+ keyFile : keyFile,
+ configsvr : ""
+ }
+
+ options = Object.merge( options, ShardingTest.configOptions || {} )
+
+ if( otherParams.configOptions && otherParams.configOptions.binVersion ){
+ otherParams.configOptions.binVersion =
+ MongoRunner.versionIterator( otherParams.configOptions.binVersion )
+ }
+
+ options = Object.merge( options, otherParams.configOptions )
+ options = Object.merge( options, otherParams["c" + i] )
+
+ var conn = MongoRunner.runMongod( options )
+
+ // TODO: Needed?
+ this._alldbpaths.push( testName + "-config" + i )
+ }
+ else{
+ conn = this["shard" + i]
+ }
+
+ this._configServers.push( conn );
+ this._configNames.push( conn.name )
+ this["config" + i] = conn
+ this["c" + i] = conn
+ }
+
+ printjson( this._configDB = this._configNames.join( "," ) )
+ this._configConnection = new Mongo( this._configDB )
+ print( "ShardingTest " + this._testName + " :\n" + tojson( { config : this._configDB, shards : this._connections } ) );
+
+ if ( numMongos == 0 && !otherParams.noChunkSize ) {
+ if ( keyFile ) {
+ throw "Cannot set chunk size without any mongos when using auth";
+ } else {
+ this._configConnection.getDB( "config" ).settings.insert(
+ { _id : "chunksize" , value : otherParams.chunksize || otherParams.chunkSize || 50 } );
+ }
+ }
+
+ this._mongos = []
+ this._mongoses = this._mongos
+ for ( var i = 0; i < ( ( numMongos == 0 ? -1 : numMongos ) || 1 ); i++ ){
+
+ var options = { useHostname : otherParams.useHostname,
+ port : 31000 - i - 1,
+ pathOpts : Object.merge( pathOpts, { mongos : i } ),
+ configdb : this._configDB,
+ verbose : verboseLevel || 0,
+ keyFile : keyFile
+ }
+ if ( ! otherParams.noChunkSize ) {
+ options.chunkSize = otherParams.chunksize || otherParams.chunkSize || 50;
+ }
+
+ options = Object.merge( options, ShardingTest.mongosOptions || {} )
+
+ if( otherParams.mongosOptions && otherParams.mongosOptions.binVersion ){
+ otherParams.mongosOptions.binVersion =
+ MongoRunner.versionIterator( otherParams.mongosOptions.binVersion )
+ }
+
+ options = Object.merge( options, otherParams.mongosOptions )
+ options = Object.merge( options, otherParams.extraOptions )
+ options = Object.merge( options, otherParams["s" + i] )
+
+ var conn = MongoRunner.runMongos( options )
+
+ this._mongos.push( conn );
+ if ( i == 0 ) this.s = conn
+ this["s" + i] = conn
+ }
+
+ var admin = this.admin = this.s.getDB( "admin" );
+ this.config = this.s.getDB( "config" );
+
+ if ( ! otherParams.manualAddShard ){
+ this._shardNames = []
+ var shardNames = this._shardNames
+ this._connections.forEach(
+ function(z){
+ var n = z.name;
+ if ( ! n ){
+ n = z.host;
+ if ( ! n )
+ n = z;
+ }
+ print( "ShardingTest " + this._testName + " going to add shard : " + n )
+ x = admin.runCommand( { addshard : n } );
+ printjson( x )
+ assert( x.ok );
+ shardNames.push( x.shardAdded )
+ z.shardName = x.shardAdded
+ }
+ );
+ }
+
+ if (jsTestOptions().keyFile && !keyFile) {
+ jsTest.addAuth( this._configConnection );
+ jsTest.authenticate( this._configConnection );
+ jsTest.authenticateNodes( this._configServers );
+ jsTest.authenticateNodes( this._mongos );
+ }
+}
+
+ShardingTest.prototype.getRSEntry = function( setName ){
+ for ( var i=0; i<this._rs.length; i++ )
+ if ( this._rs[i].setName == setName )
+ return this._rs[i];
+ throw "can't find rs: " + setName;
+}
+
+ShardingTest.prototype.getConfigIndex = function( config ){
+
+ // Assume config is a # if not a conn object
+ if( ! isObject( config ) ) config = getHostName() + ":" + config
+
+ for( var i = 0; i < this._configServers.length; i++ ){
+ if( connectionURLTheSame( this._configServers[i], config ) ) return i
+ }
+
+ return -1
+}
+
+ShardingTest.prototype.getDB = function( name ){
+ return this.s.getDB( name );
+}
+
+ShardingTest.prototype.getServerName = function( dbname ){
+ var x = this.config.databases.findOne( { _id : "" + dbname } );
+ if ( x )
+ return x.primary;
+ this.config.databases.find().forEach( printjson );
+ throw "couldn't find dbname: " + dbname + " total: " + this.config.databases.count();
+}
+
+
+ShardingTest.prototype.getNonPrimaries = function( dbname ){
+ var x = this.config.databases.findOne( { _id : dbname } );
+ if ( ! x ){
+ this.config.databases.find().forEach( printjson );
+ throw "couldn't find dbname: " + dbname + " total: " + this.config.databases.count();
+ }
+
+ return this.config.shards.find( { _id : { $ne : x.primary } } ).map( function(z){ return z._id; } )
+}
+
+
+ShardingTest.prototype.getConnNames = function(){
+ var names = [];
+ for ( var i=0; i<this._connections.length; i++ ){
+ names.push( this._connections[i].name );
+ }
+ return names;
+}
+
+ShardingTest.prototype.getServer = function( dbname ){
+ var name = this.getServerName( dbname );
+
+ var x = this.config.shards.findOne( { _id : name } );
+ if ( x )
+ name = x.host;
+
+ var rsName = null;
+ if ( name.indexOf( "/" ) > 0 )
+ rsName = name.substring( 0 , name.indexOf( "/" ) );
+
+ for ( var i=0; i<this._connections.length; i++ ){
+ var c = this._connections[i];
+ if ( connectionURLTheSame( name , c.name ) ||
+ connectionURLTheSame( rsName , c.name ) )
+ return c;
+ }
+
+ throw "can't find server for: " + dbname + " name:" + name;
+
+}
+
+ShardingTest.prototype.normalize = function( x ){
+ var z = this.config.shards.findOne( { host : x } );
+ if ( z )
+ return z._id;
+ return x;
+}
+
+ShardingTest.prototype.getOther = function( one ){
+ if ( this._connections.length < 2 )
+ throw "getOther only works with 2 servers";
+
+ if ( one._mongo )
+ one = one._mongo
+
+ for( var i = 0; i < this._connections.length; i++ ){
+ if( this._connections[i] != one ) return this._connections[i]
+ }
+
+ return null
+}
+
+ShardingTest.prototype.getAnother = function( one ){
+ if(this._connections.length < 2)
+ throw "getAnother() only works with multiple servers";
+
+ if ( one._mongo )
+ one = one._mongo
+
+ for(var i = 0; i < this._connections.length; i++){
+ if(this._connections[i] == one)
+ return this._connections[(i + 1) % this._connections.length];
+ }
+}
+
+ShardingTest.prototype.getFirstOther = function( one ){
+ for ( var i=0; i<this._connections.length; i++ ){
+ if ( this._connections[i] != one )
+ return this._connections[i];
+ }
+ throw "impossible";
+}
+
+ShardingTest.prototype.stop = function(){
+ for ( var i=0; i<this._mongos.length; i++ ){
+ stopMongoProgram( 31000 - i - 1 );
+ }
+ for ( var i=0; i<this._connections.length; i++){
+ stopMongod( 30000 + i );
+ }
+ if ( this._rs ){
+ for ( var i=0; i<this._rs.length; i++ ){
+ if( this._rs[i] ) this._rs[i].test.stopSet( 15 );
+ }
+ }
+ if( this._otherParams.separateConfig ){
+ for ( var i=0; i<this._configServers.length; i++ ){
+ MongoRunner.stopMongod( this._configServers[i] )
+ }
+ }
+ if ( this._alldbpaths ){
+ for( i=0; i<this._alldbpaths.length; i++ ){
+ resetDbpath( "/data/db/" + this._alldbpaths[i] );
+ }
+ }
+
+ var timeMillis = new Date().getTime() - this._startTime.getTime();
+
+ print('*** ShardingTest ' + this._testName + " completed successfully in " + ( timeMillis / 1000 ) + " seconds ***");
+}
+
+ShardingTest.prototype.adminCommand = function(cmd){
+ var res = this.admin.runCommand( cmd );
+ if ( res && res.ok == 1 )
+ return true;
+
+ throw "command " + tojson( cmd ) + " failed: " + tojson( res );
+}
+
+ShardingTest.prototype._rangeToString = function(r){
+ return tojsononeline( r.min ) + " -> " + tojsononeline( r.max );
+}
+
+ShardingTest.prototype.printChangeLog = function(){
+ var s = this;
+ this.config.changelog.find().forEach(
+ function(z){
+ var msg = z.server + "\t" + z.time + "\t" + z.what;
+ for ( i=z.what.length; i<15; i++ )
+ msg += " ";
+ msg += " " + z.ns + "\t";
+ if ( z.what == "split" ){
+ msg += s._rangeToString( z.details.before ) + " -->> (" + s._rangeToString( z.details.left ) + "),(" + s._rangeToString( z.details.right ) + ")";
+ }
+ else if (z.what == "multi-split" ){
+ msg += s._rangeToString( z.details.before ) + " -->> (" + z.details.number + "/" + z.details.of + " " + s._rangeToString( z.details.chunk ) + ")";
+ }
+ else {
+ msg += tojsononeline( z.details );
+ }
+
+ print( "ShardingTest " + msg )
+ }
+ );
+
+}
+
+ShardingTest.prototype.getChunksString = function( ns ){
+ var q = {}
+ if ( ns )
+ q.ns = ns;
+
+ var s = "";
+ this.config.chunks.find( q ).sort( { ns : 1 , min : 1 } ).forEach(
+ function(z){
+ s += " " + z._id + "\t" + z.lastmod.t + "|" + z.lastmod.i + "\t" + tojson(z.min) + " -> " + tojson(z.max) + " " + z.shard + " " + z.ns + "\n";
+ }
+ );
+
+ return s;
+}
+
+ShardingTest.prototype.printChunks = function( ns ){
+ print( "ShardingTest " + this.getChunksString( ns ) );
+}
+
+ShardingTest.prototype.printShardingStatus = function(){
+ printShardingStatus( this.config );
+}
+
+ShardingTest.prototype.printCollectionInfo = function( ns , msg ){
+ var out = "";
+ if ( msg )
+ out += msg + "\n";
+ out += "sharding collection info: " + ns + "\n";
+ for ( var i=0; i<this._connections.length; i++ ){
+ var c = this._connections[i];
+ out += " mongod " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n";
+ }
+ for ( var i=0; i<this._mongos.length; i++ ){
+ var c = this._mongos[i];
+ out += " mongos " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n";
+ }
+
+ out += this.getChunksString( ns );
+
+ print( "ShardingTest " + out );
+}
+
+printShardingStatus = function( configDB , verbose ){
+ if (configDB === undefined)
+ configDB = db.getSisterDB('config')
+
+ var version = configDB.getCollection( "version" ).findOne();
+ if ( version == null ){
+ print( "printShardingStatus: this db does not have sharding enabled. be sure you are connecting to a mongos from the shell and not to a mongod." );
+ return;
+ }
+
+ var raw = "";
+ var output = function(s){
+ raw += s + "\n";
+ }
+ output( "--- Sharding Status --- " );
+ output( " sharding version: " + tojson( configDB.getCollection( "version" ).findOne() ) );
+
+ output( " shards:" );
+ configDB.shards.find().sort( { _id : 1 } ).forEach(
+ function(z){
+ output( "\t" + tojsononeline( z ) );
+ }
+ );
+
+ output( " databases:" );
+ configDB.databases.find().sort( { name : 1 } ).forEach(
+ function(db){
+ output( "\t" + tojsononeline(db,"",true) );
+
+ if (db.partitioned){
+ configDB.collections.find( { _id : new RegExp( "^" +
+ RegExp.escape(db._id) + "\\." ) } ).
+ sort( { _id : 1 } ).forEach( function( coll ){
+ if ( coll.dropped == false ){
+ output("\t\t" + coll._id + " chunks:");
+
+ res = configDB.chunks.group( { cond : { ns : coll._id } , key : { shard : 1 },
+ reduce : function( doc , out ){ out.nChunks++; } , initial : { nChunks : 0 } } );
+ var totalChunks = 0;
+ res.forEach( function(z){
+ totalChunks += z.nChunks;
+ output( "\t\t\t\t" + z.shard + "\t" + z.nChunks );
+ } )
+
+ if ( totalChunks < 20 || verbose ){
+ configDB.chunks.find( { "ns" : coll._id } ).sort( { min : 1 } ).forEach(
+ function(chunk){
+ output( "\t\t\t" + tojson( chunk.min ) + " -->> " + tojson( chunk.max ) +
+ " on : " + chunk.shard + " " + tojson( chunk.lastmod ) + " " +
+ ( chunk.jumbo ? "jumbo " : "" ) );
+ }
+ );
+ }
+ else {
+ output( "\t\t\ttoo many chunks to print, use verbose if you want to force print" );
+ }
+
+ configDB.tags.find( { ns : coll._id } ).sort( { min : 1 } ).forEach(
+ function( tag ) {
+ output( "\t\t\t tag: " + tag.tag + " " + tojson( tag.min ) + " -->> " + tojson( tag.max ) );
+ }
+ )
+ }
+ }
+ )
+ }
+ }
+ );
+
+ print( raw );
+}
+
+printShardingSizes = function(){
+ configDB = db.getSisterDB('config')
+
+ var version = configDB.getCollection( "version" ).findOne();
+ if ( version == null ){
+ print( "printShardingSizes : not a shard db!" );
+ return;
+ }
+
+ var raw = "";
+ var output = function(s){
+ raw += s + "\n";
+ }
+ output( "--- Sharding Status --- " );
+ output( " sharding version: " + tojson( configDB.getCollection( "version" ).findOne() ) );
+
+ output( " shards:" );
+ var shards = {};
+ configDB.shards.find().forEach(
+ function(z){
+ shards[z._id] = new Mongo(z.host);
+ output( " " + tojson(z) );
+ }
+ );
+
+ var saveDB = db;
+ output( " databases:" );
+ configDB.databases.find().sort( { name : 1 } ).forEach(
+ function(db){
+ output( "\t" + tojson(db,"",true) );
+
+ if (db.partitioned){
+ configDB.collections.find( { _id : new RegExp( "^" +
+ RegExp.escape(db._id) + "\." ) } ).
+ sort( { _id : 1 } ).forEach( function( coll ){
+ output("\t\t" + coll._id + " chunks:");
+ configDB.chunks.find( { "ns" : coll._id } ).sort( { min : 1 } ).forEach(
+ function(chunk){
+ var mydb = shards[chunk.shard].getDB(db._id)
+ var out = mydb.runCommand({dataSize: coll._id,
+ keyPattern: coll.key,
+ min: chunk.min,
+ max: chunk.max });
+ delete out.millis;
+ delete out.ok;
+
+ output( "\t\t\t" + tojson( chunk.min ) + " -->> " + tojson( chunk.max ) +
+ " on : " + chunk.shard + " " + tojson( out ) );
+
+ }
+ );
+ }
+ )
+ }
+ }
+ );
+
+ print( raw );
+}
+
+ShardingTest.prototype.sync = function(){
+ this.adminCommand( "connpoolsync" );
+}
+
+ShardingTest.prototype.onNumShards = function( collName , dbName ){
+ this.sync(); // we should sync since we're going directly to mongod here
+ dbName = dbName || "test";
+ var num=0;
+ for ( var i=0; i<this._connections.length; i++ )
+ if ( this._connections[i].getDB( dbName ).getCollection( collName ).count() > 0 )
+ num++;
+ return num;
+}
+
+
+ShardingTest.prototype.shardCounts = function( collName , dbName ){
+ this.sync(); // we should sync since we're going directly to mongod here
+ dbName = dbName || "test";
+ var counts = {}
+ for ( var i=0; i<this._connections.length; i++ )
+ counts[i] = this._connections[i].getDB( dbName ).getCollection( collName ).count();
+ return counts;
+}
+
+ShardingTest.prototype.chunkCounts = function( collName , dbName ){
+ dbName = dbName || "test";
+ var x = {}
+
+ this.config.shards.find().forEach(
+ function(z){
+ x[z._id] = 0;
+ }
+ );
+
+ this.config.chunks.find( { ns : dbName + "." + collName } ).forEach(
+ function(z){
+ if ( x[z.shard] )
+ x[z.shard]++
+ else
+ x[z.shard] = 1;
+ }
+ );
+ return x;
+
+}
+
+ShardingTest.prototype.chunkDiff = function( collName , dbName ){
+ var c = this.chunkCounts( collName , dbName );
+ var min = 100000000;
+ var max = 0;
+ for ( var s in c ){
+ if ( c[s] < min )
+ min = c[s];
+ if ( c[s] > max )
+ max = c[s];
+ }
+ print( "ShardingTest input: " + tojson( c ) + " min: " + min + " max: " + max );
+ return max - min;
+}
+
+// Waits up to one minute for the difference in chunks between the most loaded shard and least
+// loaded shard to be 0 or 1, indicating that the collection is well balanced.
+// This should only be called after creating a big enough chunk difference to trigger balancing.
+ShardingTest.prototype.awaitBalance = function( collName , dbName , timeToWait ) {
+ timeToWait = timeToWait || 60000;
+ var shardingTest = this;
+ assert.soon( function() {
+ var x = shardingTest.chunkDiff( collName , dbName );
+ print( "chunk diff: " + x );
+ return x < 2;
+ } , "no balance happened", 60000 );
+
+}
+
+ShardingTest.prototype.getShard = function( coll, query, includeEmpty ){
+ var shards = this.getShards( coll, query, includeEmpty )
+ assert.eq( shards.length, 1 )
+ return shards[0]
+}
+
+// Returns the shards on which documents matching a particular query reside
+ShardingTest.prototype.getShards = function( coll, query, includeEmpty ){
+ if( ! coll.getDB )
+ coll = this.s.getCollection( coll )
+
+ var explain = coll.find( query ).explain()
+ var shards = []
+
+ if( explain.shards ){
+
+ for( var shardName in explain.shards ){
+ for( var i = 0; i < explain.shards[shardName].length; i++ ){
+ if( includeEmpty || ( explain.shards[shardName][i].n && explain.shards[shardName][i].n > 0 ) )
+ shards.push( shardName )
+ }
+ }
+
+ }
+
+ for( var i = 0; i < shards.length; i++ ){
+ for( var j = 0; j < this._connections.length; j++ ){
+ if ( connectionURLTheSame( this._connections[j] , shards[i] ) ){
+ shards[i] = this._connections[j]
+ break;
+ }
+ }
+ }
+
+ return shards
+}
+
+ShardingTest.prototype.isSharded = function( collName ){
+
+ var collName = "" + collName
+ var dbName = undefined
+
+ if( typeof collName.getCollectionNames == 'function' ){
+ dbName = "" + collName
+ collName = undefined
+ }
+
+ if( dbName ){
+ var x = this.config.databases.findOne( { _id : dbname } )
+ if( x ) return x.partitioned
+ else return false
+ }
+
+ if( collName ){
+ var x = this.config.collections.findOne( { _id : collName } )
+ if( x ) return true
+ else return false
+ }
+
+}
+
+ShardingTest.prototype.shardGo = function( collName , key , split , move , dbName ){
+
+ split = ( split != false ? ( split || key ) : split )
+ move = ( split != false && move != false ? ( move || split ) : false )
+
+ if( collName.getDB )
+ dbName = "" + collName.getDB()
+ else dbName = dbName || "test";
+
+ var c = dbName + "." + collName;
+ if( collName.getDB )
+ c = "" + collName
+
+ var isEmpty = this.s.getCollection( c ).count() == 0
+
+ if( ! this.isSharded( dbName ) )
+ this.s.adminCommand( { enableSharding : dbName } )
+
+ var result = this.s.adminCommand( { shardcollection : c , key : key } )
+ if( ! result.ok ){
+ printjson( result )
+ assert( false )
+ }
+
+ if( split == false ) return
+
+ result = this.s.adminCommand( { split : c , middle : split } );
+ if( ! result.ok ){
+ printjson( result )
+ assert( false )
+ }
+
+ if( move == false ) return
+
+ var result = null
+ for( var i = 0; i < 5; i++ ){
+ result = this.s.adminCommand( { movechunk : c , find : move , to : this.getOther( this.getServer( dbName ) ).name } );
+ if( result.ok ) break;
+ sleep( 5 * 1000 );
+ }
+ printjson( result )
+ assert( result.ok )
+
+};
+
+ShardingTest.prototype.shardColl = ShardingTest.prototype.shardGo
+
+ShardingTest.prototype.setBalancer = function( balancer ){
+ if( balancer || balancer == undefined ){
+ this.config.settings.update( { _id: "balancer" }, { $set : { stopped: false } } , true )
+ }
+ else if( balancer == false ){
+ this.config.settings.update( { _id: "balancer" }, { $set : { stopped: true } } , true )
+ }
+}
+
+ShardingTest.prototype.stopBalancer = function( timeout, interval ) {
+ this.setBalancer( false )
+
+ if( typeof db == "undefined" ) db = undefined
+ var oldDB = db
+
+ db = this.config
+ sh.waitForBalancer( false, timeout, interval )
+ db = oldDB
+}
+
+ShardingTest.prototype.startBalancer = function( timeout, interval ) {
+ this.setBalancer( true )
+
+ if( typeof db == "undefined" ) db = undefined
+ var oldDB = db
+
+ db = this.config
+ sh.waitForBalancer( true, timeout, interval )
+ db = oldDB
+}
+
+/**
+ * Kills the mongos with index n.
+ */
+ShardingTest.prototype.stopMongos = function(n) {
+ MongoRunner.stopMongos(this['s' + n].port);
+};
+
+/**
+ * Restarts a previously stopped mongos using the same parameter as before.
+ *
+ * Warning: Overwrites the old s (if n = 0) and sn member variables
+ */
+ShardingTest.prototype.restartMongos = function(n) {
+ this.stopMongos(n);
+ var newConn = MongoRunner.runMongos(this['s' + n].commandLine);
+
+ this['s' + n] = newConn;
+ if (n == 0) {
+ this.s = newConn;
+ }
+};
+
diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp
new file mode 100644
index 00000000000..2cd1f3d7429
--- /dev/null
+++ b/src/mongo/shell/shell_utils.cpp
@@ -0,0 +1,235 @@
+// mongo/shell/shell_utils.cpp
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+
+#include "mongo/shell/shell_utils.h"
+#include "mongo/shell/shell_utils_extended.h"
+#include "mongo/shell/shell_utils_launcher.h"
+#include "mongo/util/processinfo.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/scripting/engine.h"
+
+namespace mongo {
+
+ 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 {
+
+ std::string _dbConnect;
+ std::string _dbAuth;
+
+ const char *argv0 = 0;
+ void RecordMyLocation( const char *_argv0 ) { argv0 = _argv0; }
+
+ // helpers
+
+ 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();
+ }
+
+ const char* getUserDir() {
+#ifdef _WIN32
+ return getenv( "USERPROFILE" );
+#else
+ return getenv( "HOME" );
+#endif
+ }
+
+ // 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() );
+ ::_exit(exit_code);
+ return undefinedReturn;
+ }
+
+ 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 b;
+ b.append( "ret" , e.obj() );
+
+ return b.obj();
+ }
+
+#if !defined(_WIN32)
+ 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() );
+#if !defined(_WIN32)
+ _randomSeed.set( static_cast< unsigned int >( a.firstElement().numberLong() ) ); // grab least significant digits
+#else
+ srand( static_cast< unsigned int >( a.firstElement().numberLong() ) );
+#endif
+ return undefinedReturn;
+ }
+
+ 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() );
+#else
+ r = rand();
+#endif
+ return BSON( "" << double( r ) / ( double( RAND_MAX ) + 1 ) );
+ }
+
+ BSONObj isWindows(const BSONObj& a, void* data) {
+ uassert( 13006, "isWindows accepts no arguments", a.nFields() == 0 );
+#ifdef _WIN32
+ return BSON( "" << true );
+#else
+ return BSON( "" << false );
+#endif
+ }
+
+ void installShellUtils( Scope& scope ) {
+ scope.injectNative( "quit", Quit );
+ scope.injectNative( "getMemInfo" , JSGetMemInfo );
+ scope.injectNative( "_srand" , JSSrand );
+ scope.injectNative( "_rand" , JSRand );
+ scope.injectNative( "_isWindows" , isWindows );
+
+#ifndef MONGO_SAFE_SHELL
+ //can't launch programs
+ installShellUtilsLauncher( scope );
+ installShellUtilsExtended( scope );
+#endif
+ }
+
+ void initScope( Scope &scope ) {
+ 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);
+
+ if ( !_dbConnect.empty() ) {
+ uassert( 12513, "connect failed", scope.exec( _dbConnect , "(connect)" , false , true , false ) );
+ if ( !_dbAuth.empty() ) {
+ installGlobalUtils( scope );
+ uassert( 12514, "login failed", scope.exec( _dbAuth , "(auth)" , true , true , false ) );
+ }
+ }
+ }
+
+ Prompter::Prompter( const string &prompt ) :
+ _prompt( prompt ),
+ _confirmed() {
+ }
+
+ 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;
+ }
+
+ ConnectionRegistry::ConnectionRegistry() :
+ _mutex( "connectionRegistryMutex" ) {
+ }
+
+ void ConnectionRegistry::registerConnection( DBClientWithCommands &client ) {
+ BSONObj info;
+ if ( client.runCommand( "admin", BSON( "whatsmyuri" << 1 ), info ) ) {
+ string connstr = dynamic_cast<DBClientBase&>( client ).getServerAddress();
+ mongo::mutex::scoped_lock lk( _mutex );
+ _connectionUris[ connstr ].insert( info[ "you" ].str() );
+ }
+ }
+
+ void ConnectionRegistry::killOperationsOnAllConnections( bool withPrompt ) const {
+ Prompter prompter( "do you want to kill the current op(s) on the server?" );
+ mongo::mutex::scoped_lock lk( _mutex );
+ for( map<string,set<string> >::const_iterator i = _connectionUris.begin();
+ i != _connectionUris.end(); ++i ) {
+ string errmsg;
+ ConnectionString cs = ConnectionString::parse( i->first, errmsg );
+ if ( !cs.isValid() ) {
+ continue;
+ }
+ boost::scoped_ptr<DBClientWithCommands> conn( cs.connect( errmsg ) );
+ if ( !conn ) {
+ continue;
+ }
+
+ const set<string>& uris = i->second;
+
+ BSONObj inprog = conn->findOne( "admin.$cmd.sys.inprog", Query() )[ "inprog" ]
+ .embeddedObject().getOwned();
+ BSONForEach( op, inprog ) {
+ if ( uris.count( op[ "client" ].String() ) ) {
+ if ( !withPrompt || prompter.confirm() ) {
+ conn->findOne( "admin.$cmd.sys.killop", QUERY( "op"<< op[ "opid" ] ) );
+ }
+ else {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ ConnectionRegistry connectionRegistry;
+
+ bool _nokillop = false;
+ void onConnect( DBClientWithCommands &c ) {
+ if ( _nokillop ) {
+ return;
+ }
+ connectionRegistry.registerConnection( c );
+ }
+ }
+}
diff --git a/src/mongo/shell/shell_utils.h b/src/mongo/shell/shell_utils.h
new file mode 100644
index 00000000000..8c8d7de1542
--- /dev/null
+++ b/src/mongo/shell/shell_utils.h
@@ -0,0 +1,69 @@
+// mongo/shell/shell_utils.h
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+#include "mongo/db/jsobj.h"
+
+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 string &prompt );
+ /** @return prompted confirmation or cached confirmation. */
+ bool confirm();
+ private:
+ const string _prompt;
+ bool _confirmed;
+ };
+
+ /** Registry of server connections. */
+ class ConnectionRegistry {
+ public:
+ ConnectionRegistry();
+ void registerConnection( DBClientWithCommands &client );
+ void killOperationsOnAllConnections( bool withPrompt ) const;
+ private:
+ map<string,set<string> > _connectionUris;
+ mutable mongo::mutex _mutex;
+ };
+
+ extern ConnectionRegistry connectionRegistry;
+ }
+}
diff --git a/src/mongo/shell/shell_utils_extended.cpp b/src/mongo/shell/shell_utils_extended.cpp
new file mode 100644
index 00000000000..7e147b4eeeb
--- /dev/null
+++ b/src/mongo/shell/shell_utils_extended.cpp
@@ -0,0 +1,225 @@
+// mongo/shell/shell_utils_extended.cpp
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+
+#include <boost/filesystem/convenience.hpp>
+
+#include <fstream>
+
+#include "mongo/util/net/sock.h"
+
+#include "mongo/shell/shell_utils.h"
+#include "mongo/shell/shell_utils_launcher.h"
+#include "mongo/util/md5.hpp"
+#include "mongo/util/file.h"
+#include "mongo/scripting/engine.h"
+
+namespace mongo {
+
+ /**
+ * 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.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() );
+ 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 += '/';
+ }
+ ret << name;
+ }
+ }
+ return BSON( "" << ret.arr() );
+ }
+
+ /** Set process wide current working directory. */
+ BSONObj cd(const BSONObj& args, void* data) {
+#if defined(_WIN32)
+ std::wstring dir = toWideString( args.firstElement().String().c_str() );
+ if( SetCurrentDirectory(dir.c_str()) )
+ return BSONObj();
+#else
+ string dir = args.firstElement().String();
+ if( chdir( dir.c_str() ) == 0 )
+ return BSONObj();
+#endif
+ return BSON( "" << "change directory failed" );
+ }
+
+ 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() );
+ }
+
+ 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() );
+
+ 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 );
+
+ 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 ) );
+ }
+
+ BSONObj mkdir(const BSONObj& args, void* data) {
+ boost::filesystem::create_directories(args.firstElement().String());
+ return BSON( "" << true );
+ }
+
+ 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 );
+ }
+
+ BSONObjBuilder b;
+ b.appendBool( "removed" , found );
+ return b.obj();
+ }
+
+ /**
+ * @param args - [ name, byte index ]
+ * In this initial implementation, all bits in the specified byte are flipped.
+ */
+ BSONObj fuzzFile(const BSONObj& args, void* data) {
+ uassert( 13619, "fuzzFile takes 2 arguments", args.nFields() == 2 );
+ scoped_ptr< File > f( new File() );
+ f->open( args.getStringField( "0" ) );
+ uassert( 13620, "couldn't open file to fuzz", !f->bad() && f->is_open() );
+
+ char c;
+ f->read( args.getIntField( "1" ), &c, 1 );
+ c = ~c;
+ f->write( args.getIntField( "1" ), &c, 1 );
+
+ return undefinedReturn;
+ // f close is implicit
+ }
+
+ 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( "fuzzFile" , fuzzFile );
+ 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
new file mode 100644
index 00000000000..9ce6d1eb600
--- /dev/null
+++ b/src/mongo/shell/shell_utils_extended.h
@@ -0,0 +1,28 @@
+// mongo/shell/shell_utils_extended.h
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+namespace mongo {
+
+ 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
new file mode 100644
index 00000000000..60af4f3a6cb
--- /dev/null
+++ b/src/mongo/shell/shell_utils_launcher.cpp
@@ -0,0 +1,752 @@
+// mongo/shell/shell_utils_launcher.cpp
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/pch.h"
+
+#include "mongo/shell/shell_utils_launcher.h"
+
+#include <boost/thread/thread.hpp>
+#include <iostream>
+#include <map>
+#include <vector>
+
+#ifdef _WIN32
+# 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>
+#endif
+
+#include "mongo/client/clientOnly-private.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/scripting/engine.h"
+#include "mongo/shell/shell_utils.h"
+
+namespace mongo {
+
+ 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); }
+#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 {
+
+ ProgramOutputMultiplexer programOutputLogger;
+
+ bool ProgramRegistry::isPortRegistered( int port ) const {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ return _ports.count( port ) == 1;
+ }
+
+ pid_t ProgramRegistry::pidForPort( int port ) const {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ verify( isPortRegistered( port ) );
+ return _ports.find( port )->second.first;
+ }
+
+ void ProgramRegistry::registerPort( int port, pid_t pid, int output ) {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ verify( !isPortRegistered( port ) );
+ _ports.insert( make_pair( port, make_pair( pid, output ) ) );
+ }
+
+ void ProgramRegistry::deletePort( int port ) {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ if ( !isPortRegistered( port ) ) {
+ return;
+ }
+ close( _ports.find( port )->second.second );
+ _ports.erase( port );
+ }
+
+ void ProgramRegistry::getRegisteredPorts( vector<int> &ports ) {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ for( map<int,pair<pid_t,int> >::const_iterator i = _ports.begin(); i != _ports.end();
+ ++i ) {
+ ports.push_back( i->first );
+ }
+ }
+
+ bool ProgramRegistry::isPidRegistered( pid_t pid ) const {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ return _pids.count( pid ) == 1;
+ }
+
+ void ProgramRegistry::registerPid( pid_t pid, int output ) {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ verify( !isPidRegistered( pid ) );
+ _pids.insert( make_pair( pid, output ) );
+ }
+
+ void ProgramRegistry::deletePid( pid_t pid ) {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ if ( !isPidRegistered( pid ) ) {
+ return;
+ }
+ close( _pids.find( pid )->second );
+ _pids.erase( pid );
+ }
+
+ void ProgramRegistry::getRegisteredPids( vector<pid_t> &pids ) {
+ boost::recursive_mutex::scoped_lock lk( _mutex );
+ for( map<pid_t,int>::const_iterator i = _pids.begin(); i != _pids.end(); ++i ) {
+ pids.push_back( i->first );
+ }
+ }
+
+ ProgramRegistry &registry = *( new ProgramRegistry() );
+
+ void goingAwaySoon() {
+ mongo::mutex::scoped_lock lk( mongoProgramOutputMutex );
+ mongo::dbexitCalled = true;
+ }
+
+ void ProgramOutputMultiplexer::appendLine( int port, int pid, const char *line ) {
+ mongo::mutex::scoped_lock 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;
+ _buffer << buf.str() << endl;
+ }
+
+ string ProgramOutputMultiplexer::str() const {
+ mongo::mutex::scoped_lock 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() {
+ mongo::mutex::scoped_lock 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 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;
+
+#if 0
+ if (isMongosProgram == "mongos") {
+ _argv.push_back("valgrind");
+ _argv.push_back("--log-file=/tmp/mongos-%p.valgrind");
+ _argv.push_back("--leak-check=yes");
+ _argv.push_back("--suppressions=valgrind.suppressions");
+ //_argv.push_back("--error-exitcode=1");
+ _argv.push_back("--");
+ }
+#endif
+
+ _argv.push_back( programPath.native_file_string() );
+
+ _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);
+ }
+
+ 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 ];
+ verify( pipe( pipeEnds ) != -1 );
+
+ fflush( 0 );
+ launchProcess(pipeEnds[1]); //sets _pid
+
+ {
+ stringstream ss;
+ ss << "shell: started program";
+ for (unsigned i=0; i < _argv.size(); i++)
+ ss << " " << _argv[i];
+ log() << ss.str() << endl;
+ }
+
+ 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 ) {
+ strcpy( temp, last );
+ strcpy( buf, temp );
+ }
+ 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
+ p = change_extension(p, ".exe");
+#endif
+
+ if( boost::filesystem::exists(p) ) {
+#ifndef _WIN32
+ 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;
+ }
+ {
+ boost::filesystem::path t = boost::filesystem::initial_path() / p;
+ if( boost::filesystem::exists(t) ) return t;
+ }
+ 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 << '"';
+ }
+ }
+
+ string args = ss.str();
+
+ boost::scoped_array<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);
+
+ _pid = pi.dwProcessId;
+ registry._handles.insert( make_pair( _pid, pi.hProcess ) );
+
+#else
+
+ scoped_array<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;
+
+ scoped_array<const char *> envStorage( new const char* [2] );
+ const char** env = envStorage.get();
+ env[0] = NULL;
+ env[1] = NULL;
+
+ bool isMongos = ( _argv[0].find( "mongos" ) != string::npos );
+
+ _pid = fork();
+ // Async signal unsafe functions should not be called in the child process.
+
+ if ( _pid == -1 ) {
+ verify( _pid != -1 );
+ }
+ else if ( _pid == 0 ) {
+ // DON'T ASSERT IN THIS BLOCK - very bad things will happen
+
+ 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;
+ ::_Exit(-1); //do not pass go, do not call atexit handlers
+ }
+
+ // Heap-check for mongos only. 'argv[0]' must be in the path format.
+ if ( isMongos ) {
+#if defined(HEAP_CHECKING)
+ env[0] = "HEAPCHECK=normal";
+ env[1] = NULL;
+
+ // NOTE execve is async signal safe, but it is not clear that execvpe is async
+ // signal safe.
+ execvpe( argv[ 0 ], const_cast<char**>(argv) , const_cast<char**>(env) );
+#endif // HEAP_CHECKING
+ }
+
+ // 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;
+ ::_Exit(-1);
+ }
+
+#endif
+ }
+
+ //returns true if process exited
+ bool wait_for_pid(pid_t pid, bool block=true, int* exit_code=NULL) {
+#ifdef _WIN32
+ verify(registry._handles.count(pid));
+ HANDLE h = registry._handles[pid];
+
+ if (block)
+ WaitForSingleObject(h, INFINITE);
+
+ DWORD tmp;
+ if(GetExitCodeProcess(h, &tmp)) {
+ if ( tmp == STILL_ACTIVE ) {
+ return false;
+ }
+ CloseHandle(h);
+ registry._handles.erase(pid);
+ if (exit_code)
+ *exit_code = tmp;
+ return true;
+ }
+ else {
+ return false;
+ }
+#else
+ int tmp;
+ bool ret = (pid == waitpid(pid, &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 WaitProgram( const BSONObj& a, void* data ) {
+ int pid = singleArg( a ).numberInt();
+ BSONObj x = BSON( "" << wait_for_pid( pid ) );
+ registry.deletePid( pid );
+ return x;
+ }
+
+ BSONObj StartMongoProgram( const BSONObj &a, void* data ) {
+ _nokillop = true;
+ ProgramRunner r( a );
+ r.start();
+ boost::thread t( r );
+ return BSON( string( "" ) << int( r.pid() ) );
+ }
+
+ BSONObj RunMongoProgram( const BSONObj &a, void* data ) {
+ ProgramRunner r( a );
+ r.start();
+ boost::thread t( r );
+ int exit_code;
+ 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 RunProgram(const BSONObj &a, void* data) {
+ ProgramRunner r( a );
+ r.start();
+ boost::thread t( r );
+ int exit_code;
+ wait_for_pid(r.pid(), true, &exit_code);
+ 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;
+ }
+
+ 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" ) {
+ 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( pid_t 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.
+ }
+ else {
+ DBClientConnection conn;
+ try {
+ 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.
+ }
+ }
+#else
+ int x = kill( pid, sig );
+ if ( x ) {
+ if ( errno == ESRCH ) {
+ }
+ else {
+ log() << "killFailed: " << errnoWithDescription() << endl;
+ verify( x == 0 );
+ }
+ }
+
+#endif
+ }
+
+ int killDb( int port, pid_t _pid, int signal, const BSONObj& opt ) {
+ pid_t 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 );
+
+ int i = 0;
+ for( ; i < 130; ++i ) {
+ if ( i == 60 ) {
+ char now[64];
+ time_t_to_String(time(0), now);
+ now[ 20 ] = 0;
+ log() << now << " 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 ) {
+ char now[64];
+ time_t_to_String(time(0), now);
+ now[ 20 ] = 0;
+ log() << now << " 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
+ }
+
+ return exitCode;
+ }
+
+ int killDb( int port, pid_t _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;
+ }
+
+ BSONObj getStopMongodOpts( const BSONObj &a ) {
+ if ( a.nFields() == 3 ) {
+ BSONObjIterator i( a );
+ i.next();
+ i.next();
+ BSONElement e = i.next();
+
+ if ( e.isABSONObj() ){
+ return e.embeddedObject();
+ }
+ }
+
+ return BSONObj();
+ }
+
+ /** stopMongoProgram(port[, signal]) */
+ BSONObj StopMongoProgram( const BSONObj &a, void* data ) {
+ verify( a.nFields() >= 1 || a.nFields() <= 3 );
+ uassert( 15853 , "stopMongo needs a number" , a.firstElement().isNumber() );
+ int port = int( a.firstElement().number() );
+ int code = killDb( port, 0, getSignal( a ), getStopMongodOpts( a ));
+ log() << "shell: stopped mongo program on port " << port << endl;
+ return BSON( "" << (double)code );
+ }
+
+ BSONObj StopMongoProgramByPid( const BSONObj &a, void* data ) {
+ verify( a.nFields() == 1 || a.nFields() == 2 );
+ uassert( 15852 , "stopMongoByPid needs a number" , a.firstElement().isNumber() );
+ int pid = int( a.firstElement().number() );
+ int code = killDb( 0, pid, getSignal( a ) );
+ log() << "shell: stopped mongo program on pid " << pid << 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, 0, SIGTERM );
+ vector< pid_t > pids;
+ registry.getRegisteredPids( pids );
+ for( vector< pid_t >::iterator i = pids.begin(); i != pids.end(); ++i )
+ killDb( 0, *i, SIGTERM );
+ }
+
+ 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( "stopMongod", StopMongoProgram );
+ scope.injectNative( "stopMongoProgram", StopMongoProgram );
+ scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid );
+ scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput );
+ scope.injectNative( "clearRawMongoProgramOutput", ClearRawMongoProgramOutput );
+ scope.injectNative( "waitProgram" , WaitProgram );
+ scope.injectNative( "resetDbpath", ResetDbpath );
+ scope.injectNative( "copyDbpath", CopyDbpath );
+ }
+ }
+}
diff --git a/src/mongo/shell/shell_utils_launcher.h b/src/mongo/shell/shell_utils_launcher.h
new file mode 100644
index 00000000000..908ca9f0f04
--- /dev/null
+++ b/src/mongo/shell/shell_utils_launcher.h
@@ -0,0 +1,117 @@
+// mongo/shell/shell_utils_launcher.h
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+#include <boost/filesystem/convenience.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <utility>
+
+#include "mongo/bson/bsonobj.h"
+
+#ifdef _WIN32
+typedef int pid_t;
+#endif
+
+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, int 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.
+ */
+ class ProgramRegistry {
+ public:
+
+ bool isPortRegistered( int port ) const;
+ /** @return pid for a registered port. */
+ pid_t pidForPort( int port ) const;
+ /** Register an unregistered port. */
+ void registerPort( int port, pid_t pid, int output );
+ void deletePort( int port );
+ void getRegisteredPorts( std::vector<int> &ports );
+
+ bool isPidRegistered( pid_t pid ) const;
+ /** Register an unregistered pid. */
+ void registerPid( pid_t pid, int output );
+ void deletePid( pid_t pid );
+ void getRegisteredPids( vector<pid_t> &pids );
+
+ private:
+ std::map<int,std::pair<pid_t,int> > _ports;
+ std::map<pid_t,int> _pids;
+ mutable boost::recursive_mutex _mutex;
+
+#ifdef _WIN32
+ public:
+ std::map<pid_t,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()();
+ pid_t pid() const { return _pid; }
+ int port() const { return _port; }
+
+ private:
+ boost::filesystem::path findProgram( const string &prog );
+ void launchProcess( int child_stdout );
+
+ std::vector<std::string> _argv;
+ int _port;
+ int _pipe;
+ pid_t _pid;
+ };
+ }
+}
diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js
new file mode 100644
index 00000000000..4497400ee72
--- /dev/null
+++ b/src/mongo/shell/utils.js
@@ -0,0 +1,1940 @@
+__quiet = false;
+__magicNoPrint = { __magicNoPrint : 1111 }
+__callLastError = false;
+_verboseShell = false;
+
+chatty = function(s){
+ if ( ! __quiet )
+ print( s );
+}
+
+friendlyEqual = function( a , b ){
+ if ( a == b )
+ return true;
+
+ a = tojson(a,false,true);
+ b = tojson(b,false,true);
+
+ if ( a == b )
+ return true;
+
+ var clean = function( s ){
+ s = s.replace( /NumberInt\((\-?\d+)\)/g , "$1" );
+ return s;
+ }
+
+ a = clean(a);
+ b = clean(b);
+
+ if ( a == b )
+ return true;
+
+ return false;
+}
+
+printStackTrace = function(){
+ try{
+ throw new Error("Printing Stack Trace");
+ } catch (e) {
+ print(e.stack);
+ }
+}
+
+/**
+ * <p> Set the shell verbosity. If verbose the shell will display more information about command results. </>
+ * <p> Default is off. <p>
+ * @param {Bool} verbosity on / off
+ */
+setVerboseShell = function( value ) {
+ if( value == undefined ) value = true;
+ _verboseShell = value;
+}
+
+doassert = function (msg) {
+ if (msg.indexOf("assert") == 0)
+ print(msg);
+ else
+ print("assert: " + msg);
+ printStackTrace();
+ throw msg;
+}
+
+assert = function( b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+ if ( b )
+ return;
+ doassert( msg == undefined ? "assert failed" : "assert failed : " + msg );
+}
+
+// the mongo code uses verify
+// so this is to be nice to mongo devs
+verify = assert;
+
+assert.automsg = function( b ) {
+ assert( eval( b ), b );
+}
+
+assert._debug = false;
+
+assert.eq = function( a , b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( a == b )
+ return;
+
+ if ( ( a != null && b != null ) && friendlyEqual( a , b ) )
+ return;
+
+ doassert( "[" + tojson( a ) + "] != [" + tojson( b ) + "] are not equal : " + msg );
+}
+
+assert.eq.automsg = function( a, b ) {
+ assert.eq( eval( a ), eval( b ), "[" + a + "] != [" + b + "]" );
+}
+
+assert.neq = function( a , b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+ if ( a != b )
+ return;
+
+ doassert( "[" + a + "] != [" + b + "] are equal : " + msg );
+}
+
+assert.contains = function( o, arr, msg ){
+ var wasIn = false
+
+ if( ! arr.length ){
+ for( var i in arr ){
+ wasIn = arr[i] == o || ( ( arr[i] != null && o != null ) && friendlyEqual( arr[i] , o ) )
+ return;
+ if( wasIn ) break
+ }
+ }
+ else {
+ for( var i = 0; i < arr.length; i++ ){
+ wasIn = arr[i] == o || ( ( arr[i] != null && o != null ) && friendlyEqual( arr[i] , o ) )
+ if( wasIn ) break
+ }
+ }
+
+ if( ! wasIn ) doassert( tojson( o ) + " was not in " + tojson( arr ) + " : " + msg )
+}
+
+assert.repeat = function( f, msg, timeout, interval ) {
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ var start = new Date();
+ timeout = timeout || 30000;
+ interval = interval || 200;
+ var last;
+ while( 1 ) {
+
+ if ( typeof( f ) == "string" ){
+ if ( eval( f ) )
+ return;
+ }
+ else {
+ if ( f() )
+ return;
+ }
+
+ if ( ( new Date() ).getTime() - start.getTime() > timeout )
+ break;
+ sleep( interval );
+ }
+}
+
+assert.soon = function( f, msg, timeout /*ms*/, interval ) {
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ var start = new Date();
+ timeout = timeout || 30000;
+ interval = interval || 200;
+ var last;
+ while( 1 ) {
+
+ if ( typeof( f ) == "string" ){
+ if ( eval( f ) )
+ return;
+ }
+ else {
+ if ( f() )
+ return;
+ }
+
+ diff = ( new Date() ).getTime() - start.getTime();
+ if ( diff > timeout )
+ doassert( "assert.soon failed: " + f + ", msg:" + msg );
+ sleep( interval );
+ }
+}
+
+assert.time = function( f, msg, timeout /*ms*/ ) {
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ var start = new Date();
+ timeout = timeout || 30000;
+
+ if ( typeof( f ) == "string" ){
+ res = eval( f );
+ }
+ else {
+ res = f();
+ }
+
+ diff = ( new Date() ).getTime() - start.getTime();
+ if ( diff > timeout )
+ doassert( "assert.time failed timeout " + timeout + "ms took " + diff + "ms : " + f + ", msg:" + msg );
+ return res;
+}
+
+assert.throws = function( func , params , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( params && typeof( params ) == "string" )
+ throw "2nd argument to assert.throws has to be an array"
+
+ try {
+ func.apply( null , params );
+ }
+ catch ( e ){
+ return e;
+ }
+
+ doassert( "did not throw exception: " + msg );
+}
+
+assert.throws.automsg = function( func, params ) {
+ assert.throws( func, params, func.toString() );
+}
+
+assert.commandWorked = function( res , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( res.ok == 1 )
+ return;
+
+ doassert( "command failed: " + tojson( res ) + " : " + msg );
+}
+
+assert.commandFailed = function( res , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( res.ok == 0 )
+ return;
+
+ doassert( "command worked when it should have failed: " + tojson( res ) + " : " + msg );
+}
+
+assert.isnull = function( what , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( what == null )
+ return;
+
+ doassert( "supposed to be null (" + ( msg || "" ) + ") was: " + tojson( what ) );
+}
+
+assert.lt = function( a , b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( a < b )
+ return;
+ doassert( a + " is not less than " + b + " : " + msg );
+}
+
+assert.gt = function( a , b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( a > b )
+ return;
+ doassert( a + " is not greater than " + b + " : " + msg );
+}
+
+assert.lte = function( a , b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( a <= b )
+ return;
+ doassert( a + " is not less than or eq " + b + " : " + msg );
+}
+
+assert.gte = function( a , b , msg ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if ( a >= b )
+ return;
+ doassert( a + " is not greater than or eq " + b + " : " + msg );
+}
+
+assert.between = function( a, b, c, msg, inclusive ){
+ if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+ if( ( inclusive == undefined || inclusive == true ) &&
+ a <= b && b <= c ) return;
+ else if( a < b && b < c ) return;
+
+ doassert( b + " is not between " + a + " and " + c + " : " + msg );
+}
+
+assert.betweenIn = function( a, b, c, msg ){ assert.between( a, b, c, msg, true ) }
+assert.betweenEx = function( a, b, c, msg ){ assert.between( a, b, c, msg, false ) }
+
+assert.close = function( a , b , msg , places ){
+ if (places === undefined) {
+ places = 4;
+ }
+ if (Math.round((a - b) * Math.pow(10, places)) === 0) {
+ return;
+ }
+ doassert( a + " is not equal to " + b + " within " + places +
+ " places, diff: " + (a-b) + " : " + msg );
+};
+
+Object.extend = function( dst , src , deep ){
+ for ( var k in src ){
+ var v = src[k];
+ if ( deep && typeof(v) == "object" ){
+ if ( "floatApprox" in v ) { // convert NumberLong properly
+ eval( "v = " + tojson( v ) );
+ } else {
+ v = Object.extend( typeof ( v.length ) == "number" ? [] : {} , v , true );
+ }
+ }
+ dst[k] = v;
+ }
+ return dst;
+}
+
+Object.merge = function( dst, src, deep ){
+ var clone = Object.extend( {}, dst, deep )
+ return Object.extend( clone, src, deep )
+}
+
+argumentsToArray = function( a ){
+ var arr = [];
+ for ( var i=0; i<a.length; i++ )
+ arr[i] = a[i];
+ return arr;
+}
+
+isString = function( x ){
+ return typeof( x ) == "string";
+}
+
+isNumber = function(x){
+ return typeof( x ) == "number";
+}
+
+isObject = function( x ){
+ return typeof( x ) == "object";
+}
+
+String.prototype.trim = function() {
+ return this.replace(/^\s+|\s+$/g,"");
+}
+String.prototype.ltrim = function() {
+ return this.replace(/^\s+/,"");
+}
+String.prototype.rtrim = function() {
+ return this.replace(/\s+$/,"");
+}
+
+String.prototype.startsWith = function (str){
+ return this.indexOf(str) == 0
+}
+
+String.prototype.endsWith = function (str){
+ return new RegExp( RegExp.escape(str) + "$" ).test( this )
+}
+
+Number.prototype.zeroPad = function(width) {
+ var str = this + '';
+ while (str.length < width)
+ str = '0' + str;
+ return str;
+}
+
+Date.timeFunc = function( theFunc , numTimes ){
+
+ var start = new Date();
+
+ numTimes = numTimes || 1;
+ for ( var i=0; i<numTimes; i++ ){
+ theFunc.apply( null , argumentsToArray( arguments ).slice( 2 ) );
+ }
+
+ return (new Date()).getTime() - start.getTime();
+}
+
+Date.prototype.tojson = function(){
+
+ var UTC = Date.printAsUTC ? 'UTC' : '';
+
+ var year = this['get'+UTC+'FullYear']().zeroPad(4);
+ var month = (this['get'+UTC+'Month']() + 1).zeroPad(2);
+ var date = this['get'+UTC+'Date']().zeroPad(2);
+ var hour = this['get'+UTC+'Hours']().zeroPad(2);
+ var minute = this['get'+UTC+'Minutes']().zeroPad(2);
+ var sec = this['get'+UTC+'Seconds']().zeroPad(2)
+
+ if (this['get'+UTC+'Milliseconds']())
+ sec += '.' + this['get'+UTC+'Milliseconds']().zeroPad(3)
+
+ var ofs = 'Z';
+ if (!Date.printAsUTC){
+ var ofsmin = this.getTimezoneOffset();
+ if (ofsmin != 0){
+ ofs = ofsmin > 0 ? '-' : '+'; // This is correct
+ ofs += (ofsmin/60).zeroPad(2)
+ ofs += (ofsmin%60).zeroPad(2)
+ }
+ }
+
+ return 'ISODate("'+year+'-'+month+'-'+date+'T'+hour+':'+minute+':'+sec+ofs+'")';
+}
+
+Date.printAsUTC = true;
+
+
+ISODate = function(isoDateStr){
+ if (!isoDateStr)
+ return new Date();
+
+ var isoDateRegex = /(\d{4})-?(\d{2})-?(\d{2})([T ](\d{2})(:?(\d{2})(:?(\d{2}(\.\d+)?))?)?(Z|([+-])(\d{2}):?(\d{2})?)?)?/;
+ var res = isoDateRegex.exec(isoDateStr);
+
+ if (!res)
+ throw "invalid ISO date";
+
+ var year = parseInt(res[1],10) || 1970; // this should always be present
+ var month = (parseInt(res[2],10) || 1) - 1;
+ var date = parseInt(res[3],10) || 0;
+ var hour = parseInt(res[5],10) || 0;
+ var min = parseInt(res[7],10) || 0;
+ var sec = parseFloat(res[9]) || 0;
+ var ms = Math.round((sec%1) * 1000)
+ sec -= ms/1000
+
+ var time = Date.UTC(year, month, date, hour, min, sec, ms);
+
+ if (res[11] && res[11] != 'Z'){
+ var ofs = 0;
+ ofs += (parseInt(res[13],10) || 0) * 60*60*1000; // hours
+ ofs += (parseInt(res[14],10) || 0) * 60*1000; // mins
+ if (res[12] == '+') // if ahead subtract
+ ofs *= -1;
+
+ time += ofs
+ }
+
+ return new Date(time);
+}
+
+RegExp.escape = function( text ){
+ return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
+
+RegExp.prototype.tojson = RegExp.prototype.toString;
+
+Array.contains = function( a , x ){
+ for ( var i=0; i<a.length; i++ ){
+ if ( a[i] == x )
+ return true;
+ }
+ return false;
+}
+
+Array.unique = function( a ){
+ var u = [];
+ for ( var i=0; i<a.length; i++){
+ var o = a[i];
+ if ( ! Array.contains( u , o ) ){
+ u.push( o );
+ }
+ }
+ return u;
+}
+
+Array.shuffle = function( arr ){
+ for ( var i=0; i<arr.length-1; i++ ){
+ var pos = i+Random.randInt(arr.length-i);
+ var save = arr[i];
+ arr[i] = arr[pos];
+ arr[pos] = save;
+ }
+ return arr;
+}
+
+
+Array.tojson = function( a , indent , nolint ){
+ var lineEnding = nolint ? " " : "\n";
+
+ if (!indent)
+ indent = "";
+
+ if ( nolint )
+ indent = "";
+
+ if (a.length == 0) {
+ return "[ ]";
+ }
+
+ var s = "[" + lineEnding;
+ indent += "\t";
+ for ( var i=0; i<a.length; i++){
+ s += indent + tojson( a[i], indent , nolint );
+ if ( i < a.length - 1 ){
+ s += "," + lineEnding;
+ }
+ }
+ if ( a.length == 0 ) {
+ s += indent;
+ }
+
+ indent = indent.substring(1);
+ s += lineEnding+indent+"]";
+ return s;
+}
+
+Array.fetchRefs = function( arr , coll ){
+ var n = [];
+ for ( var i=0; i<arr.length; i ++){
+ var z = arr[i];
+ if ( coll && coll != z.getCollection() )
+ continue;
+ n.push( z.fetch() );
+ }
+
+ return n;
+}
+
+Array.sum = function( arr ){
+ if ( arr.length == 0 )
+ return null;
+ var s = arr[0];
+ for ( var i=1; i<arr.length; i++ )
+ s += arr[i];
+ return s;
+}
+
+Array.avg = function( arr ){
+ if ( arr.length == 0 )
+ return null;
+ return Array.sum( arr ) / arr.length;
+}
+
+Array.stdDev = function( arr ){
+ var avg = Array.avg( arr );
+ var sum = 0;
+
+ for ( var i=0; i<arr.length; i++ ){
+ sum += Math.pow( arr[i] - avg , 2 );
+ }
+
+ return Math.sqrt( sum / arr.length );
+}
+
+if( typeof Array.isArray != "function" ){
+ Array.isArray = function( arr ){
+ return arr != undefined && arr.constructor == Array
+ }
+}
+
+//these two are helpers for Array.sort(func)
+compare = function(l, r){ return (l == r ? 0 : (l < r ? -1 : 1)); }
+
+// arr.sort(compareOn('name'))
+compareOn = function(field){
+ return function(l, r) { return compare(l[field], r[field]); }
+}
+
+Object.keySet = function( o ) {
+ var ret = new Array();
+ for( var i in o ) {
+ if ( !( i in o.__proto__ && o[ i ] === o.__proto__[ i ] ) ) {
+ ret.push( i );
+ }
+ }
+ return ret;
+}
+
+if ( ! NumberLong.prototype ) {
+ NumberLong.prototype = {}
+}
+
+NumberLong.prototype.tojson = function() {
+ return this.toString();
+}
+
+if ( ! NumberInt.prototype ) {
+ NumberInt.prototype = {}
+}
+
+NumberInt.prototype.tojson = function() {
+ return this.toString();
+}
+
+if ( ! ObjectId.prototype )
+ ObjectId.prototype = {}
+
+ObjectId.prototype.toString = function(){
+ return "ObjectId(" + tojson(this.str) + ")";
+}
+
+ObjectId.prototype.tojson = function(){
+ return this.toString();
+}
+
+ObjectId.prototype.valueOf = function(){
+ return this.str;
+}
+
+ObjectId.prototype.isObjectId = true;
+
+ObjectId.prototype.getTimestamp = function(){
+ return new Date(parseInt(this.valueOf().slice(0,8), 16)*1000);
+}
+
+ObjectId.prototype.equals = function( other){
+ return this.str == other.str;
+}
+
+if ( typeof( DBPointer ) != "undefined" ){
+ DBPointer.prototype.fetch = function(){
+ assert( this.ns , "need a ns" );
+ assert( this.id , "need an id" );
+
+ return db[ this.ns ].findOne( { _id : this.id } );
+ }
+
+ DBPointer.prototype.tojson = function(indent){
+ return this.toString();
+ }
+
+ DBPointer.prototype.getCollection = function(){
+ return this.ns;
+ }
+
+ DBPointer.prototype.getId = function(){
+ return this.id;
+ }
+
+ DBPointer.prototype.toString = function(){
+ return "DBPointer(" + tojson(this.ns) + ", " + tojson(this.id) + ")";
+ }
+}
+else {
+ print( "warning: no DBPointer" );
+}
+
+if ( typeof( DBRef ) != "undefined" ){
+ DBRef.prototype.fetch = function(){
+ assert( this.$ref , "need a ns" );
+ assert( this.$id , "need an id" );
+
+ return db[ this.$ref ].findOne( { _id : this.$id } );
+ }
+
+ DBRef.prototype.tojson = function(indent){
+ return this.toString();
+ }
+
+ DBRef.prototype.getCollection = function(){
+ return this.$ref;
+ }
+
+ DBRef.prototype.getRef = function(){
+ return this.$ref;
+ }
+
+ DBRef.prototype.getId = function(){
+ return this.$id;
+ }
+
+ DBRef.prototype.toString = function(){
+ return "DBRef(" + tojson(this.$ref) + ", " + tojson(this.$id) + ")";
+ }
+}
+else {
+ print( "warning: no DBRef" );
+}
+
+if ( typeof( Timestamp ) != "undefined" ){
+ Timestamp.prototype.tojson = function () {
+ return this.toString();
+ }
+
+ Timestamp.prototype.getTime = function () {
+ return this.t;
+ }
+
+ Timestamp.prototype.getInc = function () {
+ return this.i;
+ }
+
+ Timestamp.prototype.toString = function () {
+ return "Timestamp(" + this.t + ", " + this.i + ")";
+ }
+}
+else {
+ print( "warning: no Timestamp class" );
+}
+
+if ( typeof( BinData ) != "undefined" ){
+ BinData.prototype.tojson = function () {
+ return this.toString();
+ }
+
+ BinData.prototype.subtype = function () {
+ return this.type;
+ }
+
+ BinData.prototype.length = function () {
+ return this.len;
+ }
+}
+else {
+ print( "warning: no BinData class" );
+}
+
+if ( typeof _threadInject != "undefined" ){
+ //print( "fork() available!" );
+
+ Thread = function(){
+ this.init.apply( this, arguments );
+ }
+ _threadInject( Thread.prototype );
+
+ ScopedThread = function() {
+ this.init.apply( this, arguments );
+ }
+ ScopedThread.prototype = new Thread( function() {} );
+ _scopedThreadInject( ScopedThread.prototype );
+
+ fork = function() {
+ var t = new Thread( function() {} );
+ Thread.apply( t, arguments );
+ return t;
+ }
+
+ // Helper class to generate a list of events which may be executed by a ParallelTester
+ EventGenerator = function( me, collectionName, mean, host ) {
+ this.mean = mean;
+ if (host == undefined) host = db.getMongo().host;
+ this.events = new Array( me, collectionName, host );
+ }
+
+ EventGenerator.prototype._add = function( action ) {
+ this.events.push( [ Random.genExp( this.mean ), action ] );
+ }
+
+ EventGenerator.prototype.addInsert = function( obj ) {
+ this._add( "t.insert( " + tojson( obj ) + " )" );
+ }
+
+ EventGenerator.prototype.addRemove = function( obj ) {
+ this._add( "t.remove( " + tojson( obj ) + " )" );
+ }
+
+ EventGenerator.prototype.addUpdate = function( objOld, objNew ) {
+ this._add( "t.update( " + tojson( objOld ) + ", " + tojson( objNew ) + " )" );
+ }
+
+ EventGenerator.prototype.addCheckCount = function( count, query, shouldPrint, checkQuery ) {
+ query = query || {};
+ shouldPrint = shouldPrint || false;
+ checkQuery = checkQuery || false;
+ var action = "assert.eq( " + count + ", t.count( " + tojson( query ) + " ) );"
+ if ( checkQuery ) {
+ action += " assert.eq( " + count + ", t.find( " + tojson( query ) + " ).toArray().length );"
+ }
+ if ( shouldPrint ) {
+ action += " print( me + ' ' + " + count + " );";
+ }
+ this._add( action );
+ }
+
+ EventGenerator.prototype.getEvents = function() {
+ return this.events;
+ }
+
+ EventGenerator.dispatch = function() {
+ var args = argumentsToArray( arguments );
+ var me = args.shift();
+ var collectionName = args.shift();
+ var host = args.shift();
+ var m = new Mongo( host );
+ var t = m.getDB( "test" )[ collectionName ];
+ for( var i in args ) {
+ sleep( args[ i ][ 0 ] );
+ eval( args[ i ][ 1 ] );
+ }
+ }
+
+ // Helper class for running tests in parallel. It assembles a set of tests
+ // and then calls assert.parallelests to run them.
+ ParallelTester = function() {
+ this.params = new Array();
+ }
+
+ ParallelTester.prototype.add = function( fun, args ) {
+ args = args || [];
+ args.unshift( fun );
+ this.params.push( args );
+ }
+
+ ParallelTester.prototype.run = function( msg, newScopes ) {
+ newScopes = newScopes || false;
+ assert.parallelTests( this.params, msg, newScopes );
+ }
+
+ // creates lists of tests from jstests dir in a format suitable for use by
+ // ParallelTester.fileTester. The lists will be in random order.
+ // n: number of lists to split these tests into
+ ParallelTester.createJstestsLists = function( n ) {
+ var params = new Array();
+ for( var i = 0; i < n; ++i ) {
+ params.push( [] );
+ }
+
+ var makeKeys = function( a ) {
+ var ret = {};
+ for( var i in a ) {
+ ret[ a[ i ] ] = 1;
+ }
+ return ret;
+ }
+
+ // some tests can't run in parallel with most others
+ var skipTests = makeKeys( [ "jstests/dbadmin.js",
+ "jstests/repair.js",
+ "jstests/cursor8.js",
+ "jstests/recstore.js",
+ "jstests/extent.js",
+ "jstests/indexb.js",
+ "jstests/profile1.js",
+ "jstests/mr3.js",
+ "jstests/indexh.js",
+ "jstests/apitest_db.js",
+ "jstests/evalb.js",
+ "jstests/evald.js",
+ "jstests/evalf.js",
+ "jstests/killop.js",
+ "jstests/run_program1.js",
+ "jstests/notablescan.js",
+ "jstests/drop2.js",
+ "jstests/dropdb_race.js",
+ "jstests/fsync2.js", // May be placed in serialTestsArr once SERVER-4243 is fixed.
+ "jstests/bench_test1.js",
+ "jstests/padding.js",
+ "jstests/queryoptimizera.js",
+ "jstests/loglong.js" // log might overflow before
+ // this has a chance to see the message
+ ] );
+
+ // some tests can't be run in parallel with each other
+ var serialTestsArr = [ "jstests/fsync.js"
+// ,"jstests/fsync2.js" // SERVER-4243
+ ];
+ var serialTests = makeKeys( serialTestsArr );
+
+ params[ 0 ] = serialTestsArr;
+
+ var files = listFiles("jstests");
+ files = Array.shuffle( files );
+
+ var i = 0;
+ files.forEach(
+ function(x) {
+
+ if ( ( /[\/\\]_/.test(x.name) ) ||
+ ( ! /\.js$/.test(x.name ) ) ||
+ ( x.name in skipTests ) ||
+ ( x.name in serialTests ) ||
+ ! /\.js$/.test(x.name ) ){
+ print(" >>>>>>>>>>>>>>> skipping " + x.name);
+ return;
+ }
+
+ params[ i % n ].push( x.name );
+ ++i;
+ }
+ );
+
+ // randomize ordering of the serialTests
+ params[ 0 ] = Array.shuffle( params[ 0 ] );
+
+ for( var i in params ) {
+ params[ i ].unshift( i );
+ }
+
+ return params;
+ }
+
+ // runs a set of test files
+ // first argument is an identifier for this tester, remaining arguments are file names
+ ParallelTester.fileTester = function() {
+ var args = argumentsToArray( arguments );
+ var suite = args.shift();
+ args.forEach(
+ function( x ) {
+ print(" S" + suite + " Test : " + x + " ...");
+ var time = Date.timeFunc( function() { load(x); }, 1);
+ print(" S" + suite + " Test : " + x + " " + time + "ms" );
+ }
+ );
+ }
+
+ // params: array of arrays, each element of which consists of a function followed
+ // by zero or more arguments to that function. Each function and its arguments will
+ // be called in a separate thread.
+ // msg: failure message
+ // newScopes: if true, each thread starts in a fresh scope
+ assert.parallelTests = function( params, msg, newScopes ) {
+ newScopes = newScopes || false;
+ var wrapper = function( fun, argv ) {
+ eval (
+ "var z = function() {" +
+ "var __parallelTests__fun = " + fun.toString() + ";" +
+ "var __parallelTests__argv = " + tojson( argv ) + ";" +
+ "var __parallelTests__passed = false;" +
+ "try {" +
+ "__parallelTests__fun.apply( 0, __parallelTests__argv );" +
+ "__parallelTests__passed = true;" +
+ "} catch ( e ) {" +
+ "print( '********** Parallel Test FAILED: ' + tojson(e) );" +
+ "}" +
+ "return __parallelTests__passed;" +
+ "}"
+ );
+ return z;
+ }
+ var runners = new Array();
+ for( var i in params ) {
+ var param = params[ i ];
+ var test = param.shift();
+ var t;
+ if ( newScopes )
+ t = new ScopedThread( wrapper( test, param ) );
+ else
+ t = new Thread( wrapper( test, param ) );
+ runners.push( t );
+ }
+
+ runners.forEach( function( x ) { x.start(); } );
+ var nFailed = 0;
+ // v8 doesn't like it if we exit before all threads are joined (SERVER-529)
+ runners.forEach( function( x ) { if( !x.returnData() ) { ++nFailed; } } );
+ assert.eq( 0, nFailed, msg );
+ }
+}
+
+tojsononeline = function( x ){
+ return tojson( x , " " , true );
+}
+
+tojson = function( x, indent , nolint ){
+ if ( x === null )
+ return "null";
+
+ if ( x === undefined )
+ return "undefined";
+
+ if (!indent)
+ indent = "";
+
+ switch ( typeof x ) {
+ case "string": {
+ var s = "\"";
+ for ( var i=0; i<x.length; i++ ){
+ switch (x[i]){
+ case '"': s += '\\"'; break;
+ case '\\': s += '\\\\'; break;
+ case '\b': s += '\\b'; break;
+ case '\f': s += '\\f'; break;
+ case '\n': s += '\\n'; break;
+ case '\r': s += '\\r'; break;
+ case '\t': s += '\\t'; break;
+
+ default: {
+ var code = x.charCodeAt(i);
+ if (code < 0x20){
+ s += (code < 0x10 ? '\\u000' : '\\u00') + code.toString(16);
+ } else {
+ s += x[i];
+ }
+ }
+ }
+ }
+ return s + "\"";
+ }
+ case "number":
+ case "boolean":
+ return "" + x;
+ case "object":{
+ var s = tojsonObject( x, indent , nolint );
+ if ( ( nolint == null || nolint == true ) && s.length < 80 && ( indent == null || indent.length == 0 ) ){
+ s = s.replace( /[\s\r\n ]+/gm , " " );
+ }
+ return s;
+ }
+ case "function":
+ return x.toString();
+ default:
+ throw "tojson can't handle type " + ( typeof x );
+ }
+
+}
+
+tojsonObject = function( x, indent , nolint ){
+ var lineEnding = nolint ? " " : "\n";
+ var tabSpace = nolint ? "" : "\t";
+
+ assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );
+
+ if (!indent)
+ indent = "";
+
+ if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
+ return x.tojson(indent,nolint);
+ }
+
+ if ( x.constructor && typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
+ return x.constructor.tojson( x, indent , nolint );
+ }
+
+ if ( x.toString() == "[object MaxKey]" )
+ return "{ $maxKey : 1 }";
+ if ( x.toString() == "[object MinKey]" )
+ return "{ $minKey : 1 }";
+
+ var s = "{" + lineEnding;
+
+ // push one level of indent
+ indent += tabSpace;
+
+ var total = 0;
+ for ( var k in x ) total++;
+ if ( total == 0 ) {
+ s += indent + lineEnding;
+ }
+
+ var keys = x;
+ if ( typeof( x._simpleKeys ) == "function" )
+ keys = x._simpleKeys();
+ var num = 1;
+ for ( var k in keys ){
+
+ var val = x[k];
+ if ( val == DB.prototype || val == DBCollection.prototype )
+ continue;
+
+ s += indent + "\"" + k + "\" : " + tojson( val, indent , nolint );
+ if (num != total) {
+ s += ",";
+ num++;
+ }
+ s += lineEnding;
+ }
+
+ // pop one level of indent
+ indent = indent.substring(1);
+ return s + indent + "}";
+}
+
+shellPrint = function( x ){
+ it = x;
+ if ( x != undefined )
+ shellPrintHelper( x );
+
+ if ( db ){
+ var e = db.getPrevError();
+ if ( e.err ) {
+ if ( e.nPrev <= 1 )
+ print( "error on last call: " + tojson( e.err ) );
+ else
+ print( "an error " + tojson( e.err ) + " occurred " + e.nPrev + " operations back in the command invocation" );
+ }
+ db.resetError();
+ }
+}
+
+printjson = function(x){
+ print( tojson( x ) );
+}
+
+printjsononeline = function(x){
+ print( tojsononeline( x ) );
+}
+
+if ( typeof TestData == "undefined" ){
+ TestData = undefined
+}
+
+jsTestName = function(){
+ if( TestData ) return TestData.testName
+ return "__unknown_name__"
+}
+
+jsTestFile = function(){
+ if( TestData ) return TestData.testFile
+ return "__unknown_file__"
+}
+
+jsTestPath = function(){
+ if( TestData ) return TestData.testPath
+ return "__unknown_path__"
+}
+
+jsTestOptions = function(){
+ if( TestData ) return { noJournal : TestData.noJournal,
+ noJournalPrealloc : TestData.noJournalPrealloc,
+ auth : TestData.auth,
+ keyFile : TestData.keyFile,
+ authUser : "__system",
+ authPassword : TestData.keyFileData,
+ adminUser : "admin",
+ adminPassword : "password" }
+ return {}
+}
+
+jsTestLog = function(msg){
+ print( "\n\n----\n" + msg + "\n----\n\n" )
+}
+
+jsTest = {}
+
+jsTest.name = jsTestName
+jsTest.file = jsTestFile
+jsTest.path = jsTestPath
+jsTest.options = jsTestOptions
+jsTest.log = jsTestLog
+
+jsTest.dir = function(){
+ return jsTest.path().replace( /\/[^\/]+$/, "/" )
+}
+
+jsTest.randomize = function( seed ) {
+ if( seed == undefined ) seed = new Date().getTime()
+ Random.srand( seed )
+ print( "Random seed for test : " + seed )
+}
+
+/**
+* Adds a user to the admin DB on the given connection. This is only used for running the test suite
+* with authentication enabled.
+*/
+jsTest.addAuth = function(conn) {
+ // Get a connection over localhost so that the first user can be added.
+ var localconn = conn;
+ if ( localconn.host.indexOf('localhost') != 0 ) {
+ print( 'Getting locahost connection instead of ' + conn + ' to add first admin user' );
+ var hosts = conn.host.split(',');
+ for ( var i = 0; i < hosts.length; i++ ) {
+ hosts[i] = 'localhost:' + hosts[i].split(':')[1];
+ }
+ localconn = new Mongo(hosts.join(','));
+ }
+ print ("Adding admin user on connection: " + localconn);
+ return localconn.getDB('admin').addUser(jsTestOptions().adminUser, jsTestOptions().adminPassword,
+ false, 'majority', 60000);
+}
+
+jsTest.authenticate = function(conn) {
+ // Set authenticated to stop an infinite recursion from getDB calling back into authenticate
+ conn.authenticated = true;
+ if (jsTest.options().auth || jsTest.options().keyFile) {
+ print ("Authenticating to admin user on connection: " + conn);
+ conn.authenticated = conn.getDB('admin').auth(jsTestOptions().adminUser,
+ jsTestOptions().adminPassword);
+ return conn.authenticated;
+ }
+}
+
+jsTest.authenticateNodes = function(nodes) {
+ jsTest.attempt({timeout:30000, desc: "Authenticate to nodes: " + nodes}, function() {
+ for (var i = 0; i < nodes.length; i++) {
+ // Don't try to authenticate to arbiters
+ res = nodes[i].getDB("admin").runCommand({replSetGetStatus: 1});
+ if(res.myState == 7) {
+ continue;
+ }
+ if(jsTest.authenticate(nodes[i]) != 1) {
+ return false;
+ }
+ }
+ return true;
+ });
+}
+
+jsTest.isMongos = function(conn) {
+ return conn.getDB('admin').isMaster().msg=='isdbgrid';
+}
+
+// Pass this method a function to call repeatedly until
+// that function returns true. Example:
+// attempt({timeout: 20000, desc: "get master"}, function() { // return false until success })
+jsTest.attempt = function( opts, func ) {
+ var timeout = opts.timeout || 1000;
+ var tries = 0;
+ var sleepTime = 2000;
+ var result = null;
+ var context = opts.context || this;
+
+ while((result = func.apply(context)) == false) {
+ tries += 1;
+ sleep(sleepTime);
+ if( tries * sleepTime > timeout) {
+ throw('[' + opts['desc'] + ']' + " timed out after " + timeout + "ms ( " + tries + " tries )");
+ }
+ }
+
+ return result;
+}
+
+replSetMemberStatePrompt = function() {
+ var state = '';
+ var stateInfo = db.getSiblingDB( 'admin' ).runCommand( { replSetGetStatus:1, forShell:1 } );
+ if ( stateInfo.ok ) {
+ // Report the self member's stateStr if it's present.
+ stateInfo.members.forEach( function( member ) {
+ if ( member.self ) {
+ state = member.stateStr;
+ }
+ } );
+ // Otherwise fall back to reporting the numeric myState field (mongodb 1.6).
+ if ( !state ) {
+ state = stateInfo.myState;
+ }
+ state = '' + stateInfo.set + ':' + state;
+ }
+ else {
+ var info = stateInfo.info;
+ if ( info && info.length < 20 ) {
+ state = info; // "mongos", "configsvr"
+ }
+ }
+ return state + '> ';
+}
+
+shellPrintHelper = function (x) {
+ if (typeof (x) == "undefined") {
+ // Make sure that we have a db var before we use it
+ // TODO: This implicit calling of GLE can cause subtle, hard to track issues - remove?
+ if (__callLastError && typeof( db ) != "undefined" && db.getMongo ) {
+ __callLastError = false;
+ // explicit w:1 so that replset getLastErrorDefaults aren't used here which would be bad.
+ var err = db.getLastError(1);
+ if (err != null) {
+ print(err);
+ }
+ }
+ return;
+ }
+
+ if (x == __magicNoPrint)
+ return;
+
+ if (x == null) {
+ print("null");
+ return;
+ }
+
+ if (typeof x != "object")
+ return print(x);
+
+ var p = x.shellPrint;
+ if (typeof p == "function")
+ return x.shellPrint();
+
+ var p = x.tojson;
+ if (typeof p == "function")
+ print(x.tojson());
+ else
+ print(tojson(x));
+}
+
+shellAutocomplete = function ( /*prefix*/ ) { // outer scope function called on init. Actual function at end
+
+ var universalMethods = "constructor prototype toString valueOf toLocaleString hasOwnProperty propertyIsEnumerable".split( ' ' );
+
+ var builtinMethods = {}; // uses constructor objects as keys
+ builtinMethods[Array] = "length concat join pop push reverse shift slice sort splice unshift indexOf lastIndexOf every filter forEach map some".split( ' ' );
+ builtinMethods[Boolean] = "".split( ' ' ); // nothing more than universal methods
+ builtinMethods[Date] = "getDate getDay getFullYear getHours getMilliseconds getMinutes getMonth getSeconds getTime getTimezoneOffset getUTCDate getUTCDay getUTCFullYear getUTCHours getUTCMilliseconds getUTCMinutes getUTCMonth getUTCSeconds getYear parse setDate setFullYear setHours setMilliseconds setMinutes setMonth setSeconds setTime setUTCDate setUTCFullYear setUTCHours setUTCMilliseconds setUTCMinutes setUTCMonth setUTCSeconds setYear toDateString toGMTString toLocaleDateString toLocaleTimeString toTimeString toUTCString UTC".split( ' ' );
+ builtinMethods[Math] = "E LN2 LN10 LOG2E LOG10E PI SQRT1_2 SQRT2 abs acos asin atan atan2 ceil cos exp floor log max min pow random round sin sqrt tan".split( ' ' );
+ builtinMethods[Number] = "MAX_VALUE MIN_VALUE NEGATIVE_INFINITY POSITIVE_INFINITY toExponential toFixed toPrecision".split( ' ' );
+ builtinMethods[RegExp] = "global ignoreCase lastIndex multiline source compile exec test".split( ' ' );
+ builtinMethods[String] = "length charAt charCodeAt concat fromCharCode indexOf lastIndexOf match replace search slice split substr substring toLowerCase toUpperCase".split( ' ' );
+ builtinMethods[Function] = "call apply".split( ' ' );
+ builtinMethods[Object] = "bsonsize".split( ' ' );
+
+ builtinMethods[Mongo] = "find update insert remove".split( ' ' );
+ builtinMethods[BinData] = "hex base64 length subtype".split( ' ' );
+
+ var extraGlobals = "Infinity NaN undefined null true false decodeURI decodeURIComponent encodeURI encodeURIComponent escape eval isFinite isNaN parseFloat parseInt unescape Array Boolean Date Math Number RegExp String print load gc MinKey MaxKey Mongo NumberInt NumberLong ObjectId DBPointer UUID BinData HexData MD5 Map".split( ' ' );
+
+ var isPrivate = function( name ) {
+ if ( shellAutocomplete.showPrivate ) return false;
+ if ( name == '_id' ) return false;
+ if ( name[0] == '_' ) return true;
+ if ( name[name.length - 1] == '_' ) return true; // some native functions have an extra name_ method
+ return false;
+ }
+
+ var customComplete = function( obj ) {
+ try {
+ if ( obj.__proto__.constructor.autocomplete ) {
+ var ret = obj.constructor.autocomplete( obj );
+ if ( ret.constructor != Array ) {
+ print( "\nautocompleters must return real Arrays" );
+ return [];
+ }
+ return ret;
+ } else {
+ return [];
+ }
+ } catch ( e ) {
+ // print( e ); // uncomment if debugging custom completers
+ return [];
+ }
+ }
+
+ var worker = function( prefix ) {
+ var global = ( function() { return this; } ).call(); // trick to get global object
+
+ var curObj = global;
+ var parts = prefix.split( '.' );
+ for ( var p = 0; p < parts.length - 1; p++ ) { // doesn't include last part
+ curObj = curObj[parts[p]];
+ if ( curObj == null )
+ return [];
+ }
+
+ var lastPrefix = parts[parts.length - 1] || '';
+ var lastPrefixLowercase = lastPrefix.toLowerCase()
+ var beginning = parts.slice( 0, parts.length - 1 ).join( '.' );
+ if ( beginning.length )
+ beginning += '.';
+
+ var possibilities = new Array().concat(
+ universalMethods,
+ Object.keySet( curObj ),
+ Object.keySet( curObj.__proto__ ),
+ builtinMethods[curObj] || [], // curObj is a builtin constructor
+ builtinMethods[curObj.__proto__.constructor] || [], // curObj is made from a builtin constructor
+ curObj == global ? extraGlobals : [],
+ customComplete( curObj )
+ );
+
+ var noDuplicates = {}; // see http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
+ for ( var i = 0; i < possibilities.length; i++ ) {
+ var p = possibilities[i];
+ if ( typeof ( curObj[p] ) == "undefined" && curObj != global ) continue; // extraGlobals aren't in the global object
+ if ( p.length == 0 || p.length < lastPrefix.length ) continue;
+ if ( lastPrefix[0] != '_' && isPrivate( p ) ) continue;
+ if ( p.match( /^[0-9]+$/ ) ) continue; // don't array number indexes
+ if ( p.substr( 0, lastPrefix.length ).toLowerCase() != lastPrefixLowercase ) continue;
+
+ var completion = beginning + p;
+ if ( curObj[p] && curObj[p].constructor == Function && p != 'constructor' )
+ completion += '(';
+
+ noDuplicates[completion] = 0;
+ }
+
+ var ret = [];
+ for ( var i in noDuplicates )
+ ret.push( i );
+
+ return ret;
+ }
+
+ // this is the actual function that gets assigned to shellAutocomplete
+ return function( prefix ) {
+ try {
+ __autocomplete__ = worker( prefix ).sort();
+ } catch ( e ) {
+ print( "exception during autocomplete: " + tojson( e.message ) );
+ __autocomplete__ = [];
+ }
+ }
+} ();
+
+shellAutocomplete.showPrivate = false; // toggle to show (useful when working on internals)
+
+shellHelper = function( command , rest , shouldPrint ){
+ command = command.trim();
+ var args = rest.trim().replace(/\s*;$/,"").split( "\s+" );
+
+ if ( ! shellHelper[command] )
+ throw "no command [" + command + "]";
+
+ var res = shellHelper[command].apply( null , args );
+ if ( shouldPrint ){
+ shellPrintHelper( res );
+ }
+ return res;
+}
+
+shellHelper.use = function (dbname) {
+ var s = "" + dbname;
+ if (s == "") {
+ print("bad use parameter");
+ return;
+ }
+ db = db.getMongo().getDB(dbname);
+ print("switched to db " + db.getName());
+}
+
+shellHelper.set = function (str) {
+ if (str == "") {
+ print("bad use parameter");
+ return;
+ }
+ tokens = str.split(" ");
+ param = tokens[0];
+ value = tokens[1];
+
+ if ( value == undefined ) value = true;
+ // value comes in as a string..
+ if ( value == "true" ) value = true;
+ if ( value == "false" ) value = false;
+
+ if (param == "verbose") {
+ _verboseShell = value;
+ }
+ print("set " + param + " to " + value);
+}
+
+shellHelper.it = function(){
+ if ( typeof( ___it___ ) == "undefined" || ___it___ == null ){
+ print( "no cursor" );
+ return;
+ }
+ shellPrintHelper( ___it___ );
+}
+
+shellHelper.show = function (what) {
+ assert(typeof what == "string");
+
+ var args = what.split( /\s+/ );
+ what = args[0]
+ args = args.splice(1)
+
+ if (what == "profile") {
+ if (db.system.profile.count() == 0) {
+ print("db.system.profile is empty");
+ print("Use db.setProfilingLevel(2) will enable profiling");
+ print("Use db.system.profile.find() to show raw profile entries");
+ }
+ else {
+ print();
+ db.system.profile.find({ millis: { $gt: 0} }).sort({ $natural: -1 }).limit(5).forEach(
+ function (x) {
+ print("" + x.op + "\t" + x.ns + " " + x.millis + "ms " + String(x.ts).substring(0, 24));
+ var l = "";
+ for ( var z in x ){
+ if ( z == "op" || z == "ns" || z == "millis" || z == "ts" )
+ continue;
+
+ var val = x[z];
+ var mytype = typeof(val);
+
+ if ( mytype == "string" ||
+ mytype == "number" )
+ l += z + ":" + val + " ";
+ else if ( mytype == "object" )
+ l += z + ":" + tojson(val ) + " ";
+ else if ( mytype == "boolean" )
+ l += z + " ";
+ else
+ l += z + ":" + val + " ";
+
+ }
+ print( l );
+ print("\n");
+ }
+ )
+ }
+ return "";
+ }
+
+ if (what == "users") {
+ db.system.users.find().forEach(printjson);
+ return "";
+ }
+
+ if (what == "collections" || what == "tables") {
+ db.getCollectionNames().forEach(function (x) { print(x) });
+ return "";
+ }
+
+ if (what == "dbs") {
+ var dbs = db.getMongo().getDBs();
+ var size = {};
+ dbs.databases.forEach(function (x) { size[x.name] = x.sizeOnDisk; });
+ var names = dbs.databases.map(function (z) { return z.name; }).sort();
+ names.forEach(function (n) {
+ if (size[n] > 1) {
+ print(n + "\t" + size[n] / 1024 / 1024 / 1024 + "GB");
+ } else {
+ print(n + "\t(empty)");
+ }
+ });
+ //db.getMongo().getDBNames().sort().forEach(function (x) { print(x) });
+ return "";
+ }
+
+ if (what == "log" ) {
+ var n = "global";
+ if ( args.length > 0 )
+ n = args[0]
+
+ var res = db.adminCommand( { getLog : n } )
+ for ( var i=0; i<res.log.length; i++){
+ print( res.log[i] )
+ }
+ return ""
+ }
+
+ if (what == "logs" ) {
+ var res = db.adminCommand( { getLog : "*" } )
+ for ( var i=0; i<res.names.length; i++){
+ print( res.names[i] )
+ }
+ return ""
+ }
+
+
+ throw "don't know how to show [" + what + "]";
+
+}
+
+if ( typeof( Map ) == "undefined" ){
+ Map = function(){
+ this._data = {};
+ }
+}
+
+Map.hash = function( val ){
+ if ( ! val )
+ return val;
+
+ switch ( typeof( val ) ){
+ case 'string':
+ case 'number':
+ case 'date':
+ return val.toString();
+ case 'object':
+ case 'array':
+ var s = "";
+ for ( var k in val ){
+ s += k + val[k];
+ }
+ return s;
+ }
+
+ throw "can't hash : " + typeof( val );
+}
+
+Map.prototype.put = function( key , value ){
+ var o = this._get( key );
+ var old = o.value;
+ o.value = value;
+ return old;
+}
+
+Map.prototype.get = function( key ){
+ return this._get( key ).value;
+}
+
+Map.prototype._get = function( key ){
+ var h = Map.hash( key );
+ var a = this._data[h];
+ if ( ! a ){
+ a = [];
+ this._data[h] = a;
+ }
+
+ for ( var i=0; i<a.length; i++ ){
+ if ( friendlyEqual( key , a[i].key ) ){
+ return a[i];
+ }
+ }
+ var o = { key : key , value : null };
+ a.push( o );
+ return o;
+}
+
+Map.prototype.values = function(){
+ var all = [];
+ for ( var k in this._data ){
+ this._data[k].forEach( function(z){ all.push( z.value ); } );
+ }
+ return all;
+}
+
+if ( typeof( gc ) == "undefined" ){
+ gc = function(){
+ print( "warning: using noop gc()" );
+ }
+}
+
+
+Math.sigFig = function( x , N ){
+ if ( ! N ){
+ N = 3;
+ }
+ var p = Math.pow( 10, N - Math.ceil( Math.log( Math.abs(x) ) / Math.log( 10 )) );
+ return Math.round(x*p)/p;
+}
+
+Random = function() {}
+
+// set random seed
+Random.srand = function( s ) { _srand( s ); }
+
+// random number 0 <= r < 1
+Random.rand = function() { return _rand(); }
+
+// random integer 0 <= r < n
+Random.randInt = function( n ) { return Math.floor( Random.rand() * n ); }
+
+Random.setRandomSeed = function( s ) {
+ s = s || new Date().getTime();
+ print( "setting random seed: " + s );
+ Random.srand( s );
+}
+
+// generate a random value from the exponential distribution with the specified mean
+Random.genExp = function( mean ) {
+ return -Math.log( Random.rand() ) * mean;
+}
+
+Geo = {};
+Geo.distance = function( a , b ){
+ var ax = null;
+ var ay = null;
+ var bx = null;
+ var by = null;
+
+ for ( var key in a ){
+ if ( ax == null )
+ ax = a[key];
+ else if ( ay == null )
+ ay = a[key];
+ }
+
+ for ( var key in b ){
+ if ( bx == null )
+ bx = b[key];
+ else if ( by == null )
+ by = b[key];
+ }
+
+ return Math.sqrt( Math.pow( by - ay , 2 ) +
+ Math.pow( bx - ax , 2 ) );
+}
+
+Geo.sphereDistance = function( a , b ){
+ var ax = null;
+ var ay = null;
+ var bx = null;
+ var by = null;
+
+ // TODO swap order of x and y when done on server
+ for ( var key in a ){
+ if ( ax == null )
+ ax = a[key] * (Math.PI/180);
+ else if ( ay == null )
+ ay = a[key] * (Math.PI/180);
+ }
+
+ for ( var key in b ){
+ if ( bx == null )
+ bx = b[key] * (Math.PI/180);
+ else if ( by == null )
+ by = b[key] * (Math.PI/180);
+ }
+
+ var sin_x1=Math.sin(ax), cos_x1=Math.cos(ax);
+ var sin_y1=Math.sin(ay), cos_y1=Math.cos(ay);
+ var sin_x2=Math.sin(bx), cos_x2=Math.cos(bx);
+ var sin_y2=Math.sin(by), cos_y2=Math.cos(by);
+
+ var cross_prod =
+ (cos_y1*cos_x1 * cos_y2*cos_x2) +
+ (cos_y1*sin_x1 * cos_y2*sin_x2) +
+ (sin_y1 * sin_y2);
+
+ if (cross_prod >= 1 || cross_prod <= -1){
+ // fun with floats
+ assert( Math.abs(cross_prod)-1 < 1e-6 );
+ return cross_prod > 0 ? 0 : Math.PI;
+ }
+
+ return Math.acos(cross_prod);
+}
+
+rs = function () { return "try rs.help()"; }
+
+rs.help = function () {
+ print("\trs.status() { replSetGetStatus : 1 } checks repl set status");
+ print("\trs.initiate() { replSetInitiate : null } initiates set with default settings");
+ print("\trs.initiate(cfg) { replSetInitiate : cfg } initiates set with configuration cfg");
+ print("\trs.conf() get the current configuration object from local.system.replset");
+ print("\trs.reconfig(cfg) updates the configuration of a running replica set with cfg (disconnects)");
+ print("\trs.add(hostportstr) add a new member to the set with default attributes (disconnects)");
+ print("\trs.add(membercfgobj) add a new member to the set with extra attributes (disconnects)");
+ print("\trs.addArb(hostportstr) add a new member which is arbiterOnly:true (disconnects)");
+ print("\trs.stepDown([secs]) step down as primary (momentarily) (disconnects)");
+ print("\trs.syncFrom(hostportstr) make a secondary to sync from the given member");
+ print("\trs.freeze(secs) make a node ineligible to become primary for the time specified");
+ print("\trs.remove(hostportstr) remove a host from the replica set (disconnects)");
+ print("\trs.slaveOk() shorthand for db.getMongo().setSlaveOk()");
+ print();
+ print("\tdb.isMaster() check who is primary");
+ print();
+ print("\treconfiguration helpers disconnect from the database so the shell will display");
+ print("\tan error, even if the command succeeds.");
+ print("\tsee also http://<mongod_host>:28017/_replSet for additional diagnostic info");
+}
+rs.slaveOk = function (value) { return db.getMongo().setSlaveOk(value); }
+rs.status = function () { return db._adminCommand("replSetGetStatus"); }
+rs.isMaster = function () { return db.isMaster(); }
+rs.initiate = function (c) { return db._adminCommand({ replSetInitiate: c }); }
+rs._runCmd = function (c) {
+ // after the command, catch the disconnect and reconnect if necessary
+ var res = null;
+ try {
+ res = db.adminCommand(c);
+ }
+ catch (e) {
+ if (("" + e).indexOf("error doing query") >= 0) {
+ // closed connection. reconnect.
+ db.getLastErrorObj();
+ var o = db.getLastErrorObj();
+ if (o.ok) {
+ print("reconnected to server after rs command (which is normal)");
+ }
+ else {
+ printjson(o);
+ }
+ }
+ else {
+ print("shell got exception during repl set operation: " + e);
+ print("in some circumstances, the primary steps down and closes connections on a reconfig");
+ }
+ return "";
+ }
+ return res;
+}
+rs.reconfig = function (cfg, options) {
+ cfg.version = rs.conf().version + 1;
+ cmd = { replSetReconfig: cfg };
+ for (var i in options) {
+ cmd[i] = options[i];
+ }
+ return this._runCmd(cmd);
+}
+rs.add = function (hostport, arb) {
+ var cfg = hostport;
+
+ var local = db.getSisterDB("local");
+ assert(local.system.replset.count() <= 1, "error: local.system.replset has unexpected contents");
+ var c = local.system.replset.findOne();
+ assert(c, "no config object retrievable from local.system.replset");
+
+ c.version++;
+
+ var max = 0;
+ for (var i in c.members)
+ if (c.members[i]._id > max) max = c.members[i]._id;
+ if (isString(hostport)) {
+ cfg = { _id: max + 1, host: hostport };
+ if (arb)
+ cfg.arbiterOnly = true;
+ }
+ c.members.push(cfg);
+ return this._runCmd({ replSetReconfig: c });
+}
+rs.syncFrom = function (host) { return db._adminCommand({replSetSyncFrom : host}); };
+rs.stepDown = function (secs) { return db._adminCommand({ replSetStepDown:(secs === undefined) ? 60:secs}); }
+rs.freeze = function (secs) { return db._adminCommand({replSetFreeze:secs}); }
+rs.addArb = function (hn) { return this.add(hn, true); }
+rs.conf = function () { return db.getSisterDB("local").system.replset.findOne(); }
+rs.config = function () { return rs.conf(); }
+
+rs.remove = function (hn) {
+ var local = db.getSisterDB("local");
+ assert(local.system.replset.count() <= 1, "error: local.system.replset has unexpected contents");
+ var c = local.system.replset.findOne();
+ assert(c, "no config object retrievable from local.system.replset");
+ c.version++;
+
+ for (var i in c.members) {
+ if (c.members[i].host == hn) {
+ c.members.splice(i, 1);
+ return db._adminCommand({ replSetReconfig : c});
+ }
+ }
+
+ return "error: couldn't find "+hn+" in "+tojson(c.members);
+};
+
+rs.debug = {};
+
+rs.debug.nullLastOpWritten = function(primary, secondary) {
+ var p = connect(primary+"/local");
+ var s = connect(secondary+"/local");
+ s.getMongo().setSlaveOk();
+
+ var secondToLast = s.oplog.rs.find().sort({$natural : -1}).limit(1).next();
+ var last = p.runCommand({findAndModify : "oplog.rs",
+ query : {ts : {$gt : secondToLast.ts}},
+ sort : {$natural : 1},
+ update : {$set : {op : "n"}}});
+
+ if (!last.value.o || !last.value.o._id) {
+ print("couldn't find an _id?");
+ }
+ else {
+ last.value.o = {_id : last.value.o._id};
+ }
+
+ print("nulling out this op:");
+ printjson(last);
+};
+
+rs.debug.getLastOpWritten = function(server) {
+ var s = db.getSisterDB("local");
+ if (server) {
+ s = connect(server+"/local");
+ }
+ s.getMongo().setSlaveOk();
+
+ return s.oplog.rs.find().sort({$natural : -1}).limit(1).next();
+};
+
+
+help = shellHelper.help = function (x) {
+ if (x == "mr") {
+ print("\nSee also http://dochub.mongodb.org/core/mapreduce");
+ print("\nfunction mapf() {");
+ print(" // 'this' holds current document to inspect");
+ print(" emit(key, value);");
+ print("}");
+ print("\nfunction reducef(key,value_array) {");
+ print(" return reduced_value;");
+ print("}");
+ print("\ndb.mycollection.mapReduce(mapf, reducef[, options])");
+ print("\noptions");
+ print("{[query : <query filter object>]");
+ print(" [, sort : <sort the query. useful for optimization>]");
+ print(" [, limit : <number of objects to return from collection>]");
+ print(" [, out : <output-collection name>]");
+ print(" [, keeptemp: <true|false>]");
+ print(" [, finalize : <finalizefunction>]");
+ print(" [, scope : <object where fields go into javascript global scope >]");
+ print(" [, verbose : true]}\n");
+ return;
+ } else if (x == "connect") {
+ print("\nNormally one specifies the server on the mongo shell command line. Run mongo --help to see those options.");
+ print("Additional connections may be opened:\n");
+ print(" var x = new Mongo('host[:port]');");
+ print(" var mydb = x.getDB('mydb');");
+ print(" or");
+ print(" var mydb = connect('host[:port]/mydb');");
+ print("\nNote: the REPL prompt only auto-reports getLastError() for the shell command line connection.\n");
+ return;
+ }
+ else if (x == "keys") {
+ print("Tab completion and command history is available at the command prompt.\n");
+ print("Some emacs keystrokes are available too:");
+ print(" Ctrl-A start of line");
+ print(" Ctrl-E end of line");
+ print(" Ctrl-K del to end of line");
+ print("\nMulti-line commands");
+ print("You can enter a multi line javascript expression. If parens, braces, etc. are not closed, you will see a new line ");
+ print("beginning with '...' characters. Type the rest of your expression. Press Ctrl-C to abort the data entry if you");
+ print("get stuck.\n");
+ }
+ else if (x == "misc") {
+ print("\tb = new BinData(subtype,base64str) create a BSON BinData value");
+ print("\tb.subtype() the BinData subtype (0..255)");
+ print("\tb.length() length of the BinData data in bytes");
+ print("\tb.hex() the data as a hex encoded string");
+ print("\tb.base64() the data as a base 64 encoded string");
+ print("\tb.toString()");
+ print();
+ print("\tb = HexData(subtype,hexstr) create a BSON BinData value from a hex string");
+ print("\tb = UUID(hexstr) create a BSON BinData value of UUID subtype");
+ print("\tb = MD5(hexstr) create a BSON BinData value of MD5 subtype");
+ print("\t\"hexstr\" string, sequence of hex characters (no 0x prefix)");
+ print();
+ print("\to = new ObjectId() create a new ObjectId");
+ print("\to.getTimestamp() return timestamp derived from first 32 bits of the OID");
+ print("\to.isObjectId()");
+ print("\to.toString()");
+ print("\to.equals(otherid)");
+ print();
+ print("\td = ISODate() like Date() but behaves more intuitively when used");
+ print("\td = ISODate('YYYY-MM-DD hh:mm:ss') without an explicit \"new \" prefix on construction");
+ return;
+ }
+ else if (x == "admin") {
+ print("\tls([path]) list files");
+ print("\tpwd() returns current directory");
+ print("\tlistFiles([path]) returns file list");
+ print("\thostname() returns name of this host");
+ print("\tcat(fname) returns contents of text file as a string");
+ print("\tremoveFile(f) delete a file or directory");
+ print("\tload(jsfilename) load and execute a .js file");
+ print("\trun(program[, args...]) spawn a program and wait for its completion");
+ print("\trunProgram(program[, args...]) same as run(), above");
+ print("\tsleep(m) sleep m milliseconds");
+ print("\tgetMemInfo() diagnostic");
+ return;
+ }
+ else if (x == "test") {
+ print("\tstartMongodEmpty(args) DELETES DATA DIR and then starts mongod");
+ print("\t returns a connection to the new server");
+ print("\tstartMongodTest(port,dir,options)");
+ print("\t DELETES DATA DIR");
+ print("\t automatically picks port #s starting at 27000 and increasing");
+ print("\t or you can specify the port as the first arg");
+ print("\t dir is /data/db/<port>/ if not specified as the 2nd arg");
+ print("\t returns a connection to the new server");
+ print("\tresetDbpath(dirpathstr) deletes everything under the dir specified including subdirs");
+ print("\tstopMongoProgram(port[, signal])");
+ return;
+ }
+ else if (x == "") {
+ print("\t" + "db.help() help on db methods");
+ print("\t" + "db.mycoll.help() help on collection methods");
+ print("\t" + "sh.help() sharding helpers");
+ print("\t" + "rs.help() replica set helpers");
+ print("\t" + "help admin administrative help");
+ print("\t" + "help connect connecting to a db help");
+ print("\t" + "help keys key shortcuts");
+ print("\t" + "help misc misc things to know");
+ print("\t" + "help mr mapreduce");
+ print();
+ print("\t" + "show dbs show database names");
+ print("\t" + "show collections show collections in current database");
+ print("\t" + "show users show users in current database");
+ print("\t" + "show profile show most recent system.profile entries with time >= 1ms");
+ print("\t" + "show logs show the accessible logger names");
+ print("\t" + "show log [name] prints out the last segment of log in memory, 'global' is default");
+ print("\t" + "use <db_name> set current database");
+ print("\t" + "db.foo.find() list objects in collection foo");
+ print("\t" + "db.foo.find( { a : 1 } ) list objects in foo where a == 1");
+ print("\t" + "it result of the last line evaluated; use to further iterate");
+ print("\t" + "DBQuery.shellBatchSize = x set default number of items to display on shell");
+ print("\t" + "exit quit the mongo shell");
+ }
+ else
+ print("unknown help option");
+}
diff --git a/src/mongo/shell/utils_sh.js b/src/mongo/shell/utils_sh.js
new file mode 100644
index 00000000000..3aa2102b2f4
--- /dev/null
+++ b/src/mongo/shell/utils_sh.js
@@ -0,0 +1,348 @@
+sh = function() { return "try sh.help();" }
+
+sh._checkMongos = function() {
+ var x = db.runCommand( "ismaster" );
+ if ( x.msg != "isdbgrid" )
+ throw "not connected to a mongos"
+}
+
+sh._checkFullName = function( fullName ) {
+ assert( fullName , "neeed a full name" )
+ assert( fullName.indexOf( "." ) > 0 , "name needs to be fully qualified <db>.<collection>'" )
+}
+
+sh._adminCommand = function( cmd , skipCheck ) {
+ if ( ! skipCheck ) sh._checkMongos();
+ return db.getSisterDB( "admin" ).runCommand( cmd );
+}
+
+sh._dataFormat = function( bytes ){
+ if( bytes < 1024 ) return Math.floor( bytes ) + "b"
+ if( bytes < 1024 * 1024 ) return Math.floor( bytes / 1024 ) + "kb"
+ if( bytes < 1024 * 1024 * 1024 ) return Math.floor( ( Math.floor( bytes / 1024 ) / 1024 ) * 100 ) / 100 + "Mb"
+ return Math.floor( ( Math.floor( bytes / ( 1024 * 1024 ) ) / 1024 ) * 100 ) / 100 + "Gb"
+}
+
+sh._collRE = function( coll ){
+ return RegExp( "^" + RegExp.escape(coll + "") + "-.*" )
+}
+
+sh._pchunk = function( chunk ){
+ return "[" + tojson( chunk.min ) + " -> " + tojson( chunk.max ) + "]"
+}
+
+sh.help = function() {
+ print( "\tsh.addShard( host ) server:port OR setname/server:port" )
+ print( "\tsh.enableSharding(dbname) enables sharding on the database dbname" )
+ print( "\tsh.shardCollection(fullName,key,unique) shards the collection" );
+
+ print( "\tsh.splitFind(fullName,find) splits the chunk that find is in at the median" );
+ print( "\tsh.splitAt(fullName,middle) splits the chunk that middle is in at middle" );
+ print( "\tsh.moveChunk(fullName,find,to) move the chunk where 'find' is to 'to' (name of shard)");
+
+ print( "\tsh.setBalancerState( <bool on or not> ) turns the balancer on or off true=on, false=off" );
+ print( "\tsh.getBalancerState() return true if on, off if not" );
+ print( "\tsh.isBalancerRunning() return true if the balancer is running on any mongos" );
+
+ print( "\tsh.addShardTag(shard,tag) adds the tag to the shard" );
+ print( "\tsh.removeShardTag(shard,tag) removes the tag from the shard" );
+
+ print( "\tsh.status() prints a general overview of the cluster" )
+}
+
+sh.status = function( verbose , configDB ) {
+ // TODO: move the actual commadn here
+ printShardingStatus( configDB , verbose );
+}
+
+sh.addShard = function( url ){
+ return sh._adminCommand( { addShard : url } , true );
+}
+
+sh.enableSharding = function( dbname ) {
+ assert( dbname , "need a valid dbname" )
+ return sh._adminCommand( { enableSharding : dbname } );
+}
+
+sh.shardCollection = function( fullName , key , unique ) {
+ sh._checkFullName( fullName )
+ assert( key , "need a key" )
+ assert( typeof( key ) == "object" , "key needs to be an object" )
+
+ var cmd = { shardCollection : fullName , key : key }
+ if ( unique )
+ cmd.unique = true;
+
+ return sh._adminCommand( cmd );
+}
+
+sh.splitFind = function( fullName , find ) {
+ sh._checkFullName( fullName )
+ return sh._adminCommand( { split : fullName , find : find } );
+}
+
+sh.splitAt = function( fullName , middle ) {
+ sh._checkFullName( fullName )
+ return sh._adminCommand( { split : fullName , middle : middle } );
+}
+
+sh.moveChunk = function( fullName , find , to ) {
+ sh._checkFullName( fullName );
+ return sh._adminCommand( { moveChunk : fullName , find : find , to : to } )
+}
+
+sh.setBalancerState = function( onOrNot ) {
+ db.getSisterDB( "config" ).settings.update({ _id: "balancer" }, { $set : { stopped: onOrNot ? false : true } }, true );
+}
+
+sh.getBalancerState = function() {
+ var x = db.getSisterDB( "config" ).settings.findOne({ _id: "balancer" } )
+ if ( x == null )
+ return true;
+ return ! x.stopped;
+}
+
+sh.isBalancerRunning = function () {
+ var x = db.getSisterDB("config").locks.findOne({ _id: "balancer" });
+ if (x == null) {
+ print("config.locks collection empty or missing. be sure you are connected to a mongos");
+ return false;
+ }
+ return x.state > 0;
+}
+
+sh.getBalancerHost = function() {
+ var x = db.getSisterDB("config").locks.findOne({ _id: "balancer" });
+ if( x == null ){
+ print("config.locks collection does not contain balancer lock. be sure you are connected to a mongos");
+ return ""
+ }
+ return x.process.match(/[^:]+:[^:]+/)[0]
+}
+
+sh.stopBalancer = function( timeout, interval ) {
+ sh.setBalancerState( false )
+ sh.waitForBalancer( false, timeout, interval )
+}
+
+sh.startBalancer = function( timeout, interval ) {
+ sh.setBalancerState( true )
+ sh.waitForBalancer( true, timeout, interval )
+}
+
+sh.waitForDLock = function( lockId, onOrNot, timeout, interval ){
+
+ // Wait for balancer to be on or off
+ // Can also wait for particular balancer state
+ var state = onOrNot
+
+ var beginTS = undefined
+ if( state == undefined ){
+ var currLock = db.getSisterDB( "config" ).locks.findOne({ _id : lockId })
+ if( currLock != null ) beginTS = currLock.ts
+ }
+
+ var lockStateOk = function(){
+ var lock = db.getSisterDB( "config" ).locks.findOne({ _id : lockId })
+
+ if( state == false ) return ! lock || lock.state == 0
+ if( state == true ) return lock && lock.state == 2
+ if( state == undefined ) return (beginTS == undefined && lock) ||
+ (beginTS != undefined && ( !lock || lock.ts + "" != beginTS + "" ) )
+ else return lock && lock.state == state
+ }
+
+ assert.soon( lockStateOk,
+ "Waited too long for lock " + lockId + " to " +
+ (state == true ? "lock" : ( state == false ? "unlock" :
+ "change to state " + state ) ),
+ timeout,
+ interval
+ )
+}
+
+sh.waitForPingChange = function( activePings, timeout, interval ){
+
+ var isPingChanged = function( activePing ){
+ var newPing = db.getSisterDB( "config" ).mongos.findOne({ _id : activePing._id })
+ return ! newPing || newPing.ping + "" != activePing.ping + ""
+ }
+
+ // First wait for all active pings to change, so we're sure a settings reload
+ // happened
+
+ // Timeout all pings on the same clock
+ var start = new Date()
+
+ var remainingPings = []
+ for( var i = 0; i < activePings.length; i++ ){
+
+ var activePing = activePings[ i ]
+ print( "Waiting for active host " + activePing._id + " to recognize new settings... (ping : " + activePing.ping + ")" )
+
+ // Do a manual timeout here, avoid scary assert.soon errors
+ var timeout = timeout || 30000;
+ var interval = interval || 200;
+ while( isPingChanged( activePing ) != true ){
+ if( ( new Date() ).getTime() - start.getTime() > timeout ){
+ print( "Waited for active ping to change for host " + activePing._id +
+ ", a migration may be in progress or the host may be down." )
+ remainingPings.push( activePing )
+ break
+ }
+ sleep( interval )
+ }
+
+ }
+
+ return remainingPings
+}
+
+sh.waitForBalancerOff = function( timeout, interval ){
+
+ var pings = db.getSisterDB( "config" ).mongos.find().toArray()
+ var activePings = []
+ for( var i = 0; i < pings.length; i++ ){
+ if( ! pings[i].waiting ) activePings.push( pings[i] )
+ }
+
+ print( "Waiting for active hosts..." )
+
+ activePings = sh.waitForPingChange( activePings, 60 * 1000 )
+
+ // After 1min, we assume that all hosts with unchanged pings are either
+ // offline (this is enough time for a full errored balance round, if a network
+ // issue, which would reload settings) or balancing, which we wait for next
+ // Legacy hosts we always have to wait for
+
+ print( "Waiting for the balancer lock..." )
+
+ // Wait for the balancer lock to become inactive
+ // We can guess this is stale after 15 mins, but need to double-check manually
+ try{
+ sh.waitForDLock( "balancer", false, 15 * 60 * 1000 )
+ }
+ catch( e ){
+ print( "Balancer still may be active, you must manually verify this is not the case using the config.changelog collection." )
+ throw e
+ }
+
+ print( "Waiting again for active hosts after balancer is off..." )
+
+ // Wait a short time afterwards, to catch the host which was balancing earlier
+ activePings = sh.waitForPingChange( activePings, 5 * 1000 )
+
+ // Warn about all the stale host pings remaining
+ for( var i = 0; i < activePings.length; i++ ){
+ print( "Warning : host " + activePings[i]._id + " seems to have been offline since " + activePings[i].ping )
+ }
+
+}
+
+sh.waitForBalancer = function( onOrNot, timeout, interval ){
+
+ // If we're waiting for the balancer to turn on or switch state or
+ // go to a particular state
+ if( onOrNot ){
+ // Just wait for the balancer lock to change, can't ensure we'll ever see it
+ // actually locked
+ sh.waitForDLock( "balancer", undefined, timeout, interval )
+ }
+ else {
+ // Otherwise we need to wait until we're sure balancing stops
+ sh.waitForBalancerOff( timeout, interval )
+ }
+
+}
+
+sh.disableBalancing = function( coll ){
+ var dbase = db
+ if( coll instanceof DBCollection ) dbase = coll.getDB()
+ dbase.getSisterDB( "config" ).collections.update({ _id : coll + "" }, { $set : { "noBalance" : true } })
+}
+
+sh.enableBalancing = function( coll ){
+ var dbase = db
+ if( coll instanceof DBCollection ) dbase = coll.getDB()
+ dbase.getSisterDB( "config" ).collections.update({ _id : coll + "" }, { $set : { "noBalance" : false } })
+}
+
+/*
+ * Can call _lastMigration( coll ), _lastMigration( db ), _lastMigration( st ), _lastMigration( mongos )
+ */
+sh._lastMigration = function( ns ){
+
+ var coll = null
+ var dbase = null
+ var config = null
+
+ if( ! ns ){
+ config = db.getSisterDB( "config" )
+ }
+ else if( ns instanceof DBCollection ){
+ coll = ns
+ config = coll.getDB().getSisterDB( "config" )
+ }
+ else if( ns instanceof DB ){
+ dbase = ns
+ config = dbase.getSisterDB( "config" )
+ }
+ else if( ns instanceof ShardingTest ){
+ config = ns.s.getDB( "config" )
+ }
+ else if( ns instanceof Mongo ){
+ config = ns.getDB( "config" )
+ }
+ else {
+ // String namespace
+ ns = ns + ""
+ if( ns.indexOf( "." ) > 0 ){
+ config = db.getSisterDB( "config" )
+ coll = db.getMongo().getCollection( ns )
+ }
+ else{
+ config = db.getSisterDB( "config" )
+ dbase = db.getSisterDB( ns )
+ }
+ }
+
+ var searchDoc = { what : /^moveChunk/ }
+ if( coll ) searchDoc.ns = coll + ""
+ if( dbase ) searchDoc.ns = new RegExp( "^" + dbase + "\\." )
+
+ var cursor = config.changelog.find( searchDoc ).sort({ time : -1 }).limit( 1 )
+ if( cursor.hasNext() ) return cursor.next()
+ else return null
+}
+
+sh._checkLastError = function( mydb ) {
+ var err = mydb.getLastError();
+ if ( err )
+ throw "error: " + err;
+}
+
+sh.addShardTag = function( shard, tag ) {
+ var config = db.getSisterDB( "config" );
+ if ( config.shards.findOne( { _id : shard } ) == null ) {
+ throw "can't find a shard with name: " + shard;
+ }
+ config.shards.update( { _id : shard } , { $addToSet : { tags : tag } } );
+ sh._checkLastError( config );
+}
+
+sh.removeShardTag = function( shard, tag ) {
+ var config = db.getSisterDB( "config" );
+ if ( config.shards.findOne( { _id : shard } ) == null ) {
+ throw "can't find a shard with name: " + shard;
+ }
+ config.shards.update( { _id : shard } , { $pull : { tags : tag } } );
+ sh._checkLastError( config );
+}
+
+sh.addTagRange = function( ns, min, max, tag ) {
+ var config = db.getSisterDB( "config" );
+ config.tags.update( { ns : ns , min : min } ,
+ { ns : ns , min : min , max : max , tag : tag } ,
+ true );
+ sh._checkLastError( config );
+}