/* Creates a file entry like "SET fish_color_cwd:FF0". Appends the result to *result (as UTF8). Returns true on success. storage may be used for temporary storage, to avoid allocations */
static bool append_file_entry(fish_message_type_t type, const wcstring &key_in, const wcstring &val_in, std::string *result, std::string *storage)
{
    assert(storage != NULL);
    assert(result != NULL);
    
    // Record the length on entry, in case we need to back up
    bool success = true;
    const size_t result_length_on_entry = result->size();
    
    // Append header like "SET "
    result->append(type==SET ? SET_MBS : SET_EXPORT_MBS);
    result->push_back(' ');

    // Append variable name like "fish_color_cwd"
    if (wcsvarname(key_in.c_str()))
    {
        debug(0, L"Illegal variable name: '%ls'", key_in.c_str());
        success = false;
    }
    if (success && ! append_utf8(key_in, result, storage))
    {
        debug(0, L"Could not convert %ls to narrow character string", key_in.c_str());
        success = false;
    }
    
    // Append ":"
    if (success)
    {
        result->push_back(':');
    }
    
    // Append value
    if (success && ! append_utf8(full_escape(val_in.c_str()), result, storage))
    {
        debug(0, L"Could not convert %ls to narrow character string", val_in.c_str());
        success = false;
    }
    
    // Append newline
    if (success)
    {
        result->push_back('\n');
    }
    
    // Don't modify result on failure. It's sufficient to simply resize it since all we ever did was append to it.
    if (! success)
    {
        result->resize(result_length_on_entry);
    }
    
    return success;
}
/* Returns an instance of message_t allocated via new */
message_t *create_message(fish_message_type_t type,
                          const wchar_t *key_in,
                          const wchar_t *val_in)
{
    message_t *msg = new message_t;
    msg->count = 0;

    char *key=0;

    //  debug( 4, L"Crete message of type %d", type );

    if (key_in)
    {
        if (wcsvarname(key_in))
        {
            debug(0, L"Illegal variable name: '%ls'", key_in);
            return 0;
        }

        key = wcs2utf(key_in);
        if (!key)
        {
            debug(0,
                  L"Could not convert %ls to narrow character string",
                  key_in);
            return 0;
        }
    }


    switch (type)
    {
        case SET:
        case SET_EXPORT:
        {
            if (!val_in)
            {
                val_in=L"";
            }

            wcstring esc = full_escape(val_in);
            char *val = wcs2utf(esc.c_str());
            set_body(msg, (type==SET?SET_MBS:SET_EXPORT_MBS), " ", key, ":", val, "\n", NULL);
            free(val);

            break;
        }

        case ERASE:
        {
            set_body(msg, ERASE_MBS, " ", key, "\n", NULL);
            break;
        }

        case BARRIER:
        {
            set_body(msg, BARRIER_MBS, "\n", NULL);
            break;
        }

        case BARRIER_REPLY:
        {
            set_body(msg, BARRIER_REPLY_MBS, "\n", NULL);
            break;
        }

        default:
        {
            debug(0, L"create_message: Unknown message type");
        }
    }

    free(key);

    //  debug( 4, L"Message body is '%s'", msg->body );

    return msg;
}
message_t *create_message( int type,
						   const wchar_t *key_in, 
						   const wchar_t *val_in )
{
	message_t *msg=0;
	
	char *key=0;
	size_t sz;

//	debug( 4, L"Crete message of type %d", type );
	
	if( key_in )
	{
		if( wcsvarname( key_in ) )
		{
			debug( 0, L"Illegal variable name: '%ls'", key_in );
			return 0;
		}
		
		key = wcs2utf(key_in);
		if( !key )
		{
			debug( 0,
				   L"Could not convert %ls to narrow character string",
				   key_in );
			return 0;
		}
	}
	
	
	switch( type )
	{
		case SET:
		case SET_EXPORT:
		{
			if( !val_in )
			{
				val_in=L"";
			}
			
			wcstring esc = full_escape( val_in );			
			char *val = wcs2utf(esc.c_str());
						
			sz = strlen(type==SET?SET_MBS:SET_EXPORT_MBS) + strlen(key) + strlen(val) + 4;
			msg = (message_t *)malloc( sizeof( message_t ) + sz );
			
			if( !msg )
				DIE_MEM();
			
			strcpy( msg->body, (type==SET?SET_MBS:SET_EXPORT_MBS) );
			strcat( msg->body, " " );
			strcat( msg->body, key );
			strcat( msg->body, ":" );
			strcat( msg->body, val );
			strcat( msg->body, "\n" );
			
			free( val );
			
			break;
		}

		case ERASE:
		{
            sz = strlen(ERASE_MBS) + strlen(key) + 3;
            msg = (message_t *)malloc( sizeof( message_t ) + sz );

			if( !msg )
				DIE_MEM();
			
            strcpy( msg->body, ERASE_MBS " " );
            strcat( msg->body, key );
            strcat( msg->body, "\n" );
            break;
		}

		case BARRIER:
		{
			msg = (message_t *)malloc( sizeof( message_t )  + 
						  strlen( BARRIER_MBS ) +2);
			if( !msg )
				DIE_MEM();
			strcpy( msg->body, BARRIER_MBS "\n" );
			break;
		}
		
		case BARRIER_REPLY:
		{
			msg = (message_t *)malloc( sizeof( message_t )  +
						  strlen( BARRIER_REPLY_MBS ) +2);
			if( !msg )
				DIE_MEM();
			strcpy( msg->body, BARRIER_REPLY_MBS "\n" );
			break;
		}
		
		default:
		{
			debug( 0, L"create_message: Unknown message type" );
		}
	}

	free( key );

	if( msg )
		msg->count=0;

//	debug( 4, L"Message body is '%s'", msg->body );

	return msg;	
}