void run() { StringBuilder sb; sb << "1" << "abc" << "5.17"; ASSERT_EQUALS( "1abc5.17" , sb.str() ); ASSERT_EQUALS( "1abc5.17" , sb.str() ); sb.reset(1); ASSERT_EQUALS( "" , sb.str() ); sb << "999"; ASSERT_EQUALS( "999" , sb.str() ); }
TEST(Builder, StringBuilderAddress) { const void* longPtr = reinterpret_cast<const void*>(-1); const void* shortPtr = reinterpret_cast<const void*>(0xDEADBEEF); const void* nullPtr = NULL; StringBuilder sb; sb << longPtr; if (sizeof(longPtr) == 8) { ASSERT_EQUALS("0xFFFFFFFFFFFFFFFF", sb.str()); } else { ASSERT_EQUALS("0xFFFFFFFF", sb.str()); } sb.reset(); sb << shortPtr; ASSERT_EQUALS("0xDEADBEEF", sb.str()); sb.reset(); sb << nullPtr; ASSERT_EQUALS("0x0", sb.str()); }
std::string escape(StringData sd, bool escape_slash) { StringBuilder ret; ret.reset(sd.size()); for (const auto& c : sd) { switch (c) { case '"': ret << "\\\""; break; case '\\': ret << "\\\\"; break; case '/': ret << (escape_slash ? "\\/" : "/"); break; case '\b': ret << "\\b"; break; case '\f': ret << "\\f"; break; case '\n': ret << "\\n"; break; case '\r': ret << "\\r"; break; case '\t': ret << "\\t"; break; default: if (c >= 0 && c <= 0x1f) { // For c < 0x7f, ASCII value == Unicode code point. ret << "\\u00" << toHexLower(&c, 1); } else { ret << c; } } } return ret.str(); }
/** * 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, false, false ) ) return; // Error already printed } else { linenoisePreloadBuffer( sb.str().c_str() ); } }
static void edit(const string& var){ static const char * editor = getenv("EDITOR"); if (!editor) { cout << "please define the EDITOR environment variable" << endl; return; } for (const char* p=var.data(); *p ; p++){ if (! (isalnum(*p) || *p == '_' || *p == '.')){ cout << "can only edit variable or property" << endl; return; } } if (!shellMainScope->exec("__jsout__ = tojson("+var+")", "tojs", false, false, false)) return; // Error already printed const string js = shellMainScope->getString("__jsout__"); if (strstr(js.c_str(), "[native code]")) { cout << "Can't edit native functions" << endl; return; } string filename; int fd; for (int i=0; i < 10; i++){ StringBuilder sb; sb << "/tmp/mongo_edit" << time(0)+i << ".js"; filename = sb.str(); fd = open(filename.c_str(), O_RDWR|O_CREAT|O_EXCL, 0600); if (fd > 0) break; if (errno != EEXIST) { cout << "couldn't open temp file: " << errnoWithDescription() << endl; return; } } if (fd == -1){ cout << "couldn't create unique temp file after 10 attempts" << endl; return; } // just to make sure this gets closed no matter what File holder; holder.fd = fd; if (write(fd, js.data(), js.size()) != (int)js.size()){ cout << "failed to write to temp file: " << errnoWithDescription() << endl; return; } StringBuilder sb; sb << editor << " " << filename; int ret = ::system(sb.str().c_str()); int systemErrno = errno; remove(filename.c_str()); // file already open, deleted on close if (ret){ if (ret == -1) { cout << "failed to launch $EDITOR (" << editor << "): " << errnoWithDescription(systemErrno) << endl; return; } cout << "editor exited with error, not applying changes" << endl; return; } lseek(fd, 0, SEEK_SET); sb.reset(); sb << var << " = "; int bytes; do { char buf[1024]; bytes = read(fd, buf, sizeof(buf)); if (bytes < 0) { cout << "failed to read temp file: " << errnoWithDescription() << endl; return; } sb.append( StringData(buf, bytes) ); }while (bytes); const string code = sb.str(); if (!shellMainScope->exec(code, "tojs", false, false, false)) return; // Error already printed }
/** * Reads the bytes in the buffer. Interprets messages as * it detects them. * * Preconditions: * -serialInBox has been initialized. * -MAX_MESSAGE_SIZE number of bytes of memory availiable * on the stack. * -Serial.begin() has been called successfully. * -serialInBox may need more memory on the heap. * * Post Conditions: * -serialInBox may have additional bytes from buffer if the proper * begginning and ending chars are received and the message is * properly formatted. * @param buffer is the array of characters to read. * @param numOfBytes is the length of the array. */ void readBytes( char buffer[], int numOfBytes ) { static boolean foundMessage = false; // Discard any previous messages. serialInBox.reset(); // Handle each byte. for( int i = 0; i < numOfBytes; ++i ) { char chr = buffer[ i ]; switch( chr ) { case MSG_START: { foundMessage = true; //XXX Clear inbox. } break; case MSG_TERMINATOR: { if ( serialInBox.len() > 0 ) { // What to do once we have the message? int messageID; bool goodMessage = false; // Get message type. char messageType = *(const char*)serialInBox; serialOutBox.appends( "\"" ); serialOutBox.appends( (const char*)serialInBox ); serialOutBox.appends( "\"" ); switch( messageType ) { case TIME_REQUEST: { int delayAmount; if ( sscanf( (const char*)serialInBox + 1, "%d/%d", &messageID, &delayAmount ) == 2 ) { goodMessage = true; timeRequestEndTime = millis() + delayAmount; } } break; default: { // Unknown request. } } // Read ID. // sscanf returns the number of variables read. if ( goodMessage ) { // Only new messages. if ( lastIDReceived < messageID ) { // Write confirmation message.` char tempOutString[MAX_MESSAGE_SIZE]; sprintf( tempOutString, "%cC%d%c", MSG_START, messageID, MSG_TERMINATOR ); Serial.write( tempOutString ); serialOutBox.appends( tempOutString ); lastIDReceived = messageID; } } else { char tempOutString[ MAX_MESSAGE_SIZE ]; sprintf( tempOutString, "%cE%d\"%s\"Bad Message Format%c", MSG_START, messageID, (const char*)serialInBox, MSG_TERMINATOR ); serialOutBox.appends( tempOutString ); } foundMessage = false; serialInBox.reset(); } } break; default: { if ( foundMessage ) serialInBox.append( chr ); } break; } } }