2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-13 12:22:17 +00:00
Files
build/src/engine/strings.c
Victor Robertson 851c19fa6b Fix strip-eol for long command output
Previously, when shell command output exceeded the 1024 character
buffer size, each chunk of output would be stripped. This had the
undesirable effect of sometimes breaking compilation by splitting on
whitespace boundaries. This patch addresses the issue by providing a
string_rtrim function and utilizing the function on the output string
instead of each buffered component.
2016-11-04 16:30:44 -07:00

250 lines
6.1 KiB
C

/* Copyright David Abrahams 2004. Distributed under 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) */
#include "jam.h"
#include "strings.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifndef NDEBUG
# define JAM_STRING_MAGIC ((char)0xcf)
# define JAM_STRING_MAGIC_SIZE 4
static void assert_invariants( string * self )
{
int i;
if ( self->value == 0 )
{
assert( self->size == 0 );
assert( self->capacity == 0 );
assert( self->opt[ 0 ] == 0 );
return;
}
assert( self->size < self->capacity );
assert( ( self->capacity <= sizeof( self->opt ) ) == ( self->value == self->opt ) );
assert( self->value[ self->size ] == 0 );
/* String objects modified manually after construction to contain embedded
* '\0' characters are considered structurally valid.
*/
assert( strlen( self->value ) <= self->size );
for ( i = 0; i < 4; ++i )
{
assert( self->magic[ i ] == JAM_STRING_MAGIC );
assert( self->value[ self->capacity + i ] == JAM_STRING_MAGIC );
}
}
#else
# define JAM_STRING_MAGIC_SIZE 0
# define assert_invariants(x) do {} while (0)
#endif
void string_new( string * s )
{
s->value = s->opt;
s->size = 0;
s->capacity = sizeof( s->opt );
s->opt[ 0 ] = 0;
#ifndef NDEBUG
memset( s->magic, JAM_STRING_MAGIC, sizeof( s->magic ) );
#endif
assert_invariants( s );
}
void string_free( string * s )
{
assert_invariants( s );
if ( s->value != s->opt )
BJAM_FREE( s->value );
string_new( s );
}
static void string_reserve_internal( string * self, size_t capacity )
{
if ( self->value == self->opt )
{
self->value = (char *)BJAM_MALLOC_ATOMIC( capacity +
JAM_STRING_MAGIC_SIZE );
self->value[ 0 ] = 0;
strncat( self->value, self->opt, sizeof(self->opt) );
assert( strlen( self->value ) <= self->capacity && "Regression test" );
}
else
{
self->value = (char *)BJAM_REALLOC( self->value, capacity +
JAM_STRING_MAGIC_SIZE );
}
#ifndef NDEBUG
memcpy( self->value + capacity, self->magic, JAM_STRING_MAGIC_SIZE );
#endif
self->capacity = capacity;
}
void string_reserve( string * self, size_t capacity )
{
assert_invariants( self );
if ( capacity <= self->capacity )
return;
string_reserve_internal( self, capacity );
assert_invariants( self );
}
static void extend_full( string * self, char const * start, char const * finish )
{
size_t new_size = self->capacity + ( finish - start );
size_t new_capacity = self->capacity;
size_t old_size = self->capacity;
while ( new_capacity < new_size + 1)
new_capacity <<= 1;
string_reserve_internal( self, new_capacity );
memcpy( self->value + old_size, start, new_size - old_size );
self->value[ new_size ] = 0;
self->size = new_size;
}
static void maybe_reserve( string * self, size_t new_size )
{
size_t capacity = self->capacity;
if ( capacity <= new_size )
{
size_t new_capacity = capacity;
while ( new_capacity <= new_size )
new_capacity <<= 1;
string_reserve_internal( self, new_capacity );
}
}
void string_append( string * self, char const * rhs )
{
size_t rhs_size = strlen( rhs );
size_t new_size = self->size + rhs_size;
assert_invariants( self );
maybe_reserve( self, new_size );
memcpy( self->value + self->size, rhs, rhs_size + 1 );
self->size = new_size;
assert_invariants( self );
}
void string_append_range( string * self, char const * start, char const * finish )
{
size_t rhs_size = finish - start;
size_t new_size = self->size + rhs_size;
assert_invariants( self );
maybe_reserve( self, new_size );
memcpy( self->value + self->size, start, rhs_size );
self->size = new_size;
self->value[ new_size ] = 0;
assert_invariants( self );
}
void string_copy( string * s, char const * rhs )
{
string_new( s );
string_append( s, rhs );
}
void string_truncate( string * self, size_t n )
{
assert_invariants( self );
assert( n <= self->capacity );
self->value[ self->size = n ] = 0;
assert_invariants( self );
}
void string_pop_back( string * self )
{
string_truncate( self, self->size - 1 );
}
void string_push_back( string * self, char x )
{
string_append_range( self, &x, &x + 1 );
}
char string_back( string * self )
{
assert_invariants( self );
return self->value[ self->size - 1 ];
}
void string_rtrim( string * self )
{
assert_invariants( self );
char * p = self->value + self->size - 1;
for ( p; p >= self->value && ( *p == '\0' || isspace( *p ) ); *p-- = 0 );
}
#ifndef NDEBUG
void string_unit_test()
{
{
string s[ 1 ];
int i;
int const limit = sizeof( s->opt ) * 2 + 2;
string_new( s );
assert( s->value == s->opt );
for ( i = 0; i < limit; ++i )
{
string_push_back( s, (char)( i + 1 ) );
assert( s->size == i + 1 );
}
assert( s->size == limit );
assert( s->value != s->opt );
for ( i = 0; i < limit; ++i )
assert( s->value[ i ] == (char)( i + 1 ) );
string_free( s );
}
{
char * const original = " \n\t\v Foo \r\n\v \tBar\n\n\r\r\t\n\v\t \t";
string copy[ 1 ];
string_copy( copy, original );
assert( !strcmp( copy->value, original ) );
assert( copy->size == strlen( original ) );
string_free( copy );
}
{
char * const foo = "Foo ";
string foo_copy[ 1 ];
string_copy( foo_copy, foo );
string_rtrim( foo_copy );
assert( !strcmp( foo_copy->value, "Foo" ) );
string_rtrim( foo_copy );
assert( !strcmp( foo_copy->value, "Foo" ) );
char * const bar = "Bar\0\0\0";
string bar_copy[ 1 ];
string_copy( bar_copy, bar );
string_rtrim( bar_copy );
assert( !strcmp( bar_copy->value, "Bar" ) );
string_rtrim( bar_copy );
assert( !strcmp( bar_copy->value, "Bar" ) );
}
}
#endif