rem: if (check_inverse(optarg, &invert)) optind++;
add: check_inverse(optarg, &invert, &optind, argc);
context: int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle){	struct ip6t_entry fw, *e = NULL;	int invert = 0;	unsigned int nsaddrs = 0, ndaddrs = 0;	struct in6_addr *saddrs = NULL, *daddrs = NULL;	int c, verbose = 0;	const char *chain = NULL;	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;	const char *policy = NULL, *newname = NULL;	unsigned int rulenum = 0, options = 0, command = 0;	const char *pcnt = NULL, *bcnt = NULL;	int ret = 1;	struct ip6tables_match *m;	struct ip6tables_target *target = NULL;	struct ip6tables_target *t;	const char *jumpto = "";	char *protocol = NULL;	const char *modprobe = NULL;	char icmp6p[] = "icmpv6";	memset(&fw, 0, sizeof(fw));	opts = original_opts;	global_option_offset = 0;	/* re-set optind to 0 in case do_command gets called	 * a second time */	optind = 0;	/* clear mflags in case do_command gets called a second time	 * (we clear the global list of all matches for security)*/	for (m = ip6tables_matches; m; m = m->next) {		m->mflags = 0;		m->used = 0;	}	for (t = ip6tables_targets; t; t = t->next) {		t->tflags = 0;		t->used = 0;	}	/* Suppress error messages: we may add new options if we           demand-load a protocol. */	opterr = 0;	while ((c = getopt_long(argc, argv,	   "-A:C:D:R:I:L::F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:",					   opts, NULL)) != -1) {		switch (c) {			/*			 * Command selection			 */		case 'A':			add_command(&command, CMD_APPEND, CMD_NONE,				    invert);			chain = optarg;			break;		case 'D':			add_command(&command, CMD_DELETE, CMD_NONE,				    invert);			chain = optarg;			if (optind < argc && argv[optind][0] != '-'			    && argv[optind][0] != '!') {				rulenum = parse_rulenumber(argv[optind++]);				command = CMD_DELETE_NUM;			}			break;		case 'C':			add_command(&command, CMD_CHECK, CMD_NONE,				    invert);			chain = optarg;			break;		case 'R':			add_command(&command, CMD_REPLACE, CMD_NONE,				    invert);			chain = optarg;			if (optind < argc && argv[optind][0] != '-'			    && argv[optind][0] != '!')				rulenum = parse_rulenumber(argv[optind++]);			else				exit_error(PARAMETER_PROBLEM,					   "-%c requires a rule number",					   cmd2char(CMD_REPLACE));			break;		case 'I':			add_command(&command, CMD_INSERT, CMD_NONE,				    invert);			chain = optarg;			if (optind < argc && argv[optind][0] != '-'			    && argv[optind][0] != '!')				rulenum = parse_rulenumber(argv[optind++]);			else rulenum = 1;			break;		case 'L':			add_command(&command, CMD_LIST, CMD_ZERO,				    invert);			if (optarg) chain = optarg;			else if (optind < argc && argv[optind][0] != '-'				 && argv[optind][0] != '!')				chain = argv[optind++];			break;		case 'F':			add_command(&command, CMD_FLUSH, CMD_NONE,				    invert);			if (optarg) chain = optarg;			else if (optind < argc && argv[optind][0] != '-'				 && argv[optind][0] != '!')				chain = argv[optind++];			break;		case 'Z':			add_command(&command, CMD_ZERO, CMD_LIST,				    invert);			if (optarg) chain = optarg;			else if (optind < argc && argv[optind][0] != '-'				&& argv[optind][0] != '!')				chain = argv[optind++];			break;		case 'N':			add_command(&command, CMD_NEW_CHAIN, CMD_NONE,				    invert);			chain = optarg;			break;		case 'X':			add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,				    invert);			if (optarg) chain = optarg;			else if (optind < argc && argv[optind][0] != '-'				 && argv[optind][0] != '!')				chain = argv[optind++];			break;		case 'E':			add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,				    invert);			chain = optarg;			if (optind < argc && argv[optind][0] != '-'			    && argv[optind][0] != '!')				newname = argv[optind++];			else				exit_error(PARAMETER_PROBLEM,				           "-%c requires old-chain-name and "					   "new-chain-name",					    cmd2char(CMD_RENAME_CHAIN));			break;		case 'P':			add_command(&command, CMD_SET_POLICY, CMD_NONE,				    invert);			chain = optarg;			if (optind < argc && argv[optind][0] != '-'			    && argv[optind][0] != '!')				policy = argv[optind++];			else				exit_error(PARAMETER_PROBLEM,					   "-%c requires a chain and a policy",					   cmd2char(CMD_SET_POLICY));			break;		case 'h':			if (!optarg)				optarg = argv[optind];			/* iptables -p icmp -h */			if (!ip6tables_matches && protocol)				find_match(protocol, TRY_LOAD);			exit_printhelp();			/*			 * Option selection			 */		case 'p':			if (check_inverse(optarg, &invert))				optind++;			set_option(&options, OPT_PROTOCOL, &fw.ipv6.invflags,				   invert);			/* Canonicalize into lower case */			for (protocol = argv[optind-1]; *protocol; protocol++)				*protocol = tolower(*protocol);			protocol = argv[optind-1];			if ( strcmp(protocol,"ipv6-icmp") == 0)				protocol = icmp6p;			fw.ipv6.proto = parse_protocol(protocol);			fw.ipv6.flags |= IP6T_F_PROTO;			if (fw.ipv6.proto == 0			    && (fw.ipv6.invflags & IP6T_INV_PROTO))				exit_error(PARAMETER_PROBLEM,					   "rule would never match protocol");			fw.nfcache |= NFC_IP6_PROTO;			break;		case 's':			if (check_inverse(optarg, &invert))				optind++;			set_option(&options, OPT_SOURCE, &fw.ipv6.invflags,				   invert);			shostnetworkmask = argv[optind-1];			fw.nfcache |= NFC_IP6_SRC;			break;		case 'd':			if (check_inverse(optarg, &invert))				optind++;			set_option(&options, OPT_DESTINATION, &fw.ipv6.invflags,				   invert);			dhostnetworkmask = argv[optind-1];			fw.nfcache |= NFC_IP6_DST;			break;		case 'j':			set_option(&options, OPT_JUMP, &fw.ipv6.invflags,				   invert);			jumpto = parse_target(optarg);			/* TRY_LOAD (may be chain name) */			target = find_target(jumpto, TRY_LOAD);			if (target) {				size_t size;				size = IP6T_ALIGN(sizeof(struct ip6t_entry_target))					+ target->size;				target->t = fw_calloc(1, size);				target->t->u.target_size = size;				strcpy(target->t->u.user.name, jumpto);				target->init(target->t, &fw.nfcache);				opts = merge_options(opts, target->extra_opts, &target->option_offset);			}			break;		case 'i':			if (check_inverse(optarg, &invert))				optind++;			set_option(&options, OPT_VIANAMEIN, &fw.ipv6.invflags,				   invert);			parse_interface(argv[optind-1],					fw.ipv6.iniface,					fw.ipv6.iniface_mask);			fw.nfcache |= NFC_IP6_IF_IN;			break;		case 'o':			if (check_inverse(optarg, &invert))				optind++;			set_option(&options, OPT_VIANAMEOUT, &fw.ipv6.invflags,				   invert);			parse_interface(argv[optind-1],					fw.ipv6.outiface,					fw.ipv6.outiface_mask);			fw.nfcache |= NFC_IP6_IF_OUT;			break;		case 'v':			if (!verbose)				set_option(&options, OPT_VERBOSE,					   &fw.ipv6.invflags, invert);			verbose++;			break;		case 'm': {			size_t size;			if (invert)				exit_error(PARAMETER_PROBLEM,					   "unexpected ! flag before --match");			m = find_match(optarg, LOAD_MUST_SUCCEED);			size = IP6T_ALIGN(sizeof(struct ip6t_entry_match))					 + m->size;			m->m = fw_calloc(1, size);			m->m->u.match_size = size;			strcpy(m->m->u.user.name, m->name);			m->init(m->m, &fw.nfcache);			opts = merge_options(opts, m->extra_opts, &m->option_offset);		}		break;		case 'n':			set_option(&options, OPT_NUMERIC, &fw.ipv6.invflags,				   invert);			break;		case 't':			if (invert)				exit_error(PARAMETER_PROBLEM,					   "unexpected ! flag before --table");			*table = argv[optind-1];			break;		case 'x':			set_option(&options, OPT_EXPANDED, &fw.ipv6.invflags,				   invert);			break;		case 'V':			if (invert)				printf("Not %s ;-)\n", program_version);			else				printf("%s v%s\n",				       program_name, program_version);			exit(0);		case '0':			set_option(&options, OPT_LINENUMBERS, &fw.ipv6.invflags,				   invert);			break;		case 'M':			modprobe = optarg;			break;		case 'c':			set_option(&options, OPT_COUNTERS, &fw.ipv6.invflags,				   invert);			pcnt = optarg;			if (optind < argc && argv[optind][0] != '-'			    && argv[optind][0] != '!')				bcnt = argv[optind++];			else				exit_error(PARAMETER_PROBLEM,					"-%c requires packet and byte counter",					opt2char(OPT_COUNTERS));			if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1)				exit_error(PARAMETER_PROBLEM,					"-%c packet counter not numeric",					opt2char(OPT_COUNTERS));			if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1)				exit_error(PARAMETER_PROBLEM,					"-%c byte counter not numeric",					opt2char(OPT_COUNTERS));						break;		case 1: /* non option */			if (optarg[0] == '!' && optarg[1] == '\0') {				if (invert)					exit_error(PARAMETER_PROBLEM,						   "multiple consecutive ! not"						   " allowed");				invert = TRUE;				optarg[0] = '\0';				continue;			}			printf("Bad argument `%s'\n", optarg);			exit_tryhelp(2);		default:			/* FIXME: This scheme doesn't allow two of the same			   matches --RR */			if (!target			    || !(target->parse(c - target->option_offset,					       argv, invert,					       &target->tflags,					       &fw, &target->t))) {				for (m = ip6tables_matches; m; m = m->next) {					if (!m->used)						continue;					if (m->parse(c - m->option_offset,						     argv, invert,						     &m->mflags,						     &fw,						     &fw.nfcache,						     &m->m))						break;				}				/* If you listen carefully, you can				   actually hear this code suck. */				if (m == NULL				    && protocol				    && !find_proto(protocol, DONT_LOAD,						   options&OPT_NUMERIC)				    && (m = find_proto(protocol, TRY_LOAD,						       options&OPT_NUMERIC))) {					/* Try loading protocol */					size_t size;					size = IP6T_ALIGN(sizeof(struct ip6t_entry_match))							 + m->size;					m->m = fw_calloc(1, size);					m->m->u.match_size = size;					strcpy(m->m->u.user.name, m->name);					m->init(m->m, &fw.nfcache);					opts = merge_options(opts,					    m->extra_opts, &m->option_offset);					optind--;					continue;				}				if (!m)					exit_error(PARAMETER_PROBLEM,						   "Unknown arg `%s'",						   argv[optind-1]);			}		}		invert = FALSE;	}	for (m = ip6tables_matches; m; m = m->next) {		if (!m->used)			continue;		m->final_check(m->mflags);	}	if (target)		target->final_check(target->tflags);	/* Fix me: must put inverse options checking here --MN */	if (optind < argc)		exit_error(PARAMETER_PROBLEM,			   "unknown arguments found on commandline");	if (!command)		exit_error(PARAMETER_PROBLEM, "no command specified");	if (invert)		exit_error(PARAMETER_PROBLEM,			   "nothing appropriate following !");	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND |	    CMD_CHECK)) {		if (!(options & OPT_DESTINATION))			dhostnetworkmask = "::0/0";		if (!(options & OPT_SOURCE))			shostnetworkmask = "::0/0";	}	if (shostnetworkmask)		parse_hostnetworkmask(shostnetworkmask, &saddrs,				      &(fw.ipv6.smsk), &nsaddrs);	if (dhostnetworkmask)		parse_hostnetworkmask(dhostnetworkmask, &daddrs,				      &(fw.ipv6.dmsk), &ndaddrs);	if ((nsaddrs > 1 || ndaddrs > 1) &&	    (fw.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))		exit_error(PARAMETER_PROBLEM, "! not allowed with multiple"			   " source or destination IP addresses");	if (command == CMD_CHECK && fw.ipv6.invflags != 0)		exit_error(PARAMETER_PROBLEM, "! not allowed with -%c",			   cmd2char(CMD_CHECK));	if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))		exit_error(PARAMETER_PROBLEM, "Replacement rule does not "			   "specify a unique address");	generic_opt_check(command, options);	if (chain && strlen(chain) > IP6T_FUNCTION_MAXNAMELEN)		exit_error(PARAMETER_PROBLEM,			   "chain name `%s' too long (must be under %i chars)",			   chain, IP6T_FUNCTION_MAXNAMELEN);	/* only allocate handle if we weren't called with a handle */	if (!*handle)		*handle = ip6tc_init(*table);	if (!*handle) {		/* try to insmod the module if iptc_init failed */		ip6tables_insmod("ip6_tables", modprobe);		*handle = ip6tc_init(*table);	}	if (!*handle)		exit_error(VERSION_PROBLEM,			"can't initialize ip6tables table `%s': %s",			*table, ip6tc_strerror(errno));	if (command == CMD_CHECK	    || command == CMD_APPEND	    || command == CMD_DELETE	    || command == CMD_INSERT	    || command == CMD_REPLACE) {		if (strcmp(chain, "PREROUTING") == 0		    || strcmp(chain, "INPUT") == 0) {			/* -o not valid with incoming packets. */			if (options & OPT_VIANAMEOUT)				exit_error(PARAMETER_PROBLEM,					   "Can't use -%c with %s\n",					   opt2char(OPT_VIANAMEOUT),					   chain);			/* -i required with -C */			if (command == CMD_CHECK && !(options & OPT_VIANAMEIN))				exit_error(PARAMETER_PROBLEM,					   "Need -%c with %s\n",					   opt2char(OPT_VIANAMEIN),					   chain);		}		if (strcmp(chain, "POSTROUTING") == 0		    || strcmp(chain, "OUTPUT") == 0) {			/* -i not valid with outgoing packets */			if (options & OPT_VIANAMEIN)				exit_error(PARAMETER_PROBLEM,					   "Can't use -%c with %s\n",					   opt2char(OPT_VIANAMEIN),					   chain);			/* -o required with -C */			if (command == CMD_CHECK && !(options&OPT_VIANAMEOUT))				exit_error(PARAMETER_PROBLEM,					   "Need -%c with %s\n",					   opt2char(OPT_VIANAMEOUT),					   chain);		}		if (target && ip6tc_is_chain(jumpto, *handle)) {			printf("Warning: using chain %s, not extension\n",			       jumpto);			target = NULL;		}		/* If they didn't specify a target, or it's a chain		   name, use standard. */		if (!target		    && (strlen(jumpto) == 0			|| ip6tc_is_chain(jumpto, *handle))) {			size_t size;			target = find_target(IP6T_STANDARD_TARGET,					     LOAD_MUST_SUCCEED);			size = sizeof(struct ip6t_entry_target)				+ target->size;			target->t = fw_calloc(1, size);			target->t->u.target_size = size;			strcpy(target->t->u.user.name, jumpto);			target->init(target->t, &fw.nfcache);		}		if (!target) {			/* it is no chain, and we can't load a plugin.			 * We cannot know if the plugin is corrupt, non			 * existant OR if the user just misspelled a			 * chain. */			find_target(jumpto, LOAD_MUST_SUCCEED);		} else {			e = generate_entry(&fw, ip6tables_matches, target->t);		}	}	switch (command) {	case CMD_APPEND:		ret = append_entry(chain, e,				   nsaddrs, saddrs, ndaddrs, daddrs,				   options&OPT_VERBOSE,				   handle);		break;	case CMD_CHECK:		ret = check_packet(chain, e,				   nsaddrs, saddrs, ndaddrs, daddrs,				   options&OPT_VERBOSE, handle);		break;	case CMD_DELETE:		ret = delete_entry(chain, e,				   nsaddrs, saddrs, ndaddrs, daddrs,				   options&OPT_VERBOSE,				   handle);		break;	case CMD_DELETE_NUM:		ret = ip6tc_delete_num_entry(chain, rulenum - 1, handle);		break;	case CMD_REPLACE:		ret = replace_entry(chain, e, rulenum - 1,				    saddrs, daddrs, options&OPT_VERBOSE,				    handle);		break;	case CMD_INSERT:		ret = insert_entry(chain, e, rulenum - 1,				   nsaddrs, saddrs, ndaddrs, daddrs,				   options&OPT_VERBOSE,				   handle);		break;	case CMD_LIST:		ret = list_entries(chain,				   options&OPT_VERBOSE,				   options&OPT_NUMERIC,				   options&OPT_EXPANDED,				   options&OPT_LINENUMBERS,				   handle);		break;	case CMD_FLUSH:		ret = flush_entries(chain, options&OPT_VERBOSE, handle);		break;	case CMD_ZERO:		ret = zero_entries(chain, options&OPT_VERBOSE, handle);		break;	case CMD_LIST|CMD_ZERO:		ret = list_entries(chain,				   options&OPT_VERBOSE,				   options&OPT_NUMERIC,				   options&OPT_EXPANDED,				   options&OPT_LINENUMBERS,				   handle);		if (ret)			ret = zero_entries(chain,					   options&OPT_VERBOSE, handle);		break;	case CMD_NEW_CHAIN:		ret = ip6tc_create_chain(chain, handle);		break;	case CMD_DELETE_CHAIN:		ret = delete_chain(chain, options&OPT_VERBOSE, handle);		break;	case CMD_RENAME_CHAIN:		ret = ip6tc_rename_chain(chain, newname,	handle);		break;	case CMD_SET_POLICY:		ret = ip6tc_set_policy(chain, policy, NULL, handle);		break;	default:		/* We should never reach this... */		exit_tryhelp(2);	}	if (verbose > 1)		dump_entries6(*handle);	return ret;}