static void _environment_set_executable_paths( const char* executable_path ) { unsigned int last_path = string_rfind( executable_path, '/', STRING_NPOS ); if( last_path != STRING_NPOS ) { if( !string_length( _environment_executable_dir ) ) string_copy( _environment_executable_dir, executable_path, last_path + 1 ); if( !string_length( _environment_executable_name ) ) { string_copy( _environment_executable_name, executable_path + last_path + 1, FOUNDATION_MAX_PATHLEN ); } } else { if( !string_length( _environment_executable_dir ) ) _environment_executable_dir[0] = 0; if( !string_length( _environment_executable_name ) ) string_copy( _environment_executable_name, executable_path, FOUNDATION_MAX_PATHLEN ); } #if FOUNDATION_PLATFORM_WINDOWS last_path = string_length( _environment_executable_name ); if( ( last_path > 4 ) && ( string_equal( _environment_executable_name + ( last_path - 4 ), ".exe" ) || string_equal( _environment_executable_name + ( last_path - 4 ), ".EXE" ) ) ) _environment_executable_name[ last_path - 4 ] = 0; #endif string_copy( _environment_executable_path, executable_path, FOUNDATION_MAX_PATHLEN ); }
int String::rfind(char ch, int pos /* = 0 */, bool caseSensitive /* = true */) const { if (empty()) return -1; // Ignore taint in comparison functions. return string_rfind(m_px->dataIgnoreTaint(), m_px->size(), ch, pos, caseSensitive); }
char* path_file_extension( const char* path ) { unsigned int start = string_find_last_of( path, "/\\", STRING_NPOS ); unsigned int end = string_rfind( path, '.', STRING_NPOS ); if( ( end != STRING_NPOS ) && ( ( start == STRING_NPOS ) || ( end > start ) ) ) return string_substr( path, end + 1, STRING_NPOS ); return string_clone( "" ); }
int String::rfind(CStrRef s, int pos /* = 0 */, bool caseSensitive /* = true */) const { if (empty()) return -1; if (s.size() == 1) { return rfind(*s.data(), pos, caseSensitive); } return string_rfind(m_px->data(), m_px->size(), s.data(), s.size(), pos, caseSensitive); }
int String::rfind(const char *s, int pos /* = 0 */, bool caseSensitive /* = true */) const { assert(s); if (empty()) return -1; if (*s && *(s+1) == 0) { return rfind(*s, pos, caseSensitive); } return string_rfind(m_px->data(), m_px->size(), s, strlen(s), pos, caseSensitive); }
int String::rfind(CStrRef s, int pos /* = 0 */, bool caseSensitive /* = true */) const { if (empty()) return -1; if (s.size() == 1) { return rfind(*s.dataIgnoreTaint(), pos, caseSensitive); } // Ignore taint in comparison functions. return string_rfind(m_px->dataIgnoreTaint(), m_px->size(), s.dataIgnoreTaint(), s.size(), pos, caseSensitive); }
int String::rfind(const char *s, int pos /* = 0 */, bool caseSensitive /* = true */) const { ASSERT(s); if (empty()) return -1; if (*s && *(s+1) == 0) { return rfind(*s, pos, caseSensitive); } // Ignore taint in comparison functions. return string_rfind(m_px->dataIgnoreTaint(), m_px->size(), s, strlen(s), pos, caseSensitive); }
char* path_base_file_name_with_path( const char* path ) { unsigned int start, end; char* base; if( !path ) return string_allocate( 0 ); start = string_find_last_of( path, "/\\", STRING_NPOS ); end = string_rfind( path, '.', STRING_NPOS ); //For "dot" files, i.e files with names like "/path/to/.file", return the dot name ".file" if( !end || ( end == ( start + 1 ) ) || ( ( start != STRING_NPOS ) && ( end < start ) ) ) end = STRING_NPOS; base = string_substr( path, 0, ( end != STRING_NPOS ) ? end : STRING_NPOS ); base = path_clean( base, path_is_absolute( base ) ); return base; }
int String::rfind(char ch, int pos /* = 0 */, bool caseSensitive /* = true */) const { if (empty()) return -1; return string_rfind(m_px->data(), m_px->size(), ch, pos, caseSensitive); }
DECLARE_TEST( string, queries ) { { char teststr[] = ""; char teststr2[] = "test"; char teststr3[] = "testing long string with more than 16 characters"; char teststr4[] = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; char* str1 = string_substr( teststr, 0, 0 ); char* str2 = string_substr( teststr2, 0, 4 ); char* str3 = string_substr( teststr2, 0, 20 ); char* str4 = string_substr( teststr3, 0, 0 ); char* str5 = string_substr( teststr3, 0, 10 ); char* str6 = string_substr( teststr3, 0, STRING_NPOS ); char* str7 = string_substr( teststr4, 0, 0 ); char* str8 = string_substr( teststr4, 0, 20 ); char* str9 = string_substr( teststr4, 0, STRING_NPOS ); EXPECT_EQ( 0, str1[0] ); EXPECT_EQ( 0, str2[ string_length( str2 ) ] ); EXPECT_EQ( 0, str3[ string_length( str3 ) ] ); EXPECT_EQ( 0, str4[ string_length( str4 ) ] ); EXPECT_EQ( 0, str5[ string_length( str5 ) ] ); EXPECT_EQ( 0, str6[ string_length( str6 ) ] ); EXPECT_EQ( 0, str7[ string_length( str7 ) ] ); EXPECT_EQ( 0, str8[ string_length( str8 ) ] ); EXPECT_EQ( 0, str9[ string_length( str9 ) ] ); EXPECT_EQ( strlen( teststr ), string_length( str1 ) ); EXPECT_EQ( strlen( teststr2 ), string_length( str2 ) ); EXPECT_EQ( strlen( teststr2 ), string_length( str3 ) ); EXPECT_EQ( 0U, string_length( str4 ) ); EXPECT_EQ( 10U, string_length( str5 ) ); EXPECT_EQ( strlen( teststr3 ), string_length( str6 ) ); EXPECT_EQ( 0U, string_length( str7 ) ); EXPECT_EQ( 20U, string_length( str8 ) ); EXPECT_EQ( strlen( teststr4 ), string_length( str9 ) ); string_deallocate( str1 ); string_deallocate( str2 ); string_deallocate( str3 ); string_deallocate( str4 ); string_deallocate( str5 ); string_deallocate( str6 ); string_deallocate( str7 ); string_deallocate( str8 ); string_deallocate( str9 ); } { //Only ASCII characters, so wstring->string conversion should not introduce any extra UTF-8 sequences wchar_t teststr[] = L""; wchar_t teststr2[] = L"test"; wchar_t teststr3[] = L"testing long string with more than 16 characters"; wchar_t teststr4[] = L"01234567890123456789012345678901234567890123456789012345678901234567890123456789"; char* str1 = string_allocate_from_wstring( teststr, 0 ); char* str2 = string_allocate_from_wstring( teststr2, 0 ); char* str3 = string_allocate_from_wstring( teststr2, 20 ); char* str4 = string_allocate_from_wstring( teststr3, 0 ); char* str5 = string_allocate_from_wstring( teststr3, 10 ); char* str6 = string_allocate_from_wstring( teststr3, STRING_NPOS ); char* str7 = string_allocate_from_wstring( teststr4, 0 ); char* str8 = string_allocate_from_wstring( teststr4, 20 ); char* str9 = string_allocate_from_wstring( teststr4, STRING_NPOS ); EXPECT_EQ( 0, str1[0] ); EXPECT_EQ( 0, str2[ string_length( str2 ) ] ); EXPECT_EQ( 0, str3[ string_length( str3 ) ] ); EXPECT_EQ( 0, str4[ string_length( str4 ) ] ); EXPECT_EQ( 0, str5[ string_length( str5 ) ] ); EXPECT_EQ( 0, str6[ string_length( str6 ) ] ); EXPECT_EQ( 0, str7[ string_length( str7 ) ] ); EXPECT_EQ( 0, str8[ string_length( str8 ) ] ); EXPECT_EQ( 0, str9[ string_length( str9 ) ] ); EXPECT_EQ( wcslen( teststr ), string_length( str1 ) ); EXPECT_EQ( wcslen( teststr2 ), string_length( str2 ) ); EXPECT_EQ( wcslen( teststr2 ), string_length( str3 ) ); EXPECT_EQ( wcslen( teststr3 ), string_length( str4 ) ); EXPECT_EQ( 10U, string_length( str5 ) ); EXPECT_EQ( wcslen( teststr3 ), string_length( str6 ) ); EXPECT_EQ( wcslen( teststr4 ), string_length( str7 ) ); EXPECT_EQ( 20U, string_length( str8 ) ); EXPECT_EQ( wcslen( teststr4 ), string_length( str9 ) ); string_deallocate( str1 ); string_deallocate( str2 ); string_deallocate( str3 ); string_deallocate( str4 ); string_deallocate( str5 ); string_deallocate( str6 ); string_deallocate( str7 ); string_deallocate( str8 ); string_deallocate( str9 ); } { char* emptystr = string_allocate( 0 ); char* shortstr = string_clone( "short string" ); char* longstr = string_clone( "testing utility string methods like finds, split, merge, explode and similar." ); { unsigned int find = string_find( longstr, ' ', 0 ); unsigned int find2 = string_find( longstr, 12, 0 ); unsigned int find3 = string_find( emptystr, ' ', 0 ); unsigned int find4 = string_find( shortstr, ' ', 0 ); unsigned int find5 = string_find( shortstr, 'z', 0 ); unsigned int findofs = string_find( longstr, ' ', find ); unsigned int findofs2 = string_find( longstr, ' ', find + 1 ); unsigned int findofs3 = string_find( longstr, 'z', 10 ); unsigned int findofs4 = string_find( emptystr, 'z', STRING_NPOS ); unsigned int findofs5 = string_find( shortstr, 's', 10 ); unsigned int findofs6 = string_find( shortstr, 's', findofs5 ); unsigned int findofs7 = string_find( shortstr, 't', 0 ); unsigned int findofs8 = string_find( shortstr, ' ', 5 ); unsigned int findofs9 = string_find( longstr, ' ', STRING_NPOS ); EXPECT_EQ( find, 7U ); EXPECT_EQ( find2, STRING_NPOS ); EXPECT_EQ( find3, STRING_NPOS ); EXPECT_EQ( find4, 5U ); EXPECT_EQ( find5, STRING_NPOS ); EXPECT_EQ( findofs, find ); EXPECT_EQ( findofs2, 15U ); EXPECT_EQ( findofs3, STRING_NPOS ); EXPECT_EQ( findofs4, STRING_NPOS ); EXPECT_EQ( findofs5, STRING_NPOS ); EXPECT_EQ( findofs6, STRING_NPOS ); EXPECT_EQ( findofs7, 4U ); EXPECT_EQ( findofs8, 5U ); EXPECT_EQ( findofs9, STRING_NPOS ); } { unsigned int rfind = string_rfind( longstr, ' ', STRING_NPOS ); unsigned int rfind2 = string_rfind( longstr, ';', STRING_NPOS ); unsigned int rfind3 = string_rfind( emptystr, ';', STRING_NPOS ); unsigned int rfind4 = string_rfind( shortstr, 's', STRING_NPOS ); unsigned int rfind5 = string_rfind( shortstr, 'z', STRING_NPOS ); unsigned int rfindofs = string_rfind( longstr, ' ', rfind ); unsigned int rfindofs2 = string_rfind( longstr, ' ', rfind - 1 ); unsigned int rfindofs3 = string_rfind( longstr, ' ', string_length( longstr ) - 1 ); unsigned int rfindofs4 = string_rfind( emptystr, ' ', 0 ); unsigned int rfindofs5 = string_rfind( longstr, ' ', 0 ); unsigned int rfindofs6 = string_rfind( shortstr, 's', 5 ); unsigned int rfindofs7 = string_rfind( shortstr, 's', 0 ); EXPECT_EQ( rfind, 68U ); EXPECT_EQ( rfind2, STRING_NPOS ); EXPECT_EQ( rfind3, STRING_NPOS ); EXPECT_EQ( rfind4, 6U ); EXPECT_EQ( rfind5, STRING_NPOS ); EXPECT_EQ( rfindofs, rfind ); EXPECT_EQ( rfindofs2, 64U ); EXPECT_EQ( rfindofs3, rfind ); EXPECT_EQ( rfindofs4, STRING_NPOS ); EXPECT_EQ( rfindofs5, STRING_NPOS ); EXPECT_EQ( rfindofs6, 0U ); EXPECT_EQ( rfindofs7, 0U ); } { unsigned int findstr = string_find_string( longstr, "st", 0 ); unsigned int findstr2 = string_find_string( longstr, "xwqz", 0 ); unsigned int findstr3 = string_find_string( emptystr, "xwqz", 0 ); unsigned int findstr4 = string_find_string( longstr, "", 0 ); unsigned int findstr5 = string_find_string( longstr, "dslike", 0 ); unsigned int findstr6 = string_find_string( shortstr, "rt", 0 ); unsigned int findstr7 = string_find_string( shortstr, "long key that does not exist", 0 ); unsigned int findstr8 = string_find_string( shortstr, "so", 0 ); unsigned int findstrofs = string_find_string( longstr, "st", findstr ); unsigned int findstrofs2 = string_find_string( longstr, "st", findstr + 1 ); unsigned int findstrofs3 = string_find_string( longstr, "xwqz", string_length( longstr ) ); unsigned int findstrofs4 = string_find_string( emptystr, "xwqz", string_length( emptystr ) ); unsigned int findstrofs5 = string_find_string( shortstr, "", 5 ); unsigned int findstrofs6 = string_find_string( shortstr, "string", 0 ); unsigned int findstrofs7 = string_find_string( shortstr, "string", 7 ); unsigned int findstrofs8 = string_find_string( longstr, "utility", 14 ); unsigned int findstrofs9 = string_find_string( longstr, "", string_length( longstr ) ); unsigned int findstrofs10 = string_find_string( longstr, "", STRING_NPOS ); unsigned int findstrofs11 = string_find_string( longstr, "string", STRING_NPOS ); EXPECT_EQ( findstr, 2U ); EXPECT_EQ( findstr2, STRING_NPOS ); EXPECT_EQ( findstr3, STRING_NPOS ); EXPECT_EQ( findstr4, 0U ); EXPECT_EQ( findstr5, STRING_NPOS ); EXPECT_EQ( findstr6, 3U ); EXPECT_EQ( findstr7, STRING_NPOS ); EXPECT_EQ( findstr8, STRING_NPOS ); EXPECT_EQ( findstrofs, findstr ); EXPECT_EQ( findstrofs2, 16U ); EXPECT_EQ( findstrofs3, STRING_NPOS ); EXPECT_EQ( findstrofs4, STRING_NPOS ); EXPECT_EQ( findstrofs5, 5U ); EXPECT_EQ( findstrofs6, 6U ); EXPECT_EQ( findstrofs7, STRING_NPOS ); EXPECT_EQ( findstrofs8, STRING_NPOS ); EXPECT_EQ( findstrofs9, strlen( longstr ) ); EXPECT_EQ( findstrofs10, STRING_NPOS ); EXPECT_EQ( findstrofs11, STRING_NPOS ); } { unsigned int rfindstr = string_rfind_string( longstr, ", ", STRING_NPOS ); unsigned int rfindstr2 = string_rfind_string( longstr, ":;", STRING_NPOS ); unsigned int rfindstr3 = string_rfind_string( emptystr, ":;", STRING_NPOS ); unsigned int rfindstr4 = string_rfind_string( longstr, "", STRING_NPOS ); unsigned int rfindstr5 = string_rfind_string( shortstr, "string", STRING_NPOS ); unsigned int rfindstr6 = string_rfind_string( shortstr, " tring", STRING_NPOS ); unsigned int rfindstrofs = string_rfind_string( longstr, ", ", rfindstr ); unsigned int rfindstrofs2 = string_rfind_string( longstr, ", ", rfindstr - 1 ); unsigned int rfindstrofs3 = string_rfind_string( longstr, ":;", 0 ); unsigned int rfindstrofs4 = string_rfind_string( emptystr, ":;", 0 ); unsigned int rfindstrofs5 = string_rfind_string( longstr, "", 5 ); unsigned int rfindstrofs6 = string_rfind_string( shortstr, "ort str", 6 ); unsigned int rfindstrofs7 = string_rfind_string( shortstr, "ort str", 1 ); EXPECT_EQ( rfindstr, 55U ); EXPECT_EQ( rfindstr2, STRING_NPOS ); EXPECT_EQ( rfindstr3, STRING_NPOS ); EXPECT_EQ( rfindstr4, strlen( longstr ) ); EXPECT_EQ( rfindstr5, 6U ); EXPECT_EQ( rfindstr6, STRING_NPOS ); EXPECT_EQ( rfindstrofs, rfindstr ); EXPECT_EQ( rfindstrofs2, 48U ); EXPECT_EQ( rfindstrofs3, STRING_NPOS ); EXPECT_EQ( rfindstrofs4, STRING_NPOS ); EXPECT_EQ( rfindstrofs5, 5U ); EXPECT_EQ( rfindstrofs6, 2U ); EXPECT_EQ( rfindstrofs7, STRING_NPOS ); } { unsigned int findof = string_find_first_of( longstr, "ui", 0 ); unsigned int findof2 = string_find_first_of( longstr, ";:", 0 ); unsigned int findof3 = string_find_first_of( emptystr, "", 0 ); unsigned int findof4 = string_find_first_of( emptystr, " ", 0 ); unsigned int findof5 = string_find_first_of( shortstr, "", 0 ); unsigned int findofofs = string_find_first_of( longstr, "ui", findof ); unsigned int findofofs2 = string_find_first_of( longstr, "ui", findof - 1 ); unsigned int findofofs3 = string_find_first_of( longstr, "ui", findof + 1 ); unsigned int findofofs4 = string_find_first_of( longstr, "ui", string_length( longstr ) ); unsigned int findofofs5 = string_find_first_of( emptystr, "", string_length( emptystr ) ); unsigned int findofofs6 = string_find_first_of( shortstr, "string", 6 ); unsigned int findofofs7 = string_find_first_of( shortstr, "", 6 ); unsigned int findofofs8 = string_find_first_of( longstr, "", 10 ); unsigned int findofofs9 = string_find_first_of( longstr, "", string_length( longstr ) ); EXPECT_EQ( findof, 4U ); EXPECT_EQ( findof2, STRING_NPOS ); EXPECT_EQ( findof3, STRING_NPOS ); EXPECT_EQ( findof4, STRING_NPOS ); EXPECT_EQ( findof5, STRING_NPOS ); EXPECT_EQ( findofofs, 4U ); EXPECT_EQ( findofofs2, 4U ); EXPECT_EQ( findofofs3, 8U ); EXPECT_EQ( findofofs4, STRING_NPOS ); EXPECT_EQ( findofofs5, STRING_NPOS ); EXPECT_EQ( findofofs6, 6U ); EXPECT_EQ( findofofs7, STRING_NPOS ); EXPECT_EQ( findofofs8, STRING_NPOS ); EXPECT_EQ( findofofs9, STRING_NPOS ); } { unsigned int findnotof = string_find_first_not_of( longstr, "testing ", 0 ); unsigned int findnotof2 = string_find_first_not_of( longstr, longstr, 0 ); unsigned int findnotof3 = string_find_first_not_of( shortstr, "", 0 ); unsigned int findnotofofs = string_find_first_not_of( longstr, "testing ", findnotof ); unsigned int findnotofofs2 = string_find_first_not_of( longstr, "testing ", findnotof + 1 ); unsigned int findnotofofs3 = string_find_first_not_of( longstr, "testing ", string_length( longstr ) ); unsigned int findnotofofs4 = string_find_first_not_of( shortstr, "", string_length( shortstr ) ); EXPECT_EQ( findnotof, 8U ); EXPECT_EQ( findnotof2, STRING_NPOS ); EXPECT_EQ( findnotof3, 0U ); EXPECT_EQ( findnotofofs, 8U ); EXPECT_EQ( findnotofofs2, 11U ); EXPECT_EQ( findnotofofs3, STRING_NPOS ); EXPECT_EQ( findnotofofs4, STRING_NPOS ); } { unsigned int findlastof = string_find_last_of( longstr, "xp", STRING_NPOS ); unsigned int findlastof2 = string_find_last_of( longstr, ";:", STRING_NPOS ); unsigned int findlastof3 = string_find_last_of( emptystr, "", STRING_NPOS ); unsigned int findlastof4 = string_find_last_of( shortstr, "", STRING_NPOS ); unsigned int findlastofofs = string_find_last_of( longstr, "xp", findlastof ); unsigned int findlastofofs2 = string_find_last_of( longstr, "xp", findlastof - 2 ); unsigned int findlastofofs3 = string_find_last_of( longstr, "xp", 0 ); unsigned int findlastofofs4 = string_find_last_of( emptystr, "", 0 ); unsigned int findlastofofs5 = string_find_last_of( shortstr, "", 5 ); unsigned int findlastofofs6 = string_find_last_of( shortstr, "", string_length( shortstr ) ); unsigned int findlastofofs7 = string_find_last_of( shortstr, "short", 5 ); EXPECT_EQ( findlastof, 59U ); EXPECT_EQ( findlastof2, STRING_NPOS ); EXPECT_EQ( findlastof3, STRING_NPOS ); EXPECT_EQ( findlastof4, STRING_NPOS ); EXPECT_EQ( findlastofofs, 59U ); EXPECT_EQ( findlastofofs2, 44U ); EXPECT_EQ( findlastofofs3, STRING_NPOS ); EXPECT_EQ( findlastofofs4, STRING_NPOS ); EXPECT_EQ( findlastofofs5, STRING_NPOS ); EXPECT_EQ( findlastofofs6, STRING_NPOS ); EXPECT_EQ( findlastofofs7, 4U ); } { unsigned int findlastnotof = string_find_last_not_of( longstr, " similar.", STRING_NPOS ); unsigned int findlastnotof2 = string_find_last_not_of( longstr, longstr, STRING_NPOS ); unsigned int findlastnotof3 = string_find_last_not_of( emptystr, "", STRING_NPOS ); unsigned int findlastnotof4 = string_find_last_not_of( shortstr, "", STRING_NPOS ); unsigned int findlastnotof5 = string_find_last_not_of( longstr, " similar", STRING_NPOS ); unsigned int findlastnotofofs = string_find_last_not_of( longstr, " similar.", findlastnotof ); unsigned int findlastnotofofs2 = string_find_last_not_of( longstr, " and similar.", findlastnotof - 1 ); unsigned int findlastnotofofs3 = string_find_last_not_of( longstr, longstr, 0 ); unsigned int findlastnotofofs4 = string_find_last_not_of( emptystr, "", 0 ); unsigned int findlastnotofofs5 = string_find_last_not_of( shortstr, "string", 5 ); unsigned int findlastnotofofs6 = string_find_last_not_of( shortstr, "string ", 5 ); unsigned int findlastnotofofs7 = string_find_last_not_of( shortstr, "", 5 ); unsigned int findlastnotofofs8 = string_find_last_not_of( longstr, "", string_length( longstr ) ); EXPECT_EQ( findlastnotof, 67U ); EXPECT_EQ( findlastnotof2, STRING_NPOS ); EXPECT_EQ( findlastnotof3, STRING_NPOS ); EXPECT_EQ( findlastnotof4, 11U ); EXPECT_EQ( findlastnotof5, 76U ); EXPECT_EQ( findlastnotofofs, 67U ); EXPECT_EQ( findlastnotofofs2, 63U ); EXPECT_EQ( findlastnotofofs3, STRING_NPOS ); EXPECT_EQ( findlastnotofofs4, STRING_NPOS ); EXPECT_EQ( findlastnotofofs5, 5U ); EXPECT_EQ( findlastnotofofs6, 2U ); EXPECT_EQ( findlastnotofofs7, 5U ); EXPECT_EQ( findlastnotofofs8, strlen( longstr ) - 1 ); } string_deallocate( emptystr ); string_deallocate( shortstr ); string_deallocate( longstr ); } return 0; }
void config_parse( stream_t* stream, hash_t filter_section, bool overwrite ) { char* buffer; hash_t section = 0; hash_t key = 0; unsigned int line = 0; #if BUILD_ENABLE_DEBUG_CONFIG log_debugf( HASH_CONFIG, "Parsing config stream: %s", stream_path( stream ) ); #endif buffer = memory_allocate_zero( 1024ULL, 0, MEMORY_TEMPORARY ); while( !stream_eos( stream ) ) { ++line; stream_read_line_buffer( stream, buffer, 1024, '\n' ); string_strip( buffer, " \t\n\r" ); if( !string_length( buffer ) || ( buffer[0] == ';' ) || ( buffer[0] == '#' ) ) continue; if( buffer[0] == '[' ) { //Section declaration unsigned int endpos = string_rfind( buffer, ']', string_length( buffer ) - 1 ); if( ( endpos == STRING_NPOS ) || ( endpos < 1 ) ) { log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid section declaration on line %d in config stream '%s'", line, stream_path( stream ) ); continue; } buffer[endpos] = 0; section = hash( buffer + 1, endpos - 1 ); #if BUILD_ENABLE_DEBUG_CONFIG log_debugf( HASH_CONFIG, " config: section set to '%s' (0x%llx)", buffer + 1, section ); #endif } else if( !filter_section || ( filter_section == section ) ) { //name=value declaration char* name; char* value; unsigned int separator = string_find( buffer, '=', 0 ); if( separator == STRING_NPOS ) { log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid value declaration on line %d in config stream '%s', missing assignment operator '=': %s", line, stream_path( stream ), buffer ); continue; } name = string_strip_substr( buffer, " \t", separator ); value = string_strip( buffer + separator + 1, " \t" ); if( !string_length( name ) ) { log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid value declaration on line %d in config stream '%s', empty name string", line, stream_path( stream ) ); continue; } key = hash( name, string_length( name ) ); if( overwrite || !config_key( section, key, false ) ) { #if BUILD_ENABLE_DEBUG_CONFIG log_debugf( HASH_CONFIG, " config: %s (0x%llx) = %s", name, key, value ); #endif if( !string_length( value ) ) config_set_string( section, key, "" ); else if( string_equal( value, "false" ) ) config_set_bool( section, key, false ); else if( string_equal( value, "true" ) ) config_set_bool( section, key, true ); else if( ( string_find( value, '.', 0 ) != STRING_NPOS ) && ( string_find_first_not_of( value, "0123456789.", 0 ) == STRING_NPOS ) && ( string_find( value, '.', string_find( value, '.', 0 ) + 1 ) == STRING_NPOS ) ) //Exactly one "." config_set_real( section, key, string_to_real( value ) ); else if( string_find_first_not_of( value, "0123456789", 0 ) == STRING_NPOS ) config_set_int( section, key, string_to_int64( value ) ); else config_set_string( section, key, value ); } } } memory_deallocate( buffer ); }
char* path_make_absolute( const char* path ) { unsigned int up, last, length, protocollen; char* abspath = string_clone( path ); if( !path_is_absolute( abspath ) ) { abspath = string_prepend( abspath, "/" ); abspath = string_prepend( abspath, environment_current_working_directory() ); abspath = path_clean( abspath, true ); } else { abspath = path_clean( abspath, true ); } protocollen = string_find_string( abspath, "://", 0 ); if( protocollen != STRING_NPOS ) protocollen += 3; //Also skip the "://" separator else protocollen = 0; //Deal with .. references while( ( up = string_find_string( abspath, "/../", 0 ) ) != STRING_NPOS ) { char* subpath; if( ( protocollen && ( up == ( protocollen - 1 ) ) ) || ( !protocollen && ( up == 0 ) ) ) { //This moves mem so "prot://../path" ends up as "prot://path" memmove( abspath + protocollen, abspath + 3 + protocollen, string_length( abspath ) + 1 - ( 3 + protocollen ) ); continue; } last = string_rfind( abspath, '/', up - 1 ); if( last == STRING_NPOS ) { //Must be a path like C:/../something since other absolute paths last = up; } subpath = string_substr( abspath, 0, last ); subpath = string_append( subpath, abspath + up + 3 ); // +3 will include the / of the later part of the path string_deallocate( abspath ); abspath = subpath; } length = string_length( abspath ); if( length >= 3 ) { while( ( length >= 3 ) && ( abspath[length-3] == '/' ) && ( abspath[length-2] == '.' ) && ( abspath[length-1] == L'.' ) ) { //Step up if( length == 3 ) { abspath[1] = 0; length = 1; } else { length = string_rfind( abspath, '/', length - 4 ); abspath[length] = 0; } } } return abspath; }
char* path_clean( char* path, bool absolute ) { //Since this function is used a lot we want to perform as much operations //in place instead of splicing up into a string array and remerge char* replace; char* inpath; char* next; unsigned int inlength, length, remain, protocollen, up, last_up, prev_up, driveofs; if( !path ) return string_allocate( 0 ); inpath = path; inlength = string_length( path ); protocollen = string_find_string( path, "://", 0 ); if( ( protocollen != STRING_NPOS ) && ( protocollen > 1 ) ) { absolute = true; protocollen += 3; //Also skip the "://" separator inlength -= protocollen; path += protocollen; } else { protocollen = 0; } length = inlength; driveofs = 0; replace = path; while( ( replace = strchr( replace, '\\' ) ) != 0 ) *replace++ = '/'; remain = length; replace = path; while( ( next = strstr( replace, "/./" ) ) != 0 ) { remain -= (unsigned int)( next - replace ) + 2; length -= 2; memmove( next + 1, next + 3, remain ); //Include terminating zero to avoid looping when string ends in "/./" replace = next; } remain = length; replace = path; while( ( next = strstr( replace, "//" ) ) != 0 ) { remain -= (unsigned int)( next - replace ) + 1; --length; memmove( next + 1, next + 2, remain ); //Include terminating zero to avoid looping when string ends in "//" replace = next; } path[length] = 0; if( string_equal( path, "." ) ) { length = 0; path[0] = 0; } else if( length > 1 ) { if( ( path[ length - 2 ] == '/' ) && ( path[ length - 1 ] == '.' ) ) { path[ length - 2 ] = 0; length -= 2; } if( string_equal( path, "." ) ) { length = 0; path[0] = 0; } else if( string_equal( path, "./" ) ) { length = 1; path[0] = '/'; path[1] = 0; } else if( ( length > 1 ) && ( path[0] == '.' ) && ( path[1] == '/' ) ) { --length; memmove( path, path + 1, length ); path[length] = 0; } } if( absolute ) { if( !length ) { if( !inlength ) { inlength = 2; inpath = memory_reallocate( inpath, inlength + protocollen + 1, 0, protocollen + 1 ); path = inpath + protocollen; } path[0] = '/'; path[1] = 0; ++length; } else if( ( length >= 2 ) && ( path[1] == ':' ) ) { driveofs = 2; //Make sure first character is upper case if( ( path[0] >= 'a' ) && ( path[0] <= 'z' ) ) path[0] = ( path[0] - (char)( (int)'a' - (int)'A' ) ); if( length == 2 ) { if( inlength <= 2 ) { inpath = memory_reallocate( inpath, inlength + 2 + protocollen + 1, 0, inlength + protocollen + 1 ); inlength += 2; path = inpath + protocollen; } path[2] = '/'; ++length; } else if( path[2] != '/' ) { //splice in slash in weird-format paths (C:foo/bar/...) if( inlength < ( length + 1 ) ) { //Need more space inpath = memory_reallocate( inpath, length + protocollen + 2, 0, inlength + protocollen + 1 ); inlength = length + 1; path = inpath + protocollen; } memmove( path + 3, path + 2, length + 1 - 2 ); path[2] = '/'; ++length; } } else if( !protocollen && ( path[0] != '/' ) ) { //make sure capacity is enough to hold additional character if( inlength < ( length + 1 ) ) { //Need more space inpath = memory_reallocate( inpath, length + protocollen + 2, 0, inlength + protocollen + 1 ); inlength = length + 1; path = inpath + protocollen; } memmove( path + 1, path, length + 1 ); path[0] = '/'; ++length; } } else //relative { if( length && ( path[0] == '/' ) ) { memmove( path, path + 1, length - 1 ); --length; } } //Deal with .. references last_up = driveofs; while( ( up = string_find_string( path, "/../", last_up ) ) != STRING_NPOS ) { if( up >= length ) break; if( up == driveofs ) { if( absolute ) { memmove( path + driveofs + 1, path + driveofs + 4, length - ( driveofs + 3 ) ); length -= 3; } else { last_up = driveofs + 3; } continue; } prev_up = string_rfind( path, '/', up - 1 ); if( prev_up == STRING_NPOS ) { if( absolute ) { memmove( path, path + up + 3, length - up - 2 ); length -= ( up + 3 ); } else { memmove( path, path + up + 4, length - up - 3 ); length -= ( up + 4 ); } } else if( prev_up >= last_up ) { memmove( path + prev_up, path + up + 3, length - up - 2 ); length -= ( up - prev_up + 3 ); } else { last_up = up + 1; } } if( length > 1 ) { if( path[ length - 1 ] == '/' ) { path[ length - 1 ] = 0; --length; } } if( protocollen ) { if( path[0] == '/' ) { if( length == 1 ) length = 0; else { memmove( path, path + 1, length ); --length; } } length += protocollen; path = inpath; } path[length] = 0; return path; }
unsigned int stacktrace_capture( void** trace, unsigned int max_depth, unsigned int skip_frames ) { unsigned int num_frames = 0; if( !trace ) return 0; if( !max_depth ) max_depth = BUILD_SIZE_STACKTRACE_DEPTH; if( max_depth > BUILD_SIZE_STACKTRACE_DEPTH ) max_depth = BUILD_SIZE_STACKTRACE_DEPTH; if( !_stackwalk_initialized ) { if( !_initialize_stackwalker() ) { memset( trace, 0, sizeof( void* ) * max_depth ); return num_frames; } } #if FOUNDATION_PLATFORM_WINDOWS && ( FOUNDATION_COMPILER_MSVC || FOUNDATION_COMPILER_INTEL ) // Add 1 skip frame for this function call ++skip_frames; # if USE_CAPTURESTACKBACKTRACE if( CallRtlCaptureStackBackTrace ) { void* local_trace[BUILD_SIZE_STACKTRACE_DEPTH]; if( max_depth + skip_frames > BUILD_SIZE_STACKTRACE_DEPTH ) max_depth = BUILD_SIZE_STACKTRACE_DEPTH - skip_frames; num_frames = (unsigned int)CallRtlCaptureStackBackTrace( skip_frames, max_depth, local_trace, 0 ); if( num_frames > max_depth ) num_frames = max_depth; memcpy( trace, local_trace, sizeof( void* ) * num_frames ); memset( trace + num_frames, 0, sizeof( void* ) * ( max_depth - num_frames ) ); } else { # else { # endif # if FOUNDATION_PLATFORM_ARCH_X86_64 // Raise an exception so helper has access to context record. __try { RaiseException( 0, // Application-defined exception code. 0, // Zero indicates continuable exception. 0, // Number of arguments in args array (ignored if args is null) 0 ); // Array of arguments } __except( _capture_stack_trace_helper( trace, max_depth, skip_frames, (GetExceptionInformation())->ContextRecord ) ) { } # else // Use a bit of inline assembly to capture the information relevant to stack walking which is // basically EIP and EBP. CONTEXT context; memset( &context, 0, sizeof( CONTEXT ) ); context.ContextFlags = CONTEXT_FULL; log_warnf( WARNING_DEPRECATED, "********** REIMPLEMENT FALLBACK STACKTRACE **********" ); /* Use a fake function call to pop the return address and retrieve EIP.*/ __asm { call FakeStackTraceCall FakeStackTraceCall: pop eax mov context.Eip, eax mov context.Ebp, ebp mov context.Esp, esp } // Capture the back trace. _capture_stack_trace_helper( trace, max_depth, skip_frames, &context ); # endif } #elif FOUNDATION_PLATFORM_APPLE //TODO: Implement #elif FOUNDATION_PLATFORM_POSIX // Add 1 skip frames for this function call skip_frames += 1; void* localframes[BUILD_SIZE_STACKTRACE_DEPTH]; num_frames = (unsigned int)backtrace( localframes, BUILD_SIZE_STACKTRACE_DEPTH ); if( num_frames > skip_frames ) { num_frames -= skip_frames; if( num_frames > max_depth ) num_frames = max_depth; memcpy( trace, localframes + skip_frames, sizeof( void* ) * num_frames ); } else trace[0] = 0; #endif return num_frames; } static bool _symbol_resolve_initialized = false; static bool _initialize_symbol_resolve() { if( _symbol_resolve_initialized ) return true; #if FOUNDATION_PLATFORM_WINDOWS { unsigned int options; void* dll = LoadLibraryA( "PSAPI.DLL" ); if( !dll ) return _symbol_resolve_initialized; CallEnumProcesses = (EnumProcessesFn)GetProcAddress( dll, "EnumProcesses" ); CallEnumProcessModules = (EnumProcessModulesFn)GetProcAddress( dll, "EnumProcessModules" ); CallGetModuleFileNameEx = (GetModuleFileNameExFn)GetProcAddress( dll, "GetModuleFileNameExA" ); CallGetModuleBaseName = (GetModuleBaseNameFn)GetProcAddress( dll, "GetModuleBaseNameA" ); CallGetModuleInformation = (GetModuleInformationFn)GetProcAddress( dll, "GetModuleInformation" ); if( !CallEnumProcesses || !CallEnumProcessModules || !CallGetModuleFileNameEx || !CallGetModuleBaseName || !CallGetModuleInformation ) return _symbol_resolve_initialized; dll = LoadLibraryA( "DBGHELP.DLL" ); if( !dll ) return _symbol_resolve_initialized; CallSymInitialize = (SymInitializeFn)GetProcAddress( dll, "SymInitialize" ); CallSymSetOptions = (SymSetOptionsFn)GetProcAddress( dll, "SymSetOptions" ); CallSymGetOptions = (SymGetOptionsFn)GetProcAddress( dll, "SymGetOptions" ); CallSymLoadModule64 = (SymLoadModule64Fn)GetProcAddress( dll, "SymLoadModule64" ); CallSymSetSearchPath = (SymSetSearchPathFn)GetProcAddress( dll, "SymSetSearchPath" ); CallSymGetModuleInfo64 = (SymGetModuleInfo64Fn)GetProcAddress( dll, "SymGetModuleInfo64" ); CallSymGetLineFromAddr64 = (SymGetLineFromAddr64Fn)GetProcAddress( dll, "SymGetLineFromAddr64" ); CallSymGetSymFromAddr64 = (SymGetSymFromAddr64Fn)GetProcAddress( dll, "SymGetSymFromAddr64" ); CallSymGetModuleBase64 = (SymGetModuleBase64Fn)GetProcAddress( dll, "SymGetModuleBase64" ); CallSymFunctionTableAccess64 = (SymFunctionTableAccess64Fn)GetProcAddress( dll, "SymFunctionTableAccess64" ); if( !CallSymInitialize || !CallSymSetOptions || !CallSymGetOptions || !CallSymLoadModule64 || !CallSymSetSearchPath || !CallSymGetModuleInfo64 || !CallSymGetLineFromAddr64 || !CallSymGetSymFromAddr64 || !CallSymGetModuleBase64 || !CallSymFunctionTableAccess64 ) return _symbol_resolve_initialized; options = CallSymGetOptions(); options |= SYMOPT_LOAD_LINES; options |= SYMOPT_DEBUG; options |= SYMOPT_UNDNAME; options |= SYMOPT_LOAD_LINES; options |= SYMOPT_FAIL_CRITICAL_ERRORS; options |= SYMOPT_DEFERRED_LOADS; options |= SYMOPT_ALLOW_ABSOLUTE_SYMBOLS; options |= SYMOPT_EXACT_SYMBOLS; options |= SYMOPT_CASE_INSENSITIVE; CallSymSetOptions( options ); CallSymInitialize( GetCurrentProcess(), 0, TRUE ); } _load_process_modules(); _symbol_resolve_initialized = true; #else _symbol_resolve_initialized = true; #endif return _symbol_resolve_initialized; } static NOINLINE char** _resolve_stack_frames( void** frames, unsigned int max_frames ) { #if FOUNDATION_PLATFORM_WINDOWS char** lines = 0; char symbol_buffer[ sizeof( IMAGEHLP_SYMBOL64 ) + 512 ]; PIMAGEHLP_SYMBOL64 symbol; DWORD displacement = 0; uint64_t displacement64 = 0; unsigned int iaddr = 0; unsigned int last_error; bool found = false; HANDLE process_handle = GetCurrentProcess(); int buffer_offset = 0; bool last_was_main = false; IMAGEHLP_LINE64 line64; IMAGEHLP_MODULE64 module64; for( iaddr = 0; ( iaddr < max_frames ) && !last_was_main; ++iaddr ) { char* resolved = 0; const char* function_name = "??"; const char* file_name = "??"; const char* module_name = "??"; unsigned int line_number = 0; //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; // Initialize symbol. symbol = (PIMAGEHLP_SYMBOL64)symbol_buffer; memset( symbol, 0, sizeof( symbol_buffer ) ); symbol->SizeOfStruct = sizeof( symbol_buffer ); symbol->MaxNameLength = 512; // Get symbol from address. if( CallSymGetSymFromAddr64 && CallSymGetSymFromAddr64( process_handle, (uint64_t)((uintptr_t)frames[iaddr]), &displacement64, symbol ) ) { int offset = 0; while( symbol->Name[offset] < 32 ) ++offset; function_name = symbol->Name + offset; } else { // No symbol found for this address. last_error = GetLastError(); } memset( &line64, 0, sizeof( line64 ) ); line64.SizeOfStruct = sizeof( line64 ); if( CallSymGetLineFromAddr64 && CallSymGetLineFromAddr64( process_handle, (uint64_t)((uintptr_t)frames[iaddr]), &displacement, &line64 ) ) { file_name = line64.FileName; line_number = line64.LineNumber; } memset( &module64, 0, sizeof( module64 ) ); module64.SizeOfStruct = sizeof( module64 ); if( CallSymGetModuleInfo64 && CallSymGetModuleInfo64( process_handle, (uint64_t)((uintptr_t)frames[iaddr]), &module64 ) ) { int last_slash = STRING_NPOS; module_name = module64.ImageName; last_slash = string_rfind( module_name, '\\', STRING_NPOS ); if( last_slash != STRING_NPOS ) module_name += last_slash + 1; } resolved = string_format( "[" STRING_FORMAT_POINTER "] %s (%s:%d +%d bytes) [in %s]", frames[iaddr], function_name, file_name, line_number, displacement, module_name ); array_push( lines, resolved ); if( string_equal( function_name, "main" ) ) last_was_main = true; } return lines; #elif FOUNDATION_PLATFORM_LINUX char** addrs = 0; char** lines = 0; const char** args = 0; process_t* proc = process_allocate(); unsigned int num_frames = 0; unsigned int requested_frames = 0; bool last_was_main = false; if( !string_length( environment_executable_path() ) ) { for( unsigned int iaddr = 0; iaddr < max_frames; ++iaddr ) { //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; array_push( lines, string_format( "[" STRING_FORMAT_POINTER "]", frames[iaddr] ) ); } return lines; } array_push( args, "-e" ); array_push( args, environment_executable_path() ); array_push( args, "-f" ); for( unsigned int iaddr = 0; iaddr < max_frames; ++iaddr ) { //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; char* addr = string_format( STRING_FORMAT_POINTER, frames[iaddr] ); array_push( addrs, addr ); array_push( args, addr ); ++requested_frames; } process_set_working_directory( proc, environment_initial_working_directory() ); process_set_executable_path( proc, "/usr/bin/addr2line" ); process_set_arguments( proc, args, array_size( args ) ); process_set_flags( proc, PROCESS_ATTACHED | PROCESS_STDSTREAMS ); process_spawn( proc ); stream_t* procout = process_stdout( proc ); while( !stream_eos( procout ) && ( num_frames < requested_frames ) && !last_was_main ) { char* function = stream_read_line( procout, '\n' ); char* filename = stream_read_line( procout, '\n' ); array_push( lines, string_format( "[" STRING_FORMAT_POINTER "] %s (%s)", frames[num_frames], function && string_length( function ) ? function : "??", filename && string_length( filename ) ? filename : "??" ) ); if( string_equal( function, "main" ) ) last_was_main = true; string_deallocate( function ); string_deallocate( filename ); ++num_frames; } process_wait( proc ); process_deallocate( proc ); string_array_deallocate( addrs ); array_deallocate( args ); return lines; #else char** lines = 0; for( unsigned int iaddr = 0; iaddr < max_frames; ++iaddr ) { //Allow first frame to be null in case of a function call to a null pointer if( iaddr && !frames[iaddr] ) break; array_push( lines, string_format( "[" STRING_FORMAT_POINTER "]\n", frames[iaddr] ) ); } return lines; #endif }