Exemple #1
0
static void input_terminfo_destroy()
{
	
	if( terminfo_mappings )
	{
		halloc_free( terminfo_mappings );
	}
}
Exemple #2
0
/**
   Recursively free all complete_entry_opt_t structs and their contents
*/
static void complete_free_opt_recursive( complete_entry_opt_t *o )
{
	if( !o )
		return;

	complete_free_opt_recursive( o->next );
	halloc_free( o );
}
Exemple #3
0
/**
   Release all memory used by the specified history mode.
*/
static void history_destroy_mode( history_mode_t *m )
{
    halloc_free( m->item_context );

    if( m->mmap_start && (m->mmap_start != MAP_FAILED ))
    {
        munmap( m->mmap_start, m->mmap_length);
    }

}
Exemple #4
0
/**
   Test path functions
 */
static void test_path()
{
	say( L"Testing path functions" );

	void *context = halloc( 0, 0 );
	

	wchar_t *can = path_make_canonical( context, L"//foo//////bar/" );
	
	if( wcscmp( can, L"/foo/bar" ) )
	{
		err( L"Bug in canonical PATH code" );
	}
	
	halloc_free( context );
	
}
Exemple #5
0
/**
   Load contents of the backing file to memory
*/
static void history_load( history_mode_t *m )
{
    int fd;
    int ok=0;

    void *context;
    wchar_t *filename;

    if( !m )
        return;

    m->has_loaded=1;

    signal_block();

    context = halloc( 0, 0 );
    filename = history_filename( context, m->name, 0 );

    if( filename )
    {
        if( ( fd = wopen( filename, O_RDONLY ) ) > 0 )
        {
            off_t len = lseek( fd, 0, SEEK_END );
            if( len != (off_t)-1)
            {
                m->mmap_length = (size_t)len;
                if( lseek( fd, 0, SEEK_SET ) == 0 )
                {
                    if( (m->mmap_start = mmap( 0, m->mmap_length, PROT_READ, MAP_PRIVATE, fd, 0 )) != MAP_FAILED )
                    {
                        ok = 1;
                        history_populate_from_mmap( m );
                    }
                }
            }
            close( fd );
        }
    }

    halloc_free( context );
    signal_unblock();
}
Exemple #6
0
/**
   The complete builtin. Used for specifying programmable
   tab-completions. Calls the functions in complete.c for any heavy
   lifting. Defined in builtin_complete.c
*/
static int builtin_complete( wchar_t **argv )
{
	int res=0;
	int argc=0;
	int result_mode=SHARED;
	int remove = 0;
	int authoritative = -1;
	int flags = COMPLETE_AUTO_SPACE;
	
	string_buffer_t short_opt;
	array_list_t gnu_opt, old_opt;
	wchar_t *comp=L"", *desc=L"", *condition=L"";

	wchar_t *do_complete = 0;
	
	array_list_t cmd;
	array_list_t path;

	static int recursion_level=0;
	
	if( !is_interactive_session )
	{
		debug( 1, _(L"%ls: Command only available in interactive sessions"), argv[0] );
	}
	
	al_init( &cmd );
	al_init( &path );
	sb_init( &short_opt );
	al_init( &gnu_opt );
	al_init( &old_opt );
	
	argc = builtin_count_args( argv );	
	
	woptind=0;
	
	while( res == 0 )
	{
		const static struct woption
			long_options[] =
			{
				{
					L"exclusive", no_argument, 0, 'x' 
				}
				,
				{
					L"no-files", no_argument, 0, 'f' 
				}
				,
				{
					L"require-parameter", no_argument, 0, 'r' 
				}
				,
				{
					L"path", required_argument, 0, 'p'
				}
				,					
				{
					L"command", required_argument, 0, 'c' 
				}
				,					
				{
					L"short-option", required_argument, 0, 's' 
				}
				,
				{
					L"long-option", required_argument, 0, 'l'
				}
				,
				{
					L"old-option", required_argument, 0, 'o' 
				}
				,
				{
					L"description", required_argument, 0, 'd'
				}
				,
				{
					L"arguments", required_argument, 0, 'a'
				}
				,
				{
					L"erase", no_argument, 0, 'e'
				}
				,
				{
					L"unauthoritative", no_argument, 0, 'u'
				}
				,
				{
					L"authoritative", no_argument, 0, 'A'
				}
				,
				{
					L"condition", required_argument, 0, 'n'
				}
				,
				{
					L"do-complete", optional_argument, 0, 'C'
				}
				,
				{
					L"help", no_argument, 0, 'h'
				}
				,
				{ 
					0, 0, 0, 0 
				}
			}
		;		
		
		int opt_index = 0;
		
		int opt = wgetopt_long( argc,
								argv, 
								L"a:c:p:s:l:o:d:frxeuAn:C::h", 
								long_options, 
								&opt_index );
		if( opt == -1 )
			break;
			
		switch( opt )
		{
			case 0:
				if(long_options[opt_index].flag != 0)
					break;
                sb_printf( sb_err,
                           BUILTIN_ERR_UNKNOWN,
                           argv[0],
                           long_options[opt_index].name );
				builtin_print_help( argv[0], sb_err );

				
				res = 1;
				break;
				
			case 'x':					
				result_mode |= EXCLUSIVE;
				break;
					
			case 'f':					
				result_mode |= NO_FILES;
				break;
				
			case 'r':					
				result_mode |= NO_COMMON;
				break;
					
			case 'p':	
			case 'c':
			{
				wchar_t *a = unescape( woptarg, 1);
				if( a )
				{
					al_push( (opt=='p'?&path:&cmd), a );
				}
				else
				{
					sb_printf( sb_err, L"%ls: Invalid token '%ls'\n", argv[0], woptarg );
					res = 1;					
				}				
				break;
			}
				
			case 'd':
				desc = woptarg;
				break;
				
			case 'u':
				authoritative=0;
				break;
				
			case 'A':
				authoritative=1;
				break;
				
			case 's':
				sb_append( &short_opt, woptarg );
				break;
					
			case 'l':
				al_push( &gnu_opt, woptarg );
				break;
				
			case 'o':
				al_push( &old_opt, woptarg );
				break;

			case 'a':
				comp = woptarg;
				break;
				
			case 'e':
				remove = 1;
				break;

			case 'n':
				condition = woptarg;
				break;
				
			case 'C':
				do_complete = woptarg?woptarg:reader_get_buffer();
				break;
				
			case 'h':
				builtin_print_help( argv[0], sb_out );
				return 0;
				
			case '?':
				builtin_unknown_option( argv[0], argv[woptind-1] );
				res = 1;
				break;
				
		}
		
	}

	if( !res )
	{
		if( condition && wcslen( condition ) )
		{
			if( parser_test( condition, 0, 0, 0 ) )
			{
				sb_printf( sb_err,
						   L"%ls: Condition '%ls' contained a syntax error\n", 
						   argv[0],
						   condition );
				
				parser_test( condition, 0, sb_err, argv[0] );
				
				res = 1;
			}
		}
	}
	
	if( !res )
	{
		if( comp && wcslen( comp ) )
		{
			if( parser_test_args( comp, 0, 0 ) )
			{
				sb_printf( sb_err,
						   L"%ls: Completion '%ls' contained a syntax error\n", 
						   argv[0],
						   comp );
				
				parser_test_args( comp, sb_err, argv[0] );
				
				res = 1;
			}
		}
	}

	if( !res )
	{
		if( do_complete )
		{
			array_list_t *comp;
			int i;

			const wchar_t *prev_temporary_buffer = temporary_buffer;

			wchar_t *token;

			parse_util_token_extent( do_complete, wcslen( do_complete ), &token, 0, 0, 0 );
						
			temporary_buffer = do_complete;		

			if( recursion_level < 1 )
			{
				recursion_level++;
			
				comp = al_halloc( 0 );
			
				complete( do_complete, comp );
			
				for( i=0; i<al_get_count( comp ); i++ )
				{
					completion_t *next = (completion_t *)al_get( comp, i );
					wchar_t *prepend;
					
					if( next->flags & COMPLETE_NO_CASE )
					{
						prepend = L"";
					}
					else
					{
						prepend = token;
					}
						

					if( next->description )
					{
						sb_printf( sb_out, L"%ls%ls\t%ls\n", prepend, next->completion, next->description );
					}
					else
					{
						sb_printf( sb_out, L"%ls%ls\n", prepend, next->completion );
					}
				}
			
				halloc_free( comp );
				recursion_level--;
			}
		
			temporary_buffer = prev_temporary_buffer;		
		
		}
		else if( woptind != argc )
		{
			sb_printf( sb_err, 
					   _( L"%ls: Too many arguments\n" ),
					   argv[0] );
			builtin_print_help( argv[0], sb_err );

			res = 1;
		}
		else if( (al_get_count( &cmd) == 0 ) && (al_get_count( &path) == 0 ) )
		{
			/* No arguments specified, meaning we print the definitions of
			 * all specified completions to stdout.*/
			complete_print( sb_out );		
		}
		else
		{
			if( remove )
			{
				builtin_complete_remove( &cmd,
										 &path,
										 (wchar_t *)short_opt.buff,
										 &gnu_opt,
										 &old_opt );									 
			}
			else
			{
				builtin_complete_add( &cmd, 
									  &path,
									  (wchar_t *)short_opt.buff,
									  &gnu_opt,
									  &old_opt, 
									  result_mode, 
									  authoritative,
									  condition,
									  comp,
									  desc,
									  flags ); 
			}

		}	
	}
	
	al_foreach( &cmd, &free );
	al_foreach( &path, &free );

	al_destroy( &cmd );
	al_destroy( &path );
	sb_destroy( &short_opt );
	al_destroy( &gnu_opt );
	al_destroy( &old_opt );

	return res;
}
Exemple #7
0
int complete_is_valid_option( const wchar_t *str,
							  const wchar_t *opt,
							  array_list_t *errors )
{
	complete_entry_t *i;
	complete_entry_opt_t *o;
	wchar_t *cmd, *path;
	int found_match = 0;
	int authoritative = 1;
	int opt_found=0;
	hash_table_t gnu_match_hash;
	int is_gnu_opt=0;
	int is_old_opt=0;
	int is_short_opt=0;
	int is_gnu_exact=0;
	int gnu_opt_len=0;
	char *short_validated;

	void *context;

	CHECK( str, 0 );
	CHECK( opt, 0 );

	/*
	  Check some generic things like -- and - options.
	*/
	switch( wcslen(opt ) )
	{

		case 0:
		case 1:
		{
			return 1;
		}

		case 2:
		{
			if( wcscmp( L"--", opt ) == 0 )
			{
				return 1;
			}
			break;
		}
	}

	if( opt[0] != L'-' )
	{
		if( errors )
		{
			al_push( errors, wcsdup(L"Option does not begin with a '-'") );
		}
		return 0;
	}

	context = halloc( 0, 0 );

	if( !(short_validated = halloc( context, wcslen( opt ) )))
	{
		DIE_MEM();
	}



	memset( short_validated, 0, wcslen( opt ) );

	hash_init( &gnu_match_hash,
			   &hash_wcs_func,
			   &hash_wcs_cmp );

	is_gnu_opt = opt[1]==L'-';
	if( is_gnu_opt )
	{
		wchar_t *opt_end = wcschr(opt, L'=' );
		if( opt_end )
		{
			gnu_opt_len = (opt_end-opt)-2;
		}
		else
		{
			gnu_opt_len = wcslen(opt)-2;
		}
	}

	parse_cmd_string( context, str, &path, &cmd );

	/*
	  Make sure completions are loaded for the specified command
	*/
	complete_load( cmd, 0 );

	for( i=first_entry; i; i=i->next )
	{
		wchar_t *match = i->cmd_type?path:cmd;
		const wchar_t *a;

		if( !wildcard_match( match, i->cmd ) )
		{
			continue;
		}

		found_match = 1;

		if( !i->authoritative )
		{
			authoritative = 0;
			break;
		}


		if( is_gnu_opt )
		{

			for( o = i->first_option; o; o=o->next )
			{
				if( o->old_mode )
				{
					continue;
				}

				if( wcsncmp( &opt[2], o->long_opt, gnu_opt_len )==0)
				{
					hash_put( &gnu_match_hash, o->long_opt, L"" );
					if( (wcsncmp( &opt[2],
								  o->long_opt,
								  wcslen( o->long_opt) )==0) )
					{
						is_gnu_exact=1;
					}
				}
			}
		}
		else
		{
			/* Check for old style options */
			for( o = i->first_option; o; o=o->next )
			{
				if( !o->old_mode )
					continue;


				if( wcscmp( &opt[1], o->long_opt )==0)
				{
					opt_found = 1;
					is_old_opt = 1;
					break;
				}

			}

			if( is_old_opt )
				break;


			for( a = &opt[1]; *a; a++ )
			{

				wchar_t *str_pos = wcschr(i->short_opt_str, *a);

				if  (str_pos )
				{
					if( *(str_pos +1)==L':' )
					{
						/*
						  This is a short option with an embedded argument,
						  call complete_is_valid_argument on the argument.
						*/
						wchar_t nopt[3];
						nopt[0]=L'-';
						nopt[1]=opt[1];
						nopt[2]=L'\0';

						short_validated[a-opt] =
							complete_is_valid_argument( str, nopt, &opt[2]);
					}
					else
					{
						short_validated[a-opt]=1;
					}
				}
			}
		}
	}

	if( authoritative )
	{

		if( !is_gnu_opt && !is_old_opt )
			is_short_opt = 1;


		if( is_short_opt )
		{
			int j;

			opt_found=1;
			for( j=1; j<wcslen(opt); j++)
			{
				if ( !short_validated[j])
				{
					if( errors )
					{
						wchar_t str[2];
						str[0] = opt[j];
						str[1]=0;
						al_push( errors,
								 wcsdupcat(_( L"Unknown option: " ), L"'", str, L"'" ) );
					}

					opt_found = 0;
					break;
				}

			}
		}

		if( is_gnu_opt )
		{
			opt_found = is_gnu_exact || (hash_get_count( &gnu_match_hash )==1);
			if( errors && !opt_found )
			{
				if( hash_get_count( &gnu_match_hash )==0)
				{
					al_push( errors,
							 wcsdupcat( _(L"Unknown option: "), L"'", opt, L"\'" ) );
				}
				else
				{
					al_push( errors,
							 wcsdupcat( _(L"Multiple matches for option: "), L"'", opt, L"\'" ) );
				}
			}
		}
	}

	hash_destroy( &gnu_match_hash );

	halloc_free( context );

	return (authoritative && found_match)?opt_found:1;
}
Exemple #8
0
/**
   Save the specified mode to file
*/
static void history_save_mode( void *n, history_mode_t *m )
{
    FILE *out;
    history_mode_t *on_disk;
    int i;
    int has_new=0;
    wchar_t *tmp_name;

    int ok = 1;

    /*
      First check if there are any new entries to save. If not, then
      we can just return
    */
    for( i=0; i<al_get_count(&m->item); i++ )
    {
        void *ptr = al_get( &m->item, i );
        has_new = item_is_new( m, ptr );
        if( has_new )
        {
            break;
        }
    }

    if( !has_new )
    {
        return;
    }

    signal_block();

    /*
      Set up on_disk variable to describe the current contents of the
      history file
    */
    on_disk = history_create_mode( m->name );
    history_load( on_disk );

    tmp_name = history_filename( on_disk, m->name, L".tmp" );

    if( tmp_name )
    {
        tmp_name = wcsdup(tmp_name );

        if( (out=wfopen( tmp_name, "w" ) ) )
        {
            hash_table_t mine;

            hash_init( &mine, &hash_item_func, &hash_item_cmp );

            for( i=0; i<al_get_count(&m->item); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    hash_put( &mine, item_get( m, ptr ), L"" );
                }
            }

            /*
              Re-save the old history
            */
            for( i=0; ok && (i<al_get_count(&on_disk->item)); i++ )
            {
                void *ptr = al_get( &on_disk->item, i );
                item_t *i = item_get( on_disk, ptr );
                if( !hash_get( &mine, i ) )
                {
                    if( item_write( out, on_disk, ptr ) == -1 )
                    {
                        ok = 0;
                        break;
                    }
                }

            }

            hash_destroy( &mine );

            /*
              Add our own items last
            */
            for( i=0; ok && (i<al_get_count(&m->item)); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    if( item_write( out, m, ptr ) == -1 )
                    {
                        ok = 0;
                    }
                }
            }

            if( fclose( out ) || !ok )
            {
                /*
                  This message does not have high enough priority to
                  be shown by default.
                */
                debug( 2, L"Error when writing history file" );
            }
            else
            {
                wrename( tmp_name, history_filename( on_disk, m->name, 0 ) );
            }
        }
        free( tmp_name );
    }

    halloc_free( on_disk);

    if( ok )
    {

        /*
          Reset the history. The item_t entries created in this session
          are not lost or dropped, they are stored in the session_item
          hash table. On reload, they will be automatically inserted at
          the end of the history list.
        */

        if( m->mmap_start && (m->mmap_start != MAP_FAILED ) )
        {
            munmap( m->mmap_start, m->mmap_length );
        }

        al_truncate( &m->item, 0 );
        al_truncate( &m->used, 0 );
        m->pos = 0;
        m->has_loaded = 0;
        m->mmap_start=0;
        m->mmap_length=0;

        m->save_timestamp=time(0);
        m->new_count = 0;
    }

    signal_unblock();
}
Exemple #9
0
/**
   Free all memory used by specified mistory mode
 */
static void history_destroy_mode_wrapper( void *n, history_mode_t *m )
{
    halloc_free( m );
}