コード例 #1
0
ファイル: path.c プロジェクト: HardlyHaki/ProDBG
char* path_prepend( char* tail, const char* base )
{
	if( !tail )
		return path_clean( string_clone( base ), path_is_absolute( base ) );
	tail = string_prepend( tail, "/" );
	tail = string_prepend( tail, base );
	tail = path_clean( tail, path_is_absolute( tail ) );
	return tail;
}
コード例 #2
0
ファイル: string_test.cpp プロジェクト: ShenTensen/circa
void test_prepend()
{
    Value hello, there;
    set_string(&hello, "hello");
    set_string(&there, "there");

    test_equals(&hello, "hello");
    test_equals(&there, "there");

    string_prepend(&there, " ");
    test_equals(&there, " there");
    string_prepend(&there, &hello);
    string_prepend(&there, "hello there");
    test_equals(&hello, "hello");
}
コード例 #3
0
ファイル: string_utils.c プロジェクト: golovishnikov/emacs
static void test1()
{
  String* a = string_create("");
  String* b = string_create("Hello");
  String* c = string_create("World");

  printf("a = \"%s\"\n", a->text);
  printf("b = \"%s\"\n", b->text);
  printf("c = \"%s\"\n", c->text);
  assert(strcmp(a->text, "") == 0);
  assert(strcmp(b->text, "Hello") == 0);
  assert(strcmp(c->text, "World") == 0);

  string_append(a, b->text);
  string_append(b, c->text);
  string_append(c, a->text);

  printf("a = a+b = \"%s\"\n", a->text);
  printf("b = b+c = \"%s\"\n", b->text);
  printf("c = c+a = \"%s\"\n", c->text);
  assert(strcmp(a->text, "Hello") == 0);
  assert(strcmp(b->text, "HelloWorld") == 0);
  assert(strcmp(c->text, "WorldHello") == 0);

  string_prepend(a, b->text);
  string_prepend(b, c->text);
  string_prepend(c, a->text);

  printf("a = b+a = \"%s\"\n", a->text);
  printf("b = c+b = \"%s\"\n", b->text);
  printf("c = a+c = \"%s\"\n", c->text);
  assert(strcmp(a->text, "HelloWorldHello") == 0);
  assert(strcmp(b->text, "WorldHelloHelloWorld") == 0);
  assert(strcmp(c->text, "HelloWorldHelloWorldHello") == 0);

  string_destroy(a);
  string_destroy(b);
  string_destroy(c);
}
コード例 #4
0
ファイル: w32date.cpp プロジェクト: alilloyd/livecode
static void windows_cache_locale(void)
{
	if (s_datetime_locale != NULL)
		return;

	s_datetime_locale = new MCDateTimeLocale;

	// OK-2007-05-23: Fix for bug 5035. Adjusted to ensure that first element of weekday names is always Sunday.
	s_datetime_locale -> weekday_names[0] = windows_query_locale(LOCALE_SDAYNAME7);
	s_datetime_locale -> abbrev_weekday_names[0] = windows_query_locale(LOCALE_SABBREVDAYNAME7);

	for (uint4 t_index = 0; t_index < 6; ++t_index)
	{
		s_datetime_locale -> weekday_names[t_index + 1] = windows_query_locale(LOCALE_SDAYNAME1 + t_index);
		s_datetime_locale -> abbrev_weekday_names[t_index + 1] = windows_query_locale(LOCALE_SABBREVDAYNAME1 + t_index);
	}

	for(uint4 t_index = 0; t_index < 12; ++t_index)
	{
		s_datetime_locale -> month_names[t_index] = windows_query_locale(LOCALE_SMONTHNAME1 + t_index);
		s_datetime_locale -> abbrev_month_names[t_index] = windows_query_locale(LOCALE_SABBREVMONTHNAME1 + t_index);
	}

	s_datetime_locale -> date_formats[0] = string_prepend(windows_query_date_format(LOCALE_SSHORTDATE, false), '^');
	s_datetime_locale -> date_formats[1] = windows_query_date_format(LOCALE_SLONGDATE, true);
	s_datetime_locale -> date_formats[2] = windows_query_date_format(LOCALE_SLONGDATE, false);

	// AL-2013-02-08: [[ Bug 9942 ]] Allow appropriate versions of Windows to retrieve the short time format.
	if (MCmajorosversion >= 0x0601)
		s_datetime_locale -> time_formats[0] = string_prepend(windows_query_time_format(LOCALE_SSHORTTIME), '!');
	else
		s_datetime_locale -> time_formats[0] = string_prepend(windows_query_time_format(LOCALE_STIMEFORMAT), '!');

	s_datetime_locale -> time_formats[1] = string_prepend(windows_query_time_format(LOCALE_STIMEFORMAT), '!');

	s_datetime_locale -> time24_formats[0] = string_prepend(windows_query_time_format(LOCALE_STIMEFORMAT), '!');
	s_datetime_locale -> time24_formats[1] = string_prepend(windows_query_time_format(LOCALE_STIMEFORMAT), '!');
	
	// AL-2013-02-08: [[ Bug 9945 ]] Retrieve locale-specific AM & PM designators.
	s_datetime_locale -> time_morning_suffix = windows_query_locale(LOCALE_S1159);
	s_datetime_locale -> time_evening_suffix = windows_query_locale(LOCALE_S2359);
}
コード例 #5
0
ファイル: process.c プロジェクト: Jasper-Bekkers/ProDBG
int process_spawn( process_t* proc )
{
	static char unescaped[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.:/\\";
	int i, num_args;
	int size;
#if FOUNDATION_PLATFORM_WINDOWS
	wchar_t* wcmdline;
	wchar_t* wwd;
	char* cmdline = 0;
#endif

	if( !proc )
		return PROCESS_INVALID_ARGS;
	
	proc->code = PROCESS_INVALID_ARGS;

	if( !string_length( proc->path ) )
		return proc->code;

	//Always escape path on Windows platforms
#if FOUNDATION_PLATFORM_POSIX
	if( string_find_first_not_of( proc->path, unescaped, 0 ) != STRING_NPOS )
#endif
	{
		if( proc->path[0] != '"' )
			proc->path = string_prepend( proc->path, "\"" );
		if( proc->path[ string_length( proc->path ) - 1 ] != '"' )
			proc->path = string_append( proc->path, "\"" );
	}

	size = array_size( proc->args );
	for( i = 0, num_args = 0; i < size; ++i )
	{
		char* arg = proc->args[i];
		
		if( !string_length( arg ) )
			continue;
		
		++num_args;
		
		if( string_find_first_not_of( arg, unescaped, 0 ) != STRING_NPOS )
		{
			if( arg[0] != '"' )
			{
				//Check if we need to escape " characters
				unsigned int pos = string_find( arg, '"', 0 );
				while( pos != STRING_NPOS )
				{
					if( arg[ pos - 1 ] != '\\' )
					{
						char* escarg = string_substr( arg, 0, pos );
						char* left = string_substr( arg, pos, STRING_NPOS );
						escarg = string_append( escarg, "\\" );
						escarg = string_append( escarg, left );
						string_deallocate( left );
						string_deallocate( arg );
						arg = escarg;
					}
					pos = string_find( arg, '"', pos + 2 );
				}
				arg = string_prepend( arg, "\"" );
				arg = string_append( arg, "\"" );

				proc->args[i] = arg;
			}
		}
	}

#if FOUNDATION_PLATFORM_WINDOWS

#  ifndef SEE_MASK_NOASYNC
#    define SEE_MASK_NOASYNC           0x00000100
#  endif

	if( !( proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE ) ) //Don't prepend exe path to parameters if using ShellExecute
		cmdline = string_clone( proc->path );
	
	//Build command line string
	for( i = 0; i < size; ++i )
	{
		char* arg = proc->args[i];
		
		if( !string_length( arg ) )
			continue;

		if( cmdline )
			cmdline = string_append( cmdline, " " );
		cmdline = string_append( cmdline, arg );
	}
	
	if( !string_length( proc->wd ) )
		proc->wd = string_clone( environment_current_working_directory() );

	wcmdline = wstring_allocate_from_string( cmdline, 0 );
	wwd = wstring_allocate_from_string( proc->wd, 0 );
	
	if( proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE )
	{
		SHELLEXECUTEINFOW sei;
		wchar_t* wverb;
		wchar_t* wpath;

		wverb = ( proc->verb && string_length( proc->verb ) ) ? wstring_allocate_from_string( proc->verb, 0 ) : 0;
		wpath = wstring_allocate_from_string( proc->path, 0 );

		ZeroMemory( &sei, sizeof( sei ) );

		sei.cbSize          = sizeof(SHELLEXECUTEINFOW);
		sei.hwnd            = 0;
		sei.fMask           = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
		sei.lpVerb          = wverb;
		sei.lpFile          = wpath;
		sei.lpParameters    = wcmdline;
		sei.lpDirectory     = wwd;
		sei.nShow           = SW_SHOWNORMAL;

		if( !( proc->flags & PROCESS_CONSOLE ) )
			sei.fMask      |= SEE_MASK_NO_CONSOLE;

		if( proc->flags & PROCESS_STDSTREAMS )
			log_warnf( 0, WARNING_UNSUPPORTED, "Unable to redirect standard in/out through pipes when using ShellExecute for process spawning" );

		log_debugf( 0, "Spawn process (ShellExecute): %s %s", proc->path, cmdline );

		if( !ShellExecuteExW( &sei ) )
		{
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to spawn process (ShellExecute) for executable '%s': %s", proc->path, system_error_message( GetLastError() ) );
		}
		else
		{
			proc->hp   = sei.hProcess;
			proc->ht   = 0;
			proc->code = 0;
		}

		wstring_deallocate( wverb );
		wstring_deallocate( wpath );
	}
	else
	{
		STARTUPINFOW si;
		PROCESS_INFORMATION pi;
		BOOL inherit_handles = FALSE;

		memset( &si, 0, sizeof( si ) );
		memset( &pi, 0, sizeof( pi ) );
		si.cb = sizeof( si );

		if( proc->flags & PROCESS_STDSTREAMS )
		{
			proc->pipeout = pipe_allocate();
			proc->pipein = pipe_allocate();

			si.dwFlags |= STARTF_USESTDHANDLES;
			si.hStdOutput = pipe_write_handle( proc->pipeout );
			si.hStdError = pipe_write_handle( proc->pipeout );
			si.hStdInput = pipe_read_handle( proc->pipein );

			//Don't inherit wrong ends of pipes
			SetHandleInformation( pipe_read_handle( proc->pipeout ), HANDLE_FLAG_INHERIT, 0 );
			SetHandleInformation( pipe_write_handle( proc->pipein ), HANDLE_FLAG_INHERIT, 0 );

			inherit_handles = TRUE;
		}

		log_debugf( 0, "Spawn process (CreateProcess): %s %s", proc->path, cmdline );

		if( !CreateProcessW( 0/*wpath*/, wcmdline, 0, 0, inherit_handles, ( proc->flags & PROCESS_CONSOLE ) ? CREATE_NEW_CONSOLE : 0, 0, wwd, &si, &pi ) )
		{
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to spawn process (CreateProcess) for executable '%s': %s", proc->path, system_error_message( GetLastError() ) );

			stream_deallocate( proc->pipeout );
			stream_deallocate( proc->pipein );

			proc->pipeout = 0;
			proc->pipein = 0;
		}
		else
		{
			proc->hp = pi.hProcess;
			proc->ht = pi.hThread;
			proc->code = 0;
		}

		if( proc->pipeout )
			pipe_close_write( proc->pipeout );
		if( proc->pipein )
			pipe_close_read( proc->pipein );
	}

	wstring_deallocate( wcmdline );
	wstring_deallocate( wwd );
	string_deallocate( cmdline );
	
	if( proc->code < 0 )
		return proc->code; //Error

#endif

#if FOUNDATION_PLATFORM_MACOSX
	
	if( proc->flags & PROCESS_OSX_USE_OPENAPPLICATION )
	{
		proc->pid = 0;
		
		LSApplicationParameters params;
		ProcessSerialNumber psn;
		FSRef* fsref = memory_allocate( 0, sizeof( FSRef ), 0, MEMORY_TEMPORARY | MEMORY_ZERO_INITIALIZED );
		
		memset( &params, 0, sizeof( LSApplicationParameters ) );
		memset( &psn, 0, sizeof( ProcessSerialNumber ) );
		
		char* pathstripped = string_strip( string_clone( proc->path ), "\"" );
		
		OSStatus status = 0;
		status = FSPathMakeRef( (uint8_t*)pathstripped, fsref, 0 );
		if( status < 0 )
		{
			pathstripped = string_append( pathstripped, ".app" );
			status = FSPathMakeRef( (uint8_t*)pathstripped, fsref, 0 );
		}
		
		CFStringRef* args = 0;
		for( i = 0, size = array_size( proc->args ); i < size; ++i ) //App gets executable path automatically, don't include
			array_push( args, CFStringCreateWithCString( 0, proc->args[i], kCFStringEncodingUTF8 ) );
		
		CFArrayRef argvref = CFArrayCreate( 0, (const void**)args, (CFIndex)array_size( args ), 0 );
		
		params.flags = kLSLaunchDefaults;
		params.application = fsref;
		params.argv = argvref;

		log_debugf( 0, "Spawn process (LSOpenApplication): %s", pathstripped );
		
		status = LSOpenApplication( &params, &psn );
		if( status != 0 )
		{
			proc->code = status;
			log_warnf( 0, WARNING_BAD_DATA, "Unable to spawn process for executable '%s': %s", proc->path, system_error_message( status ) );
		}
		
		CFRelease( argvref );
		for( i = 0, size = array_size( args ); i < size; ++i )
			CFRelease( args[i] );
		
		memory_deallocate( fsref );
		string_deallocate( pathstripped );
		
		if( status == 0 )
		{
			pid_t pid = 0;
			GetProcessPID( &psn, &pid );
			
			proc->pid = pid;

			//Always "detached" with LSOpenApplication, not a child process at all
			//Setup a kqueue to watch when process terminates so we can emulate a wait
			proc->kq = kqueue();
			if( proc->kq < 0 )
			{
				log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create kqueue for process watch: %s (%d)", proc->kq, system_error_message( proc->kq ) );
				proc->kq = 0;
			}
			else
			{
				struct kevent changes;
				EV_SET( &changes, (pid_t)pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, 0 );
				int ret = kevent( proc->kq, &changes, 1, &changes, 1, 0 );
				if( ret != 1 )
				{
					log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to setup kqueue for process watch, failed to add event to kqueue (%d)", ret );
					close( proc->kq );
					proc->kq = 0;
				}
			}
		}
		
		goto exit;
	}
#endif

#if FOUNDATION_PLATFORM_POSIX

	//Insert executable arg at start and null ptr at end
	int argc = array_size( proc->args ) + 1;
	array_grow( proc->args, 2 );
	for( int arg = argc - 1; arg > 0; --arg )
		proc->args[arg] = proc->args[arg-1];
	proc->args[0] = string_clone( proc->path );
	proc->args[argc] = 0;

	if( proc->flags & PROCESS_STDSTREAMS )
	{
		proc->pipeout = pipe_allocate();
		proc->pipein = pipe_allocate();
	}
	
	proc->pid = 0;	
	pid_t pid = fork();

	if( pid == 0 )
	{
		//Child
		if( string_length( proc->wd ) )
		{
			log_debugf( 0, "Spawned child process, setting working directory to %s", proc->wd );
			environment_set_current_working_directory( proc->wd );
		}

		log_debugf( 0, "Child process executing: %s", proc->path );

		if( proc->flags & PROCESS_STDSTREAMS )
		{
			pipe_close_read( proc->pipeout );
			dup2( pipe_write_fd( proc->pipeout ), STDOUT_FILENO );

			pipe_close_write( proc->pipein );
			dup2( pipe_read_fd( proc->pipein ), STDIN_FILENO );
		}

		int code = execv( proc->path, proc->args );
		if( code < 0 ) //Will always be true since this point will never be reached if execve() is successful
			log_warnf( 0, WARNING_BAD_DATA, "Child process failed execve() : %s : %s", proc->path, system_error_message( errno ) );
		
		//Error
		process_exit( -1 );
	}

	if( pid > 0 )
	{		
		log_debugf( 0, "Child process forked, pid %d", pid );

		proc->pid = pid;

		if( proc->pipeout )
			pipe_close_write( proc->pipeout );
		if( proc->pipein )
			pipe_close_read( proc->pipein );
		
		if( proc->flags & PROCESS_DETACHED )
		{
			int cstatus = 0;
			pid_t err = waitpid( pid, &cstatus, WNOHANG );
			if( err == 0 )
			{
				//TODO: Ugly wait to make sure process spawned correctly
				thread_sleep( 500 );
				err = waitpid( pid, &cstatus, WNOHANG );
			}
			if( err > 0 )
			{
				//Process exited, check code
				proc->code = (int)((char)WEXITSTATUS( cstatus ));
				log_debugf( 0, "Child process returned: %d", proc->code );
				return proc->code;
			}
		}
	}
	else
	{
		//Error
		proc->code = errno;
		log_warnf( 0, WARNING_BAD_DATA, "Unable to spawn process: %s : %s", proc->path, system_error_message( proc->code ) );

		if( proc->pipeout )
			stream_deallocate( proc->pipeout );
		if( proc->pipein )
			stream_deallocate( proc->pipein );

		proc->pipeout = 0;
		proc->pipein = 0;
		
		return proc->code;
	}	

#endif

#if !FOUNDATION_PLATFORM_WINDOWS && !FOUNDATION_PLATFORM_POSIX
	FOUNDATION_ASSERT_FAIL( "Process spawning not supported on platform" );
#endif
	
#if FOUNDATION_PLATFORM_MACOSX
exit:
#endif

	if( proc->flags & PROCESS_DETACHED )
		return PROCESS_STILL_ACTIVE;

	return process_wait( proc );
}
コード例 #6
0
ファイル: main.c プロジェクト: apprisi/foundation_lib
DECLARE_TEST( string, prepend )
{
	const char* nullstr = 0;
	const char* emptystr = "";
	const char* shortstr = "short";
	const char* longstr = "long long long long long long long long long";
	char* val;

	val = 0;
	val = string_prepend( val, nullstr );
	EXPECT_STREQ( val, "" );
	string_deallocate( val );

	val = 0;
	val = string_prepend( val, emptystr );
	EXPECT_STREQ( val, "" );
	string_deallocate( val );

	val = string_clone( emptystr );
	val = string_prepend( val, nullstr );
	EXPECT_STREQ( val, "" );
	string_deallocate( val );

	val = string_clone( emptystr );
	val = string_prepend( val, emptystr );
	EXPECT_STREQ( val, "" );
	string_deallocate( val );

	val = 0;
	val = string_prepend( val, shortstr );
	EXPECT_STREQ( val, "short" );
	string_deallocate( val );

	val = string_clone( shortstr );
	val = string_prepend( val, nullstr );
	EXPECT_STREQ( val, "short" );
	string_deallocate( val );

	val = string_clone( emptystr );
	val = string_prepend( val, shortstr );
	EXPECT_STREQ( val, "short" );
	string_deallocate( val );

	val = string_clone( shortstr );
	val = string_prepend( val, emptystr );
	EXPECT_STREQ( val, "short" );
	string_deallocate( val );

	val = string_clone( shortstr );
	val = string_prepend( val, shortstr );
	EXPECT_STREQ( val, "shortshort" );
	string_deallocate( val );

	val = 0;
	val = string_prepend( val, longstr );
	EXPECT_STREQ( val, "long long long long long long long long long" );
	string_deallocate( val );

	val = string_clone( longstr );
	val = string_prepend( val, nullstr );
	EXPECT_STREQ( val, "long long long long long long long long long" );
	string_deallocate( val );

	val = string_clone( emptystr );
	val = string_prepend( val, longstr );
	EXPECT_STREQ( val, "long long long long long long long long long" );
	string_deallocate( val );

	val = string_clone( longstr );
	val = string_prepend( val, emptystr );
	EXPECT_STREQ( val, "long long long long long long long long long" );
	string_deallocate( val );

	val = string_clone( shortstr );
	val = string_prepend( val, longstr );
	EXPECT_STREQ( val, "long long long long long long long long longshort" );
	string_deallocate( val );

	val = string_clone( longstr );
	val = string_prepend( val, shortstr );
	EXPECT_STREQ( val, "shortlong long long long long long long long long" );
	string_deallocate( val );

	val = string_clone( longstr );
	val = string_prepend( val, longstr );
	EXPECT_STREQ( val, "long long long long long long long long longlong long long long long long long long long" );
	string_deallocate( val );

	return 0;
}
コード例 #7
0
ファイル: path.c プロジェクト: HardlyHaki/ProDBG
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;
}
コード例 #8
0
ファイル: strings_test.c プロジェクト: savage13/libkitty
int
main(int argc, char *argv[]) {

  string *s = NULL;
  string *s2 = NULL;
  string *s3 = NULL;

  s = string_append(s, "Hello There");
  test(s, "Hello There");

  s = string_append(s, "123");
  test(s, "Hello There123");

  s = string_insert(s, 1, "<new>");
  test(s, "H<new>ello There123");

  s = string_insert(s, 23, "<new>");
  test(s, "H<new>ello There123<new>");

  s = string_remove(s, 11, 5);
  test(s, "H<new>ello 123<new>");

  s = string_replace(s, "<new>", "<nothing>");
  test(s, "H<nothing>ello 123<nothing>");

  s = string_remove(s, 0, 30);
  test(s, "");
  s = string_append(s, "H<nothing>ello 123<nothing>");
  test(s, "H<nothing>ello 123<nothing>");
  s = string_trunc(s);
  test(s, "");
  string_free(&s);

  s = string_append_int(s, 1);
  test(s, "1");
  s = string_append_int(s, 10);
  test(s, "110");
  s = string_append_int(s, 100);
  test(s, "110100");
  s = string_append_int(s, 1000000000);
  test(s, "1101001000000000");
  s = string_append_int(s, -2);
  test(s, "1101001000000000-2");
  s = string_append_int(s, -345);
  test(s, "1101001000000000-2-345");
  s = string_append_int(s, -3.45);
  test(s, "1101001000000000-2-345-3");
  s = string_trunc(s);
  test(s,"");

  s = string_prepend_int(s, 1);
  test(s, "1");
  s = string_prepend_int(s, 10);
  test(s, "101");
  s = string_prepend_int(s, 100);
  test(s, "100101");
  s = string_prepend_int(s, 1000000000);
  test(s, "1000000000100101");
  s = string_prepend_int(s, -2);
  test(s, "-21000000000100101");
  s = string_prepend_int(s, -345);
  test(s, "-345-21000000000100101");
  s = string_prepend_int(s, -3.45);
  test(s, "-3-345-21000000000100101");
  s = string_trunc(s);
  test(s,"");

  string_free(&s);

  s = string_new("\"Quoted String\"");
  test(s, "\"Quoted String\"");

  s = string_replace(s, "\"", "");
  test(s, "Quoted String");

  string_free(&s);

  s = string_prepend(s, "Nothing");
  test(s, "Nothing");
  s = string_prepend(s, "12345678901234567890");
  test(s, "12345678901234567890Nothing");
  s = string_prepend(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
  test(s, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890Nothing");

  string_free(&s);
  s = string_append(s, "Nothing");
  test(s, "Nothing");
  s = string_append(s, "12345678901234567890");
  test(s, "Nothing12345678901234567890");
  s = string_append(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
  test(s, "Nothing12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

  string_free(&s);
  s = string_new("printf_append");
  test(s, "printf_append");
  s = string_printf_append(s, "%8s %3d %10.6f", "string", 20, 3.4);
  test(s, "printf_append  string  20   3.400000");

  string_free(&s);
  s = string_new("");
  s = string_printf(s, "%8s %3d %10.6f", "string", 20, 3.4);
  test(s, "  string  20   3.400000");

  s2 = string_copy(s);
  test(s2, "  string  20   3.400000");

  testi(string_equal_char(s, string_string(s2)), 1);
  testi(string_equal(s, s2), 1);

  testi(string_equal_char(s, " string  20   3.40"), 0);
  s3 = string_new(" string  20   3.40");
  testi(string_equal(s, s3), 0);
  string_free(&s2);
  string_free(&s3);
  
  s = string_remove(s, 100000, 20);
  test(s, "  string  20   3.400000");

  s = string_remove(s, 15, 20);
  test(s, "  string  20   ");

  s = string_remove(s, 13, -1);
  test(s, "  string  20 ");

  s = string_remove(s, 1, 1);
  test(s, " string  20 ");

  s = string_remove(s, 7, 2);
  test(s, " string20 ");

  s = string_remove(s, 9, 1);
  test(s, " string20");

  s = string_remove(s, -1, -1);
  test(s, "");

  s = string_insert(s, -1, " string20");
  test(s, " string20");

  s = string_insert(s, 9, " ");
  test(s, " string20 ");

  s = string_insert(s, 7, " ");
  test(s, " string 20 ");

  s = string_insert(s, 1, " ");
  test(s, "  string 20 ");

  s = string_insert(s, 13, "  ");
  test(s, "  string 20   ");

  s = string_insert(s, 15, "3.400000");
  test(s, "  string 20   3.400000");
  
  s = string_insert(s, 10000, " morestuff");
  test(s, "  string 20   3.400000 morestuff");

  s = string_insert(s, -1, " morestuff");
  test(s, " morestuff  string 20   3.400000 morestuff");

  s2 = string_substr(s, 1, 4);
  test(s2, "more");
  string_free(&s2);

  s2 = string_substr(s, 5, 7);
  test(s2, "stuff  ");
  string_free(&s2);
  string_free(&s);

  return retval;
}