예제 #1
0
/* 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;
}
예제 #2
0
/**
   The set builtin. Creates, updates and erases environment variables
   and environemnt variable arrays.
*/
static int builtin_set( parser_t &parser, wchar_t **argv ) 
{
	
	/**
	   Variables used for parsing the argument list
	*/
	static const struct woption
		long_options[] = 
		{
			{ 
				L"export", no_argument, 0, 'x' 
			}
			,
			{ 
				L"global", no_argument, 0, 'g' 
			}
			,
			{ 
				L"local", no_argument, 0, 'l'  
			}
			,
			{ 
				L"erase", no_argument, 0, 'e'  
			}
			,
			{ 
				L"names", no_argument, 0, 'n' 
			} 
			,
			{ 
				L"unexport", no_argument, 0, 'u' 
			} 
			,
			{ 
				L"universal", no_argument, 0, 'U'
			}
            ,
			{ 
				L"long", no_argument, 0, 'L'
			} 
			,
			{ 
				L"query", no_argument, 0, 'q' 
			} 
			,
			{ 
				L"help", no_argument, 0, 'h' 
			} 
			,
			{ 
				0, 0, 0, 0 
			}
		}
	;
	
	const wchar_t *short_options = L"+xglenuULqh";

	int argc = builtin_count_args(argv);

	/*
	  Flags to set the work mode
	*/
	int local = 0, global = 0, exportv = 0;
	int erase = 0, list = 0, unexport=0;
	int universal = 0, query=0;
	bool shorten_ok = true;

	/*
	  Variables used for performing the actual work
	*/
	wchar_t *dest = 0;
	int retcode=0;
	int scope;
	int slice=0;
	int i;
	
	wchar_t *bad_char;
	
	
	/* Parse options to obtain the requested operation and the modifiers */
	woptind = 0;
	while (1) 
	{
		int c = wgetopt_long(argc, argv, short_options, long_options, 0);

		if (c == -1) 
		{
			break;
		}
    
		switch(c) 
		{
			case 0:
				break;

			case 'e':
				erase = 1;
				break;

			case 'n':
				list = 1;
				break;

			case 'x':
				exportv = 1;
				break;

			case 'l':
				local = 1;
				break;

			case 'g':
				global = 1;
				break;

			case 'u':
				unexport = 1;
				break;

			case 'U':
				universal = 1;
				break;
            
            case 'L':
                shorten_ok = false;
                break;

			case 'q':
				query = 1;
				break;

			case 'h':
				builtin_print_help( parser, argv[0], stdout_buffer );
				return 0;

			case '?':
				builtin_unknown_option( parser, argv[0], argv[woptind-1] );
				return 1;

			default:
				break;
		}
	}

	/*
	  Ok, all arguments have been parsed, let's validate them
	*/

	/*
	  If we are checking the existance of a variable (-q) we can not
	  also specify scope
	*/

	if( query && (erase || list) )
	{
		append_format(stderr_buffer,
				  BUILTIN_ERR_COMBO,
				  argv[0] );
		
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}
	

	/* We can't both list and erase varaibles */
	if( erase && list ) 
	{
		append_format(stderr_buffer,
				  BUILTIN_ERR_COMBO,
				  argv[0] );		

		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}

	/*
	  Variables can only have one scope
	*/
	if( local + global + universal > 1 ) 
	{
		append_format(stderr_buffer,
				   BUILTIN_ERR_GLOCAL,
				   argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}

	/*
	  Variables can only have one export status
	*/
	if( exportv && unexport ) 
	{
		append_format(stderr_buffer,
				   BUILTIN_ERR_EXPUNEXP,
				   argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}

	/*
	  Calculate the scope value for variable assignement
	*/
	scope = (local ? ENV_LOCAL : 0) | (global ? ENV_GLOBAL : 0) | (exportv ? ENV_EXPORT : 0) | (unexport ? ENV_UNEXPORT : 0) | (universal ? ENV_UNIVERSAL:0) | ENV_USER; 

	if( query )
	{
		/*
		  Query mode. Return the number of variables that do not exist
		  out of the specified variables.
		*/
		int i;
		for( i=woptind; i<argc; i++ )
		{
			wchar_t *arg = argv[i];
			int slice=0;

			if( !(dest = wcsdup(arg)))
			{
				DIE_MEM();		
			}

			if( wcschr( dest, L'[' ) )
			{
				slice = 1;
				*wcschr( dest, L'[' )=0;
			}
			
			if( slice )
			{
				std::vector<long> indexes;
				wcstring_list_t result;
				size_t j;
				
                env_var_t dest_str = env_get_string(dest);
                if (! dest_str.missing())
                    tokenize_variable_array( dest_str, result );
								
				if( !parse_index( indexes, arg, dest, result.size() ) )
				{
					builtin_print_help( parser, argv[0], stderr_buffer );
					retcode = 1;
					break;
				}
				for( j=0; j < indexes.size() ; j++ )
				{
					long idx = indexes[j];
					if( idx < 1 || (size_t)idx > result.size() )
					{
						retcode++;
					}
				}
			}
			else
			{
				if( !env_exist( arg, scope ) )
				{
					retcode++;
				}
			}
			
			free( dest );
			
		}
		return retcode;
	}
	
	if( list ) 
	{
		/* Maybe we should issue an error if there are any other arguments? */
		print_variables(0, 0, shorten_ok, scope);
		return 0;
	} 
	
	if( woptind == argc )
	{
		/*
		  Print values of variables
		*/

		if( erase ) 
		{
			append_format(stderr_buffer,
					   _(L"%ls: Erase needs a variable name\n"), 
					   argv[0] );
			
			builtin_print_help( parser, argv[0], stderr_buffer );
			retcode = 1;
		}
		else
		{
			print_variables( 1, 1, shorten_ok, scope );
		}
		
		return retcode;
	}

	if( !(dest = wcsdup(argv[woptind])))
	{
		DIE_MEM();		
	}

	if( wcschr( dest, L'[' ) )
	{
		slice = 1;
		*wcschr( dest, L'[' )=0;
	}
	
	if( !wcslen( dest ) )
	{
		free( dest );
		append_format(stderr_buffer, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}
	
	if( (bad_char = wcsvarname( dest ) ) )
	{
		append_format(stderr_buffer, BUILTIN_ERR_VARCHAR, argv[0], *bad_char );
		builtin_print_help( parser, argv[0], stderr_buffer );
		free( dest );
		return 1;
	}
	
	if( slice && erase && (scope != ENV_USER) )
	{
		free( dest );
		append_format(stderr_buffer, _(L"%ls: Can not specify scope when erasing array slice\n"), argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}
	
	/*
	  set assignment can work in two modes, either using slices or
	  using the whole array. We detect which mode is used here.
	*/
	
	if( slice )
	{

		/*
		  Slice mode
		*/
		int idx_count, val_count;
		wcstring_list_t values;
		std::vector<long> indexes;
		wcstring_list_t result;
		
        const env_var_t dest_str = env_get_string(dest);
        if (! dest_str.missing())
            tokenize_variable_array( dest_str, result );
		
		for( ; woptind<argc; woptind++ )
		{			
			if( !parse_index( indexes, argv[woptind], dest, result.size() ) )
			{
				builtin_print_help( parser, argv[0], stderr_buffer );
				retcode = 1;
				break;
			}
			
			val_count = argc-woptind-1;
			idx_count = indexes.size();

			if( !erase )
			{
				if( val_count < idx_count )
				{
					append_format(stderr_buffer, _(BUILTIN_SET_ARG_COUNT), argv[0] );
					builtin_print_help( parser, argv[0], stderr_buffer );
					retcode=1;
					break;
				}
				if( val_count == idx_count )
				{
					woptind++;
					break;
				}
			}
		}		

		if( !retcode )
		{
			/*
			  Slice indexes have been calculated, do the actual work
			*/

			if( erase )
			{
				erase_values(result, indexes);
				my_env_set( dest, result, scope);
			}
			else
			{
				wcstring_list_t value;
//				al_init(&value);

				while( woptind < argc ) 
				{
					value.push_back( argv[woptind++] );
				}

				if( update_values( result, 
								   indexes,
								   value ) )
				{
					append_format(stderr_buffer, L"%ls: ", argv[0] );
					append_format(stderr_buffer, ARRAY_BOUNDS_ERR );
					stderr_buffer.push_back(L'\n');
				}
				
				my_env_set(dest, result, scope);
								
//				al_destroy( &value );
								
			}			
		}

//		al_foreach( &result, &free );
//		al_destroy( &result );

//		al_destroy(&indexes);
//		al_destroy(&values);
		
	}
	else
	{
		woptind++;
		
		/*
		  No slicing
		*/
		if( erase )
		{
			if( woptind != argc )
			{
				append_format(stderr_buffer, 
						   _(L"%ls: Values cannot be specfied with erase\n"),
						   argv[0] );
				builtin_print_help( parser, argv[0], stderr_buffer );
				retcode=1;
			}
			else
			{
				retcode = env_remove( dest, scope );
			}
		}
		else
		{
            wcstring_list_t val;
			for( i=woptind; i<argc; i++ )
                val.push_back(argv[i]);
			retcode = my_env_set( dest, val, scope );
		}		
	}
	
	free( dest );
	
	return retcode;

}
예제 #3
0
void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_pos, int error_pos)
{
    size_t stop_pos = token_pos+1;

    switch (token[stop_pos])
    {
        case BRACKET_BEGIN:
        {
            wchar_t *cpy = wcsdup(token);
            *(cpy+token_pos)=0;
            wchar_t *name = &cpy[stop_pos+1];
            wchar_t *end = wcschr(name, BRACKET_END);
            wchar_t *post;
            int is_var=0;
            if (end)
            {
                post = end+1;
                *end = 0;

                if (!wcsvarname(name))
                {
                    is_var = 1;
                }
            }

            if (is_var)
            {
                parser.error(SYNTAX_ERROR,
                             error_pos,
                             COMPLETE_VAR_BRACKET_DESC,
                             cpy,
                             name,
                             post);
            }
            else
            {
                parser.error(SYNTAX_ERROR,
                             error_pos,
                             COMPLETE_VAR_BRACKET_DESC,
                             L"",
                             L"VARIABLE",
                             L"");
            }
            free(cpy);

            break;
        }

        case INTERNAL_SEPARATOR:
        {
            parser.error(SYNTAX_ERROR,
                         error_pos,
                         COMPLETE_VAR_PARAN_DESC);
            break;
        }

        case 0:
        {
            parser.error(SYNTAX_ERROR,
                         error_pos,
                         COMPLETE_VAR_NULL_DESC);
            break;
        }

        default:
        {
            wchar_t token_stop_char = token[stop_pos];
            // Unescape (see http://github.com/fish-shell/fish-shell/issues/50)
            if (token_stop_char == ANY_CHAR)
                token_stop_char = L'?';
            else if (token_stop_char == ANY_STRING || token_stop_char == ANY_STRING_RECURSIVE)
                token_stop_char = L'*';

            parser.error(SYNTAX_ERROR,
                         error_pos,
                         (token_stop_char == L'?' ? COMPLETE_YOU_WANT_STATUS : COMPLETE_VAR_DESC),
                         token_stop_char);
            break;
        }
    }
}
예제 #4
0
void parse_util_expand_variable_error(const parse_node_t &node, const wcstring &token, size_t token_pos, size_t error_pos, parse_error_list_t *out_errors)
{
    size_t stop_pos = token_pos+1;

    switch (token[stop_pos])
    {
        case BRACKET_BEGIN:
        {
            wchar_t *cpy = wcsdup(token.c_str());
            *(cpy+token_pos)=0;
            wchar_t *name = &cpy[stop_pos+1];
            wchar_t *end = wcschr(name, BRACKET_END);
            wchar_t *post = NULL;
            int is_var=0;
            if (end)
            {
                post = end+1;
                *end = 0;

                if (!wcsvarname(name))
                {
                    is_var = 1;
                }
            }

            if (is_var)
            {
                append_syntax_error(out_errors,
                                    node,
                                    COMPLETE_VAR_BRACKET_DESC,
                                    cpy,
                                    name,
                                    post);
            }
            else
            {
                append_syntax_error(out_errors,
                                    node,
                                    COMPLETE_VAR_BRACKET_DESC,
                                    L"",
                                    L"VARIABLE",
                                    L"");
            }
            free(cpy);

            break;
        }

        case INTERNAL_SEPARATOR:
        {
            append_syntax_error(out_errors,
                                node,
                                COMPLETE_VAR_PARAN_DESC);
            break;
        }

        case 0:
        {
            append_syntax_error(out_errors,
                                node,
                                COMPLETE_VAR_NULL_DESC);
            break;
        }

        default:
        {
            wchar_t token_stop_char = token[stop_pos];
            // Unescape (see http://github.com/fish-shell/fish-shell/issues/50)
            if (token_stop_char == ANY_CHAR)
                token_stop_char = L'?';
            else if (token_stop_char == ANY_STRING || token_stop_char == ANY_STRING_RECURSIVE)
                token_stop_char = L'*';

            append_syntax_error(out_errors,
                                node,
                                (token_stop_char == L'?' ? COMPLETE_YOU_WANT_STATUS : COMPLETE_VAR_DESC),
                                token_stop_char);
            break;
        }
    }
}
예제 #5
0
/* 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;
}
예제 #6
0
/// Test if the given string is a valid variable name.
///
/// \return null if this is a valid name, and a pointer to the first invalid character otherwise.
const wchar_t *wcsvarname(const wcstring &str) { return wcsvarname(str.c_str()); }
예제 #7
0
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;	
}