diff --git a/.cirrus.yml b/.cirrus.yml index a09ed95051..fde5147ea7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,6 +39,7 @@ freebsd_task: "CXX_PATH=`which ${CXX}`", "cd test", "echo \"using ${TEST_TOOLSET} : : ${CXX_PATH} ;\" > ${HOME}/user-config.jam", + "python3 grep.py ${TEST_TOOLSET}", "python3 test_all.py ${TEST_TOOLSET}", "cd ..", ] diff --git a/README.adoc b/README.adoc index 5bc9056a95..63722c83fa 100644 --- a/README.adoc +++ b/README.adoc @@ -20,7 +20,7 @@ Continuously tested on: * Linux GCC 9, 10, 11, 12 * macOS Xcode 11.7, 12.4, 12.5.1, 13.4.1, 14.0.1, 14.1, 14.2 * Windows MinGW 8.1.0 -* Windows VS 2013, 2015, 2017, 2019, 2022 +* Windows 2015, 2017, 2019, 2022 * Cygwin 3.1.7 x64 * Ubuntu 20.04 GCC 9 (armhf, arm64, ppc64el) * Debian 11 GCC 10 (armhf) diff --git a/appveyor.yml b/appveyor.yml index 6b8233e978..933ab88fd9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ # subject to the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # -# Copyright Rene Ferdinand Rivera Morell 2015-2020. +# Copyright Rene Ferdinand Rivera Morell 2015-2023. branches: only: @@ -11,6 +11,15 @@ branches: - /feature\/.*/ - /backport-.*/ +skip_commits: + files: + - ".circleci/*" + - ".cirrus.yml" + - ".drone.star" + - ".github/workflows/*" + - ".semaphore/*" + - "azure-pipelines.yml" + environment: matrix: - job_name: 'Visual Studio 2017, Test' @@ -23,11 +32,6 @@ environment: TOOLSET: vc14 TEST_TOOLSET: msvc-14.0 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - job_name: 'Visual Studio 2013, Test' - job_group: 'Test' - TOOLSET: vc12 - TEST_TOOLSET: msvc-12.0 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - job_name: 'Clang 9 (VS2015), Test' job_group: 'Test' TOOLSET: clang-win diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8c08d02519..4b0f9178f6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -99,6 +99,7 @@ stages: Clang ${{variables.clang_latest}} (VS${{variables.vs_latest}}): {TOOLSET: clang-win, TEST_TOOLSET: clang-win, VM_IMAGE: "${{variables.windows_latest_vm}}"} pool: vmImage: $(VM_IMAGE) + continueOnError: 'true' steps: - template: .ci/azp-windows-test.yml diff --git a/src/engine/builtins.cpp b/src/engine/builtins.cpp index df03162bc0..ec90962014 100644 --- a/src/engine/builtins.cpp +++ b/src/engine/builtins.cpp @@ -491,7 +491,6 @@ LIST * builtin_calc( FRAME * frame, int flags ) long lhs_value; long rhs_value; long result_value; - char buffer[ 16 ]; char const * lhs; char const * op; char const * rhs; @@ -519,8 +518,7 @@ LIST * builtin_calc( FRAME * frame, int flags ) else return L0; - sprintf( buffer, "%ld", result_value ); - result = list_push_back( result, object_new( buffer ) ); + result = list_push_back( result, b2::value::as_string(result_value) ); return result; } @@ -1408,10 +1406,8 @@ LIST * builtin_backtrace( FRAME * frame, int flags ) { char const * file; int line; - char buf[ 32 ]; string module_name[ 1 ]; get_source_line( frame, &file, &line ); - sprintf( buf, "%d", line ); string_new( module_name ); if ( frame->module->name ) { @@ -1419,7 +1415,7 @@ LIST * builtin_backtrace( FRAME * frame, int flags ) string_append( module_name, "." ); } result = list_push_back( result, object_new( file ) ); - result = list_push_back( result, object_new( buf ) ); + result = list_push_back( result, b2::value::as_string(line) ); result = list_push_back( result, object_new( module_name->value ) ); result = list_push_back( result, object_new( frame->rulename ) ); string_free( module_name ); @@ -1695,12 +1691,10 @@ LIST * builtin_nearest_user_location( FRAME * frame, int flags ) LIST * result = L0; char const * file; int line; - char buf[ 32 ]; get_source_line( nearest_user_frame, &file, &line ); - sprintf( buf, "%d", line ); result = list_push_back( result, object_new( file ) ); - result = list_push_back( result, object_new( buf ) ); + result = list_push_back( result, b2::value::as_string(line) ); return result; } } @@ -1730,8 +1724,13 @@ LIST * builtin_md5( FRAME * frame, int flags ) md5_append( &state, (md5_byte_t const *)s, strlen( s ) ); md5_finish( &state, digest ); + static const char hex_digit[] = "0123456789abcdef"; for ( di = 0; di < 16; ++di ) - sprintf( hex_output + di * 2, "%02x", digest[ di ] ); + { + hex_output[di*2+0] = hex_digit[digest[di]>>4]; + hex_output[di*2+1] = hex_digit[digest[di]&0xF]; + } + hex_output[16*2] = '\0'; return list_new( object_new( hex_output ) ); } @@ -1742,7 +1741,6 @@ LIST * builtin_file_open( FRAME * frame, int flags ) char const * name = object_str( list_front( lol_get( frame->args, 0 ) ) ); char const * mode = object_str( list_front( lol_get( frame->args, 1 ) ) ); int fd; - char buffer[ sizeof( "4294967295" ) ]; if ( strcmp(mode, "t") == 0 ) { @@ -1772,8 +1770,7 @@ LIST * builtin_file_open( FRAME * frame, int flags ) if ( fd != -1 ) { - sprintf( buffer, "%d", fd ); - return list_new( object_new( buffer ) ); + return list_new( b2::value::as_string(fd) ); } return L0; } @@ -2114,8 +2111,7 @@ LIST * builtin_shell( FRAME * frame, int flags ) /* Harmonize VMS success status with POSIX */ if ( exit_status == 1 ) exit_status = EXIT_SUCCESS; #endif - sprintf( buffer, "%d", exit_status ); - result = list_push_back( result, object_new( buffer ) ); + result = list_push_back( result, b2::value::as_string(exit_status) ); } return result; diff --git a/src/engine/config.h b/src/engine/config.h index 99e153ec05..a732d7349a 100644 --- a/src/engine/config.h +++ b/src/engine/config.h @@ -2,7 +2,7 @@ #define B2_CONFIG_H /* -Copyright 2002-2021 Rene Rivera. +Copyright 2002-2023 Rene Rivera. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or copy at https://www.bfgroup.xyz/b2/LICENSE.txt) @@ -42,38 +42,13 @@ Distributed under the Boost Software License, Version 1.0. #define _FILE_OFFSET_BITS 64 #endif -// Correct missing types in some earlier compilers.. - -#include -#ifndef INT32_MIN - -// VS 2013 is barely C++11/C99. And opts to not provide specific sized int -// types. Provide a generic implementation of the sizes we use. -#if UINT_MAX == 0xffffffff -typedef int int32_t; -#elif (USHRT_MAX == 0xffffffff) -typedef short int32_t; -#elif ULONG_MAX == 0xffffffff -typedef long int32_t; -#endif - -#endif - // Account for incomplete C++ standard implementations. -// VS 2012 doesn't implement noexcept. -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define B2_NOEXCEPT -#endif - #ifndef B2_NOEXCEPT #define B2_NOEXCEPT noexcept #endif // Indicate if we can use std::thread and friends. -#if defined(_MSC_VER) && _MSC_VER <= 1800 -#define B2_USE_STD_THREADS 0 -#endif #ifndef B2_USE_STD_THREADS #define B2_USE_STD_THREADS 1 #endif diff --git a/src/engine/debugger.cpp b/src/engine/debugger.cpp index c9b87cf267..5b10bb4f26 100644 --- a/src/engine/debugger.cpp +++ b/src/engine/debugger.cpp @@ -1108,7 +1108,6 @@ static void debug_parent_copy_breakpoints( void ) static void debug_start_child( int argc, const char * * argv ) { #if NT - char buf[ 80 ]; HANDLE pipe1[ 2 ]; HANDLE pipe2[ 2 ]; string self[ 1 ]; @@ -1143,12 +1142,10 @@ static void debug_start_child( int argc, const char * * argv ) string_copy( command_line, "b2 " ); /* Pass the handles as the first and second arguments. */ string_append( command_line, debugger_opt ); - sprintf( buf, "%p", pipe1[ 0 ] ); - string_append( command_line, buf ); + string_append( command_line, b2::value::format( "%p", pipe1[ 0 ] )->str() ); string_push_back( command_line, ' ' ); string_append( command_line, debugger_opt ); - sprintf( buf, "%p", pipe2[ 1 ] ); - string_append( command_line, buf ); + string_append( command_line, b2::value::format( "%p", pipe2[ 1 ] )->str() ); /* Pass the rest of the command line. */ { int i; @@ -1495,7 +1492,6 @@ static void debug_parent_delete( int argc, const char * * argv ) static void debug_parent_clear( int argc, const char * * argv ) { - char buf[ 16 ]; const char * new_args[ 2 ]; int id; if ( argc < 2 ) @@ -1520,9 +1516,9 @@ static void debug_parent_clear( int argc, const char * * argv ) printf( "Deleted breakpoint %d\n", id ); } - sprintf( buf, "%d", id ); + auto id_s = std::to_string(id); new_args[ 0 ] = "delete"; - new_args[ 1 ] = buf; + new_args[ 1 ] = id_s.c_str(); debug_parent_delete( 2, new_args ); } @@ -1577,9 +1573,8 @@ static void debug_parent_backtrace( int argc, const char * * argv ) for ( i = 0; i < depth; ++i ) { FRAME_INFO frame; - char buf[ 16 ]; - sprintf( buf, "%d", i ); - new_args[ 2 ] = buf; + auto i_s = std::to_string(i); + new_args[ 2 ] = i_s.c_str(); debug_parent_forward_nowait( 3, new_args, 0, 0 ); debug_frame_read( command_child, &frame ); printf( "#%d in ", i ); @@ -1937,10 +1932,9 @@ static void debug_mi_break_insert( int argc, const char * * argv ) if ( disabled ) { - char buf[ 80 ]; - sprintf( buf, "%d", num_breakpoints ); + auto num_breakpoints_s = std::to_string(num_breakpoints); inner_argv[ 0 ] = "disable"; - inner_argv[ 1 ] = buf; + inner_argv[ 1 ] = num_breakpoints_s.c_str(); debug_child_disable( 2, inner_argv ); debug_parent_forward_nowait( 2, inner_argv, 1, 0 ); } diff --git a/src/engine/execcmd.cpp b/src/engine/execcmd.cpp index dfbd5a7f8a..c25416f3da 100644 --- a/src/engine/execcmd.cpp +++ b/src/engine/execcmd.cpp @@ -43,8 +43,6 @@ static int intr; void argv_from_shell( char const * * argv, LIST * shell, char const * command, int32_t const slot ) { - static char jobno[ 12 ]; - int i; int gotpercent = 0; LISTITER iter = list_begin( shell ); @@ -52,14 +50,14 @@ void argv_from_shell( char const * * argv, LIST * shell, char const * command, assert( 0 <= slot ); assert( slot < 999 ); - sprintf( jobno, "%d", slot + 1 ); + auto jobno = b2::value::as_string( slot + 1 ); for ( i = 0; iter != end && i < MAXARGC; ++i, iter = list_next( iter ) ) { switch ( object_str( list_item( iter ) )[ 0 ] ) { case '%': argv[ i ] = command; ++gotpercent; break; - case '!': argv[ i ] = jobno; break; + case '!': argv[ i ] = jobno->str(); break; default : argv[ i ] = object_str( list_item( iter ) ); } } diff --git a/src/engine/execnt.cpp b/src/engine/execnt.cpp index 1cf627f2fc..28c3a86078 100644 --- a/src/engine/execnt.cpp +++ b/src/engine/execnt.cpp @@ -1219,9 +1219,8 @@ static FILE * open_command_file( int32_t const slot ) DWORD const procID = GetCurrentProcessId(); string const * const tmpdir = path_tmpdir(); string_new( command_file ); - string_reserve( command_file, tmpdir->size + 64 ); - command_file->size = sprintf( command_file->value, - "%s\\jam%lu-%02d-##.bat", tmpdir->value, procID, slot ); + string_copy( command_file, b2::value::format( "%s\\jam%lu-%02d-##.bat", + tmpdir->value, procID, slot )->str() ); } /* For some reason opening a command file can fail intermittently. But doing @@ -1321,7 +1320,6 @@ static void string_new_from_argv( string * result, char const * const * argv ) static void reportWindowsError( char const * const apiName, int32_t slot ) { char * errorMessage; - char buf[24]; string * err_buf; timing_info time; DWORD const errorCode = GetLastError(); @@ -1343,8 +1341,8 @@ static void reportWindowsError( char const * const apiName, int32_t slot ) err_buf = cmdtab[ slot ].buffer_out; string_append( err_buf, apiName ); string_append( err_buf, "() Windows API failed: " ); - sprintf( buf, "%lu", errorCode ); - string_append( err_buf, buf ); + auto errorCode_s = std::to_string( errorCode ); + string_append( err_buf, errorCode_s.c_str() ); if ( !apiResult ) string_append( err_buf, ".\n" ); diff --git a/src/engine/filent.cpp b/src/engine/filent.cpp index faf4833554..cfe369e010 100644 --- a/src/engine/filent.cpp +++ b/src/engine/filent.cpp @@ -367,7 +367,6 @@ void file_archscan( char const * arch, scanback func, void * closure ) { FILELISTITER iter = filelist_begin( archive->members ); FILELISTITER const end = filelist_end( archive->members ); - char buf[ MAXJPATH ]; for ( ; iter != end ; iter = filelist_next( iter ) ) { @@ -375,11 +374,10 @@ void file_archscan( char const * arch, scanback func, void * closure ) /* Construct member path: 'archive-path(member-name)' */ - sprintf( buf, "%s(%s)", - object_str( archive->file->name ), - object_str( member_file->name ) ); { - OBJECT * member = object_new( buf ); + OBJECT * member = b2::value::format( "%s(%s)", + object_str( archive->file->name ), + object_str( member_file->name ) ); (*func)( closure, member, 1 /* time valid */, &member_file->time ); object_free( member ); } @@ -486,9 +484,9 @@ int file_collect_archive_content_( file_archive_info_t * const archive ) name = c + 1; } - sprintf( buf, "%.*s", int(endname - name), name ); + auto member_name = b2::value::format( "%.*s", int(endname - name), name ); - if ( strcmp( buf, "") != 0 ) + if ( member_name->as_string().size > 0 ) { file_info_t * member = 0; @@ -497,7 +495,7 @@ int file_collect_archive_content_( file_archive_info_t * const archive ) * Here we reverse the stored sequence by pushing members to front of * member file list to get the intended members order. */ - archive->members = filelist_push_front( archive->members, object_new( buf ) ); + archive->members = filelist_push_front( archive->members, member_name ); member = filelist_front( archive->members ); member->is_file = 1; member->is_dir = 0; diff --git a/src/engine/filesys.cpp b/src/engine/filesys.cpp index d6728e0a93..98e1aabe87 100644 --- a/src/engine/filesys.cpp +++ b/src/engine/filesys.cpp @@ -397,7 +397,6 @@ static void file_archivescan_impl( OBJECT * path, archive_scanback func, void * { FILELISTITER iter = filelist_begin( archive->members ); FILELISTITER const end = filelist_end( archive->members ); - char buf[ MAXJPATH ]; for ( ; iter != end ; iter = filelist_next( iter ) ) { @@ -406,12 +405,10 @@ static void file_archivescan_impl( OBJECT * path, archive_scanback func, void * /* Construct member path: 'archive-path(member-name)' */ - sprintf( buf, "%s(%s)", - object_str( archive->file->name ), - object_str( member_file->name ) ); - { - OBJECT * member = object_new( buf ); + OBJECT * member = b2::value::format( "%s(%s)", + object_str( archive->file->name ), + object_str( member_file->name ) ); (*func)( closure, member, symbols, 1, &member_file->time ); object_free( member ); } diff --git a/src/engine/fileunix.cpp b/src/engine/fileunix.cpp index 6cde3f695f..3a7907eadb 100644 --- a/src/engine/fileunix.cpp +++ b/src/engine/fileunix.cpp @@ -229,7 +229,6 @@ void file_archscan( char const * arch, scanback func, void * closure ) { FILELISTITER iter = filelist_begin( archive->members ); FILELISTITER const end = filelist_end( archive->members ); - char buf[ MAXJPATH ]; for ( ; iter != end ; iter = filelist_next( iter ) ) { @@ -237,11 +236,10 @@ void file_archscan( char const * arch, scanback func, void * closure ) /* Construct member path: 'archive-path(member-name)' */ - sprintf( buf, "%s(%s)", - object_str( archive->file->name ), - object_str( member_file->name ) ); { - OBJECT * member = object_new( buf ); + OBJECT * member = b2::value::format( "%s(%s)", + object_str( archive->file->name ), + object_str( member_file->name ) ); (*func)( closure, member, 1 /* time valid */, &member_file->time ); object_free( member ); } @@ -354,13 +352,13 @@ int file_collect_archive_content_( file_archive_info_t * const archive ) if ( DEBUG_BINDSCAN ) out_printf( "archive name %s found\n", lar_name ); - sprintf( buf, "%s", lar_name ); + auto name = b2::value::format( "%s", lar_name ); - if ( strcmp( buf, "") != 0 ) + if ( name->as_string().size > 0 ) { file_info_t * member = 0; - archive->members = filelist_push_back( archive->members, object_new( buf ) ); + archive->members = filelist_push_back( archive->members, name); member = filelist_back( archive->members ); member->is_file = 1; member->is_dir = 0; @@ -419,13 +417,13 @@ static void collect_archive_content_small( int fd, file_archive_info_t * const a ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0'; - sprintf( buf, "%s", ar_hdr.hdr._ar_name.ar_name ); + auto name = b2::value::format( "%s", ar_hdr.hdr._ar_name.ar_name ); - if ( strcmp( buf, "") != 0 ) + if ( name->as_string().size > 0 ) { file_info_t * member = 0; - archive->members = filelist_push_back( archive->members, object_new( buf ) ); + archive->members = filelist_push_back( archive->members, name ); member = filelist_back( archive->members ); member->is_file = 1; member->is_dir = 0; @@ -474,13 +472,13 @@ static void collect_archive_content_big( int fd, file_archive_info_t * const arc ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0'; - sprintf( buf, "%s", ar_hdr.hdr._ar_name.ar_name ); + auto name = b2::value::format( "%s", ar_hdr.hdr._ar_name.ar_name ); - if ( strcmp( buf, "") != 0 ) + if ( name->as_string().size > 0 ) { file_info_t * member = 0; - archive->members = filelist_push_back( archive->members, object_new( buf ) ); + archive->members = filelist_push_back( archive->members, name ); member = filelist_back( archive->members ); member->is_file = 1; member->is_dir = 0; diff --git a/src/engine/filevms.cpp b/src/engine/filevms.cpp index cf24b8c602..b3b2303e73 100644 --- a/src/engine/filevms.cpp +++ b/src/engine/filevms.cpp @@ -20,6 +20,9 @@ #include "pathsys.h" #include "jam_strings.h" +#include +#include + #ifdef OS_VMS @@ -310,9 +313,12 @@ static unsigned int set_archive_member( struct dsc$descriptor_s *module, file_info_t * member = 0; /* Construct member's filename as lowercase "module.obj" */ - sprintf( buf, "%s.obj", filename ); - downcase_inplace( buf ); - archive->members = filelist_push_back( archive->members, object_new( buf ) ); + std::string name = filename; + name += ".obj"; + std::transform(name.begin(), name.end(), name.begin(), + [](unsigned char c) { return std::tolower(c); }); + archive->members = filelist_push_back( archive->members, + b2::value::make( name ) ); member = filelist_back( archive->members ); member->is_file = 1; @@ -350,7 +356,6 @@ void file_archscan( char const * arch, scanback func, void * closure ) { FILELISTITER iter = filelist_begin( archive->members ); FILELISTITER const end = filelist_end( archive->members ); - char buf[ MAXJPATH ]; for ( ; iter != end ; iter = filelist_next( iter ) ) { @@ -359,11 +364,10 @@ void file_archscan( char const * arch, scanback func, void * closure ) /* Construct member path: 'archive-path(member-name)' */ - sprintf( buf, "%s(%s)", - object_str( archive->file->name ), - object_str( member_file->name ) ); { - OBJECT * member = object_new( buf ); + OBJECT * member = b2::value::format( "%s(%s)", + object_str( archive->file->name ), + object_str( member_file->name ) ); (*func)( closure, member, 1 /* time valid */, &member_file->time ); object_free( member ); } diff --git a/src/engine/hcache.cpp b/src/engine/hcache.cpp index f606a65fa2..02b8d8c141 100644 --- a/src/engine/hcache.cpp +++ b/src/engine/hcache.cpp @@ -171,11 +171,14 @@ OBJECT * read_netstring( FILE * f ) * Write a netstring. */ -void write_netstring( FILE * f, char const * s ) +template +void write_netstring( FILE * f, char const * format, Args... args ) { - if ( !s ) - s = ""; - fprintf( f, "%lu\t%s\n", (long unsigned)strlen( s ), s ); + if ( format == nullptr ) format = ""; + auto size = std::snprintf(nullptr, 0, format, args...); + std::unique_ptr s(new char[size+1]); + std::snprintf(s.get(), size+1, format, args...); + fprintf( f, "%lu\t%s\n", (long unsigned)size, s.get() ); } @@ -373,49 +376,38 @@ void hcache_done() maxage = cache_maxage(); /* Print out the version. */ - write_netstring( f, CACHE_FILE_VERSION ); + write_netstring( f, "%s",CACHE_FILE_VERSION ); c = hcachelist; for ( c = hcachelist; c; c = c->next ) { LISTITER iter; LISTITER end; - char time_secs_str[ 30 ]; - char time_nsecs_str[ 30 ]; - char age_str[ 30 ]; - char includes_count_str[ 30 ]; - char hdrscan_count_str[ 30 ]; if ( maxage == 0 ) c->age = 0; else if ( c->age > maxage ) continue; - sprintf( includes_count_str, "%lu", (long unsigned)list_length( + write_netstring( f, "%s", CACHE_RECORD_HEADER ); + write_netstring( f, "%s", object_str( c->boundname ) ); + write_netstring( f, "%lu", (long unsigned)c->time.secs ); + write_netstring( f, "%lu", (long unsigned)c->time.nsecs ); + write_netstring( f, "%lu", (long unsigned)c->age ); + write_netstring( f, "%lu", (long unsigned)list_length( c->includes ) ); - sprintf( hdrscan_count_str, "%lu", (long unsigned)list_length( - c->hdrscan ) ); - sprintf( time_secs_str, "%lu", (long unsigned)c->time.secs ); - sprintf( time_nsecs_str, "%lu", (long unsigned)c->time.nsecs ); - sprintf( age_str, "%lu", (long unsigned)c->age ); - - write_netstring( f, CACHE_RECORD_HEADER ); - write_netstring( f, object_str( c->boundname ) ); - write_netstring( f, time_secs_str ); - write_netstring( f, time_nsecs_str ); - write_netstring( f, age_str ); - write_netstring( f, includes_count_str ); for ( iter = list_begin( c->includes ), end = list_end( c->includes ); iter != end; iter = list_next( iter ) ) - write_netstring( f, object_str( list_item( iter ) ) ); - write_netstring( f, hdrscan_count_str ); + write_netstring( f, "%s", object_str( list_item( iter ) ) ); + write_netstring( f, "%lu", (long unsigned)list_length( + c->hdrscan ) ); for ( iter = list_begin( c->hdrscan ), end = list_end( c->hdrscan ); iter != end; iter = list_next( iter ) ) - write_netstring( f, object_str( list_item( iter ) ) ); + write_netstring( f, "%s", object_str( list_item( iter ) ) ); fputs( "\n", f ); ++header_count; } - write_netstring( f, CACHE_RECORD_END ); + write_netstring( f, "%s", CACHE_RECORD_END ); if ( DEBUG_HEADER ) out_printf( "hcache written to %s. %d dependencies, %.0f%% hit rate\n", diff --git a/src/engine/make.cpp b/src/engine/make.cpp index 5d37640350..90fbc17833 100644 --- a/src/engine/make.cpp +++ b/src/engine/make.cpp @@ -770,11 +770,9 @@ void make0 static char const * target_name( TARGET * t ) { - static char buf[ 1000 ]; if ( t->flags & T_FLAG_INTERNAL ) { - sprintf( buf, "%s (internal node)", object_str( t->name ) ); - return buf; + return b2::value::format( "%s (internal node)", t->name->str() )->str(); } return object_str( t->name ); } diff --git a/src/engine/output.cpp b/src/engine/output.cpp index 196082c781..d4ab5c5a80 100644 --- a/src/engine/output.cpp +++ b/src/engine/output.cpp @@ -172,17 +172,13 @@ void errno_printf(char const * const f, ...) OBJECT * outf_int( int const value ) { - char buffer[ 50 ]; - sprintf( buffer, "%i", value ); - return object_new( buffer ); + return b2::value::as_string( value ); } OBJECT * outf_double( double const value ) { - char buffer[ 50 ]; - sprintf( buffer, "%f", value ); - return object_new( buffer ); + return b2::value::as_string( value ); } diff --git a/src/engine/pathsys.cpp b/src/engine/pathsys.cpp index 98606aff6c..22e8e81747 100644 --- a/src/engine/pathsys.cpp +++ b/src/engine/pathsys.cpp @@ -262,13 +262,11 @@ string const * path_tmpdir() OBJECT * path_tmpnam( void ) { - char name_buffer[ 64 ]; unsigned long const pid = path_get_process_id_(); - static unsigned long t; + static unsigned long t = 0; if ( !t ) t = time( 0 ) & 0xffff; t += 1; - sprintf( name_buffer, "jam%lx%lx.000", pid, t ); - return object_new( name_buffer ); + return b2::value::format( "jam%lx%lx.000", pid, t ); } diff --git a/src/engine/scan.cpp b/src/engine/scan.cpp index fcfd018b57..c7f2b16e3a 100644 --- a/src/engine/scan.cpp +++ b/src/engine/scan.cpp @@ -47,7 +47,7 @@ static int scanmode = SCAN_NORMAL; static int anyerrors = 0; -static char * symdump( YYSTYPE * ); +static std::string symdump( YYSTYPE * ); #define BIGGEST_TOKEN 10240 /* no single token can be larger */ @@ -77,7 +77,7 @@ void yyerror( char const * s ) * hold the information about where reading it broke. */ out_printf( "%s:%d: %s at %s\n", object_str( yylval.file ), yylval.line, s, - symdump( &yylval ) ); + symdump( &yylval ).c_str() ); ++anyerrors; } @@ -239,7 +239,7 @@ static int use_new_scanner = 0; void do_token_warning() { out_printf( "%s:%d: %s %s\n", object_str( yylval.file ), yylval.line, "Unescaped special character in", - symdump( &yylval ) ); + symdump( &yylval ).c_str() ); } #define token_warning() has_token_warning = 1 @@ -764,7 +764,7 @@ int yylex() } if ( DEBUG_SCAN ) - out_printf( "scan %s\n", symdump( &yylval ) ); + out_printf( "scan %s\n", symdump( &yylval ).c_str() ); return yylval.type; @@ -777,18 +777,17 @@ int yylex() } -static char * symdump( YYSTYPE * s ) +static std::string symdump( YYSTYPE * s ) { - static char buf[ BIGGEST_TOKEN + 20 ]; switch ( s->type ) { - case EOF : sprintf( buf, "EOF" ); break; - case 0 : sprintf( buf, "unknown symbol %s", object_str( s->string ) ); break; - case ARG : sprintf( buf, "argument %s" , object_str( s->string ) ); break; - case STRING: sprintf( buf, "string \"%s\"" , object_str( s->string ) ); break; - default : sprintf( buf, "keyword %s" , s->keyword ); break; + case EOF : return "EOF"; break; + case 0 : return std::string("unknown symbol ") + s->string->str(); break; + case ARG : return std::string("argument ") + s->string->str(); break; + case STRING: return std::string("string \"") + s->string->str() + "\""; break; + default : return std::string("keyword ") + s->keyword; break; } - return buf; + return ""; } diff --git a/src/engine/tasks.cpp b/src/engine/tasks.cpp index fb85d1b6e8..10e114592f 100644 --- a/src/engine/tasks.cpp +++ b/src/engine/tasks.cpp @@ -39,32 +39,32 @@ struct sync inline sync::sync() { - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS wait_arrived = false; signal_arrived = false; - #endif +#endif } inline void sync::wait() { - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS // Indicate that we waiting. wait_arrived = true; // Wait for the signal that we can proceed. std::unique_lock lock(arrived_mx); arrived_cv.wait(lock, [this]() { return signal_arrived.load(); }); - #endif +#endif } inline bool sync::signal() { - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS // Wait for wait() to get called. if (!wait_arrived.load()) return false; // Tell the waiter that we arrived. signal_arrived = true; arrived_cv.notify_one(); - #endif +#endif return true; } @@ -218,14 +218,14 @@ inline executor::implementation::implementation(unsigned parallelism) if (parallelism == 0) return; // Launch the threads to cover the expected parallelism. scope_lock_t lock(mx); - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS runners.reserve(parallelism); for (; parallelism > 0; --parallelism) { running_count += 1; runners.emplace_back([this]() { runner(); }); } - #endif +#endif } inline void executor::implementation::push_group(std::shared_ptr g) @@ -236,16 +236,16 @@ inline void executor::implementation::push_group(std::shared_ptr g) inline void executor::implementation::call_signal() { - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS call_cv.notify_one(); - #endif +#endif } inline std::function executor::implementation::call_get() { std::function result; scope_lock_t lock(mx); - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS // We only dequeue task calls when we have a thread to run them. if (call_count < runners.size()) { @@ -261,7 +261,7 @@ inline std::function executor::implementation::call_get() } // We don't have tasks to run, wait for some to become available. call_cv.wait(lock); - #endif +#endif return result; } @@ -279,7 +279,7 @@ inline bool executor::implementation::is_running() inline void executor::implementation::stop() { - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS // Stop all the runner threads (i.e. signal and wait). std::vector to_join; { @@ -292,7 +292,7 @@ inline void executor::implementation::stop() call_cv.notify_all(); t.join(); } - #endif +#endif } void executor::implementation::runner() @@ -316,13 +316,13 @@ void executor::implementation::runner() namespace { unsigned get_parallelism(int parallelism) { - #if B2_USE_STD_THREADS +#if B2_USE_STD_THREADS return parallelism >= 0 ? parallelism : std::min(unsigned(globs.jobs), system_info().cpu_thread_count()) - 1; - #else +#else return 0; - #endif +#endif } } // namespace diff --git a/src/engine/timestamp.cpp b/src/engine/timestamp.cpp index 1664c64b57..9082f02dce 100644 --- a/src/engine/timestamp.cpp +++ b/src/engine/timestamp.cpp @@ -7,6 +7,7 @@ /* This file is ALSO: * Copyright 2001-2004 David Abrahams. * Copyright 2020 Nikita Kniazev. + * Copyright 2023 René Ferdinand Rivera Morell. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE.txt or * https://www.bfgroup.xyz/b2/LICENSE.txt) @@ -24,14 +25,15 @@ */ #include "jam.h" -#include "timestamp.h" #include "filesys.h" #include "hash.h" -#include "object.h" -#include "pathsys.h" #include "jam_strings.h" +#include "object.h" #include "output.h" +#include "pathsys.h" +#include "timestamp.h" +#include "types.h" /* @@ -182,12 +184,14 @@ void timestamp_max( timestamp * const max, timestamp const * const lhs, static char const * timestamp_formatstr( timestamp const * const time, char const * const format ) { + // gmtime is not thread safe. And there's no alternative in C++11. + // So we make this whole thing exclusive to prevent errors. + static b2::mutex_t m; + b2::scope_lock_t l(m); static char result1[ 500 ]; - static char result2[ 500 ]; strftime( result1, sizeof( result1 ) / sizeof( *result1 ), format, gmtime( &time->secs ) ); - sprintf( result2, result1, time->nsecs ); - return result2; + return b2::value::format( result1, time->nsecs )->str(); } diff --git a/src/engine/types.h b/src/engine/types.h index 7ccaa9f2fe..e53ed39387 100644 --- a/src/engine/types.h +++ b/src/engine/types.h @@ -1,6 +1,7 @@ -/* Copyright 2019 Rene Rivera +/* Copyright 2019-2023 René Ferdinand Rivera Morell * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) + * (See accompanying file LICENSE.txt or + * https://www.bfgroup.xyz/b2/LICENSE.txt) */ #ifndef B2_TYPES_H @@ -14,8 +15,7 @@ #include #endif -namespace b2 -{ +namespace b2 { using string_t = std::string; using int_t = int; using uint_t = unsigned int; @@ -27,10 +27,11 @@ using scope_lock_t = std::unique_lock; #else -struct mutex_t {}; +struct mutex_t +{}; struct scope_lock_t { - inline scope_lock_t(mutex_t &) {} + inline scope_lock_t(mutex_t &) {} }; #endif diff --git a/src/engine/value.h b/src/engine/value.h index b31e4f0c7c..0038f7845a 100644 --- a/src/engine/value.h +++ b/src/engine/value.h @@ -1,5 +1,5 @@ /* -Copyright 2022 René Ferdinand Rivera Morell +Copyright 2022-2023 René Ferdinand Rivera Morell Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) */ @@ -12,8 +12,10 @@ Distributed under the Boost Software License, Version 1.0. #include "strview.h" #include +#include #include #include +#include #include namespace b2 { @@ -75,6 +77,21 @@ struct value static void done(); inline bool has_value() const { return get_type() == type::null; } + + template + static inline value * as_string(T v) + { + return value::make(std::to_string(v)); + } + + template + static inline value * format(const char * f, Args... args) + { + auto size = std::snprintf(nullptr, 0, f, args...); + std::unique_ptr s(new char[size + 1]); + std::snprintf(s.get(), size + 1, f, args...); + return value::make(s.get(), size); + } }; typedef value * value_ptr; diff --git a/src/engine/w32_getreg.cpp b/src/engine/w32_getreg.cpp index 4cbc9dd01e..2f5b0478ad 100644 --- a/src/engine/w32_getreg.cpp +++ b/src/engine/w32_getreg.cpp @@ -111,9 +111,8 @@ LIST * builtin_system_registry( FRAME * frame, int flags ) case REG_DWORD: { - char buf[100]; - sprintf( buf, "%lu", *(PDWORD)data ); - result = list_push_back( result, object_new(buf) ); + result = list_push_back( result, + b2::value::as_string( *(PDWORD)data ) ); } break;