Пример #1
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;
}
Пример #2
0
int main(int argc, char **argv)
{
    save_argv0(argv[0]);

    struct cyrbu_cmd_options options = {0};
    enum cyrbu_mode mode = CYRBU_MODE_UNSPECIFIED;
    enum cyrbu_cmd cmd = CYRBU_CMD_UNSPECIFIED;
    const char *alt_config = NULL;
    const char *backup_name = NULL;
    const char *command = NULL;
    const char *subcommand = NULL;
    struct backup *backup = NULL;
    mbname_t *mbname = NULL;
    int i, opt, r = 0;

    while ((opt = getopt(argc, argv, "C:fmuv")) != EOF) {
        switch (opt) {
        case 'C':
            alt_config = optarg;
            break;
        case 'f':
            if (mode != CYRBU_MODE_UNSPECIFIED) usage();
            mode = CYRBU_MODE_FILENAME;
            break;
        case 'm':
            if (mode != CYRBU_MODE_UNSPECIFIED) usage();
            mode = CYRBU_MODE_MBOXNAME;
            break;
        case 'u':
            if (mode != CYRBU_MODE_UNSPECIFIED) usage();
            mode = CYRBU_MODE_USERNAME;
            break;
        case 'v':
            options.verbose++;
            break;
        default:
            usage();
            break;
        }
    }

    /* default mode is username */
    if (mode == CYRBU_MODE_UNSPECIFIED)
        mode = CYRBU_MODE_USERNAME;

    /* get the backup name */
    if (optind == argc) usage();
    backup_name = argv[optind++];

    /* get the command */
    if (optind == argc) usage();
    command = argv[optind++];

    /* get the subcommand */
    if (optind == argc) usage();
    subcommand = argv[optind++];

    /* parse the command and subcommand */
    cmd = parse_cmd_string(command, subcommand);

    /* check remaining arguments based on command */
    switch (cmd) {
    case CYRBU_CMD_LIST_ALL:
    case CYRBU_CMD_LIST_CHUNKS:
    case CYRBU_CMD_LIST_MAILBOXES:
    case CYRBU_CMD_LIST_MESSAGES:
        /* these want no more arguments */
        if (optind != argc) usage();
        break;
    case CYRBU_CMD_SHOW_CHUNKS:
    case CYRBU_CMD_SHOW_MAILBOXES:
    case CYRBU_CMD_SHOW_MESSAGES:
        /* these need at least one more argument */
        if (optind == argc) usage();
        break;
    case CYRBU_CMD_DUMP_CHUNK:
    case CYRBU_CMD_DUMP_MAILBOX:
    case CYRBU_CMD_DUMP_MESSAGE:
        /* these need exactly one more argument */
        if (argc - optind != 1) usage();
        break;
    default:
        usage();
        break;
    }

    /* build a nice args list */
    options.argv = strarray_new();
    for (i = optind; i < argc; i++) {
        strarray_add(options.argv, argv[i]);
    }

    // FIXME finish parsing options

    cyrus_init(alt_config, "cyr_backup", 0, 0);

    /* open backup */
    switch (mode) {
    case CYRBU_MODE_FILENAME:
        r = backup_open_paths(&backup, backup_name, NULL,
                              BACKUP_OPEN_NONBLOCK, BACKUP_OPEN_NOCREATE);
        break;
    case CYRBU_MODE_MBOXNAME:
        mbname = mbname_from_intname(backup_name);
        if (!mbname) usage();
        r = backup_open(&backup, mbname,
                        BACKUP_OPEN_NONBLOCK, BACKUP_OPEN_NOCREATE);
        break;
    case CYRBU_MODE_USERNAME:
        mbname = mbname_from_userid(backup_name);
        if (!mbname) usage();
        r = backup_open(&backup, mbname,
                        BACKUP_OPEN_NONBLOCK, BACKUP_OPEN_NOCREATE);
        break;
    default:
        usage();
        break;
    }

    /* run command */
    if (!r && cmd_func[cmd])
        r = cmd_func[cmd](backup, &options);

    if (r)
        fprintf(stderr, "%s: %s\n", backup_name, error_message(r));

    /* close backup */
    if (backup)
        backup_close(&backup);

    /* clean up and exit */
    backup_cleanup_staging_path();
    cyrus_done();

    strarray_free(options.argv);
    exit(r ? EC_TEMPFAIL : EC_OK);
}